OGS
FixedTimeStepping.cpp
Go to the documentation of this file.
1
13#include "FixedTimeStepping.h"
14
15#include <algorithm>
16#include <cassert>
17#include <limits>
18#include <numeric>
19
21
22namespace
23{
25NumLib::Time addTimeIncrement(std::vector<double>& delta_ts,
26 std::size_t const repeat, double const delta_t,
27 NumLib::Time const t_curr)
28{
29 auto const new_size = delta_ts.size() + repeat;
30 try
31 {
32 delta_ts.resize(new_size, delta_t);
33 }
34 catch (std::exception const& e)
35 {
37 "Resize of the time steps vector failed for the requested new size "
38 "{:d}. Probably there is not enough memory ({:g} GiB "
39 "requested).\nThrown exception: {:s}",
40 new_size,
41 new_size * sizeof(double) / 1024. / 1024. / 1024.,
42 e.what());
43 }
44
45 // Multiplying dt * repeat is not the same as in the current
46 // implementation of the time loop, where the dt's are added.
47 // Therefore the sum of all dt is taken here.
48 return std::accumulate(end(delta_ts) - repeat, end(delta_ts), t_curr);
49}
50} // namespace
51
52namespace NumLib
53{
54std::size_t findDeltatInterval(Time const& t_initial,
55 std::vector<double> const& delta_ts,
56 Time const& fixed_output_time)
57{
58 if (fixed_output_time < t_initial)
59 {
60 return std::numeric_limits<std::size_t>::max();
61 }
62
63 auto timestepper_time = t_initial;
64 for (std::size_t k = 0; k < delta_ts.size(); ++k)
65 {
66 if (timestepper_time <= fixed_output_time &&
67 fixed_output_time < timestepper_time + delta_ts[k])
68 {
69 return k;
70 }
71 timestepper_time += delta_ts[k];
72 }
73
74 return std::numeric_limits<std::size_t>::max();
75}
76
78 NumLib::Time const t_initial, NumLib::Time const t_end,
79 std::vector<double>& delta_ts,
80 std::vector<double> const& fixed_times_for_output)
81{
82 if (fixed_times_for_output.empty())
83 {
84 return;
85 }
86
87 if (auto lower_bound = std::lower_bound(
88 begin(fixed_times_for_output), end(fixed_times_for_output),
89 t_initial,
90 [](auto const time, NumLib::Time const& initial_time)
91 { return NumLib::Time(time) < initial_time; });
92 lower_bound != begin(fixed_times_for_output))
93 {
94 WARN(
95 "Request for output at times {}, but the simulation's start time "
96 "is {}. Output will be skipped.",
97 fmt::join(begin(fixed_times_for_output), lower_bound, ", "),
98 t_initial());
99 }
100
101 if (auto upper_bound =
102 std::upper_bound(begin(fixed_times_for_output),
103 end(fixed_times_for_output), t_end());
104 upper_bound != end(fixed_times_for_output))
105 {
106 WARN(
107 "Request for output at times {}, but simulation's end time is {}. "
108 "Output will be skipped.",
109 fmt::join(upper_bound, end(fixed_times_for_output), ", "),
110 t_end());
111 }
112
113 if (delta_ts.empty())
114 {
115 WARN("No timesteps specified.");
116 return;
117 }
118
119 // incorporate fixed output times into dts vector
120 for (auto const fixed_time_for_output : fixed_times_for_output)
121 {
122 auto const interval_number = findDeltatInterval(
123 t_initial, delta_ts, Time(fixed_time_for_output));
124 if (interval_number == std::numeric_limits<std::size_t>::max())
125 {
126 WARN("Did not find interval for fixed output time {}",
127 fixed_time_for_output);
128 continue;
129 }
130
131 auto const lower_bound = std::accumulate(
132 begin(delta_ts), begin(delta_ts) + interval_number, t_initial);
133 auto const upper_bound = lower_bound + delta_ts[interval_number];
134 // in order to use the comparison from struct Time
135 if (NumLib::Time(fixed_time_for_output) == lower_bound)
136 {
137 continue;
138 }
139 if (upper_bound == NumLib::Time(fixed_time_for_output))
140 {
141 continue;
142 }
143 delta_ts[interval_number] = fixed_time_for_output - lower_bound();
144
145 delta_ts.insert(delta_ts.begin() + interval_number + 1,
146 upper_bound() - fixed_time_for_output);
147 }
148}
149
151 double t0, double tn, std::vector<RepeatDtPair> const& repeat_dt_pairs,
152 std::vector<double> const& fixed_times_for_output)
153 : TimeStepAlgorithm(t0, tn)
154{
155 Time t_curr = _t_initial;
156
157 if (!areRepeatDtPairsValid(repeat_dt_pairs))
158 {
159 OGS_FATAL("FixedTimeStepping: Couldn't construct object from data");
160 }
161 for (auto const& [repeat, delta_t] : repeat_dt_pairs)
162 {
163 if (t_curr <= _t_end)
164 {
165 t_curr = addTimeIncrement(_dt_vector, repeat, delta_t, t_curr);
166 }
167 }
168
169 // append last delta_t until t_end is reached
170 if (t_curr <= _t_end)
171 {
172 auto const delta_t = std::get<1>(repeat_dt_pairs.back());
173 auto const repeat = static_cast<std::size_t>(
174 std::ceil((_t_end() - t_curr()) / delta_t));
175 addTimeIncrement(_dt_vector, repeat, delta_t, t_curr);
176 }
177
179 fixed_times_for_output);
180}
181
182FixedTimeStepping::FixedTimeStepping(double t0, double t_end, double dt)
183 : TimeStepAlgorithm(t0, t_end)
184{
185 auto const new_size =
186 static_cast<std::size_t>(std::ceil((t_end - t0) / dt));
187 try
188 {
189 _dt_vector = std::vector<double>(new_size, dt);
190 }
191 catch (std::length_error const& e)
192 {
193 OGS_FATAL(
194 "Resize of the time steps vector failed for the requested new "
195 "size {}. Probably there is not enough memory ({:g} GiB "
196 "requested).\n"
197 "Thrown exception: {}",
198 new_size, new_size * sizeof(double) / 1024. / 1024. / 1024.,
199 e.what());
200 }
201 catch (std::bad_alloc const& e)
202 {
203 OGS_FATAL(
204 "Allocation of the time steps vector failed for the requested "
205 "size {}. Probably there is not enough memory ({:g} GiB "
206 "requested).\n"
207 "Thrown exception: {}",
208 new_size,
209 new_size * sizeof(double) / 1024. / 1024. / 1024.,
210 e.what());
211 }
212}
213
214std::tuple<bool, double> FixedTimeStepping::next(
215 double const /*solution_error*/, int const /*number_iterations*/,
216 NumLib::TimeStep& /*ts_previous*/, NumLib::TimeStep& ts_current)
217{
218 // check if last time step
219 if (ts_current.timeStepNumber() == _dt_vector.size() ||
220 ts_current.current() >= end())
221 {
222 return std::make_tuple(true, 0.0);
223 }
224
225 double dt = _dt_vector[ts_current.timeStepNumber()];
226 if (ts_current.current() + dt > end())
227 { // upper bound by t_end
228 dt = end()() - ts_current.current()();
229 }
230
231 return std::make_tuple(true, dt);
232}
233
235 std::vector<RepeatDtPair> const& repeat_dt_pairs)
236{
237 if (repeat_dt_pairs.empty())
238 {
239 return false;
240 }
241
242 for (auto const& [repeat, delta_t] : repeat_dt_pairs)
243 {
244 if (repeat == 0)
245 {
246 ERR("FixedTimeStepping: <repeat> is zero.");
247 return false;
248 }
249 if (delta_t <= 0.0)
250 {
251 ERR("FixedTimeStepping: timestep <delta_t> is <= 0.0.");
252 return false;
253 }
254 }
255 return true;
256}
257
258} // namespace NumLib
#define OGS_FATAL(...)
Definition Error.h:26
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
std::tuple< bool, double > next(double solution_error, int number_iterations, NumLib::TimeStep &ts_previous, NumLib::TimeStep &ts_current) override
static bool areRepeatDtPairsValid(std::vector< RepeatDtPair > const &repeat_dt_pairs)
std::vector< double > _dt_vector
a vector of time step sizes
FixedTimeStepping(double t0, double t_end, double dt)
Interface of time stepping algorithms.
const Time _t_initial
initial time
Time end() const
return the end of time steps
Time step object.
Definition TimeStep.h:31
Time current() const
return current time step
Definition TimeStep.h:78
std::size_t timeStepNumber() const
the time step number
Definition TimeStep.h:82
void incorporateFixedTimesForOutput(NumLib::Time const t_initial, NumLib::Time const t_end, std::vector< double > &delta_ts, std::vector< double > const &fixed_times_for_output)
std::size_t findDeltatInterval(Time const &t_initial, std::vector< double > const &delta_ts, Time const &fixed_output_time)
NumLib::Time addTimeIncrement(std::vector< double > &delta_ts, std::size_t const repeat, double const delta_t, NumLib::Time const t_curr)
Returns sum of the newly added time increments.