Finite Volume Solver  prototype
A framework to build finite volume solvers for the AG Klein at the Freie Universität Berlin.
flux_method/FluxMethod.hpp
Go to the documentation of this file.
1 // Copyright (c) 2019 Maikel Nadolski
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 #ifndef FUB_FLUX_METHOD_HPP
22 #define FUB_FLUX_METHOD_HPP
23 
24 #include "fub/Direction.hpp"
25 #include "fub/Duration.hpp"
26 #include "fub/Equation.hpp"
27 #include "fub/Execution.hpp"
28 #include "fub/ForEach.hpp"
29 #include "fub/Meta.hpp"
30 #include "fub/State.hpp"
31 #include "fub/StateArray.hpp"
32 #include "fub/StateRow.hpp"
33 
34 #include <array>
35 
36 namespace fub {
37 
38 /// \defgroup FluxMethod Flux Methods
39 /// \ingroup IntegratorContext
40 /// \brief This module collects all types and functions relevant to compute
41 /// numerical fluxes
42 
43 
44 /// \ingroup FluxMethod
45 /// \brief This class applies a base flux nethod on a view of states.
46 ///
47 /// The base class only needs to define its logic on single states or state
48 /// arrays instead of on a multi dimensional arrray. By using this class the
49 /// developer does not need to repeat the logic which might involve iterating
50 /// through all indices of a patch, loading the states and applying the base
51 /// method.
52 ///
53 /// There are in total two strategies implemented, a cell-wise and a simdified
54 /// one. The sequential strategy is easier to debug but less performant. The
55 /// simd version does use the spatial grid index. This class also assumes that
56 /// base class does not use the local coordinates.
57 template <typename BaseMethod> class FluxMethod : public BaseMethod {
58 public:
64 
65  static constexpr int Rank = Equation::Rank();
66 
67  /// \brief Returns the stencil width of this flux method.
68  static constexpr int GetStencilWidth() noexcept;
69 
70  /// \brief Returns the number of elements in a stencil of this flux method.
71  static constexpr int GetStencilSize() noexcept;
72 
73  /// \brief Returns the number of elements in a stencil of this flux method
74  /// (std::size_t version).
75  static constexpr std::size_t StencilSize =
76  static_cast<std::size_t>(GetStencilSize());
77 
78  FluxMethod() = default;
79  ~FluxMethod() = default;
80 
81  FluxMethod(const FluxMethod&) = default;
82  FluxMethod(FluxMethod&&) = default;
83 
84  FluxMethod& operator=(const FluxMethod&) = default;
85  FluxMethod& operator=(FluxMethod&&) = default;
86 
87  template <typename... Args> FluxMethod(Args&&... args);
88 
89  /// @{
90  /// \brief Returns the Implementation class which will be used to compute
91  /// single fluxes.
92  const BaseMethod& Base() const noexcept;
93  BaseMethod& Base() noexcept;
94  /// @}
95 
96  using BaseMethod::GetEquation;
97 
98  /// @{
99  /// \brief This function computes numerical fluxes.
100  ///
101  /// \param[out] fluxes The destination view where numeric fluxes will be
102  /// stored at.
103  ///
104  /// \param[in] states A view over cell states which will be used to fill the
105  /// stencil for this method.
106  ///
107  /// \param[in] dir The direction parameter specifies which directional flux
108  /// method to use.
109  ///
110  /// \param[in] dt The time step size which will be used to compute the
111  /// numerical flux.
112  ///
113  /// \param[in] dx The cell width size which will be used to compute the
114  /// numerical flux.
116  const View<const Complete>& states, Duration dt,
117  double dx, Direction dir);
118 
119  void ComputeNumericFluxes(execution::SequentialTag,
120  const View<Conservative>& fluxes,
121  const View<const Complete>& states, Duration dt,
122  double dx, Direction dir);
123 
124  void ComputeNumericFluxes(execution::SimdTag,
125  const View<Conservative>& fluxes,
126  const View<const Complete>& states, Duration dt,
127  double dx, Direction dir);
128 
129  void ComputeNumericFluxes(execution::OpenMpTag,
130  const View<Conservative>& fluxes,
131  const View<const Complete>& states, Duration dt,
132  double dx, Direction dir);
133 
134  void ComputeNumericFluxes(execution::OpenMpSimdTag,
135  const View<Conservative>& fluxes,
136  const View<const Complete>& states, Duration dt,
137  double dx, Direction dir);
138  /// @}
139 
140  using BaseMethod::ComputeNumericFlux;
141 
142  /// @{
143  /// \brief This function computes a time step size such that no signal will
144  /// leave any cell covered by this view.
145  ///
146  /// \param[in] states A view over cell states which will be used to fill the
147  /// stencil for this method.
148  ///
149  /// \param[in] dir The direction parameter specifies which directional flux
150  /// method to use.
151  ///
152  /// \param[in] dx The cell width size which will be used to compute the
153  /// numerical flux.
154  double ComputeStableDt(const View<const Complete>& states, double dx,
155  Direction dir);
156 
157  double ComputeStableDt(execution::SequentialTag,
158  const View<const Complete>& states, double dx,
159  Direction dir);
160 
161  double ComputeStableDt(execution::SimdTag, const View<const Complete>& states,
162  double dx, Direction dir);
163 
164  double ComputeStableDt(execution::OpenMpTag,
165  const View<const Complete>& states, double dx,
166  Direction dir);
167 
168  double ComputeStableDt(execution::OpenMpSimdTag,
169  const View<const Complete>& states, double dx,
170  Direction dir);
171  /// @}
172 
173  using BaseMethod::ComputeStableDt;
174 
175  std::array<Complete, StencilSize> stencil_{};
176  Conservative numeric_flux_{GetEquation()};
177 
178  std::array<CompleteArray, StencilSize> stencil_array_{};
180 };
181 
182 template <typename BaseMethod>
183 constexpr int FluxMethod<BaseMethod>::GetStencilWidth() noexcept {
184  return BaseMethod::GetStencilWidth();
185 }
186 
187 template <typename BaseMethod>
188 constexpr int FluxMethod<BaseMethod>::GetStencilSize() noexcept {
189  return 2 * GetStencilWidth();
190 }
191 
192 template <typename BaseMethod>
193 template <typename... Args>
195  : BaseMethod(std::forward<Args>(args)...) {
196  stencil_.fill(Complete{BaseMethod::GetEquation()});
197  stencil_array_.fill(CompleteArray{BaseMethod::GetEquation()});
198 }
199 
200 template <typename BaseMethod>
203  const View<const Complete>& states, Duration dt, double dx, Direction dir) {
204  ForEachIndex(Box<0>(fluxes), [&](const auto... is) {
205  using Index = std::array<std::ptrdiff_t, sizeof...(is)>;
206  const Index face{is...};
207  const Index cell0 = Shift(face, dir, -GetStencilWidth());
208  for (std::size_t i = 0; i < stencil_.size(); ++i) {
209  const Index cell = Shift(cell0, dir, static_cast<int>(i));
210  Load(stencil_[i], states, cell);
211  }
212  BaseMethod::ComputeNumericFlux(numeric_flux_, stencil_, dt, dx, dir);
213  Store(fluxes, numeric_flux_, face);
214  });
215 }
216 
217 template <typename BaseMethod>
219  const View<Conservative>& fluxes, const View<const Complete>& states,
220  Duration dt, double dx, Direction dir) {
221  ComputeNumericFluxes(execution::seq, fluxes, states, dt, dx, dir);
222 }
223 
224 template <typename BaseMethod>
227  const View<const Complete>& states, Duration dt, double dx, Direction dir) {
228  ComputeNumericFluxes(execution::seq, fluxes, states, dt, dx, dir);
229 }
230 
231 template <typename BaseMethod>
234  const View<const Complete>& states, Duration dt, double dx, Direction dir) {
235  ComputeNumericFluxes(execution::simd, fluxes, states, dt, dx, dir);
236 }
237 
238 template <typename FM, typename... Args>
240  decltype(std::declval<FM>().ComputeNumericFlux(std::declval<Args>()...));
241 
242 template <typename FM, typename... Args>
245 
246 template <typename BaseMethod>
248  execution::SimdTag, const View<Conservative>& fluxes,
249  const View<const Complete>& states, Duration dt, double dx, Direction dir) {
250  static_assert(HasComputeNumericFlux<BaseMethod&, ConservativeArray&,
251  std::array<CompleteArray, StencilSize>,
252  Duration, double, Direction>());
253  IndexBox<Rank> fluxbox = Box<0>(fluxes);
254  static constexpr int kWidth = GetStencilWidth();
255  IndexBox<Rank> cellbox = Grow(fluxbox, dir, {kWidth, kWidth - 1});
256  BasicView base = Subview(states, cellbox);
257  std::array<View<const Complete>, StencilSize> stencil_views;
258  for (std::size_t i = 0; i < StencilSize; ++i) {
259  stencil_views[i] =
260  Shrink(base, dir,
261  {static_cast<std::ptrdiff_t>(i),
262  static_cast<std::ptrdiff_t>(StencilSize - i) - 1});
263  }
264  std::tuple views = std::apply(
265  [&fluxes](const auto&... vs) {
266  return std::tuple{fluxes, vs...};
267  },
268  stencil_views);
269  ForEachRow(views, [this, dt, dx, dir](const Row<Conservative>& fluxes,
270  auto... rows) {
271  ViewPointer fit = Begin(fluxes);
272  ViewPointer fend = End(fluxes);
273  std::array<ViewPointer<const Complete>, StencilSize> states{Begin(rows)...};
274  int n = static_cast<int>(get<0>(fend) - get<0>(fit));
275  while (n >= kDefaultChunkSize) {
276  for (std::size_t i = 0; i < StencilSize; ++i) {
277  Load(stencil_array_[i], states[i]);
278  }
279  ComputeNumericFlux(numeric_flux_array_, stencil_array_, dt, dx, dir);
280  Store(fit, numeric_flux_array_);
282  for (std::size_t i = 0; i < StencilSize; ++i) {
283  Advance(states[i], kDefaultChunkSize);
284  }
285  n = static_cast<int>(get<0>(fend) - get<0>(fit));
286  }
287  for (std::size_t i = 0; i < StencilSize; ++i) {
288  LoadN(stencil_array_[i], states[i], n);
289  }
290  ComputeNumericFlux(numeric_flux_array_, stencil_array_, dt, dx, dir);
291  StoreN(fit, numeric_flux_array_, n);
292  });
293 }
294 
295 template <typename BaseMethod>
296 double
298  const View<const Complete>& states,
299  double dx, Direction dir) {
300  double min_dt = std::numeric_limits<double>::infinity();
301  ForEachIndex(Shrink(Box<0>(states), dir, {0, GetStencilSize()}),
302  [&](const auto... is) {
303  using Index = std::array<std::ptrdiff_t, sizeof...(is)>;
304  const Index face{is...};
305  for (std::size_t i = 0; i < stencil_.size(); ++i) {
306  const Index cell = Shift(face, dir, static_cast<int>(i));
307  Load(stencil_[i], states, cell);
308  }
309  const double dt =
310  BaseMethod::ComputeStableDt(stencil_, dx, dir);
311  min_dt = std::min(dt, min_dt);
312  });
313  return min_dt;
314 }
315 
316 template <typename BaseMethod>
317 double
319  double dx, Direction dir) {
320  return ComputeStableDt(execution::seq, states, dx, dir);
321 }
322 
323 template <typename BaseMethod>
324 double
326  const View<const Complete>& states,
327  double dx, Direction dir) {
328  return ComputeStableDt(execution::seq, states, dx, dir);
329 }
330 
331 template <typename BaseMethod>
332 double
334  const View<const Complete>& states,
335  double dx, Direction dir) {
336  return ComputeStableDt(execution::simd, states, dx, dir);
337 }
338 
339 template <typename T, typename... Ts> T Head(T&& head, Ts&&...) { return head; }
340 
341 template <typename BaseMethod>
342 double
344  const View<const Complete>& states,
345  double dx, Direction dir) {
346  Array1d min_dt(std::numeric_limits<double>::infinity());
347  std::array<View<const Complete>, StencilSize> stencil_views;
348  for (std::size_t i = 0; i < StencilSize; ++i) {
349  stencil_views[i] =
350  Shrink(states, dir,
351  {static_cast<std::ptrdiff_t>(i),
352  static_cast<std::ptrdiff_t>(StencilSize - i) - 1});
353  }
354  std::tuple views = std::apply(
355  [](const auto&... vs) { return std::tuple{vs...}; }, stencil_views);
356  ForEachRow(views, [this, dx, dir, &min_dt](auto... rows) {
357  std::array<ViewPointer<const Complete>, StencilSize> states{Begin(rows)...};
358  ViewPointer<const Complete> send = End(Head(rows...));
359  int n = static_cast<int>(get<0>(send) - get<0>(states[0]));
360  while (n >= kDefaultChunkSize) {
361  for (std::size_t i = 0; i < StencilSize; ++i) {
362  Load(stencil_array_[i], states[i]);
363  }
364  min_dt = min_dt.min(ComputeStableDt(stencil_array_, dx, dir));
365  for (std::size_t i = 0; i < StencilSize; ++i) {
366  Advance(states[i], kDefaultChunkSize);
367  }
368  n = static_cast<int>(get<0>(send) - get<0>(states[0]));
369  }
370  for (std::size_t i = 0; i < StencilSize; ++i) {
371  LoadN(stencil_array_[i], states[i], n);
372  }
373  Array1d mask_;
374  for (int i = 0; i < mask_.rows(); ++i) {
375  mask_[i] = static_cast<double>(i);
376  }
377  auto mask = (mask_ < n).eval();
378  min_dt = mask.select(min_dt.min(ComputeStableDt(stencil_array_, dx, dir)),
379  min_dt);
380  });
381  return min_dt.minCoeff();
382 }
383 
384 } // namespace fub
385 
386 #endif
This class applies a base flux nethod on a view of states.
Definition: flux_method/FluxMethod.hpp:57
Conservative numeric_flux_
Definition: flux_method/FluxMethod.hpp:176
FluxMethod()=default
static constexpr int GetStencilWidth() noexcept
Returns the stencil width of this flux method.
Definition: flux_method/FluxMethod.hpp:183
ConservativeArray numeric_flux_array_
Definition: flux_method/FluxMethod.hpp:179
std::array< Complete, StencilSize > stencil_
Definition: flux_method/FluxMethod.hpp:175
static constexpr int Rank
Definition: flux_method/FluxMethod.hpp:65
static constexpr int GetStencilSize() noexcept
Returns the number of elements in a stencil of this flux method.
Definition: flux_method/FluxMethod.hpp:188
meta::Equation< const BaseMethod & > Equation
Definition: flux_method/FluxMethod.hpp:59
std::array< CompleteArray, StencilSize > stencil_array_
Definition: flux_method/FluxMethod.hpp:178
const BaseMethod & Base() const noexcept
Returns the Implementation class which will be used to compute single fluxes.
double ComputeStableDt(const View< const Complete > &states, double dx, Direction dir)
This function computes a time step size such that no signal will leave any cell covered by this view.
Definition: flux_method/FluxMethod.hpp:318
void ComputeNumericFluxes(const View< Conservative > &fluxes, const View< const Complete > &states, Duration dt, double dx, Direction dir)
This function computes numerical fluxes.
Definition: flux_method/FluxMethod.hpp:218
static constexpr std::size_t StencilSize
Returns the number of elements in a stencil of this flux method (std::size_t version).
Definition: flux_method/FluxMethod.hpp:75
Function ForEachIndex(const layout_left::mapping< Extents > &mapping, Function function)
Iterate through the multi-dimensional index space descibed by mapping and invoke function for each su...
Definition: ForEach.hpp:74
constexpr SequentialTag seq
Definition: Execution.hpp:31
constexpr SimdTag simd
Definition: Execution.hpp:34
std::decay_t< decltype(std::declval< T >().GetEquation())> Equation
A template typedef to detect the member function.
Definition: Meta.hpp:59
The fub namespace.
Definition: AnyBoundaryCondition.hpp:31
auto Shrink(const layout_left::mapping< Extent > &layout, Direction dir, std::ptrdiff_t n=1)
Definition: Equation.hpp:78
std::chrono::duration< double > Duration
Definition: Duration.hpp:31
View< State > Subview(const BasicView< State, Layout, Rank > &state, const IndexBox< Rank > &box)
Definition: Equation.hpp:86
Array< double, 1 > Array1d
Definition: Eigen.hpp:53
constexpr const int kDefaultChunkSize
Definition: Eigen.hpp:39
void StoreN(nodeduce_t< ViewPointer< Conservative< Eq >>> pointer, const ConservativeArray< Eq > &state, int n)
Definition: StateArray.hpp:416
IndexBox< Rank > Grow(const IndexBox< Rank > &box, Direction dir, const std::array< std::ptrdiff_t, 2 > &shifts)
Definition: PatchDataView.hpp:106
void ForEachRow(const Tuple &views, Function f)
Definition: StateRow.hpp:172
decltype(std::declval< FM >().ComputeNumericFlux(std::declval< Args >()...)) HasComputeNumericFluxType
Definition: flux_method/FluxMethod.hpp:240
void Load(State &state, const BasicView< const State, Layout, Rank > &view, const std::array< std::ptrdiff_t, State::Equation::Rank()> &index)
Definition: State.hpp:640
ViewPointer< State > Begin(const BasicView< State, Layout, Rank > &view)
Definition: State.hpp:769
void LoadN(CompleteArray< Eq, N > &state, const BasicView< const Complete< Eq >, Layout, Rank > &view, int size, nodeduce_t< const std::array< std::ptrdiff_t, std::size_t(Rank)> & > pos)
Definition: StateArray.hpp:310
Direction
This is a type safe type to denote a dimensional split direction.
Definition: Direction.hpp:30
void Advance(ViewPointer< State > &pointer, std::ptrdiff_t n) noexcept
Definition: State.hpp:825
std::array< std::ptrdiff_t, static_cast< std::size_t >(Rank)> Index
Definition: PatchDataView.hpp:34
void Store(const BasicView< Conservative< Eq >, Layout, Eq::Rank()> &view, const Conservative< Eq > &state, const std::array< std::ptrdiff_t, Eq::Rank()> &index)
Definition: State.hpp:663
T Head(T &&head, Ts &&...)
Definition: flux_method/FluxMethod.hpp:339
ViewPointer< State > End(const BasicView< State, Layout, Rank > &view)
Definition: State.hpp:782
std::array< std::ptrdiff_t, N > Shift(const std::array< std::ptrdiff_t, N > &idx, Direction dir, std::ptrdiff_t shift)
Definition: PatchDataView.hpp:37
Definition: State.hpp:403
Definition: PatchDataView.hpp:56
Definition: StateRow.hpp:51
Definition: State.hpp:750
Definition: Execution.hpp:39
Definition: Execution.hpp:36
Definition: Execution.hpp:30
Definition: Execution.hpp:33
This is std::true_type if Op<Args...> is a valid SFINAE expression.
Definition: type_traits.hpp:92