BEM++  2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
concrete_geometry.hpp
1 // Copyright (C) 2011-2012 by the BEM++ Authors
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE.
20 
21 #ifndef bempp_concrete_geometry_hpp
22 #define bempp_concrete_geometry_hpp
23 
24 #include "../common/common.hpp"
25 
26 #include "geometry.hpp"
27 #include "dune.hpp"
28 #include "geometry_type.hpp"
29 
30 #include "../common/not_implemented_error.hpp"
31 #include "../fiber/geometrical_data.hpp"
32 #include <dune/common/fvector.hh>
33 #include <dune/common/fmatrix.hh>
34 #include <dune/common/static_assert.hh>
35 #include <dune/grid/common/grid.hh>
36 
37 #include "../common/armadillo_fwd.hpp"
38 #include <memory>
39 
40 namespace Bempp
41 {
42 
44 template <typename DuneGeometry> class ConcreteGeometryFactory;
47 // Internal helper function for setting up geometries manually (independently
48 // from the grid).
49 
50 template <typename DuneGeometry>
51 DuneGeometry setupDuneGeometry(
52  const GeometryType& type,
53  const std::vector<Dune::FieldVector<double, DuneGeometry::dimensionworld> >& corners)
54 {
55  throw std::runtime_error("setupDuneGeometry() is only supported for a "
56  "small number of Dune geometry classes");
57 }
58 
59 template <>
60 Default2dIn3dDuneGrid::Codim<0>::Geometry
61 setupDuneGeometry<Default2dIn3dDuneGrid::Codim<0>::Geometry>(
62  const GeometryType& type,
63  const std::vector<Dune::FieldVector<double, 3> >& corners)
64 {
65  return Default2dIn3dDuneGrid::Codim<0>::Geometry(
66  Dune::FoamGridGeometry<2, 3, const Dune::FoamGrid<3> >(type, corners));
67 }
68 
71 template <typename DuneGeometry>
72 class ConcreteGeometry : public Geometry
73 {
74  dune_static_assert((int)DuneGeometry::coorddimension ==
75  (int)DuneGeometry::dimensionworld,
76  "ConcreteGeometry: world dimension does not agree with "
77  "number of coordinates");
78 
79 private:
80  std::auto_ptr<DuneGeometry> m_dune_geometry;
81 
82  void setDuneGeometry(const DuneGeometry& dune_geometry) {
83  m_dune_geometry.reset(new DuneGeometry(dune_geometry));
84  }
85 
86  ConcreteGeometry() {}
87 
88  template<int codim, typename DuneEntity> friend class ConcreteEntity;
89  friend class ConcreteGeometryFactory<DuneGeometry>;
90 
91 public:
93  explicit ConcreteGeometry(const DuneGeometry& dune_geometry) :
94  m_dune_geometry(new DuneGeometry(dune_geometry)) {}
95 
97  const DuneGeometry& duneGeometry() const {
98  return m_dune_geometry;
99  }
100 
103  bool isInitialized() const {
104  return m_dune_geometry.get();
105  }
106 
108  void uninitialize() {
109  m_dune_geometry.reset();
110  }
111 
112  virtual int dim() const {
113  return DuneGeometry::mydimension;
114  }
115 
116  virtual int dimWorld() const {
117  return DuneGeometry::coorddimension;
118  }
119 
120  virtual void setupImpl(const arma::Mat<double>& corners,
121  const arma::Col<char>& auxData) {
122  const int dimWorld = DuneGeometry::coorddimension;
123  const int cornerCount = corners.n_cols;
124  assert((int)corners.n_rows == dimWorld);
125 
127  if (DuneGeometry::mydimension == 0) {
128  assert(cornerCount == 1);
129  type.makeVertex();
130  }
131  else if (DuneGeometry::mydimension == 1) {
132  assert(cornerCount == 2);
133  type.makeLine();
134  }
135  else if (DuneGeometry::mydimension == 2) {
136  assert (cornerCount == 3 || cornerCount == 4);
137  if (cornerCount == 3)
138  type.makeTriangle();
139  else
140  type.makeQuadrilateral();
141  }
142  else
143  throw NotImplementedError("ConcreteGeometry::setup(): "
144  "not implemented yet for 3D entities");
145 
146  std::vector<Dune::FieldVector<double, dimWorld> > duneCorners(cornerCount);
147  for (size_t i = 0; i < corners.n_cols; ++i)
148  for (int j = 0; j < dimWorld; ++j)
149  duneCorners[i][j] = corners(j, i);
150 
151  typedef Dune::MakeableInterfaceObject<DuneGeometry> DuneMakeableGeometry;
152  typedef typename DuneMakeableGeometry::ImplementationType DuneGeometryImp;
153 
154  m_dune_geometry.reset(
155  new DuneGeometry(
156  setupDuneGeometry<DuneGeometry>(type, duneCorners)));
157  }
158 
159  virtual GeometryType type() const {
160  return m_dune_geometry->type();
161  }
162 
163  virtual bool affine() const {
164  return m_dune_geometry->affine();
165  }
166 
167  virtual int cornerCount() const {
168  return m_dune_geometry->corners();
169  }
170 
171  virtual void getCornersImpl(arma::Mat<double>& c) const {
172  const int cdim = DuneGeometry::dimensionworld;
173  const int n = m_dune_geometry->corners();
174  c.set_size(cdim, n);
175 
176  /* TODO: In future this copying should be optimised away by casting
177  appropriate columns of c to Dune field vectors. But this
178  can't be done until unit tests are in place. */
179  typename DuneGeometry::GlobalCoordinate g;
180  for (int j = 0; j < n; ++j) {
181  g = m_dune_geometry->corner(j);
182  for (int i = 0; i < cdim; ++i)
183  c(i,j) = g[i];
184  }
185  }
186 
187  virtual void local2globalImpl(const arma::Mat<double>& local,
188  arma::Mat<double>& global) const {
189  const int mdim = DuneGeometry::mydimension;
190  const int cdim = DuneGeometry::coorddimension;
191 #ifndef NDEBUG
192  if ((int)local.n_rows != mdim)
193  throw std::invalid_argument("Geometry::local2global(): invalid "
194  "dimensions of the 'local' array");
195 #endif
196  const size_t n = local.n_cols;
197  global.set_size(cdim, n);
198 
199  /* TODO: Optimise (get rid of data copying). */
200  typename DuneGeometry::GlobalCoordinate g;
201  typename DuneGeometry::LocalCoordinate l;
202  for (size_t j = 0; j < n; ++j) {
203  for (int i = 0; i < mdim; ++i)
204  l[i] = local(i,j);
205  g = m_dune_geometry->global(l);
206  for (int i = 0; i < cdim; ++i)
207  global(i,j) = g[i];
208  }
209  }
210 
211  virtual void global2localImpl(const arma::Mat<double>& global,
212  arma::Mat<double>& local) const {
213  const int mdim = DuneGeometry::mydimension;
214  const int cdim = DuneGeometry::coorddimension;
215 #ifndef NDEBUG
216  if ((int)global.n_rows != cdim)
217  throw std::invalid_argument("Geometry::global2local(): invalid "
218  "dimensions of the 'global' array");
219 #endif
220  const size_t n = global.n_cols;
221  local.set_size(mdim, n);
222 
223  /* TODO: Optimise (get rid of data copying). */
224  typename DuneGeometry::GlobalCoordinate g;
225  typename DuneGeometry::LocalCoordinate l;
226  for (size_t j = 0; j < n; ++j) {
227  for (int i = 0; i < cdim; ++i)
228  g[i] = global(i,j);
229  l = m_dune_geometry->local(g);
230  for (int i = 0; i < mdim; ++i)
231  local(i,j) = l[i];
232  }
233  }
234 
235  virtual void getIntegrationElementsImpl(const arma::Mat<double>& local,
236  arma::Row<double>& int_element) const {
237  const int mdim = DuneGeometry::mydimension;
238 #ifndef NDEBUG
239  if ((int)local.n_rows != mdim)
240  throw std::invalid_argument("Geometry::local2global(): invalid "
241  "dimensions of the 'local' array");
242 #endif
243  const size_t n = local.n_cols;
244  int_element.set_size(n);
245 
246  /* TODO: Optimise (get rid of data copying). */
247  typename DuneGeometry::LocalCoordinate l;
248  for (size_t j = 0; j < n; ++j) {
249  for (int i = 0; i < mdim; ++i)
250  l[i] = local(i,j);
251  double ie = m_dune_geometry->integrationElement(l);
252  int_element(j) = ie;
253  }
254  }
255 
256  virtual double volume() const {
257  return m_dune_geometry->volume();
258  }
259 
260  virtual void getCenterImpl(arma::Col<double>& c) const {
261  const int cdim = DuneGeometry::coorddimension;
262  c.set_size(cdim);
263 
264  /* TODO: Optimise (get rid of data copying). */
265  typename DuneGeometry::GlobalCoordinate g = m_dune_geometry->center();
266  for (int i = 0; i < cdim; ++i)
267  c(i) = g[i];
268  }
269 
270  virtual void getJacobiansTransposedImpl(const arma::Mat<double>& local,
271  Fiber::_3dArray<double>& jacobian_t) const {
272  const int mdim = DuneGeometry::mydimension;
273  const int cdim = DuneGeometry::coorddimension;
274 #ifndef NDEBUG
275  if ((int)local.n_rows != mdim)
276  throw std::invalid_argument("Geometry::getJacobiansTransposed(): "
277  "invalid dimensions of the 'local' array");
278 #endif
279  const size_t n = local.n_cols;
280  jacobian_t.set_size(mdim, cdim, n);
281 
282  /* Unfortunately Dune::FieldMatrix (the underlying type of
283  JacobianTransposed) stores elements rowwise, while Armadillo does it
284  columnwise. Hence element-by-element filling of jacobian_t seems
285  unavoidable). */
286  typename DuneGeometry::JacobianTransposed j_t;
287  typename DuneGeometry::LocalCoordinate l;
288  for (size_t k = 0; k < n; ++k) {
289  /* However, this bit of data copying could be avoided. */
290  for (int i = 0; i < mdim; ++i)
291  l[i] = local(i,k);
292  j_t = m_dune_geometry->jacobianTransposed(l);
293  for (int j = 0; j < cdim; ++j)
294  for (int i = 0; i < mdim; ++i)
295  jacobian_t(i,j,k) = j_t[i][j];
296  }
297  }
298 
300  const arma::Mat<double>& local,
301  Fiber::_3dArray<double>& jacobian_inv_t) const {
302  const int mdim = DuneGeometry::mydimension;
303  const int cdim = DuneGeometry::coorddimension;
304 #ifndef NDEBUG
305  if ((int)local.n_rows != mdim)
306  throw std::invalid_argument("Geometry::getJacobianInversesTransposed(): "
307  "invalid dimensions of the 'local' array");
308 #endif
309  const size_t n = local.n_cols;
310  jacobian_inv_t.set_size(cdim, mdim, n);
311 
312  /* Unfortunately Dune::FieldMatrix (the underlying type of
313  Jacobian) stores elements rowwise, while Armadillo does it
314  columnwise. Hence element-by-element filling of jacobian_t seems
315  unavoidable). */
316  typename DuneGeometry::Jacobian j_inv_t;
317  typename DuneGeometry::LocalCoordinate l;
318  for (size_t k = 0; k < n; ++k) {
320  for (int i = 0; i < mdim; ++i)
321  l[i] = local(i,k);
322  j_inv_t = m_dune_geometry->jacobianInverseTransposed(l);
323  for (int j = 0; j < mdim; ++j)
324  for (int i = 0; i < cdim; ++i)
325  jacobian_inv_t(i,j,k) = j_inv_t[i][j];
326  }
327  }
328 
329  virtual void getNormalsImpl(const arma::Mat<double>& local,
330  arma::Mat<double>& normal) const {
331  Fiber::_3dArray<double> jacobian_t;
332  getJacobiansTransposed(local, jacobian_t);
333  calculateNormals(jacobian_t, normal);
334  }
335 
336  virtual void getDataImpl(size_t what, const arma::Mat<double>& local,
337  Fiber::GeometricalData<double>& data) const {
338  // In this first implementation we call the above virtual functions as required.
339  // In future some optimisations (elimination of redundant calculations)
340  // might be possible.
341 
342  typedef ConcreteGeometry<DuneGeometry> This; // to avoid virtual function calls
343 
344  if (what & Fiber::GLOBALS)
345  This::local2global(local, data.globals);
346  if (what & Fiber::INTEGRATION_ELEMENTS)
347  This::getIntegrationElements(local, data.integrationElements);
348  if (what & Fiber::JACOBIANS_TRANSPOSED || what & Fiber::NORMALS)
349  This::getJacobiansTransposed(local, data.jacobiansTransposed);
350  if (what & Fiber::JACOBIAN_INVERSES_TRANSPOSED)
351  This::getJacobianInversesTransposed(
352  local, data.jacobianInversesTransposed);
353  if (what & Fiber::NORMALS)
354  calculateNormals(data.jacobiansTransposed, data.normals);
355  }
356 
357 private:
358  void calculateNormals(const Fiber::_3dArray<double>& jt,
359  arma::Mat<double>& normals) const {
360  const int mdim = DuneGeometry::mydimension;
361  const int cdim = DuneGeometry::coorddimension;
362 
363  if (mdim != cdim - 1)
364  throw std::logic_error("ConcreteGeometry::calculateNormals(): "
365  "normal vectors are defined only for "
366  "entities of dimension (worldDimension - 1)");
367 
368  const size_t pointCount = jt.extent(2); //jt.n_slices;
369  normals.set_size(cdim, pointCount);
370 
371  // First calculate normal vectors of arbitrary length
372 
373  // Compile-time if
374  if (cdim == 3)
375  for (size_t i = 0; i < pointCount; ++i) {
376  normals(0,i) = jt(0,1,i) * jt(1,2,i) - jt(0,2,i) * jt(1,1,i);
377  normals(1,i) = jt(0,2,i) * jt(1,0,i) - jt(0,0,i) * jt(1,2,i);
378  normals(2,i) = jt(0,0,i) * jt(1,1,i) - jt(0,1,i) * jt(1,0,i);
379  }
380  else if (cdim == 2)
381  for (size_t i = 0; i < pointCount; ++i) {
382  normals(0,i) = jt(0,1,i);
383  normals(1,i) = jt(0,0,i);
384  }
385  else if (cdim == 1) // probably unnecessary
386  for (size_t i = 0; i < pointCount; ++i)
387  normals(0,i) = 1.;
388  else
389  throw std::runtime_error("ConcreteGeometry::calculateNormals(): "
390  "Normal vector is not defined for "
391  "zero-dimensional space");
392 
393  // Now set vector length to 1.
394 
395  for (size_t i = 0; i < pointCount; ++i) {
396  double sum = 0.;
397  for (int dim = 0; dim < cdim; ++dim)
398  sum += normals(dim, i) * normals(dim, i);
399  double invLength = 1. / sqrt(sum);
400  for (size_t j = 0; j < cdim; ++j)
401  normals(j, i) *= invLength;
402  }
403  }
404 };
405 
406 } // namespace Bempp
407 
408 #endif
virtual int dimWorld() const
Dimension of the space containing the geometry.
Definition: concrete_geometry.hpp:116
Wrapper of a Dune geometry of type DuneGeometry.
Definition: concrete_geometry.hpp:72
Dune::GeometryType GeometryType
Identifier of geometry type.
Definition: geometry_type.hpp:34
void getJacobiansTransposed(const arma::Mat< double > &local, arma::Cube< double > &jacobian_t) const
Get transposed Jacobian matrices at specified points.
Definition: geometry_imp.hpp:118
virtual int dim() const
Dimension of the geometry.
Definition: concrete_geometry.hpp:112
Wrapper of a Dune entity of type DuneEntity and codimension codim.
Definition: concrete_entity_decl.hpp:46
virtual double volume() const
Volume of geometry.
Definition: concrete_geometry.hpp:256
Storage of geometrical data.
Definition: geometrical_data.hpp:54
virtual void getJacobianInversesTransposedImpl(const arma::Mat< double > &local, Fiber::_3dArray< double > &jacobian_inv_t) const
Definition: concrete_geometry.hpp:299
Factory able to construct an &quot;empty&quot; geometry wrapping a Dune geometry of type DuneGeometry.
Definition: concrete_geometry_factory.hpp:38
const DuneGeometry & duneGeometry() const
Read-only access to the underlying Dune geometry object.
Definition: concrete_geometry.hpp:97
ConcreteGeometry(const DuneGeometry &dune_geometry)
Constructor from a DuneGeometry object.
Definition: concrete_geometry.hpp:93
virtual bool affine() const
True if the geometry mapping is affine and false otherwise.
Definition: concrete_geometry.hpp:163
bool isInitialized() const
Return true if the Dune geometry object has already been set, false otherwise.
Definition: concrete_geometry.hpp:103
virtual GeometryType type() const
Type of the reference element.
Definition: concrete_geometry.hpp:159
void uninitialize()
Uninitialize the Dune geometry object.
Definition: concrete_geometry.hpp:108
virtual int cornerCount() const
Number of corners of the reference element.
Definition: concrete_geometry.hpp:167
Simple implementation of a 3D Fortran-ordered array.
Definition: _3d_array.hpp:48
Abstract wrapper of a geometry.
Definition: geometry.hpp:45