Skip to content
Snippets Groups Projects
supportpatchfactory.hh 28 KiB
Newer Older
podlesny's avatar
.
podlesny committed
#ifndef SUPPORT_PATCH_FACTORY_HH
#define SUPPORT_PATCH_FACTORY_HH

#include <set>
#include <queue>
#include <memory>

#include <dune/common/bitsetvector.hh>
#include <dune/common/fvector.hh>
podlesny's avatar
.  
podlesny committed
#include <dune/common/hybridutilities.hh>
podlesny's avatar
.
podlesny committed

#include <dune/fufem/referenceelementhelper.hh>
#include <dune/grid/common/mcmgmapper.hh>

#include <dune/localfunctions/lagrange/pqkfactory.hh>

//#include "../../data-structures/levelcontactnetwork.hh"
#include "hierarchicleveliterator.hh"

podlesny's avatar
.  
podlesny committed
#include "../../utils/debugutils.hh"

podlesny's avatar
.
podlesny committed
template <class LevelContactNetwork>
podlesny's avatar
.  
podlesny committed
class NetworkIndexMapper {
podlesny's avatar
.
podlesny committed
private:
podlesny's avatar
.  
podlesny committed
    static const int dim = LevelContactNetwork::dim; //TODO
    using ctype = typename LevelContactNetwork::GridView::ctype;

podlesny's avatar
.  
podlesny committed
    using FiniteElementCache = Dune::PQkLocalFiniteElementCache<ctype, ctype, dim, 1>; // P1 finite element cache
podlesny's avatar
.  
podlesny committed
    using Element = typename LevelContactNetwork::GridView::template Codim<0>::Entity;
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
    const FiniteElementCache cache_;
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
    const LevelContactNetwork& levelContactNetwork_;
    const size_t nBodies_;
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
    std::vector<size_t> vertexOffSet_;
    std::vector<size_t> faceOffSet_;
    std::vector<size_t> elementOffSet_;
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
public:
    NetworkIndexMapper(const LevelContactNetwork& levelContactNetwork) :
        levelContactNetwork_(levelContactNetwork),
        nBodies_(levelContactNetwork_.nBodies()),
        vertexOffSet_(nBodies_),
        faceOffSet_(nBodies_),
        elementOffSet_(nBodies_) {
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
        size_t vertexOffSet = 0;
        size_t faceOffSet = 0;
        size_t elementOffSet = 0;
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
        for (size_t i=0; i<nBodies_; i++) {
            const auto& gridView = levelContactNetwork_.body(i)->gridView();
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
            vertexOffSet_[i] = vertexOffSet;
            vertexOffSet = vertexOffSet_[i] + gridView.size(dim);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
            faceOffSet_[i] = faceOffSet;
            faceOffSet = faceOffSet_[i] + gridView.size(1);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
            elementOffSet_[i] = elementOffSet;
            elementOffSet = elementOffSet_[i] + gridView.size(0);
podlesny's avatar
.
podlesny committed
        }
    }

podlesny's avatar
.  
podlesny committed
    size_t vertexIndex(const size_t bodyID, const Element& elem, const size_t localVertex) const {
        const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
        auto localIdx = cache().get(elem.type()).localCoefficients().localKey(localVertex).subEntity();
podlesny's avatar
.  
podlesny committed
        return vertexOffSet_[bodyID] + gridView.indexSet().subIndex(elem, localIdx, dim);
podlesny's avatar
.
podlesny committed
    }

podlesny's avatar
.  
podlesny committed
    template <class Intersection>
    size_t faceIndex(const size_t bodyID, const Intersection& is) const {
        const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
        return faceOffSet_[bodyID] + gridView.indexSet().subIndex(is.inside(), is.indexInInside(), 1);
podlesny's avatar
.
podlesny committed
    }

podlesny's avatar
.  
podlesny committed
    size_t faceIndex(const size_t bodyID, const Element& elem, const size_t indexInInside) const {
        const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
        return faceOffSet_[bodyID] + gridView.indexSet().subIndex(elem, indexInInside, 1);
podlesny's avatar
.
podlesny committed
    }

podlesny's avatar
.  
podlesny committed
    size_t elementIndex(const size_t bodyID, const Element& elem) const {
        const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
        return elementOffSet_[bodyID] + gridView.indexSet().index(elem);
podlesny's avatar
.
podlesny committed
    }

podlesny's avatar
.  
podlesny committed
    const auto& cache() const {
podlesny's avatar
.
podlesny committed
        return cache_;
    }
};

