Newer
Older
#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>
#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"
template <class LevelContactNetwork>
using FiniteElementCache = Dune::PQkLocalFiniteElementCache<ctype, ctype, dim, 1>; // P1 finite element cache
using GridType = typename LevelContactNetwork::DeformedGridType;
using Element = typename GridType::template Codim<0>::Entity;
static const int dim = LevelContactNetwork::dimension; //TODO
static const FiniteElementCache cache_;
std::vector<size_t> vertexOffSet_;
std::vector<size_t> faceOffSet_;
std::vector<size_t> elementOffSet_;
public:
NetworkIndexMapper(const LevelContactNetwork& levelContactNetwork) :
levelContactNetwork_(levelContactNetwork),
nBodies_(levelContactNetwork_.nBodies()),
vertexOffSet_(nBodies_),
faceOffSet_(nBodies_),
elementOffSet_(nBodies_) {
size_t vertexOffSet = 0;
size_t faceOffSet = 0;
size_t elementOffSet = 0;
for (size_t i=0; i<nBodies_; i++) {
const auto& gridView = levelContactNetwork_.body(i)->gridView();
vertexOffSet_[i] = vertexOffSet + gridView.size(dim);
vertexOffSet = vertexOffSet_[i];
faceOffSet_[i] = faceOffSet + gridView.size(1);
faceOffSet = faceOffSet_[i];
elementOffSet_[i] = elementOffSet + gridView.size(0);
elementOffSet = elementOffSet_[i];
size_t vertexIndex(const size_t bodyID, const Element& elem, const size_t localVertex) const {
const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
auto localIdx = cache_.get(elem.type()).localCoefficients().localKey(localVertex).subEntity();
return vertexOffSet_[bodyID] + gridView.indexSet().subIndex(elem, localIdx, dim);
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);
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);
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);
return cache_;
}
};
/**
* 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:
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
struct BodyElement {
size_t bodyID;
Element element;
void set(const size_t _bodyID, const Element& _elem) {
bodyID = _bodyID;
element = _elem;
}
};
struct RemoteIntersection {
size_t bodyID; // used to store bodyID of outside elem
GridGlue& glue;
size_t intersectionID;
bool flip = false;
void set(const size_t _bodyID, const GridGlue& _glue, const size_t _intersectionID, bool _flip = false) {
bodyID = _bodyID;
glue = _glue;
intersectionID = _intersectionID;
flip = _flip;
}
auto& get() {
return (flip) ? glue.getIntersection(intersectionID).flip() : glue.getIntersection(intersectionID);
}
};
static const int dim = LevelContactNetwork::dimension; //TODO
using ctype = typename LevelContactNetwork::ctype;
//using Vertex = typename GridType::template Codim<dim>::Entity;
using Element = typename LevelContactNetwork::DeformedGridType::template Codim<0>::Entity;
using BodyElement = BodyElement<Element>;
using NetworkIndexMapper = NetworkIndexMapper<LevelContactNetwork>;
using GridGlue = ;
const size_t nBodies_;
const LevelContactNetwork& coarseContactNetwork_;
const LevelContactNetwork& fineContactNetwork_;
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
const NetworkIndexMapper coarseIndices_;
const NetworkIndexMapper fineIndices_;
public:
SupportPatchFactory(const LevelContactNetwork& coarseContactNetwork, const LevelContactNetwork& fineContactNetwork) :
nBodies_(coarseContactNetwork_.nBodies()),
coarseContactNetwork_(coarseContactNetwork),
fineContactNetwork_(fineContactNetwork),
coarseIndices_(coarseContactNetwork_),
fineIndices_(fineContactNetwork_) {
setup(coarseContactNetwork_, coarseIndices_, coarseIntersectionMapper_);
setup(fineContactNetwork_, fineIndices_, fineIntersectionMapper_);
// setup neighborFaceDofs_
const auto& contactCouplings = coarseContactNetwork_.nBodyAssembler().getContactCouplings();
const auto& coupling = nBodyAssembler.getCoupling(i);
const auto& glue = *contactCouplings[i].getGlue();
const size_t nmBody = coupling.gridIdx_[0];
const size_t mBody = coupling.gridIdx_[1];
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());
std::array<std::set<size_t>, 2> dofs;
remoteIntersectionDofs(coarseIndices_, rIs, nmBody, mBody, dofs);
neighborFaceDofs_[nmFaceIdx].insert(neighborFaceDofs_[nmFaceIdx].end(), dofs[1].begin(), dofs[1].end());
neighborFaceDofs_[mFaceIdx].insert(neighborFaceDofs_[mFaceIdx].end(), dofs[0].begin(), dofs[0].end());
}
/*
// 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());
}
void build(const size_t bodyID, const Element& coarseElement, const size_t localVertex, Patch& patchDofs, const int patchDepth = 0) {
BodyElement seedElement(bodyID, coarseElement);
auto isPatchIntersection = [](auto& is, const size_t bodyID, const std::set<size_t>& patchVertices, std::set<size_t>& newPatchVertices) {
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;
};
// construct coarse patch
std::vector<BodyElement> patchElements;
patchElements.emplace_back(seedElement);
std::set<size_t> visitedElements;
visitedElements.insert(coarseIndices_.elementIndex(seedElement.bodyID, seedElement.element));
patchVertices.insert(coarseIndices_.vertexIndex(bodyID, coarseElement, localVertex));
std::queue<BodyElement> patchSeeds;
patchSeeds.push(seedElement);
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();
patchSeeds.pop();
size_t elemIdx = coarseIndices_.elementIndex(patchSeed.bodyID, patchSeed.element);
if (visitedElements.count(elemIdx))
continue;
visitedElements.insert(elemIdx);
size_t bodyIdx = patchSeed.bodyID;
const auto& elem = patchSeed.element;
const auto& gridView = coarseContactNetwork_.body(bodyIdx)->gridView();
if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
continue;
patchElements.emplace_back(neighbor);
patchSeeds.push(neighbor);
} else {
if (coarseIntersectionMapper_.count(faceIdx)) {
const auto& intersections = coarseIntersectionMapper_[faceIdx];
for (size_t i=0; i<intersections.size(); i++) {
BodyElement neighbor;
neighbor.set(intersections[i].bodyID, intersections[i].get().outside());
if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
continue;
patchVertices.insert(neighborElementDofs_[faceIdx].begin(), neighborElementDofs_[faceIdx].end());
patchElements.emplace_back(neighbor);
patchSeeds.push(neighbor);
}
}
}
} else {
if (it.neighbor()) {
BodyElement neighbor(bodyIdx, it.outside());
if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
if (coarseIntersectionMapper_.count(faceIdx)) {
const auto& intersections = coarseIntersectionMapper_[faceIdx];
for (size_t i=0; i<intersections.size(); i++) {
BodyElement neighbor;
neighbor.set(intersections[i].bodyID, intersections[i].get().outside());
if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
continue;
newPatchVertices.insert(neighborElementDofs_[faceIdx].begin(), neighborElementDofs_[faceIdx].end());
nextSeeds.emplace_back(neighbor);
}
}
}
}
}
}
for (size_t i=0; i<nextSeeds.size(); i++) {
patchSeeds.push(nextSeeds[i]);
}
patchVertices.insert(newPatchVertices.begin(), newPatchVertices.end());
}
// construct fine patch
using HierarchicLevelIteratorType = HierarchicLevelIterator<typename LevelContactNetwork::DeformedGridType>;
std::set<size_t> patchBoundary;
const auto& grid = coarseContactNetwork_.body(coarseElem.bodyID)->gridView().grid();
const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID)->gridView().level();
// 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);
private:
void setup(const LevelContactNetwork& levelContactNetwork, const NetworkIndexMapper& indices, std::map<size_t, std::vector<RemoteIntersection>>& faceToRIntersections) {
const auto& nBodyAssembler = levelContactNetwork.nBodyAssembler();
const auto& contactCouplings = nBodyAssembler.getContactCouplings();
for (size_t i=0; i<contactCouplings.size(); i++) {
const auto& coupling = nBodyAssembler.getCoupling(i);
const auto& glue = *contactCouplings[i].getGlue();
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());
size_t mFaceIdx = indices.faceIndex(mBody, rIs.outside(), rIs.indexInOutside());
RemoteIntersection nmIntersection(mBody, glue, rIsID, false);
faceToRIntersections[nmFaceIdx].emplace_back(nmIntersection);
RemoteIntersection mIntersection(nmBody, glue, rIsID, true);
faceToRIntersections[mFaceIdx].emplace_back(mIntersection);
rIsID++;
}
}
}
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);
}
void addLocalDofs(const BodyElement& coarseElem, const Element& fineElem, const std::set<size_t>& coarsePatch, std::set<size_t>& patchBoundary, Patch& patchDofs) {
const auto& gridView = fineContactNetwork_.body(coarseElem.bodyID)->gridView();
const size_t bodyID = coarseElem.bodyID;
const auto coarseLevel = coarseElem.element.level();
// search for parts of the global and inner boundary
for (const auto& is : intersections(gridView, fineElem)) {
if (is.neighbor()) {
std::set<size_t> isDofs;
intersectionDofs(fineIndices_, is, bodyID, isDofs);
auto outsideFather = coarseFather(is.outside(), coarseLevel);
if (!coarsePatch.count(coarseIndices_.elementIndex(coarseElem.bodyID, outsideFather))) {
addToPatchBoundary(isDofs, patchBoundary, patchDofs);
} else {
addToPatch(isDofs, patchBoundary, patchDofs);
size_t faceIdx = fineIndices_.faceIndex(bodyID, is);
if (fineIntersectionMapper_.count(faceIdx)) {
const auto& intersections = coarseIntersectionMapper_[faceIdx];
for (size_t i=0; i<intersections.size(); i++) {
const auto& intersection = intersections[i];
const auto& rIs = intersection.get();
const size_t outsideID = intersection.bodyID;
std::set<size_t> rIsDofs;
remoteIntersectionDofs(fineIndices_, rIs, bodyID, outsideID, rIsDofs);
if (rIs.neighbor()) {
auto outsideFather = coarseFather(rIs.outside(), fineContactNetwork_.body(outsideID)->gridView().level());
if (!coarsePatch.count(coarseIndices_.elementIndex(outsideID, outsideFather))) {
addToPatchBoundary(rIsDofs, patchBoundary, patchDofs);
} else {
addToPatch(rIsDofs, patchBoundary, patchDofs);
}
} else {
addToPatchBoundary(rIsDofs, patchBoundary, patchDofs);
}
} else {
std::set<size_t> isDofs;
intersectionDofs(fineIndices_, is, bodyID, isDofs);
addToPatchBoundary(isDofs, patchBoundary, patchDofs);
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
}
}
auto&& coarseFather(const Element& fineElem, const size_t coarseLevel) const {
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;
}
}
template <class Intersection>
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;
}
}
}
template <class RIntersection>
void remoteIntersectionDofs(const NetworkIndexMapper& indices, const RIntersection& is, const size_t insideID, const size_t outsideID, std::array<std::set<size_t>, 2>& dofs) {
dofs.clear();
const auto& inside = is.inside();
const auto& insideGeo = inside.geometry();
const auto& insideRefElement = Dune::ReferenceElements<ctype, dim>::general(inside.type());
for (int i=0; i<insideRefElement.size(dim); i++) {
const auto& localCorner = isGeo.local(insideGeo.corner(i));
if (isRefElement.checkInside(localCorner)) {
dofs[0].insert(indices.vertexIndex(insideID, inside, i));
const auto& isGeo = is.geometry();
const auto& isRefElement = Dune::ReferenceElements<ctype, dim-1>::general(is.type());
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(dim); i++) {
const auto& localCorner = isGeo.local(outsideGeo.corner(i));
if (isRefElement.checkInside(localCorner)) {
dofs[1].insert(indices.vertexIndex(outsideID, outside, i));
}
}
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();
const auto& refElement = Dune::ReferenceElements<double, dimElement>::general(elem.type());
for (int i=0; i<refElement.size(intersectionIndex, 1, dimElement); i++) {
size_t idxInElement = refElement.subEntity(intersectionIndex, 1, i, dimElement);