24#ifndef DUMUX_IO_STRUCTURED_LATTICE_GRID_CREATOR_HH
25#define DUMUX_IO_STRUCTURED_LATTICE_GRID_CREATOR_HH
34#include <dune/common/concept.hh>
35#include <dune/common/exceptions.hh>
36#include <dune/grid/common/gridfactory.hh>
37#include <dune/grid/yaspgrid.hh>
38#include <dune/geometry/referenceelements.hh>
41#include <dune/foamgrid/foamgrid.hh>
42#include <dune/foamgrid/dgffoam.hh>
56template<
class GlobalPosition>
57struct LowDimElementSelector
60 auto require(F&& f) ->
decltype(
61 bool(f(std::declval<const GlobalPosition&>(), std::declval<const GlobalPosition&>()))
71class StructuredLatticeGridCreator
73 using GridType = Dune::FoamGrid<1, dimWorld>;
74 using Element =
typename GridType::template Codim<0>::Entity;
75 using GlobalPosition =
typename Element::Geometry::GlobalCoordinate;
76 using CoordScalar =
typename GridType::ctype;
78 using HostGridView =
typename HostGrid::LeafGridView;
79 using ReferenceElements =
typename Dune::ReferenceElements<CoordScalar, dimWorld>;
81 using VertexIndexPair = std::pair<unsigned int, unsigned int>;
85 VertexIndexPair localVertexIndices;
86 unsigned int directionNumber;
90 using Grid = GridType;
92 void init(
const std::string& paramGroup =
"")
94 auto useAllElements = [](
const GlobalPosition& a,
const GlobalPosition& b){
return true; };
95 init(useAllElements, paramGroup);
98 template<
class LowDimElementSelector,
99 typename std::enable_if_t<Dune::models<Concept::LowDimElementSelector<GlobalPosition>, LowDimElementSelector>(),
int> = 0>
100 void init(
const LowDimElementSelector& lowDimElementSelector,
101 const std::string& paramGroup =
"")
103 paramGroup_ = paramGroup;
104 removeThroatsOnBoundary_ = getParamFromGroup<std::vector<std::size_t>>(paramGroup,
"Grid.RemoveThroatsOnBoundary",
105 std::vector<std::size_t>());
107 setElementSelector_(lowDimElementSelector);
108 initRandomNumberGenerator_();
111 const auto hostGridInputData = getHostGridInputData_();
113 using HastGridManager = GridManager<HostGrid>;
114 HastGridManager hostGridManager;
115 hostGridManager.init(hostGridInputData.positions, hostGridInputData.cells, hostGridInputData.grading, paramGroup_);
116 hostGridView_ = std::make_unique<HostGridView>(hostGridManager.grid().leafGridView());
118 hostGridLowerLeft_ = hostGridInputData.lowerLeft;
119 hostGridUpperRight_ = hostGridInputData.upperRight;
121 convertHostGridToLowDimGrid_();
129 if (Dune::MPIHelper::getCommunication().size() > 1)
130 gridPtr_->loadBalance();
137 {
return *gridPtr(); }
142 std::shared_ptr<Grid>& gridPtr()
147 template<
class LowDimElementSelector>
148 void setElementSelector_(
const LowDimElementSelector& lowDimElementSelector)
150 if (!removeThroatsOnBoundary_.empty())
152 auto finalSelector = [&](
const GlobalPosition& a,
const GlobalPosition& b)
154 static const auto lambdaToRemoveThroatsOnBoundary = getLambdaToRemoveThroatsOnBoundary_();
156 return min(lambdaToRemoveThroatsOnBoundary(a, b), lowDimElementSelector(a, b));
158 considerLowDimElement_ = finalSelector;
161 considerLowDimElement_ = lowDimElementSelector;
164 void initRandomNumberGenerator_()
166 directionProbability_ = getDirectionProbability_();
170 const auto seed = getParamFromGroup<std::size_t>(paramGroup_,
"Grid.DeletionRandomNumberSeed");
171 generator_.seed(seed);
175 std::random_device rd;
176 generator_.seed(rd());
180 void convertHostGridToLowDimGrid_()
184 for (
const auto& element : elements(*hostGridView_))
186 const auto& geometry =
element.geometry();
187 const auto& refElement = ReferenceElements::general(geometry.type());
188 treatEdges_(element, refElement, geometry);
189 treatDiagonals_(element, refElement, geometry);
191 if (elementSet_.empty())
192 DUNE_THROW(Dune::GridError,
"Trying to create pore network with zero elements!");
195 Dune::GridFactory<Grid> factory;
196 for (
auto&& vertex : vertexSet_)
197 factory.insertVertex(vertex);
198 for (
auto&& element : elementSet_)
199 factory.insertElement(Dune::GeometryTypes::cube(1), {
element.first,
element.second});
201 gridPtr_ = std::shared_ptr<Grid>(factory.createGrid());
204 void resizeContainers_()
206 vertexInserted_.resize(hostGridView_->size(dimWorld),
false);
207 hostVertexIdxToVertexIdx_.resize(hostGridView_->size(dimWorld));
208 edgeInserted_.resize(hostGridView_->size(dimWorld-1),
false);
209 faceInserted_.resize(hostGridView_->size(dimWorld-2),
false);
212 template<
class HostGr
idElement>
213 bool maybeInsertElementAndVertices_(
const HostGridElement& hostGridElement,
214 const typename HostGridElement::Geometry& hostGridElementGeometry,
215 std::size_t localVertexIdx0,
216 std::size_t localVertexIdx1,
217 double directionProbability)
219 if (neglectElement_(hostGridElementGeometry, localVertexIdx0, localVertexIdx1, directionProbability))
223 insertElementAndVertices_(hostGridElement, hostGridElementGeometry, localVertexIdx0, localVertexIdx1, directionProbability);
228 template<
class HostGr
idElement>
229 void insertElementAndVertices_(
const HostGridElement& hostGridElement,
230 const typename HostGridElement::Geometry& hostGridElementGeometry,
231 std::size_t localVertexIdx0,
232 std::size_t localVertexIdx1,
233 double directionProbability)
236 const auto vIdxGlobal0 = hostGridView_->indexSet().subIndex(hostGridElement, localVertexIdx0, dimWorld);
237 const auto vIdxGlobal1 = hostGridView_->indexSet().subIndex(hostGridElement, localVertexIdx1, dimWorld);
239 auto getGobalVertexIdx = [&](
auto globalIdx,
auto localIdx)
241 if (!vertexInserted_[globalIdx])
243 vertexInserted_[globalIdx] =
true;
244 hostVertexIdxToVertexIdx_[globalIdx] = vertexSet_.size();
245 vertexSet_.push_back(hostGridElementGeometry.corner(localIdx));
248 return hostVertexIdxToVertexIdx_[globalIdx];
251 const auto newVertexIdx0 = getGobalVertexIdx(vIdxGlobal0, localVertexIdx0);
252 const auto newVertexIdx1 = getGobalVertexIdx(vIdxGlobal1, localVertexIdx1);
253 elementSet_.emplace_back(newVertexIdx0, newVertexIdx1);
256 auto getDirectionProbability_()
const
258 std::array<double, numDirections_()> directionProbability;
259 directionProbability.fill(0.0);
262 if (getParamFromGroup<bool>(paramGroup_,
"Grid.RegularLattice",
false))
264 directionProbability.fill(1.0);
265 for (
int i = 0; i < dimWorld; ++i)
266 directionProbability[i] = 0.0;
268 return directionProbability;
276 directionProbability = getParamFromGroup<decltype(directionProbability)>(paramGroup_,
"Grid.DeletionProbability");
280 throwDirectionError_();
284 return directionProbability;
287 void throwDirectionError_()
const
290 Dune::FieldVector<std::string, numDirections_()> directions;
294 directions[0] =
"1: (1, 0)\n";
295 directions[1] =
"2: (0, 1)\n";
297 directions[2] =
"3: (1, 1)\n";
298 directions[3] =
"4: (1, -1)\n";
303 directions[0] =
" 1: (1, 0, 0)\n";
304 directions[1] =
"2: (0, 1, 0)\n";
305 directions[2] =
"3: (0, 0, 1)\n";
307 directions[3] =
"4: (1, 1, 0)\n";
308 directions[4] =
"5: (1, -1, 0)\n";
309 directions[5] =
"6: (1, 0, 1)\n";
310 directions[6] =
"7: (1, 0, -1)\n";
311 directions[7] =
"8: (0, 1, 1)\n";
312 directions[8] =
"9: (0, 1, -1)\n";
314 directions[9] =
"10: (1, 1, 1)\n";
315 directions[10] =
"11: (1, 1, -1)\n";
316 directions[11] =
"12: (-1, 1, 1)\n";
317 directions[12] =
"13: (-1, -1, 1)\n";
319 DUNE_THROW(ParameterException,
"You must specify probabilities for all directions (" << numDirections_() <<
") \n" << directions <<
"\nExample (3D):\n\n"
320 <<
"DeletionProbability = 0.5 0.5 0 0 0 0 0 0 0 0 0 0 0 \n\n"
321 <<
"deletes approximately 50% of all throats in x and y direction, while no deletion in any other direction takes place.\n" );
324 static constexpr std::size_t numDirections_()
325 {
return (dimWorld < 3) ? 4 : 13; }
327 template<
class Geometry>
328 bool neglectElement_(Geometry& hostGridElementGeometry,
329 std::size_t localVertexIdx0,
330 std::size_t localVertexIdx1,
331 double directionProbability)
333 if (randomNumer_() < directionProbability)
338 if (!considerLowDimElement_(hostGridElementGeometry.corner(localVertexIdx0), hostGridElementGeometry.corner(localVertexIdx1)))
345 {
return uniformdist_(generator_); }
347 auto getHostGridInputData_()
const
351 std::array<std::vector<int>, dimWorld> cells;
352 std::array<std::vector<CoordScalar>, dimWorld> positions;
353 std::array<std::vector<CoordScalar>, dimWorld> grading;
354 GlobalPosition lowerLeft;
355 GlobalPosition upperRight;
359 auto& cells = inputData.cells;
360 auto& positions = inputData.positions;
361 auto& grading = inputData.grading;
362 auto& lowerLeft = inputData.lowerLeft;
363 auto& upperRight = inputData.upperRight;
366 for (
int i = 0; i < dimWorld; ++i)
367 positions[i] =
getParamFromGroup<std::vector<CoordScalar>>(paramGroup_,
"Grid.Positions" + std::to_string(i), std::vector<CoordScalar>{});
368 if (std::none_of(positions.begin(), positions.end(), [&](
auto& v){ return v.empty(); }))
370 for (
int i = 0; i < dimWorld; ++i)
372 cells[i].resize(positions[i].size()-1, 1.0);
373 grading[i].resize(positions[i].size()-1, 1.0);
378 const auto lowerLeft = getParamFromGroup<GlobalPosition>(paramGroup_,
"Grid.LowerLeft", GlobalPosition(0.0));
379 const auto upperRight = getParamFromGroup<GlobalPosition>(paramGroup_,
"Grid.UpperRight");
380 const auto numPores = getParamFromGroup<std::vector<unsigned int>>(paramGroup_,
"Grid.NumPores");
381 if (numPores.size() != dimWorld)
382 DUNE_THROW(ParameterException,
"Grid.NumPores has to be a space-separated list of " << dimWorld <<
" integers!");
384 for (
int i = 0; i < dimWorld; ++i)
386 positions[i].push_back(lowerLeft[i]);
387 positions[i].push_back(upperRight[i]);
388 cells[i].push_back(numPores[i] - 1);
389 grading[i].resize(positions[i].size()-1, 1.0);
390 grading[i] = getParamFromGroup<std::vector<CoordScalar>>(paramGroup_,
"Grid.Grading" + std::to_string(i), grading[i]);
397 GlobalPosition result;
398 for (
int i = 0; i < dimWorld; ++i)
399 result[i] = positions[i][0];
406 GlobalPosition result;
407 for (
int i = 0; i < dimWorld; ++i)
408 result[i] = positions[i].back();
415 template<
class HostGr
idElement,
class ReferenceElement,
class Geometry>
416 void treatEdges_(
const HostGridElement& element,
const ReferenceElement& refElement,
const Geometry& geometry)
419 for (
unsigned int edgeIdx = 0; edgeIdx <
element.subEntities(dimWorld-1); ++edgeIdx)
421 const auto vIdxLocal0 = refElement.subEntity(edgeIdx, dimWorld-1, 0, dimWorld);
422 const auto vIdxLocal1 = refElement.subEntity(edgeIdx, dimWorld-1, 1, dimWorld);
423 const auto edgeIdxGlobal = hostGridView_->indexSet().subIndex(element, edgeIdx, dimWorld-1);
425 if (edgeInserted_[edgeIdxGlobal])
428 edgeInserted_[edgeIdxGlobal] =
true;
430 std::size_t directionNumber = 0;
443 else if(edgeIdx == 4 || edgeIdx == 5 || edgeIdx == 8 || edgeIdx == 9)
445 else if(edgeIdx == 6 || edgeIdx == 7 || edgeIdx == 10 || edgeIdx == 11)
448 maybeInsertElementAndVertices_(element, geometry, vIdxLocal0, vIdxLocal1, directionProbability_[directionNumber]);
452 template<
class HostGr
idElement,
class ReferenceElement,
class Geometry>
453 void treatDiagonals_(
const HostGridElement& element,
const ReferenceElement& refElement,
const Geometry& geometry)
455 if constexpr (dimWorld < 3)
456 treatDiagonalConnections2D_(element, geometry);
458 treatDiagonalConnections3D_(element, refElement, geometry);
461 template<
class HostGr
idElement,
class Geometry>
462 void treatDiagonalConnections2D_(
const HostGridElement& element,
463 const Geometry& geometry)
465 static constexpr std::array<Diagonal, 2> diagonals{ Diagonal{std::make_pair(0, 3), 2},
466 Diagonal{std::make_pair(1, 2), 3} };
468 treatIntersectingDiagonals_(element, geometry, diagonals);
471 template<
class HostGr
idElement,
class ReferenceElement,
class Geometry>
472 void treatDiagonalConnections3D_(
const HostGridElement& element,
473 const ReferenceElement& refElement,
474 const Geometry& geometry)
477 for (
auto faceIdx = 0; faceIdx <
element.subEntities(dimWorld-2); ++faceIdx)
479 const auto faceIdxGlobal = hostGridView_->indexSet().subIndex(element, faceIdx, dimWorld-2);
481 if (faceInserted_[faceIdxGlobal])
484 faceInserted_[faceIdxGlobal] =
true;
487 std::array<unsigned int, 4> vIdxLocal;
488 for (
int i = 0; i < 4; i++)
489 vIdxLocal[i] = refElement.subEntity(faceIdx, dimWorld-2, i, dimWorld);
491 const auto directionNumbers = [&]()
494 return std::make_pair<unsigned int, unsigned int>(8,7);
495 else if (faceIdx < 4)
496 return std::make_pair<unsigned int, unsigned int>(6,5);
498 return std::make_pair<unsigned int, unsigned int>(4,3);
501 const std::array<Diagonal, 2> diagonals{ Diagonal{std::make_pair(vIdxLocal[1], vIdxLocal[2]), directionNumbers.first},
502 Diagonal{std::make_pair(vIdxLocal[0], vIdxLocal[3]), directionNumbers.second} };
504 treatIntersectingDiagonals_(element, geometry, diagonals);
507 static constexpr std::array<Diagonal, 4> diagonals{ Diagonal{std::make_pair(0, 7), 9},
508 Diagonal{std::make_pair(3, 4), 10},
509 Diagonal{std::make_pair(1, 6), 11},
510 Diagonal{std::make_pair(2, 5), 12}, };
512 treatIntersectingDiagonals_(element, geometry, diagonals);
515 template<
class HostGr
idElement,
class Geometry,
class Diagonals>
516 void treatIntersectingDiagonals_(
const HostGridElement& element,
517 const Geometry& geometry,
518 const Diagonals& diagonals)
520 static const bool allowIntersectingDiagonals = getParamFromGroup<bool>(paramGroup_,
"Grid.AllowIntersectingDiagonals",
true);
522 auto treat = [&](
const Diagonal& diagonal)
524 return maybeInsertElementAndVertices_(element, geometry,
525 diagonal.localVertexIndices.first, diagonal.localVertexIndices.second,
526 directionProbability_[diagonal.directionNumber]);
529 if (allowIntersectingDiagonals)
532 for (
const auto& diagonal : diagonals)
537 auto order = createOrderedList_(diagonals.size());
538 std::shuffle(order.begin(), order.end(), generator_);
541 const auto& diagonal = diagonals[i];
542 const bool inserted = treat(diagonal);
549 std::vector<std::size_t> createOrderedList_(
const std::size_t size)
const
551 std::vector<std::size_t> result(size);
552 std::iota(result.begin(), result.end(), 0);
556 auto getLambdaToRemoveThroatsOnBoundary_()
const
558 auto negletElementsOnBoundary = [&](
const GlobalPosition& a,
const GlobalPosition& b)
560 const auto center = 0.5 * (a + b);
561 const auto eps = (a-b).two_norm() * 1e-5;
563 bool neglectElement =
false;
564 for (
auto i : removeThroatsOnBoundary_)
568 case 0: neglectElement =
center[0] < hostGridLowerLeft_[0] + eps;
break;
569 case 1: neglectElement =
center[0] > hostGridUpperRight_[0] - eps;
break;
570 case 2:
if constexpr (dimWorld > 1)
572 neglectElement =
center[1] < hostGridLowerLeft_[1] + eps;
575 case 3:
if constexpr (dimWorld > 1)
577 neglectElement =
center[1] > hostGridUpperRight_[1] - eps;
580 case 4:
if constexpr (dimWorld > 2)
582 neglectElement =
center[2] < hostGridLowerLeft_[2] + eps;
585 case 5:
if constexpr (dimWorld > 2)
587 neglectElement =
center[2] > hostGridUpperRight_[2] - eps;
599 return negletElementsOnBoundary;
602 std::string paramGroup_;
603 GlobalPosition hostGridLowerLeft_;
604 GlobalPosition hostGridUpperRight_;
605 std::vector<std::size_t> removeThroatsOnBoundary_;
606 std::unique_ptr<const HostGridView> hostGridView_;
607 std::function<bool(
const GlobalPosition&,
const GlobalPosition&)> considerLowDimElement_;
609 std::vector<GlobalPosition> vertexSet_;
610 std::vector<VertexIndexPair> elementSet_;
612 std::vector<bool> vertexInserted_;
613 std::vector<std::size_t> hostVertexIdxToVertexIdx_;
614 std::vector<std::size_t> edgeInserted_;
615 std::vector<std::size_t> faceInserted_;
617 mutable std::mt19937 generator_;
618 std::uniform_real_distribution<> uniformdist_{0, 1};
619 std::array<double, numDirections_()> directionProbability_;
621 std::shared_ptr<Grid> gridPtr_;
Some exceptions thrown in DuMux
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Grid manager specialization for YaspGrid.
Corners::value_type center(const Corners &corners)
The center of a given list of corners.
Definition: center.hh:36
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition: parameters.hh:161
bool hasParamInGroup(const std::string ¶mGroup, const std::string ¶m)
Check whether a key exists in the parameter tree with a model group prefix.
Definition: parameters.hh:177
Definition: discretization/porenetwork/fvelementgeometry.hh:34
Exception thrown if a run-time parameter is not specified correctly.
Definition: exceptions.hh:60
Definition: consistentlyorientedgrid.hh:32