Skip to content

GeometryType cannot be used as a template parameter

Back when I cleaned up the GeometryType, the consensus seemed that we really don't need the BasicType anymore. While cleaning up PDELab for 2.6, we've stumbled across BasicType in a few places and got rid of it in most of them, but we have found one problematic case (see also pdelab/dune-pdelab#102):

In PDELab, we have a unified interface for picking the correct LocalFiniteElement from dune-localfunctions depending on the GridView:

using FEM = RaviartThomasLocalFiniteElementMap<GV,DomainField,RangeField,rt_order>;

That class inspects the GridView and picks the correct implementation from dune-localfunctions, e.g. Dune::RT0Cube2DLocalFiniteElement<D,R>. This inspection fails for grids that do not export compile-time information about their unique cell GeometryType - mostly UG as it supports mixed grids. Right now, the user can work around this problem by explicitly specifying the BasicType:

using FEM = RaviartThomasLocalFiniteElementMap<GV,DomainField,RangeField,rt_order,Dune::GeometryType::simplex>;

That workaround now triggers lots of deprecation warnings.

We basically want the user to be able to say in a template parameter: Pick an implementation that works for tetrahedral or hexahedral elements. The easy solution

RaviartThomasLocalFiniteElementMap<...,Dune::GeometryTypes::simplex(GV::dimension)>

does not work because you can only have certain built-in types as template parameters.

I see three (two-and-a-half) possible solutions:

  1. Revert the deprecation of BasicType and postpone a real solution: the cheap way out. Maybe not a bad idea considering where we are in the release process of 2.6. Short term I would really like this and re-deprecate after 2.6 is out.

  2. Use the topologyId (accessible via GeometryType::id()) instead of the Basictype. That works, but you still need two template parameters to encode a GeometryType in the general case (dimension and topologyId). Moreover, explaining to users why they have to write

    Dune::GeometryTypes::simplex(dim).id() // note the trailing .id()

    won't be easy...

  3. Settle on GlobalGeometryTypeIndex as the "canonical" encoding of GeometryType in a single template parameter and provide implicit and constexpr-capable roundtripping between a GeometryType and its index:

    template<GeometryTypeIndex gt_index>
    struct FEM
    {
      static constexpr GeometryType gt(gt_index);
    };
    
    int test()
    {
      constexpr auto gt = GeometryTypes::triangle;
      FEM fem<gt>();
      constexpr auto gt2 = fem.gt;
      static_assert(gt == gt2, "this should work");
    }

    This can be easily implemented by adding a enum class GeometryTypeIndex and the necessary implicit conversion operators. This should not create unwanted implicit conversions, as enum class does not implicitly cast into its underlying type.

I am in favor of 1. and 3. Even though we are really late in the release, 3. seems rather low-risk as it is just a straight interface addition. @all: Thoughts?