Forked from
agnumpde / dune-tectonic
156 commits ahead of the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
cantorfactory.cc 16.29 KiB
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <dune/common/fvector.hh>
#include <dune/fufem/geometry/convexpolyhedron.hh>
#include <dune/contact/projections/normalprojection.hh>
#include "../utils/almostequal.hh"
#include "cantorfactory.hh"
#include "../multi-body-problem-data/bc.hh"
#include "../multi-body-problem-data/cuboidgeometry.hh"
#include "../multi-body-problem-data/myglobalfrictiondata.hh"
#include "../multi-body-problem-data/weakpatch.hh"
#include "../multi-body-problem-data/cubegridconstructor.hh"
#include "../utils/diameter.hh"
template <class GridType, int dim>
void CantorFactory<GridType, dim>::setBodies() {
for (size_t level=0; level<=maxLevel_; level++) {
const LevelCubes& levelCubes = cubes_[level];
for (size_t i=0; i<levelCubes.size(); i++) {
const std::shared_ptr<Cube>& cube = levelCubes[i];
CubeGridConstructor
}
}
std::vector<LocalVector> origins(this->bodyCount_);
std::vector<LocalVector> lowerWeakOrigins(this->bodyCount_);
std::vector<LocalVector> upperWeakOrigins(this->bodyCount_);
#if MY_DIM == 3
double const depth = 0.60;
origins[0] = {0,0,0};
lowerWeakOrigins[0] = {0.2,0,0};
upperWeakOrigins[0] = {0.2,width,0};
cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lowerWeakOrigins[0], upperWeakOrigins[0], 0.0, weakLength, length, width, depth);
for (size_t i=1; i<this->bodyCount_-1; i++) {
origins[i] = cuboidGeometries_[i-1]->D;
lowerWeakOrigins[i] = {0.6,i*width,0};
upperWeakOrigins[i] = {0.6,(i+1)*width,0};
cuboidGeometries_[i] = std::make_shared<CuboidGeometry>(origins[i], lowerWeakOrigins[i], upperWeakOrigins[i], weakLength, weakLength, length, width, depth);
}
const size_t idx = this->bodyCount_-1;
origins[idx] = cuboidGeometries_[idx-1]->D;
lowerWeakOrigins[idx] = {0.6,idx*width,0};
upperWeakOrigins[idx] = {0.6,(idx+1)*width,0};
cuboidGeometries_[idx] = std::make_shared<CuboidGeometry>(origins[idx], lowerWeakOrigins[idx], upperWeakOrigins[idx], weakLength, 0.0, length, width, depth);
#elif MY_DIM == 2
origins[0] = {0,0};
lowerWeakOrigins[0] = {0.2,0};
upperWeakOrigins[0] = {0.2,width};
cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lowerWeakOrigins[0], upperWeakOrigins[0], 0.0, weakLength, length, width);
for (size_t i=1; i<this->bodyCount_-1; i++) {
origins[i] = cuboidGeometries_[i-1]->D;
lowerWeakOrigins[i] = {0.6,i*width};
upperWeakOrigins[i] = {0.6,(i+1)*width};
cuboidGeometries_[i] = std::make_shared<CuboidGeometry>(origins[i], lowerWeakOrigins[i], upperWeakOrigins[i], weakLength, weakLength, length, width);
}
const size_t idx = this->bodyCount_-1;
origins[idx] = cuboidGeometries_[idx-1]->D;
lowerWeakOrigins[idx] = {0.6,idx*width};
upperWeakOrigins[idx] = {0.6,(idx+1)*width};
cuboidGeometries_[idx] = std::make_shared<CuboidGeometry>(origins[idx], lowerWeakOrigins[idx], upperWeakOrigins[idx], weakLength, 0.0, length, width);
#else
#error CuboidGeometry only supports 2D and 3D!"
#endif
// set up reference grids
gridConstructor_ = new GridsConstructor<GridType>(cuboidGeometries_);
auto& grids = gridConstructor_->getGrids();
for (size_t i=0; i<this->bodyCount_; i++) {
const auto& cuboidGeometry = *cuboidGeometries_[i];
// define weak patch and refine grid
auto lowerWeakPatch = lowerWeakPatches_[i] = std::make_shared<ConvexPolyhedron<LocalVector>>();
auto upperWeakPatch = upperWeakPatches_[i] = std::make_shared<ConvexPolyhedron<LocalVector>>();
getWeakPatch<LocalVector>(this->parset_.sub("boundary.friction.weakening"), cuboidGeometry, *lowerWeakPatch, *upperWeakPatch);
refine(*grids[i], *lowerWeakPatch, this->parset_.template get<double>("boundary.friction.smallestDiameter"), cuboidGeometry.lengthScale);
refine(*grids[i], *upperWeakPatch, this->parset_.template get<double>("boundary.friction.smallestDiameter"), cuboidGeometry.lengthScale);
}
for (size_t i=0; i<this->bodyCount_; i++) {
this->bodies_[i] = std::make_shared<typename Base::Body>(bodyData_, grids[i]);
}
}
template <class GridType, int dim>
void CantorFactory<GridType, dim>::setCouplings() {
const auto deformedGrids = this->contactNetwork_.deformedGrids();
for (size_t i=0; i<this->bodyCount_; i++) {
const auto& cuboidGeometry = *cuboidGeometries_[i];
leafFaces_[i] = std::make_shared<LeafFaces>(this->contactNetwork_.leafView(i), cuboidGeometry);
levelFaces_[i] = std::make_shared<LevelFaces>(this->contactNetwork_.levelView(i), cuboidGeometry);
}
auto contactProjection = std::make_shared<Dune::Contact::NormalProjection<LeafBoundaryPatch>>();
std::shared_ptr<typename Base::CouplingPair::BackEndType> backend = nullptr;
for (size_t i=0; i<this->couplings_.size(); i++) {
auto& coupling = this->couplings_[i];
coupling = std::make_shared<typename Base::CouplingPair>();
nonmortarPatch_[i] = std::make_shared<LevelBoundaryPatch>(levelFaces_[i]->upper);
mortarPatch_[i] = std::make_shared<LevelBoundaryPatch>(levelFaces_[i+1]->lower);
coupling->set(i, i+1, nonmortarPatch_[i], mortarPatch_[i], 0.1, Base::CouplingPair::CouplingType::STICK_SLIP, contactProjection, backend);
}
}
template <class GridType, int dim>
void CantorFactory<GridType, dim>::setBoundaryConditions() {
using LeafBoundaryCondition = BoundaryCondition<DeformedLeafGridView, dim>;
using FrictionBoundaryCondition = FrictionBoundaryCondition<DeformedLeafGridView, LocalVector, dim>;
using Function = Dune::VirtualFunction<double, double>;
std::shared_ptr<Function> neumannFunction = std::make_shared<NeumannCondition>();
std::shared_ptr<Function> velocityDirichletFunction = std::make_shared<VelocityDirichletCondition>();
const double lengthScale = CuboidGeometry::lengthScale;
for (size_t i=0; i<this->bodyCount_; i++) {
const auto& body = this->contactNetwork_.body(i);
const auto& leafVertexCount = body->leafVertexCount();
std::cout << "Grid" << i << " Number of DOFs: " << leafVertexCount << std::endl;
// friction boundary
if (i<this->bodyCount_-1 && upperWeakPatches_[i]->vertices.size()>0) {
std::shared_ptr<FrictionBoundaryCondition> frictionBoundary = std::make_shared<FrictionBoundaryCondition>();
frictionBoundary->setBoundaryPatch(leafFaces_[i]->upper);
frictionBoundary->setWeakeningPatch(upperWeakPatches_[i]);
frictionBoundary->setFrictionData(std::make_shared<MyGlobalFrictionData<LocalVector>>(this->parset_.sub("boundary.friction"), *upperWeakPatches_[i], lengthScale));
body->addBoundaryCondition(frictionBoundary);
}
if (i>0 && lowerWeakPatches_[i]->vertices.size()>0) {
std::shared_ptr<FrictionBoundaryCondition> frictionBoundary = std::make_shared<FrictionBoundaryCondition>();
frictionBoundary->setBoundaryPatch(leafFaces_[i]->lower);
frictionBoundary->setWeakeningPatch(lowerWeakPatches_[i]);
frictionBoundary->setFrictionData(std::make_shared<MyGlobalFrictionData<LocalVector>>(this->parset_.sub("boundary.friction"), *lowerWeakPatches_[i], lengthScale));
body->addBoundaryCondition(frictionBoundary);
}
// Neumann boundary
std::shared_ptr<LeafBoundaryCondition> neumannBoundary = std::make_shared<LeafBoundaryCondition>(std::make_shared<LeafBoundaryPatch>(body->leafView()), neumannFunction, "neumann");
body->addBoundaryCondition(neumannBoundary);
// Dirichlet Boundary
// identify Dirichlet nodes on leaf level
std::shared_ptr<Dune::BitSetVector<dim>> dirichletNodes = std::make_shared<Dune::BitSetVector<dim>>(leafVertexCount);
for (int j=0; j<leafVertexCount; j++) {
if (leafFaces_[i]->right.containsVertex(j))
(*dirichletNodes)[j][0] = true;
if (leafFaces_[i]->lower.containsVertex(j))
(*dirichletNodes)[j][0] = true;
#if MY_DIM == 3
if (leafFaces_[i]->front.containsVertex(j) || leafFaces_[i]->back.containsVertex(j))
dirichletNodes->at(j)[2] = true;
#endif
}
std::shared_ptr<LeafBoundaryCondition> dirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet");
dirichletBoundary->setBoundaryPatch(body->leafView(), dirichletNodes);
dirichletBoundary->setBoundaryFunction(velocityDirichletFunction);
body->addBoundaryCondition(dirichletBoundary);
}
}
class CantorIndexHierarchy {
public:
typedef std::map<std::pair<int,int>, bool> LevelCantorIndices;
private:
const size_t maxLevel_;
std::vector<size_t> levelN_;
std::vector<LevelCantorIndices> cantorIndexHierarchy_;
void prolongIndices(size_t currentLevel, size_t newLevel) {
const LevelCantorIndices& indices = cantorIndexHierarchy_[currentLevel];
LevelCantorIndices& newIndices = cantorIndexHierarchy_[newLevel];
size_t offset = levelN_[currentLevel];
std::map<std::pair<int,int>, bool>::const_iterator it = indices.begin();
std::map<std::pair<int,int>, bool>::const_iterator endIt = indices.end();
for (; it!=endIt; ++it) {
int xID = it->first.first;
int yID = it->first.second;
newIndices[std::make_pair(xID, yID)] = true;
newIndices[std::make_pair(xID+offset, yID)] = true;
newIndices[std::make_pair(xID, yID+offset)] = true;
}
size_t doubleOffset = 2*offset;
for (size_t i=offset+1; i<=doubleOffset; i=i+2) {
newIndices[std::make_pair(doubleOffset, i)] = true;
newIndices[std::make_pair(i, doubleOffset)] = true;
}
}
void print(const LevelCantorIndices& indices) const {
std::cout << "LevelCantorIndices: " << std::endl;
std::map<std::pair<int,int>, bool>::const_iterator it = indices.begin();
std::map<std::pair<int,int>, bool>::const_iterator endIt = indices.end();
for (; it!=endIt; ++it) {
std::cout << "(" << it->first.first << ", " << it->first.second << ")"<< std::endl;
}
}
public:
CantorIndexHierarchy(size_t maxLevel) :
maxLevel_(maxLevel)
{
levelN_.resize(maxLevel_+1);
cantorIndexHierarchy_.resize(maxLevel_+1);
// init levelCantorIndices on level 0
LevelCantorIndices& initCantorIndices = cantorIndexHierarchy_[0];
initCantorIndices[std::make_pair(0, 1)] = true;
initCantorIndices[std::make_pair(1, 0)] = true;
initCantorIndices[std::make_pair(1, 2)] = true;
initCantorIndices[std::make_pair(2, 1)] = true;
for (size_t i=0; i<maxLevel_; i++) {
levelN_[i] = std::pow(2, i+1);
prolongIndices(i, i+1);
}
levelN_[maxLevel_] = std::pow(2, maxLevel_+1);
}
const LevelCantorIndices& levelCantorIndices(size_t i) const {
return cantorIndexHierarchy_[i];
}
size_t levelN(const size_t i) const {
return levelN_[i];
}
};
template <class GridType>
class CantorFaultFactory
{
//! 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 Dune::MultipleCodimMultipleGeomTypeMapper<GV, FaceMapperLayout > FaceMapper;
private:
const std::map<size_t, size_t>& levelToCantorLevel_;
const int coarseResolution_;
const size_t maxLevel_;
const size_t maxCantorLevel_;
const CantorIndexHierarchy cantorIndexHierarchy_;
const int coarseGridN_;
std::shared_ptr<GridType> grid_;
std::vector<double> levelResolutions_;
std::shared_ptr<InterfaceNetwork<GridType>> interfaceNetwork_;
private:
bool computeID(Dune::FieldVector<ctype, dimworld> vertex, const size_t gridN, std::pair<size_t, size_t>& IDs) const {
ctype xID = vertex[0]*gridN;
ctype yID = vertex[1]*gridN;
ctype x = 0;
ctype y = 0;
bool xIsInt = almost_equal(std::modf(xID, &x), 0.0, 2);
bool yIsInt = almost_equal(std::modf(yID, &y), 0.0, 2);
if (xIsInt && yIsInt) {
IDs = std::make_pair((size_t) x, (size_t) y);
return true;
}
if (xIsInt) {
y = std::ceil(yID);
if ((size_t) y % 2==0)
y = y-1;
IDs = std::make_pair((size_t) x, (size_t) y);
return true;
}
if (yIsInt) {
x = std::ceil(xID);
if ((size_t) x % 2==0)
x = x-1;
IDs = std::make_pair((size_t) x, (size_t) y);
return true;
}
return false;
}
public:
//setup
CantorFaultFactory(const std::map<size_t, size_t>& levelToCantorLevel, const int coarseResolution, const size_t maxLevel, const size_t maxCantorLevel) :
levelToCantorLevel_(levelToCantorLevel),
coarseResolution_(coarseResolution),
maxLevel_(maxLevel),
maxCantorLevel_(maxCantorLevel),
cantorIndexHierarchy_(maxCantorLevel_),
coarseGridN_(std::pow(2, coarseResolution_)),
interfaceNetwork_(nullptr)
{
Dune::UGGrid<dim>::setDefaultHeapSize(4000);
GridOb unitCube(coarseGridN_);
grid_ = unitCube.grid();
grid_->globalRefine(maxLevel_);
levelResolutions_.resize(maxLevel_+1);
// init interface network
interfaceNetwork_ = std::make_shared<InterfaceNetwork<GridType>>(*grid_);
for (size_t i=0; i<=maxLevel_; i++) {
if (i>0) {
interfaceNetwork_->prolongLevel(i-1, i);
}
if (levelToCantorLevel_.count(i)) {
levelResolutions_[i] = std::pow(2, coarseResolution_+i);
const size_t levelResolution = levelResolutions_[i];
const size_t cantorResolution = cantorIndexHierarchy_.levelN(levelToCantorLevel_.at(i));
if (2*levelResolution<cantorResolution)
DUNE_THROW(Dune::Exception, "Level " + std::to_string(i) + " does not support cantor set with resolution " + std::to_string(cantorResolution));
const typename CantorIndexHierarchy::LevelCantorIndices& levelCantorIndices = cantorIndexHierarchy_.levelCantorIndices(levelToCantorLevel_.at(i));
std::shared_ptr<LevelInterfaceNetwork<GV>> levelInterfaceNetwork = interfaceNetwork_->levelInterfaceNetworkPtr(i);
const GV& gridView = levelInterfaceNetwork->levelGridView();
FaceMapper intersectionMapper(gridView);
std::vector<bool> intersectionHandled(intersectionMapper.size(),false);
for (const auto& elem:elements(gridView)) {
for (const auto& isect:intersections(gridView, elem)) {
if (intersectionHandled[intersectionMapper.subIndex(elem, isect.indexInInside(),1)])
continue;
intersectionHandled[intersectionMapper.subIndex(elem, isect.indexInInside(),1)]=true;
if (isect.boundary())
continue;
std::pair<size_t, size_t> intersectionID;
bool isAdmissibleID = computeID(isect.geometry().center(), cantorResolution, intersectionID);
if (isAdmissibleID && levelCantorIndices.count(intersectionID)) {
levelInterfaceNetwork->addIntersection(isect, i);
}
}
}
}
}
}
#include "cantorfactory_tmpl.cc"