OGS
IterationNumberBasedTimeStepping.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
6#include <algorithm>
7#include <cassert>
8#include <cmath>
9#include <limits>
10#include <utility>
11
12#include "BaseLib/Algorithm.h"
13#include "BaseLib/Error.h"
17
18namespace NumLib
19{
21 double const t_initial, double const t_end, double const min_dt,
22 double const max_dt, double const initial_dt,
23 MultiplyerInterpolationType const multiplier_interpolation_type,
24 std::vector<int>&& iter_times_vector,
25 std::vector<double>&& multiplier_vector,
26 std::vector<double> const& fixed_times_for_output)
27 : TimeStepAlgorithm(t_initial, t_end),
28 _iter_times_vector(std::move(iter_times_vector)),
29 _multiplier_vector(std::move(multiplier_vector)),
30 _min_dt(min_dt),
31 _max_dt(max_dt),
32 _initial_dt(initial_dt),
33 _multiplier_interpolation_type(multiplier_interpolation_type),
35 _fixed_times_for_output(fixed_times_for_output)
36{
37 if (_iter_times_vector.empty())
38 {
39 OGS_FATAL("Vector of iteration numbers must not be empty.");
40 }
41 if (_iter_times_vector.size() != _multiplier_vector.size())
42 {
43 OGS_FATAL(
44 "Vector of iteration numbers must be of the same size as the "
45 "vector of multipliers.");
46 }
47 if (!std::is_sorted(std::begin(_iter_times_vector),
48 std::end(_iter_times_vector)))
49 {
50 OGS_FATAL("Vector of iteration numbers must be sorted.");
51 }
52}
53
54double IterationNumberBasedTimeStepping::next(double const /*solution_error*/,
55 int const number_iterations,
56 NumLib::TimeStep& ts_previous,
57 NumLib::TimeStep& ts_current)
58{
59 _iter_times = number_iterations;
60
61 if (ts_previous.isAccepted())
62 {
63 ts_previous = ts_current;
64 }
65
66 // confirm current time and move to the next if accepted
67 if (ts_current.isAccepted())
68 {
69 ts_previous.setAccepted(true);
70 return getNextTimeStepSize(ts_previous, ts_current);
71 }
72
73 double dt = getNextTimeStepSize(ts_previous, ts_current);
74 // In case it is the first time be rejected, re-computed dt again with
75 // current dt
76 if (std::abs(dt - ts_current.dt()) < std::numeric_limits<double>::epsilon())
77 {
78 // time step was rejected, keep dt for the next dt computation.
79 ts_previous = // essentially equal to _ts_prev.dt = _ts_current.dt.
80 TimeStep{ts_previous.previous(), ts_previous.previous() + dt,
81 ts_previous.timeStepNumber()};
82 dt = getNextTimeStepSize(ts_previous, ts_current);
83 }
84
85 // time step was rejected, keep dt for the next dt computation.
86 ts_previous = // essentially equal to ts_previous.dt = _ts_current.dt.
87 TimeStep{ts_previous.previous(), ts_previous.previous() + dt,
88 ts_previous.timeStepNumber()};
89 ts_current = TimeStep{ts_current.previous(), ts_current.previous() + dt,
90 ts_current.timeStepNumber()};
91
92 return dt;
93}
94
96 int const number_iterations, bool const current_time_step_is_accepted,
97 std::vector<int> const& nonlinear_iteration_numbers,
98 std::vector<double> const& multipliers,
99 MultiplyerInterpolationType const multiplier_interpolation_type)
100{
101 double const multiplier = [&]
102 {
103 switch (multiplier_interpolation_type)
104 {
106 {
107 auto const& pwli = MathLib::PiecewiseLinearInterpolation(
108 nonlinear_iteration_numbers, multipliers, false);
109 return pwli.getValue(number_iterations);
110 }
112 {
113 auto const& piecewise_constant_interpolation =
115 nonlinear_iteration_numbers, multipliers);
116 return piecewise_constant_interpolation.value(
117 number_iterations);
118 }
119 }
120 OGS_FATAL("Unknown multiplier interpolation type.");
121 }();
122
123 if (!current_time_step_is_accepted && (multiplier >= 1.0))
124 {
125 return *std::min_element(multipliers.begin(), multipliers.end());
126 }
127
128 return multiplier;
129}
130
132 NumLib::TimeStep const& ts_previous,
133 NumLib::TimeStep const& ts_current) const
134{
135 double dt = 0.0;
136
137 // In first time step and first non-linear iteration take the initial dt.
138 if (ts_previous.timeStepNumber() == 0 && _iter_times == 0)
139 {
140 dt = _initial_dt;
141 }
142 else
143 {
144 // Attention: for the first time step and second iteration the
145 // ts_prev.dt is 0 and 0*multiplier is the next dt, which will be
146 // clamped to the minimum dt.
147 dt = ts_previous.dt() *
151 }
152
153 if (_fixed_times_for_output.empty())
154 {
155 return std::clamp(dt, _min_dt, _max_dt);
156 }
157
158 // restrict dt to _max_dt before taking fixed times for output into account
159 dt = std::min(dt, _max_dt);
160
161 // find first fixed timestep for output larger than the current time, i.e.,
162 // current time < fixed output time
163 auto fixed_output_time_it = std::find_if(
165 [&ts_current](auto const fixed_output_time)
166 { return ts_current.current()() < fixed_output_time; });
167
168 if (fixed_output_time_it != _fixed_times_for_output.end())
169 {
170 // check if the fixed output time is in the interval
171 // (current time, current time + dt)
172 if (*fixed_output_time_it < ts_current.current()() + dt)
173 {
174 // check if the potential adjusted time step is larger than zero
175 if (std::abs(*fixed_output_time_it - ts_current.current()()) >
176 std::numeric_limits<double>::epsilon() * ts_current.current()())
177 {
178 return *fixed_output_time_it - ts_current.current()();
179 }
180 }
181 }
182 return std::clamp(dt, _min_dt, _max_dt);
183}
184
186 NumLib::TimeStep const& timestep_previous,
187 NumLib::TimeStep const& timestep_current) const
188{
189 return NumLib::canReduceTimestepSize(timestep_previous, timestep_current,
190 _min_dt);
191}
192
193} // namespace NumLib
#define OGS_FATAL(...)
Definition Error.h:10
IterationNumberBasedTimeStepping(double const t_initial, double const t_end, double const min_dt, double const max_dt, double const initial_dt, MultiplyerInterpolationType const multiplier_interpolation_type, std::vector< int > &&iter_times_vector, std::vector< double > &&multiplier_vector, std::vector< double > const &fixed_times_for_output)
double next(double solution_error, int number_iterations, NumLib::TimeStep &ts_previous, NumLib::TimeStep &ts_current) override
const MultiplyerInterpolationType _multiplier_interpolation_type
Interpolation type for the multiplier.
double getNextTimeStepSize(NumLib::TimeStep const &ts_previous, NumLib::TimeStep const &ts_current) const
Calculate the next time step size.
const double _max_dt
The maximum allowed time step size.
const std::vector< double > _multiplier_vector
This vector stores the multiplier coefficients.
bool canReduceTimestepSize(NumLib::TimeStep const &timestep_previous, NumLib::TimeStep const &timestep_current) const override
Query the timestepper if further time step size reduction is possible.
int _iter_times
The number of nonlinear iterations.
const double _min_dt
The minimum allowed time step size.
const int _max_iter
The maximum allowed iteration number to accept current time step.
TimeStepAlgorithm(const double t0, const double t_end)
Time step object.
Definition TimeStep.h:24
void setAccepted(bool const accepted)
Definition TimeStep.h:77
Time current() const
return current time step
Definition TimeStep.h:71
bool isAccepted() const
Definition TimeStep.h:78
Time previous() const
return previous time step
Definition TimeStep.h:69
double dt() const
time step size from _previous
Definition TimeStep.h:73
std::size_t timeStepNumber() const
the time step number
Definition TimeStep.h:75
double findMultiplier(int const number_iterations, bool const current_time_step_is_accepted, std::vector< int > const &nonlinear_iteration_numbers, std::vector< double > const &multipliers, MultiplyerInterpolationType const multiplier_interpolation_type)
Find a multiplier for the given number of iterations.
bool canReduceTimestepSize(TimeStep const &timestep_previous, TimeStep const &timestep_current, double const min_dt)