podlesny's avatar
.  
podlesny committed


podlesny's avatar
.
podlesny committed
/**
 *  constructs BitSetVector whose entries are
 *      true,   if vertex is outside of patch or part of patch boundary
 *      false,  if vertex is in interior of patch
 */
template <class LevelContactNetwork>
class SupportPatchFactory
{
public:
    using Patch = Dune::BitSetVector<1>;

private:
podlesny's avatar
.  
podlesny committed
    static const int dim = LevelContactNetwork::dim; //TODO
    using ctype = typename LevelContactNetwork::ctype;

    using Element = typename LevelContactNetwork::GridView::template Codim<0>::Entity;

podlesny's avatar
.  
podlesny committed
    struct RemoteIntersection {
        size_t bodyID; // used to store bodyID of outside elem
podlesny's avatar
.  
podlesny committed
        size_t contactCouplingID;
podlesny's avatar
.  
podlesny committed
        size_t intersectionID;

        bool flip = false;

podlesny's avatar
.  
podlesny committed
        void set(const size_t _bodyID, const size_t _contactCouplingID, const size_t _intersectionID, const bool _flip = false) {
podlesny's avatar
.  
podlesny committed
            bodyID = _bodyID;
podlesny's avatar
.  
podlesny committed
            contactCouplingID = _contactCouplingID;
podlesny's avatar
.  
podlesny committed
            intersectionID = _intersectionID;
            flip = _flip;
        }

podlesny's avatar
.  
podlesny committed
        auto get(const LevelContactNetwork& levelContactNetwork) const {
            return std::move(levelContactNetwork.glue(contactCouplingID)->getIntersection(intersectionID));
        }
    };

    struct BodyElement {
        size_t bodyID;
        Element element;

        void set(const size_t _bodyID, const Element& _elem) {
            bodyID = _bodyID;
            element = _elem;
        }

        void set(const LevelContactNetwork& levelContactNetwork, const RemoteIntersection& rIs) {
            const auto& is = rIs.get(levelContactNetwork);

            if (rIs.flip) {
                set(rIs.bodyID, is.inside());
            } else {
                set(rIs.bodyID, is.outside());
            }
podlesny's avatar
.  
podlesny committed
        }
    };

    using NetworkIndexMapper = NetworkIndexMapper<LevelContactNetwork>;

podlesny's avatar
.
podlesny committed
    const size_t nBodies_;

