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
20namespace
21{
23double addTimeIncrement(std::vector<double>& delta_ts, std::size_t const repeat,
24 double const delta_t, double const t_curr)
25{
26 auto const new_size = delta_ts.size() + repeat;
27 try
28 {
29 delta_ts.resize(new_size, delta_t);
30 }
31 catch (std::exception const& e)
32 {
34 "Resize of the time steps vector failed for the requested new size "
35 "{:d}. Probably there is not enough memory ({:g} GiB "
36 "requested).\nThrown exception: {:s}",
37 new_size,
38 new_size * sizeof(double) / 1024. / 1024. / 1024.,
39 e.what());
40 }
41
42 // Multiplying dt * repeat is not the same as in the current
43 // implementation of the time loop, where the dt's are added.
44 // Therefore the sum of all dt is taken here.
45 return std::accumulate(end(delta_ts) - repeat, end(delta_ts), t_curr);
46}
47} // namespace
48
49namespace NumLib
50{
51std::size_t findDeltatInterval(double const t_initial,
52 std::vector<double> const& delta_ts,
53 double const fixed_output_time)
54{
55 if (fixed_output_time < t_initial)
56 {
57 return std::numeric_limits<std::size_t>::max();
58 }
59
60 auto timestepper_time = t_initial;
61 for (std::size_t k = 0; k < delta_ts.size(); ++k)
62 {
63 if (timestepper_time <= fixed_output_time &&
64 fixed_output_time < timestepper_time + delta_ts[k])
65 {
66 return k;
67 }
68 timestepper_time += delta_ts[k];
69 }
70
71 return std::numeric_limits<std::size_t>::max();
72}
73
75 double const t_initial, double const t_end, std::vector<double>& delta_ts,
76 std::vector<double> const& fixed_times_for_output)
77{
78 if (fixed_times_for_output.empty())
79 {
80 return;
81 }
82
83 if (auto lower_bound =
84 std::lower_bound(begin(fixed_times_for_output),
85 end(fixed_times_for_output), t_initial);
86 lower_bound != begin(fixed_times_for_output))
87 {
88 WARN(
89 "Request for output at times {}, but the simulation's start time "
90 "is {}. Output will be skipped.",
91 fmt::join(begin(fixed_times_for_output), lower_bound, ", "),
92 t_initial);
93 }
94
95 if (auto upper_bound = std::upper_bound(begin(fixed_times_for_output),
96 end(fixed_times_for_output), t_end);
97 upper_bound != end(fixed_times_for_output))
98 {
99 WARN(
100 "Request for output at times {}, but simulation's end time is {}. "
101 "Output will be skipped.",
102 fmt::join(upper_bound, end(fixed_times_for_output), ", "),
103 t_end);
104 }
105
106 if (delta_ts.empty())
107 {
108 WARN("No timesteps specified.");
109 return;
110 }
111
112 // incorporate fixed output times into dts vector
113 for (auto const fixed_time_for_output : fixed_times_for_output)
114 {
115 auto const interval_number =
116 findDeltatInterval(t_initial, delta_ts, fixed_time_for_output);
117 if (interval_number == std::numeric_limits<std::size_t>::max())
118 {
119 WARN("Did not find interval for fixed output time {}",
120 fixed_time_for_output);
121 continue;
122 }
123 auto const lower_bound = std::accumulate(
124 begin(delta_ts), begin(delta_ts) + interval_number, t_initial);
125 auto const upper_bound = lower_bound + delta_ts[interval_number];
126 if (fixed_time_for_output - lower_bound <=
127 std::numeric_limits<double>::epsilon())
128 {
129 continue;
130 }
131 if (upper_bound - fixed_time_for_output <=
132 std::numeric_limits<double>::epsilon())
133 {
134 continue;
135 }
136 delta_ts[interval_number] = fixed_time_for_output - lower_bound;
137
138 delta_ts.insert(delta_ts.begin() + interval_number + 1,
139 upper_bound - fixed_time_for_output);
140 }
141}
142
144 double t0, double tn,
145 std::vector<std::pair<std::size_t, double>> const& repeat_dt_pairs,
146 std::vector<double> const& fixed_times_for_output)
147 : TimeStepAlgorithm(t0, tn)
148{
149 double t_curr = _t_initial;
150
151 for (auto const& [repeat, delta_t] : repeat_dt_pairs)
152 {
153 if (repeat == 0)
154 {
155 OGS_FATAL("<repeat> is zero.");
156 }
157 if (delta_t <= 0.0)
158 {
159 OGS_FATAL("timestep <delta_t> is <= 0.0.");
160 }
161
162 if (t_curr <= _t_end)
163 {
164 t_curr = addTimeIncrement(_dt_vector, repeat, delta_t, t_curr);
165 }
166 }
167
168 // append last delta_t until t_end is reached
169 if (t_curr <= _t_end)
170 {
171 auto const delta_t = repeat_dt_pairs.back().second;
172 auto const repeat =
173 static_cast<std::size_t>(std::ceil((_t_end - t_curr) / delta_t));
174 addTimeIncrement(_dt_vector, repeat, delta_t, t_curr);
175 }
176
178 fixed_times_for_output);
179}
180
181FixedTimeStepping::FixedTimeStepping(double t0, double t_end, double dt)
182 : TimeStepAlgorithm(t0, t_end)
183{
184 auto const new_size =
185 static_cast<std::size_t>(std::ceil((t_end - t0) / dt));
186 try
187 {
188 _dt_vector = std::vector<double>(new_size, dt);
189 }
190 catch (std::length_error const& e)
191 {
192 OGS_FATAL(
193 "Resize of the time steps vector failed for the requested new "
194 "size {}. Probably there is not enough memory ({:g} GiB "
195 "requested).\n"
196 "Thrown exception: {}",
197 new_size, new_size * sizeof(double) / 1024. / 1024. / 1024.,
198 e.what());
199 }
200 catch (std::bad_alloc const& e)
201 {
202 OGS_FATAL(
203 "Allocation of the time steps vector failed for the requested "
204 "size {}. Probably there is not enough memory ({:g} GiB "
205 "requested).\n"
206 "Thrown exception: {}",
207 new_size,
208 new_size * sizeof(double) / 1024. / 1024. / 1024.,
209 e.what());
210 }
211}
212
213std::tuple<bool, double> FixedTimeStepping::next(
214 double const /*solution_error*/, int const /*number_iterations*/,
215 NumLib::TimeStep& /*ts_previous*/, NumLib::TimeStep& ts_current)
216{
217 // check if last time step
218 if (ts_current.timeStepNumber() == _dt_vector.size() ||
219 std::abs(ts_current.current() - end()) <
220 std::numeric_limits<double>::epsilon())
221 {
222 return std::make_tuple(false, 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
234} // namespace NumLib
#define OGS_FATAL(...)
Definition Error.h:26
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
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 double _t_initial
initial time
const double _t_end
end time
double end() const
return the end of time steps
Time step object.
Definition TimeStep.h:28
double current() const
return current time step
Definition TimeStep.h:90
std::size_t timeStepNumber() const
the time step number
Definition TimeStep.h:94
void incorporateFixedTimesForOutput(double const t_initial, double const t_end, std::vector< double > &delta_ts, std::vector< double > const &fixed_times_for_output)
std::size_t findDeltatInterval(double const t_initial, std::vector< double > const &delta_ts, double const fixed_output_time)
double addTimeIncrement(std::vector< double > &delta_ts, std::size_t const repeat, double const delta_t, double const t_curr)
Returns sum of the newly added time increments.