OGS
NumLib::EvolutionaryPIDcontroller Class Referencefinal

Detailed Description

This class gives an adaptive algorithm whose time step control is evolutionary PID controller. With an definition of relative solution change \(e_n=\frac{\|u^{n+1}-u^n\|}{\|u^{n+1}\|}\), the algorithm gives a time step size estimation as

\[ h_{n+1} = \left(\frac{e_{n-1}}{e_n}\right)^{k_P} \left(\frac{TOL}{e_n}\right)^{k_I} \left(\frac{e^2_{n-1}}{e_n e_{n-2}}\right)^{k_D} \]

where \(k_P=0.075\), \(k_I=0.175\), \(k_D=0.01\) are empirical PID parameters.

In the computation, \( e_n\) is calculated firstly. If \(e_n>TOL\), the current time step is rejected and repeated with a new time step size of \(h=\frac{TOL}{e_n} h_n\).

Limits of the time step size are given as

\[ h_{\mbox{min}} \leq h_{n+1} \leq h_{\mbox{max}}, l \leq \frac{h_{n+1}}{h_n} \leq L \]

Similar algorithm can be found in [1] .

Definition at line 46 of file EvolutionaryPIDcontroller.h.

#include <EvolutionaryPIDcontroller.h>

Inheritance diagram for NumLib::EvolutionaryPIDcontroller:
[legend]
Collaboration diagram for NumLib::EvolutionaryPIDcontroller:
[legend]

Public Member Functions

 EvolutionaryPIDcontroller (const double t0, const double t_end, const double h0, const double h_min, const double h_max, const double rel_h_min, const double rel_h_max, const double tol, std::vector< double > const &fixed_times_for_output)
 
std::tuple< bool, double > next (double solution_error, int number_iterations, NumLib::TimeStep &timestep_previous, NumLib::TimeStep &timestep_current) override
 
bool isSolutionErrorComputationNeeded () const override
 
virtual 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.
 
- Public Member Functions inherited from NumLib::TimeStepAlgorithm
 TimeStepAlgorithm (const double t0, const double t_end)
 
virtual ~TimeStepAlgorithm ()=default
 
Time begin () const
 return the beginning of time steps
 
Time end () const
 return the end of time steps
 
virtual void resetCurrentTimeStep (const double, TimeStep &, TimeStep &)
 reset the current step size from the previous time
 

Private Member Functions

double limitStepSize (const double h_new, const bool previous_step_accepted, NumLib::TimeStep const &timestep_current) const
 

Private Attributes

const double _kP = 0.075
 Parameter.
 
const double _kI = 0.175
 Parameter.
 
const double _kD = 0.01
 Parameter.
 
const double _h0
 initial time step size.
 
const double _h_min
 minimum step size.
 
const double _h_max
 maximum step size.
 
const double _rel_h_min
 \(l\) in \( h_{\mbox{min}} \leq h_{n+1} \leq h_{\mbox{max}},\)
 
const double _rel_h_max
 \(L\) in \( h_{\mbox{min}} \leq h_{n+1} \leq h_{\mbox{max}},\)
 
const double _tol
 
double _e_n_minus1
 \(e_{n-1}\).
 
double _e_n_minus2
 \(e_{n-2}\).
 
std::vector< double > const _fixed_times_for_output
 

Additional Inherited Members

- Protected Attributes inherited from NumLib::TimeStepAlgorithm
const Time _t_initial
 initial time
 
const Time _t_end
 end time
 

Constructor & Destructor Documentation

◆ EvolutionaryPIDcontroller()

NumLib::EvolutionaryPIDcontroller::EvolutionaryPIDcontroller ( const double t0,
const double t_end,
const double h0,
const double h_min,
const double h_max,
const double rel_h_min,
const double rel_h_max,
const double tol,
std::vector< double > const & fixed_times_for_output )
inline

Definition at line 49 of file EvolutionaryPIDcontroller.h.

54 : TimeStepAlgorithm(t0, t_end),
55 _h0(h0),
56 _h_min(h_min),
57 _h_max(h_max),
58 _rel_h_min(rel_h_min),
59 _rel_h_max(rel_h_max),
60 _tol(tol),
61 _e_n_minus1(0.),
62 _e_n_minus2(0.),
63 _fixed_times_for_output(fixed_times_for_output)
64 {
65 }
const double _h_max
maximum step size.
std::vector< double > const _fixed_times_for_output
const double _h_min
minimum step size.
const double _h0
initial time step size.
TimeStepAlgorithm(const double t0, const double t_end)

Member Function Documentation

◆ canReduceTimestepSize()

bool NumLib::EvolutionaryPIDcontroller::canReduceTimestepSize ( NumLib::TimeStep const & ,
NumLib::TimeStep const &  ) const
overridevirtual

Query the timestepper if further time step size reduction is possible.

Reimplemented from NumLib::TimeStepAlgorithm.

Definition at line 171 of file EvolutionaryPIDcontroller.cpp.