    const LevelContactNetwork& coarseContactNetwork_;
    const LevelContactNetwork& fineContactNetwork_;

podlesny's avatar
.  
podlesny committed
    size_t nVertices_ = 0;

podlesny's avatar
.  
podlesny committed
    std::map<size_t, std::vector<RemoteIntersection>> coarseIntersectionMapper_; // map faceID to neighbor elements
    std::map<size_t, std::vector<RemoteIntersection>> fineIntersectionMapper_; // map faceID to neighbor elements
    std::map<size_t, std::vector<size_t>> neighborFaceDofs_; // map faceID to neighbor element dofs
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
    std::set<size_t> interiorContactDofs_;
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
    const NetworkIndexMapper coarseIndices_;
    const NetworkIndexMapper fineIndices_;
podlesny's avatar
.
podlesny committed

public:
    SupportPatchFactory(const LevelContactNetwork& coarseContactNetwork, const LevelContactNetwork& fineContactNetwork) :
podlesny's avatar
.  
podlesny committed
        nBodies_(coarseContactNetwork.nBodies()),
podlesny's avatar
.
podlesny committed
        coarseContactNetwork_(coarseContactNetwork),
        fineContactNetwork_(fineContactNetwork),
podlesny's avatar
.  
podlesny committed
        coarseIndices_(coarseContactNetwork_),
        fineIndices_(fineContactNetwork_) {
podlesny's avatar
.
podlesny committed

        assert(nBodies_ == fineContactNetwork_.nBodies());

podlesny's avatar
.  
podlesny committed
        for (size_t i=0; i<nBodies_; i++) {
            nVertices_ += fineContactNetwork_.body(i)->nVertices();
        }

podlesny's avatar
.  
podlesny committed
        setup(coarseContactNetwork_, coarseIndices_, coarseIntersectionMapper_);
        setup(fineContactNetwork_, fineIndices_, fineIntersectionMapper_);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
        // setup neighborFaceDofs_
podlesny's avatar
.  
podlesny committed
        for (size_t i=0; i<coarseContactNetwork_.nCouplings(); i++) {
                const auto& coupling = *coarseContactNetwork_.coupling(i);
                const auto& glue = *coarseContactNetwork_.glue(i);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                const size_t nmBody = coupling.gridIdx_[0];
                const size_t mBody = coupling.gridIdx_[1];
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                for (const auto& rIs : intersections(glue)) {
                    size_t nmFaceIdx = coarseIndices_.faceIndex(nmBody, rIs.inside(), rIs.indexInInside());
                    size_t mFaceIdx = coarseIndices_.faceIndex(mBody, rIs.outside(), rIs.indexInOutside());
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                    std::vector<std::set<size_t>> dofs;
podlesny's avatar
.  
podlesny committed
                    remoteIntersectionDofs(coarseIndices_, rIs, nmBody, mBody, dofs);
podlesny's avatar
.  
podlesny committed

                    if (dofs[1].size()>0) {
                        neighborFaceDofs_[nmFaceIdx].insert(neighborFaceDofs_[nmFaceIdx].end(), dofs[1].begin(), dofs[1].end());
                    }

                    if (dofs[0].size()>0) {
                        neighborFaceDofs_[mFaceIdx].insert(neighborFaceDofs_[mFaceIdx].end(), dofs[0].begin(), dofs[0].end());
                    }
podlesny's avatar
.  
podlesny committed
                }
podlesny's avatar
.  
podlesny committed
        }

        for (size_t i=0; i<nBodies_; i++) {
            std::cout << "Coarse body" << i << ":" << std::endl;

            for (const auto& e : elements(coarseContactNetwork_.body(i)->gridView())) {
                std::cout << "elemID: " << coarseIndices_.elementIndex(i, e) << std::endl;
                std::cout << "vertexIDs: ";
                const int dimElement = Element::dimension;
                const auto& refElement = Dune::ReferenceElements<double, dimElement>::general(e.type());

                for (int j=0; j<refElement.size(dim); j++) {
                    std::cout << coarseIndices_.vertexIndex(i, e, j) << " ";
                }
                std::cout << std::endl;

                std::cout << "intersectionIDs: ";
                for (const auto& is : intersections(coarseContactNetwork_.body(i)->gridView(), e)) {
                    std::cout << coarseIndices_.faceIndex(i, e, is.indexInInside()) << " (";

                    std::set<size_t> dofs;
                    intersectionDofs(coarseIndices_, is, i, dofs);
                    for (auto& d : dofs) {
                        std::cout << d << " ";
                    }
                    std::cout << "); ";

                }
                std::cout << std::endl  << "--------------" << std::endl;
podlesny's avatar
.
podlesny committed
            }
podlesny's avatar
.  
podlesny committed
        }

        std::cout << std::endl;
        for (auto& kv : neighborFaceDofs_) {
            std::cout << "faceID: " << kv.first << " dofs: ";
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
            const auto& dofs = kv.second;
            for (auto& d : dofs) {
                std::cout << d << " ";
            }
            std::cout << std::endl;
        }
podlesny's avatar
.  
podlesny committed
        /*
            // neighborElementDofs_ contains dofs of connected intersections that are neighbors to a face given by faceID,
            // boundary dofs are contained once, interior dofs multiple times
            // task: remove boundary dofs and redundant multiples of interior dofs
            // TODO: only works in 2D
            for (auto& it : neighborElementDofs) {
                auto& dofs = it.second;

                std::sort(dofs.begin(), dofs.end());
                auto& dof = dofs.begin();
                while (dof != dofs.end()) {
                    auto next = dof;
                    if (*dof != *(++next))
                        dof = dofs.erase(dof);
                }
                dofs.erase(std::unique(dofs.begin(), dofs.end()), dofs.end());
podlesny's avatar
.
podlesny committed
            }
podlesny's avatar
.  
podlesny committed
        */
podlesny's avatar
.
podlesny committed
    }

podlesny's avatar
.  
podlesny committed
    void build(const size_t bodyID, const Element& coarseElement, const size_t localVertex, Patch& patchDofs, const size_t patchDepth = 0) {
        std::cout << "Building SupportPatch... ";

podlesny's avatar
.  
podlesny committed
        std::cout << "elemID: " << coarseIndices_.elementIndex(bodyID, coarseElement) << " vertexID: " << coarseIndices_.vertexIndex(bodyID, coarseElement, localVertex) << std::endl;

podlesny's avatar
.  
podlesny committed
        patchDofs.resize(nVertices_);
        patchDofs.setAll();

        BodyElement seedElement;
        seedElement.set(bodyID, coarseElement);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
        auto isPatchIntersection = [this](auto& is, const size_t bodyID, const std::set<size_t>& patchVertices, std::set<size_t>& newPatchVertices) {
podlesny's avatar
.  
podlesny committed
            std::set<size_t> dofs;
            intersectionDofs(coarseIndices_, is, bodyID, dofs);

            for (auto& dof : dofs) {
                if (patchVertices.count(dof)) {
                    newPatchVertices.insert(dofs.begin(), dofs.end());
                    return true;
                }
            }
            return false;
        };

podlesny's avatar
.  
podlesny committed
        auto isRPatchIntersection = [this](std::vector<std::set<size_t>>& dofs, const std::set<size_t>& patchVertices) {
            for (auto& dof : dofs[0]) {
                if (patchVertices.count(dof)) {
                    return true;
                }
            }
            return false;
        };

podlesny's avatar
.
podlesny committed
        // construct coarse patch
        std::vector<BodyElement> patchElements;
        patchElements.emplace_back(seedElement);

        std::set<size_t> visitedElements;
podlesny's avatar
.  
podlesny committed
        //visitedElements.insert(coarseIndices_.elementIndex(seedElement.bodyID, seedElement.element));
podlesny's avatar
.
podlesny committed

        std::set<size_t> patchVertices;
podlesny's avatar
.  
podlesny committed
        patchVertices.insert(coarseIndices_.vertexIndex(bodyID, coarseElement, localVertex));
podlesny's avatar
.
podlesny committed

        std::queue<BodyElement> patchSeeds;
        patchSeeds.push(seedElement);

podlesny's avatar
.
podlesny committed
        for (size_t depth=0; depth<=patchDepth; depth++) {
            std::vector<BodyElement> nextSeeds;
            std::set<size_t> newPatchVertices;

            while (!patchSeeds.empty()) {
                const auto& patchSeed = patchSeeds.front();

podlesny's avatar
.  
podlesny committed
                size_t elemIdx = coarseIndices_.elementIndex(patchSeed.bodyID, patchSeed.element);
podlesny's avatar
.
podlesny committed

                if (visitedElements.count(elemIdx)) {
                    patchSeeds.pop();
podlesny's avatar
.
podlesny committed
                    continue;
podlesny's avatar
.
podlesny committed

                visitedElements.insert(elemIdx);

podlesny's avatar
.  
podlesny committed
                size_t bodyIdx = patchSeed.bodyID;
                const auto& elem = patchSeed.element;
                const auto& gridView = coarseContactNetwork_.body(bodyIdx)->gridView();
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                for (const auto& it : intersections(gridView, elem)) {
podlesny's avatar
.  
podlesny committed
                    if (isPatchIntersection(it, bodyIdx, patchVertices, newPatchVertices)) {
podlesny's avatar
.
podlesny committed
                        if (it.neighbor()) {
podlesny's avatar
.  
podlesny committed
                            BodyElement neighbor;
                            neighbor.set(bodyIdx, it.outside());
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                            size_t neighborIdx = coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element);

                            std::cout << "elementID: " << neighborIdx << std::endl;

                            if (visitedElements.count(neighborIdx))
podlesny's avatar
.
podlesny committed
                                continue;

                            patchElements.emplace_back(neighbor);
                            patchSeeds.push(neighbor);
                        } else {
podlesny's avatar
.  
podlesny committed
                            size_t faceIdx = coarseIndices_.faceIndex(bodyIdx, it);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                            if (coarseIntersectionMapper_.count(faceIdx)) {
                                const auto& intersections = coarseIntersectionMapper_[faceIdx];
                                for (size_t i=0; i<intersections.size(); i++) {
podlesny's avatar
.  
podlesny committed
                                    const auto& intersection = intersections[i];
                                    const auto& rIs = intersection.get(coarseContactNetwork_);

podlesny's avatar
.  
podlesny committed
                                    BodyElement neighbor;
podlesny's avatar
.  
podlesny committed
                                    neighbor.set(coarseContactNetwork_, intersection);
podlesny's avatar
.  
podlesny committed

                                    size_t neighborIdx = coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element);
podlesny's avatar
.
podlesny committed

                                    if (visitedElements.count(neighborIdx) || visitedBodies.count(neighbor.bodyID))
podlesny's avatar
.
podlesny committed
                                        continue;

podlesny's avatar
.  
podlesny committed
                                    std::vector<std::set<size_t>> dofs;
                                    remoteIntersectionDofs(coarseIndices_, rIs, bodyIdx, neighbor.bodyID, dofs, intersection.flip);
podlesny's avatar
.  
podlesny committed

podlesny's avatar
.  
podlesny committed
                                    if (isRPatchIntersection(dofs, patchVertices)) {
                                        patchVertices.insert(dofs[1].begin(), dofs[1].end());
                                        patchElements.emplace_back(neighbor);
                                        patchSeeds.push(neighbor);
                                    } else {
                                        newPatchVertices.insert(dofs[1].begin(), dofs[1].end());
                                        nextSeeds.emplace_back(neighbor);
                                    }
podlesny's avatar
.  
podlesny committed

                                    print(patchVertices, "patchVertices: ");
podlesny's avatar
.
podlesny committed
                                }
                            }
                        }
                    } else {
                        if (it.neighbor()) {
podlesny's avatar
.  
podlesny committed
                            BodyElement neighbor;
                            neighbor.set(bodyIdx, it.outside());
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                            size_t neighborIdx = coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element);

                            if (visitedElements.count(neighborIdx))
podlesny's avatar
.
podlesny committed
                                continue;

                            nextSeeds.emplace_back(neighbor);
                        } else {
podlesny's avatar
.  
podlesny committed
                            size_t faceIdx = coarseIndices_.faceIndex(bodyIdx, it);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                            if (coarseIntersectionMapper_.count(faceIdx)) {
                                const auto& intersections = coarseIntersectionMapper_[faceIdx];
                                for (size_t i=0; i<intersections.size(); i++) {
                                    BodyElement neighbor;
podlesny's avatar
.  
podlesny committed
                                    neighbor.set(coarseContactNetwork_, intersections[i]);

                                    size_t neighborIdx = coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element);
podlesny's avatar
.
podlesny committed

                                    if (visitedElements.count(neighborIdx) || visitedBodies.count(neighbor.bodyID))
podlesny's avatar
.
podlesny committed
                                        continue;

podlesny's avatar
.  
podlesny committed
                                    newPatchVertices.insert(neighborFaceDofs_[faceIdx].begin(), neighborFaceDofs_[faceIdx].end());
podlesny's avatar
.
podlesny committed
                                    nextSeeds.emplace_back(neighbor);
                                }
                            }
                        }
                    }
                }
podlesny's avatar
.
podlesny committed
            }

            for (size_t i=0; i<nextSeeds.size(); i++) {
                patchSeeds.push(nextSeeds[i]);
            }
            patchVertices.insert(newPatchVertices.begin(), newPatchVertices.end());
