Skip to content
Snippets Groups Projects
lineartransformedlocalfiniteelement.hh 16.94 KiB
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:

#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LINEARTRANSFORMEDLOCALFINITEELEMENT_HH
#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_LINEARTRANSFORMEDLOCALFINITEELEMENT_HH
#include <dune/functions/functionspacebases/globalvaluedlocalfiniteelement.hh>
#include <dune/istl/scaledidmatrix.hh>

namespace Dune
{
  namespace Functions::Impl
  {
    /**
     * @brief This set of classes models a global valued Finite Element similar to the classes in
     * dune/functions/functionspacebases/globalvaluedlocalfiniteelement.hh
     *
     * However, here we restrict the admissable transformations to linear transformations of
     * the basisfunctions, as is the case for various Elements like Hermite, Morley and Argyris.
     * Additionally the Transformator classes can implemenent caching of the transformation and
     * thus cannot be purely static anymore.
     * This leads to some changes in the interface in constrast to range-space transformations like
     * Piola-Transformations.
     *
     * In particular, the interfaces differ from the "GlobalValued"-classes in the following points:
     *    LinearTransformator interface:
     *      - The LinearTransformator classes implement a linear transformation from one set of
     *        basisfunction onto another, that means, the transformation is invariant to
     *        differentiation, and the need for methods like "applyJacobian" vanishes.
     *      - The LinearTransformator classes are expected to implement a method bind(Element)
     *        which sets up the transformation, for example by filling a sparse Matrix with values.
     *      - The LinearTransformator classes are not static.
     *      - The inner class LocalValuedFunction cannot implement the inverse of the transformation
     *        as for Piola transformations. Instead, the LocalValuedFunction is the object, that,
     *        when evaluated by the LocalInterpolation class, gives the coefficients as if it was
     *        evaluated by the Physical Interpolation. It can (and should) therefore implement hooks
     *        for which the corresponding LocalInterpolation classes provide templates for, e.g.
     *        normalDerivative(size_t). The dune-functions interface mandates the derivative of a
     *        LocalFunction to be global-valued, which is another example for the mentioned
     *        template-hook pattern.
     *      - Additionally the inner class LocalValuedFunction should be differentiable (in the c++
     *        sense) as often as needed by the Node set.
     *      - Exports type ElementInformation, that elementspecific data, like orientation or
     * direction of vertices. Should implement a method isDirichlet(LocalKey) that returns a boolean
     * if the localKey is intendet to be used for Dirichlet Interpolation
     *      + Possible extensions:
     *      - "transposed-Inverse" application for applying the transformation
     *        on reference interpolation coefficients. This is an alternative to the
     *        "derivative-hook" approach.
     *      - Congruence transformation: Instead of assembling the correct function/derivative
     *        values, one can assemble the Elementmatrix of the pullbacks of the reference basis,
     *        and afterwards apply a congruence transformation the get the correct Elementmatrix.
     *    LinearTransformedLocalBasis:
     *      - holds an instance of the Transformator class
     *      - calls transformator.bind() whenever bound to an element
     *      - higher derivatives are implemented
     *
     *    LinearTransformedLocalInterpolation:
     *      - same as GlobalValuedInterpolation, or provided by Transformator class as exported type
     * GlobalInterpolation, alongside a exported bool globalInterpolation to indicate this. TODO
     * switch completely to this!
     *
     *    LinearTransformedLocalCoefficients:
     *      - wraps the LocalCoefficients of the localvalued finite element
     *      - can be bound to ElementInformation
     *      - provides an additional method isDirichlet(size_t i) that returns boolean indicating
     * whether the ith local dof is to be used in Dirichlet Interpolation
     *
     *    LinearTransformedLocalFiniteElement:
     *      - very similar  GlobalValuedFiniteElement with adapted typedefs and additional
     *       binding operations
     *
     */
    /** \brief Example of LinearTransformation Interface
     *  \tparam F Field type
     *  \tparam size number of basisfunctions
     *  TODO add ElementInformation, GlobalInterpolation
     */
    template <class F, unsigned int size>
    struct IdentityTransformation
    {
      IdentityTransformation() : m_(1) {}

