Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added several chain controls #29161

Merged
merged 14 commits into from
Dec 4, 2024
Merged
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# GetFunctionValueChainControl

This [ChainControl](syntax/ChainControls/index.md) creates a new [/ChainControlData.md]
named `<control>:value`, where `<control>` is the name of the `ChainControl`
object, and it computes its value by evaluating a given [Function](syntax/Functions/index.md)
named `<control>:value`, where `<control>` is the user-given name of the `GetFunctionValueChainControl`,
and it computes its value by evaluating a given [Function](syntax/Functions/index.md)
at the current time and a given point in space.

!syntax parameters /ChainControls/GetFunctionValueChainControl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This [ChainControl](syntax/ChainControls/index.md) copies the current value of a
[Postprocessor](syntax/Postprocessors/index.md) into a [/ChainControlData.md] of
type `Real`. This data will be named as `<control>:value`, where `<control>`
is the user-given name of the control, unless
is the user-given name of the `GetPostprocessorChainControl`, unless
[!param](/ChainControls/GetPostprocessorChainControl/name_data_same_as_postprocessor)
is set to `true`, in which case the data is named the same as the post-processor.

Expand Down
12 changes: 12 additions & 0 deletions framework/doc/content/source/chaincontrols/LimitChainControl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# LimitChainControl

This [ChainControl](syntax/ChainControls/index.md) allows the user to apply
a minimum and maximum value to a [chain control value](/ChainControlData.md).
The resulting value is named `<control>:value`, where `<control>` is the
user-given name of the `LimitChainControl`.

!syntax parameters /ChainControls/LimitChainControl

!syntax inputs /ChainControls/LimitChainControl

!syntax children /ChainControls/LimitChainControl
64 changes: 64 additions & 0 deletions framework/doc/content/source/chaincontrols/PIDChainControl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# PIDChainControl

This [ChainControl](syntax/ChainControls/index.md) implements the classic PID controller, which takes as its input
a value $x$ and the set point for that value, $\bar{x}$. It produces an output
signal $y$, which should be used as the input for some controllable device that
impacts the measured quantity $x$. For example, in a thermal system, $x$ may
be the temperature of a fluid at some location, and $y$ may be the power sent
to the heaters in the system, with the goal to heat the fluid such that the
temperature at some location is $\bar{x}$.

"PID" stands for its three components:

- P: Proportional
- I: Integral
- D: Derivative

The output signal $y$ at time $t_n$ is computed as follows:

!equation
y_n = K_p e_n + K_i \sum\limits_{m=1}^n e_m \Delta t_m + K_d \frac{e_n - e_{n-1}}{\Delta t_n} \,,

where $\Delta t_n \equiv t_n - t_{n-1}$ is the time step size and
$e_n$ is the error:

!equation
e_n \equiv \bar{x}_n - x_n \,.

!alert warning title=Execute only once per time step
The implementation assumes that the control will only be executed once per
time step, so you should set [!param](/ChainControls/PIDChainControl/execute_on) accordingly,
such as `execute_on = 'INITIAL TIMESTEP_END'`, which is the default.

The inputs and outputs are retrieved and named as follows, respectively:

- $x$ is set with [!param](/ChainControls/PIDChainControl/input).
- $\bar{x}$ is set with [!param](/ChainControls/PIDChainControl/set_point).
- $y$ is declared with the name `<control_name>:value`, where `<control_name>`
is the user-given name of the `PIDChainControl`.

!alert tip title=Tuning PID coefficients
If you are unsure on how to select the PID coefficients $K_p$, $K_i$, and $K_d$,
you may try the following strategy, which involves some trial and error. First,
set $K_i$ and $K_d$ to zero. Then, set $K_p$ to some arbitrary (positive) value.
Run a simulation with $x_0 \neq \bar{x}$ and examine the transient response of $x$
to the set point value $\bar{x}$. The goal should be to maximize $K_p$ without
causing an unstable response, where $x$ oscillates indefinitely around $\bar{x}$.
Some initial overshoot and subsequent diminishing oscillations are acceptable.
After this acceptable value of $K_p$ is found, you'll likely find that $x$ appears
to be nearly constant in time, but at the wrong value. At this point, you should
start increasing $K_i$ from zero until you get an acceptable response time to
get the initial response (largely driven by $K_p$) to bridge the gap to $\bar{x}$,
without introducing oscillatory behavior. Lastly, $K_d$ can be used to fine-tune
the response, but it is not necessary, and it risks some oscillatory behavior
if the inputs have any noise, so it should only be used for relatively smooth
inputs.

!alert note
To control a controllable value directly instead of using a [ChainControlData.md], use [PIDTransientControl.md].

!syntax parameters /ChainControls/PIDChainControl

!syntax inputs /ChainControls/PIDChainControl

