FunctorGridFunction.hpp 9.67 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
9
10
11
12
#include <amdis/Operations.hpp>
#include <amdis/common/IndexSeq.hpp>
#include <amdis/common/Loops.hpp>
#include <amdis/common/Mpl.hpp>
#include <amdis/gridfunctions/GridFunctionConcepts.hpp>
Praetorius, Simon's avatar
Praetorius, Simon committed
13
14
15
16
17
18
19
20
21

namespace AMDiS
{
  namespace Impl
  {
    template <class T0, class... Ts>
    struct DomainType
    {
      using type = typename T0::Domain;
22
23
      // static_assert( all_of_v< std::is_same<type, typename DomainType<Ts>::type>::value... >,
      //   "All GridFunctions must have the same Domain." );
Praetorius, Simon's avatar
Praetorius, Simon committed
24
25
26
27
28
29
    };

    template <class T0, class... Ts>
    struct EntitySetType
    {
      using type = typename T0::EntitySet;
30
31
      // static_assert( all_of_v< std::is_same<type, typename EntitySetType<Ts>::type>::value... >,
      //   "All GridFunctions must have the same EntitySet." );
Praetorius, Simon's avatar
Praetorius, Simon committed
32
33
34
35
    };

  } // end namespace Impl

36

37
#ifndef DOXYGEN
38
39
  template <class Signatur, class Functor, class... LocalFunctions>
  class FunctorLocalFunction;
40
#endif
Praetorius, Simon's avatar
Praetorius, Simon committed
41

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

50
51
    enum { hasDerivative = true };

52
53
54
55
56
57
58
59
60
61
62
63
64
65
    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
66
  public:
67
    /// Constructor. Stores copies of the functor and localFunction(gridfunction)s.
68
69
    template <class... GridFcts>
    FunctorLocalFunction(Functor const& fct, GridFcts&&... gridFcts)
70
71
      : fct_{fct}
      , localFcts_{std::forward<GridFcts>(gridFcts)...}
72
    {}
Praetorius, Simon's avatar
Praetorius, Simon committed
73

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

83
84
85
86
    /// Calls \ref unbind for all localFunctions
    void unbind()
    {
      forEach(localFcts_, [&](auto& localFct) {
87
        (*localFct).unbind();
88
89
      });
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
90

91
92
93
    /// Applies the functor \ref fct_ to the evaluated localFunctions
    Range operator()(Domain const& x) const
    {
94
      using Dune::Std::apply;
95
      return apply([&](auto&&... localFct) { return fct_((*localFct)(x)...); }, localFcts_);
96
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
97

98
99
100
101
102
103
  public:
    /// Return the stored functor
    Functor const& fct() const
    {
      return fct_;
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
104

105
    auto const& localFcts() const
106
107
108
    {
      return localFcts_;
    }
Praetorius, Simon's avatar
Praetorius, Simon committed
109

110
111
  private:
    Functor fct_;
112
    std::tuple<LocalFunctionWrapper<LocalFunctions>...> localFcts_;
113
  };
Praetorius, Simon's avatar
Praetorius, Simon committed
114

115
116
117
118
119

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

    // d_i(f)[lgfs...] * lgfs_i
    auto term_i = [&](auto const _i)
    {
134
135
      using Dune::Std::apply;
      auto di_f = apply([&](auto const&... lgfs) {
136
        return makeFunctorGridFunction(partial(lf.fct(), _i), (*lgfs)...);
137
138
      }, lf.localFcts());

139
      using std::get;
140
      auto const& lgfs_i = *get<decltype(_i)::value>(lf.localFcts());
141
142
143
      return makeFunctorGridFunction(Operation::Multiplies{}, di_f, derivative(lgfs_i));
    };

144
145
146
    // sum_i [ d_i(f)[lgfs...] * derivative(lgfs_i)
    using Dune::Std::apply;
    auto gridFct = apply([&](auto const... _i)
147
148
149
150
151
152
153
154
    {
      return makeFunctorGridFunction(Operation::Plus{}, term_i(_i)...);
    }, index_seq);

    return localFunction(gridFct);
  }


155
156
157
158
159
160
161
162
  /// \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`
   **/
163
164
165
166
167
  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)
  {
168
    using Dune::Std::apply;
169
    return apply([&lf](auto const&... lgfs) { return order(lf.fct(), order(*lgfs)...); },
170
171
172
173
      lf.localFcts());
  }


174
  /// \class FunctorGridFunction
175
  /// \brief A Gridfunction that applies a functor to the evaluated Gridfunctions
176
  /**
177
178
179
   * \ingroup GridFunctions
   * Composition of GridFunctions `g_i` by applying a functor `f` locally, i.e.
   * locally it is evaluated
180
181
182
183
184
185
186
187
188
189
   * \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
   **/
190
191
192
193
  template <class Functor, class... GridFunctions>
  class FunctorGridFunction
  {
  public:
194
    /// The result type of the functor when applied to the grid-functions
Praetorius, Simon's avatar
Praetorius, Simon committed
195
    using Range = decltype(std::declval<Functor>()(std::declval<typename GridFunctions::Range>()...));
196

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

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

203
204
    enum { hasDerivative = false };

205
  private:
206
207
208
209
    template <class GridFct>
    using LocalFct = std::decay_t<decltype(localFunction(std::declval<GridFct>()))>;

