#pragma once #include #include #include #include #include #include #include #include namespace AMDiS { #ifndef DOXYGEN template class AnalyticLocalFunction; #endif template class AnalyticLocalFunction { public: /// The LocalDomain this LocalFunction can be evaluated in using Domain = D; /// The range type of the LocalFunction using Range = R; /// This LocalFunction has its own \ref derivativeOf() function enum { hasDerivative = true }; private: using Geometry = typename LC::Geometry; public: /// \brief Constructor. stores the function `fct`. AnalyticLocalFunction(Function const& fct) : fct_{fct} {} /// \brief Create a geometry object from the element void bind(LC const& element) { geometry_.emplace(element.geometry()); } /// \brief Releases the geometry object void unbind() { geometry_.reset(); } /// \brief Evaluate the function in global coordinate by a local-to-global /// mapping of the local coordinates using the bound geometry object. Range operator()(Domain const& local) const { assert( bool(geometry_) ); return fct_(geometry_.value().global(local)); } Function const& fct() const { return fct_; } private: Function fct_; std::optional geometry_; }; /// \fn order /// \brief Return the polynomial order of the LocalFunction. /** * \relates AnalyticLocalFunction * The order is defined as the polynomial order of the functor `fct` and * requires a free function `order(fct,1)` to exists. * * **Requirements:** * - The functor `F` must fulfill the concept \ref Concepts::HasFunctorOrder **/ template )> int order(AnalyticLocalFunction const& lf) { return order(lf.fct(),1); } /// \fn derivative /// \brief Create an \ref AnalyticLocalFunction representing the derivative /// of the given AnalyticLocalFunction. /** * In order to differentiate the local function, the functor must be * differentiable, i.e. a free function `partial(fct,_0)` must exist. * * **Requirements:** * - The functor `F` must fulfill the concept \ref Concepts::HasDerivative **/ template auto derivativeOf(AnalyticLocalFunction const& lf, Type const& type) { static_assert(Concepts::HasDerivative, "No derivative(F,DerivativeType) defined for Functor F of AnalyticLocalFunction."); auto df = derivativeOf(lf.fct(), type); using RawSignature = typename Dune::Functions::SignatureTraits::RawSignature; using DerivativeSignature = typename DerivativeTraits::Range(D); return AnalyticLocalFunction{df}; } /// \class AnalyticGridFunction /// \brief A Gridfunction that evaluates a function with global coordinates. /** * \ingroup GridFunctions * Implements a GridFunction that wraps a functor around global coordinates. * * \tparam Function The callable `f=f(x)` with `x in Domain == GlobalCoordinates` * \tparam GridView A GridView that models `Dune::GridViewConcept`. * * **Requirements:** * - Function models \ref Concepts::Callable **/ template class AnalyticGridFunction { public: using EntitySet = Dune::Functions::GridViewEntitySet; using Domain = typename EntitySet::GlobalCoordinate; using Range = remove_cvref_t>; enum { hasDerivative = true }; private: using Element = typename EntitySet::Element; using LocalDomain = typename EntitySet::LocalCoordinate; using LocalFunction = AnalyticLocalFunction; public: /// Constructor. Stores the function `fct` and creates an `EntitySet`. AnalyticGridFunction(Function const& fct, GridView const& gridView) : fct_{fct} , entitySet_{gridView} {} /// Return the evaluated functor at global coordinates Range operator()(Domain const& x) const { return fct_(x); } /// Return the \ref AnalyticLocalFunction of the AnalyticGridFunction. LocalFunction makeLocalFunction() const { return {fct_}; } /// Returns \ref entitySet_ EntitySet const& entitySet() const { return entitySet_; } /// Returns \ref fct_ Function const& fct() const { return fct_; } private: Function fct_; EntitySet entitySet_; }; namespace Concepts { namespace Definition { template constexpr bool CallableDow = Concepts::Callable>; } /// \brief Functor F is collable with GlobalCoordinates `F(Dune::FieldVector)` #ifndef WORLDDIM template constexpr bool CallableDomain = Definition::CallableDow || Definition::CallableDow || Definition::CallableDow; #else template constexpr bool CallableDomain = Definition::CallableDow; #endif template using CallableDomain_t = bool_t>; } // end namespace Concepts // Creator for the AnalyticGridFunction template struct GridFunctionCreator>> { template static auto create(Function const& fct, GridView const& gridView) { return AnalyticGridFunction{fct, gridView}; } }; /// \fn derivative /// \brief Return a GridFunction representing the derivative of a functor. /** * \relates AnalyticGridfunction * * **Requirements:** * - Functor `F` must fulfill the concept \ref Concepts::HasDerivative **/ template auto derivativeOf(AnalyticGridFunction const& gf, Type const& type) { static_assert(Concepts::HasDerivative, "No derivative(F,DerivativeType) defined for Functor of AnalyticLocalFunction."); auto df = derivativeOf(gf.fct(), type); return AnalyticGridFunction{df, gf.entitySet().gridView()}; } #ifndef DOXYGEN // A pre-GridFunction that just stores the function template struct AnalyticPreGridFunction { using Self = AnalyticPreGridFunction; struct Creator { template static auto create(Self const& self, GridView const& gridView) { return AnalyticGridFunction{self.fct_, gridView}; } }; Function fct_; }; namespace Traits { template struct IsPreGridFunction> : std::true_type {}; } #endif /// \fn evalAtQP /// \brief Generator function for AnalyticGridFunction. /** * \relates AnalyticGridfunction * \ingroup GridFunctions * Evaluate a functor at global coordinates. See \ref AnalyticGridFunction. * * **Examples:** * - `evalAtQP([](Dune::FieldVector const& x) { return x[0]; })` * - `evalAtQP(Operation::TwoNorm{})` **/ template )> auto evalAtQP(Function const& f) { return AnalyticPreGridFunction{f}; } } // end namespace AMDiS