3.6-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
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 * 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_PORE_NETWORK_GRID_MANAGER_HH
25#define DUMUX_PORE_NETWORK_GRID_MANAGER_HH
26
27#if HAVE_DUNE_FOAMGRID
28
29#include <iostream>
30#include <algorithm>
31#include <vector>
32
33#include <dune/common/classname.hh>
34#include <dune/common/exceptions.hh>
35#include <dune/common/timer.hh>
36
37// FoamGrid specific includes
38#include <dune/foamgrid/foamgrid.hh>
39#include <dune/foamgrid/dgffoam.hh>
40
43
44#include "griddata.hh"
46
47namespace Dumux::PoreNetwork {
48
53template<int dimWorld, class GData = Dumux::PoreNetwork::GridData<Dune::FoamGrid<1, dimWorld>>>
54class GridManager
55{
56 using GridType = Dune::FoamGrid<1, dimWorld>;
57 using Element = typename GridType::template Codim<0>::Entity;
58 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
59
60public:
61 using Grid = GridType;
62 using GridData = GData;
63
64 void init(const std::string& paramGroup = "")
65 {
66 Dune::Timer timer;
67 paramGroup_ = paramGroup;
68
69 // First try to create it from a DGF file in GridParameterGroup.File
70 if (hasParamInGroup(paramGroup, "Grid.File"))
71 {
72 makeGridFromDgfFile(getParamFromGroup<std::string>(paramGroup, "Grid.File"));
73 loadBalance();
74 }
75 else // no grid file found
76 {
77 // create a structured grid (1D grid or lattice grid)
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();
83 else
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)."
88 );
89
90 loadBalance();
91 }
92
93 timer.stop();
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;
97 }
98
102 void makeGridFromDgfFile(const std::string& fileName)
103 {
104 // We found a file in the input file...does it have a supported extension?
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);
108
109 enableDgfGridPointer_ = true;
110 dgfGridPtr() = Dune::GridPtr<Grid>(fileName.c_str(), Dune::MPIHelper::getCommunicator());
111 gridData_ = std::make_shared<GridData>(dgfGridPtr_, paramGroup_);
112
113 if (getParamFromGroup<bool>(paramGroup_, "Grid.Sanitize", false))
114 sanitizeGrid();
115 }
116
120 void makeGridFromStructuredLattice()
121 {
122 StructuredLatticeGridCreator<dimWorld> creator;
123 creator.init(paramGroup_);
124 gridPtr() = creator.gridPtr();
125
126 gridData_ = std::make_shared<GridData>(gridPtr_, paramGroup_);
127
128 if (getParamFromGroup<bool>(paramGroup_, "Grid.Sanitize", true))
129 sanitizeGrid();
130 else
131 std::cout << "\nWARNING: Set Grid.Sanitize = true in order to remove insular patches of elements not connected to the boundary." << std::endl;
132
133 gridData_->assignParameters();
134 }
135
139 std::string getFileExtension(const std::string& fileName) const
140 {
141 std::size_t i = fileName.rfind('.', fileName.length());
142 if (i != std::string::npos)
143 return(fileName.substr(i+1, fileName.length() - i));
144 else
145 DUNE_THROW(Dune::IOError, "Please provide and extension for your grid file ('"<< fileName << "')!");
146 return "";
147 }
148
152 Grid& grid()
153 { return enableDgfGridPointer_ ? *dgfGridPtr() : *gridPtr(); }
154
158 std::shared_ptr<GridData> getGridData() const
159 {
160 if (!gridData_)
161 DUNE_THROW(Dune::IOError, "No grid data available");
162
163 return gridData_;
164 }
165
169 void loadBalance()
170 {
171 if (Dune::MPIHelper::getCommunication().size() > 1)
172 {
173 // if we may have dgf parameters use load balancing of the dgf pointer
174 if (enableDgfGridPointer_)
175 {
176 dgfGridPtr().loadBalance();
177 // update the grid data
178 gridData_ = std::make_shared<GridData>(dgfGridPtr(), paramGroup_);
179 }
180 else
181 gridPtr()->loadBalance();
182 }
183 }
184
188 void sanitizeGrid()
189 {
190 // evaluate the coordination numbers to check if all pores are connected to at least one throat
191 gridData_->getCoordinationNumbers();
192
193 // for dgf grid, copy the data to persistent containers
194 if (enableDgfGridPointer_)
195 gridData_->copyDgfData();
196
197 const auto gridView = grid().leafGridView();
198 static const std::string sanitationMode = getParamFromGroup<std::string>(paramGroup_, "Grid.SanitationMode", "KeepLargestCluster");
199
200 // find the elements to keep, all others will be deleted
201 const auto keepElement = [&]
202 {
203 if (sanitationMode == "UsePoreLabels")
204 return findElementsConnectedToPoreLabel(gridView);
205 else if (sanitationMode == "KeepLargestCluster")
206 return findElementsInLargestCluster(gridView);
207 else
208 DUNE_THROW(Dune::IOError, sanitationMode << "is not a valid sanitation mode. Use KeepLargestCluster or UsePoreLabels.");
209
210
211 }();
212
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");
216
217 // remove the elements in the grid
218 std::size_t numDeletedElements = 0;
219 grid().preGrow();
220 for (const auto& element : elements(gridView))
221 {
222 const auto eIdx = gridView.indexSet().index(element);
223 if (!keepElement[eIdx])
224 {
225 grid().removeElement(element);
226 ++numDeletedElements;
227 }
228 }
229 // triggers the grid growth process
230 grid().grow();
231 grid().postGrow();
232
233 // resize the parameters for dgf grids
234 if (enableDgfGridPointer_)
235 gridData_->resizeParameterContainers();
236
237 if (numDeletedElements > 0)
238 std::cout << "\nDeleted " << numDeletedElements << " isolated elements.\n" << std::endl;
239 }
240
245 std::vector<bool> findElementsConnectedToPoreLabel(const typename Grid::LeafGridView& gridView) const
246 {
247 // pruning -- remove elements not connected to a Dirichlet boundary (marker == 1)
248 const auto pruningSeedIndices = getParamFromGroup<std::vector<int>>(paramGroup_, "Grid.PruningSeedIndices", std::vector<int>{1});
249 std::vector<bool> elementIsConnected(gridView.size(0), false);
250
251 auto boundaryIdx = [&](const auto& vertex)
252 {
253 if (enableDgfGridPointer_)
254 return static_cast<int>(dgfGridPtr_.parameters(vertex)[gridData_->parameterIndex("PoreLabel")]);
255 else
256 return static_cast<int>(gridData_->poreLabelAtPosForGenericGrid(vertex.geometry().center()));
257 };
258
259 for (const auto& element : elements(gridView))
260 {
261 const auto eIdx = gridView.indexSet().index(element);
262 if (elementIsConnected[eIdx])
263 continue;
264
265 // try to find a seed from which to start the search process
266 bool isSeed = false;
267 bool hasNeighbor = false;
268 for (const auto& intersection : intersections(gridView, element))
269 {
270 auto vertex = element.template subEntity<1>(intersection.indexInInside());
271 // seed found
272 if (std::any_of(pruningSeedIndices.begin(), pruningSeedIndices.end(),
273 [&]( const int i ){ return i == boundaryIdx(vertex); }))
274 {
275 isSeed = true;
276 // break;
277 }
278
279 if (intersection.neighbor())
280 hasNeighbor = true;
281 }
282
283 if (!hasNeighbor)
284 continue;
285
286 if (isSeed)
287 {
288 elementIsConnected[eIdx] = true;
289
290 // use iteration instead of recursion here because the recursion can get too deep
291 recursivelyFindConnectedElements_(gridView, element, elementIsConnected);
292 }
293 }
294
295 return elementIsConnected;
296 }
297
302 std::vector<bool> findElementsInLargestCluster(const typename Grid::LeafGridView& gridView) const
303 {
304 const auto clusteredElements = clusterElements(gridView);
305
306 const auto numClusters = *std::max_element(clusteredElements.begin(), clusteredElements.end()) + 1;
307 std::cout << "\nFound " << numClusters << " unconnected clusters." << std::endl;
308
309 // count number of elements in individual clusters
310 std::vector<std::size_t> clusterFrequency(numClusters);
311 for (const auto clusterIdx : clusteredElements)
312 clusterFrequency[clusterIdx] += 1;
313
314 const auto largestCluster = std::max_element(clusterFrequency.begin(), clusterFrequency.end());
315 const auto largestClusterIdx = std::distance(clusterFrequency.begin(), largestCluster);
316
317 std::vector<bool> elementsInLargestCluster(gridView.size(0));
318
319 for (int eIdx = 0; eIdx < clusteredElements.size(); ++eIdx)
320 if (clusteredElements[eIdx] == largestClusterIdx)
321 elementsInLargestCluster[eIdx] = true;
322
323 return elementsInLargestCluster;
324 }
325
329 std::vector<std::size_t> clusterElements(const typename Grid::LeafGridView& gridView) const
330 {
331 std::vector<std::size_t> elementInCluster(gridView.size(0), 0); // initially, all elements are in pseudo cluster 0
332 std::size_t clusterIdx = 0;
333
334 for (const auto& element : elements(gridView))
335 {
336 const auto eIdx = gridView.indexSet().index(element);
337 if (elementInCluster[eIdx]) // element already is in a cluster
338 continue;
339
340 ++clusterIdx;
341 elementInCluster[eIdx] = clusterIdx;
342
343 recursivelyFindConnectedElements_(gridView, element, elementInCluster, clusterIdx);
344 }
345
346 // make sure the clusters start with index zero
347 for (auto& clusterIdx : elementInCluster)
348 clusterIdx -= 1;
349
350 return elementInCluster;
351 }
352
353protected:
354
358 std::shared_ptr<Grid>& gridPtr()
359 {
360 if(!enableDgfGridPointer_)
361 return gridPtr_;
362 else
363 DUNE_THROW(Dune::InvalidStateException, "You are using DGF. To get the grid pointer use method dgfGridPtr()!");
364 }
365
369 Dune::GridPtr<Grid>& dgfGridPtr()
370 {
371 if(enableDgfGridPointer_)
372 return dgfGridPtr_;
373 else
374 DUNE_THROW(Dune::InvalidStateException, "The DGF grid pointer is only available if the grid was constructed with a DGF file!");
375 }
376
381 bool enableDgfGridPointer_ = false;
382
383 std::shared_ptr<Grid> gridPtr_;
384 Dune::GridPtr<Grid> dgfGridPtr_;
385
386 std::shared_ptr<GridData> gridData_;
387
388 std::string paramGroup_;
389
390private:
391
392 void createOneDGrid_(unsigned int numPores)
393 {
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;
397
398 // create a step vector
399 GlobalPosition step = upperRight;
400 step -= lowerLeft, step /= cells;
401
402 // make the grid (structured interval grid in dimworld space)
403 Dune::GridFactory<Grid> factory;
404
405 // create the vertices
406 GlobalPosition globalPos = lowerLeft;
407 for (unsigned int vIdx = 0; vIdx <= cells; vIdx++, globalPos += step)
408 factory.insertVertex(globalPos);
409
410 // create the cells
411 for(unsigned int eIdx = 0; eIdx < cells; eIdx++)
412 factory.insertElement(Dune::GeometryTypes::line, {eIdx, eIdx+1});
413
414 gridPtr() = std::shared_ptr<Grid>(factory.createGrid());
415 gridData_ = std::make_shared<GridData>(gridPtr_, paramGroup_);
416 gridData_->assignParameters();
417 }
418
419 template<class T>
420 void recursivelyFindConnectedElements_(const typename Grid::LeafGridView& gridView,
421 const Element& element,
422 std::vector<T>& elementIsConnected,
423 T marker = 1) const
424 {
425 // use iteration instead of recursion here because the recursion can get too deep
426 std::stack<Element> elementStack;
427 elementStack.push(element);
428 while (!elementStack.empty())
429 {
430 auto e = elementStack.top();
431 elementStack.pop();
432 for (const auto& intersection : intersections(gridView, e))
433 {
434 if (!intersection.boundary())
435 {
436 auto outside = intersection.outside();
437 auto nIdx = gridView.indexSet().index(outside);
438 if (!elementIsConnected[nIdx])
439 {
440 elementIsConnected[nIdx] = marker;
441 elementStack.push(outside);
442 }
443 }
444 }
445 }
446 }
447};
448
449}
450
451#endif // HAVE_DUNE_FOAMGRID
452
453#endif
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 &paramGroup, const std::string &param)
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