From 7ed44503b2bc8d69f9903b61d083889c28f60b94 Mon Sep 17 00:00:00 2001 From: Timo Koch <timo.koch@iws.uni-stuttgart.de> Date: Mon, 30 Mar 2020 17:19:32 +0200 Subject: [PATCH] [md] Use intersectionentityset for implementing MultiDomainGlue --- dumux/multidomain/glue.hh | 267 ++------------------------------------ 1 file changed, 12 insertions(+), 255 deletions(-) diff --git a/dumux/multidomain/glue.hh b/dumux/multidomain/glue.hh index dab4af6316..a5996d7fd8 100644 --- a/dumux/multidomain/glue.hh +++ b/dumux/multidomain/glue.hh @@ -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 -- GitLab