12#ifndef DUMUX_IO_GRID_MANAGER_SUB_HH
13#define DUMUX_IO_GRID_MANAGER_SUB_HH
22#include <dune/common/shared_ptr.hh>
23#include <dune/common/concept.hh>
24#include <dune/common/exceptions.hh>
25#include <dune/grid/common/exceptions.hh>
26#include <dune/grid/yaspgrid.hh>
30#include <dune/subgrid/subgrid.hh>
35#ifndef DUMUX_IO_GRID_MANAGER_BASE_HH
51template<
class Element>
55 auto require(F&& f) ->
decltype(
56 bool(f(std::declval<const Element&>()))
65template <
class HostGr
id,
class HostGr
idManager = Gr
idManager<HostGr
id>>
66class SubGridManagerBase
67:
public GridManagerBase<Dune::SubGrid<HostGrid::dimension, HostGrid>>
69 static constexpr int dim = HostGrid::dimension;
70 using HostElement =
typename HostGrid::template Codim<0>::Entity;
71 using GlobalPosition =
typename HostElement::Geometry::GlobalCoordinate;
80 typename std::enable_if_t<Dune::models<Concept::ElementSelector<HostElement>, ES>(),
int> = 0>
81 void init(HostGrid& hostGrid,
83 const std::string& paramGroup =
"")
85 this->gridPtr() = std::make_unique<Grid>(hostGrid);
86 updateSubGrid_(selector);
94 typename std::enable_if_t<Dune::models<Concept::ElementSelector<HostElement>, ES>(),
int> = 0>
95 void init(
const ES& selector,
96 const std::string& paramGroup =
"")
98 initHostGrid_(paramGroup);
99 this->gridPtr() = std::make_unique<Grid>(hostGridManager_->grid());
100 updateSubGrid_(selector);
109 if (Dune::MPIHelper::getCommunication().size() > 1)
110 this->grid().loadBalance();
117 typename std::enable_if_t<Dune::models<Concept::ElementSelector<HostElement>, ES>(),
int> = 0>
118 void update(
const ES& selector)
120 updateSubGrid_(selector);
130 typename std::enable_if_t<Dune::models<Concept::ElementSelector<HostElement>, ES>(),
int> = 0>
131 void updateSubGrid_(
const ES& selector)
133 auto& subgridPtr = this->gridPtr();
136 std::set<typename HostGrid::Traits::GlobalIdSet::IdType> elementsForSubgrid;
137 const auto& globalIDset = subgridPtr->getHostGrid().globalIdSet();
140 subgridPtr->createBegin();
144 auto hostGridView = subgridPtr->getHostGrid().leafGridView();
145 for (
const auto& e : elements(hostGridView))
147 elementsForSubgrid.insert(globalIDset.template id<0>(e));
149 if (elementsForSubgrid.empty())
150 DUNE_THROW(Dune::GridError,
"No elements in subgrid");
152 subgridPtr->insertSetPartial(elementsForSubgrid);
153 subgridPtr->createEnd();
156 void initHostGrid_(
const std::string& paramGroup)
158 hostGridManager_ = std::make_unique<HostGridManager>();
159 hostGridManager_->init(paramGroup);
162 void initHostGrid_(
const GlobalPosition& lowerLeft,
163 const GlobalPosition& upperRight,
164 const std::array<int, dim>& cells,
165 const std::string& paramGroup,
166 const int overlap = 1,
167 const std::bitset<dim> periodic = std::bitset<dim>{})
169 hostGridManager_ = std::make_unique<HostGridManager>();
170 hostGridManager_->init(lowerLeft, upperRight, cells, paramGroup, overlap, periodic);
176 HostGrid& hostGrid_()
178 return hostGridManager_->grid();
181 std::unique_ptr<HostGridManager> hostGridManager_;
192template<
int dim,
class HostGr
id>
193class GridManager<
Dune::SubGrid<dim, HostGrid>>
194:
public SubGridManagerBase<HostGrid, GridManager<HostGrid>>
207template<
int dim,
class Coordinates>
208class GridManager<
Dune::SubGrid<dim, Dune::YaspGrid<dim, Coordinates>>>
209:
public SubGridManagerBase<Dune::YaspGrid<dim, Coordinates>, GridManager<Dune::YaspGrid<dim, Coordinates>>>
211 using ParentType = SubGridManagerBase<Dune::YaspGrid<dim, Coordinates>,
212 GridManager<Dune::YaspGrid<dim, Coordinates>>>;
214 using typename ParentType::Grid;
215 using ParentType::init;
222 void init(
const std::string& paramGroup =
"")
224 const auto overlap = getParamFromGroup<int>(paramGroup,
"Grid.Overlap", 1);
225 const auto periodic = getParamFromGroup<std::bitset<dim>>(paramGroup,
"Grid.Periodic", std::bitset<dim>{});
230 const auto imgFileName = getParamFromGroup<std::string>(paramGroup,
"Grid.Image");
235 DUNE_THROW(Dune::GridError,
"Portable Bitmap Format only supports dim == 2");
239 createGridFromImage_(img, paramGroup, overlap, periodic);
242 DUNE_THROW(Dune::IOError,
"The SubGridManager doesn't support image files with extension: *." << ext);
247 const auto maskFileName = getParamFromGroup<std::string>(paramGroup,
"Grid.BinaryMask");
248 std::ifstream mask(maskFileName, std::ios_base::binary);
249 std::vector<char> buffer(std::istreambuf_iterator<char>(mask), std::istreambuf_iterator<char>{});
250 const auto cells = getParamFromGroup<std::array<int, dim>>(paramGroup,
"Grid.Cells");
251 if (
const auto c = std::accumulate(cells.begin(), cells.end(), 1, std::multiplies<int>{}); c != buffer.size())
252 DUNE_THROW(Dune::IOError,
"Grid dimensions doesn't match number of cells specified " << c <<
":" << buffer.size());
254 maybePostProcessBinaryMask_(buffer, cells, paramGroup);
256 using GlobalPosition =
typename ParentType::Grid::template Codim<0>::Geometry::GlobalCoordinate;
257 const auto lowerLeft = GlobalPosition(0.0);
258 const auto upperRight = [&]{
261 auto upperRight = getParamFromGroup<GlobalPosition>(paramGroup,
"Grid.PixelDimensions");
262 for (
int i = 0; i < upperRight.size(); ++i)
263 upperRight[i] *= cells[i];
264 upperRight += lowerLeft;
268 return getParamFromGroup<GlobalPosition>(paramGroup,
"Grid.UpperRight");
272 this->initHostGrid_(lowerLeft, upperRight, cells, paramGroup, overlap, periodic);
276 const char marker = getParamFromGroup<char>(paramGroup,
"Grid.Marker", 0);
277 const auto elementSelector = [&](
const auto&
element)
280 while(level0.hasFather())
281 level0 = level0.father();
282 const auto eIdx = this->hostGrid_().levelGridView(0).indexSet().index(level0);
283 return buffer[eIdx] != marker;
287 this->
gridPtr() = std::make_unique<Grid>(this->hostGrid_());
288 this->updateSubGrid_(elementSelector);
293 std::cerr <<
"No element selector provided and Grid.Image or Grid.BinaryMask not found" << std::endl;
294 std::cerr <<
"Constructing sub-grid with all elements of the host grid" << std::endl;
297 using GlobalPosition =
typename ParentType::Grid::template Codim<0>::Geometry::GlobalCoordinate;
298 const auto lowerLeft = getParamFromGroup<GlobalPosition>(paramGroup,
"Grid.LowerLeft", GlobalPosition(0.0));
299 const auto upperRight = getParamFromGroup<GlobalPosition>(paramGroup,
"Grid.UpperRight");
300 const auto cells = getParamFromGroup<std::array<int, dim>>(paramGroup,
"Grid.Cells");
301 this->initHostGrid_(lowerLeft, upperRight, cells, paramGroup, overlap, periodic);
302 const auto elementSelector = [](
const auto&
element){
return true; };
304 this->
gridPtr() = std::make_unique<Grid>(this->hostGrid_());
305 this->updateSubGrid_(elementSelector);
312 void createGridFromImage_(
const Img& img,
const std::string& paramGroup,
const int overlap,
const std::bitset<dim> periodic)
314 using GlobalPosition =
typename ParentType::Grid::template Codim<0>::Geometry::GlobalCoordinate;
318 const std::array<int, dim> imageDimensions{
static_cast<int>(img.header().nCols),
static_cast<int>(img.header().nRows)};
319 std::array<int, dim> cells{imageDimensions[0], imageDimensions[1]};
321 std::array<int, dim> repeatsDefault; repeatsDefault.fill(1);
322 const auto numRepeats = getParamFromGroup<std::array<int, dim>>(paramGroup,
"Grid.Repeat", repeatsDefault);
323 for (
int i = 0; i < dim; i++)
324 cells[i] = cells[i] * numRepeats[i];
327 const auto [lowerLeft, upperRight] = [&]()
329 const auto lowerLeft = getParamFromGroup<GlobalPosition>(paramGroup,
"Grid.LowerLeft", GlobalPosition(0.0));
332 auto upperRight = getParamFromGroup<GlobalPosition>(paramGroup,
"Grid.PixelDimensions");
333 for (
int i = 0; i < upperRight.size(); ++i)
334 upperRight[i] *= cells[i];
335 upperRight += lowerLeft;
336 return std::make_pair(lowerLeft, upperRight);
339 return std::make_pair(lowerLeft, getParamFromGroup<GlobalPosition>(paramGroup,
"Grid.UpperRight"));
343 this->initHostGrid_(lowerLeft, upperRight, cells, paramGroup, overlap, periodic);
347 const bool marked = getParamFromGroup<bool>(paramGroup,
"Grid.Marker",
false);
350 const auto elementSelector = [&](
const auto&
element)
352 auto eIdx = this->hostGrid_().leafGridView().indexSet().index(element);
358 auto level0Element =
element.father();
359 while (level0Element.hasFather())
360 level0Element = level0Element.father();
362 assert(level0Element.level() == 0);
363 eIdx = this->hostGrid_().levelGridView(0).indexSet().index(level0Element);
365 return img[eIdx] == marked;
369 const auto repeatedElementSelector = [&](
const auto&
element)
371 auto eIdx = this->hostGrid_().leafGridView().indexSet().index(element);
377 auto level0Element =
element.father();
378 while (level0Element.hasFather())
379 level0Element = level0Element.father();
381 assert(level0Element.level() == 0);
382 eIdx = this->hostGrid_().levelGridView(0).indexSet().index(level0Element);
386 const int numCols = imageDimensions[0];
387 const int numRows = imageDimensions[1];
390 const int repeatUnitIndex = eIdx % (numCols * numRepeats[0] * numRows);
391 const int imgI = repeatUnitIndex % numCols;
392 const int imgJ = repeatUnitIndex / (numCols * numRepeats[0]);
393 return img[ (imgJ * numCols + imgI) ] == marked;
399 this->
gridPtr() = std::make_unique<Grid>(this->hostGrid_());
400 this->updateSubGrid_(repeatedElementSelector);
404 this->
gridPtr() = std::make_unique<Grid>(this->hostGrid_());
405 this->updateSubGrid_(elementSelector);
412 void maybePostProcessBinaryMask_(std::vector<char>& mask,
const std::array<int, dim>& cells,
const std::string& paramGroup)
const
418 std::vector<int> marker(mask.size(), 0);
419 const std::string direction = getParamFromGroup<std::string>(paramGroup,
"Grid.KeepOnlyConnected");
420 if constexpr (dim == 3)
422 if (direction ==
"Y")
424 std::cout <<
"Keeping only cells connected to both boundaries in y-direction" << std::endl;
425 flood_(mask, marker, cells, 0, 0, 0, cells[0], 1, cells[2], 1);
426 flood_(mask, marker, cells, 0, cells[1]-1, 0, cells[0], cells[1], cells[2], 2);
428 else if (direction ==
"Z")
430 std::cout <<
"Keeping only cells connected to both boundaries in z-direction" << std::endl;
431 flood_(mask, marker, cells, 0, 0, 0, cells[0], cells[1], 1, 1);
432 flood_(mask, marker, cells, 0, 0, cells[2]-1, cells[0], cells[1], cells[2], 2);
436 std::cout <<
"Keeping only cells connected to both boundaries in x-direction" << std::endl;
437 flood_(mask, marker, cells, 0, 0, 0, 1, cells[1], cells[2], 1);
438 flood_(mask, marker, cells, cells[0]-1, 0, 0, cells[0], cells[1], cells[2], 2);
441 for (
unsigned int i = 0; i < cells[0]; ++i)
442 for (
unsigned int j = 0; j < cells[1]; ++j)
443 for (
unsigned int k = 0; k < cells[2]; ++k)
444 if (
const auto ijk = getIJK_(i, j, k, cells); marker[ijk] < 2)
448 else if constexpr (dim == 2)
450 if (direction ==
"Y")
452 std::cout <<
"Keeping only cells connected to both boundaries in y-direction" << std::endl;
453 flood_(mask, marker, cells, 0, 0, cells[0], 1, 1);
454 flood_(mask, marker, cells, 0, cells[1]-1, cells[0], cells[1], 2);
458 std::cout <<
"Keeping only cells connected to both boundaries in x-direction" << std::endl;
459 flood_(mask, marker, cells, 0, 0, 1, cells[1], 1);
460 flood_(mask, marker, cells, cells[0]-1, 0, cells[0], cells[1], 2);
463 for (
unsigned int i = 0; i < cells[0]; ++i)
464 for (
unsigned int j = 0; j < cells[1]; ++j)
465 if (
const auto ij = getIJ_(i, j, cells); marker[ij] < 2)
469 DUNE_THROW(Dune::NotImplemented,
"KeepOnlyConnected only implemented for 2D and 3D");
473 void flood_(std::vector<char>& mask, std::vector<int>& markers,
const std::array<int, 3>& cells,
474 unsigned int iMin,
unsigned int jMin,
unsigned int kMin,
475 unsigned int iMax,
unsigned int jMax,
unsigned int kMax,
479 for (
unsigned int i = iMin; i < iMax; ++i)
480 for (
unsigned int j = jMin; j < jMax; ++j)
481 for (
unsigned int k = kMin; k < kMax; ++k)
482 fill_(mask, markers, cells, i, j, k, marker);
485 void flood_(std::vector<char>& mask, std::vector<int>& markers,
const std::array<int, 2>& cells,
486 unsigned int iMin,
unsigned int jMin,
487 unsigned int iMax,
unsigned int jMax,
491 for (
unsigned int i = iMin; i < iMax; ++i)
492 for (
unsigned int j = jMin; j < jMax; ++j)
493 fill_(mask, markers, cells, i, j, marker);
496 void fill_(std::vector<char>& mask, std::vector<int>& markers,
const std::array<int, 3>& cells,
497 unsigned int i,
unsigned int j,
unsigned int k,
int marker)
const
499 std::stack<std::tuple<unsigned int, unsigned int, unsigned int>> st;
500 st.push(std::make_tuple(i, j, k));
503 std::tie(i, j, k) = st.top();
506 if (i >= cells[0] || j >= cells[1] || k >= cells[2])
509 const auto ijk = getIJK_(i, j, k, cells);
510 if (!mask[ijk] || markers[ijk] >= marker)
516 st.push(std::make_tuple(i+1, j, k));
517 st.push(std::make_tuple(i-1, j, k));
518 st.push(std::make_tuple(i, j+1, k));
519 st.push(std::make_tuple(i, j-1, k));
520 st.push(std::make_tuple(i, j, k+1));
521 st.push(std::make_tuple(i, j, k-1));
525 void fill_(std::vector<char>& mask, std::vector<int>& markers,
const std::array<int, 2>& cells,
526 unsigned int i,
unsigned int j,
int marker)
const
528 std::stack<std::tuple<unsigned int, unsigned int>> st;
529 st.push(std::make_tuple(i, j));
532 std::tie(i, j) = st.top();
535 if (i >= cells[0] || j >= cells[1])
538 const auto ij = getIJ_(i, j, cells);
539 if (!mask[ij] || markers[ij] >= marker)
545 st.push(std::make_tuple(i+1, j));
546 st.push(std::make_tuple(i-1, j));
547 st.push(std::make_tuple(i, j+1));
548 st.push(std::make_tuple(i, j-1));
552 int getIJK_(
int i,
int j,
int k,
const std::array<int, 3>& cells)
const
553 {
return i + j*cells[0] + k*cells[0]*cells[1]; }
555 int getIJ_(
int i,
int j,
const std::array<int, 2>& cells)
const
556 {
return i + j*cells[0]; }
560template<
int dim,
class HostGr
id>
561class BoundaryFlag<
Dune::SubGrid<dim, HostGrid>>
564 BoundaryFlag() : flag_(invalidFlag_) {}
566 template<
class Intersection>
567 BoundaryFlag(
const Intersection& i) : flag_(invalidFlag_) {}
572 { DUNE_THROW(Dune::NotImplemented,
"Sub-grid doesn't implement boundary segment indices!"); }
574 operator bool()
const {
return flag_ != invalidFlag_; }
577 static constexpr value_type invalidFlag_ = -1;
582template<
int dim,
typename HostGr
id,
bool MapIndexStorage>
583struct PeriodicGridTraits<
Dune::SubGrid<dim, HostGrid, MapIndexStorage>>
588 const Grid& subGrid_;
589 const PeriodicGridTraits<HostGrid> hostTraits_;
592 struct SupportsPeriodicity :
public PeriodicGridTraits<HostGrid>::SupportsPeriodicity {};
595 : subGrid_(subGrid), hostTraits_(subGrid_.getHostGrid()) {};
597 bool isPeriodic (
const typename Grid::LeafIntersection& intersection)
const
599 const auto& hostElement = subGrid_.template getHostEntity<0>(intersection.inside());
600 for (
const auto& hostIntersection : intersections(subGrid_.getHostGrid().leafGridView(), hostElement))
602 if (hostIntersection.indexInInside() == intersection.indexInInside())
604 const bool periodicInHostGrid = hostTraits_.isPeriodic(hostIntersection);
605 return periodicInHostGrid && subGrid_.template contains<0>(hostIntersection.outside());
611 void verifyConformingPeriodicBoundary()
const
613 for (
const auto& element : elements(subGrid_.leafGridView()))
615 for (
const auto& intersection : intersections(subGrid_.leafGridView(), element))
617 const auto& hostElement = subGrid_.template getHostEntity<0>(intersection.inside());
618 for (
const auto& hostIntersection : intersections(subGrid_.getHostGrid().leafGridView(), hostElement))
620 if (hostIntersection.indexInInside() == intersection.indexInInside())
622 const bool periodicInHostGrid = hostTraits_.isPeriodic(hostIntersection);
623 if (periodicInHostGrid && !subGrid_.template contains<0>(hostIntersection.outside()))
624 DUNE_THROW(Dune::GridError,
"Periodic boundary in host grid but outside"
625 <<
" element not included in subgrid. If this is intentional,"
626 <<
" take additional care with boundary conditions and remove"
627 <<
" verification call.");
Boundary flag to store e.g. in sub control volume faces.
std::size_t value_type
Definition: boundaryflag.hh:28
value_type get() const
Definition: boundaryflag.hh:41
void loadBalance()
Call loadBalance() function of the grid.
Definition: gridmanager_base.hh:98
std::shared_ptr< Grid > & gridPtr()
Returns a reference to the grid pointer (std::shared_ptr<Grid>)
Definition: gridmanager_base.hh:163
void init(const std::string &modelParamGroup="")
Make the grid. Implement this method in the specialization of this class for a grid type.
Definition: gridmanager_base.hh:64
std::string getFileExtension(const std::string &fileName) const
Returns the filename extension of a given filename.
Definition: gridmanager_base.hh:185
static Result< bool > readPBM(const std::string &fileName, const bool useDuneGridOrdering=true)
Reads a *pbm (black and white) in ASCII or binary encoding. Returns a struct that contains both the p...
Definition: rasterimagereader.hh:81
Definition: consistentlyorientedgrid.hh:23
Provides a grid manager for all supported grid managers with input file interfaces....
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
Definition: common/pdesolver.hh:24
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Grid properties related to periodicity.
A simple reader class for raster images.
A simple writer class for raster images.
bool isPeriodic(const typename Grid::LeafIntersection &intersection) const
Definition: periodicgridtraits.hh:28
PeriodicGridTraits(const Grid &grid)
Definition: periodicgridtraits.hh:26