Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
geofaultfactory.hh 28.88 KiB
#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