3.4
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
cakegridmanager.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*****************************************************************************
4 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
24#ifndef DUMUX_CAKE_GRID_MANAGER_HH
25#define DUMUX_CAKE_GRID_MANAGER_HH
26
27#include <vector>
28#include <iostream>
29#include <cmath>
30#include <algorithm>
31
32#include <dune/common/dynvector.hh>
33#include <dune/common/float_cmp.hh>
34#include <dune/common/math.hh>
35#include <dune/grid/common/gridfactory.hh>
37
38namespace Dumux {
39
46template <class Grid>
48{
49 using Scalar = typename Grid::ctype;
50
51 using GridFactory = Dune::GridFactory<Grid>;
52 using GridPointer = std::shared_ptr<Grid>;
53
54 enum { dim = Grid::dimension,
55 dimWorld = Grid::dimensionworld };
56
57public:
61 void init(const std::string& modelParamGroup = "")
62 {
63 static_assert(dim == 2 || dim == 3, "The CakeGridManager is only implemented for 2D and 3D.");
64
65 const bool verbose = getParamFromGroup<bool>(modelParamGroup, "Grid.Verbosity", false);
66
67 std::array<std::vector<Scalar>, dim> polarCoordinates;
68 // Indices specifying in which direction the piece of cake is oriented
69 Dune::FieldVector<int, dim> indices(-1);
70 createVectors(polarCoordinates, indices, modelParamGroup, verbose);
71
72 gridPtr() = createCakeGrid(polarCoordinates, indices, modelParamGroup, verbose);
74 }
75
96 static void createVectors(std::array<std::vector<Scalar>, dim> &polarCoordinates,
97 Dune::FieldVector<int, dim> &indices,
98 const std::string& modelParamGroup,
99 bool verbose = false)
100 {
101 // The positions
102 std::array<std::vector<Scalar>, dim> positions;
103
104 for (int i = 0; i < dim; ++i)
105 {
106 const bool hasRadial = hasParamInGroup(modelParamGroup, "Grid.Radial" + std::to_string(i));
107 const bool hasAngular = hasParamInGroup(modelParamGroup, "Grid.Angular" + std::to_string(i));
108 const bool hasAxial = (dim == 3) && hasParamInGroup(modelParamGroup, "Grid.Axial" + std::to_string(i));
109 if (static_cast<int>(hasRadial) + static_cast<int>(hasAngular) + static_cast<int>(hasAxial) != 1)
110 DUNE_THROW(Dune::RangeError, "Multiple or no position vectors (radial, angular, axial) specified in coord direction: " << i << std::endl);
111
112 if (hasRadial)
113 {
114 positions[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Radial" + std::to_string(i));
115 indices[0] = i; // Index specifying radial direction
116 }
117 else if (hasAngular)
118 {
119 positions[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Angular" + std::to_string(i));
120 indices[1] = i; // Index specifying angular direction
121 }
122 else // hasAxial
123 {
124 positions[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Axial" + std::to_string(i));
125 indices[2] = i; // Index specifying axial direction
126 }
127
128 if (!std::is_sorted(positions[i].begin(), positions[i].end()))
129 DUNE_THROW(Dune::GridError, "Make sure to specify a monotone increasing \"Positions\" array");
130
131 if(positions[i].size() < 2)
132 DUNE_THROW(Dune::GridError, "Make sure to specify position arrays with at least two entries (min and max value).");
133 }
134
135 // check that all indices are specified i.e. > 0
136 for (int i = 0; i < dim; ++i)
137 if (indices[i] < 0)
138 DUNE_THROW(Dune::RangeError, "Please specify Positions Angular and Radial and Axial correctly and unambiguously!" << std::endl);
139
140 // the number of cells (has a default)
141 std::array<std::vector<int>, dim> cells;
142 for (int i = 0; i < dim; ++i)
143 {
144 cells[i].resize(positions[i].size()-1, 1.0);
145 cells[i] = getParamFromGroup<std::vector<int>>(modelParamGroup, "Grid.Cells" + std::to_string(i), cells[i]);
146 if (cells[i].size() + 1 != positions[i].size())
147 DUNE_THROW(Dune::RangeError, "Make sure to specify the correct length of \"Cells\" and \"Positions\" arrays");
148 }
149
150 // grading factor (has a default)
151 std::array<std::vector<Scalar>, dim> grading;
152 for (int i = 0; i < dim; ++i)
153 {
154 grading[i].resize(positions[i].size()-1, 1.0);
155 grading[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Grading" + std::to_string(i), grading[i]);
156 if (grading[i].size() + 1 != positions[i].size())
157 DUNE_THROW(Dune::RangeError, "Make sure to specify the correct length of \"Grading\" and \"Positions\" arrays");
158 }
159
160 // make the grid
161 std::array<std::vector<Scalar>, dim> globalPositions;
162 using std::pow;
163 using Dune::power;
164 for (int dimIdx = 0; dimIdx < dim; dimIdx++)
165 {
166 // Each grid direction is subdivided into (numCells + 1) points
167 std::size_t numGlobalPositions = 1;
168 for (int zoneIdx = 0; zoneIdx < cells[dimIdx].size(); ++zoneIdx)
169 numGlobalPositions += cells[dimIdx][zoneIdx];
170
171 globalPositions[dimIdx].resize(numGlobalPositions);
172 std::size_t posIdx = 0;
173 for (int zoneIdx = 0; zoneIdx < cells[dimIdx].size(); ++zoneIdx)
174 {
175 const Scalar lower = positions[dimIdx][zoneIdx];
176 const Scalar upper = positions[dimIdx][zoneIdx+1];
177 const int numCells = cells[dimIdx][zoneIdx];
178 Scalar gradingFactor = grading[dimIdx][zoneIdx];
179 const Scalar length = upper - lower;
180 Scalar height = 1.0;
181 bool increasingCellSize = false;
182
183 if (verbose)
184 {
185 std::cout << "dim " << dimIdx
186 << " lower " << lower
187 << " upper " << upper
188 << " numCells " << numCells
189 << " grading " << gradingFactor;
190 }
191
192 if (gradingFactor > 1.0)
193 increasingCellSize = true;
194
195 // take absolute values and reverse cell size increment to achieve
196 // reverse behavior for negative values
197 if (gradingFactor < 0.0)
198 {
199 using std::abs;
200 gradingFactor = abs(gradingFactor);
201
202 if (gradingFactor < 1.0)
203 increasingCellSize = true;
204 }
205
206 const bool useGrading = Dune::FloatCmp::eq(gradingFactor, 1.0) ? false : true;
207
208 // if the grading factor is exactly 1.0 do equal spacing
209 if (!useGrading)
210 {
211 height = 1.0 / numCells;
212 if (verbose)
213 std::cout << " -> h " << height * length << std::endl;
214 }
215 // if grading factor is not 1.0, do power law spacing
216 else
217 {
218 height = (1.0 - gradingFactor) / (1.0 - power(gradingFactor, numCells));
219
220 if (verbose)
221 {
222 std::cout << " -> grading_eff " << gradingFactor
223 << " h_min " << height * power(gradingFactor, 0) * length
224 << " h_max " << height * power(gradingFactor, numCells-1) * length
225 << std::endl;
226 }
227 }
228
229 // the positions inside a global segment
230 Dune::DynamicVector<Scalar> localPositions(numCells, 0.0);
231 for (int i = 1; i < numCells; i++)
232 {
233 Scalar hI = height;
234 if (useGrading)
235 {
236 if (increasingCellSize)
237 hI *= power(gradingFactor, i-1);
238
239 else
240 hI *= power(gradingFactor, numCells-i);
241 }
242 localPositions[i] = localPositions[i-1] + hI;
243 }
244
245 localPositions *= length;
246 localPositions += lower;
247
248 for (int i = 0; i < numCells; ++i)
249 globalPositions[dimIdx][posIdx++] = localPositions[i];
250 }
251
252 globalPositions[dimIdx][posIdx] = positions[dimIdx].back();
253 }
254
255 polarCoordinates[0] = globalPositions[indices[0]];
256 polarCoordinates[1] = globalPositions[indices[1]];
257 if (dim == 3)
258 polarCoordinates[2] = globalPositions[dim - indices[0] - indices[1]];
259
260 // convert angular coordinates into radians
261 std::transform(polarCoordinates[1].begin(), polarCoordinates[1].end(),
262 polarCoordinates[1].begin(),
263 [](Scalar s){ return s*M_PI/180; });
264 }
265
274 std::unique_ptr<Grid> createCakeGrid(std::array<std::vector<Scalar>, dim> &polarCoordinates,
275 Dune::FieldVector<int, dim> &indices,
276 const std::string& modelParamGroup,
277 bool verbose = false)
278 {
279 std::vector<Scalar> dR = polarCoordinates[0];
280 std::vector<Scalar> dA = polarCoordinates[1];
281
282 // For the special case of 360°, the last element is connected with the first one.
283 // Thus, one needs to distinguish here between all other cases, were the normal procedure
284 // is applied for all elements until the last one (= dA.size() - 1) and the 360° case,
285 // where it is only applied until the second to last element (dA.size() - 2).
286 int maxdA = dA.size() - 1;
287 if (Dune::FloatCmp::eq(dA[dA.size()-1], 2*M_PI))
288 {
289 maxdA = dA.size() - 2;
290 }
291
292 GridFactory gridFactory;
293 constexpr auto type = Dune::GeometryTypes::cube(dim);
294
295 bool hasHole = true;
296 if(dR[0] < 1.0e-8*dR.back())
297 hasHole = false;
298
299 // create nodes
300 if (dim == 3)
301 {
302 constexpr auto prismType = Dune::GeometryTypes::prism;
303 std::vector<Scalar> dZ = polarCoordinates[2];
304 for (int j = 0; j <= maxdA; ++j)
305 {
306 for (int l = 0; l <= dZ.size() - 1; ++l)
307 {
308 for (int i = hasHole ? 0 : 1; i <= dR.size()- 1; ++i)
309 {
310 // transform into Cartesian coordinates
311 using std::cos;
312 using std::sin;
313 Dune::FieldVector <double, dim> v(0.0);
314 v[indices[2]] = dZ[l];
315 v[indices[0]] = cos(dA[j])*dR[i];
316 v[indices[1]] = sin(dA[j])*dR[i];
317 if (verbose)
319 gridFactory.insertVertex(v);
320 }
321 }
322 }
323
324 // if the well is not considered, we have to add the points lying on the center-line
325 // this has to be done separately, otherwise these points would occur multiple times
326 if(!hasHole)
327 {
328 for (int l = 0; l <= dZ.size() - 1; ++l)
329 {
330 Dune::FieldVector <double, dim> v(0.0);
331 v[indices[2]] = dZ[l];
332 v[indices[0]] = 0.0;
333 v[indices[1]] = 0.0;
334
335 if (verbose)
337 gridFactory.insertVertex(v);
338 }
339 }
340
341 if (verbose)
342 std::cout << "Filled node vector" << std::endl;
343
344 // assign nodes
345 unsigned int z = 0;
346 unsigned int t = 0;
347 unsigned int rSize = hasHole ? dR.size() : dR.size()-1;
348 unsigned int zSize = dZ.size();
349 for (int j = 0; j < dA.size() - 1; ++j)
350 {
351 for (int l = 0; l < dZ.size() - 1; ++l)
352 {
353 if (j < maxdA)
354 {
355 for (int i = 0; i < dR.size() - 1; ++i)
356 {
357 if(!hasHole && i==0)
358 {
359 std::vector<unsigned int> vid({rSize*zSize*(maxdA+1) + l, z, z+rSize*zSize,
360 rSize*zSize*(maxdA+1) + l+1, z+rSize, z+rSize*zSize+rSize});
361
362 if (verbose)
363 printIndices(vid);
364
365 gridFactory.insertElement(prismType, vid);
366 }
367 else
368 {
369 std::vector<unsigned int> vid({z, z+1,
370 z+rSize*zSize, z+rSize*zSize+1,
371 z+rSize, z+rSize+1,
372 z+rSize*zSize+rSize, z+rSize*zSize+rSize+1});
373
374 if (verbose)
375 printIndices(vid);
376
377 gridFactory.insertElement(type, vid);
378
379 z++;
380 }
381 }
382 z++;
383 }
384 else
385 {
386 // assign nodes for 360°-cake
387 for (int i = 0; i < dR.size() - 1; ++i)
388 {
389 if(!hasHole && i==0)
390 {
391 std::vector<unsigned int> vid({rSize*zSize*(maxdA+1) + l, z, t,
392 rSize*zSize*(maxdA+1) + l+1, z+rSize, t+rSize});
393
394 if (verbose)
395 printIndices(vid);
396
397 gridFactory.insertElement(prismType, vid);
398 }
399 else
400 {
401 std::vector<unsigned int> vid({z, z+1,
402 t, t+1,
403 z+rSize, z+rSize+1,
404 t+rSize, t+rSize+1});
405
406 if (verbose)
407 printIndices(vid);
408
409 gridFactory.insertElement(type, vid);
410 t++;
411 z++;
412 }
413 }
414 t++;
415 z++;
416
417 if (verbose)
418 std::cout << "assign nodes 360° ends..." << std::endl;
419 }
420 }
421 z += rSize;
422 }
423 }
424 // for dim = 2
425 else
426 {
427 constexpr auto triangleType = Dune::GeometryTypes::simplex(dim);
428 for (int j = 0; j <= maxdA; ++j)
429 {
430 for (int i = hasHole ? 0 : 1; i <= dR.size()- 1; ++i)
431 {
432 // transform into Cartesian coordinates
433 Dune::FieldVector <double, dim> v(0.0);
434
435 v[indices[0]] = cos(dA[j])*dR[i];
436 v[indices[1]] = sin(dA[j])*dR[i];
437 if(verbose)
439 gridFactory.insertVertex(v);
440 }
441 }
442
443 // if the well is not considered, we have to add the point located at the center
444 // this has to be done separately, otherwise this point would occur multiple times
445 if(!hasHole)
446 {
447 Dune::FieldVector <double, dim> v(0.0);
448 v[indices[0]] = 0.0;
449 v[indices[1]] = 0.0;
450
451 if(verbose)
453 gridFactory.insertVertex(v);
454 }
455
456 std::cout << "Filled node vector" << std::endl;
457
458 // assign nodes
459 unsigned int z = 0;
460 unsigned int t = 0;
461 unsigned int rSize = hasHole ? dR.size() : dR.size()-1;
462 for (int j = 0; j < dA.size() - 1; ++j)
463 {
464 if (j < maxdA)
465 {
466 for (int i = 0; i < dR.size() - 1; ++i)
467 {
468 if(!hasHole && i==0)
469 {
470 std::vector<unsigned int> vid({rSize*(maxdA+1), z, z+rSize});
471
472 if (verbose)
473 printIndices(vid);
474
475 gridFactory.insertElement(triangleType, vid);
476 }
477 else
478 {
479 std::vector<unsigned int> vid({z, z+1, z+rSize, z+rSize+1});
480
481 if (verbose)
482 printIndices(vid);
483
484 gridFactory.insertElement(type, vid);
485 z++;
486 }
487 }
488 z++;
489 }
490 else
491 {
492 // assign nodes for 360°-cake
493 for (int i = 0; i < dR.size() - 1; ++i)
494 {
495 if(!hasHole && i==0)
496 {
497 std::vector<unsigned int> vid({rSize*(maxdA+1), z, t});
498
499 if (verbose)
500 printIndices(vid);
501
502 gridFactory.insertElement(triangleType, vid);
503 }
504 else
505 {
506 std::vector<unsigned int> vid({z, z+1, t, t+1});
507
508 if (verbose)
509 printIndices(vid);
510
511 gridFactory.insertElement(type, vid);
512 t++;
513 z++;
514 }
515 }
516 t++;
517 z++;
518
519 if (verbose)
520 std::cout << "assign nodes 360 ends..." << std::endl;
521 }
522 }
523 }
524 // return the grid pointer
525 return std::unique_ptr<Grid>(gridFactory.createGrid());
526 }
527
531 Grid& grid()
532 {
533 return *gridPtr();
534 }
535
541 {
542 gridPtr()->loadBalance();
543 }
544
545protected:
546 static void printCoordinate(const Dune::FieldVector <double, dim>& v)
547 {
548 std::cout << "Coordinates of : ";
549 for (int k = 0; k < v.size(); ++k)
550 std::cout << v[k] << " ";
551 std::cout << std::endl;
552 }
553
554 static void printIndices(const std::vector<unsigned int>& vid)
555 {
556 std::cout << "element vertex indices: ";
557 for (int k = 0; k < vid.size(); ++k)
558 std::cout << vid[k] << " ";
559 std::cout << std::endl;
560 }
561
565 GridPointer& gridPtr()
566 {
567 return cakeGrid_;
568 }
569
570private:
571 GridPointer cakeGrid_;
572};
573
574} // end namespace Dumux
575
576#endif
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
bool hasParamInGroup(const std::string &paramGroup, const std::string &param)
Check whether a key exists in the parameter tree with a model group prefix.
Definition: parameters.hh:374
Definition: adapt.hh:29
Provides a grid manager with a method for creating creating vectors with polar Coordinates and one fo...
Definition: cakegridmanager.hh:48
void init(const std::string &modelParamGroup="")
Make the grid.
Definition: cakegridmanager.hh:61
void loadBalance()
Distributes the grid on all processes of a parallel computation.
Definition: cakegridmanager.hh:540
GridPointer & gridPtr()
Returns a reference to the shared pointer to the grid.
Definition: cakegridmanager.hh:565
static void printCoordinate(const Dune::FieldVector< double, dim > &v)
Definition: cakegridmanager.hh:546
static void printIndices(const std::vector< unsigned int > &vid)
Definition: cakegridmanager.hh:554
Grid & grid()
Returns a reference to the grid.
Definition: cakegridmanager.hh:531
static void createVectors(std::array< std::vector< Scalar >, dim > &polarCoordinates, Dune::FieldVector< int, dim > &indices, const std::string &modelParamGroup, bool verbose=false)
Create vectors containing polar coordinates of all points.
Definition: cakegridmanager.hh:96
std::unique_ptr< Grid > createCakeGrid(std::array< std::vector< Scalar >, dim > &polarCoordinates, Dune::FieldVector< int, dim > &indices, const std::string &modelParamGroup, bool verbose=false)
Creates Cartesian grid from polar coordinates.
Definition: cakegridmanager.hh:274