diff --git a/dune/subgrid/CMakeLists.txt b/dune/subgrid/CMakeLists.txt index 5f078aad77f62ec6cb17e1a9db05778c01c5b56a..c09b0c42fa656bcabbfd5ae6fc2d9088e1427a0a 100644 --- a/dune/subgrid/CMakeLists.txt +++ b/dune/subgrid/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(common) add_subdirectory(facetools) add_subdirectory(subgrid) add_subdirectory(test) diff --git a/dune/subgrid/common/CMakeLists.txt b/dune/subgrid/common/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a31ec91c4cfb2205d700956f5a1633d72fe8b067 --- /dev/null +++ b/dune/subgrid/common/CMakeLists.txt @@ -0,0 +1,5 @@ +set(commonincludedir ${CMAKE_INSTALL_INCLUDEDIR}/dune/subgrid/common) +set(commoninclude_HEADERS variant.hh) +# include not needed for CMake +# include $(top_srcdir)/am/global-rules +install(FILES ${commoninclude_HEADERS} DESTINATION ${commonincludedir}) diff --git a/dune/subgrid/common/variant.hh b/dune/subgrid/common/variant.hh new file mode 100644 index 0000000000000000000000000000000000000000..e2132ea6c66de8266669eb87f8b9a44fe6143837 --- /dev/null +++ b/dune/subgrid/common/variant.hh @@ -0,0 +1,387 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_COMMON_STD_VARIANT_HH +#define DUNE_COMMON_STD_VARIANT_HH +#include <tuple> +#include <memory> +#include <dune/common/hybridutilities.hh> +#include <dune/common/exceptions.hh> + +namespace Dune { +namespace Std { +namespace Impl { + + /* helper constructs to find position of a type T in a pack Ts... */ + template <typename T, typename... Ts> + struct index_in_pack; + + template <typename T, typename... Ts> + struct index_in_pack<T, T, Ts...> : std::integral_constant<std::size_t, 0> {}; + + template <typename T, typename U, typename... Ts> + struct index_in_pack<T, U, Ts...> : std::integral_constant<std::size_t, 1 + index_in_pack<T, Ts...>::value> {}; + + /* end helper constructs to find position of a type T in a pack Ts... */ + + template<typename Tp> + struct Buffer_ : std::aligned_storage<sizeof(Tp)> { + using Storage = typename std::aligned_storage_t<sizeof(Tp)>::type; + Storage storage_; + + void* addr() { + return static_cast<void*>(&storage_); + } + + const void* addr() const { + return static_cast<const void*>(&storage_); + } + + Tp* ptr() { + return static_cast<Tp*>(addr()); + } + + const Tp* ptr() const { + return static_cast<const Tp*>(addr()); + } + }; + + template<typename Tp, bool isTrivial> + struct TypeStorage_ { }; + + template<typename Tp> + struct TypeStorage_<Tp, true> { + TypeStorage_(Tp t) : + tp_(t) {} + + template<typename... Args> + TypeStorage_(Args... args) : + tp_(args...) {} + + auto& get() { + return tp_; + } + const auto& get() const { + return tp_; + } + private: + Tp tp_; + }; + + template<typename Tp> + struct TypeStorage_<Tp, false> { + TypeStorage_(Tp t) { + ::new (&tp_) Tp(t); + } + + template<typename... Args> + TypeStorage_(Args... args) { + ::new (&tp_) Tp(std::forward<Args>(args)...); + } + + auto& get() { + return *(tp_.ptr()); + } + const auto& get() const { + return *(tp_.ptr()); + } + + private: + Buffer_<Tp> tp_; + }; + + template<typename... T> + union variant_union_ {}; + + template<typename Head_, typename... Tail_> + union variant_union_<Head_, Tail_...> { + constexpr variant_union_() : + tail_() {} + + template<typename... Args> + constexpr variant_union_(std::integral_constant<size_t, 0>, Args&&... args) : + head_(std::forward<Args...>(args)...) {} + + template<size_t N, typename... Args> + constexpr variant_union_(std::integral_constant<size_t, N>, Args&&... args) : + tail_(std::integral_constant<size_t, N-1>(), std::forward<Args...>(args)...) {} + + auto& getByIndex(std::integral_constant<size_t, 0>) { + return head_.get(); + } + + const auto& getByIndex(std::integral_constant<size_t, 0>) const { + return head_.get(); + } + + + template<size_t N> + auto& getByIndex(std::integral_constant<size_t, N>) { + return tail_.getByIndex(std::integral_constant<size_t, N-1>()); + } + + template<size_t N> + const auto& getByIndex(std::integral_constant<size_t, N>) const { + return tail_.getByIndex(std::integral_constant<size_t, N-1>()); + } + + template<typename Tp> + void set(Tp obj) { + Dune::Hybrid::ifElse(std::is_same<Tp, Head_>(), + [&](auto&& id) { head_=std::move(id(obj)); }, + [&](auto&& id) { return id(tail_).set(std::move(obj)); } + ); + } + + constexpr size_t size() const { + return sizeof...(Tail_)+1; + } + + private: + TypeStorage_<Head_, std::is_literal_type<Head_>::value> head_; + variant_union_<Tail_...> tail_; + }; + + template<typename...T> + struct variant_{ + + constexpr variant_() : + unions_() {} + + template<typename Tp> + constexpr variant_(Tp obj) : + unions_(), + index_(index_in_pack<Tp, T...>::value) + { + unions_.set(std::move(obj)); + } + + template<typename Tp> + auto& get() { + constexpr size_t idx = index_in_pack<Tp, T...>::value; + if (index_ != idx) + DUNE_THROW(Dune::Exception, "Bad variant access."); + + return get<idx>(); + } + + template<typename Tp> + const auto& get() const { + constexpr size_t idx = index_in_pack<Tp, T...>::value; + if (index_ != idx) + DUNE_THROW(Dune::Exception, "Bad variant access."); + + return get<idx>(); + } + + template<typename Tp> + Tp* get_if() { + if (not holds_alternative<Tp>()) + return (Tp*) nullptr; + else + return &(get<Tp>()); + } + + template<typename Tp> + const Tp* get_if() const { + if (not holds_alternative<Tp>()) + return (Tp*) nullptr; + else + return &(get<Tp>()); + } + + template<size_t N> + auto* get_if() { + using Tp = std::decay_t<decltype(get<N>())>; + if (not holds_alternative<N>()) + return (Tp*) nullptr; + else + return &(get<Tp>()); + } + + template<size_t N> + const auto* get_if() const { + using Tp = std::decay_t<decltype(get<N>())>; + if (not holds_alternative<N>()) + return (Tp*) nullptr; + else + return &(get<Tp>()); + } + + template<size_t N> + auto& get() { + if (index_ != N) + DUNE_THROW(Dune::Exception, "Bad variant access."); + return unions_.template getByIndex(std::integral_constant<size_t, N>()); + } + template<size_t N> + const auto& get() const { + if (index_ != N) + DUNE_THROW(Dune::Exception, "Bad variant access."); + return unions_.template getByIndex(std::integral_constant<size_t, N>()); + } + + template<typename Tp> + constexpr Tp& operator=(Tp obj) { + unions_.set(std::move(obj)); + constexpr auto index = index_in_pack<Tp, T...>::value; + index_=index; + return unions_.getByIndex(std::integral_constant<size_t,index>()); + } + + constexpr std::size_t index() const noexcept { + return index_; + } + + constexpr auto size() const { + return sizeof...(T); + } + + /* \brief Apply visitor to the active variant. + * + * visit assumes that the result of + * func(T) has the same type for all types T + * in this variant. + */ + template<typename F> + auto visit(F&& func) { + using namespace Dune::Hybrid; + + using Result = decltype(func(unions_.getByIndex(std::integral_constant<size_t, 0>()))); + + return ifElse(std::is_same<Result, void>(), [&, this](auto id) { + constexpr auto tsize = size_; + Dune::Hybrid::forEach(Dune::Hybrid::integralRange(std::integral_constant<size_t, tsize>()), [&](auto i) { + if (i==this->index_) + func(id(unions_).getByIndex(std::integral_constant<size_t, i>())); + }); + return;}, + [&func,this](auto id) { + constexpr auto tsize = size_; + + auto result = std::unique_ptr<Result>(); + + Dune::Hybrid::forEach(Dune::Hybrid::integralRange(std::integral_constant<size_t, tsize>()), [&, this](auto i) { + if (i==this->index_) + result = std::make_unique<Result>(func(id(this->unions_).getByIndex(std::integral_constant<size_t, i>()))); + }); + return *result; + }); + } + + template<typename F> + auto visit(F&& func) const { + using namespace Dune::Hybrid; + + using Result = decltype(func(unions_.getByIndex(std::integral_constant<size_t, 0>()))); + + return ifElse(std::is_same<Result, void>(), [&, this](auto id) { + constexpr auto tsize = size_; + Dune::Hybrid::forEach(Dune::Hybrid::integralRange(std::integral_constant<size_t, tsize>()), [&](auto i) { + if (i==this->index_) + func(id(unions_).getByIndex(std::integral_constant<size_t, i>())); + }); + return;}, + [&func,this](auto id) { + constexpr auto tsize = size_; + + auto result = std::unique_ptr<Result>(); + + Dune::Hybrid::forEach(Dune::Hybrid::integralRange(std::integral_constant<size_t, tsize>()), [&, this](auto i) { + if (i==this->index_) + result = std::make_unique<Result>(func(id(this->unions_).getByIndex(std::integral_constant<size_t, i>()))); + }); + return *result; + }); + } + + /** \brief Check if a given type is the one that is currently active in the variant. */ + template<typename Tp> + constexpr bool holds_alternative() const { + // I have no idea how this could be really constexpr, but for STL-conformity, + // I'll leave the modifier there. + return (index_in_pack<Tp, T...>::value == index_); + } + + /** \brief Check if a given type is the one that is currently active in the variant. */ + template<size_t N> + constexpr bool holds_alternative() const { + // I have no idea how this could be really constexpr, but for STL-conformity, + // I'll leave the modifier there. + return (N == index_); + } + + private: + variant_union_<T...> unions_; + std::size_t index_; + constexpr static auto size_ = sizeof...(T); + }; + +} // end namespace Impl + + /** \brief Incomplete re-implementation of C++17's std::variant. */ + template<typename ...T> + using variant = Impl::variant_<T...>; + + template<size_t N, typename... T> + auto& get(variant<T...>& var) { + return var.template get<N>(); + } + + template<size_t N, typename... T> + const auto& get(const variant<T...>& var) { + return var.template get<N>(); + } + + template<typename F, typename... T> + auto visit(F&& visitor, variant<T...>& var) { + return var.visit(std::forward<F>(visitor)); + } + + template<typename F, typename... T> + auto visit(F&& visitor, const variant<T...>& var) { + return var.visit(std::forward<F>(visitor)); + } + + template<typename Tp, typename ...T> + auto& get(variant<T...>& var) { + return var.template get<Tp>(); + } + + template<typename Tp, typename ...T> + const auto& get(const variant<T...>& var) { + return var.template get<Tp>(); + } + + template<typename Tp, typename ...T> + const auto* get_if(const variant<T...>& var) { + return var.template get_if<Tp>(); + } + + template<typename Tp, typename ...T> + auto* get_if(variant<T...>& var) { + return var.template get_if<Tp>(); + } + + template<size_t N, typename ...T> + const auto* get_if(const variant<T...>& var) { + return var.template get_if<N>(); + } + + template<size_t N, typename ...T> + auto* get_if(variant<T...>& var) { + return var.template get_if<N>(); + } + + template<typename Tp, typename ...T> + constexpr bool holds_alternative(const variant<T...>& var) { + return var.template holds_alternative<Tp>(); + } + + template <typename... T> + constexpr auto variant_size_v(const variant<T...>&) { + return std::integral_constant<std::size_t,sizeof...(T)>::value; + } + +} // end namespace Std +} // end namespace Dune +#endif diff --git a/dune/subgrid/subgrid/subgridgeometry.hh b/dune/subgrid/subgrid/subgridgeometry.hh index 26d700e3dd228a6e0c5f53ae1a19a003596345a5..578ca06328afd5d4d24e7543e45b28124259296b 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 f8cef36b5326e8291add18e65061a800548b65dc..8e231df7b8757bd28611d59d1b21448414978207 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 { diff --git a/dune/subgrid/test/CMakeLists.txt b/dune/subgrid/test/CMakeLists.txt index 1cb2c78ee5dd68fa6288e0e83b9effc9bfeb25ce..735fbd88d618686fdf69086a3f87a445c943cdae 100644 --- a/dune/subgrid/test/CMakeLists.txt +++ b/dune/subgrid/test/CMakeLists.txt @@ -1,5 +1,5 @@ -set(TESTPROGS test-w-onedgrid test-w-yaspgrid test-w-alugrid) +set(TESTPROGS test-w-onedgrid test-w-yaspgrid test-w-alugrid testvariant) if(ALBERTA_FOUND) list(APPEND TESTPROGS test-w-albertagrid2d) diff --git a/dune/subgrid/test/testvariant.cc b/dune/subgrid/test/testvariant.cc new file mode 100644 index 0000000000000000000000000000000000000000..ca0393f89e1c53ab03a65ce361ddeea4fe45d7bb --- /dev/null +++ b/dune/subgrid/test/testvariant.cc @@ -0,0 +1,107 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <iostream> +#include <dune/common/parallel/mpihelper.hh> // An initializer of MPI +#include <dune/common/exceptions.hh> // We use exceptions +#include <dune/common/test/testsuite.hh> + +#include <dune/subgrid/common/variant.hh> + +// some non-default constructible type +struct F { + int i; + F() = delete; + F(int j) : + i(j) {} +}; + +Dune::TestSuite testVariant() { + using namespace Dune; + TestSuite suite; + + int i = 42; + double d = 3.14; + F f(13); + using V = std::vector<int>; + + auto variant = Std::variant<int, double, F, V>(); + + suite.check(Std::variant_size_v(variant) == 4, "Test variant_size_v"); + + + variant = d; + suite.check(Std::holds_alternative<double>(variant), "Test holds_alternative"); + + variant = f; + suite.check(Std::holds_alternative<F>(variant), "Test holds_alternative"); + + variant = i; + suite.check(Std::holds_alternative<int>(variant), "Test holds_alternative"); + + suite.check(Std::get<int>(variant) == i, "Test get<Type>"); + suite.check(Std::get<0>(variant) == i, "Test get<Index>"); + + suite.check(Std::get_if<int>(variant) != nullptr, "Test get_if on right type"); + suite.check(Std::get_if<double>(variant) == nullptr, "Test get_if on wrong type"); + + suite.check(Std::get_if<0>(variant) != nullptr, "Test get_if on right index"); + suite.check(Std::get_if<1>(variant) == nullptr, "Test get_if on wrong index"); + + // test if get<Type> throws if one tries to get the wrong type: + try { + // currently hold type is still int, so double should throw + Std::get<double>(variant); + suite.check(false, "Test get<Type> on wrong type should have thrown"); + } + catch (...) { + suite.check(true, "Test get<Type> on wrong type has thrown"); + } + + + variant = V(1); + suite.check(Std::get<V>(variant).size() == 1, "Test with non-trivial type"); + + variant = f; + + suite.check(variant.index() == 2, "Test index()"); // we're at type F, which has position 2 + + // Demonstrate visit concept and using vector as an example of a non-POD type + using V2 = std::vector<double>; + Std::variant<V, V2> variant2; + variant2 = V(1); + auto size = [](auto&& v) {return v.size();}; + suite.check(Std::visit(size, variant2)== 1, "Test visit"); + variant2 = V2(2); + suite.check(Std::visit(size, variant2)== 2, "Test visit"); + + // try on a const reference: + const auto& constv2 = variant2; + suite.check(Std::visit(size, constv2)== 2, "Test const visit"); + suite.check(Std::get_if<V2>(constv2) != nullptr, "Test const get_if"); + + + return suite; +} + +int main(int argc, char** argv) +{ + try{ + // Maybe initialize MPI + Dune::MPIHelper::instance(argc, argv); + + Dune::TestSuite suite; + suite.subTest(testVariant()); + + return suite.exit(); + } + catch (Dune::Exception &e){ + std::cerr << "Dune reported error: " << e << std::endl; + } + catch (...){ + std::cerr << "Unknown exception thrown!" << std::endl; + } +}