forked from idaholab/moose
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add PID controller, refs idaholab#17271
Update tests Add resiliency to picard iteration fails Add integral windup reset
- Loading branch information
Showing
13 changed files
with
584 additions
and
1 deletion.
There are no files selected for viewing
23 changes: 23 additions & 0 deletions
23
framework/doc/content/source/controls/PIDTransientControl.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# PIDTransientControl | ||
|
||
The `PIDTransientControl` object is designed to use the principle of Proportional Integral Derivative control to either: | ||
- control a "Real" parameter from the input file rather than use the constant value specified in the input file. | ||
|
||
- modify the value of a postprocessor, used in a PostprocessorDirichletBC for example, rather than use the computed/received value | ||
|
||
|
||
This allows a simple 1D parametric optimization to make the output of a postprocessor match the `target` value. | ||
|
||
The parameter $C$ is replaced at every time step $n$, at time $t$, by: | ||
\begin{equation} | ||
C_{n} = C_{n-1} + K_{integral} \int_0^{t} pp(s) - target mathrm{d}s + K_{proportional} (pp(t) - target) + K_{derivative} \dfrac{pp(t) - target}{dt} | ||
\end{equation} | ||
|
||
with $pp(t)$ the value at time $t$ of the postprocessor that we are trying to match to the $target$ value and | ||
$K_{integral/proportional/derivative}$ the coefficients for the integral error, current error, and backward derivative respectively. | ||
|
||
!syntax parameters /Controls/PIDTransientControl | ||
|
||
!syntax inputs /Controls/PIDTransientControl | ||
|
||
!syntax children /Controls/PIDTransientControl |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
//* This file is part of the MOOSE framework | ||
//* https://www.mooseframework.org | ||
//* | ||
//* All rights reserved, see COPYRIGHT for full restrictions | ||
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT | ||
//* | ||
//* Licensed under LGPL 2.1, please see LICENSE for details | ||
//* https://www.gnu.org/licenses/lgpl-2.1.html | ||
|
||
#pragma once | ||
|
||
// moose includes | ||
#include "Control.h" | ||
|
||
/** | ||
* A time-dependent control of an input parameter or a postprocessor, which aims at | ||
* making a postprocessor match a desired value. | ||
*/ | ||
class PIDTransientControl : public Control | ||
{ | ||
public: | ||
/** | ||
* Class constructor | ||
* @param parameters Input parameters for this Control object | ||
*/ | ||
static InputParameters validParams(); | ||
|
||
PIDTransientControl(const InputParameters & parameters); | ||
|
||
virtual void execute() override; | ||
|
||
private: | ||
/// The current value of the target postprocessor | ||
const PostprocessorValue & _current; | ||
/// The target 1D time-dependent function for the postprocessor | ||
const Function & _target; | ||
/// Integral of the error | ||
Real _integral; | ||
/// The coefficient multiplying the integral of the error | ||
const Real _Kint; | ||
/// The coefficient multiplying the error | ||
const Real _Kpro; | ||
/// The coefficient multiplying the derivative of the error | ||
const Real _Kder; | ||
/// The time to start the PID controller on | ||
const Real _start_time; | ||
/// The time to stop using the PID controller on | ||
const Real _stop_time; | ||
/// Whether to reset the PID integral error when changing timestep, to limit its action to within coupling iterations | ||
const bool _reset_every_timestep; | ||
/// Whether to reset the PID integral error when the error crosses 0, to avoid windup | ||
const bool _reset_integral_windup; | ||
/// Saved value of the integral at the beginning of a timestep, to recover from a failed solve | ||
Real _integral_old; | ||
/// Saved value of the controlled parameter at the beginning of a timestep, to recover from a failed solve | ||
Real _value_old; | ||
/// the previous time step | ||
int _t_step_old; | ||
/// the previous value of the difference with the target, to detect changes of sign | ||
Real _old_delta; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
//* This file is part of the MOOSE framework | ||
//* https://www.mooseframework.org | ||
//* | ||
//* All rights reserved, see COPYRIGHT for full restrictions | ||
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT | ||
//* | ||
//* Licensed under LGPL 2.1, please see LICENSE for details | ||
//* https://www.gnu.org/licenses/lgpl-2.1.html | ||
|
||
// MOOSE includes | ||
#include "PIDTransientControl.h" | ||
#include "Function.h" | ||
#include "Transient.h" | ||
|
||
registerMooseObject("MooseApp", PIDTransientControl); | ||
|
||
InputParameters | ||
PIDTransientControl::validParams() | ||
{ | ||
InputParameters params = Control::validParams(); | ||
params.addClassDescription( | ||
"Sets the value of a 'Real' input parameter (or postprocessor) based on a Proportional Integral " | ||
"Derivative control of a postprocessor to match a target a target value."); | ||
params.addRequiredParam<PostprocessorName>( | ||
"postprocessor", "The postprocessor to watch for controlling the specified parameter."); | ||
params.addRequiredParam<FunctionName>("target", "The target value 1D time function for the postprocessor"); | ||
params.addRequiredParam<Real>("K_integral", "The coefficient multiplying the integral term"); | ||
params.addRequiredParam<Real>("K_proportional", "The coefficient multiplying the difference term"); | ||
params.addRequiredParam<Real>("K_derivative", "The coefficient multiplying the derivative term"); | ||
params.addParam<std::string>( | ||
"parameter", | ||
"The input parameter(s) to control. Specify a single parameter name and all " | ||
"parameters in all objects matching the name will be updated"); | ||
params.addParam<std::string>("parameter_pp", "The postprocessor to control. Should be accessed by reference by " | ||
"the objects depending on its value."); | ||
params.addParam<Real>("start_time", -std::numeric_limits<Real>::max(), "The time to start the PID controller at"); | ||
params.addParam<Real>("stop_time", std::numeric_limits<Real>::max(), "The time to stop the PID controller at"); | ||
params.addParam<bool>("reset_every_timestep", | ||
false, | ||
"Reset the PID integral when changing timestep, for coupling iterations within a timestep"); | ||
params.addParam<bool>("reset_integral_windup", | ||
true, | ||
"Reset the PID integral when the error crosses zero and the integral is larger than the error."); | ||
|
||
return params; | ||
} | ||
|
||
PIDTransientControl::PIDTransientControl(const InputParameters & parameters) | ||
: Control(parameters), | ||
_current(getPostprocessorValueByName(getParam<PostprocessorName>("postprocessor"))), | ||
_target(getFunction("target")), | ||
_Kint(getParam<Real>("K_integral")), | ||
_Kpro(getParam<Real>("K_proportional")), | ||
_Kder(getParam<Real>("K_derivative")), | ||
_start_time(getParam<Real>("start_time")), | ||
_stop_time(getParam<Real>("stop_time")), | ||
_reset_every_timestep(getParam<bool>("reset_every_timestep")), | ||
_reset_integral_windup(getParam<bool>("reset_integral_windup")) | ||
{ | ||
_integral = 0; | ||
|
||
// To keep the previous values if a multiapp coupling iteration fails | ||
_value_old = 0; | ||
_integral_old = 0; | ||
|
||
if (isParamValid("parameter") && isParamValid("parameter_pp")) | ||
paramError("parameter_pp", | ||
"Either a controllable parameter or a postprocessor to control should be specified, not both."); | ||
if (!isParamValid("parameter") && !isParamValid("parameter_pp")) | ||
mooseError("A parameter or a postprocessor to control should be specified."); | ||
if (isParamValid("parameter") && _reset_every_timestep) | ||
paramError("reset_every_timestep", | ||
"Resetting the PID every time step is only supported using controlled postprocessors"); | ||
} | ||
|
||
void | ||
PIDTransientControl::execute() | ||
{ | ||
Point dummy; | ||
|
||
if (_t >= _start_time && _t < _stop_time) | ||
{ | ||
// Get the current value of the controllable parameter | ||
Real value; | ||
if (isParamValid("parameter")) | ||
value = getControllableValue<Real>("parameter"); | ||
else | ||
value = getPostprocessorValueByName(getParam<std::string>("parameter_pp")); | ||
|
||
// Save integral and controlled value at each time step | ||
// if the solver fails, a smaller time step will be used but _t_step is unchanged | ||
if (_t_step != _t_step_old) | ||
{ | ||
// Reset the error integral if PID is only used within each timestep | ||
if (_reset_every_timestep) | ||
_integral = 0; | ||
|
||
_integral_old = _integral; | ||
_value_old = value; | ||
_t_step_old = _t_step; | ||
_old_delta = 0; | ||
} | ||
|
||
// If there were coupling/Picard iterations during the transient and they failed, | ||
// we need to reset the controlled value and the error integral to their initial value at the | ||
// beginning of the coupling process | ||
if (dynamic_cast<Transient *>(_app.getExecutioner())->picardSolve().numPicardIts() == 1) | ||
{ | ||
_integral = _integral_old; | ||
value = _value_old; | ||
} | ||
|
||
// Compute the delta between the current value of the postprocessor and the desired value | ||
Real delta = _current - _target.value(_t, dummy); | ||
|
||
// If desired, reset integral of the error if the error crosses zero | ||
if (_reset_integral_windup && delta * _old_delta < 0) | ||
{ | ||
_integral = 0; | ||
} | ||
|
||
// Compute the three error terms and add them to the controlled value | ||
_integral += delta * _dt; | ||
value += _Kint * _integral + _Kpro * delta; | ||
if (_dt > 0) | ||
value += _Kder * delta / _dt; | ||
|
||
if (isParamValid("parameter")) | ||
// Set the new value using the Control system | ||
setControllableValue<Real>("parameter", value); | ||
else | ||
// Set the new postprocessor value using the FE Problem | ||
_fe_problem.setPostprocessorValueByName(getParam<std::string>("parameter_pp"), value); | ||
|
||
// Keep track of the previous delta for integral windup control | ||
_old_delta = delta; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
time,integral | ||
0,0 | ||
1,1.2500000019024 | ||
2,1.5124999979718 | ||
3,1.6243749993119 | ||
4,1.6125312499924 | ||
5,1.5509359379194 | ||
6,1.4977500783125 | ||
7,1.4749414026996 | ||
8,1.4772067971694 | ||
9,1.4896228260422 | ||
10,1.5003986260823 | ||
11,1.5050484230471 | ||
12,1.5046166201441 | ||
13,1.5021139987568 | ||
14,1.4999308197787 | ||
15,1.4989829793333 | ||
16,1.4990649614658 | ||
17,1.4995693726957 | ||
18,1.5000116713998 | ||
19,1.5002048701164 | ||
20,1.5001893744816 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
time,integral,received_bc | ||
0,0,1.5 | ||
1,1.2499999929539,2.0250000147969 | ||
2,1.5125000086897,1.9987499965485 | ||
3,1.4993749983264,2.0000625000631 | ||
4,1.5000312500345,1.9999968749907 | ||
5,1.499998437495,2.0000001562513 | ||
6,1.5000000781256,1.9999999921874 | ||
7,1.4999999960937,2.0000000003906 | ||
8,1.5000000001953,1.9999999999805 | ||
9,1.4999999999902,2.000000000001 | ||
10,1.4999999999902,2.0000000000215 | ||
11,1.4999999999902,2.000000000042 | ||
12,1.500000000021,1.9999999999979 | ||
13,1.500000000021,1.9999999999538 | ||
14,1.4999999999769,2.0000000000023 | ||
15,1.4999999999769,2.0000000000508 | ||
16,1.5000000000254,1.9999999999975 | ||
17,1.5000000000254,1.9999999999441 | ||
18,1.4999999999721,2.0000000000028 | ||
19,1.5000000000014,1.9999999999999 | ||
20,1.5000000000014,1.9999999999969 |
22 changes: 22 additions & 0 deletions
22
test/tests/controls/pid_control/gold/picard_resets_out.csv
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
time,integral,received_bc | ||
0,0,0 | ||
1,2.0750000002998,3.15 | ||
1.5,2.3362499979628,3.6724999994903 | ||
2.5,2.0644374994832,3.1288750036185 | ||
3.5,1.6599031321169,2.3198062565912 | ||
4.5,1.3979110885044,1.7958221815498 | ||
5.5,1.3310591330534,1.6621182659777 | ||
6.5,1.3854461844374,1.7708923683484 | ||
7.5,1.4671972648003,1.9343945297591 | ||
8.5,1.5203866191641,2.0407732379705 | ||
9.5,1.5341285185424,2.0682570372176 | ||
10.5,1.5232481144013,2.0464962286063 | ||
11.5,1.5067278750744,2.0134557501487 | ||
12.5,1.4959298298578,1.9918596598765 | ||
13.5,1.4931057947564,1.9862115894847 | ||
14.5,1.4952820814815,1.9905641629481 | ||
15.5,1.4986203697672,1.9972407395323 | ||
16.5,1.5008124146255,2.0016248292351 | ||
17.5,1.5013926274845,2.0027852549683 | ||
18.5,1.5009574095391,2.0019148190721 | ||
19.5,1.5002828566841,2.0005657133767 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
time,integral,received_bc | ||
0,0,1.5 | ||
1,1.2499999929539,2.0250000147969 | ||
2,1.5125000086897,2.2487500035946 | ||
3,1.6243750013529,2.2250624991099 | ||
4,1.6125312496318,2.1018718718867 | ||
5,1.5509359359113,1.9955001538447 | ||
6,1.4977500772041,1.9498828031766 | ||
7,1.474941401493,1.9544135942976 | ||
8,1.4772067971532,1.9792456530392 | ||
9,1.489622826589,2.0007972528125 | ||
10,1.5003986263689,2.010096846459 | ||
11,1.5050484232342,2.0092332403195 | ||
12,1.5046166201597,2.0042279974022 | ||
13,1.5021139987112,1.9998616393671 | ||
14,1.4999308196738,1.9979659585993 | ||
15,1.4989829793008,1.998129922941 | ||
16,1.4990649614703,1.999138745426 | ||
17,1.4995693727126,2.0000233428318 | ||
18,1.5000116714148,2.0004097402504 | ||
19,1.5002048701266,2.0003787489593 | ||
20,1.5001893744798,2.0001754284 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
time,integral | ||
0,0 | ||
1,1.2500000019024 | ||
2,1.5124999979718 | ||
3,1.6243749993119 | ||
4,1.6125312499924 | ||
5,1.5509359379194 | ||
6,1.4977500783125 | ||
7,1.4749414026996 | ||
8,1.4772067971694 | ||
9,1.4896228260422 | ||
10,1.5003986260823 | ||
11,1.5050484230471 | ||
12,1.5046166201441 | ||
13,1.5021139987568 | ||
14,1.4999308197787 | ||
15,1.4989829793333 | ||
16,1.4990649614658 | ||
17,1.4995693726957 | ||
18,1.5000116713998 | ||
19,1.5002048701164 | ||
20,1.5001893744816 |
Oops, something went wrong.