    using RawRange = std::decay_t<Range>;
210
    using LocalDomain = typename EntitySet::LocalCoordinate;
211
212

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

215
    /// \brief Constructor. Stores copies of the functor and gridfunctions.
Praetorius, Simon's avatar
Praetorius, Simon committed
216
217
    template <class... GridFcts>
    explicit FunctorGridFunction(Functor const& fct, GridFcts&&... gridFcts)
218
219
      : fct_{fct}
      , gridFcts_{std::forward<GridFcts>(gridFcts)...}
Praetorius, Simon's avatar
Praetorius, Simon committed
220
221
    {}

222
    /// Applies the functor to the evaluated gridfunctions
Praetorius, Simon's avatar
Praetorius, Simon committed
223
224
    Range operator()(Domain const& x) const
    {
225
226
      using Dune::Std::apply;
      return apply([&](auto&&... gridFct) { return fct_(gridFct(x)...); }, gridFcts_);
Praetorius, Simon's avatar
Praetorius, Simon committed
227
228
    }

229
    /// Return the stored \ref EntitySet of the first GridFunction
Praetorius, Simon's avatar
Praetorius, Simon committed
230
231
    EntitySet const& entitySet() const
    {
232
233
      using std::get;
      return get<0>(gridFcts_).entitySet();
Praetorius, Simon's avatar
Praetorius, Simon committed
234
235
    }

236
    LocalFunction localFunction() const
Praetorius, Simon's avatar
Praetorius, Simon committed
237
    {
238
239
      using Dune::Std::apply;
      return apply([&](auto const&... gridFcts) { return LocalFunction{fct_, gridFcts...}; }, gridFcts_);
Praetorius, Simon's avatar
Praetorius, Simon committed
240
241
242
243
244
245
246
    }

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

247

248
249
250
  /// \fn localFunction
  /// \brief Creates a LocalFunction from the LocalFunctions of the GridFunctions.
  /// \relates FunctorLocalFunction
251
252
253
  template <class F, class... GFs>
  auto localFunction(FunctorGridFunction<F,GFs...> const& gf)
  {
254
    return gf.localFunction();
255
256
257
  }


258
  // Generator function for FunctorGridFunction expressions
259
260
261
262
263
  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.");
264
    static_assert(Concepts::Callable<Functor, typename GridFcts::Range...>,
265
266
267
268
      "Range types of grid functions are not compatible with the functor.");
    return FunctorGridFunction<Functor, GridFcts...>{f, gridFcts...};
  }

269
270

#ifndef DOXYGEN
271
  // PreGridFunction related to FunctorGridFunction.
272
  template <class Functor, class... PreGridFunctions>
Praetorius, Simon's avatar
Praetorius, Simon committed
273
274
  struct FunctorPreGridFunction
  {
275
276
277
278
279
280
281
282
283
284
    using Self = FunctorPreGridFunction;

    struct Creator
    {
      template <class GridView>
      static auto create(Self const& self, GridView const& gridView)
      {
        return Dune::Std::apply([&](auto const&... pgf) {
          return makeFunctorGridFunction(self.fct_,
            makeGridFunction(pgf, gridView)...);
285
        }, self.preGridFcts_);
286
287
288
      }
    };

289
290
291
292
    template <class... PreGridFcts>
    explicit FunctorPreGridFunction(Functor const& fct, PreGridFcts&&... pgfs)
      : fct_{fct}
      , preGridFcts_{std::forward<PreGridFcts>(pgfs)...}
Praetorius, Simon's avatar
Praetorius, Simon committed
293
294
    {}

295
  private:
Praetorius, Simon's avatar
Praetorius, Simon committed
296
    Functor fct_;
297
    std::tuple<PreGridFunctions...> preGridFcts_;
Praetorius, Simon's avatar
Praetorius, Simon committed
298
299
  };

300
  namespace Traits
Praetorius, Simon's avatar
Praetorius, Simon committed
301
  {
302
303
    template <class Functor, class... PreGridFcts>
    struct IsPreGridFunction<FunctorPreGridFunction<Functor, PreGridFcts...>>
Praetorius, Simon's avatar
Praetorius, Simon committed
304
      : std::true_type {};
305
  }
306
#endif
Praetorius, Simon's avatar
Praetorius, Simon committed
307
308


309
310
  /// \brief Generator function for FunctorGridFunction.
  /// \relates FunctorGridFunction
311
  /**
312
313
314
   * \ingroup GridFunctions
   * Applies the functor `f` to the grid-functions `gridFcts...`.
   * See \ref FunctorGridFunction.
315
316
317
318
319
320
   *
   * **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));`
   **/
321
322
  template <class Functor, class... PreGridFcts>
  auto invokeAtQP(Functor const& f, PreGridFcts&&... gridFcts)
Praetorius, Simon's avatar
Praetorius, Simon committed
323
  {
324
    return FunctorPreGridFunction<Functor, std::decay_t<PreGridFcts>...>{f, std::forward<PreGridFcts>(gridFcts)...};
Praetorius, Simon's avatar
Praetorius, Simon committed
325
326
327
328
329
  }

  /** @} **/

} // end namespace AMDiS