24#ifndef DUMUX_PORE_NETWORK_GRID_MANAGER_HH
25#define DUMUX_PORE_NETWORK_GRID_MANAGER_HH
33#include <dune/common/classname.hh>
34#include <dune/common/exceptions.hh>
35#include <dune/common/timer.hh>
38#include <dune/foamgrid/foamgrid.hh>
39#include <dune/foamgrid/dgffoam.hh>
53template<
int dimWorld,
class GData = Dumux::PoreNetwork::Gr
idData<Dune::FoamGr
id<1, dimWorld>>>
56 using GridType = Dune::FoamGrid<1, dimWorld>;
57 using Element =
typename GridType::template Codim<0>::Entity;
58 using GlobalPosition =
typename Element::Geometry::GlobalCoordinate;
61 using Grid = GridType;
62 using GridData = GData;
64 void init(
const std::string& paramGroup =
"")
67 paramGroup_ = paramGroup;
72 makeGridFromDgfFile(getParamFromGroup<std::string>(paramGroup,
"Grid.File"));
78 const auto numPores = getParamFromGroup<std::vector<unsigned int>>(paramGroup_,
"Grid.NumPores");
79 if (numPores.size() == 1)
80 createOneDGrid_(numPores[0]);
81 else if (numPores.size() == dimWorld)
82 makeGridFromStructuredLattice();
84 DUNE_THROW(ParameterException,
85 "Grid.NumPores parameter has wrong size " << numPores.size()
86 <<
". Should be 1 (for 1D grid) or "
87 << dimWorld <<
" (for structured lattice grid)."
94 const auto gridType = enableDgfGridPointer_ ?
"grid from dgf file" :
"generic grid from structured lattice";
95 std::cout <<
"Creating " << gridType <<
" with " << grid().leafGridView().size(0) <<
" elements and "
96 << grid().leafGridView().size(1) <<
" vertices took " << timer.elapsed() <<
" seconds." << std::endl;
102 void makeGridFromDgfFile(
const std::string& fileName)
105 const std::string extension = getFileExtension(fileName);
106 if (extension !=
"dgf")
107 DUNE_THROW(Dune::IOError,
"Grid type " << Dune::className<Grid>() <<
" only supports DGF (*.dgf) but the specified filename has extension: *."<< extension);
109 enableDgfGridPointer_ =
true;
110 dgfGridPtr() = Dune::GridPtr<Grid>(fileName.c_str(), Dune::MPIHelper::getCommunicator());
111 gridData_ = std::make_shared<GridData>(dgfGridPtr_, paramGroup_);
113 if (getParamFromGroup<bool>(paramGroup_,
"Grid.Sanitize",
false))
120 void makeGridFromStructuredLattice()
122 StructuredLatticeGridCreator<dimWorld> creator;
123 creator.init(paramGroup_);
124 gridPtr() = creator.gridPtr();
126 gridData_ = std::make_shared<GridData>(gridPtr_, paramGroup_);
128 if (getParamFromGroup<bool>(paramGroup_,
"Grid.Sanitize",
true))
131 std::cout <<
"\nWARNING: Set Grid.Sanitize = true in order to remove insular patches of elements not connected to the boundary." << std::endl;
133 gridData_->assignParameters();
139 std::string getFileExtension(
const std::string& fileName)
const
141 std::size_t i = fileName.rfind(
'.', fileName.length());
142 if (i != std::string::npos)
143 return(fileName.substr(i+1, fileName.length() - i));
145 DUNE_THROW(Dune::IOError,
"Please provide and extension for your grid file ('"<< fileName <<
"')!");
153 {
return enableDgfGridPointer_ ? *dgfGridPtr() : *gridPtr(); }
158 std::shared_ptr<GridData> getGridData()
const
161 DUNE_THROW(Dune::IOError,
"No grid data available");
171 if (Dune::MPIHelper::getCommunication().size() > 1)
174 if (enableDgfGridPointer_)
176 dgfGridPtr().loadBalance();
178 gridData_ = std::make_shared<GridData>(dgfGridPtr(), paramGroup_);
181 gridPtr()->loadBalance();
191 gridData_->getCoordinationNumbers();
194 if (enableDgfGridPointer_)
195 gridData_->copyDgfData();
197 const auto gridView = grid().leafGridView();
198 static const std::string sanitationMode = getParamFromGroup<std::string>(paramGroup_,
"Grid.SanitationMode",
"KeepLargestCluster");
201 const auto keepElement = [&]
203 if (sanitationMode ==
"UsePoreLabels")
204 return findElementsConnectedToPoreLabel(gridView);
205 else if (sanitationMode ==
"KeepLargestCluster")
206 return findElementsInLargestCluster(gridView);
208 DUNE_THROW(Dune::IOError, sanitationMode <<
"is not a valid sanitation mode. Use KeepLargestCluster or UsePoreLabels.");
213 if (std::none_of(keepElement.begin(), keepElement.end(), [](
const bool i){return i;}))
214 DUNE_THROW(Dune::InvalidStateException,
"sanitize() deleted all elements! Check your boundary face indices. "
215 <<
"If the problem persists, add at least one of your boundary face indices to PruningSeedIndices");
218 std::size_t numDeletedElements = 0;
220 for (
const auto& element : elements(gridView))
222 const auto eIdx = gridView.indexSet().index(element);
223 if (!keepElement[eIdx])
225 grid().removeElement(element);
226 ++numDeletedElements;
234 if (enableDgfGridPointer_)
235 gridData_->resizeParameterContainers();
237 if (numDeletedElements > 0)
238 std::cout <<
"\nDeleted " << numDeletedElements <<
" isolated elements.\n" << std::endl;
245 std::vector<bool> findElementsConnectedToPoreLabel(
const typename Grid::LeafGridView& gridView)
const
248 const auto pruningSeedIndices = getParamFromGroup<std::vector<int>>(paramGroup_,
"Grid.PruningSeedIndices", std::vector<int>{1});
249 std::vector<bool> elementIsConnected(gridView.size(0),
false);
251 auto boundaryIdx = [&](
const auto&
vertex)
253 if (enableDgfGridPointer_)
254 return static_cast<int>(dgfGridPtr_.parameters(vertex)[gridData_->parameterIndex(
"PoreLabel")]);
256 return static_cast<int>(gridData_->poreLabelAtPosForGenericGrid(
vertex.geometry().center()));
259 for (
const auto& element : elements(gridView))
261 const auto eIdx = gridView.indexSet().index(element);
262 if (elementIsConnected[eIdx])
267 bool hasNeighbor =
false;
268 for (
const auto& intersection : intersections(gridView, element))
270 auto vertex =
element.template subEntity<1>(intersection.indexInInside());
272 if (std::any_of(pruningSeedIndices.begin(), pruningSeedIndices.end(),
273 [&](
const int i ){ return i == boundaryIdx(vertex); }))
279 if (intersection.neighbor())
288 elementIsConnected[eIdx] =
true;
291 recursivelyFindConnectedElements_(gridView, element, elementIsConnected);
295 return elementIsConnected;
302 std::vector<bool> findElementsInLargestCluster(
const typename Grid::LeafGridView& gridView)
const
304 const auto clusteredElements = clusterElements(gridView);
306 const auto numClusters = *std::max_element(clusteredElements.begin(), clusteredElements.end()) + 1;
307 std::cout <<
"\nFound " << numClusters <<
" unconnected clusters." << std::endl;
310 std::vector<std::size_t> clusterFrequency(numClusters);
311 for (
const auto clusterIdx : clusteredElements)
312 clusterFrequency[clusterIdx] += 1;
314 const auto largestCluster = std::max_element(clusterFrequency.begin(), clusterFrequency.end());
315 const auto largestClusterIdx =
std::distance(clusterFrequency.begin(), largestCluster);
317 std::vector<bool> elementsInLargestCluster(gridView.size(0));
319 for (
int eIdx = 0; eIdx < clusteredElements.size(); ++eIdx)
320 if (clusteredElements[eIdx] == largestClusterIdx)
321 elementsInLargestCluster[eIdx] =
true;
323 return elementsInLargestCluster;
329 std::vector<std::size_t> clusterElements(
const typename Grid::LeafGridView& gridView)
const
331 std::vector<std::size_t> elementInCluster(gridView.size(0), 0);
332 std::size_t clusterIdx = 0;
334 for (
const auto& element : elements(gridView))
336 const auto eIdx = gridView.indexSet().index(element);
337 if (elementInCluster[eIdx])
341 elementInCluster[eIdx] = clusterIdx;
343 recursivelyFindConnectedElements_(gridView, element, elementInCluster, clusterIdx);
347 for (
auto& clusterIdx : elementInCluster)
350 return elementInCluster;
358 std::shared_ptr<Grid>& gridPtr()
360 if(!enableDgfGridPointer_)
363 DUNE_THROW(Dune::InvalidStateException,
"You are using DGF. To get the grid pointer use method dgfGridPtr()!");
369 Dune::GridPtr<Grid>& dgfGridPtr()
371 if(enableDgfGridPointer_)
374 DUNE_THROW(Dune::InvalidStateException,
"The DGF grid pointer is only available if the grid was constructed with a DGF file!");
381 bool enableDgfGridPointer_ =
false;
383 std::shared_ptr<Grid> gridPtr_;
384 Dune::GridPtr<Grid> dgfGridPtr_;
386 std::shared_ptr<GridData> gridData_;
388 std::string paramGroup_;
392 void createOneDGrid_(
unsigned int numPores)
394 const auto lowerLeft = getParamFromGroup<GlobalPosition>(paramGroup_,
"Grid.LowerLeft", GlobalPosition(0.0));
395 const auto upperRight = getParamFromGroup<GlobalPosition>(paramGroup_,
"Grid.UpperRight");
396 const auto cells = numPores - 1;
399 GlobalPosition step = upperRight;
400 step -= lowerLeft, step /= cells;
403 Dune::GridFactory<Grid> factory;
406 GlobalPosition globalPos = lowerLeft;
407 for (
unsigned int vIdx = 0; vIdx <= cells; vIdx++, globalPos += step)
408 factory.insertVertex(globalPos);
411 for(
unsigned int eIdx = 0; eIdx < cells; eIdx++)
414 gridPtr() = std::shared_ptr<Grid>(factory.createGrid());
415 gridData_ = std::make_shared<GridData>(gridPtr_, paramGroup_);
416 gridData_->assignParameters();
420 void recursivelyFindConnectedElements_(
const typename Grid::LeafGridView& gridView,
421 const Element& element,
422 std::vector<T>& elementIsConnected,
426 std::stack<Element> elementStack;
427 elementStack.push(element);
428 while (!elementStack.empty())
430 auto e = elementStack.top();
432 for (
const auto& intersection : intersections(gridView, e))
434 if (!intersection.boundary())
436 auto outside = intersection.outside();
437 auto nIdx = gridView.indexSet().index(outside);
438 if (!elementIsConnected[nIdx])
440 elementIsConnected[nIdx] = marker;
441 elementStack.push(outside);
Some exceptions thrown in DuMux
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Creates a network grid from a structured lattice. Connections can be randomly deleted.
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:294
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
constexpr Line line
Definition: couplingmanager1d3d_line.hh:43