Newer
Older
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_GFE_FUNCTIONS_EMBEDDEDGLOBALGFEFUNCTION_HH
#define DUNE_GFE_FUNCTIONS_EMBEDDEDGLOBALGFEFUNCTION_HH
#include <memory>
#include <optional>
#include <dune/common/typetraits.hh>
#include <dune/common/version.hh>
#include <dune/grid/utility/hierarchicsearch.hh>
#include <dune/functions/gridfunctions/gridviewentityset.hh>
#include <dune/functions/gridfunctions/gridfunction.hh>
#include <dune/functions/backends/concepts.hh>
#include <dune/gfe/functions/globalgfefunction.hh>
template<typename EGGF>
class EmbeddedGlobalGFEFunctionDerivative;
/**
* \brief A geometric finite element function with an embedding into Euclidean space
*
* The `GlobalGFEFunction` implements a geometric finite element function.
* The values of that function implement the `TargetSpace` model.
* In contrast, the values of the `EmbeddedGlobalGFEFunction` implemented here
* are the corresponding values in Euclidean space. The precise type is
* `TargetSpace::CoordinateType`, which is typically a vector or matrix type.
*
* \tparam B Type of global scalar(!) basis
* \tparam LIR Local interpolation rule for manifold-valued data
* \tparam TargetSpace Range type of this function
*/
template<typename B, typename LIR, typename TargetSpace>
class EmbeddedGlobalGFEFunction
// There is no separate base class for EmbeddedGlobalGFEFunction, because the base class
// only handles coefficients and indices. It is independent of the type of function values.
#if DUNE_VERSION_LTE(DUNE_FUFEM, 2, 9)
: public Impl::GlobalGFEFunctionBase<B, std::vector<TargetSpace>, LIR, typename TargetSpace::CoordinateType>
: public Impl::GlobalGFEFunctionBase<B, std::vector<TargetSpace>, LIR>
#if DUNE_VERSION_LTE(DUNE_FUFEM, 2, 9)
using Base = Impl::GlobalGFEFunctionBase<B, std::vector<TargetSpace>, LIR, typename TargetSpace::CoordinateType>;
using Base = Impl::GlobalGFEFunctionBase<B, std::vector<TargetSpace>, LIR>;
using Data = typename Base::Data;
public:
using Basis = typename Base::Basis;
using Vector = typename Base::Vector;
#if DUNE_VERSION_LTE(DUNE_FUFEM, 2, 9)
using Data = typename Impl::Data<Basis,Vector>;
using LocalInterpolationRule = LIR;
using Domain = typename Base::Domain;
using Range = typename TargetSpace::CoordinateType;
using Traits = Functions::Imp::GridFunctionTraits<Range (Domain), typename Base::EntitySet, Functions::DefaultDerivativeTraits, 16>;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
class LocalFunction
: public Base::LocalFunctionBase
{
using LocalBase = typename Base::LocalFunctionBase;
using size_type = typename Base::Tree::size_type;
public:
using GlobalFunction = EmbeddedGlobalGFEFunction;
using Domain = typename LocalBase::Domain;
using Range = GlobalFunction::Range;
using Element = typename LocalBase::Element;
//! Create a local-function from the associated grid-function
LocalFunction(const EmbeddedGlobalGFEFunction& globalFunction)
: LocalBase(globalFunction.data_)
{
/* Nothing. */
}
/**
* \brief Evaluate this local-function in coordinates `x` in the bound element.
*
* The result of this method is undefined if you did
* not call bind() beforehand or changed the coefficient
* vector after the last call to bind(). In the latter case
* you have to call bind() again in order to make operator()
* usable.
*/
Range operator()(const Domain& x) const
{
return this->localInterpolationRule_->evaluate(x).globalCoordinates();
}
//! Local function of the derivative
friend typename EmbeddedGlobalGFEFunctionDerivative<EmbeddedGlobalGFEFunction>::LocalFunction derivative(const LocalFunction& lf)
{
auto dlf = localFunction(EmbeddedGlobalGFEFunctionDerivative<EmbeddedGlobalGFEFunction>(lf.data_));
if (lf.bound())
dlf.bind(lf.localContext());
return dlf;
}
};
//! Create a grid-function, by wrapping the arguments in `std::shared_ptr`.
template<class B_T, class V_T>
EmbeddedGlobalGFEFunction(B_T && basis, V_T && coefficients)
: Base(std::make_shared<Data>(Data{{basis.gridView()}, wrap_or_move(std::forward<B_T>(basis)), wrap_or_move(std::forward<V_T>(coefficients))}))
{}
//! Create a grid-function, by moving the arguments in `std::shared_ptr`.
EmbeddedGlobalGFEFunction(std::shared_ptr<const Basis> basis, std::shared_ptr<const Vector> coefficients)
: Base(std::make_shared<Data>(Data{{basis->gridView()}, basis, coefficients}))
{}
/** \brief Evaluate at a point given in world coordinates
*
* \warning This has to find the element that the evaluation point is in.
* It is therefore very slow.
*/
Range operator() (const Domain& x) const
{
HierarchicSearch search(this->data_->basis->gridView().grid(), this->data_->basis->gridView().indexSet());
const auto e = search.findEntity(x);
auto localThis = localFunction(*this);
localThis.bind(e);
return localThis(e.geometry().local(x));
}
//! Derivative of the `EmbeddedGlobalGFEFunction`
friend EmbeddedGlobalGFEFunctionDerivative<EmbeddedGlobalGFEFunction> derivative(const EmbeddedGlobalGFEFunction& f)
return EmbeddedGlobalGFEFunctionDerivative<EmbeddedGlobalGFEFunction>(f.data_);
}
* \brief Construct local function from a EmbeddedGlobalGFEFunction.
* The obtained local function satisfies the concept
* `Dune::Functions::Concept::LocalFunction`. It must be bound
* to an entity from the entity set of the EmbeddedGlobalGFEFunction
* before it can be used.
friend LocalFunction localFunction(const EmbeddedGlobalGFEFunction& t)
{
return LocalFunction(t);
}
#if DUNE_VERSION_LTE(DUNE_FUFEM, 2, 9)
using Element = typename Basis::GridView::template Codim<0>::Entity;
/** \brief Evaluate the function at local coordinates. */
void evaluateLocal(const Element& element, const Domain& local, typename TargetSpace::CoordinateType& out) const override
out = this->operator()(element,local);
/** \brief Evaluate the function at local coordinates. */
typename TargetSpace::CoordinateType operator()(const Element& element, const Domain& local) const
{
auto localView = this->basis().localView();
localView.bind(element);
auto numOfBaseFct = localView.size();
// Extract local coefficients
std::vector<TargetSpace> localCoeff(numOfBaseFct);
for (size_t i=0; i<numOfBaseFct; i++)
localCoeff[i] = this->dofs()[localView.index(i)];
// create local gfe function
LocalInterpolationRule localInterpolationRule(localView.tree().finiteElement(),localCoeff);
return localInterpolationRule.evaluate(local).globalCoordinates();
}
/** \brief evaluation of derivative in local coordinates
*
* \param e Evaluate in local coordinates with respect to this element.
* \param x point in local coordinates at which to evaluate the derivative
* \param d will contain the derivative at x after return
*/
void evaluateDerivativeLocal(const Element& element, const Domain& local,
typename Functions::SignatureTraits<typename EmbeddedGlobalGFEFunction::Traits::DerivativeInterface>::Range& out) const override
{
auto localView = this->basis().localView();
localView.bind(element);
auto numOfBaseFct = localView.size();
// Extract local coefficients
std::vector<TargetSpace> localCoeff(numOfBaseFct);
for (decltype(numOfBaseFct) i=0; i<numOfBaseFct; i++)
localCoeff[i] = this->dofs()[localView.index(i)];
// create local gfe function
LocalInterpolationRule localInterpolationRule(localView.tree().finiteElement(),localCoeff);
// use it to evaluate the derivative
auto refJac = localInterpolationRule.evaluateDerivative(local);
//transform the gradient
const auto jacInvTrans = element.geometry().jacobianInverseTransposed(local);
for (size_t k=0; k< refJac.N(); k++)
jacInvTrans.umv(refJac[k],out[k]);
}
#endif
};
/**
* \brief Derivative of a `EmbeddedGlobalGFEFunction`
*
* Function returning the derivative of the given `EmbeddedGlobalGFEFunction`
* with respect to global coordinates.
* \tparam EGGF instance of the `EmbeddedGlobalGFEFunction` this is a derivative of
template<typename EGGF>
class EmbeddedGlobalGFEFunctionDerivative
// There is no separate base class for EmbeddedGlobalGFEFunction, because the base class
// only handles coefficients and indices. It is independent of the type of function values.
#if DUNE_VERSION_LTE(DUNE_FUFEM, 2, 9)
: public Impl::GlobalGFEFunctionBase<typename EGGF::Basis, typename EGGF::Vector, typename EGGF::LocalInterpolationRule,
Dune::FieldMatrix<double, EGGF::Vector::value_type::EmbeddedTangentVector::dimension, EGGF::Basis::GridView::dimensionworld> >
: public Impl::GlobalGFEFunctionBase<typename EGGF::Basis, typename EGGF::Vector, typename EGGF::LocalInterpolationRule>
#if DUNE_VERSION_LTE(DUNE_FUFEM, 2, 9)
using Base = Impl::GlobalGFEFunctionBase<typename EGGF::Basis, typename EGGF::Vector, typename EGGF::LocalInterpolationRule,
Dune::FieldMatrix<double, EGGF::Vector::value_type::EmbeddedTangentVector::dimension, EGGF::Basis::GridView::dimensionworld> >;
using Base = Impl::GlobalGFEFunctionBase<typename EGGF::Basis, typename EGGF::Vector, typename EGGF::LocalInterpolationRule>;
using Data = typename Base::Data;
public:
using EmbeddedGlobalGFEFunction = EGGF;
using Basis = typename Base::Basis;
using Vector = typename Base::Vector;
#if DUNE_VERSION_LTE(DUNE_FUFEM, 2, 9)
using Data = typename Impl::Data<Basis,Vector>;
using Domain = typename Base::Domain;
using Range = typename Functions::SignatureTraits<typename EmbeddedGlobalGFEFunction::Traits::DerivativeInterface>::Range;
using Traits = Functions::Imp::GridFunctionTraits<Range (Domain), typename Base::EntitySet, Functions::DefaultDerivativeTraits, 16>;
* \brief local function evaluating the derivative in reference coordinates
* Note that the function returns the derivative with respect to global
* coordinates even when the point is given in reference coordinates on
* an element.
class LocalFunction
: public Base::LocalFunctionBase
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
using LocalBase = typename Base::LocalFunctionBase;
using size_type = typename Base::Tree::size_type;
public:
using GlobalFunction = EmbeddedGlobalGFEFunctionDerivative;
using Domain = typename LocalBase::Domain;
using Range = GlobalFunction::Range;
using Element = typename LocalBase::Element;
//! Create a local function from the associated grid function
LocalFunction(const GlobalFunction& globalFunction)
: LocalBase(globalFunction.data_)
{
/* Nothing. */
}
/**
* \brief Bind LocalFunction to grid element.
*
* You must call this method before `operator()`
* and after changes to the coefficient vector.
*/
void bind(const Element& element)
{
LocalBase::bind(element);
geometry_.emplace(element.geometry());
}
//! Unbind the local-function.
void unbind()
{
geometry_.reset();
LocalBase::unbind();
}
/**
* \brief Evaluate this local-function in coordinates `x` in the bound element.
*
* The result of this method is undefined if you did
* not call bind() beforehand or changed the coefficient
* vector after the last call to bind(). In the latter case
* you have to call bind() again in order to make operator()
* usable.
*
* Note that the function returns the derivative with respect to global
* coordinates even though the evaluation point is given in reference coordinates
* on the current element.
*/
Range operator()(const Domain& x) const
{
// Jacobian with respect to local coordinates
auto refJac = this->localInterpolationRule_->evaluateDerivative(x);
// Transform to world coordinates
return refJac * geometry_->jacobianInverse(x);
}
//! Not implemented
friend typename Traits::LocalFunctionTraits::DerivativeInterface derivative(const LocalFunction&)
{
DUNE_THROW(NotImplemented, "derivative of derivative is not implemented");
}
private:
std::optional<typename Element::Geometry> geometry_;
};
* \brief create object from `EmbeddedGlobalGFEFunction` data
* Please call `derivative(embeddedGlobalGFEFunction)` to create an instance
* of this class.
*/
EmbeddedGlobalGFEFunctionDerivative(const std::shared_ptr<const Data>& data)
: Base(data)
{
/* Nothing. */
}
/** \brief Evaluate the discrete grid-function derivative in global coordinates
* \warning This has to find the element that the evaluation point is in.
* It is therefore very slow.
*/
Range operator()(const Domain& x) const
HierarchicSearch search(this->data_->basis->gridView().grid(), this->data_->basis->gridView().indexSet());
const auto e = search.findEntity(x);
auto localThis = localFunction(*this);
localThis.bind(e);
return localThis(e.geometry().local(x));
friend typename Traits::DerivativeInterface derivative(const EmbeddedGlobalGFEFunctionDerivative& f)
DUNE_THROW(NotImplemented, "derivative of derivative is not implemented");
//! Construct local function from a `EmbeddedGlobalGFEFunctionDerivative`
friend LocalFunction localFunction(const EmbeddedGlobalGFEFunctionDerivative& f)
{
return LocalFunction(f);
}
#if DUNE_VERSION_LTE(DUNE_FUFEM, 2, 9)
using Element = typename Basis::GridView::template Codim<0>::Entity;
/** \brief Evaluate the function at local coordinates. */
void evaluateLocal(const Element& element, const Domain& local, Range& out) const override
{
// This method will never be called.
}
} // namespace Dune::GFE
#endif // DUNE_GFE_FUNCTIONS_EMBEDDEDGLOBALGFEFUNCTION_HH