!syntax children /ChainControls/PIDChainControl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This [ChainControl](syntax/ChainControls/index.md) allows the user to specify
a function expression to be parsed and evaluated to populate a new [/ChainControlData.md]
named `<control>:value`, where `<control>` is the user-given name of the control.
named `<control>:value`, where `<control>` is the user-given name of the `ParsedChainControl`.

See [ChainControlParsedFunctionWrapper.md] for a list of acceptable types of
values for the entries in [!param](/ChainControls/ParsedChainControl/symbol_values)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# RealToBoolChainControl

This [ChainControl](syntax/ChainControls/index.md) converts a `Real`-valued
[chain control data](/ChainControlData.md) to a `bool` data, with the name
`<control>:value`, where `<control>` is the user-given name of the `RealToBoolChainControl`:

- A value of 1 converts to `true`.
- A value of 0 converts to `false`.
- Other values result in an error.

joshuahansel marked this conversation as resolved.
Show resolved Hide resolved
Note that the tolerance on the value is 1e-12 in a double-precision MOOSE build.

!syntax parameters /ChainControls/RealToBoolChainControl

!syntax inputs /ChainControls/RealToBoolChainControl

!syntax children /ChainControls/RealToBoolChainControl
35 changes: 35 additions & 0 deletions framework/doc/content/source/chaincontrols/ScaleOldChainControl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# ScaleOldChainControl

This [ChainControl](syntax/ChainControls/index.md) allows the user to scale
the previous time value for a [chain control data](/ChainControlData.md)
by another chain control data.
The resulting value is named `<control>:value`, where `<control>` is the
user-given name of the `ScaleOldChainControl`.
The chain control data to scale may be the
same chain control data created by this `ChainControl`, or it may be another.

This `ChainControl` is useful for applying corrections to simulation quantities.
For example, suppose the objective is to tune a heat transfer coefficient such
that the resulting cooling power, which we calculate using a [Postprocessor](Postprocessors/index.md) `simulated_power`,
matches an experimentally measured power, given in a `Postprocessor` `experiment_power`.
One provides an initial guess for the heat transfer coefficient [!param](/ChainControls/ScaleOldChainControl/initial_value).
The heat transfer coefficient in the boundary condition is controlled using a
[SetValueChainControl.md]. The `Postprocessor` `simulated_power` is computed
using a numerical integral over the boundary, and then a [GetPostprocessorChainControl.md]
is used to copy each of `simulated_power` and `experiment_power`. A
[ParsedChainControl.md] is used to compute a scaling factor as `experiment_power / simulated_power`.
This value is then used in [!param](/ChainControls/ScaleOldChainControl/scale_factor).
To keep the scaled value in a physical range (for instance, the heat transfer
coefficient should be a positive value), one may use a [LimitChainControl.md].
This is important, for example, because often there is noise in experimental data,
and the response time of the controlled quantity may vary. This limited
heat transfer coefficient chain control data is the one that should be used with
the `SetValueChainControl`, so it should also be the one used in
[!param](/ChainControls/ScaleOldChainControl/control_data). If there were no
limitation step, then this parameter would be set to `<control>:value`.

!syntax parameters /ChainControls/ScaleOldChainControl

!syntax inputs /ChainControls/ScaleOldChainControl

!syntax children /ChainControls/ScaleOldChainControl
20 changes: 20 additions & 0 deletions framework/doc/content/source/chaincontrols/SmootherChainControl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SmootherChainControl

This [ChainControl](syntax/ChainControls/index.md) smooths an input signal using a moving average.
The $n$ most recent values are used to compute the average $\bar{y}$ of the input
values $y$:

!equation
\bar{y}_i = \frac{1}{n} \Sigma\limits_{k=i-n+1}^i y_i

where $i$ represents the time index.

The resulting value is named `<control>:value`, where `<control>` is the
user-given name of the `SmootherChainControl`.
The number of points to average, $n$, is provided with [!param](/ChainControls/SmootherChainControl/n_points).

!syntax parameters /ChainControls/SmootherChainControl

!syntax inputs /ChainControls/SmootherChainControl

!syntax children /ChainControls/SmootherChainControl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# TerminateChainControl

This [ChainControl](syntax/ChainControls/index.md) terminates the simulation
when a boolean [chain control data](/ChainControlData.md) has a given value.
The simulation may be terminated either by throwing an error or by signalling
to the [problem](/FEProblemBase.md) to terminate. This behavior is controlled
with the parameter [!param](/ChainControls/TerminateChainControl/throw_error).

!alert note title=The Terminator user object
An alternative way to terminate a simulation is to use a [Terminator.md] user object,
but `Terminator` works with [Postprocessors](Postprocessors/index.md) for the criterion
instead of a boolean chain control data.

!alert tip title=Converting to boolean control data
This object requires the input data to have type `bool`. If you have a data of
type `Real`, you can convert using [RealToBoolChainControl.md].

