BEM++  2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
structured_grid_factory.hpp
Go to the documentation of this file.
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_structured_grid_factory_hpp
22 #define bempp_structured_grid_factory_hpp
23 
24 #include "../common/common.hpp"
25 
30 #include <algorithm>
31 #include <cstddef>
32 #include <cstdlib>
33 #include <memory>
34 
35 #include <dune/common/array.hh>
36 #include <dune/common/classname.hh>
37 #include <dune/common/exceptions.hh>
38 #include <dune/common/fvector.hh>
39 #include <dune/common/mpihelper.hh>
40 
41 #include <dune/grid/common/gridfactory.hh>
42 #include <dune/grid/yaspgrid.hh>
43 
44 namespace Dune
45 {
46 
55 template <class GridType>
57 {
58  typedef typename GridType::ctype ctype;
59 
60  static const int dim = GridType::dimension;
61 
62  static const int dimworld = GridType::dimensionworld;
63 
66  class MultiIndex
67  : public array<int,dim>
68  {
69 
70  // The range of each component
71  array<int,dim> limits_;
72 
73  public:
75  MultiIndex(const array<int,dim>& limits)
76  : limits_(limits) {
77  std::fill(this->begin(), this->end(), 0);
78  }
79 
82 
83  for (int i=0; i<dim; i++) {
84 
85  // Augment digit
86  (*this)[i]++;
87 
88  // If there is no carry-over we can stop here
89  if ((*this)[i]<limits_[i])
90  break;
91 
92  (*this)[i] = 0;
93 
94  }
95  return *this;
96  }
97 
99  int cycle() const {
100  int result = 1;
101  for (int i=0; i<dim; i++)
102  result *= limits_[i];
103  return result;
104  }
105 
106  };
107 
109  static void insertVertices(GridFactory<GridType>& factory,
110  const FieldVector<ctype,dim>& lowerLeft,
111  const FieldVector<ctype,dim>& upperRight,
112  const array<int,dim>& vertices) {
113 
114  // Pad lowerLeft and upperRight with zeros to dimworld dimensions
115  FieldVector<ctype,dimworld> fullLowerLeft(0.);
116  for (int i = 0; i < dim; ++i)
117  fullLowerLeft[i] = lowerLeft[i];
118  FieldVector<ctype,dimworld> fullUpperRight(0.);
119  for (int i = 0; i < dim; ++i)
120  fullUpperRight[i] = upperRight[i];
121 
122  MultiIndex index(vertices);
123 
124  // Compute the total number of vertices to be created
125  int numVertices = index.cycle();
126 
127  // Create vertices
128  for (int i=0; i<numVertices; i++, ++index) {
129 
130  // scale the multiindex to obtain a world position
131  FieldVector<double,dimworld> pos(0);
132  for (int j=0; j<dim; j++)
133  pos[j] = fullLowerLeft[j] + index[j] * (fullUpperRight[j]-fullLowerLeft[j])/(vertices[j]-1);
134 
135  factory.insertVertex(pos);
136 
137  }
138 
139  }
140 
141  // Compute the index offsets needed to move to the adjacent vertices
142  // in the different coordinate directions
143  static array<int, dim> computeUnitOffsets(const array<int,dim>& vertices) {
144  array<int, dim> unitOffsets;
145  if (dim>0) // paranoia
146  unitOffsets[0] = 1;
147 
148  for (int i=1; i<dim; i++)
149  unitOffsets[i] = unitOffsets[i-1] * vertices[i-1];
150 
151  return unitOffsets;
152  }
153 
154 public:
155 
161  static std::auto_ptr<GridType> createCubeGrid(const FieldVector<ctype,dim>& lowerLeft,
162  const FieldVector<ctype,dim>& upperRight,
163  const array<int,dim>& elements) {
164  // The grid factory
165  GridFactory<GridType> factory;
166 
167  if (MPIHelper::getCollectiveCommunication().rank() == 0) {
168  // Insert uniformly spaced vertices
169  array<int,dim> vertices = elements;
170  for( int i = 0; i < vertices.size(); ++i )
171  vertices[i]++;
172 
173  // Insert vertices for structured grid into the factory
174  insertVertices(factory, lowerLeft, upperRight, vertices);
175 
176  // Compute the index offsets needed to move to the adjacent
177  // vertices in the different coordinate directions
178  array<int, dim> unitOffsets =
179  computeUnitOffsets(vertices);
180 
181  // Compute an element template (the cube at (0,...,0). All
182  // other cubes are constructed by moving this template around
183  int nCorners = 1<<dim;
184 
185  std::vector<int> cornersTemplate(nCorners,0);
186 
187  for (int i=0; i<nCorners; i++)
188  for (int j=0; j<dim; j++)
189  if ( i & (1<<j) )
190  cornersTemplate[i] += unitOffsets[j];
191 
192  // Insert elements
193  MultiIndex index(elements);
194 
195  // Compute the total number of elementss to be created
196  int numElements = index.cycle();
197 
198  for (int i=0; i<numElements; i++, ++index) {
199 
200  // 'base' is the index of the lower left element corner
201  int base = 0;
202  for (int j=0; j<dim; j++)
203  base += index[j] * unitOffsets[j];
204 
205  // insert new element
206  std::vector<int> corners = cornersTemplate;
207  for (size_t j=0; j<corners.size(); j++)
208  corners[j] += base;
209 
210  factory.insertElement
211  (GeometryType(GeometryType::cube, dim), corners);
212 
213  }
214 
215  } // if(rank == 0)
216 
217  // Create the grid and hand it to the calling method
218  return std::auto_ptr<GridType>(factory.createGrid());
219 
220  }
221 
228  static std::auto_ptr<GridType> createSimplexGrid(const FieldVector<ctype,dim>& lowerLeft,
229  const FieldVector<ctype,dim>& upperRight,
230  const array<int,dim>& elements) {
231  // The grid factory
232  GridFactory<GridType> factory;
233 
234  if(MPIHelper::getCollectiveCommunication().rank() == 0) {
235  // Insert uniformly spaced vertices
236  array<int,dim> vertices = elements;
237  for (std::size_t i=0; i<vertices.size(); i++)
238  vertices[i]++;
239 
240  insertVertices(factory, lowerLeft, upperRight, vertices);
241 
242  // Compute the index offsets needed to move to the adjacent
243  // vertices in the different coordinate directions
244  array<int, dim> unitOffsets =
245  computeUnitOffsets(vertices);
246 
247  // Insert the elements
248  std::vector<int> corners(dim+1);
249 
250  // Loop over all "cubes", and split up each cube into dim!
251  // (factorial) simplices
252  MultiIndex elementsIndex(elements);
253  int cycle = elementsIndex.cycle();
254 
255  for (int i=0; i<cycle; ++elementsIndex, i++) {
256 
257  // 'base' is the index of the lower left element corner
258  int base = 0;
259  for (int j=0; j<dim; j++)
260  base += elementsIndex[j] * unitOffsets[j];
261 
262  // each permutation of the unit vectors gives a simplex.
263  std::vector<unsigned int> permutation(dim);
264  for (int j=0; j<dim; j++)
265  permutation[j] = j;
266 
267  // A hack for triangular lattices: swap the two last
268  // vertices of every second triangle to uniformize orientation
269  // of their normals
270  int triangle = 0;
271  do {
272 
273  // Make a simplex
274  std::vector<unsigned int> corners(dim+1);
275  corners[0] = base;
276 
277  for (int j=0; j<dim; j++)
278  corners[j+1] =
279  corners[j] + unitOffsets[permutation[j]];
280  if (dim == 2 && triangle == 1)
281  std::swap(corners[1], corners[2]);
282  ++triangle;
283 
284  factory.insertElement
285  (GeometryType(GeometryType::simplex, dim),
286  corners);
287 
288  } while (std::next_permutation(permutation.begin(),
289  permutation.end()));
290 
291  }
292 
293  } // if(rank == 0)
294 
295  // Create the grid and hand it to the calling method
296  return std::auto_ptr<GridType>(factory.createGrid());
297  }
298 
299 };
300 
310 template<int dim>
311 class BemppStructuredGridFactory<YaspGrid<dim> >
312 {
313  typedef YaspGrid<dim> GridType;
314  typedef typename GridType::ctype ctype;
315  static const int dimworld = GridType::dimensionworld;
316 
317 public:
327  static std::auto_ptr<GridType>
328  createCubeGrid(const FieldVector<ctype,dimworld>& lowerLeft,
329  const FieldVector<ctype,dimworld>& upperRight,
330  const array<int,dim>& elements) {
331  for(int d = 0; d < dimworld; ++d)
332  if(std::abs(lowerLeft[d]) > std::abs(upperRight[d])*1e-10)
333  DUNE_THROW(GridError, className<BemppStructuredGridFactory>()
334  << "::createCubeGrid(): The lower coordinates "
335  "must be at the origin for YaspGrid.");
336 
337  FieldVector<int, dim> elements_;
338  std::copy(elements.begin(), elements.end(), elements_.begin());
339 
340  return std::auto_ptr<GridType>
341  (new GridType(upperRight, elements_,
342  FieldVector<bool,dim>(false), 0));
343  }
344 
350  static std::auto_ptr<GridType>
351  createSimplexGrid(const FieldVector<ctype,dimworld>& lowerLeft,
352  const FieldVector<ctype,dimworld>& upperRight,
353  const array<int,dim>& elements) {
354  DUNE_THROW(GridError, className<BemppStructuredGridFactory>()
355  << "::createSimplexGrid(): Simplices are not supported "
356  "by YaspGrid.");
357  }
358 
359 };
360 
361 } // namespace Dune
362 
363 #endif
static std::auto_ptr< GridType > createSimplexGrid(const FieldVector< ctype, dimworld > &lowerLeft, const FieldVector< ctype, dimworld > &upperRight, const array< int, dim > &elements)
Create a structured simplex grid.
Definition: structured_grid_factory.hpp:351
static std::auto_ptr< GridType > createCubeGrid(const FieldVector< ctype, dim > &lowerLeft, const FieldVector< ctype, dim > &upperRight, const array< int, dim > &elements)
Create a structured cube grid.
Definition: structured_grid_factory.hpp:161
Dune::GeometryType GeometryType
Identifier of geometry type.
Definition: geometry_type.hpp:34
static std::auto_ptr< GridType > createSimplexGrid(const FieldVector< ctype, dim > &lowerLeft, const FieldVector< ctype, dim > &upperRight, const array< int, dim > &elements)
Create a structured simplex grid.
Definition: structured_grid_factory.hpp:228
static std::auto_ptr< GridType > createCubeGrid(const FieldVector< ctype, dimworld > &lowerLeft, const FieldVector< ctype, dimworld > &upperRight, const array< int, dim > &elements)
Create a structured cube grid.
Definition: structured_grid_factory.hpp:328
MultiIndex(const array< int, dim > &limits)
Constructor with a given range for each digit.
Definition: structured_grid_factory.hpp:75
static void insertVertices(GridFactory< GridType > &factory, const FieldVector< ctype, dim > &lowerLeft, const FieldVector< ctype, dim > &upperRight, const array< int, dim > &vertices)
Insert a structured set of vertices into the factory.
Definition: structured_grid_factory.hpp:109
MultiIndex & operator++()
Increment the MultiIndex.
Definition: structured_grid_factory.hpp:81
Construct structured cube and simplex grids in unstructured grid managers.
Definition: structured_grid_factory.hpp:56
dim-dimensional multi-index. The range for each component can be set individually ...
Definition: structured_grid_factory.hpp:66
int cycle() const
Compute how many times you can call operator++ before getting to (0,...,0) again. ...
Definition: structured_grid_factory.hpp:99