12#ifndef DUMUX_PORE_NETWORK_GRID_MANAGER_HH
13#define DUMUX_PORE_NETWORK_GRID_MANAGER_HH
21#include <dune/common/classname.hh>
22#include <dune/common/exceptions.hh>
23#include <dune/common/timer.hh>
26#include <dune/foamgrid/foamgrid.hh>
27#include <dune/foamgrid/dgffoam.hh>
41template<
int dimWorld,
class GData = Dumux::PoreNetwork::Gr
idData<Dune::FoamGr
id<1, dimWorld>>>
44 using GridType = Dune::FoamGrid<1, dimWorld>;
45 using Element =
typename GridType::template Codim<0>::Entity;
46 using GlobalPosition =
typename Element::Geometry::GlobalCoordinate;
49 using Grid = GridType;
50 using GridData = GData;
52 void init(
const std::string& paramGroup =
"")
55 paramGroup_ = paramGroup;
60 makeGridFromDgfFile(getParamFromGroup<std::string>(paramGroup,
"Grid.File"));
66 const auto numPores = getParamFromGroup<std::vector<unsigned int>>(paramGroup_,
"Grid.NumPores");
67 if (numPores.size() == 1)
68 createOneDGrid_(numPores[0]);
69 else if (numPores.size() == dimWorld)
70 makeGridFromStructuredLattice();
72 DUNE_THROW(ParameterException,
73 "Grid.NumPores parameter has wrong size " << numPores.size()
74 <<
". Should be 1 (for 1D grid) or "
75 << dimWorld <<
" (for structured lattice grid)."
82 const auto gridType = enableDgfGridPointer_ ?
"grid from dgf file" :
"generic grid from structured lattice";
83 std::cout <<
"Creating " << gridType <<
" with " << grid().leafGridView().size(0) <<
" elements and "
84 << grid().leafGridView().size(1) <<
" vertices took " << timer.elapsed() <<
" seconds." << std::endl;
90 void makeGridFromDgfFile(
const std::string& fileName)
93 const std::string extension = getFileExtension(fileName);
94 if (extension !=
"dgf")
95 DUNE_THROW(Dune::IOError,
"Grid type " << Dune::className<Grid>() <<
" only supports DGF (*.dgf) but the specified filename has extension: *."<< extension);
97 enableDgfGridPointer_ =
true;
98 dgfGridPtr() = Dune::GridPtr<Grid>(fileName.c_str(), Dune::MPIHelper::getCommunicator());
99 gridData_ = std::make_shared<GridData>(dgfGridPtr_, paramGroup_);
101 if (getParamFromGroup<bool>(paramGroup_,
"Grid.Sanitize",
false))
108 void makeGridFromStructuredLattice()
110 StructuredLatticeGridCreator<dimWorld> creator;
111 creator.init(paramGroup_);
112 gridPtr() = creator.gridPtr();
114 gridData_ = std::make_shared<GridData>(gridPtr_, paramGroup_);
116 if (getParamFromGroup<bool>(paramGroup_,
"Grid.Sanitize",
true))
119 std::cout <<
"\nWARNING: Set Grid.Sanitize = true in order to remove insular patches of elements not connected to the boundary." << std::endl;
121 gridData_->assignParameters();
127 std::string getFileExtension(
const std::string& fileName)
const
129 std::size_t i = fileName.rfind(
'.', fileName.length());
130 if (i != std::string::npos)
131 return(fileName.substr(i+1, fileName.length() - i));
133 DUNE_THROW(Dune::IOError,
"Please provide and extension for your grid file ('"<< fileName <<
"')!");
141 {
return enableDgfGridPointer_ ? *dgfGridPtr() : *gridPtr(); }
146 std::shared_ptr<GridData> getGridData()
const
149 DUNE_THROW(Dune::IOError,
"No grid data available");
159 if (Dune::MPIHelper::getCommunication().size() > 1)
162 if (enableDgfGridPointer_)
164 dgfGridPtr().loadBalance();
166 gridData_ = std::make_shared<GridData>(dgfGridPtr(), paramGroup_);
169 gridPtr()->loadBalance();
179 gridData_->getCoordinationNumbers();
182 if (enableDgfGridPointer_)
183 gridData_->copyDgfData();
185 const auto gridView = grid().leafGridView();
186 static const std::string sanitationMode = getParamFromGroup<std::string>(paramGroup_,
"Grid.SanitationMode",
"KeepLargestCluster");
189 const auto keepElement = [&]
191 if (sanitationMode ==
"UsePoreLabels")
192 return findElementsConnectedToPoreLabel(gridView);
193 else if (sanitationMode ==
"KeepLargestCluster")
194 return findElementsInLargestCluster(gridView);
196 DUNE_THROW(Dune::IOError, sanitationMode <<
"is not a valid sanitation mode. Use KeepLargestCluster or UsePoreLabels.");
201 if (std::none_of(keepElement.begin(), keepElement.end(), [](
const bool i){return i;}))
202 DUNE_THROW(Dune::InvalidStateException,
"sanitize() deleted all elements! Check your boundary face indices. "
203 <<
"If the problem persists, add at least one of your boundary face indices to PruningSeedIndices");
206 std::size_t numDeletedElements = 0;
208 for (
const auto& element : elements(gridView))
210 const auto eIdx = gridView.indexSet().index(element);
211 if (!keepElement[eIdx])
213 grid().removeElement(element);
214 ++numDeletedElements;
222 if (enableDgfGridPointer_)
223 gridData_->resizeParameterContainers();
225 if (numDeletedElements > 0)
226 std::cout <<
"\nDeleted " << numDeletedElements <<
" isolated elements.\n" << std::endl;
233 std::vector<bool> findElementsConnectedToPoreLabel(
const typename Grid::LeafGridView& gridView)
const
236 const auto pruningSeedIndices = getParamFromGroup<std::vector<int>>(paramGroup_,
"Grid.PruningSeedIndices", std::vector<int>{1});
237 std::vector<bool> elementIsConnected(gridView.size(0),
false);
239 auto boundaryIdx = [&](
const auto&
vertex)
241 if (enableDgfGridPointer_)
242 return static_cast<int>(dgfGridPtr_.parameters(vertex)[gridData_->parameterIndex(
"PoreLabel")]);
244 return static_cast<int>(gridData_->poreLabelAtPosForGenericGrid(
vertex.geometry().center()));
247 for (
const auto& element : elements(gridView))
249 const auto eIdx = gridView.indexSet().index(element);
250 if (elementIsConnected[eIdx])
255 bool hasNeighbor =
false;
256 for (
const auto& intersection : intersections(gridView, element))
258 auto vertex =
element.template subEntity<1>(intersection.indexInInside());
260 if (std::any_of(pruningSeedIndices.begin(), pruningSeedIndices.end(),
261 [&](
const int i ){ return i == boundaryIdx(vertex); }))
267 if (intersection.neighbor())
276 elementIsConnected[eIdx] =
true;
279 recursivelyFindConnectedElements_(gridView, element, elementIsConnected);
283 return elementIsConnected;
290 std::vector<bool> findElementsInLargestCluster(
const typename Grid::LeafGridView& gridView)
const
292 const auto clusteredElements = clusterElements(gridView);
294 const auto numClusters = *std::max_element(clusteredElements.begin(), clusteredElements.end()) + 1;
295 std::cout <<
"\nFound " << numClusters <<
" unconnected clusters." << std::endl;
298 std::vector<std::size_t> clusterFrequency(numClusters);
299 for (
const auto clusterIdx : clusteredElements)
300 clusterFrequency[clusterIdx] += 1;
302 const auto largestCluster = std::max_element(clusterFrequency.begin(), clusterFrequency.end());
303 const auto largestClusterIdx =
std::distance(clusterFrequency.begin(), largestCluster);
305 std::vector<bool> elementsInLargestCluster(gridView.size(0));
307 for (
int eIdx = 0; eIdx < clusteredElements.size(); ++eIdx)
308 if (clusteredElements[eIdx] == largestClusterIdx)
309 elementsInLargestCluster[eIdx] =
true;
311 return elementsInLargestCluster;
317 std::vector<std::size_t> clusterElements(
const typename Grid::LeafGridView& gridView)
const
319 std::vector<std::size_t> elementInCluster(gridView.size(0), 0);
320 std::size_t clusterIdx = 0;
322 for (
const auto& element : elements(gridView))
324 const auto eIdx = gridView.indexSet().index(element);
325 if (elementInCluster[eIdx])
329 elementInCluster[eIdx] = clusterIdx;
331 recursivelyFindConnectedElements_(gridView, element, elementInCluster, clusterIdx);
335 for (
auto& clusterIdx : elementInCluster)
338 return elementInCluster;
346 std::shared_ptr<Grid>& gridPtr()
348 if(!enableDgfGridPointer_)
351 DUNE_THROW(Dune::InvalidStateException,
"You are using DGF. To get the grid pointer use method dgfGridPtr()!");
357 Dune::GridPtr<Grid>& dgfGridPtr()
359 if(enableDgfGridPointer_)
362 DUNE_THROW(Dune::InvalidStateException,
"The DGF grid pointer is only available if the grid was constructed with a DGF file!");
369 bool enableDgfGridPointer_ =
false;
371 std::shared_ptr<Grid> gridPtr_;
372 Dune::GridPtr<Grid> dgfGridPtr_;
374 std::shared_ptr<GridData> gridData_;
376 std::string paramGroup_;
380 void createOneDGrid_(
unsigned int numPores)
382 const auto lowerLeft = getParamFromGroup<GlobalPosition>(paramGroup_,
"Grid.LowerLeft", GlobalPosition(0.0));
383 const auto upperRight = getParamFromGroup<GlobalPosition>(paramGroup_,
"Grid.UpperRight");
384 const auto cells = numPores - 1;
387 GlobalPosition step = upperRight;
388 step -= lowerLeft, step /= cells;
391 Dune::GridFactory<Grid> factory;
394 GlobalPosition globalPos = lowerLeft;
395 for (
unsigned int vIdx = 0; vIdx <= cells; vIdx++, globalPos += step)
396 factory.insertVertex(globalPos);
399 for(
unsigned int eIdx = 0; eIdx < cells; eIdx++)
402 gridPtr() = std::shared_ptr<Grid>(factory.createGrid());
403 gridData_ = std::make_shared<GridData>(gridPtr_, paramGroup_);
404 gridData_->assignParameters();
408 void recursivelyFindConnectedElements_(
const typename Grid::LeafGridView& gridView,
409 const Element& element,
410 std::vector<T>& elementIsConnected,
414 std::stack<Element> elementStack;
415 elementStack.push(element);
416 while (!elementStack.empty())
418 auto e = elementStack.top();
420 for (
const auto& intersection : intersections(gridView, e))
422 if (!intersection.boundary())
424 auto outside = intersection.outside();
425 auto nIdx = gridView.indexSet().index(outside);
426 if (!elementIsConnected[nIdx])
428 elementIsConnected[nIdx] = marker;
429 elementStack.push(outside);
Some exceptions thrown in DuMux
static ctype distance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest distance between two points.
Definition: distance.hh:282
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:165
constexpr Line line
Definition: couplingmanager1d3d_line.hh:31
Definition: discretization/porenetwork/fvelementgeometry.hh:24
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Creates a network grid from a structured lattice. Connections can be randomly deleted.