version 3.11-dev
Loading...
Searching...
No Matches
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// SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
13#ifndef DUMUX_CAKE_GRID_MANAGER_HH
14#define DUMUX_CAKE_GRID_MANAGER_HH
15
16#include <vector>
17#include <iostream>
18#include <cmath>
19#include <algorithm>
20
21#include <dune/common/dynvector.hh>
22#include <dune/common/float_cmp.hh>
23#include <dune/common/math.hh>
24#include <dune/grid/common/gridfactory.hh>
26
27namespace Dumux {
28
53template <class Grid>
55{
56 using Scalar = typename Grid::ctype;
57
58 using GridFactory = Dune::GridFactory<Grid>;
59 using GridPointer = std::shared_ptr<Grid>;
60
61 enum { dim = Grid::dimension,
62 dimWorld = Grid::dimensionworld };
63
64public:
68 void init(const std::string& modelParamGroup = "")
69 {
70 static_assert(dim == 2 || dim == 3, "The CakeGridManager is only implemented for 2D and 3D.");
71
72 const bool verbose = getParamFromGroup<bool>(modelParamGroup, "Grid.Verbosity", false);
73
74 std::array<std::vector<Scalar>, dim> polarCoordinates;
75 // Indices specifying in which direction the piece of cake is oriented
76 Dune::FieldVector<int, dim> indices(-1);
77 createVectors(polarCoordinates, indices, modelParamGroup, verbose);
78
79 gridPtr() = createCakeGrid(polarCoordinates, indices, modelParamGroup, verbose);
81 }
82
86 static void createVectors(std::array<std::vector<Scalar>, dim> &polarCoordinates,
87 Dune::FieldVector<int, dim> &indices,
88 const std::string& modelParamGroup,
89 bool verbose = false)
90 {
91 // The positions
92 std::array<std::vector<Scalar>, dim> positions;
93
94 for (int i = 0; i < dim; ++i)
95 {
96 const bool hasRadial = hasParamInGroup(modelParamGroup, "Grid.Radial" + std::to_string(i));
97 const bool hasAngular = hasParamInGroup(modelParamGroup, "Grid.Angular" + std::to_string(i));
98 const bool hasAxial = (dim == 3) && hasParamInGroup(modelParamGroup, "Grid.Axial" + std::to_string(i));
99 if (static_cast<int>(hasRadial) + static_cast<int>(hasAngular) + static_cast<int>(hasAxial) != 1)
100 DUNE_THROW(Dune::RangeError, "Multiple or no position vectors (radial, angular, axial) specified in coord direction: " << i << std::endl);
101
102 if (hasRadial)
103 {
104 positions[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Radial" + std::to_string(i));
105 indices[0] = i; // Index specifying radial direction
106 }
107 else if (hasAngular)
108 {
109 positions[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Angular" + std::to_string(i));
110 indices[1] = i; // Index specifying angular direction
111 }
112 else // hasAxial
113 {
114 positions[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Axial" + std::to_string(i));
115 indices[2] = i; // Index specifying axial direction
116 }
117
118 if (!std::is_sorted(positions[i].begin(), positions[i].end()))
119 DUNE_THROW(Dune::GridError, "Make sure to specify a monotone increasing \"Positions\" array");
120
121 if(positions[i].size() < 2)
122 DUNE_THROW(Dune::GridError, "Make sure to specify position arrays with at least two entries (min and max value).");
123 }
124
125 // check that all indices are specified i.e. > 0
126 for (int i = 0; i < dim; ++i)
127 if (indices[i] < 0)
128 DUNE_THROW(Dune::RangeError, "Please specify Positions Angular and Radial and Axial correctly and unambiguously!" << std::endl);
129
130 // the number of cells (has a default)
131 std::array<std::vector<int>, dim> cells;
132 for (int i = 0; i < dim; ++i)
133 {
134 cells[i].resize(positions[i].size()-1, 1.0);
135 cells[i] = getParamFromGroup<std::vector<int>>(modelParamGroup, "Grid.Cells" + std::to_string(i), cells[i]);
136 if (cells[i].size() + 1 != positions[i].size())
137 DUNE_THROW(Dune::RangeError, "Make sure to specify the correct length of \"Cells\" and \"Positions\" arrays");
138 }
139
140 // grading factor (has a default)
141 std::array<std::vector<Scalar>, dim> grading;
142 for (int i = 0; i < dim; ++i)
143 {
144 grading[i].resize(positions[i].size()-1, 1.0);
145 grading[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Grading" + std::to_string(i), grading[i]);
146 if (grading[i].size() + 1 != positions[i].size())
147 DUNE_THROW(Dune::RangeError, "Make sure to specify the correct length of \"Grading\" and \"Positions\" arrays");
148 }
149
150 // make the grid
151 std::array<std::vector<Scalar>, dim> globalPositions;
152 using std::pow;
153 using Dune::power;
154 for (int dimIdx = 0; dimIdx < dim; dimIdx++)
155 {
156 // Each grid direction is subdivided into (numCells + 1) points
157 std::size_t numGlobalPositions = 1;
158 for (int zoneIdx = 0; zoneIdx < cells[dimIdx].size(); ++zoneIdx)
159 numGlobalPositions += cells[dimIdx][zoneIdx];
160
161 globalPositions[dimIdx].resize(numGlobalPositions);
162 std::size_t posIdx = 0;
163 for (int zoneIdx = 0; zoneIdx < cells[dimIdx].size(); ++zoneIdx)
164 {
165 const Scalar lower = positions[dimIdx][zoneIdx];
166 const Scalar upper = positions[dimIdx][zoneIdx+1];
167 const int numCells = cells[dimIdx][zoneIdx];
168 Scalar gradingFactor = grading[dimIdx][zoneIdx];
169 const Scalar length = upper - lower;
170 Scalar height = 1.0;
171 bool increasingCellSize = false;
172
173 if (verbose)
174 {
175 std::cout << "dim " << dimIdx
176 << " lower " << lower
177 << " upper " << upper
178 << " numCells " << numCells
179 << " grading " << gradingFactor;
180 }
181
182 if (gradingFactor > 1.0)
183 increasingCellSize = true;
184
185 // take absolute values and reverse cell size increment to achieve
186 // reverse behavior for negative values
187 if (gradingFactor < 0.0)
188 {
189 using std::abs;
190 gradingFactor = abs(gradingFactor);
191
192 if (gradingFactor < 1.0)
193 increasingCellSize = true;
194 }
195
196 const bool useGrading = Dune::FloatCmp::eq(gradingFactor, 1.0) ? false : true;
197
198 // if the grading factor is exactly 1.0 do equal spacing
199 if (!useGrading)
200 {
201 height = 1.0 / numCells;
202 if (verbose)
203 std::cout << " -> h " << height * length << std::endl;
204 }
205 // if grading factor is not 1.0, do power law spacing
206 else
207 {
208 height = (1.0 - gradingFactor) / (1.0 - power(gradingFactor, numCells));
209
210 if (verbose)
211 {
212 std::cout << " -> grading_eff " << gradingFactor
213 << " h_min " << height * power(gradingFactor, 0) * length
214 << " h_max " << height * power(gradingFactor, numCells-1) * length
215 << std::endl;
216 }
217 }
218
219 // the positions inside a global segment
220 Dune::DynamicVector<Scalar> localPositions(numCells, 0.0);
221 for (int i = 1; i < numCells; i++)
222 {
223 Scalar hI = height;
224 if (useGrading)
225 {
226 if (increasingCellSize)
227 hI *= power(gradingFactor, i-1);
228
229 else
230 hI *= power(gradingFactor, numCells-i);
231 }
232 localPositions[i] = localPositions[i-1] + hI;
233 }
234
235 localPositions *= length;
236 localPositions += lower;
237
238 for (int i = 0; i < numCells; ++i)
239 globalPositions[dimIdx][posIdx++] = localPositions[i];
240 }
241
242 globalPositions[dimIdx][posIdx] = positions[dimIdx].back();
243 }
244
245 polarCoordinates[0] = globalPositions[indices[0]];
246 polarCoordinates[1] = globalPositions[indices[1]];
247 if (dim == 3)
248 polarCoordinates[2] = globalPositions[dim - indices[0] - indices[1]];
249
250 // convert angular coordinates into radians
251 std::transform(polarCoordinates[1].begin(), polarCoordinates[1].end(),
252 polarCoordinates[1].begin(),
253 [](Scalar s){ return s*M_PI/180; });
254 }
255
264 std::unique_ptr<Grid> createCakeGrid(std::array<std::vector<Scalar>, dim> &polarCoordinates,
265 Dune::FieldVector<int, dim> &indices,
266 const std::string& modelParamGroup,
267 bool verbose = false)
268 {
269 GridFactory gridFactory;
270
271 // create grid on rank 0, return empty grid on all other ranks
272 if (gridFactory.comm().rank() != 0)
273 return std::unique_ptr<Grid>(gridFactory.createGrid());
274
275 const auto& dR = polarCoordinates[0];
276 const auto& dA = polarCoordinates[1];
277
278 // For the special case of 360°, the last element is connected with the first one.
279 // Thus, one needs to distinguish here between all other cases, were the normal procedure
280 // is applied for all elements until the last one (= dA.size() - 1) and the 360° case,
281 // where it is only applied until the second to last element (dA.size() - 2).
282 const int dAMax = Dune::FloatCmp::eq(dA[dA.size()-1], 2*M_PI) ? dA.size() - 2 : dA.size() - 1;
283 constexpr auto type = Dune::GeometryTypes::cube(dim);
284 const bool hasHole = dR[0] >= 1.0e-8*dR.back();
285
286 // create nodes
287 if constexpr (dim == 3)
288 {
289 constexpr auto prismType = Dune::GeometryTypes::prism;
290 std::vector<Scalar> dZ = polarCoordinates[2];
291 for (int j = 0; j <= dAMax; ++j)
292 {
293 for (int l = 0; l <= dZ.size() - 1; ++l)
294 {
295 for (int i = hasHole ? 0 : 1; i <= dR.size()- 1; ++i)
296 {
297 // transform into Cartesian coordinates
298 using std::cos;
299 using std::sin;
300 Dune::FieldVector <double, dim> v(0.0);
301 v[indices[2]] = dZ[l];
302 v[indices[0]] = cos(dA[j])*dR[i];
303 v[indices[1]] = sin(dA[j])*dR[i];
304 if (verbose)
306 gridFactory.insertVertex(v);
307 }
308 }
309 }
310
311 // if the well is not considered, we have to add the points lying on the center-line
312 // this has to be done separately, otherwise these points would occur multiple times
313 if(!hasHole)
314 {
315 for (int l = 0; l <= dZ.size() - 1; ++l)
316 {
317 Dune::FieldVector <double, dim> v(0.0);
318 v[indices[2]] = dZ[l];
319 v[indices[0]] = 0.0;
320 v[indices[1]] = 0.0;
321
322 if (verbose)
324 gridFactory.insertVertex(v);
325 }
326 }
327
328 if (verbose)
329 std::cout << "Filled node vector" << std::endl;
330
331 // assign nodes
332 unsigned int z = 0;
333 unsigned int t = 0;
334 unsigned int rSize = hasHole ? dR.size() : dR.size()-1;
335 unsigned int zSize = dZ.size();
336 for (int j = 0; j < dA.size() - 1; ++j)
337 {
338 for (int l = 0; l < dZ.size() - 1; ++l)
339 {
340 if (j < dAMax)
341 {
342 for (int i = 0; i < dR.size() - 1; ++i)
343 {
344 if(!hasHole && i==0)
345 {
346 std::vector<unsigned int> vid({rSize*zSize*(dAMax+1) + l, z, z+rSize*zSize,
347 rSize*zSize*(dAMax+1) + l+1, z+rSize, z+rSize*zSize+rSize});
348
349 if (verbose)
350 printIndices(vid);
351
352 gridFactory.insertElement(prismType, vid);
353 }
354 else
355 {
356 std::vector<unsigned int> vid({z, z+1,
357 z+rSize*zSize, z+rSize*zSize+1,
358 z+rSize, z+rSize+1,
359 z+rSize*zSize+rSize, z+rSize*zSize+rSize+1});
360
361 if (verbose)
362 printIndices(vid);
363
364 gridFactory.insertElement(type, vid);
365
366 z++;
367 }
368 }
369 z++;
370 }
371 else
372 {
373 // assign nodes for 360°-cake
374 for (int i = 0; i < dR.size() - 1; ++i)
375 {
376 if(!hasHole && i==0)
377 {
378 std::vector<unsigned int> vid({rSize*zSize*(dAMax+1) + l, z, t,
379 rSize*zSize*(dAMax+1) + l+1, z+rSize, t+rSize});
380
381 if (verbose)
382 printIndices(vid);
383
384 gridFactory.insertElement(prismType, vid);
385 }
386 else
387 {
388 std::vector<unsigned int> vid({z, z+1,
389 t, t+1,
390 z+rSize, z+rSize+1,
391 t+rSize, t+rSize+1});
392
393 if (verbose)
394 printIndices(vid);
395
396 gridFactory.insertElement(type, vid);
397 t++;
398 z++;
399 }
400 }
401 t++;
402 z++;
403
404 if (verbose)
405 std::cout << "assign nodes 360° ends..." << std::endl;
406 }
407 }
408 z += rSize;
409 }
410 }
411
412 // for dim = 2
413 else
414 {
415 constexpr auto triangleType = Dune::GeometryTypes::simplex(dim);
416 for (int j = 0; j <= dAMax; ++j)
417 {
418 for (int i = hasHole ? 0 : 1; i <= dR.size()- 1; ++i)
419 {
420 // transform into Cartesian coordinates
421 Dune::FieldVector <double, dim> v(0.0);
422
423 v[indices[0]] = cos(dA[j])*dR[i];
424 v[indices[1]] = sin(dA[j])*dR[i];
425 if(verbose)
427 gridFactory.insertVertex(v);
428 }
429 }
430
431 // if the well is not considered, we have to add the point located at the center
432 // this has to be done separately, otherwise this point would occur multiple times
433 if(!hasHole)
434 {
435 Dune::FieldVector <double, dim> v(0.0);
436 v[indices[0]] = 0.0;
437 v[indices[1]] = 0.0;
438
439 if(verbose)
441 gridFactory.insertVertex(v);
442 }
443
444 std::cout << "Filled node vector" << std::endl;
445
446 // assign nodes
447 unsigned int z = 0;
448 unsigned int t = 0;
449 unsigned int rSize = hasHole ? dR.size() : dR.size()-1;
450 for (int j = 0; j < dA.size() - 1; ++j)
451 {
452 if (j < dAMax)
453 {
454 for (int i = 0; i < dR.size() - 1; ++i)
455 {
456 if(!hasHole && i==0)
457 {
458 std::vector<unsigned int> vid({rSize*(dAMax+1), z, z+rSize});
459
460 if (verbose)
461 printIndices(vid);
462
463 gridFactory.insertElement(triangleType, vid);
464 }
465 else
466 {
467 std::vector<unsigned int> vid({z, z+1, z+rSize, z+rSize+1});
468
469 if (verbose)
470 printIndices(vid);
471
472 gridFactory.insertElement(type, vid);
473 z++;
474 }
475 }
476 z++;
477 }
478 else
479 {
480 // assign nodes for 360°-cake
481 for (int i = 0; i < dR.size() - 1; ++i)
482 {
483 if(!hasHole && i==0)
484 {
485 std::vector<unsigned int> vid({rSize*(dAMax+1), z, t});
486
487 if (verbose)
488 printIndices(vid);
489
490 gridFactory.insertElement(triangleType, vid);
491 }
492 else
493 {
494 std::vector<unsigned int> vid({z, z+1, t, t+1});
495
496 if (verbose)
497 printIndices(vid);
498
499 gridFactory.insertElement(type, vid);
500 t++;
501 z++;
502 }
503 }
504 t++;
505 z++;
506
507 if (verbose)
508 std::cout << "assign nodes 360 ends..." << std::endl;
509 }
510 }
511 }
512
513 // create the grid
514 return std::unique_ptr<Grid>(gridFactory.createGrid());
515 }
516
521 {
522 return *gridPtr();
523 }
524
530 {
531 gridPtr()->loadBalance();
532 }
533
534protected:
535 static void printCoordinate(const Dune::FieldVector <double, dim>& v)
536 { std::cout << "Coordinates of: " << v << std::endl; }
537
538 static void printIndices(const std::vector<unsigned int>& vid)
539 {
540 std::cout << "element vertex indices: ";
541 for (int k = 0; k < vid.size(); ++k)
542 std::cout << vid[k] << " ";
543 std::cout << std::endl;
544 }
545
549 GridPointer& gridPtr()
550 {
551 return cakeGrid_;
552 }
553
554private:
555 GridPointer cakeGrid_;
556};
557
558} // end namespace Dumux
559
560#endif
Provides a grid manager with a method for creating vectors with polar Coordinates and one for creatin...
Definition cakegridmanager.hh:55
void init(const std::string &modelParamGroup="")
Make the grid.
Definition cakegridmanager.hh:68
void loadBalance()
Distributes the grid on all processes of a parallel computation.
Definition cakegridmanager.hh:529
GridPointer & gridPtr()
Returns a reference to the shared pointer to the grid.
Definition cakegridmanager.hh:549
static void printCoordinate(const Dune::FieldVector< double, dim > &v)
Definition cakegridmanager.hh:535
static void printIndices(const std::vector< unsigned int > &vid)
Definition cakegridmanager.hh:538
Grid & grid()
Returns a reference to the grid.
Definition cakegridmanager.hh:520
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:86
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:264
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition parameters.hh:149
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:165
Definition gridcapabilities.hh:17
Definition adapt.hh:17
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.