podlesny's avatar
.  
podlesny committed
            print(patchVertices, "patchVertices: ");
podlesny's avatar
.
podlesny committed
        }

podlesny's avatar
.  
podlesny committed
        std::cout << "constructing fine patch... " << std::endl;

podlesny's avatar
.
podlesny committed
        // construct fine patch
podlesny's avatar
.  
podlesny committed
        using HierarchicLevelIteratorType = HierarchicLevelIterator<typename LevelContactNetwork::GridType>;
podlesny's avatar
.  
podlesny committed
        std::set<size_t> visited;
podlesny's avatar
.  
podlesny committed
        std::set<size_t> patchBoundary;
podlesny's avatar
.
podlesny committed
        for (size_t i=0; i<patchElements.size(); ++i) {
podlesny's avatar
.  
podlesny committed
            const auto& coarseElem = patchElements[i];
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
            size_t elemIdx = coarseIndices_.elementIndex(coarseElem.bodyID, coarseElem.element);
            if (visited.count(elemIdx))
                continue;

podlesny's avatar
.  
podlesny committed
            std::cout << "coarse element: " << elemIdx << std::endl;

podlesny's avatar
.  
podlesny committed
            visited.insert(elemIdx);

podlesny's avatar
.  
podlesny committed
            const auto& grid = coarseContactNetwork_.body(coarseElem.bodyID)->gridView().grid();
podlesny's avatar
.  
podlesny committed
            const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID)->level();
