From ceaf95c12677d041d1ba392abeb708d20bccae9f Mon Sep 17 00:00:00 2001 From: Lasse Hinrichsen <lh1887@mi.fu-berlin.de> Date: Wed, 18 Oct 2017 16:29:14 +0200 Subject: [PATCH] Add implementation for geometryInInside and geometryInOutside --- dune/subgrid/subgrid/subgridgeometry.hh | 152 ++++++++++++++------ dune/subgrid/subgrid/subgridintersection.hh | 74 ++++++++-- 2 files changed, 175 insertions(+), 51 deletions(-) diff --git a/dune/subgrid/subgrid/subgridgeometry.hh b/dune/subgrid/subgrid/subgridgeometry.hh index 26d700e..578ca06 100644 --- a/dune/subgrid/subgrid/subgridgeometry.hh +++ b/dune/subgrid/subgrid/subgridgeometry.hh @@ -5,9 +5,11 @@ * \brief The SubGridGeometry class and its specializations */ #include <type_traits> +#include <dune/subgrid/common/variant.hh> #include <dune/common/fmatrix.hh> #include <dune/common/typetraits.hh> +#include <dune/geometry/multilineargeometry.hh> namespace Dune { @@ -22,13 +24,10 @@ template<int mydim, int coorddim, class GridImp> class SubGridLocalGeometry; because the Dune grid interface specifies the number and types of template parameters of that class. */ -template<int mydim, int coorddim, class GridImp, bool isLocal> -class SubGridGeometryBase +template<int mydim, int coorddim, class GridImp> +class SubGridGeometry { - private: - - typedef typename GridImp::ctype ctype; - + using ctype = typename GridImp::ctype; public: @@ -36,12 +35,7 @@ class SubGridGeometryBase enum {CodimInHostGrid = GridImp::HostGridType::dimension - mydim}; enum {DimensionWorld = GridImp::HostGridType::dimensionworld}; - // Select the type we are wrapping depending on the isLocal flag - // - isLocal == true: LocalGeometry - // - isLocal == false: Geometry - typedef typename std::conditional<isLocal, - typename GridImp::HostGridType::Traits::template Codim<CodimInHostGrid>::LocalGeometry, - typename GridImp::HostGridType::Traits::template Codim<CodimInHostGrid>::Geometry>::type HostGridGeometry; + using HostGridGeometry = typename GridImp::HostGridType::Traits::template Codim<CodimInHostGrid>::Geometry; //! The type of the Jacobian matrix of the mapping from the reference element to this element typedef typename HostGridGeometry::JacobianTransposed JacobianTransposed; @@ -50,7 +44,7 @@ class SubGridGeometryBase /** Constructor for a given host grid geometry */ - SubGridGeometryBase(const HostGridGeometry& hostGeometry) + SubGridGeometry(const HostGridGeometry& hostGeometry) : hostGeometry_(hostGeometry) { } @@ -120,59 +114,135 @@ class SubGridGeometryBase return hostGeometry_.center(); } - //! The Jacobian matrix of the mapping from the reference element to this element const JacobianTransposed jacobianTransposed (const FieldVector<ctype, mydim>& local) const { return hostGeometry_.jacobianTransposed(local); } - //! The inverse of the Jacobian matrix of the mapping from the reference element to this element const JacobianInverseTransposed jacobianInverseTransposed (const FieldVector<ctype, mydim>& local) const { return hostGeometry_.jacobianInverseTransposed(local); } - + private: const HostGridGeometry hostGeometry_; - }; -/** \brief Encapsulate a host grid Geometry */ +/** \brief Local SubGrid geometries. They can be either a wrapped hostgrid geometry or a multilineargeometry. */ template<int mydim, int coorddim, class GridImp> -class SubGridGeometry : - public SubGridGeometryBase<mydim,coorddim,GridImp,false> +class SubGridLocalGeometry { + + using ctype = typename GridImp::ctype; + public: - enum {CodimInHostGrid = GridImp::HostGridType::dimension - mydim}; + constexpr static int hostDim = GridImp::HostGridType::dimension; + constexpr static int dim = hostDim; + constexpr static int CodimInHostGrid = hostDim - mydim; - // select appropiate hostgrid geometry via typeswitch - typedef typename GridImp::HostGridType::Traits::template Codim<CodimInHostGrid>::Geometry HostGridGeometry; + private: + // the local geometry is either a wrapped hostgrid local geometry or a multilineargeometry + // TODO does this work for arbitratry co-dimensions? + using HostGridLocalGeometry = typename GridImp::HostGridType::Traits::template Codim<CodimInHostGrid>::LocalGeometry; + using MultiLinGeometry = MultiLinearGeometry<ctype, mydim, coorddim>; - /** Constructor for a given host grid geometry - */ - SubGridGeometry(const HostGridGeometry& hostGeometry) - : SubGridGeometryBase<mydim,coorddim,GridImp,false>(hostGeometry) + // use a variant to store either a HostGridLocalGeometry or a MultiLinearGeometry + using GeometryContainer = Std::variant<HostGridLocalGeometry, MultiLinGeometry>; + + public: + + // The codimension of this entitypointer wrt the host grid + //enum {CodimInHostGrid = GridImp::HostGridType::dimension - mydim}; + enum {DimensionWorld = GridImp::HostGridType::dimensionworld}; + + + //! The type of the Jacobian matrix of the mapping from the reference element to this element + using JacobianTransposed = typename std::common_type<FieldMatrix< ctype, mydim, coorddim>, + typename HostGridLocalGeometry::JacobianTransposed>::type; + + //! The type of the nverse of the Jacobian matrix of the mapping from the reference element to this element + using JacobianInverseTransposed = typename std::common_type<Dune::FieldMatrix<ctype,coorddim, mydim>, + typename HostGridLocalGeometry::JacobianInverseTransposed>::type; + + /** \brief Construct from a given host grid geometry*/ + SubGridLocalGeometry(HostGridLocalGeometry hostLocalGeometry) + : localGeometry_(std::move(hostLocalGeometry)) {} -}; + /** \brief Construct from MultiLinearGeometry */ + SubGridLocalGeometry(MultiLinGeometry multiLinGeometry) + : localGeometry_(std::move(multiLinGeometry)) + {} -/** \brief Encapsulate a host grid LocalGeometry */ -template<int mydim, int coorddim, class GridImp> -class SubGridLocalGeometry : - public SubGridGeometryBase<mydim,coorddim,GridImp,true> -{ - public: - enum {CodimInHostGrid = GridImp::HostGridType::dimension - mydim}; + /** \brief Return the element type identifier + */ + GeometryType type () const { + return Std::visit([&](auto&& geom) {return geom.type();}, localGeometry_); + } + + /** \brief Return true if the geometry mapping is affine and false otherwise */ + bool affine() const { + return Std::visit([&](auto&& geom) {return geom.affine();}, localGeometry_); + } + + //! return the number of corners of this element. Corners are numbered 0...n-1 + int corners () const { + return Std::visit([&](auto&& geom) {return geom.corners();}, localGeometry_); + } - // select appropiate hostgrid geometry via typeswitch - typedef typename GridImp::HostGridType::Traits::template Codim<CodimInHostGrid>::LocalGeometry HostGridLocalGeometry; + //! access to coordinates of corners. Index is the number of the corner + FieldVector<ctype, coorddim> corner (int i) const { + return Std::visit([&](auto&& geom) {return geom.corner(i);}, localGeometry_); + } - /** Constructor for a given host grid local geometry + /** \brief Maps a local coordinate within reference element to + * global coordinate in element */ + FieldVector<ctype, coorddim> global (const FieldVector<ctype, mydim>& local) const{ + return Std::visit([&](auto&& geom) {return geom.global(local);}, localGeometry_); + } + + /** \brief Maps a global coordinate within the element to a + * local coordinate in its reference element */ + FieldVector<ctype, mydim> local (const FieldVector<ctype, coorddim>& global) const { + return Std::visit([&](auto&& geom) {return geom.local(global);}, localGeometry_); + } + + /** */ - SubGridLocalGeometry(const HostGridLocalGeometry& hostGeometry) - : SubGridGeometryBase<mydim,coorddim,GridImp,true>(hostGeometry) - {} + ctype integrationElement (const FieldVector<ctype, mydim>& local) const { + return Std::visit([&](auto&& geom) {return geom.integrationElement(local);}, localGeometry_); + } + + /** \brief return volume of geometry */ + ctype volume () const { + return Std::visit([&](auto&& geom) {return geom.volume();}, localGeometry_); + } + /** \brief return center of geometry + * Note that this method is still subject to a change of name and semantics. + * At the moment, the center is not required to be the centroid of the + * geometry, or even the centroid of its corners. This makes the current + * default implementation acceptable, which maps the centroid of the + * reference element to the geometry. + * We may change the name (and semantic) of the method to centroid() if we + * find reasonably efficient ways to implement it properly. + */ + FieldVector<ctype, coorddim> center () const { + return Std::visit([&](auto&& geom) {return geom.center();}, localGeometry_); + } + + //! The Jacobian matrix of the mapping from the reference element to this element + const JacobianTransposed jacobianTransposed (const FieldVector<ctype, mydim>& local) const { + return Std::visit([&](auto&& geom) {return static_cast<JacobianTransposed>(geom.jacobianTransposed(local));}, localGeometry_); + } + + //! The inverse of the Jacobian matrix of the mapping from the reference element to this element + const JacobianInverseTransposed jacobianInverseTransposed (const FieldVector<ctype, mydim>& local) const { + return Std::visit([&](auto&& geom) {return static_cast<JacobianInverseTransposed>(geom.jacobianInverseTransposed(local));}, localGeometry_); + } + + private: + const GeometryContainer localGeometry_; }; } // namespace Dune diff --git a/dune/subgrid/subgrid/subgridintersection.hh b/dune/subgrid/subgrid/subgridintersection.hh index f8cef36..8e231df 100644 --- a/dune/subgrid/subgrid/subgridintersection.hh +++ b/dune/subgrid/subgrid/subgridintersection.hh @@ -5,6 +5,7 @@ #include <dune/subgrid/subgrid/subgridgeometry.hh> #include <dune/grid/common/exceptions.hh> +#include <dune/geometry/multilineargeometry.hh> namespace Dune { @@ -220,7 +221,7 @@ public: //! Return the global geometry of the intersection Geometry geometry () const { - if (outsideIntersect_.inside().level() >= insideIntersect_.inside().level()) + if (outsideIntersect_.inside().level() > insideIntersect_.inside().level()) return Geometry(GeometryImpl(outsideIntersect_.geometry())); else return Geometry(GeometryImpl(insideIntersect_.geometry())); @@ -231,21 +232,74 @@ public: return boundary() or ((outside_.level() == inside_.level()) and insideIntersect_.conforming()); } - //! intersection of codimension 1 of this neighbor with element where - //! iteration started. - //! Here returned element is in LOCAL coordinates of the element - //! where iteration started. + /** \brief Return the local geometry, mapping local coordinates of the intersection to + * local coordinates of the inside element. + * If the intersection is not part of the host grid, construct one using MultiLinearGeometry. + */ LocalGeometry geometryInInside () const { if (boundary()) return LocalGeometry(LocalGeometryImpl(insideIntersect_.geometryInInside())); - else - DUNE_THROW(NotImplemented, "SubGridLeafIntersection::geometryInInside()"); + + // Case 0: inside_'s the smaller element, or both elements are on the same level. + if (inside_.level() >= outside_.level()) + return LocalGeometry(LocalGeometryImpl(insideIntersect_.geometryInInside())); + + // Case 1: outsideIntersect_ is the intersection we want, embedded in inside_'s geometry + + auto outsideIsGeo = outsideIntersect_.geometry(); + auto insideGeo = inside_.geometry(); + + using Coords = std::decay_t<decltype(insideGeo.local(outsideIsGeo.corner(0)))>; + auto corners = std::vector<Coords>(outsideIsGeo.corners()); + + // Map the coordinates of the corners from the outside's local coordinates into inside's + // local coordinates + for (size_t i = 0; i < corners.size(); i++) + corners[i] = insideGeo.local(outsideIsGeo.corner(i)); + + // create a new geometry with the coordinates we just computed + auto geo = Dune::MultiLinearGeometry<ctype, dim-1, dim>(outsideIsGeo.type(), corners); + return LocalGeometry(LocalGeometryImpl(std::move(geo))); } - //! intersection of codimension 1 of this neighbor with element where iteration started. - //! Here returned element is in LOCAL coordinates of neighbor + /** \brief Return the local geometry, mapping local coordinates of the intersection to + * local coordinates of the outside element. + */ LocalGeometry geometryInOutside () const { - DUNE_THROW(NotImplemented, "SubGridLeafIntersection::geometryInOutside()"); + if(boundary()) + DUNE_THROW(Dune::Exception, "No outside geometry available for boundary intersections"); + + // Case 0: outside_'s the smaller element, or both elements are on the same level. + if (inside_.level() < outside_.level()) { + + auto outsideIsGeo = outsideIntersect_.geometry(); + auto outsideGeo = outside_.geometry(); + + using Coords = std::decay_t<decltype(outsideGeo.local(outsideIsGeo.corner(0)))>; + auto corners = std::vector<Coords>(outsideIsGeo.corners()); + for (size_t i = 0; i < corners.size(); i++) + corners[i] = outsideGeo.local(outsideIsGeo.corner(i)); + + // create a new geometry with the coordinates we just computed + auto geo = Dune::MultiLinearGeometry<ctype, dim-1, dim>(outsideIsGeo.type(), corners); + return LocalGeometry(LocalGeometryImpl(geo)); + } + + // Case 1: outsideIntersect_ is the intersection we want, embedded in inside_'s geometry + auto insideIsGeo = insideIntersect_.geometry(); + auto outsideGeo = outside_.geometry(); + + using Coords = std::decay_t<decltype(outsideGeo.local(insideIsGeo.corner(0)))>; + auto corners = std::vector<Coords>(insideIsGeo.corners()); + + // Map the coordinates of the corners from the insides's local coordinates into outside's + // local coordinates + for (size_t i = 0; i < corners.size(); i++) + corners[i] = outsideGeo.local(insideIsGeo.corner(i)); + + // create a new geometry with the coordinates we just computed + auto geo = Dune::MultiLinearGeometry<ctype, dim-1, dim>(insideIsGeo.type(), corners); + return LocalGeometry(LocalGeometryImpl(std::move(geo))); } bool equals(const SubGridLeafIntersection<GridImp> & other) const { -- GitLab