version 3.11-dev
Loading...
Searching...
No Matches
io/grid/porenetwork/gridmanager.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_PORE_NETWORK_GRID_MANAGER_HH
14#define DUMUX_PORE_NETWORK_GRID_MANAGER_HH
15
16#if HAVE_DUNE_FOAMGRID
17
18#include <iostream>
19#include <algorithm>
20#include <vector>
21
22#include <dune/common/classname.hh>
23#include <dune/common/exceptions.hh>
24#include <dune/common/timer.hh>
25
26// FoamGrid specific includes
27#include <dune/foamgrid/foamgrid.hh>
28#include <dune/foamgrid/dgffoam.hh>
29
32
33#include "griddata.hh"
35
36namespace Dumux::PoreNetwork {
37
42template<int dimWorld, class GData = Dumux::PoreNetwork::GridData<Dune::FoamGrid<1, dimWorld>>>
44{
45 using GridType = Dune::FoamGrid<1, dimWorld>;
46 using Element = typename GridType::template Codim<0>::Entity;
47 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
48
49public:
50 using Grid = GridType;
51 using GridData = GData;
52
53 void init(const std::string& paramGroup = "")
54 {
55 Dune::Timer timer;
56 paramGroup_ = paramGroup;
57
58 // First try to create it from a DGF file in GridParameterGroup.File
59 if (hasParamInGroup(paramGroup, "Grid.File"))
60 {
63 }
64 else // no grid file found
65 {
66 // create a structured grid (1D grid or lattice grid)
67 const auto numPores = getParamFromGroup<std::vector<unsigned int>>(paramGroup_, "Grid.NumPores");
68 if (numPores.size() == 1)
69 createOneDGrid_(numPores[0]);
70 else if (numPores.size() == dimWorld)
72 else
73 DUNE_THROW(ParameterException,
74 "Grid.NumPores parameter has wrong size " << numPores.size()
75 << ". Should be 1 (for 1D grid) or "
76 << dimWorld << " (for structured lattice grid)."
77 );
78
80 }
81
82 timer.stop();
83 const auto gridType = enableDgfGridPointer_ ? "grid from dgf file" : "generic grid from structured lattice";
84 std::cout << "Creating " << gridType << " with " << grid().leafGridView().size(0) << " elements and "
85 << grid().leafGridView().size(1) << " vertices took " << timer.elapsed() << " seconds." << std::endl;
86 }
87
91 void makeGridFromDgfFile(const std::string& fileName)
92 {
93 // We found a file in the input file...does it have a supported extension?
94 const std::string extension = getFileExtension(fileName);
95 if (extension != "dgf")
96 DUNE_THROW(Dune::IOError, "Grid type " << Dune::className<Grid>() << " only supports DGF (*.dgf) but the specified filename has extension: *."<< extension);
97
99 dgfGridPtr() = Dune::GridPtr<Grid>(fileName.c_str(), Dune::MPIHelper::getCommunicator());
100 gridData_ = std::make_shared<GridData>(dgfGridPtr_, paramGroup_);
101
102 if (getParamFromGroup<bool>(paramGroup_, "Grid.Sanitize", false))
103 sanitizeGrid();
104 }
105
110 {
112 creator.init(paramGroup_);
113 gridPtr() = creator.gridPtr();
114
115 gridData_ = std::make_shared<GridData>(gridPtr_, paramGroup_);
116
117 if (getParamFromGroup<bool>(paramGroup_, "Grid.Sanitize", true))
118 sanitizeGrid();
119 else
120 std::cout << "\nWARNING: Set Grid.Sanitize = true in order to remove insular patches of elements not connected to the boundary." << std::endl;
121
122 gridData_->assignParameters();
123 }
124
128 std::string getFileExtension(const std::string& fileName) const
129 {
130 std::size_t i = fileName.rfind('.', fileName.length());
131 if (i != std::string::npos)
132 return(fileName.substr(i+1, fileName.length() - i));
133 else
134 DUNE_THROW(Dune::IOError, "Please provide and extension for your grid file ('"<< fileName << "')!");
135 return "";
136 }
137
142 { return enableDgfGridPointer_ ? *dgfGridPtr() : *gridPtr(); }
143
147 std::shared_ptr<GridData> getGridData() const
148 {
149 if (!gridData_)
150 DUNE_THROW(Dune::IOError, "No grid data available");
151
152 return gridData_;
153 }
154
159 {
160 if (Dune::MPIHelper::getCommunication().size() > 1)
161 {
162 // if we may have dgf parameters use load balancing of the dgf pointer
164 {
165 dgfGridPtr().loadBalance();
166 // update the grid data
167 gridData_ = std::make_shared<GridData>(dgfGridPtr(), paramGroup_);
168 }
169 else
170 gridPtr()->loadBalance();
171 }
172 }
173
178 {
179 // evaluate the coordination numbers to check if all pores are connected to at least one throat
180 gridData_->getCoordinationNumbers();
181
182 // for dgf grid, copy the data to persistent containers
184 gridData_->copyDgfData();
185
186 const auto gridView = grid().leafGridView();
187 static const std::string sanitationMode = getParamFromGroup<std::string>(paramGroup_, "Grid.SanitationMode", "KeepLargestCluster");
188
189 // find the elements to keep, all others will be deleted
190 const auto keepElement = [&]
191 {
192 if (sanitationMode == "UsePoreLabels")
193 return findElementsConnectedToPoreLabel(gridView);
194 else if (sanitationMode == "KeepLargestCluster")
195 return findElementsInLargestCluster(gridView);
196 else
197 DUNE_THROW(Dune::IOError, sanitationMode << "is not a valid sanitation mode. Use KeepLargestCluster or UsePoreLabels.");
198
199
200 }();
201
202 if (std::none_of(keepElement.begin(), keepElement.end(), [](const bool i){return i;}))
203 DUNE_THROW(Dune::InvalidStateException, "sanitize() deleted all elements! Check your boundary face indices. "
204 << "If the problem persists, add at least one of your boundary face indices to PruningSeedIndices");
205
206 // remove the elements in the grid
207 std::size_t numDeletedElements = 0;
208 grid().preGrow();
209 for (const auto& element : elements(gridView))
210 {
211 const auto eIdx = gridView.indexSet().index(element);
212 if (!keepElement[eIdx])
213 {
214 grid().removeElement(element);
215 ++numDeletedElements;
216 }
217 }
218 // triggers the grid growth process
219 grid().grow();
220 grid().postGrow();
221
222 // resize the parameters for dgf grids
224 gridData_->resizeParameterContainers();
225
226 if (numDeletedElements > 0)
227 std::cout << "\nDeleted " << numDeletedElements << " isolated elements.\n" << std::endl;
228 }
229
234 std::vector<bool> findElementsConnectedToPoreLabel(const typename Grid::LeafGridView& gridView) const
235 {
236 // pruning -- remove elements not connected to a Dirichlet boundary (marker == 1)
237 const auto pruningSeedIndices = getParamFromGroup<std::vector<int>>(paramGroup_, "Grid.PruningSeedIndices", std::vector<int>{1});
238 std::vector<bool> elementIsConnected(gridView.size(0), false);
239
240 auto boundaryIdx = [&](const auto& vertex)
241 {
243 return static_cast<int>(dgfGridPtr_.parameters(vertex)[gridData_->parameterIndex("PoreLabel")]);
244 else
245 return static_cast<int>(gridData_->poreLabelAtPosForGenericGrid(vertex.geometry().center()));
246 };
247
248 for (const auto& element : elements(gridView))
249 {
250 const auto eIdx = gridView.indexSet().index(element);
251 if (elementIsConnected[eIdx])
252 continue;
253
254 // try to find a seed from which to start the search process
255 bool isSeed = false;
256 bool hasNeighbor = false;
257 for (const auto& intersection : intersections(gridView, element))
258 {
259 auto vertex = element.template subEntity<1>(intersection.indexInInside());
260 // seed found
261 if (std::any_of(pruningSeedIndices.begin(), pruningSeedIndices.end(),
262 [&]( const int i ){ return i == boundaryIdx(vertex); }))
263 {
264 isSeed = true;
265 // break;
266 }
267
268 if (intersection.neighbor())
269 hasNeighbor = true;
270 }
271
272 if (!hasNeighbor)
273 continue;
274
275 if (isSeed)
276 {
277 elementIsConnected[eIdx] = true;
278
279 // use iteration instead of recursion here because the recursion can get too deep
280 recursivelyFindConnectedElements_(gridView, element, elementIsConnected);
281 }
282 }
283
284 return elementIsConnected;
285 }
286
291 std::vector<bool> findElementsInLargestCluster(const typename Grid::LeafGridView& gridView) const
292 {
293 const auto clusteredElements = clusterElements(gridView);
294
295 const auto numClusters = *std::max_element(clusteredElements.begin(), clusteredElements.end()) + 1;
296 std::cout << "\nFound " << numClusters << " unconnected clusters." << std::endl;
297
298 // count number of elements in individual clusters
299 std::vector<std::size_t> clusterFrequency(numClusters);
300 for (const auto clusterIdx : clusteredElements)
301 clusterFrequency[clusterIdx] += 1;
302
303 const auto largestCluster = std::max_element(clusterFrequency.begin(), clusterFrequency.end());
304 const auto largestClusterIdx = std::distance(clusterFrequency.begin(), largestCluster);
305
306 std::vector<bool> elementsInLargestCluster(gridView.size(0));
307
308 for (int eIdx = 0; eIdx < clusteredElements.size(); ++eIdx)
309 if (clusteredElements[eIdx] == largestClusterIdx)
310 elementsInLargestCluster[eIdx] = true;
311
312 return elementsInLargestCluster;
313 }
314
318 std::vector<std::size_t> clusterElements(const typename Grid::LeafGridView& gridView) const
319 {
320 std::vector<std::size_t> elementInCluster(gridView.size(0), 0); // initially, all elements are in pseudo cluster 0
321 std::size_t clusterIdx = 0;
322
323 for (const auto& element : elements(gridView))
324 {
325 const auto eIdx = gridView.indexSet().index(element);
326 if (elementInCluster[eIdx]) // element already is in a cluster
327 continue;
328
329 ++clusterIdx;
330 elementInCluster[eIdx] = clusterIdx;
331
332 recursivelyFindConnectedElements_(gridView, element, elementInCluster, clusterIdx);
333 }
334
335 // make sure the clusters start with index zero
336 for (auto& clusterIdx : elementInCluster)
337 clusterIdx -= 1;
338
339 return elementInCluster;
340 }
341
342protected:
343
347 std::shared_ptr<Grid>& gridPtr()
348 {
350 return gridPtr_;
351 else
352 DUNE_THROW(Dune::InvalidStateException, "You are using DGF. To get the grid pointer use method dgfGridPtr()!");
353 }
354
358 Dune::GridPtr<Grid>& dgfGridPtr()
359 {
361 return dgfGridPtr_;
362 else
363 DUNE_THROW(Dune::InvalidStateException, "The DGF grid pointer is only available if the grid was constructed with a DGF file!");
364 }
365
371
372 std::shared_ptr<Grid> gridPtr_;
373 Dune::GridPtr<Grid> dgfGridPtr_;
374
375 std::shared_ptr<GridData> gridData_;
376
377 std::string paramGroup_;
378
379private:
380
381 void createOneDGrid_(unsigned int numPores)
382 {
383 const auto lowerLeft = getParamFromGroup<GlobalPosition>(paramGroup_, "Grid.LowerLeft", GlobalPosition(0.0));
384 const auto upperRight = getParamFromGroup<GlobalPosition>(paramGroup_, "Grid.UpperRight");
385 const auto cells = numPores - 1;
386
387 // create a step vector
388 GlobalPosition step = upperRight;
389 step -= lowerLeft, step /= cells;
390
391 // make the grid (structured interval grid in dimworld space)
392 Dune::GridFactory<Grid> factory;
393
394 // create the vertices
395 GlobalPosition globalPos = lowerLeft;
396 for (unsigned int vIdx = 0; vIdx <= cells; vIdx++, globalPos += step)
397 factory.insertVertex(globalPos);
398
399 // create the cells
400 for(unsigned int eIdx = 0; eIdx < cells; eIdx++)
401 factory.insertElement(Dune::GeometryTypes::line, {eIdx, eIdx+1});
402
403 gridPtr() = std::shared_ptr<Grid>(factory.createGrid());
404 gridData_ = std::make_shared<GridData>(gridPtr_, paramGroup_);
405 gridData_->assignParameters();
406 }
407
408 template<class T>
409 void recursivelyFindConnectedElements_(const typename Grid::LeafGridView& gridView,
410 const Element& element,
411 std::vector<T>& elementIsConnected,
412 T marker = 1) const
413 {
414 // use iteration instead of recursion here because the recursion can get too deep
415 std::stack<Element> elementStack;
416 elementStack.push(element);
417 while (!elementStack.empty())
418 {
419 auto e = elementStack.top();
420 elementStack.pop();
421 for (const auto& intersection : intersections(gridView, e))
422 {
423 if (!intersection.boundary())
424 {
425 auto outside = intersection.outside();
426 auto nIdx = gridView.indexSet().index(outside);
427 if (!elementIsConnected[nIdx])
428 {
429 elementIsConnected[nIdx] = marker;
430 elementStack.push(outside);
431 }
432 }
433 }
434 }
435 }
436};
437
438}
439
440#endif // HAVE_DUNE_FOAMGRID
441
442#endif
Exception thrown if a run-time parameter is not specified correctly.
Definition exceptions.hh:48
A grid manager for pore-network models.
Definition io/grid/porenetwork/gridmanager.hh:44
std::vector< bool > findElementsInLargestCluster(const typename Grid::LeafGridView &gridView) const
Returns a vector of bool which entries are true for elements located in the largest connected cluster...
Definition io/grid/porenetwork/gridmanager.hh:291
Dune::GridPtr< Grid > dgfGridPtr_
Definition io/grid/porenetwork/gridmanager.hh:373
std::vector< std::size_t > clusterElements(const typename Grid::LeafGridView &gridView) const
Assigns a cluster index for each element.
Definition io/grid/porenetwork/gridmanager.hh:318
std::string paramGroup_
Definition io/grid/porenetwork/gridmanager.hh:377
bool enableDgfGridPointer_
A state variable if the DGF Dune::GridPtr has been enabled. It is always enabled if a DGF grid file w...
Definition io/grid/porenetwork/gridmanager.hh:370
void makeGridFromStructuredLattice()
Make a grid based on a structured lattice which allows to randomly delete elements based on Raoof et ...
Definition io/grid/porenetwork/gridmanager.hh:109
std::shared_ptr< GridData > getGridData() const
Returns the grid data.
Definition io/grid/porenetwork/gridmanager.hh:147
GData GridData
Definition io/grid/porenetwork/gridmanager.hh:51
void init(const std::string &paramGroup="")
Definition io/grid/porenetwork/gridmanager.hh:53
void loadBalance()
Call loadBalance() function of the grid.
Definition io/grid/porenetwork/gridmanager.hh:158
Dune::GridPtr< Grid > & dgfGridPtr()
Returns a reference to the DGF grid pointer (Dune::GridPtr<Grid>).
Definition io/grid/porenetwork/gridmanager.hh:358
std::string getFileExtension(const std::string &fileName) const
Returns the filename extension of a given filename.
Definition io/grid/porenetwork/gridmanager.hh:128
std::vector< bool > findElementsConnectedToPoreLabel(const typename Grid::LeafGridView &gridView) const
Returns a vector of bool which entries are true for elements connected to pores at the boundary with ...
Definition io/grid/porenetwork/gridmanager.hh:234
std::shared_ptr< Grid > & gridPtr()
Returns a reference to the grid pointer (std::shared_ptr<Grid>).
Definition io/grid/porenetwork/gridmanager.hh:347
std::shared_ptr< GridData > gridData_
Definition io/grid/porenetwork/gridmanager.hh:375
GridType Grid
Definition io/grid/porenetwork/gridmanager.hh:50
std::shared_ptr< Grid > gridPtr_
Definition io/grid/porenetwork/gridmanager.hh:372
Grid & grid()
Returns a reference to the grid.
Definition io/grid/porenetwork/gridmanager.hh:141
void sanitizeGrid()
post-processing to remove insular groups of elements that are not connected to a Dirichlet boundary
Definition io/grid/porenetwork/gridmanager.hh:177
void makeGridFromDgfFile(const std::string &fileName)
Make a grid from a DGF file.
Definition io/grid/porenetwork/gridmanager.hh:91
Creates a network grid from a structured lattice. Connections can be randomly deleted.
Definition structuredlatticegridcreator.hh:60
std::shared_ptr< Grid > & gridPtr()
Returns a reference to the grid pointer (std::shared_ptr<Grid>).
Definition structuredlatticegridcreator.hh:130
void init(const std::string &paramGroup="")
Definition structuredlatticegridcreator.hh:80
Some exceptions thrown in DuMux.
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 discretization/porenetwork/fvelementgeometry.hh:24
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Class for grid data attached to dgf or gmsh grid files.
Creates a network grid from a structured lattice. Connections can be randomly deleted.