podlesny's avatar
.  
podlesny committed

            // add fine patch elements
            HierarchicLevelIteratorType endHierIt(grid, coarseElem.element, HierarchicLevelIteratorType::PositionFlag::end, fineLevel);
            HierarchicLevelIteratorType hierIt(grid, coarseElem.element, HierarchicLevelIteratorType::PositionFlag::begin, fineLevel);
            for (; hierIt!=endHierIt; ++hierIt) {
                const Element& fineElem = *hierIt;
                addLocalDofs(coarseElem, fineElem, visitedElements, patchBoundary, patchDofs);
podlesny's avatar
.
podlesny committed
            }
        }
podlesny's avatar
.  
podlesny committed

        std::cout << "Success!" << std::endl;
    }

    const auto& coarseContactNetwork() {
        return coarseContactNetwork_;
podlesny's avatar
.
podlesny committed
    }

podlesny's avatar
.  
podlesny committed
private:
    void setup(const LevelContactNetwork& levelContactNetwork, const NetworkIndexMapper& indices, std::map<size_t, std::vector<RemoteIntersection>>& faceToRIntersections) {
podlesny's avatar
.  
podlesny committed
        for (size_t i=0; i<levelContactNetwork.nCouplings(); i++) {
            const auto& coupling = *levelContactNetwork.coupling(i);
            const auto& glue = *levelContactNetwork.glue(i);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
            const size_t nmBody = coupling.gridIdx_[0];
            const size_t mBody = coupling.gridIdx_[1];

            size_t rIsID = 0;
            for (const auto& rIs : intersections(glue)) {
                size_t nmFaceIdx = indices.faceIndex(nmBody, rIs.inside(), rIs.indexInInside());

podlesny's avatar
.  
podlesny committed
                RemoteIntersection nmIntersection;
                nmIntersection.set(mBody, i, rIsID, false);
podlesny's avatar
.  
podlesny committed
                faceToRIntersections[nmFaceIdx].emplace_back(nmIntersection);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                if (rIs.neighbor()) {
                    size_t mFaceIdx = indices.faceIndex(mBody, rIs.outside(), rIs.indexInOutside());

                    RemoteIntersection mIntersection;
                    mIntersection.set(nmBody, i, rIsID, true);
                    faceToRIntersections[mFaceIdx].emplace_back(mIntersection);
                }
podlesny's avatar
.  
podlesny committed

                rIsID++;
            }
        }
podlesny's avatar
.
podlesny committed
    }

    template <class Intersection>
    bool containsInsideSubentity(const Element& elem, const Intersection& intersection, int subEntity, int codim) {
	    return ReferenceElementHelper<double, dim>::subEntityContainsSubEntity(elem.type(), intersection.indexInInside(), 1, subEntity, codim);
	}
      