174{
175 return NumLib::canReduceTimestepSize(timestep_previous, timestep_current,
176 _h_min);
177}
bool canReduceTimestepSize(TimeStep const &timestep_previous, TimeStep const &timestep_current, double const min_dt)

References _h_min, and NumLib::canReduceTimestepSize().

◆ isSolutionErrorComputationNeeded()

bool NumLib::EvolutionaryPIDcontroller::isSolutionErrorComputationNeeded ( ) const
inlineoverridevirtual

Get a flag to indicate whether this algorithm needs to compute solution error. The default return value is false.

Reimplemented from NumLib::TimeStepAlgorithm.

Definition at line 72 of file EvolutionaryPIDcontroller.h.

72{ return true; }

◆ limitStepSize()

double NumLib::EvolutionaryPIDcontroller::limitStepSize ( const double h_new,
const bool previous_step_accepted,
NumLib::TimeStep const & timestep_current ) const
private

Force the computed time step size in the given range (see the formulas in the documentation of the class) or use the half of the previous time step size under some other constrains.

Parameters
h_newThe computed time step size.
previous_step_acceptedAn indicator for whether the previous time step is rejected.
timestep_currentthe current time step
Returns
The new time step after apply the constrains.

Definition at line 105 of file EvolutionaryPIDcontroller.cpp.

108{
109 const double h_n = timestep_current.dt();
110 // Forced the computed time step size in the given range
111 // (see the formulas in the documentation of the class)
112 const double h_in_range = std::max(_h_min, std::min(h_new, _h_max));
113 // Limit the step size change ratio.
114 double limited_h =
115 std::max(_rel_h_min * h_n, std::min(h_in_range, _rel_h_max * h_n));
116
117 if (!previous_step_accepted)
118 {
119 // If the last time step was rejected and the new predicted time step
120 // size is identical to that of the previous rejected step, the new
121 // step size is then reduced by half.
122 if (std::abs(limited_h - timestep_current.dt()) <
123 std::numeric_limits<double>::min())
124 {
125 limited_h = std::max(_h_min, 0.5 * limited_h);
126 }
127
128 // If the last time step was rejected and the new predicted time step
129 // size is larger than the step size of the rejected step, the new step
130 // size takes the half of the size of the rejected step. This could
131 // happen when a time step is rejected due to a diverged non-linear
132 // solver. In such case, this algorithm may give a large time step size
133 // by using the diverged solution.
134 if (limited_h > timestep_current.dt())
135 {
136 limited_h = std::max(_h_min, 0.5 * timestep_current.dt());
137 }
138 }
139
140 if (_fixed_times_for_output.empty())
141 {
142 return limited_h;
143 }
144
145 // find first fixed output time larger than the current time, i.e.,
146 // current time < fixed output time
147 auto fixed_output_time_it = std::find_if(
149 [&timestep_current](auto const fixed_output_time)
150 { return timestep_current.current() < Time{fixed_output_time}; });
151
152 if (fixed_output_time_it != _fixed_times_for_output.end())
153 {
154 // check if the fixed output time is in the interval
155 // (current time, current time + limited_h)
156 if (Time{*fixed_output_time_it} <
157 timestep_current.current() + limited_h)
158 {
159 // check if the potential adjusted time step is larger than zero
160 if (std::abs(*fixed_output_time_it - timestep_current.current()()) >
161 std::numeric_limits<double>::epsilon() *
162 timestep_current.current()())
163 {
164 return *fixed_output_time_it - timestep_current.current()();
165 }
166 }
167 }
168 return limited_h;
169}

References _fixed_times_for_output, _h_max, _h_min, _rel_h_max, _rel_h_min, NumLib::TimeStep::current(), and NumLib::TimeStep::dt().

Referenced by next().

◆ next()

std::tuple< bool, double > NumLib::EvolutionaryPIDcontroller::next ( double solution_error,
int number_iterations,
NumLib::TimeStep & ts_previous,
NumLib::TimeStep & ts_current )
overridevirtual

Move to the next time step

Parameters
solution_errorSolution error \(e_n\) between two successive time steps.
number_iterationsNumber of non-linear iterations used.
ts_previousthe previous time step used to compute the size of the next step
ts_currentthe current time step used to compute the size of the next step
Returns
A step acceptance flag and the computed step size.

Implements NumLib::TimeStepAlgorithm.

Definition at line 23 of file EvolutionaryPIDcontroller.cpp.

