Finite Volume Solver  prototype
A framework to build finite volume solvers for the AG Klein at the Freie Universität Berlin.
RunSimulation.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_SAMRAI_RUN_SIMULATION_HPP
22 #define FUB_SAMRAI_RUN_SIMULATION_HPP
23 
24 #include "fub/Duration.hpp"
25 #include "fub/TimeStepError.hpp"
26 #include "fub/core/assert.hpp"
28 
29 #include "fub/counter/CounterRegistry.hpp"
30 #include "fub/counter/Timer.hpp"
31 
33 
34 #include <boost/log/common.hpp>
35 #include <boost/log/sources/severity_logger.hpp>
36 #include <boost/log/trivial.hpp>
37 #include <boost/outcome.hpp>
38 
39 #include <fmt/format.h>
40 
41 #include <optional>
42 #include <vector>
43 
44 namespace fub {
45 
46 struct RunOptions {
47  RunOptions() = default;
48 
50 
51  template <typename Logger> void Print(Logger& log) {
52  BOOST_LOG(log) << " - final_time = " << final_time.count() << " [s]";
53  BOOST_LOG(log) << " - max_cycles = " << max_cycles << " [-]";
54  BOOST_LOG(log) << " - smallest_time_step_size = "
55  << smallest_time_step_size.count() << " [s]";
56  BOOST_LOG(log) << " - cfl = " << cfl << " [-]";
57  BOOST_LOG(log) << " - do_backup = " << do_backup << " [-]";
58  }
59 
61  std::ptrdiff_t max_cycles{-1};
63  double cfl{0.8};
64  int do_backup{1};
65 };
66 
67 std::string
68 FormatTimeStepLine(std::ptrdiff_t cycle,
69  std::chrono::duration<double> time_point,
70  std::chrono::duration<double> time_step_size,
71  std::chrono::duration<double> final_time,
72  std::chrono::steady_clock::duration wall_time,
73  std::chrono::steady_clock::duration wall_time_difference);
74 
75 template <typename DestGrid, typename SrcGrid>
76 void MakeBackup(std::shared_ptr<DestGrid>& dest,
77  const std::shared_ptr<SrcGrid>& src,
78  CounterRegistry& counter_database) {
79  Timer counter = counter_database.get_timer("RunSimulation::MakeBackup");
80  dest = std::make_shared<DestGrid>(*src);
81 }
82 
83 template <typename Solver,
84  typename Grid = std::decay_t<
85  decltype(*std::declval<Solver&>().GetGriddingAlgorithm())>>
86 void RunSimulation(Solver& solver, RunOptions options,
87  std::chrono::steady_clock::time_point wall_time_reference,
88  BasicOutput<Grid>& output) {
89  namespace logger = boost::log;
90  using namespace logger::trivial;
91  logger::sources::severity_logger<severity_level> log(
92  logger::keywords::severity = info);
93  fub::Duration time_point = solver.GetTimePoint();
94  const fub::Duration eps = options.smallest_time_step_size;
95  std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
96  std::chrono::steady_clock::duration wall_time = wall_time_reference - now;
97  using GriddingAlgorithm =
98  std::decay_t<decltype(*std::declval<Solver&>().GetGriddingAlgorithm())>;
99  // Deeply copy the grid for a fallback scenario in case of time step errors
100  std::shared_ptr<GriddingAlgorithm> backup{};
101  if (options.do_backup) {
102  MakeBackup(backup, solver.GetGriddingAlgorithm(),
103  *solver.GetCounterRegistry());
104  }
105  std::optional<Duration> failure_dt{};
106  while (time_point + eps < options.final_time &&
107  (options.max_cycles < 0 || solver.GetCycles() < options.max_cycles)) {
108  // We have a nested loop to exactly reach output time points.
109  do {
110  const fub::Duration next_output_time = output.NextOutputTime(time_point);
111  solver.PreAdvanceHierarchy();
112  // Compute the next time step size. If an estimate is available from a
113  // prior failure we use that one.
114  const fub::Duration stable_dt =
115  failure_dt ? *failure_dt : solver.ComputeStableDt();
116  FUB_ASSERT(stable_dt > eps);
117  const fub::Duration limited_dt =
118  std::min({options.final_time - time_point,
119  next_output_time - time_point, options.cfl * stable_dt});
120 
121  // Advance the hierarchy in time!
122  boost::outcome_v2::result<void, TimeStepTooLarge> result =
123  solver.AdvanceHierarchy(limited_dt);
124 
125  if (result.has_error() && options.do_backup) {
126  // If the solver returned with an error, reduce the time step size with
127  // the new estimate.
128  failure_dt = result.error().dt;
129  BOOST_LOG_SCOPED_LOGGER_TAG(log, "Time", time_point.count());
130  BOOST_LOG_SEV(log, warning) << fmt::format(
131  "Pre-estimated coarse time step size (dt_old = {}s) "
132  "was too large.\nRestarting this time step with a "
133  "smaller coarse time step size (dt_new = {}s).\n",
134  limited_dt.count(), options.cfl * failure_dt->count());
135  solver.ResetHierarchyConfiguration(backup);
136  MakeBackup(backup, backup, *solver.GetCounterRegistry());
137  } else if (result.has_error() && !options.do_backup) {
138  BOOST_LOG_SCOPED_LOGGER_TAG(log, "Time", time_point.count());
139  BOOST_LOG_SEV(log, error) << fmt::format(
140  "Pre-estimated coarse time step size (dt_old = {}s) was too large "
141  "but no backup present. Aborting.",
142  limited_dt.count());
143  return;
144  } else {
145  solver.PostAdvanceHierarchy(limited_dt);
146  // If advancing the hierarchy was successfull print a successful time
147  // step line and reset any failure indicators.
148  now = std::chrono::steady_clock::now();
149  time_point = solver.GetTimePoint();
150  std::chrono::steady_clock::duration wall_time_difference =
151  (now - wall_time_reference) - wall_time;
152  wall_time = now - wall_time_reference;
153  const std::ptrdiff_t cycle = solver.GetCycles();
154  BOOST_LOG_SCOPED_LOGGER_TAG(log, "Time", time_point.count());
155  BOOST_LOG(log) << FormatTimeStepLine(cycle, time_point, limited_dt,
156  options.final_time, wall_time,
157  wall_time_difference);
158  failure_dt.reset();
159  if (options.do_backup) {
160  MakeBackup(backup, solver.GetGriddingAlgorithm(),
161  *solver.GetCounterRegistry());
162  }
163  }
164  } while (
165  time_point + eps < options.final_time &&
166  (options.max_cycles < 0 || solver.GetCycles() < options.max_cycles) &&
167  !output.ShallOutputNow(*solver.GetGriddingAlgorithm()));
168  output(*solver.GetGriddingAlgorithm());
169  }
170  // return solver;
171 }
172 
173 } // namespace fub
174 
175 #endif
#define FUB_ASSERT(x)
Definition: assert.hpp:39
Definition: Timer.hpp:14
std::decay_t< decltype(*std::declval< T >().GetGriddingAlgorithm())> GriddingAlgorithm
A template typedef to detect the member function.
Definition: Meta.hpp:56
The fub namespace.
Definition: AnyBoundaryCondition.hpp:31
std::string FormatTimeStepLine(std::ptrdiff_t cycle, std::chrono::duration< double > time_point, std::chrono::duration< double > time_step_size, std::chrono::duration< double > final_time, std::chrono::steady_clock::duration wall_time, std::chrono::steady_clock::duration wall_time_difference)
std::chrono::duration< double > Duration
Definition: Duration.hpp:31
void RunSimulation(Solver &solver, RunOptions options, std::chrono::steady_clock::time_point wall_time_reference, BasicOutput< Grid > &output)
Definition: RunSimulation.hpp:86
void MakeBackup(std::shared_ptr< DestGrid > &dest, const std::shared_ptr< SrcGrid > &src, CounterRegistry &counter_database)
Definition: RunSimulation.hpp:76
std::map< std::string, pybind11::object > ProgramOptions
Definition: ProgramOptions.hpp:40
virtual bool ShallOutputNow(const GriddingAlgorithm &grid)=0
Returns true if this output class shall be invoked at the specified time point.
virtual Duration NextOutputTime(Duration time_point)=0
Returns the time point at which the simulation shall stop to do some output.
Definition: RunSimulation.hpp:46
double cfl
Definition: RunSimulation.hpp:63
RunOptions()=default
std::ptrdiff_t max_cycles
Definition: RunSimulation.hpp:61
int do_backup
Definition: RunSimulation.hpp:64
RunOptions(const ProgramOptions &vm)
void Print(Logger &log)
Definition: RunSimulation.hpp:51
Duration smallest_time_step_size
Definition: RunSimulation.hpp:62
Duration final_time
Definition: RunSimulation.hpp:60