podlesny's avatar
.  
podlesny committed
    void addLocalDofs(const BodyElement& coarseElem, const Element& fineElem, const std::set<size_t>& coarsePatch, std::set<size_t>& patchBoundary, Patch& patchDofs) {
podlesny's avatar
.
podlesny committed
	    // insert local dofs
podlesny's avatar
.  
podlesny committed
        const auto& gridView = fineContactNetwork_.body(coarseElem.bodyID)->gridView();
        const size_t bodyID = coarseElem.bodyID;

        const auto coarseLevel = coarseContactNetwork_.body(coarseElem.bodyID)->level();
podlesny's avatar
.
podlesny committed

	    // search for parts of the global and inner boundary 
        for (const auto& is : intersections(gridView, fineElem)) {
            if (is.neighbor()) {
podlesny's avatar
.  
podlesny committed
                std::set<size_t> isDofs;
                intersectionDofs(fineIndices_, is, bodyID, isDofs);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                auto outsideFather = coarseFather(is.outside(), coarseLevel);
		    
                if (!coarsePatch.count(coarseIndices_.elementIndex(coarseElem.bodyID, outsideFather))) {
                    addToPatchBoundary(isDofs, patchBoundary, patchDofs);
                } else {
                    addToPatch(isDofs, patchBoundary, patchDofs);
podlesny's avatar
.
podlesny committed
                }
            } else {
podlesny's avatar
.  
podlesny committed
                size_t faceIdx = fineIndices_.faceIndex(bodyID, is);
podlesny's avatar
.  
podlesny committed
                if (fineIntersectionMapper_.count(faceIdx)) {
podlesny's avatar
.  
podlesny committed
                    const auto& intersections = fineIntersectionMapper_[faceIdx];
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                    for (size_t i=0; i<intersections.size(); i++) {
                        const auto& intersection = intersections[i];
podlesny's avatar
.  
podlesny committed
                        const auto& rIs = intersection.get(fineContactNetwork_);
podlesny's avatar
.  
podlesny committed
                        const size_t outsideID = intersection.bodyID;
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                        std::vector<std::set<size_t>> rIsDofs;
podlesny's avatar
.  
podlesny committed
                        remoteIntersectionDofs(fineIndices_, rIs, bodyID, outsideID, rIsDofs, intersection.flip);
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                        if (rIs.neighbor()) {
podlesny's avatar
.  
podlesny committed
                            Element outsideFather;
podlesny's avatar
.  
podlesny committed
                            const size_t outsideLevel = coarseContactNetwork_.body(outsideID)->level();

podlesny's avatar
.  
podlesny committed
                            if (intersection.flip)
podlesny's avatar
.  
podlesny committed
                                outsideFather = coarseFather(rIs.inside(), outsideLevel);
podlesny's avatar
.  
podlesny committed
                            else
podlesny's avatar
.  
podlesny committed
                                outsideFather = coarseFather(rIs.outside(), outsideLevel);
podlesny's avatar
.  
podlesny committed

                            std::set<size_t> totalRIsDofs(rIsDofs[0]);
                            totalRIsDofs.insert(rIsDofs[1].begin(), rIsDofs[1].end());
podlesny's avatar
.  
podlesny committed

podlesny's avatar
.  
podlesny committed
                            if (!coarsePatch.count(coarseIndices_.elementIndex(outsideID, outsideFather))) {
podlesny's avatar
.  
podlesny committed
                                addToPatchBoundary(totalRIsDofs, patchBoundary, patchDofs);
podlesny's avatar
.  
podlesny committed
                            } else {
podlesny's avatar
.  
podlesny committed
                                addToPatch(totalRIsDofs, patchBoundary, patchDofs);
podlesny's avatar
.  
podlesny committed
                            }
                        } else {
podlesny's avatar
.  
podlesny committed
                            addToPatchBoundary(rIsDofs[0], patchBoundary, patchDofs);
podlesny's avatar
.  
podlesny committed
                        }
podlesny's avatar
.
podlesny committed
                    }
podlesny's avatar
.  
podlesny committed
                } else {
                    std::set<size_t> isDofs;
                    intersectionDofs(fineIndices_, is, bodyID, isDofs);

                    addToPatchBoundary(isDofs, patchBoundary, patchDofs);
podlesny's avatar
.  
podlesny committed
                }
podlesny's avatar
.
podlesny committed
            }
podlesny's avatar
.  
podlesny committed
        }
	}

