Finite Volume Solver  prototype
A framework to build finite volume solvers for the AG Klein at the Freie Universität Berlin.
DimensionalSplitLevelIntegrator.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_DIMENSIONAL_SPLIT_LEVEL_INTEGRATOR_HPP
22 #define FUB_DIMENSIONAL_SPLIT_LEVEL_INTEGRATOR_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/Meta.hpp"
29 #include "fub/TimeStepError.hpp"
30 #include "fub/core/algorithm.hpp"
31 #include "fub/ext/Mpi.hpp"
32 #include "fub/ext/outcome.hpp"
33 
34 #include "fub/split_method/GodunovSplitting.hpp"
35 
36 #include <utility>
37 
38 namespace fub {
39 
40 /// \defgroup LevelIntegrator Level Integrators
41 /// \brief This group collects all classes that define a time integration on a
42 /// single refinement level.
43 
44 /// \ingroup LevelIntegrator
45 ///
46 /// \brief This Level Integrator applies a very general AMR integration scheme
47 /// in context of dimensional splitting.
48 ///
49 /// The time integration is split into multiple intermediate steps where each is
50 /// supposed to do a certain task. The detailed implementation of these tasks
51 /// happens in the integrator context object.
52 template <int R, typename IntegratorContext,
53  typename SplitMethod = GodunovSplitting>
54 class DimensionalSplitLevelIntegrator : public IntegratorContext,
55  private SplitMethod {
56 public:
57  static constexpr int Rank = R;
58 
60 
62  const DimensionalSplitLevelIntegrator& other) = default;
63 
65  operator=(const DimensionalSplitLevelIntegrator& other) = default;
66 
68  default;
69 
72 
73  template <typename OtherSplitMethod>
75  const DimensionalSplitLevelIntegrator<Rank, IntegratorContext,
76  OtherSplitMethod>& other)
77  : IntegratorContext(other), SplitMethod(other.GetSplitMethod()) {}
78 
79  DimensionalSplitLevelIntegrator(IntegratorContext context,
80  SplitMethod splitting = SplitMethod())
81  : IntegratorContext(std::move(context)),
82  SplitMethod(std::move(splitting)) {}
83 
85  SplitMethod splitting = SplitMethod())
86  : DimensionalSplitLevelIntegrator(std::move(context),
87  std::move(splitting)) {}
88 
89  const IntegratorContext& GetContext() const noexcept { return *this; }
90  IntegratorContext& GetContext() noexcept { return *this; }
91 
92  const SplitMethod& GetSplitMethod() const noexcept { return *this; }
93 
95 
96  void PostAdvanceHierarchy([[maybe_unused]] Duration time_step_size);
97 
98  void PreAdvanceLevel([[maybe_unused]] int level,
99  [[maybe_unused]] Duration time_step_size,
100  [[maybe_unused]] std::pair<int, int> subcycle);
101 
103  PostAdvanceLevel([[maybe_unused]] int level,
104  [[maybe_unused]] Duration time_step_size,
105  [[maybe_unused]] std::pair<int, int> subcycle);
106 
107  using IntegratorContext::GetCounterRegistry;
108  using IntegratorContext::GetCycles;
109  using IntegratorContext::GetMpiCommunicator;
110  using IntegratorContext::GetTimePoint;
111 
112  using IntegratorContext::FillGhostLayerSingleLevel;
113  using IntegratorContext::FillGhostLayerTwoLevels;
114 
115  using IntegratorContext::GetRatioToCoarserLevel;
116  using IntegratorContext::LevelExists;
117 
118  using IntegratorContext::CoarsenConservatively;
120  using IntegratorContext::ComputeNumericFluxes;
121  using IntegratorContext::CopyDataToScratch;
122  using IntegratorContext::CopyScratchToData;
123  using IntegratorContext::UpdateConservatively;
124 
125  using IntegratorContext::AccumulateCoarseFineFluxes;
126  using IntegratorContext::ApplyFluxCorrection;
127  using IntegratorContext::ResetCoarseFineFluxes;
128 
129  /// Returns a stable dt on a specified level across all spatial directions.
130  ///
131  /// For stability it is advised to multiply some additional CFL factor < 1.0.
132  Duration ComputeStableDt(int level_number);
133 
134  /// Advance a specified patch level and all finer levels by time `dt`.
135  ///
136  /// This method subcycles finer levels.
137  ///
138  /// \param[in] level_num An integer denoting the patch level where 0 is the
139  /// coarsest level.
140  ///
141  /// \param[in] dt A stable time step size for the level_num-th patch level.
142  ///
143  /// \param[in] subcycle The ith subcycle which we are currently in, starting
144  /// at 0.
146  AdvanceLevelNonRecursively(int level_number, Duration dt,
147  std::pair<int, int> subcycle);
148 };
149 
150 template <int R, typename IntegratorContext, typename SplitMethod>
151 void DimensionalSplitLevelIntegrator<R, IntegratorContext,
152  SplitMethod>::PreAdvanceHierarchy() {
155  }
156 }
157 template <int R, typename IntegratorContext, typename SplitMethod>
159  PostAdvanceHierarchy([[maybe_unused]] Duration time_step_size) {
162  } else if constexpr (is_detected<meta::PostAdvanceHierarchy,
163  IntegratorContext&, Duration>()) {
165  }
166 }
167 template <int R, typename IntegratorContext, typename SplitMethod>
169  PreAdvanceLevel(int level, Duration time_step_size,
170  std::pair<int, int> subcycle) {
171  int regrid_level =
172  IntegratorContext::PreAdvanceLevel(level, time_step_size, subcycle);
173  if (regrid_level == 0) {
174  IntegratorContext::FillGhostLayerSingleLevel(0);
175  }
176  for (int ilvl = std::max(1, regrid_level);
177  IntegratorContext::LevelExists(ilvl); ++ilvl) {
178  IntegratorContext::FillGhostLayerTwoLevels(ilvl, ilvl - 1);
179  }
180 
181  const Duration coarse_time_point = IntegratorContext::GetTimePoint(0);
182  const Duration this_time_point = IntegratorContext::GetTimePoint(level);
183  if (level < regrid_level && this_time_point != coarse_time_point) {
184  if (level > 0) {
185  IntegratorContext::FillGhostLayerTwoLevels(level, level - 1);
186  } else {
187  IntegratorContext::FillGhostLayerSingleLevel(level);
188  }
189  }
190 }
191 
192 template <int R, typename IntegratorContext, typename SplitMethod>
195  PostAdvanceLevel(int level, Duration time_step_size,
196  std::pair<int, int> subcycle) {
197  if constexpr (is_detected<meta::PostAdvanceLevel, IntegratorContext&, int,
198  Duration, std::pair<int, int>>()) {
199  return IntegratorContext::PostAdvanceLevel(level, time_step_size, subcycle);
200  }
201  return boost::outcome_v2::success();
202 }
203 
204 template <int Rank, typename Context, typename SplitMethod>
205 Duration
207  int level) {
208  if (level > 0) {
209  Context::FillGhostLayerTwoLevels(level, level - 1);
210  } else {
211  Context::FillGhostLayerSingleLevel(level);
212  }
213  Duration min_dt(std::numeric_limits<double>::max());
214  for (int d = 0; d < Rank; ++d) {
215  const Direction dir = static_cast<Direction>(d);
216  min_dt = std::min(min_dt, Context::ComputeStableDt(level, dir));
217  }
218  return min_dt;
219 }
220 
221 template <int Rank, typename Context, typename SplitMethod>
224  AdvanceLevelNonRecursively(int this_level, Duration dt,
225  std::pair<int, int> subcycle) {
226  auto AdvanceLevel_Split = [&](Direction dir) {
227  return [&, this_level, dir, count_split_steps = 0](
228  Duration split_dt) mutable -> Result<void, TimeStepTooLarge> {
229  if (count_split_steps > 0) {
230  // Apply boundary condition for the physical boundary only.
231  Context::ApplyBoundaryCondition(this_level, dir);
232  }
233  count_split_steps += 1;
234 
235  // Check stable time step size and if the CFL condition is violated then
236  // restart the coarse time step
237  const Duration local_dt = Context::ComputeStableDt(this_level, dir);
238  MPI_Comm comm = GetMpiCommunicator();
239  const Duration level_dt = MinAll(comm, local_dt);
240  if (level_dt < split_dt) {
241  return TimeStepTooLarge{level_dt, this_level};
242  }
243 
244  // Compute fluxes in the specified direction
245  Context::ComputeNumericFluxes(this_level, split_dt, dir);
246 
247  // Use the updated fluxes to update cons variables at the "SCRATCH"
248  // context.
249  Context::UpdateConservatively(this_level, split_dt, dir);
250 
251  // The conservative update and happened on conservative variables.
252  // We have to reconstruct the missing variables in the complete state.
253  Context::CompleteFromCons(this_level, split_dt);
254 
255  // We have to accumulate the fluxes now,
256  const double scale = split_dt.count();
257  Context::AccumulateCoarseFineFluxes(this_level, scale, dir);
258 
259  return boost::outcome_v2::success();
260  };
261  };
262 
263  // Depending on the space dimension of this dimensional split operator we
264  // apply the configured splitting method with multiple operators
265 
266  Result<void, TimeStepTooLarge> result = std::apply(
267  [&](auto... directions) {
268  return GetSplitMethod().Advance(dt, AdvanceLevel_Split(directions)...);
269  },
270  MakeSplitDirections<Rank>(static_cast<int>(GetCycles(0)), subcycle));
271 
272  return result;
273 }
274 
275 } // namespace fub
276 
277 #endif
This Level Integrator applies a very general AMR integration scheme in context of dimensional splitti...
Definition: DimensionalSplitLevelIntegrator.hpp:55
void PostAdvanceHierarchy([[maybe_unused]] Duration time_step_size)
Definition: DimensionalSplitLevelIntegrator.hpp:159
const IntegratorContext & GetContext() const noexcept
Definition: DimensionalSplitLevelIntegrator.hpp:89
DimensionalSplitLevelIntegrator(int_constant< R >, IntegratorContext context, SplitMethod splitting=SplitMethod())
Definition: DimensionalSplitLevelIntegrator.hpp:84
DimensionalSplitLevelIntegrator(DimensionalSplitLevelIntegrator &&other)=default
void PreAdvanceLevel([[maybe_unused]] int level, [[maybe_unused]] Duration time_step_size, [[maybe_unused]] std::pair< int, int > subcycle)
Definition: DimensionalSplitLevelIntegrator.hpp:169
DimensionalSplitLevelIntegrator(const DimensionalSplitLevelIntegrator &other)=default
DimensionalSplitLevelIntegrator(IntegratorContext context, SplitMethod splitting=SplitMethod())
Definition: DimensionalSplitLevelIntegrator.hpp:79
static constexpr int Rank
Definition: DimensionalSplitLevelIntegrator.hpp:57
IntegratorContext & GetContext() noexcept
Definition: DimensionalSplitLevelIntegrator.hpp:90
DimensionalSplitLevelIntegrator & operator=(DimensionalSplitLevelIntegrator &&other)=default
void PreAdvanceHierarchy()
Definition: DimensionalSplitLevelIntegrator.hpp:152
DimensionalSplitLevelIntegrator & operator=(const DimensionalSplitLevelIntegrator &other)=default
const SplitMethod & GetSplitMethod() const noexcept
Definition: DimensionalSplitLevelIntegrator.hpp:92
Result< void, TimeStepTooLarge > AdvanceLevelNonRecursively(int level_number, Duration dt, std::pair< int, int > subcycle)
Advance a specified patch level and all finer levels by time dt.
Definition: DimensionalSplitLevelIntegrator.hpp:224
DimensionalSplitLevelIntegrator(const DimensionalSplitLevelIntegrator< Rank, IntegratorContext, OtherSplitMethod > &other)
Definition: DimensionalSplitLevelIntegrator.hpp:74
Result< void, TimeStepTooLarge > PostAdvanceLevel([[maybe_unused]] int level, [[maybe_unused]] Duration time_step_size, [[maybe_unused]] std::pair< int, int > subcycle)
Definition: DimensionalSplitLevelIntegrator.hpp:195
Duration ComputeStableDt(int level_number)
Returns a stable dt on a specified level across all spatial directions.
Definition: DimensionalSplitLevelIntegrator.hpp:206
void CompleteFromCons(Equation &&equation, Complete< std::decay_t< Equation >> &complete, const Conservative< std::decay_t< Equation >> &cons)
Definition: CompleteFromCons.hpp:42
decltype(std::declval< Context >().PreAdvanceHierarchy(std::declval< Args >()...)) PreAdvanceHierarchy
A template typedef to detect the member function.
Definition: Meta.hpp:36
decltype(std::declval< Context >().PreAdvanceLevel(std::declval< Args >()...)) PreAdvanceLevel
A template typedef to detect the member function.
Definition: Meta.hpp:44
decltype(std::declval< Context >().PostAdvanceHierarchy(std::declval< Args >()...)) PostAdvanceHierarchy
A template typedef to detect the member function.
Definition: Meta.hpp:40
decltype(std::declval< Context >().PostAdvanceLevel(std::declval< Args >()...)) PostAdvanceLevel
A template typedef to detect the member function.
Definition: Meta.hpp:48
The fub namespace.
Definition: AnyBoundaryCondition.hpp:31
Duration MinAll(MPI_Comm comm, Duration local_duration)
std::chrono::duration< double > Duration
Definition: Duration.hpp:31
Direction
This is a type safe type to denote a dimensional split direction.
Definition: Direction.hpp:30
boost::outcome_v2::result< T, E > Result
Definition: outcome.hpp:32
std::integral_constant< int, I > int_constant
Definition: type_traits.hpp:183
Definition: TimeStepError.hpp:71
This is std::true_type if Op<Args...> is a valid SFINAE expression.
Definition: type_traits.hpp:92