diff --git a/dune/gdt/spaces/rt/default.hh b/dune/gdt/spaces/rt/default.hh index 0acf0f5edd0eb02ae41779f0eaee80834c3e578c..04c79fed951a20aee02e1d51c62adfe057cced6f 100644 --- a/dune/gdt/spaces/rt/default.hh +++ b/dune/gdt/spaces/rt/default.hh @@ -31,11 +31,20 @@ #include <dune/gdt/spaces/rt/interface.hh> namespace Dune { + + +// forwards +template <int dim, class Coordinates> +class YaspGrid; + +class OneDGrid; + + namespace GDT { // forwards, required for the traits -template <class E, class R = double> +template <class FE, class E, class R = double> class RaviartThomasBasefunctionSet; template <class GL, int p, class R = double> @@ -45,16 +54,16 @@ class RtSpace; namespace internal { -template <class E, class R> +template <class FE, class E, class R> class RaviartThomasBasefunctionSetTraits { using LocalFunctionTraits = XT::Functions::LocalfunctionSetInterface<E, typename E::Geometry::ctype, E::dimension, R, E::dimension>; public: - using derived_type = RaviartThomasBasefunctionSet<E, R>; + using derived_type = RaviartThomasBasefunctionSet<FE, E, R>; using EntityType = E; - using BackendType = RaviartThomasSimplexLocalFiniteElement<E::dimension, typename E::Geometry::ctype, R>; + using BackendType = FE; }; @@ -64,51 +73,120 @@ class RtSpaceTraits static_assert(XT::Grid::is_layer<GL>::value, ""); static_assert(p == 0, "Not implemented yet!"); using G = XT::Grid::extract_grid_t<GL>; - static_assert(Capabilities::hasSingleGeometryType<G>::v - && Capabilities::hasSingleGeometryType<G>::topologyId - == Impl::SimplexTopology<GL::dimension>::type::id, - "Not Implemented yet!"); public: - using derived_type = RtSpace<GL, p, R>; static const constexpr int polOrder = p; static const constexpr size_t dimDomain = GL::dimension; static const constexpr size_t dimRange = dimDomain; static const constexpr size_t dimRangeCols = 1; + +private: + template <class G_ = G, bool anything = true> + struct ChooseLocalFiniteElement + { + template <class some_type_we_need_for_the_always_false = G_, + bool single_geometry_type = Capabilities::hasSingleGeometryType<G>::v, + bool is_simplex = + Capabilities::hasSingleGeometryType<G>::topologyId == Impl::SimplexTopology<dimDomain>::type::id, + bool is_cube = + Capabilities::hasSingleGeometryType<G>::topologyId == Impl::CubeTopology<dimDomain>::type::id> + struct geometry_type_switch + { + // This requires virtual interfaces for the local finite elements. + static_assert(AlwaysFalse<some_type_we_need_for_the_always_false>::value, + "RtSpace is only available for purely simplicial or purely cubic grids atm!"); + }; + + template <class some_type_we_need_for_the_always_false> + struct geometry_type_switch<some_type_we_need_for_the_always_false, true, true, false> + { + using type = RaviartThomasSimplexLocalFiniteElement<dimDomain, typename GL::ctype, R>; + + static std::shared_ptr<type> create(const Dune::GeometryType& geometry_type, const int& polorder) + { + return std::make_shared<type>(geometry_type, polorder); + } + }; + + template <class some_type_we_need_for_the_always_false> + struct geometry_type_switch<some_type_we_need_for_the_always_false, true, false, true> + { + using type = RaviartThomasCubeLocalFiniteElement<typename GL::ctype, R, dimDomain, p>; + + static std::shared_ptr<type> create(const Dune::GeometryType& /*geometry_type*/, const int& /*polorder*/) + { + return std::make_shared<type>(); + } + }; + + using type = typename geometry_type_switch<>::type; + + static std::shared_ptr<type> create(const Dune::GeometryType& geometry_type, const int& polorder) + { + return geometry_type_switch<>::create(geometry_type, polorder); + } + }; + + // We need an exception for 1d YaspGrid: it reports to contain cubes but everything is a simplex in 1d. + template <bool anything, class Coordinates> + struct ChooseLocalFiniteElement<YaspGrid<1, Coordinates>, anything> + { + using type = RaviartThomasSimplexLocalFiniteElement<dimDomain, typename GL::ctype, R>; + + static std::shared_ptr<type> create(const Dune::GeometryType& geometry_type, const int& polorder) + { + return std::make_shared<type>(geometry_type, polorder); + } + }; + + // We need an exception for OneDGrid: it reports to contain cubes but everything is a simplex in 1d. + template <bool anything> + struct ChooseLocalFiniteElement<OneDGrid, anything> + { + using type = RaviartThomasSimplexLocalFiniteElement<dimDomain, typename GL::ctype, R>; + + static std::shared_ptr<type> create(const Dune::GeometryType& geometry_type, const int& polorder) + { + return std::make_shared<type>(geometry_type, polorder); + } + }; + +public: + using derived_type = RtSpace<GL, p, R>; static const constexpr bool continuous = false; using GridLayerType = GL; - using BaseFunctionSetType = RaviartThomasBasefunctionSet<XT::Grid::extract_entity_t<GL>, R>; - using MapperType = - FixedOrderMultipleCodimMultipleGeomTypeMapper<GL, - RaviartThomasSimplexLocalFiniteElement<dimDomain, - typename GL::ctype, - R>>; + using BackendType = typename ChooseLocalFiniteElement<>::type; + using BaseFunctionSetType = RaviartThomasBasefunctionSet<BackendType, XT::Grid::extract_entity_t<GL>, R>; + using MapperType = FixedOrderMultipleCodimMultipleGeomTypeMapper<GL, BackendType>; using RangeFieldType = R; - using BackendType = double; static const constexpr XT::Grid::Backends layer_backend = XT::Grid::Backends::view; static const constexpr Backends backend_type{Backends::gdt}; typedef DofCommunicationChooser<GridLayerType, false> DofCommunicationChooserType; typedef typename DofCommunicationChooserType::Type DofCommunicatorType; + +private: + friend class RtSpace<GL, p, R>; }; // class RtSpaceTraits } // namespace internal -template <class E, class R> -class RaviartThomasBasefunctionSet : public BaseFunctionSetInterface<internal::RaviartThomasBasefunctionSetTraits<E, R>, - typename E::Geometry::ctype, - E::dimension, - R, - E::dimension, - 1> +template <class FE, class E, class R> +class RaviartThomasBasefunctionSet + : public BaseFunctionSetInterface<internal::RaviartThomasBasefunctionSetTraits<FE, E, R>, + typename E::Geometry::ctype, + E::dimension, + R, + E::dimension, + 1> { public: - using Traits = internal::RaviartThomasBasefunctionSetTraits<E, R>; + using Traits = internal::RaviartThomasBasefunctionSetTraits<FE, E, R>; private: using BaseType = BaseFunctionSetInterface<Traits, typename E::Geometry::ctype, E::dimension, R, E::dimension, 1>; - using ThisType = RaviartThomasBasefunctionSet<E, R>; + using ThisType = RaviartThomasBasefunctionSet<FE, E, R>; public: using typename BaseType::BackendType; @@ -219,11 +297,12 @@ private: using ThisType = RtSpace<GL, p, R>; using D = typename GL::ctype; static const constexpr size_t d = BaseType::dimDomain; - using FiniteElementType = RaviartThomasSimplexLocalFiniteElement<d, D, R>; + using FiniteElementType = typename BaseType::BackendType; typedef typename Traits::DofCommunicationChooserType DofCommunicationChooserType; public: using typename BaseType::GridLayerType; + using typename BaseType::BackendType; using typename BaseType::EntityType; using typename BaseType::MapperType; using typename BaseType::BaseFunctionSetType; @@ -235,14 +314,14 @@ public: , backend_(0) , finite_elements_(new std::map<GeometryType, std::shared_ptr<FiniteElementType>>()) , geometry_to_local_DoF_indices_map_(new std::map<GeometryType, std::vector<size_t>>()) - , switches_(new std::vector<std::vector<R>>(grid_layer_.indexSet().size(0))) - , mapper_(nullptr) + , entity_indices_(new ZeroOrderScalarDiscontinuousMapper<GL>(grid_layer_)) // <- We need unique indices for codim 0 + , switches_(new std::vector<std::vector<R>>(entity_indices_->size())) // entities: this cannot be achieved by + , mapper_(nullptr) // the grid layers index set for mixed grids. , communicator_prepared_(false) { - const auto& index_set = grid_layer_.indexSet(); // create finite elements - for (auto&& geometry_type : index_set.types(0)) { - auto finite_element = std::make_shared<FiniteElementType>(geometry_type, p); + for (auto&& geometry_type : grid_layer_.indexSet().types(0)) { + auto finite_element = Traits::template ChooseLocalFiniteElement<>::create(geometry_type, p); finite_elements_->insert(std::make_pair(geometry_type, finite_element)); // this is only valid for p0 elements geometry_to_local_DoF_indices_map_->insert( @@ -288,11 +367,11 @@ public: const auto geometry_type = entity.geometry().type(); const auto& finite_element = *finite_elements_->at(geometry_type); const auto& coeffs = finite_element.localCoefficients(); - const auto entity_index = index_set.index(entity); + const auto entity_index = entity_indices_->mapToGlobal(entity, 0); (*switches_)[entity_index] = geometry_to_scaling_factors_map.at(geometry_type); auto& local_switches = switches_->at(entity_index); for (auto&& intersection : intersections(grid_layer_, entity)) { - if (intersection.neighbor() && entity_index < index_set.index(intersection.outside())) { + if (intersection.neighbor() && entity_index < entity_indices_->mapToGlobal(intersection.outside(), 0)) { const auto intersection_index = XT::Common::numeric_cast<unsigned int>(intersection.indexInInside()); for (size_t ii = 0; ii < coeffs.size(); ++ii) { const auto& local_key = coeffs.localKey(ii); @@ -318,9 +397,9 @@ public: return grid_layer_; } - const double& backend() const + const BackendType& backend() const { - return backend_; + return *finite_elements_->begin(); } const MapperType& mapper() const @@ -337,7 +416,7 @@ public: "\n entity.geometry().type() = " << entity.geometry().type()); const auto& finite_element = *finite_element_search_result->second; - return BaseFunctionSetType(entity, finite_element, (*switches_)[grid_layer_.indexSet().index(entity)]); + return BaseFunctionSetType(entity, finite_element, (*switches_)[entity_indices_->mapToGlobal(entity, 0)]); } DofCommunicatorType& dof_communicator() const @@ -366,6 +445,7 @@ private: const double backend_; std::shared_ptr<std::map<GeometryType, std::shared_ptr<FiniteElementType>>> finite_elements_; std::shared_ptr<std::map<GeometryType, std::vector<size_t>>> geometry_to_local_DoF_indices_map_; + std::shared_ptr<ZeroOrderScalarDiscontinuousMapper<GL>> entity_indices_; std::shared_ptr<std::vector<std::vector<R>>> switches_; std::shared_ptr<MapperType> mapper_; mutable bool communicator_prepared_;