!syntax parameters /ChainControls/TerminateChainControl

!syntax inputs /ChainControls/TerminateChainControl

!syntax children /ChainControls/TerminateChainControl
22 changes: 22 additions & 0 deletions framework/doc/content/source/chaincontrols/UnitTripChainControl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# UnitTripChainControl

This [ChainControl](syntax/ChainControls/index.md) produces a boolean trip
[chain control data](/ChainControlData.md), which is initially `false` but
upon being triggered, becomes `true` for the remainder of the simulation.
This trip value is named `<control>:tripped`, where `<control>` is the
user-given name of the `UnitTripChainControl`.
The trip is determined by the value of the input boolean value given by
[!param](/ChainControls/UnitTripChainControl/input) and
[!param](/ChainControls/UnitTripChainControl/trip_on_true). If `trip_on_true`
is set to `true`, then the trip occurs when the input value is `true`; else
it occurs when the input value is `false`.

!alert tip title=Converting to boolean control data
This object requires the input data to have type `bool`. If you have a data of
type `Real`, you can convert using [RealToBoolChainControl.md].

!syntax parameters /ChainControls/UnitTripChainControl

!syntax inputs /ChainControls/UnitTripChainControl

!syntax children /ChainControls/UnitTripChainControl
5 changes: 5 additions & 0 deletions framework/include/base/ChainControlDataSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ class ChainControlDataSystem
ChainControlData<T> & declareChainControlData(const std::string & data_name,
ChainControl & chain_control);

/**
* Copies current chain control data values into old values
*/
void copyValuesBack();

/**
* Gets the map of ChainControlData names to the relevant ChainControlDataBase
*/
Expand Down
25 changes: 23 additions & 2 deletions framework/include/chaincontrols/ChainControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Control.h"
#include "ChainControlData.h"
#include "ChainControlDataSystem.h"
#include "MooseUtils.h"

/**
* Control that additionally provides the capability to produce/consume data values,
Expand Down Expand Up @@ -97,6 +98,15 @@ class ChainControl : public Control
*/
void addChainControlDataDependency(const std::string & data_name);

/**
* Gets the full control data name, including object name prefix (if any)
*
* @param data_name Chain control data name
* @param apply_object_prefix If true, apply the object name as a prefix to the data name
*/
std::string fullControlDataName(const std::string & data_name,
bool apply_object_prefix = true) const;

/// List of chain control data that this control depends upon
std::vector<std::string> _control_data_depends_on;
};
Expand All @@ -105,7 +115,7 @@ template <typename T>
T &
ChainControl::declareChainControlData(const std::string & data_name, bool apply_object_prefix)
{
const std::string full_data_name = (apply_object_prefix ? name() + ":" : "") + data_name;
const std::string full_data_name = fullControlDataName(data_name, apply_object_prefix);
auto & data =
getMooseApp().getChainControlDataSystem().declareChainControlData<T>(full_data_name, *this);
return data.set();
Expand All @@ -129,7 +139,18 @@ template <typename T>
const T &
ChainControl::getChainControlDataByName(const std::string & data_name)
{
auto & data = getMooseApp().getChainControlDataSystem().getChainControlData<T>(data_name);
auto & system = getMooseApp().getChainControlDataSystem();

if (system.hasChainControlData(data_name) && !system.hasChainControlDataOfType<T>(data_name))
mooseError("The chain control data '",
data_name,
"' has the type '",
system.getChainControlDataMap().at(data_name)->type(),
"', but this chain control requires its type to be '",
MooseUtils::prettyCppType<T>(),
"'.");

auto & data = system.getChainControlData<T>(data_name);

addChainControlDataDependency(data_name);

Expand Down
3 changes: 2 additions & 1 deletion framework/include/chaincontrols/ChainControlData.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#pragma once

#include "Restartable.h"
#include "MooseUtils.h"

class ChainControl;

Expand Down Expand Up @@ -131,7 +132,7 @@ template <typename T>
inline std::string
ChainControlData<T>::type()
{
return typeid(T).name();
return MooseUtils::prettyCppType<T>();
}

template <typename T>
Expand Down
35 changes: 35 additions & 0 deletions framework/include/chaincontrols/LimitChainControl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//* 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

#include "ChainControl.h"

/**
* Limits a control value by a range.
*/
class LimitChainControl : public ChainControl
{
public:
static InputParameters validParams();

LimitChainControl(const InputParameters & parameters);

virtual void execute() override;

protected:
/// Lower bound to apply to control data
const Real _min_value;
GiudGiud marked this conversation as resolved.
Show resolved Hide resolved
/// Upper bound to apply to control data
const Real _max_value;
/// Control value before limiting
const Real & _unlimited_value;
/// Control value after limiting
Real & _limited_value;
};
Loading