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
#include <amdis/common/Order.hpp>
12
13
#include <amdis/gridfunctions/Derivative.hpp>
#include <amdis/gridfunctions/GridFunction.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
      Ranges::forEach(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
      Ranges::forEach(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 Ranges::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)...] * derivativeOf(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 derivativeOf(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 = Ranges::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, derivativeOf(lgfs_i, type));
137
138
    };

139
    // sum_i [ d_i(f)[lgfs...] * derivativeOf(lgfs_i)
140
    auto gridFct = Ranges::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
  /// \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`
155
   * - All localFunctions `LFs...` must model `Concepts::Polynomial`
156
   **/
157
158
  template <class Sig, class F, class... LFs,
    REQUIRES(Concepts::HasFunctorOrder<F,sizeof...(LFs)>
159
             && (Concepts::Polynomial<LFs> &&...))>
160
161
  int order(FunctorLocalFunction<Sig,F,LFs...> const& lf)
  {
162
    return Ranges::apply([&lf](auto const&... lgfs) {
Praetorius, Simon's avatar
Praetorius, Simon committed
163
164
      return order(lf.fct(), order(*lgfs)...);
    }, lf.localFcts());
165
166
167
  }


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

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

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

197
198
    enum { hasDerivative = false };

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

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

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

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

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

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

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

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

238
239

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

250
251

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

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

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

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

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


290
291
  /// \brief Generator function for FunctorGridFunction.
  /// \relates FunctorGridFunction
292
  /**
293
294
295
   * \ingroup GridFunctions
   * Applies the functor `f` to the grid-functions `gridFcts...`.
   * See \ref FunctorGridFunction.
296
297
298
299
300
301
   *
   * **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));`
   **/
302
303
  template <class Functor, class... PreGridFcts>
  auto invokeAtQP(Functor const& f, PreGridFcts&&... gridFcts)
Praetorius, Simon's avatar
Praetorius, Simon committed
304
  {
305
    return FunctorPreGridFunction<Functor, TYPEOF(gridFcts)...>{f, FWD(gridFcts)...};
Praetorius, Simon's avatar
Praetorius, Simon committed
306
307
308
  }

} // end namespace AMDiS