      template <class LocalBasis, class Element>
      void bind(LocalBasis const &lB, Element e)
      {
        // Adapt values
      }

      template <typename Values, typename LocalCoordinate, typename Geometry>
      void apply(Values &values, const LocalCoordinate &xi, const Geometry &geometry)
      {
        Values tmp = values;
        m_.mv(tmp, values);
      }

      template <class Element>
      class ElementInformation
      {
      };

      template <class Function, class LocalCoordinate, class Element>
      class LocalValuedFunction
      {

        using ElementInfo = ElementInformation<Element>;
        const Function &f_;
        const Element &element_;
        const ElementInfo &elementInfo_;

      public:
        LocalValuedFunction(const Function &f, const Element &e, const ElementInfo &elementInfo)
            : f_(f), element_(e), elementInfo_(elementInfo)
        {
        }

        auto operator()(const LocalCoordinate &xi) const
        {
          auto &&f = Dune::Impl::makeFunctionWithCallOperator<LocalCoordinate>(f_);
          return f(xi); // no transformation for functionvalues needed
        }

        friend auto derivative(LocalValuedFunction const &t)
        {
          return derivative(t.f_);
        }
      };

      ScaledIdentityMatrix<F, size> m_;
    };

    /** \brief Implementation of a dune-localfunctions LocalBasis that applies a transformation
     *
     * \tparam Transformator The transformation that is to be applied
     * \tparam LocalValuedLocalBasis The local-valued LocalBasis that is getting transformed
     * \tparam Element The element that the global-valued FE lives on
     */
    template <class LinearTransformator, class LocalValuedLocalBasis, class Element>
    class LinearTransformedLocalBasis
    {
      using ElementInformation = typename LinearTransformator::template ElementInformation<Element>;

    public:
      using Traits = typename LocalValuedLocalBasis::Traits;

      // LinearTransformedLocalBasis() : elementInformation_(), transformator_() {}
      /** \brief Bind the local basis to a particular grid element
       */
      void bind(const LocalValuedLocalBasis &localValuedLocalBasis, const Element &element,
                const ElementInformation &elementInfo)
      {
        localValuedLocalBasis_ = &localValuedLocalBasis;
        element_ = &element;
        elementInformation_ = &elementInfo;
        transformator_.bind(element, *elementInformation_);
      }

      /** \brief Number of shape functions
       */
      auto size() const
      {
        return localValuedLocalBasis_->size();
      }

      //! \brief Evaluate all shape functions
      void evaluateFunction(const typename Traits::DomainType &x,
                            std::vector<typename Traits::RangeType> &out) const
      {
        localValuedLocalBasis_->evaluateFunction(x, out);

        transformator_.apply(out, x, element_->geometry());
      }

      /** \brief Evaluate Jacobian of all shape functions
       *
       * \param x Point in the reference element where to evaluation the Jacobians
       * \param[out] out The Jacobians of all shape functions at the point x
       */
      void evaluateJacobian(const typename Traits::DomainType &x,
                            std::vector<typename Traits::JacobianType> &out) const
      {
        localValuedLocalBasis_->evaluateJacobian(x, out);

        transformator_.apply(out, x, element_->geometry());
      }

      /** \brief Evaluate partial derivatives of any order of all shape functions
       *
       * \param order Order of the partial derivatives, in the classic multi-index notation
       * \param in Position where to evaluate the derivatives
       * \param[out] out The desired partial derivatives
       */
      void partial(const std::array<unsigned int, Traits::dimDomain> &order,
                   const typename Traits::DomainType &x,
                   std::vector<typename Traits::RangeType> &out) const
      {
        localValuedLocalBasis_->partial(order, x, out);
        transformator_.apply(out, x, element_->geometry());
      }

