#ifndef GEO_FAULT_FACTORY_HH #define GEO_FAULT_FACTORY_HH #include <math.h> #include <dune/faultnetworks/facehierarchy.hh> #include <dune/faultnetworks/utils/debugutils.hh> #include <dune/faultnetworks/faultfactories/oscunitcube.hh> #include <dune/faultnetworks/levelinterfacenetwork.hh> #include <dune/faultnetworks/interfacenetwork.hh> #include <dune/faultnetworks/faultinterface.hh> #include <dune/faultnetworks/hierarchicleveliterator.hh> #include <dune/grid/common/mcmgmapper.hh> #include <dune/grid/io/file/vtk/vtkwriter.hh> #include <dune/fufem/boundarypatch.hh> #include <dune/fufem/boundaryiterator.hh> class FaultCorridor { protected: int level_; int lowerY_; int upperY_; std::vector<int> faultToLevel_; int numberOfFaults_; std::vector<int> separatingYIDs_; std::vector<int> faultYs_; private: void setup() { numberOfFaults_ = 0; for (size_t i=0; i<faultToLevel_.size(); i++) { if (faultToLevel_[i]==level_) numberOfFaults_++; } if (numberOfFaults_>0) { separatingYIDs_.resize(numberOfFaults_-1); faultYs_.resize(numberOfFaults_); int yStep = (upperY_-lowerY_)/numberOfFaults_; if (yStep<2) { std::cout << "FaultCorridor::setup() : FaultCorridor does not admit " + std::to_string(numberOfFaults_) + " faults on level " + std::to_string(level_) << std::endl; DUNE_THROW(Dune::Exception, "FaultCorridor::setup() : FaultCorridor does not admit " + std::to_string(numberOfFaults_) + " faults on level " + std::to_string(level_)); } int offSet = yStep + (upperY_-lowerY_-yStep*numberOfFaults_)/2; int prevYID = lowerY_; for (size_t i=0; i<separatingYIDs_.size(); i++) { int newYID = lowerY_ + offSet + i*yStep; separatingYIDs_[i] = newYID; faultYs_[i] = (prevYID+newYID)/2; prevYID = newYID; } faultYs_[faultYs_.size()-1] = (upperY_+prevYID)/2; } else { separatingYIDs_.resize(0); faultYs_.resize(0); } } public: FaultCorridor() {} FaultCorridor(const int level, const int lowerY, const int upperY, std::vector<int> faultToLevel) : level_(level), lowerY_(lowerY), upperY_(upperY), faultToLevel_(faultToLevel) { setup(); } FaultCorridor(const FaultCorridor& faultCorridor) : level_(faultCorridor.level_), lowerY_(faultCorridor.lowerY_), upperY_(faultCorridor.upperY_), faultToLevel_(faultCorridor.faultToLevel_), numberOfFaults_(faultCorridor.numberOfFaults_), separatingYIDs_(faultCorridor.separatingYIDs_), faultYs_(faultCorridor.faultYs_) {} void nextLevel(std::vector<FaultCorridor>& newFaultCorridors, const int resolutionFactor = 2) { size_t idx = 0; int prevYID = resolutionFactor*lowerY_; for (size_t i=0; i<faultYs_.size(); i++) { std::vector<int> newFaultToLevel; for (size_t j=idx; j<faultToLevel_.size(); j++) { idx++; if (faultToLevel_[j]>level_) newFaultToLevel.push_back(faultToLevel_[j]); else break; } newFaultCorridors.push_back(FaultCorridor(level_+1, prevYID, resolutionFactor*faultYs_[i], newFaultToLevel)); prevYID = resolutionFactor*faultYs_[i]; } std::vector<int> newFaultToLevel; for (size_t j=idx; j<faultToLevel_.size(); j++) { idx++; if (faultToLevel_[j]>level_) newFaultToLevel.push_back(faultToLevel_[j]); else break; } newFaultCorridors.push_back(FaultCorridor(level_+1, prevYID, resolutionFactor*upperY_, newFaultToLevel)); } bool isfaultY(int candidatY, int& idx) const { for (size_t i=0; i<faultYs_.size(); i++) { if (faultYs_[i]<candidatY) continue; if (faultYs_[i]==candidatY) { idx = i; return true; } else return false; } return false; } int upperY() const { return upperY_; } int lowerY() const { return lowerY_; } const std::vector<int>& faultToLevel() const { return faultToLevel_; } const std::vector<int>& separatingYIDs() const { return separatingYIDs_; } const std::vector<int>& faultYs() const { return faultYs_; } }; template <class GridType> class LevelGeoFaultFactory { //! Parameter for mapper class template<int dim> struct FaceMapperLayout { bool contains (Dune::GeometryType gt) { return gt.dim() == dim-1; } }; protected: static const int dimworld = GridType::dimensionworld; static const int dim = GridType::dimension; typedef typename GridType::ctype ctype; typedef typename GridType::LevelGridView GV; typedef typename GridType::LevelIntersection Intersection; typedef typename GridType::template Codim<0>::Entity Element; static const int dimElement = Element::dimension; typedef typename Dune::MultipleCodimMultipleGeomTypeMapper<GV, FaceMapperLayout > FaceMapper; private: const std::shared_ptr<GridType> grid_; const int level_; const ctype resolution_; const bool allowLevelIntersections_; const GV gridView_; const typename GV::IndexSet& indexSet_; FaceMapper faceMapper_; std::vector<Intersection> faces_; std::vector<Dune::FieldVector<ctype, dimworld>> vertexPositions_; std::vector<std::vector<size_t>> vertexToFaces_; private: bool intersectionAllowed(const size_t faceID, const size_t vertexID, const double maxAngle, const std::set<size_t>& separatingDofs, const std::set<int>& separatingYIDs, const std::set<size_t>& faultDofs) const { const Intersection& intersection = faces_[faceID]; //check if "back" edge, cannot deviate from desiredOrientation more than maxAngle degrees (radian) Dune::FieldVector<ctype, dimworld> desiredOrientation(1); desiredOrientation /= desiredOrientation.two_norm(); Dune::FieldVector<ctype, dimworld> orientation(intersection.geometry().center()); orientation -= vertexPositions_[vertexID]; orientation /= orientation.two_norm(); if (std::acos(desiredOrientation*orientation) > maxAngle) return false; // check if intersection has separating dofs or other fault dofs std::set<size_t> intersectionDofs; computeIntersectionDofs(indexSet_, intersection, intersectionDofs); intersectionDofs.erase(vertexID); std::set<size_t>::iterator iDofIt = intersectionDofs.begin(); std::set<size_t>::iterator iDofItEnd = intersectionDofs.end(); for (; iDofIt!=iDofItEnd; ++iDofIt) { int yID = computeYID(vertexPositions_[*iDofIt]); if (separatingDofs.count(*iDofIt) || faultDofs.count(*iDofIt) || separatingYIDs.count(yID)) { return false; } } return true; } /* ctype distance(const Intersection& isec, const Dune::FieldVector<ctype, dimworld> & vertex) const { Dune::FieldVector<ctype, dimworld> vec(vertex); vec += isec.center(); return isec.unitOuterNormal()*vec; }*/ //works only in 2D, vertex(1) = vertex(0) - yid, intersection of line (given by vertex and derivative 1) with y axis int computeYID(Dune::FieldVector<ctype, dimworld> vertex) const { return (int) ((vertex[1]-vertex[0])*resolution_); } void computeIntersectionDofs(const typename GV::IndexSet& idxSet, const Intersection& intersection, std::set<size_t>& intersectionDofs) const { intersectionDofs.clear(); // loop over all vertices of the intersection const Element& insideElement = intersection.inside(); const auto& refElement = Dune::ReferenceElements<double,dimElement>::general(insideElement.type()); for (int i=0; i<refElement.size(intersection.indexInInside(), 1, dimElement); i++) { size_t idxInElement = refElement.subEntity(intersection.indexInInside(), 1, i, dimElement); size_t globalIdx = idxSet.subIndex(insideElement, idxInElement, dimElement); intersectionDofs.insert(globalIdx); } } bool isTargetBoundaryVertex(const Dune::FieldVector<ctype, dimworld>& vertex) const { bool result = false; for (size_t i=0; i<vertex.size(); i++) { if (vertex[i]==1.0) { result = true; break; } } return result; } typedef std::vector<double>::const_iterator ConstVectorIterator; struct ordering { bool operator ()(std::pair<size_t, ConstVectorIterator> const& a, std::pair<size_t, ConstVectorIterator> const& b) { return *(a.second) < *(b.second); } }; void distanceSort(std::vector<size_t>& admissibleFaces, std::vector<double>& distances) const { std::vector<std::pair<size_t, ConstVectorIterator>> order(distances.size()); size_t j = 0; ConstVectorIterator it = distances.begin(); ConstVectorIterator itEnd = distances.end(); for (; it != itEnd; ++it, ++j) order[j] = std::make_pair(j, it); sort(order.begin(), order.end(), ordering()); std::vector<size_t> initialAdmissibleFaces(admissibleFaces); for (size_t i=0; i<admissibleFaces.size(); i++) admissibleFaces[i] = initialAdmissibleFaces[order[i].first]; } void generateFaultSeeds(std::vector<FaultCorridor>& faultCorridors, std::vector<std::vector<size_t>>& faultSeeds) { //std::cout << "LevelGeoFaultFactory::generateFaultSeeds() " << std::endl; //std::cout << "------------------------------------- " << std::endl << std::endl; faultSeeds.resize(faultCorridors.size()); std::map<int, std::pair<size_t,size_t>> yIDtoFaultCorridor; for (size_t i=0; i<faultCorridors.size(); i++){ FaultCorridor& faultCorridor = faultCorridors[i]; const std::vector<int> & faultYs = faultCorridor.faultYs(); faultSeeds[i].resize(faultYs.size()); for (size_t j=0; j<faultYs.size(); j++) { yIDtoFaultCorridor[faultYs[j]] = std::make_pair(i, j); } } BoundaryIterator<GV> bIt(gridView_, BoundaryIterator<GV>::begin); BoundaryIterator<GV> bEnd(gridView_, BoundaryIterator<GV>::end); for(; bIt!=bEnd; ++bIt) { const Element& insideElement = bIt->inside(); const auto& geometry = insideElement.geometry(); // neglect "upper" part of boundary, where (y==1 and x>0) or (y>0 and x==1) const auto& center = bIt->geometry().center(); if (center[0] + center[1] >1) continue; const auto& refElement = Dune::ReferenceElements<double,dimElement>::general(insideElement.type()); for (int i=0; i<refElement.size(bIt->indexInInside(), 1, dimElement); i++) { size_t idxInElement = refElement.subEntity(bIt->indexInInside(), 1, i, dimElement); size_t globalIdx = indexSet_.subIndex(insideElement, idxInElement, dimElement); const auto& vertex = geometry.corner(idxInElement); const int yID = computeYID(vertex); if (yIDtoFaultCorridor.count(yID)) { const std::pair<size_t, size_t>& indices = yIDtoFaultCorridor[yID]; faultSeeds[indices.first][indices.second] = globalIdx; } } } //std::cout << "------------------------------------- " << std::endl << std::endl; } void generateFault(std::shared_ptr<FaultInterface<GV>> fault, const size_t faultSeedIdx, const std::set<size_t>& separatingDofs, const std::set<int>& separatingYIDs, const double maxAngle) { // compute target at upper/right part of boundary //std::cout << "LevelGeoFaultFactory::generateFault() " << std::endl; //std::cout << "------------------------------------- " << std::endl << std::endl; bool success = false; const auto& vertexPosition = vertexPositions_[faultSeedIdx]; ctype n = vertexPosition[1]-vertexPosition[0]; Dune::FieldVector<ctype, dimworld> target; if (n>0) { target[0] = 1-n; target[1] = 1; } else { target[0] = 1; target[1] = 1+n; } std::set<size_t> faultDofs; faultDofs.insert(faultSeedIdx); std::vector<size_t> faultFaces; std::map<size_t, std::vector<size_t>> vertexToAdmissibleFaces; std::queue<size_t> vertexQueue; vertexQueue.push(faultSeedIdx); while (!vertexQueue.empty()) { const size_t vertexID = vertexQueue.front(); vertexQueue.pop(); if (isTargetBoundaryVertex(vertexPositions_[vertexID])) { success = true; break; } if (vertexToAdmissibleFaces.count(vertexID)==0) { const std::vector<size_t>& faces = vertexToFaces_[vertexID]; std::vector<size_t> admissibleFaces; for (size_t i=0; i<faces.size(); i++) { if (intersectionAllowed(faces[i], vertexID, maxAngle, separatingDofs, separatingYIDs, faultDofs)) { admissibleFaces.push_back(faces[i]); } } std::vector<double> distances(admissibleFaces.size(), 0); for (size_t i=0; i<admissibleFaces.size(); i++) { Dune::FieldVector<ctype, dimworld> vec(target); vec -= faces_[admissibleFaces[i]].geometry().center(); distances[i] = vec.two_norm(); } distanceSort(admissibleFaces, distances); vertexToAdmissibleFaces[vertexID] = admissibleFaces; } std::vector<size_t>& suitableFaces = vertexToAdmissibleFaces[vertexID]; if (suitableFaces.size()==0) { faultDofs.erase(vertexID); faultFaces.pop_back(); vertexToAdmissibleFaces.erase(vertexID); } else { // generate random number from (0,1) double randomNumber = ((double) std::rand() / (RAND_MAX)); size_t randSelector = (size_t) std::abs(std::log2(randomNumber)); if (randSelector >= suitableFaces.size()) { randSelector = suitableFaces.size() -1; } size_t nextFaceID = suitableFaces[randSelector]; suitableFaces.erase(suitableFaces.begin()+randSelector); std::set<size_t> nextFaceDofs; computeIntersectionDofs(indexSet_, faces_[nextFaceID], nextFaceDofs); nextFaceDofs.erase(vertexID); faultDofs.insert(nextFaceDofs.begin(), nextFaceDofs.end()); faultFaces.push_back(nextFaceID); size_t nextVertexID = *(nextFaceDofs.begin()); vertexQueue.push(nextVertexID); } } if (!success) { std::cout << "Generating a fault failed: Unable to reach target boundary! This should not happend, FaultCorridors should prevent it!" << std::endl; DUNE_THROW(Dune::Exception, "Generating a fault failed: Unable to reach target boundary!"); } for (size_t i=0; i<faultFaces.size(); i++) { fault->addFace(faces_[faultFaces[i]]); } //std::cout << "------------------------------------- " << std::endl << std::endl; } public: LevelGeoFaultFactory(const std::shared_ptr<GridType> grid, const int level, const ctype resolution, const bool allowLevelIntersections = false) : grid_(grid), level_(level), resolution_(resolution), allowLevelIntersections_(allowLevelIntersections), gridView_(grid_->levelGridView(level_)), indexSet_(gridView_.indexSet()), faceMapper_(gridView_) { // init faces_, vertexPositions_, vertexToFaces_ faces_.resize(faceMapper_.size()); vertexPositions_.resize(gridView_.size(dim)); vertexToFaces_.resize(gridView_.size(dim)); std::vector<bool> faceHandled(faceMapper_.size(), false); for (const auto& elem:elements(gridView_)) { for (const auto& isect:intersections(gridView_, elem)) { //const size_t faceID = faceMapper_.index(isect); const int faceID = faceMapper_.subIndex(elem, isect.indexInInside(), 1); if (isect.boundary()) continue; if (faceHandled[faceID]) continue; faceHandled[faceID] = true; faces_[faceID] = isect; const auto& refElement = Dune::ReferenceElements<double,dimElement>::general(elem.type()); for (int i=0; i<refElement.size(isect.indexInInside(), 1, dimElement); i++) { //size_t vertexID = idxSet.subIndex(elem.subEntity<1>(isect), i, dimElement); size_t idxInElement = refElement.subEntity(isect.indexInInside(), 1, i, dimElement); const size_t vertexID = indexSet_.subIndex(elem, idxInElement, dimElement); vertexPositions_[vertexID] = elem.geometry().corner(idxInElement); vertexToFaces_[vertexID].push_back(faceID); } } } } void build(std::vector<std::shared_ptr<FaultInterface<GV>>>& faults, std::vector<FaultCorridor>& faultCorridors, std::set<size_t> separatingDofs, double maxAngle = 2) { std::vector<std::vector<size_t>> faultSeeds; generateFaultSeeds(faultCorridors, faultSeeds); faults.resize(0); for (size_t i=0; i<faultCorridors.size(); i++) { const std::vector<int>& allSeparatingYIDs = faultCorridors[i].separatingYIDs(); if (faultSeeds[i].size()==0) continue; if (faultSeeds[i].size()==1) { std::shared_ptr<FaultInterface<GV>> fault = std::make_shared<FaultInterface<GV>>(gridView_, level_); std::set<int> separatingYIDs; generateFault(fault, faultSeeds[i][0], separatingDofs, separatingYIDs, maxAngle); faults.push_back(fault); } else { // generate first fault whose limits are given by coarser fault and one separatingYID std::shared_ptr<FaultInterface<GV>> fault = std::make_shared<FaultInterface<GV>>(gridView_, level_); std::set<int> separatingYIDs; separatingYIDs.insert(allSeparatingYIDs[0]); generateFault(fault, faultSeeds[i][0], separatingDofs, separatingYIDs, maxAngle); faults.push_back(fault); // generate all intermediate faults whose limits are given by two separatingYIDs for (size_t j=1; j<faultSeeds[i].size()-1; j++) { std::shared_ptr<FaultInterface<GV>> interface = std::make_shared<FaultInterface<GV>>(gridView_, level_); std::set<int> separatingYIDs; separatingYIDs.insert(allSeparatingYIDs[j-1]); separatingYIDs.insert(allSeparatingYIDs[j]); generateFault(interface, faultSeeds[i][j], separatingDofs, separatingYIDs, maxAngle); faults.push_back(interface); } // generate last fault whose limits are given by coarser fault and one separatingYID std::shared_ptr<FaultInterface<GV>> lastFault = std::make_shared<FaultInterface<GV>>(gridView_, level_); std::set<int> lastSeparatingYIDs; lastSeparatingYIDs.insert(allSeparatingYIDs[allSeparatingYIDs.size()-1]); generateFault(lastFault, faultSeeds[i][faultSeeds[i].size()-1], separatingDofs, lastSeparatingYIDs, maxAngle); faults.push_back(lastFault); } } } }; template <class GridType> class GeoFaultFactory { //! Parameter for mapper class template<int dim> struct FaceMapperLayout { bool contains (Dune::GeometryType gt) { return gt.dim() == dim-1; } }; protected: typedef OscUnitCube<GridType, 2> GridOb; static const int dimworld = GridType::dimensionworld ; static const int dim = GridType::dimension; typedef typename GridType::ctype ctype; typedef typename GridType::LevelGridView GV; typedef typename GridType::LevelIntersection Intersection; typedef typename GridType::template Codim<0>::Entity Element; static const int dimElement = Element::dimension; typedef typename Dune::MultipleCodimMultipleGeomTypeMapper<GV, FaceMapperLayout > FaceMapper; private: const std::vector<int>& faultToLevel_; const int coarseResolution_; const size_t maxLevel_; const bool allowIntersections_; const bool allowLevelIntersections_; const int coarseGridN_; std::vector<std::set<size_t>> separatingDofs_; std::vector<int> faultPerLevel_; std::shared_ptr<GridType> grid_; std::shared_ptr<InterfaceNetwork<GridType>> interfaceNetwork_; std::vector<std::shared_ptr<LevelGeoFaultFactory<GridType>>> levelGeoFaultFactories_; std::vector<std::vector<FaultCorridor>> faultCorridorHierarchy_; std::vector<double> levelResolutions_; private: typename std::enable_if<!std::numeric_limits<ctype>::is_integer, bool>::type almost_equal(ctype x, ctype y, int ulp) const { return std::abs(x-y) < std::numeric_limits<ctype>::epsilon() * std::abs(x+y) * ulp || std::abs(x-y) < std::numeric_limits<ctype>::min(); } bool isSeparatingIntersection(const Intersection& intersection, const std::set<int>& separatingYIDs) const { Dune::FieldVector<ctype, dimworld> faceCenter = intersection.geometry().center(); ctype yID = faceCenter[1]*coarseGridN_; ctype intpart; if (almost_equal(std::modf(yID, &intpart), 0.0, 2)) { std::set<int>::iterator it = separatingYIDs.find((int) intpart); if (it!=separatingYIDs.end()) return true; else return false; } else return false; } void computeIntersectionDofs(const typename GV::IndexSet& idxSet, const Intersection& intersection, std::set<size_t>& intersectionDofs) { intersectionDofs.clear(); // loop over all vertices of the intersection const Element& insideElement = intersection.inside(); const auto& refElement = Dune::ReferenceElements<double,dimElement>::general(insideElement.type()); for (int i=0; i<refElement.size(intersection.indexInInside(), 1, dimElement); i++) { size_t idxInElement = refElement.subEntity(intersection.indexInInside(), 1, i, dimElement); size_t globalIdx = idxSet.subIndex(insideElement, idxInElement, dimElement); intersectionDofs.insert(globalIdx); } } public: //setup GeoFaultFactory(const std::vector<int>& faultToLevel, const int coarseResolution, const size_t maxLevel, const bool allowIntersections = false, const bool allowLevelIntersections = false, const double maxAngle = 2) : faultToLevel_(faultToLevel), coarseResolution_(coarseResolution), maxLevel_(maxLevel), allowIntersections_(allowIntersections), allowLevelIntersections_(allowLevelIntersections), coarseGridN_(std::pow(2, coarseResolution_)), interfaceNetwork_(nullptr) { // set faultPerLevel_: faultPerLevel_.resize(maxLevel_+1, 0); for (size_t i=0; i<faultToLevel_.size(); i++) { faultPerLevel_[faultToLevel_[i]]++; } print(faultPerLevel_, "faultPerLevel: "); Dune::UGGrid<dim>::setDefaultHeapSize(4000); GridOb unitCube(coarseGridN_); grid_ = unitCube.grid(); grid_->globalRefine(maxLevel_); separatingDofs_.resize(maxLevel_+1); levelResolutions_.resize(maxLevel_+1); faultCorridorHierarchy_.resize(maxLevel_+1); levelGeoFaultFactories_.resize(maxLevel_+1); // init interface network interfaceNetwork_ = std::make_shared<InterfaceNetwork<GridType>>(*grid_); std::vector<FaultCorridor>& coarsefaultCorridors = faultCorridorHierarchy_[0]; if (faultPerLevel_[0]==0) { FaultCorridor newFaultCorridor(0, -coarseGridN_, coarseGridN_, faultToLevel_); coarsefaultCorridors.push_back(newFaultCorridor); } else { int yStep = (2*coarseGridN_-2)/(faultPerLevel_[0]); int offSet = (2*coarseGridN_-yStep*faultPerLevel_[0])/2 - coarseGridN_; //std::cout << "yStep: " << yStep << " offSet: " << offSet << std::endl; FaultCorridor newFaultCorridor(0, offSet, faultPerLevel_[0]*yStep + offSet, faultToLevel_); coarsefaultCorridors.push_back(newFaultCorridor); } for (size_t i=0; i<=maxLevel_; i++) { std::vector<std::shared_ptr<FaultInterface<GV>>> faults; std::vector<FaultCorridor>& faultCorridors = faultCorridorHierarchy_[i]; levelResolutions_[i] = std::pow(2, coarseResolution_+i); //generate faults on level levelGeoFaultFactories_[i] = std::make_shared<LevelGeoFaultFactory<GridType>>(grid_, i, levelResolutions_[i], allowLevelIntersections_); levelGeoFaultFactories_[i]->build(faults, faultCorridors, separatingDofs_[i], maxAngle); for (size_t j=0; j<faults.size(); j++) { interfaceNetwork_->addInterface(faults[j]); } if (i<maxLevel_) { const int newLevel = i+1; //compute separating dofs for next level given by current levelinterfacenetwork interfaceNetwork_->prolongLevel(i, newLevel); if (!allowIntersections_) { separatingDofs_[newLevel] = interfaceNetwork_->getInterfaceNetworkDofs(newLevel); } //compute faultCorridors for next level std::vector<FaultCorridor>& newLevelFaultCorridors = faultCorridorHierarchy_[newLevel]; newLevelFaultCorridors.resize(0); for (size_t j=0; j<faultCorridors.size(); j++) { faultCorridors[j].nextLevel(newLevelFaultCorridors); } } } } /* void prolongToAll() { // prolong all faults to all subsequent levels for (int i=maxLevel_-1; i>=0; i--) { if (interfaceNetwork_->size(i)>0) { std::set<int> toLevels; for (size_t j=i+1; j<=maxLevel_; j++) { toLevels.insert(j); } interfaceNetwork_->prolongLevelInterfaces(i, toLevels); } } interfaceNetwork_->build(); }*/ /*void prolongToAll() { // prolong all faults to all subsequent levels for (int i=interfaceNetwork_->size()-1; i>=0; i--) { interfaceNetwork_->prolongLevelInterfaces(i, maxLevel_); } interfaceNetwork_->build(); }*/ const GridType& grid() const { return *grid_; } /*const InterfaceNetwork<GridType>& interfaceNetwork() { return *interfaceNetwork_; }*/ InterfaceNetwork<GridType>& interfaceNetwork() { return *interfaceNetwork_; } }; #endif