podlesny's avatar
.  
podlesny committed
    auto coarseFather(const Element& fineElem, const size_t coarseLevel) const {
podlesny's avatar
.  
podlesny committed
        Element coarseElem = fineElem;
        while (coarseElem.level() > coarseLevel) {
            coarseElem = coarseElem.father();
        }
        return coarseElem;
    }

    void addToPatchBoundary(const std::set<size_t>& dofs, std::set<size_t>& patchBoundary, Patch& patchDofs) {
        for (auto& dof : dofs) {
            patchBoundary.insert(dof);
            patchDofs[dof][0] = true;
        }
    }

    void addToPatch(const std::set<size_t>& dofs, const std::set<size_t>& patchBoundary, Patch& patchDofs) {
        for (auto& dof : dofs) {
            if (!patchBoundary.count(dof)) {
                patchDofs[dof][0] = false;
            }
        }
    }
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
    template <class RIntersection>
podlesny's avatar
.  
podlesny committed
    void remoteIntersectionDofs(const NetworkIndexMapper& indices, const RIntersection& is, const size_t insideID, const size_t outsideID, std::vector<std::set<size_t>>& dofs, bool flip = false) {
        assert(!flip || (flip && is.neighbor()));

podlesny's avatar
.  
podlesny committed
        dofs.resize(2);
        dofs[0].clear();
        dofs[1].clear();

        const auto& isGeo = is.geometry();
        const auto& isRefElement = Dune::ReferenceElements<ctype, dim-1>::general(is.type());
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
        if (!flip) {
             const auto& inside = is.inside();
             const auto& insideGeo = inside.geometry();
             const auto& insideRefElement = Dune::ReferenceElements<ctype, dim>::general(inside.type());
             const int dimElement = Dune::ReferenceElements<ctype, dim>::dimension;

             for (int i=0; i<insideRefElement.size(is.indexInInside(), 1, dimElement); i++) {
                 size_t idxInElement = insideRefElement.subEntity(is.indexInInside(), 1, i, dimElement);

                 const auto& localCorner = isGeo.local(insideGeo.corner(idxInElement));

                 if (isRefElement.checkInside(localCorner)) {
                     dofs[0].insert(indices.vertexIndex(insideID, inside, idxInElement));
                 }
             }

             if (is.neighbor()) {
                 const auto& outside = is.outside();
                 const auto& outsideGeo = outside.geometry();
                 const auto& outsideRefElement = Dune::ReferenceElements<ctype, dim>::general(outside.type());

                 for (int i=0; i<outsideRefElement.size(is.indexInOutside(), 1, dimElement); i++) {
                     size_t idxInElement = outsideRefElement.subEntity(is.indexInOutside(), 1, i, dimElement);
podlesny's avatar
.  
podlesny committed

podlesny's avatar
.  
podlesny committed
                     const auto& localCorner = isGeo.local(outsideGeo.corner(idxInElement));
podlesny's avatar
.  
podlesny committed

podlesny's avatar
.  
podlesny committed
                     if (isRefElement.checkInside(localCorner)) {
                         dofs[1].insert(indices.vertexIndex(outsideID, outside, idxInElement));
                     }
                 }
             }
        } else {
            const auto& inside = is.outside();
            const auto& insideGeo = inside.geometry();
            const auto& insideRefElement = Dune::ReferenceElements<ctype, dim>::general(inside.type());
            const int dimElement = Dune::ReferenceElements<ctype, dim>::dimension;
podlesny's avatar
.  
podlesny committed

podlesny's avatar
.  
podlesny committed
            for (int i=0; i<insideRefElement.size(is.indexInOutside(), 1, dimElement); i++) {
                size_t idxInElement = insideRefElement.subEntity(is.indexInOutside(), 1, i, dimElement);

                const auto& localCorner = isGeo.local(insideGeo.corner(idxInElement));

                if (isRefElement.checkInside(localCorner)) {
                    dofs[0].insert(indices.vertexIndex(insideID, inside, idxInElement));
                }
podlesny's avatar
.
podlesny committed
            }

podlesny's avatar
.  
podlesny committed
            const auto& outside = is.inside();
podlesny's avatar
.  
podlesny committed
            const auto& outsideGeo = outside.geometry();
            const auto& outsideRefElement = Dune::ReferenceElements<ctype, dim>::general(outside.type());
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
            for (int i=0; i<outsideRefElement.size(is.indexInInside(), 1, dimElement); i++) {
                size_t idxInElement = outsideRefElement.subEntity(is.indexInInside(), 1, i, dimElement);
podlesny's avatar
.  
podlesny committed

                const auto& localCorner = isGeo.local(outsideGeo.corner(idxInElement));
podlesny's avatar
.
podlesny committed

podlesny's avatar
.  
podlesny committed
                if (isRefElement.checkInside(localCorner)) {
podlesny's avatar
.  
podlesny committed
                    dofs[1].insert(indices.vertexIndex(outsideID, outside, idxInElement));
podlesny's avatar
.  
podlesny committed
                }
podlesny's avatar
.  
podlesny committed
            }
podlesny's avatar
.
podlesny committed
        }
podlesny's avatar
.  
podlesny committed

podlesny's avatar
.  
podlesny committed
    }

    template <class Intersection>
    void intersectionDofs(const NetworkIndexMapper& indices, const Intersection& is, const size_t bodyID, std::set<size_t>& dofs) {
        dofs.clear();

        const Element& elem = is.inside();
        size_t intersectionIndex = is.indexInInside();
podlesny's avatar
.
podlesny committed

        const int dimElement = Element::dimension;
podlesny's avatar
.  
podlesny committed
        const auto& refElement = Dune::ReferenceElements<double, dimElement>::general(elem.type());
podlesny's avatar
.
podlesny committed

        for (int i=0; i<refElement.size(intersectionIndex, 1, dimElement); i++) {
            size_t idxInElement = refElement.subEntity(intersectionIndex, 1, i, dimElement);
podlesny's avatar
.  
podlesny committed
            dofs.insert(indices.vertexIndex(bodyID, elem, idxInElement));
podlesny's avatar
.
podlesny committed
        }
    }
};
#endif