      // TODO sfinae protected hessian method

      //! \brief Polynomial order of the shape functions
      auto order() const
      {
        return localValuedLocalBasis_->order();
      }

      LinearTransformator const &transformator() { return transformator_; }

    private:
      const LocalValuedLocalBasis *localValuedLocalBasis_;
      const Element *element_;
      const ElementInformation *elementInformation_;
      LinearTransformator transformator_;
    };

    /** \brief Implementation of a dune-localfunctions LocalInterpolation
     *    that accepts global-valued functions
     *
     * \tparam Transformator The linear transformation that transforms from local to global
     * values \tparam LocalValuedLocalInterpolation The local-valued LocalInterpolation that is used
     * for the actual interpolation \tparam Element The element that the global-valued FE lives on
     */
    template <class LinearTransformator, class LocalValuedLocalInterpolation, class Element>
    class LocalValuedLinearTransformedLocalInterpolation
    {
      using ElementInformation = typename LinearTransformator::template ElementInformation<Element>;

    public:
      /** \brief Bind the local interpolation object to a particular grid element
       */
      void bind(const LocalValuedLocalInterpolation &localValuedLocalInterpolation,
                Element const &element, const ElementInformation &elementInfo)
      {
        localValuedLocalInterpolation_ = &localValuedLocalInterpolation;
        element_ = &element;
        elementInformation_ = &elementInfo;
      }

      template <typename F, typename C>
      void interpolate(const F &f, std::vector<C> &out) const
      {
        using LocalCoordinate = typename Element::Geometry::LocalCoordinate;
        typename LinearTransformator::template LocalValuedFunction<F, LocalCoordinate, Element>
            localValuedFunction(f, *element_, *elementInformation_);
        localValuedLocalInterpolation_->interpolate(localValuedFunction, out);
      }

    private:
      const LocalValuedLocalInterpolation *localValuedLocalInterpolation_;
      const Element *element_;

      const ElementInformation *elementInformation_;
    };

    template <class LinearTransformator, class LocalValuedLFE, class Element, class Enable = void>
    struct LinearTransformedInterpolation
    {
    };

    template <class LinearTransformator, class LocalValuedLFE, class Element>
    struct LinearTransformedInterpolation<
        LinearTransformator, LocalValuedLFE, Element,
        typename std::enable_if<LinearTransformator::globalInterpolation>::type>
    {
      using type = typename LinearTransformator::template GlobalInterpolation<
          typename LocalValuedLFE::Traits::LocalBasisType, Element>;
    };

    template <class LinearTransformator, class LocalValuedLFE, class Element>
    struct LinearTransformedInterpolation<
        LinearTransformator, LocalValuedLFE, Element,
        typename std::enable_if<not LinearTransformator::globalInterpolation>::type>
    {
      using type = LocalValuedLinearTransformedLocalInterpolation<
          LinearTransformator, typename LocalValuedLFE::Traits::LocalInterpolationType, Element>;
    };

    template <class LocalCoefficients, class ElementInformation>
    class LinearTransformedLocalCoefficients: public LocalCoefficients
    {

    public:
      LinearTransformedLocalCoefficients() : LocalCoefficients(), elementInfo_(nullptr) {}
      // TODO maybe variadic forward constructor
      void bind(ElementInformation const &elementInfo) { elementInfo_ = &elementInfo; }

      bool isDirichlet(std::size_t i) const
      {
        return isDirichletImpl(*elementInfo_, i, PriorityTag<42>());
      }

      bool isClamped(std::size_t i) const
      {
        return isClampedImpl(*elementInfo_, i, PriorityTag<42>());
      }

      ElementInformation const &getElementInformation() const { return *elementInfo_; }

    private:
      bool isDirichletImpl(ElementInformation const &elInfo, std::size_t i,
                           PriorityTag<0> tag) const
      {
        return true;
      }

