FunctorGridFunction.hpp 8.91 KB
Newer Older
Praetorius, Simon's avatar
Praetorius, Simon committed
1
2
3
4
5
#pragma once

#include <tuple>
#include <type_traits>

6
7
#include <dune/common/std/apply.hh>

8
#include <amdis/Operations.hpp>
9
10
#include <amdis/common/ForEach.hpp>
#include <amdis/common/Logical.hpp>
11
12
13
#include <amdis/gridfunctions/Derivative.hpp>
#include <amdis/gridfunctions/GridFunction.hpp>
#include <amdis/gridfunctions/Order.hpp>
Praetorius, Simon's avatar
Praetorius, Simon committed
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

namespace AMDiS
{
  namespace Impl
  {
    template <class T0, class... Ts>
    struct DomainType
    {
      using type = typename T0::Domain;
    };

    template <class T0, class... Ts>
    struct EntitySetType
    {
      using type = typename T0::EntitySet;
    };

  } // end namespace Impl

33

34
#ifndef DOXYGEN
35
36
  template <class Signatur, class Functor, class... LocalFunctions>
  class FunctorLocalFunction;
37
#endif
Praetorius, Simon's avatar
Praetorius, Simon committed
38

39
  // implementation
40
41
  template <class R, class D, class Functor, class... LocalFunctions>
  class FunctorLocalFunction<R(D), Functor, LocalFunctions...>
Praetorius, Simon's avatar
Praetorius, Simon committed
42
43
  {
  public:
44
45
    using Range = R;
    using Domain = D;
Praetorius, Simon's avatar
Praetorius, Simon committed
46

47
48
    enum { hasDerivative = true };

49
50
51
52
53
54
55
56
57
58
59
60
61
62
    template <class LocalFct>
    struct LocalFunctionWrapper
    {
      template <class GridFct>
      LocalFunctionWrapper(GridFct const& gridFct)
        : localFct_{localFunction(gridFct)}
      {}

      LocalFct const& operator*() const { return localFct_; }
      LocalFct      & operator*()       { return localFct_; }

      LocalFct localFct_;
    };

Praetorius, Simon's avatar
Praetorius, Simon committed
63
  public:
64
    /// Constructor. Stores copies of the functor and localFunction(gridfunction)s.
65
66
    template <class... GridFcts>
    FunctorLocalFunction(Functor const& fct, GridFcts&&... gridFcts)
67
      : fct_{fct}
68
      , localFcts_{FWD(gridFcts)...}
69
    {}
Praetorius, Simon's avatar
Praetorius, Simon committed
70

71
72
73
    /// Calls \ref bind for all localFunctions
    template <class Element>
    void bind(Element const& element)
Praetorius, Simon's avatar
Praetorius, Simon committed
74
    {
75
      Tools::for_each(localFcts_, [&](auto& localFct) {
76
        (*localFct).bind(element);
77
78
      });
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
79

80
81
82
    /// Calls \ref unbind for all localFunctions
    void unbind()
    {
83
      Tools::for_each(localFcts_, [&](auto& localFct) {
84
        (*localFct).unbind();
85
86
      });
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
87

88
89
90
    /// Applies the functor \ref fct_ to the evaluated localFunctions
    Range operator()(Domain const& x) const
    {
91
      return Tools::apply([&](auto&&... localFct) { return fct_((*localFct)(x)...); }, localFcts_);
92
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
93

94
95
96
97
98
99
  public:
    /// Return the stored functor
    Functor const& fct() const
    {
      return fct_;
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
100

101
    auto const& localFcts() const
102
103
104
    {
      return localFcts_;
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
105

106
107
  private:
    Functor fct_;
108
    std::tuple<LocalFunctionWrapper<LocalFunctions>...> localFcts_;
109
  };
Praetorius, Simon's avatar
Praetorius, Simon committed
110

111
112
113
114
115

  /// \fn derivative
  /// \brief Derivative of the LocalFunction of a FunctorGridFunction, utilizing
  /// the chain-rule. Only available if the functor provides partial derivatives.
  /**
116
   * \f$ d_x(f(lf(x)...)) = \sum_i d_i(f)[lf(x)...] * derivative(lf[i]) \f$
117
118
119
120
   *
   * **Requirements:**
   * - The Functor `F` must model `Concepts::HasPartial`
   **/
121
  template <class Sig, class F, class... LFs, class Type,
122
    REQUIRES(Concepts::HasPartial<F>)>
123
  auto derivative(FunctorLocalFunction<Sig,F,LFs...> const& lf, Type const& type)
124
  {
125
    auto index_seq = std::index_sequence_for<LFs...>{};
126
127
128
129

    // d_i(f)[lgfs...] * lgfs_i
    auto term_i = [&](auto const _i)
    {
130
      auto di_f = Tools::apply([&](auto const&... lgfs) {
131
        return makeFunctorGridFunction(partial(lf.fct(), _i), (*lgfs)...);
132
133
      }, lf.localFcts());

134
      using std::get;
Praetorius, Simon's avatar
Praetorius, Simon committed
135
      auto const& lgfs_i = *get<VALUE(_i)>(lf.localFcts());
136
      return makeFunctorGridFunction(Operation::Multiplies{}, di_f, derivative(lgfs_i, type));
137
138
    };

139
    // sum_i [ d_i(f)[lgfs...] * derivative(lgfs_i)
140
    auto gridFct = Tools::apply([&](auto const... _i)
141
142
143
144
145
146
147
148
    {
      return makeFunctorGridFunction(Operation::Plus{}, term_i(_i)...);
    }, index_seq);

    return localFunction(gridFct);
  }


149
150
151
152
153
154
155
156
  /// \fn order
  /// \brief Calculate the polynomial order of a functor `F` that provides a free
  /// function order(f, degs...), where degs are the orders of the LocalFunctions.
  /**
   * **Requirements:**
   * - The functor `F` must model `Concepts::HasFunctorOrder`
   * - All localFunctions `LFs...` must model `Concepts::HasOrder`
   **/
157
158
159
160
161
  template <class Sig, class F, class... LFs,
    REQUIRES(Concepts::HasFunctorOrder<F,sizeof...(LFs)>
             && all_of_v<Concepts::HasOrder<LFs>...>)>
  int order(FunctorLocalFunction<Sig,F,LFs...> const& lf)
  {
162
    return Tools::apply([&lf](auto const&... lgfs) { return order(lf.fct(), order(*lgfs)...); },
163
164
165
166
      lf.localFcts());
  }


167
  /// \class FunctorGridFunction
168
  /// \brief A Gridfunction that applies a functor to the evaluated Gridfunctions
169
  /**
170
171
172
   * \ingroup GridFunctions
   * Composition of GridFunctions `g_i` by applying a functor `f` locally, i.e.
   * locally it is evaluated
173
174
175
176
177
178
179
180
181
182
   * \f$ f(g_0(x), g_1(x), ...) \f$
   *
   * \tparam Functor           The type of the outer functor `f`
   * \tparam GridFunctions...  The GridFunction types of `g_i`
   *
   * Requirements:
   * - `arity(f) == sizeof...(GridFunctions)`
   * - `arity(g_i) == arity(g_j) for i != j`
   * - `g_i` models concept \ref GridFunction
   **/
183
184
185
186
  template <class Functor, class... GridFunctions>
  class FunctorGridFunction
  {
  public:
187
    /// The result type of the functor when applied to the grid-functions
Praetorius, Simon's avatar
Praetorius, Simon committed
188
    using Range = decltype(std::declval<Functor>()(std::declval<typename GridFunctions::Range>()...));
189

190
    /// The argument type that can be applied to the grid-functions
191
    using Domain = typename Impl::DomainType<GridFunctions...>::type;
192

193
    /// The set of entities this grid-function binds to
194
    using EntitySet = typename Impl::EntitySetType<GridFunctions...>::type;
Praetorius, Simon's avatar
Praetorius, Simon committed
195

196
197
    enum { hasDerivative = false };

198
  private:
199
    template <class GridFct>
200
    using LocalFct = TYPEOF( localFunction(std::declval<GridFct>()) );
201

202
    using RawRange = remove_cvref_t<Range>;
203
    using LocalDomain = typename EntitySet::LocalCoordinate;
204
205

  public:
206
207
    using LocalFunction = FunctorLocalFunction<RawRange(LocalDomain), Functor, LocalFct<GridFunctions>...>;

208
    /// \brief Constructor. Stores copies of the functor and gridfunctions.
Praetorius, Simon's avatar
Praetorius, Simon committed
209
210
    template <class... GridFcts>
    explicit FunctorGridFunction(Functor const& fct, GridFcts&&... gridFcts)
211
      : fct_{fct}
212
      , gridFcts_{FWD(gridFcts)...}
Praetorius, Simon's avatar
Praetorius, Simon committed
213
214
    {}

215
    /// Applies the functor to the evaluated gridfunctions
Praetorius, Simon's avatar
Praetorius, Simon committed
216
217
    Range operator()(Domain const& x) const
    {
218
      return Tools::apply([&](auto&&... gridFct) { return fct_(gridFct(x)...); }, gridFcts_);
Praetorius, Simon's avatar
Praetorius, Simon committed
219
220
    }

221
    /// Return the stored \ref EntitySet of the first GridFunction
Praetorius, Simon's avatar
Praetorius, Simon committed
222
223
    EntitySet const& entitySet() const
    {
224
      return std::get<0>(gridFcts_).entitySet();
Praetorius, Simon's avatar
Praetorius, Simon committed
225
226
    }

227
    LocalFunction makeLocalFunction() const
Praetorius, Simon's avatar
Praetorius, Simon committed
228
    {
229
      return Tools::apply([&](auto const&... gridFcts) { return LocalFunction{fct_, gridFcts...}; }, gridFcts_);
Praetorius, Simon's avatar
Praetorius, Simon committed
230
231
232
233
234
235
236
    }

  private:
    Functor fct_;
    std::tuple<GridFunctions...> gridFcts_;
  };

237
238

  // Generator function for FunctorGridFunction expressions
239
240
241
242
243
  template <class Functor, class... GridFcts>
  auto makeFunctorGridFunction(Functor const& f, GridFcts const&... gridFcts)
  {
    static_assert(all_of_v<Concepts::GridFunction<GridFcts>...>,
      "All passed parameters must be GridFunctions.");
244
    static_assert(Concepts::Callable<Functor, typename GridFcts::Range...>,
245
246
247
248
      "Range types of grid functions are not compatible with the functor.");
    return FunctorGridFunction<Functor, GridFcts...>{f, gridFcts...};
  }

249
250

#ifndef DOXYGEN
251
  // PreGridFunction related to FunctorGridFunction.
252
  template <class Functor, class... PreGridFunctions>
Praetorius, Simon's avatar
Praetorius, Simon committed
253
254
  struct FunctorPreGridFunction
  {
255
256
257
258
259
260
261
    using Self = FunctorPreGridFunction;

    struct Creator
    {
      template <class GridView>
      static auto create(Self const& self, GridView const& gridView)
      {
262
        return Tools::apply([&](auto const&... pgf) {
263
264
          return makeFunctorGridFunction(self.fct_,
            makeGridFunction(pgf, gridView)...);
265
        }, self.preGridFcts_);
266
267
268
      }
    };

269
270
271
    template <class... PreGridFcts>
    explicit FunctorPreGridFunction(Functor const& fct, PreGridFcts&&... pgfs)
      : fct_{fct}
272
      , preGridFcts_{FWD(pgfs)...}
Praetorius, Simon's avatar
Praetorius, Simon committed
273
274
    {}

275
  private:
Praetorius, Simon's avatar
Praetorius, Simon committed
276
    Functor fct_;
277
    std::tuple<PreGridFunctions...> preGridFcts_;
Praetorius, Simon's avatar
Praetorius, Simon committed
278
279
  };

280
  namespace Traits
Praetorius, Simon's avatar
Praetorius, Simon committed
281
  {
282
283
    template <class Functor, class... PreGridFcts>
    struct IsPreGridFunction<FunctorPreGridFunction<Functor, PreGridFcts...>>
Praetorius, Simon's avatar
Praetorius, Simon committed
284
      : std::true_type {};
285
  }
286
#endif
Praetorius, Simon's avatar
Praetorius, Simon committed
287
288


289
290
  /// \brief Generator function for FunctorGridFunction.
  /// \relates FunctorGridFunction
291
  /**
292
293
294
   * \ingroup GridFunctions
   * Applies the functor `f` to the grid-functions `gridFcts...`.
   * See \ref FunctorGridFunction.
295
296
297
298
299
300
   *
   * **Examples:**
   * - `invokeAtQP([](Dune::FieldVector<double, 2> const& x) { return two_norm(x); }, X());`
   * - `invokeAtQP([](double u, auto const& x) { return u + x[0]; }, 1.0, X());`
   * - `invokeAtQP(Operation::Plus{}, X(0), X(1));`
   **/
301
302
  template <class Functor, class... PreGridFcts>
  auto invokeAtQP(Functor const& f, PreGridFcts&&... gridFcts)
Praetorius, Simon's avatar
Praetorius, Simon committed
303
  {
304
    return FunctorPreGridFunction<Functor, TYPEOF(gridFcts)...>{f, FWD(gridFcts)...};
Praetorius, Simon's avatar
Praetorius, Simon committed
305
306
307
  }

} // end namespace AMDiS