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++)
 
  400            factory.insertElement(Dune::GeometryTypes::line, {eIdx, eIdx+1});
 
  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
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 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.