26{
27 const bool is_previous_step_accepted = timestep_current.isAccepted();
28
29 const double e_n = solution_error;
30 const double zero_threshold = std::numeric_limits<double>::epsilon();
31 // step rejected.
32 if (e_n > _tol)
33 {
34 timestep_current.setAccepted(false);
35
36 double h_new = (e_n > zero_threshold)
37 ? timestep_current.dt() * _tol / e_n
38 : 0.5 * timestep_current.dt();
39
40 h_new =
41 limitStepSize(h_new, is_previous_step_accepted, timestep_current);
42
43 WARN(
44 "This step is rejected due to the relative change from the"
45 " solution of the previous\n"
46 "\t time step to the current solution exceeds the given tolerance"
47 " of {:g}.\n"
48 "\t This time step will be repeated with a new time step size of"
49 " {:g}\n"
50 "\t or the simulation will be halted.",
51 _tol, h_new);
52
53 return std::make_tuple(timestep_current.isAccepted(), h_new);
54 }
55
56 // step accepted.
57 timestep_current.setAccepted(true);
58
59 if (timestep_current.timeStepNumber() == 0)
60 {
61 _e_n_minus1 = e_n;
62
63 return std::make_tuple(timestep_current.isAccepted(), _h0);
64 }
65 else
66 {
67 const double h_n = timestep_current.dt();
68 double h_new = h_n;
69
70 if (e_n > zero_threshold)
71 {
72 if (_e_n_minus1 > zero_threshold)
73 {
74 if (_e_n_minus2 > zero_threshold)
75 {
76 h_new = std::pow(_e_n_minus1 / e_n, _kP) *
77 std::pow(_tol / e_n, _kI) *
78 std::pow(
80 _kD) *
81 h_n;
82 }
83 else
84 {
85 h_new = std::pow(_e_n_minus1 / e_n, _kP) *
86 std::pow(_tol / e_n, _kI) * h_n;
87 }
88 }
89 else
90 {
91 h_new = std::pow(_tol / e_n, _kI) * h_n;
92 }
93 }
94
95 h_new =
96 limitStepSize(h_new, is_previous_step_accepted, timestep_current);
97
99 _e_n_minus1 = e_n;
100
101 return std::make_tuple(timestep_current.isAccepted(), h_new);
102 }
103}
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
double limitStepSize(const double h_new, const bool previous_step_accepted, NumLib::TimeStep const &timestep_current) const

References _e_n_minus1, _e_n_minus2, _h0, _kD, _kI, _kP, _tol, NumLib::TimeStep::dt(), NumLib::TimeStep::isAccepted(), limitStepSize(), NumLib::TimeStep::setAccepted(), NumLib::TimeStep::timeStepNumber(), and WARN().

Member Data Documentation

◆ _e_n_minus1

double NumLib::EvolutionaryPIDcontroller::_e_n_minus1
private

\(e_{n-1}\).

Definition at line 94 of file EvolutionaryPIDcontroller.h.

Referenced by next().

◆ _e_n_minus2

double NumLib::EvolutionaryPIDcontroller::_e_n_minus2
private

\(e_{n-2}\).

Definition at line 95 of file EvolutionaryPIDcontroller.h.

Referenced by next().

◆ _fixed_times_for_output

std::vector<double> const NumLib::EvolutionaryPIDcontroller::_fixed_times_for_output
private

Definition at line 97 of file EvolutionaryPIDcontroller.h.

Referenced by limitStepSize().

◆ _h0

const double NumLib::EvolutionaryPIDcontroller::_h0
private

initial time step size.

Definition at line 83 of file EvolutionaryPIDcontroller.h.

Referenced by next().

◆ _h_max

const double NumLib::EvolutionaryPIDcontroller::_h_max
private

maximum step size.

Definition at line 85 of file EvolutionaryPIDcontroller.h.

Referenced by limitStepSize().

◆ _h_min

const double NumLib::EvolutionaryPIDcontroller::_h_min
private

minimum step size.

Definition at line 84 of file EvolutionaryPIDcontroller.h.

Referenced by canReduceTimestepSize(), and limitStepSize().

◆ _kD

const double NumLib::EvolutionaryPIDcontroller::_kD = 0.01
private

Parameter.

See also
EvolutionaryPIDcontroller

Definition at line 81 of file EvolutionaryPIDcontroller.h.

Referenced by next().

◆ _kI

const double NumLib::EvolutionaryPIDcontroller::_kI = 0.175
private

Parameter.

See also
EvolutionaryPIDcontroller

Definition at line 80 of file EvolutionaryPIDcontroller.h.

Referenced by next().

◆ _kP

const double NumLib::EvolutionaryPIDcontroller::_kP = 0.075
private

Parameter.

See also
EvolutionaryPIDcontroller

Definition at line 79 of file EvolutionaryPIDcontroller.h.

Referenced by next().

◆ _rel_h_max

const double NumLib::EvolutionaryPIDcontroller::_rel_h_max
private

\(L\) in \( h_{\mbox{min}} \leq h_{n+1} \leq h_{\mbox{max}},\)

Definition at line 90 of file EvolutionaryPIDcontroller.h.

Referenced by limitStepSize().

◆ _rel_h_min

const double NumLib::EvolutionaryPIDcontroller::_rel_h_min
private

\(l\) in \( h_{\mbox{min}} \leq h_{n+1} \leq h_{\mbox{max}},\)

Definition at line 88 of file EvolutionaryPIDcontroller.h.

Referenced by limitStepSize().

◆ _tol

const double NumLib::EvolutionaryPIDcontroller::_tol
private

Definition at line 92 of file EvolutionaryPIDcontroller.h.

Referenced by next().


The documentation for this class was generated from the following files: