3.1-git
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/grid/common/gridfactory.hh>
36
37namespace Dumux {
38
45template <class Grid>
47{
48 using Scalar = typename Grid::ctype;
49
50 using GridFactory = Dune::GridFactory<Grid>;
51 using GridPointer = std::shared_ptr<Grid>;
52
53 enum { dim = Grid::dimension,
54 dimWorld = Grid::dimensionworld };
55
56public:
60 void init(const std::string& modelParamGroup = "")
61 {
62 static_assert(dim == 2 || dim == 3, "The CakeGridManager is only implemented for 2D and 3D.");
63
64 const bool verbose = getParamFromGroup<bool>(modelParamGroup, "Grid.Verbosity", false);
65
66 std::array<std::vector<Scalar>, dim> polarCoordinates;
67 // Indices specifing in which direction the piece of cake is oriented
68 Dune::FieldVector<int, dim> indices(-1);
69 createVectors(polarCoordinates, indices, modelParamGroup, verbose);
70
71 gridPtr() = createCakeGrid(polarCoordinates, indices, modelParamGroup, verbose);
73 }
74
95 static void createVectors(std::array<std::vector<Scalar>, dim> &polarCoordinates,
96 Dune::FieldVector<int, dim> &indices,
97 const std::string& modelParamGroup,
98 bool verbose = false)
99 {
100 // The positions
101 std::array<std::vector<Scalar>, dim> positions;
102
103 for (int i = 0; i < dim; ++i)
104 {
105 const bool hasRadial = hasParamInGroup(modelParamGroup, "Grid.Radial" + std::to_string(i));
106 const bool hasAngular = hasParamInGroup(modelParamGroup, "Grid.Angular" + std::to_string(i));
107 const bool hasAxial = (dim == 3) && hasParamInGroup(modelParamGroup, "Grid.Axial" + std::to_string(i));
108 if (static_cast<int>(hasRadial) + static_cast<int>(hasAngular) + static_cast<int>(hasAxial) != 1)
109 DUNE_THROW(Dune::RangeError, "Multiple or no position vectors (radial, angular, axial) specified in coord direction: " << i << std::endl);
110
111 if (hasRadial)
112 {
113 positions[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Radial" + std::to_string(i));
114 indices[0] = i; // Index specifing radial direction
115 }
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 specifing angular direction
121 }
122
123 else // hasAxial
124 {
125 positions[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Axial" + std::to_string(i));
126 indices[2] = i; // Index specifing axial direction
127 }
128
129 if (!std::is_sorted(positions[i].begin(), positions[i].end()))
130 DUNE_THROW(Dune::GridError, "Make sure to specify a monotone increasing \"Positions\" array");
131 }
132
133 // check that all indices are specified i.e. > 0
134 for (int i = 0; i < dim; ++i)
135 if (indices[i] < 0)
136 DUNE_THROW(Dune::RangeError, "Please specify Positions Angular and Radial and Axial correctly and unambiguously!" << std::endl);
137
138 // the number of cells (has a default)
139 std::array<std::vector<int>, dim> cells;
140 for (int i = 0; i < dim; ++i)
141 {
142 cells[i].resize(positions[i].size()-1, 1.0);
143 cells[i] = getParamFromGroup<std::vector<int>>(modelParamGroup, "Grid.Cells" + std::to_string(i), cells[i]);
144 if (cells[i].size() + 1 != positions[i].size())
145 DUNE_THROW(Dune::RangeError, "Make sure to specify the correct length of \"Cells\" and \"Positions\" arrays");
146 }
147
148 // grading factor (has a default)
149 std::array<std::vector<Scalar>, dim> grading;
150 for (int i = 0; i < dim; ++i)
151 {
152 grading[i].resize(positions[i].size()-1, 1.0);
153 grading[i] = getParamFromGroup<std::vector<Scalar>>(modelParamGroup, "Grid.Grading" + std::to_string(i), grading[i]);
154 if (grading[i].size() + 1 != positions[i].size())
155 DUNE_THROW(Dune::RangeError, "Make sure to specify the correct length of \"Grading\" and \"Positions\" arrays");
156 }
157
158 // make the grid
159 std::array<std::vector<Scalar>, dim> globalPositions;
160 using std::pow;
161 for (int dimIdx = 0; dimIdx < dim; dimIdx++)
162 {
163 std::size_t numGlobalPositions = 0;
164 for (int zoneIdx = 0; zoneIdx < cells[dimIdx].size(); ++zoneIdx)
165 numGlobalPositions += cells[dimIdx][zoneIdx] + 1;
166
167 globalPositions[dimIdx].resize(numGlobalPositions);
168 std::size_t posIdx = 0;
169 for (int zoneIdx = 0; zoneIdx < cells[dimIdx].size(); ++zoneIdx)
170 {
171 const Scalar lower = positions[dimIdx][zoneIdx];
172 const Scalar upper = positions[dimIdx][zoneIdx+1];
173 const int numCells = cells[dimIdx][zoneIdx];
174 Scalar gradingFactor = grading[dimIdx][zoneIdx];
175 const Scalar length = upper - lower;
176 Scalar height = 1.0;
177 bool increasingCellSize = false;
178
179 if (verbose)
180 {
181 std::cout << "dim " << dimIdx
182 << " lower " << lower
183 << " upper " << upper
184 << " numCells " << numCells
185 << " grading " << gradingFactor;
186 }
187
188 if (gradingFactor > 1.0)
189 increasingCellSize = true;
190
191 // take absolute values and reverse cell size increment to achieve
192 // reverse behavior for negative values
193 if (gradingFactor < 0.0)
194 {
195 using std::abs;
196 gradingFactor = abs(gradingFactor);
197
198 if (gradingFactor < 1.0)
199 increasingCellSize = true;
200 }
201
202 // if the grading factor is exactly 1.0 do equal spacing
203 if (gradingFactor > 1.0 - 1e-7 && gradingFactor < 1.0 + 1e-7)
204 {
205 height = 1.0 / numCells;
206 if (verbose)
207 std::cout << " -> h " << height * length << std::endl;
208 }
209
210 // if grading factor is not 1.0, do power law spacing
211 else
212 {
213 height = (1.0 - gradingFactor) / (1.0 - pow(gradingFactor, numCells));
214
215 if (verbose)
216 {
217 std::cout << " -> grading_eff " << gradingFactor
218 << " h_min " << height * pow(gradingFactor, 0) * length
219 << " h_max " << height * pow(gradingFactor, numCells-1) * length
220 << std::endl;
221 }
222 }
223
224 // the positions inside a global segment
225 Dune::DynamicVector<Scalar> localPositions(numCells, 0.0);
226 for (int i = 1; i < numCells; i++)
227 {
228 Scalar hI = height;
229 if (!(gradingFactor < 1.0 + 1e-7 && gradingFactor > 1.0 - 1e-7))
230 {
231 if (increasingCellSize)
232 hI *= pow(gradingFactor, i-1);
233
234 else
235 hI *= pow(gradingFactor, numCells-i);
236 }
237 localPositions[i] = localPositions[i-1] + hI;
238 }
239
240 localPositions *= length;
241 localPositions += lower;
242
243 for (int i = 0; i < numCells; ++i)
244 globalPositions[dimIdx][posIdx++] = localPositions[i];
245 }
246
247 globalPositions[dimIdx][posIdx] = positions[dimIdx].back();
248 }
249
250 polarCoordinates[0] = globalPositions[indices[0]];
251 polarCoordinates[1] = globalPositions[indices[1]];
252 if (dim == 3)
253 polarCoordinates[2] = globalPositions[dim - indices[0] - indices[1]];
254
255 // convert angular coordinates into radians
256 std::transform(polarCoordinates[1].begin(), polarCoordinates[1].end(),
257 polarCoordinates[1].begin(),
258 [](Scalar s){ return s*M_PI/180; });
259 }
260
269 std::unique_ptr<Grid> createCakeGrid(std::array<std::vector<Scalar>, dim> &polarCoordinates,
270 Dune::FieldVector<int, dim> &indices,
271 const std::string& modelParamGroup,
272 bool verbose = false)
273 {
274 std::vector<Scalar> dR = polarCoordinates[0];
275 std::vector<Scalar> dA = polarCoordinates[1];
276
277 // For the special case of 36o°, the last element is connected with the first one.
278 // Thus, one needs to distinguish here between all other cases, were the normal procedure
279 // is applied for all elements until the last one (= dA.size() - 1) and the 360° case,
280 // where it is only applied until the second to last element (dA.size() - 2).
281 int maxdA = dA.size() - 1;
282 if (Dune::FloatCmp::eq(polarCoordinates[1][polarCoordinates[1].size()-1], 360.0))
283 {
284 maxdA = dA.size() - 2;
285 }
286
287 GridFactory gridFactory;
288 constexpr auto type = Dune::GeometryTypes::cube(dim);
289
290 // create nodes
291 if (dim == 3)
292 {
293 std::vector<Scalar> dZ = polarCoordinates[2];
294 for (int j = 0; j <= dA.size() - 1; ++j)
295 {
296 for (int l = 0; l <= dZ.size() - 1; ++l)
297 {
298 for (int i = 0; i <= dR.size()- 1; ++i)
299 {
300 // Get radius for the well (= a hole) in the center
301 const auto wellRadius = getParamFromGroup<Scalar>(modelParamGroup, "Grid.WellRadius");
302
303 // transform into cartesian Coordinates
304 using std::cos;
305 using std::sin;
306 Dune::FieldVector <double, dim> v(0.0);
307 v[indices[2]] = dZ[l];
308 v[indices[0]] = cos(dA[j])*wellRadius + cos(dA[j])*dR[i];
309 v[indices[1]] = sin(dA[j])*wellRadius + sin(dA[j])*dR[i];
310 if (verbose)
311 {
312 std::cout << "Coordinates of : "
313 << v[0] << " " << v[1] << " " << v[2] << std::endl;
314 }
315 gridFactory.insertVertex(v);
316 }
317 }
318 }
319
320 if (verbose)
321 std::cout << "Filled node vector" << std::endl;
322
323 // assign nodes
324 unsigned int z = 0;
325 unsigned int t = 0;
326 for (int j = 0; j < dA.size() - 1; ++j)
327 {
328 for (int l = 0; l < dZ.size() - 1; ++l)
329 {
330 if (j < maxdA)
331 {
332 for (int i = 0; i < dR.size() - 1; ++i)
333 {
334 unsigned int rSize = dR.size();
335 unsigned int zSize = dZ.size();
336 std::vector<unsigned int> vid({z, z+1, z+rSize*zSize,
337 z+rSize*zSize+1, z+rSize, z+rSize+1,
338 z+rSize*zSize+rSize, z+rSize*zSize+rSize+1});
339
340 if (verbose)
341 {
342 std::cout << "element vertex ids: ";
343 for (int k = 0; k < vid.size(); ++k)
344 std::cout << vid[k] << " ";
345 std::cout << std::endl;
346 }
347
348 gridFactory.insertElement(type, vid);
349
350 z = z+1;
351 }
352 z = z+1;
353 }
354 else
355 {
356 // assign nodes for 360°-cake
357 for (int i = 0; i < dR.size() - 1; ++i)
358 {
359 // z = z + 1;
360 unsigned int rSize = dR.size();
361 std::vector<unsigned int> vid({z, z+1, t,
362 t+1, z+rSize, z+rSize+1,
363 t+rSize, t+rSize+1});
364
365 if (verbose)
366 {
367 std::cout << "element vertex ids: ";
368 for (int k = 0; k < vid.size(); ++k)
369 std::cout << vid[k] << " ";
370 std::cout << std::endl;
371 }
372
373 gridFactory.insertElement(type, vid);
374 t = t + 1;
375 z = z+1;
376 }
377 t = t + 1;
378 z = z+1;
379 }
380 if (verbose)
381 std::cout << "assign nodes 360° ends..." << std::endl;
382 }
383
384 z = z + dR.size();
385 }
386 }
387
388 // for dim = 2
389 else
390 {
391 for (int j = 0; j <= dA.size() - 1; ++j)
392 {
393 for (int i = 0; i <= dR.size()- 1; ++i)
394 {
395 // Get radius for the well (= a hole) in the center
396 const Scalar wellRadius = getParamFromGroup<Scalar>(modelParamGroup, "Grid.WellRadius");
397
398 // transform into cartesian Coordinates
399 Dune::FieldVector <double, dim> v(0.0);
400
401 v[indices[0]] = cos(dA[j])*wellRadius + cos(dA[j])*dR[i];
402 v[indices[1]] = sin(dA[j])*wellRadius + sin(dA[j])*dR[i];
403 if(verbose) std::cout << "Coordinates of : " << v[0] << " " << v[1] << std::endl;
404 gridFactory.insertVertex(v);
405 }
406 }
407 std::cout << "Filled node vector" << std::endl;
408
409 // assign nodes
410 unsigned int z = 0;
411 unsigned int t = 0;
412 for (int j = 0; j < dA.size() - 1; ++j)
413 {
414 if (j < maxdA)
415 {
416 for (int i = 0; i < dR.size() - 1; ++i)
417 {
418 unsigned int rSize = dR.size();
419 std::vector<unsigned int> vid({z, z+1, z+rSize, z+rSize+1});
420
421 if (verbose)
422 {
423 std::cout << "element vertex ids: ";
424 for (int k = 0; k < vid.size(); ++k)
425 std::cout << vid[k] << " ";
426 std::cout << std::endl;
427 }
428
429 gridFactory.insertElement(type, vid);
430 z = z+1;
431 }
432 z = z+1;
433 }
434 else
435 {
436 // assign nodes for 360°-cake
437 for (int i = 0; i < dR.size() - 1; ++i)
438 {
439 // z = z + 1;
440 std::vector<unsigned int> vid({z, z+1, t, t+1});
441
442 if (verbose)
443 {
444 std::cout << "element vertex ids: ";
445 for (int k = 0; k < vid.size(); ++k)
446 std::cout << vid[k] << " ";
447 std::cout << std::endl;
448 }
449
450 gridFactory.insertElement(type, vid);
451 t = t + 1;
452 z = z+1;
453 }
454 t = t + 1;
455 z = z+1;
456 }
457 std::cout << "assign nodes 360 ends..." << std::endl;
458 }
459 }
460 // return the grid pointer
461 return std::unique_ptr<Grid>(gridFactory.createGrid());
462 }
463
467 Grid& grid()
468 {
469 return *gridPtr();
470 }
471
477 {
478 gridPtr()->loadBalance();
479 }
480
481protected:
482
486 GridPointer& gridPtr()
487 {
488 return cakeGrid_;
489 }
490
491private:
492 GridPointer cakeGrid_;
493};
494
495} // end namespace Dumux
496
497#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:454
make the local view function available whenever we use the grid geometry
Definition: adapt.hh:29
Provides a grid manager with a method for creating creating vectors with polar Coordinates and one fo...
Definition: cakegridmanager.hh:47
void init(const std::string &modelParamGroup="")
Make the grid.
Definition: cakegridmanager.hh:60
void loadBalance()
Distributes the grid on all processes of a parallel computation.
Definition: cakegridmanager.hh:476
GridPointer & gridPtr()
Returns a reference to the shared pointer to the grid.
Definition: cakegridmanager.hh:486
Grid & grid()
Returns a reference to the grid.
Definition: cakegridmanager.hh:467
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:95
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:269