      template <class ElInfo>
      bool isDirichletImpl(ElInfo const &elInfo, std::size_t i, PriorityTag<1> tag,
                           decltype((std::declval<ElementInformation>().isDirichlet(
                                         std::declval<LocalCoefficients>().localKey(0)),
                                     true))
                           = true) const
      {
        return elInfo.isDirichlet(LocalCoefficients::localKey(i));
      }

      bool isClampedImpl(ElementInformation const &e, std::size_t i, PriorityTag<0> tag) const
      {
        return true;
      }
      // template ElInfo to enable sfinae
      template <class ElInfo, decltype((std::declval<ElInfo>().isClamped(
                                            std::declval<LocalCoefficients>().localKey(0)),
                                        true))
                              = true>
      bool isClampedImpl(ElInfo const &elInfo, std::size_t i, PriorityTag<1> tag) const
      {
        return elInfo.isClamped(LocalCoefficients::localKey(i));
      }

      ElementInformation const *elementInfo_;
    };

    /** \brief LocalFiniteElement implementation that uses values defined wrt particular grid
     * elements
     *
     * \tparam Transformator Class implementing linear transformations
     *  \tparam LocalValuedLFE LocalFiniteElement implementation whose values are to be
     * transformed \tparam Element Element where to transform the FE values to
     */
    template <class LinearTransformator, class LocalValuedLFE, class Element>
    class LinearTransformedLocalFiniteElement
    {
      using LocalBasis
          = LinearTransformedLocalBasis<LinearTransformator,
                                        typename LocalValuedLFE::Traits::LocalBasisType, Element>;
      using LocalInterpolation =
          typename LinearTransformedInterpolation<LinearTransformator, LocalValuedLFE,
                                                  Element>::type;
      using ElementInformation = typename LinearTransformator::template ElementInformation<Element>;
      using LocalCoefficients = LinearTransformedLocalCoefficients<
          typename LocalValuedLFE::Traits::LocalCoefficientsType, ElementInformation>;

    public:
      /** \brief Export number types, dimensions, etc.
       */
      using Traits = LocalFiniteElementTraits<LocalBasis, LocalCoefficients, LocalInterpolation>;

      LinearTransformedLocalFiniteElement() {}

      void bind(const LocalValuedLFE &localValuedLFE, const Element &element,
                const ElementInformation &elementInfo)
      {
        globalValuedLocalBasis_.bind(localValuedLFE.localBasis(), element, elementInfo);
        globalValuedLocalInterpolation_.bind(localValuedLFE.localInterpolation(), element,
                                             elementInfo);
        globalValuedLocalCoefficients_.bind(elementInfo);
        localValuedLFE_ = &localValuedLFE;
      }

      /** \brief Returns the local basis, i.e., the set of shape functions
       */
      const typename Traits::LocalBasisType &localBasis() const
      {
        return globalValuedLocalBasis_;
      }

      /** \brief Returns the assignment of the degrees of freedom to the element subentities
       */
      const typename Traits::LocalCoefficientsType &localCoefficients() const
      {
        return globalValuedLocalCoefficients_;
      }

      /** \brief Returns object that evaluates degrees of freedom
       */
      const typename Traits::LocalInterpolationType &localInterpolation() const
      {
        return globalValuedLocalInterpolation_;
      }

      /** \brief The number of shape functions */
      std::size_t size() const
      {
        return localValuedLFE_->size();
      }

      /** \brief The reference element that the local finite element is defined on
       */
      GeometryType type() const
      {
        return localValuedLFE_->type();
      }

    private:
      typename Traits::LocalBasisType globalValuedLocalBasis_;
      typename Traits::LocalInterpolationType globalValuedLocalInterpolation_;
      typename Traits::LocalCoefficientsType globalValuedLocalCoefficients_;
      const LocalValuedLFE *localValuedLFE_;
    };
  } // namespace Functions::Impl
} // namespace Dune
#endif