#pragma once #include #include #include #include #include #include namespace AMDiS { namespace Impl { template struct CheckFunctorConcept { static_assert(Concepts::Functor, "Derivative of LocalFunction can not be called as a functor."); }; template struct CheckValidRange { static_assert(!std::is_same_v, "Invalid Range."); }; } /// \class DerivativeGridFunction /// \brief A Gridfunction that returns the derivative when calling localFunction. /** * \ingroup GridFunctions * Wraps the GridFunction so that \ref localFunction returns a LocalFunction * representing the derivative of the LocalFunction of the GridFunction. * * \tparam GridFunction The GridFunction that is wrapped. * \tparam The type of derivative, i.e. one of tag::gradient, tag::partial{i}, or tag::divergence * * **Requirements:** * - `GridFunction` models \ref Concepts::GridFunction and the LocalFunction * has a derivative. **/ template class DerivativeGridFunction { using GridFctRange = typename GridFunction::Range; using GridFctDomain = typename GridFunction::Domain; using RawSignature = typename Dune::Functions::SignatureTraits::RawSignature; using Traits = DerivativeTraits; using LocalFunction = TYPEOF( derivativeOf(localFunction(std::declval()), std::declval()) ) ; using LocalFctRange = typename Traits::Range; using LocalFctDomain = typename GridFunction::EntitySet::LocalCoordinate; CHECK_CONCEPT(Impl::CheckValidRange); CHECK_CONCEPT(Impl::CheckFunctorConcept); enum { hasDerivative = false }; public: /// The Range of the derivative of the GridFunction using Range = typename Traits::Range; /// The domain of the GridFunction using Domain = GridFctDomain; /// The EntitySet of the GridFunction using EntitySet = typename GridFunction::EntitySet; public: /// Constructor. Stores a copy of gridFct. explicit DerivativeGridFunction(GridFunction const& gridFct, Type const& type) : gridFct_{gridFct} , type_{type} {} /// Evaluate derivative in global coordinates. NOTE: expensive Range operator()(Domain const& x) const { auto gv = entitySet().gridView(); using GridView = decltype(gv); using Grid = typename GridView::Grid; using IS = typename GridView::IndexSet; Dune::HierarchicSearch hsearch{gv.grid(), gv.indexSet()}; auto element = hsearch.findEntity(x); auto geometry = element.geometry(); auto localFct = makeLocalFunction(); localFct.bind(element); return localFct(geometry.local(x)); } /// Return the derivative-localFunction of the GridFunction. LocalFunction makeLocalFunction() const { return derivativeOf(localFunction(gridFct_), type_); } /// Return the \ref EntitySet of the \ref GridFunction. EntitySet const& entitySet() const { return gridFct_.entitySet(); } private: GridFunction gridFct_; Type type_; }; /// \fn derivativeOf /// \brief Create a GridFunction representing the derivative of the given /// Gridfunction. /** * A GridFunction can be differentiated if the corresponding LocalFunction * provides a free function `derivativeOf()` * * **Requirements:** * - The type `GridFct` models the concept of a GridFunction * - The `GridFct` has no own `derivativeOf()` function, i.e. it holds * `GridFct::hasDerivative == false`. * - The localFunction of the `GridFct` models `Concepts::HasDerivative`. **/ template ()) ), REQUIRES(not GridFct::hasDerivative)> auto derivativeOf(GridFct const& gridFct, Type const& type) { static_assert(Concepts::HasDerivative, "derivativeOf(LocalFunction,type) not defined!"); return DerivativeGridFunction{gridFct, type}; } #ifndef DOXYGEN template struct DerivativePreGridFunction { using Self = DerivativePreGridFunction; struct Creator { template static auto create(Self const& self, GridView const& gridView) { return derivativeOf(makeGridFunction(self.expr_, gridView), self.type_); } }; Expr expr_; Type type_ = {}; }; namespace Traits { template struct IsPreGridFunction> : std::true_type {}; } #endif /// \fn gradientOf /// \brief Generator function for DerivativeGridFunction expressions. /// \relates DerivativeGridFunction /** * \ingroup GridFunctions * Generates a Gridfunction representing the gradient of a GridFunction. * See \ref DerivativeGridFunction. * * **Examples:** * - `gradientOf(prob.solution(_0))` * - `gradientOf(X(0) + X(1) + prob.solution(_0))` **/ template auto gradientOf(Expr const& expr) { return DerivativePreGridFunction{expr}; } /// Generates a Gridfunction representing the divergence of a vector-valued GridFunction. template auto divergenceOf(Expr const& expr) { return DerivativePreGridFunction{expr}; } /// Generates a Gridfunction representing the partial derivative of a GridFunction. template auto partialDerivativeOf(Expr const& expr, std::size_t i) { return DerivativePreGridFunction{expr, tag::partial{i}}; } /** @} **/ } // end namespace AMDiS