-
Porrmann, Maik authoredPorrmann, Maik authored
lineartransformedlocalfiniteelement.hh 18.67 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 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 linear
* 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;
/** \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_;
};
// SFINAE structure to enable two approaches for interpolation
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>;
};
/**
* @brief Class representing Linear transformed coefficients. This class mainly forwards the
* LocalCoefficient class of the reference finite element. Technically this is wrong! A linear
* transformation might change the Location of a degree of freedom! This class extends the
* LocalCoefficient interface by providing a binding methods, such that it can access the
* ElementInformation object, and provides methods to determine whether the ith degree of
* freedom is to be used when strongly incorporation Dirichlet or Clamped boundary conditions.
* This information is obtained from the ElementInformation object.
* @tparam LocalCoefficients
* @tparam ElementInformation
*/
template <class LocalCoefficients, class ElementInformation>
class LinearTransformedLocalCoefficients: public LocalCoefficients
{
public:
// TODO maybe variadic forward constructor
LinearTransformedLocalCoefficients() : LocalCoefficients(), elementInfo_(nullptr) {}
void bind(ElementInformation const &elementInfo) { elementInfo_ = &elementInfo; }
/**
* @brief Wheter or not to use the ith dof when strongly incorporating Dirichlet Conditions.
* If the ElementInformation class does not implement a corresponding methods, this method
* will always return true. Also note that this methods will wrongly return true on inner
* dofs, too.
*
* @param i
* @return true
* @return false
*/
bool isDirichlet(std::size_t i) const
{
return isDirichletImpl(*elementInfo_, i, PriorityTag<42>());
}
/**
* @brief Wheter or not to use the ith dof when strongly incorporating Clamped Conditions. If
* the ElementInformation class does not implement a corresponding methods, this method will
* always return true. Also note that this methods will wrongly return true on inner dofs,
* too.
*
* @param i
* @return true
* @return false
*/
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 onto which the FE is transformed
*/
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() {}
/**
* @brief Binding routine. This binds all other objects of the LocalFiniteElement interface,
* as well as the Transformator.
*
* @param localValuedLFE
* @param element
* @param elementInfo
*/
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