Commit 7ed44503 authored by Timo Koch's avatar Timo Koch
Browse files

[md] Use intersectionentityset for implementing MultiDomainGlue

parent ea170d36
......@@ -26,274 +26,28 @@
#ifndef DUMUX_MULTIDOMAIN_GLUE_HH
#define DUMUX_MULTIDOMAIN_GLUE_HH
#include <iostream>
#include <fstream>
#include <string>
#include <utility>
#include <type_traits>
#include <tuple>
#include <dune/common/indices.hh>
#include <dune/common/timer.hh>
#include <dune/common/iteratorrange.hh>
#include <dune/common/promotiontraits.hh>
#include <dune/common/reservedvector.hh>
#include <dune/geometry/affinegeometry.hh>
#include <dune/geometry/type.hh>
#include <dune/grid/common/mcmgmapper.hh>
#include <dumux/common/geometry/geometricentityset.hh>
#include <dumux/common/geometry/boundingboxtree.hh>
#include <dumux/common/geometry/intersectingentities.hh>
#include <dumux/common/geometry/intersectionentityset.hh>
namespace Dumux {
// forward declaration
template<class DomainGridView, class TargetGridView, class DomainMapper, class TargetMapper>
class MultiDomainGlue;
/*!
* \ingroup MultiDomain
* \brief Range generator to iterate with range-based for loops over all intersections
* as follows: for (const auto& is : intersections(glue)) { ... }
*/
template<class DomainGridView, class TargetGridView, class DomainMapper, class TargetMapper>
Dune::IteratorRange<typename MultiDomainGlue<DomainGridView, TargetGridView, DomainMapper, TargetMapper>::Intersections::const_iterator>
intersections(const MultiDomainGlue<DomainGridView, TargetGridView, DomainMapper, TargetMapper>& glue)
{ return {glue.ibegin(), glue.iend()}; }
namespace Glue {
/*!
* \ingroup MultiDomain
* \brief An intersection object representing the intersection
* between two grid entites of different grids
*/
template<class DomainGridView, class TargetGridView, class DomainMapper, class TargetMapper>
class Intersection
class MultiDomainGlue : public IntersectionEntitySet<GridViewGeometricEntitySet<DomainGridView, 0, DomainMapper>,
GridViewGeometricEntitySet<TargetGridView, 0, TargetMapper>>
{
using DomainElement = typename DomainGridView::template Codim<0>::Entity;
using TargetElement = typename TargetGridView::template Codim<0>::Entity;
using DomainEntitySet = GridViewGeometricEntitySet<DomainGridView, 0, DomainMapper>;
using DomainTree = BoundingBoxTree<DomainEntitySet>;
using TargetEntitySet = GridViewGeometricEntitySet<TargetGridView, 0, TargetMapper>;
using TargetTree = BoundingBoxTree<TargetEntitySet>;
static constexpr int dimWorld = DomainGridView::dimensionworld;
static_assert(dimWorld == int(TargetGridView::dimensionworld), "Grids must have the same world dimension");
static constexpr int dimDomain = DomainGridView::dimension;
static constexpr int dimTarget = TargetGridView::dimension;
static constexpr int dimIs = std::min(dimDomain, dimTarget);
using ctypeDomain = typename DomainGridView::ctype;
using ctypeTarget = typename TargetGridView::ctype;
using ctype = typename Dune::PromotionTraits<ctypeDomain, ctypeTarget>::PromotedType;
using Geometry = Dune::AffineGeometry<ctype, dimIs, dimWorld>;
using GlobalPosition = Dune::FieldVector<ctype, dimWorld>;
// we can only have multiple neighbors in the mixeddimensional case and then only for the side with the largest dimension
using IndexStorage = std::pair<std::conditional_t<dimDomain <= dimTarget, Dune::ReservedVector<std::size_t, 1>, std::vector<std::size_t>>,
std::conditional_t<dimTarget <= dimDomain, Dune::ReservedVector<std::size_t, 1>, std::vector<std::size_t>>>;
static constexpr auto domainIdx = Dune::index_constant<0>{};
static constexpr auto targetIdx = Dune::index_constant<1>{};
public:
Intersection(const DomainTree& domainTree, const TargetTree& targetTree)
: domainTree_(domainTree)
, targetTree_(targetTree)
{}
//! set the intersection geometry corners
void setCorners(const std::vector<GlobalPosition>& corners)
{
corners_ = corners;
assert(corners.size() == dimIs + 1); // Only simplex intersections are allowed
}
//! add a pair of neighbor elements
void addNeighbors(std::size_t domain, std::size_t target)
{
if (numDomainNeighbors() == 0 && numTargetNeighbors() == 0)
{
std::get<domainIdx>(neighbors_).push_back(domain);
std::get<targetIdx>(neighbors_).push_back(target);
}
else if (dimDomain > dimTarget)
std::get<domainIdx>(neighbors_).push_back(domain);
else if (dimTarget > dimDomain)
std::get<targetIdx>(neighbors_).push_back(target);
else
DUNE_THROW(Dune::InvalidStateException, "Cannot add more than one neighbor per side for equidimensional intersection!");
}
//! get the intersection geometry
Geometry geometry() const
{ return Geometry(Dune::GeometryTypes::simplex(dimIs), corners_); }
//! get the number of domain neighbors of this intersection
std::size_t numDomainNeighbors() const
{ return std::get<domainIdx>(neighbors_).size(); }
//! get the number of target neighbors of this intersection
std::size_t numTargetNeighbors() const
{ return std::get<targetIdx>(neighbors_).size(); }
//! get the nth domain neighbor entity
DomainElement domainEntity(unsigned int n = 0) const
{ return domainTree_.entitySet().entity(std::get<domainIdx>(neighbors_)[n]); }
//! get the nth target neighbor entity
TargetElement targetEntity(unsigned int n = 0) const
{ return targetTree_.entitySet().entity(std::get<targetIdx>(neighbors_)[n]); }
private:
IndexStorage neighbors_;
std::vector<GlobalPosition> corners_;
const DomainTree& domainTree_;
const TargetTree& targetTree_;
};
} // end namespace Glue
/*!
* \ingroup MultiDomain
* \brief Manages the coupling between domain elements and lower dimensional elements
* Point sources on each integration point are computed by an AABB tree.
* Both domain are assumed to be discretized using a cc finite volume scheme.
*/
template<class DomainGridView, class TargetGridView,
class DomainMapper = Dune::MultipleCodimMultipleGeomTypeMapper<DomainGridView>,
class TargetMapper = Dune::MultipleCodimMultipleGeomTypeMapper<TargetGridView>>
class MultiDomainGlue
{
using DomainEntitySet = GridViewGeometricEntitySet<DomainGridView, 0, DomainMapper>;
using ParentType = IntersectionEntitySet<DomainEntitySet, TargetEntitySet>;
using DomainTree = BoundingBoxTree<DomainEntitySet>;
using TargetEntitySet = GridViewGeometricEntitySet<TargetGridView, 0, TargetMapper>;
using TargetTree = BoundingBoxTree<TargetEntitySet>;
using ctypeDomain = typename DomainGridView::ctype;
using ctypeTarget = typename TargetGridView::ctype;
using ctype = typename Dune::PromotionTraits<ctypeDomain, ctypeTarget>::PromotedType;
enum { dimWorld = DomainGridView::dimensionworld };
using GlobalPosition = Dune::FieldVector<ctype, dimWorld>;
static constexpr int dimDomain = DomainGridView::dimension;
static constexpr int dimTarget = TargetGridView::dimension;
static constexpr bool isMixedDimensional = dimDomain != dimTarget;
public:
// export intersection container type
using Intersections = std::vector<Glue::Intersection<DomainGridView, TargetGridView, DomainMapper, TargetMapper>>;
using ParentType::ParentType;
/*!
* \brief Default constructor
*/
MultiDomainGlue() = default;
/*!
* \brief Constructor
*/
// TODO: After the deprecation period (after release 3.2) this class can be replaced by an alias template
[[deprecated("Will be removed after 3.2. Use default constructor and call build(domainTree, targetTree)!")]]
MultiDomainGlue(const DomainTree& domainTree, const TargetTree& targetTree)
{ build(domainTree, targetTree); }
void build(const DomainTree& domainTree, const TargetTree& targetTree)
{
Dune::Timer timer;
// compute raw intersections
auto rawIntersections = intersectingEntities(domainTree, targetTree);
// create a map to check whether intersection geometries were already inserted
// Note that this can only occur if the grids have different dimensionality.
// If this is the case, we keep track of the intersections using the indices of the lower-
// dimensional entities which is identical for all geometrically identical intersections.
std::vector<std::vector<std::vector<GlobalPosition>>> intersectionMap;
std::vector<std::vector<std::size_t>> intersectionIndex;
if ( isMixedDimensional )
{
const auto numLowDimEntities = dimTarget < dimDomain ? targetTree.entitySet().size()
: domainTree.entitySet().size();
intersectionMap.resize(numLowDimEntities);
intersectionIndex.resize(numLowDimEntities);
}
// lambda to obtain the index of the lower-dimensional neighbor of a raw intersection
auto getLowDimNeighborIdx = [] (const auto& rawIS)
{ return dimTarget < dimDomain ? rawIS.second() : rawIS.first(); };
// reserve memory for storing the intersections. In case of grids of
// different dimensionality this might be an overestimate. We get rid
// of the overhead memory at the end of this function though.
intersections_.clear();
intersections_.reserve(rawIntersections.size());
for (const auto& rawIntersection : rawIntersections)
{
bool add = true;
// Check if intersection was already inserted.
// In this case we only add new neighbor information as the geometry is identical.
if ( isMixedDimensional )
{
const auto lowDimNeighborIdx = getLowDimNeighborIdx(rawIntersection);
for (int i = 0; i < intersectionMap[lowDimNeighborIdx].size(); ++i)
{
if (rawIntersection.cornersMatch(intersectionMap[lowDimNeighborIdx][i]))
{
add = false;
// only add the pair of neighbors using the insertionIndex
auto idx = intersectionIndex[lowDimNeighborIdx][i];
intersections_[idx].addNeighbors(rawIntersection.first(), rawIntersection.second());
break;
}
}
}
if(add)
{
// maybe add to the map
if ( isMixedDimensional )
{
intersectionMap[getLowDimNeighborIdx(rawIntersection)].push_back(rawIntersection.corners());
intersectionIndex[getLowDimNeighborIdx(rawIntersection)].push_back(intersections_.size());
}
// add new intersection and add the neighbors
intersections_.emplace_back(domainTree, targetTree);
intersections_.back().setCorners(rawIntersection.corners());
intersections_.back().addNeighbors(rawIntersection.first(), rawIntersection.second());
}
}
intersections_.shrink_to_fit();
std::cout << "Computed tree intersections in " << timer.elapsed() << std::endl;
}
//! Return begin iterator to intersection container
typename Intersections::const_iterator ibegin() const
{ return intersections_.begin(); }
//! Return end iterator to intersection container
typename Intersections::const_iterator iend() const
{ return intersections_.end(); }
//! the number of intersections
std::size_t size() const
{ return intersections_.size(); }
private:
Intersections intersections_;
{ this->build(domainTree, targetTree); }
};
/*!
......@@ -309,7 +63,10 @@ MultiDomainGlue< typename DomainGG::GridView, typename TargetGG::GridView,
typename DomainGG::ElementMapper, typename TargetGG::ElementMapper >
makeGlue(const DomainGG& domainGridGeometry, const TargetGG& targetGridGeometry)
{
return {domainGridGeometry.boundingBoxTree(), targetGridGeometry.boundingBoxTree()};
MultiDomainGlue< typename DomainGG::GridView, typename TargetGG::GridView,
typename DomainGG::ElementMapper, typename TargetGG::ElementMapper > glue;
glue.build(domainGridGeometry.boundingBoxTree(), targetGridGeometry.boundingBoxTree());
return glue;
}
} // end namespace Dumux
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment