From 6b37c58718841615f45bbdf212961578e43d1f72 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Wed, 13 Nov 2024 13:23:12 -0600 Subject: [PATCH 01/14] Added "chaincontrols" source link Refs #28948 --- modules/doc/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/doc/config.yml b/modules/doc/config.yml index 91837c3c0b68..4334a0554b64 100644 --- a/modules/doc/config.yml +++ b/modules/doc/config.yml @@ -145,6 +145,7 @@ Extensions: auxscalarkernels: AuxScalarKernels/index.md bcs: syntax/BCs/index.md bounds: syntax/Bounds/index.md + chaincontrols: syntax/ChainControls/index.md closures: syntax/Closures/index.md components: syntax/Components/index.md constraints: syntax/Constraints/index.md From 682e1ad540ec15d6523fb954e1203a2ac4e83a63 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Tue, 26 Nov 2024 08:12:43 -0600 Subject: [PATCH 02/14] Copied chain control values back Refs #28948 --- framework/include/base/ChainControlDataSystem.h | 5 +++++ framework/src/actions/ChainControlSetupAction.C | 4 ++++ framework/src/base/ChainControlDataSystem.C | 7 +++++++ framework/src/problems/FEProblemBase.C | 2 ++ 4 files changed, 18 insertions(+) diff --git a/framework/include/base/ChainControlDataSystem.h b/framework/include/base/ChainControlDataSystem.h index 0102630978e6..5be06c5efd07 100644 --- a/framework/include/base/ChainControlDataSystem.h +++ b/framework/include/base/ChainControlDataSystem.h @@ -70,6 +70,11 @@ class ChainControlDataSystem ChainControlData & 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 */ diff --git a/framework/src/actions/ChainControlSetupAction.C b/framework/src/actions/ChainControlSetupAction.C index 290f1efbfaac..0e34ee5eb8fd 100644 --- a/framework/src/actions/ChainControlSetupAction.C +++ b/framework/src/actions/ChainControlSetupAction.C @@ -50,6 +50,10 @@ ChainControlSetupAction::act() chain_control->init(); } + // Copy initial current values back into old values. + // Note that if an "older" state value is ever added, this will need to be called twice. + getMooseApp().getChainControlDataSystem().copyValuesBack(); + // Add ChainControl dependencies based on ChainControlData dependencies for (auto & control_shared_ptr : control_warehouse.getObjects()) { diff --git a/framework/src/base/ChainControlDataSystem.C b/framework/src/base/ChainControlDataSystem.C index 9e69f4dce161..465410ab3b1a 100644 --- a/framework/src/base/ChainControlDataSystem.C +++ b/framework/src/base/ChainControlDataSystem.C @@ -17,6 +17,13 @@ ChainControlDataSystem::hasChainControlData(const std::string & data_name) const return _chain_control_data_map.find(data_name) != _chain_control_data_map.end(); } +void +ChainControlDataSystem::copyValuesBack() +{ + for (const auto & item : _chain_control_data_map) + item.second->copyValuesBack(); +} + const std::map> & ChainControlDataSystem::getChainControlDataMap() const { diff --git a/framework/src/problems/FEProblemBase.C b/framework/src/problems/FEProblemBase.C index 3b9e8d7b2cea..e06467c71aea 100644 --- a/framework/src/problems/FEProblemBase.C +++ b/framework/src/problems/FEProblemBase.C @@ -6463,6 +6463,8 @@ FEProblemBase::advanceState() _reporter_data.copyValuesBack(); + getMooseApp().getChainControlDataSystem().copyValuesBack(); + if (_material_props.hasStatefulProperties()) _material_props.shift(); From 0fb7df870348dea7b1e4dd21506789935624b598 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Tue, 26 Nov 2024 08:13:17 -0600 Subject: [PATCH 03/14] Added ChainControl::fullControlDataName() Refs #28948 --- framework/include/chaincontrols/ChainControl.h | 11 ++++++++++- framework/src/chaincontrols/ChainControl.C | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/framework/include/chaincontrols/ChainControl.h b/framework/include/chaincontrols/ChainControl.h index e26f52e2feff..4f3219c01bb8 100644 --- a/framework/include/chaincontrols/ChainControl.h +++ b/framework/include/chaincontrols/ChainControl.h @@ -97,6 +97,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 _control_data_depends_on; }; @@ -105,7 +114,7 @@ template 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(full_data_name, *this); return data.set(); diff --git a/framework/src/chaincontrols/ChainControl.C b/framework/src/chaincontrols/ChainControl.C index 8f4b748779af..e1996614be93 100644 --- a/framework/src/chaincontrols/ChainControl.C +++ b/framework/src/chaincontrols/ChainControl.C @@ -26,3 +26,9 @@ ChainControl::addChainControlDataDependency(const std::string & data_name) _control_data_depends_on.end()) _control_data_depends_on.push_back(data_name); } + +std::string +ChainControl::fullControlDataName(const std::string & data_name, bool apply_object_prefix) const +{ + return (apply_object_prefix ? name() + ":" : "") + data_name; +} From c5c656568b1fc82b59cea0e05f1754f90985c2b3 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Tue, 26 Nov 2024 08:14:11 -0600 Subject: [PATCH 04/14] Added ScaleOldChainControl Refs #28948 --- .../chaincontrols/ScaleOldChainControl.md | 35 +++++++++ .../chaincontrols/ScaleOldChainControl.h | 33 +++++++++ .../src/chaincontrols/ScaleOldChainControl.C | 45 ++++++++++++ .../gold/scale_old_chain_control_out.csv | 5 ++ .../scale_old_chain_control.i | 72 +++++++++++++++++++ .../scale_old_chain_control/tests | 10 +++ 6 files changed, 200 insertions(+) create mode 100644 framework/doc/content/source/chaincontrols/ScaleOldChainControl.md create mode 100644 framework/include/chaincontrols/ScaleOldChainControl.h create mode 100644 framework/src/chaincontrols/ScaleOldChainControl.C create mode 100644 test/tests/chaincontrols/scale_old_chain_control/gold/scale_old_chain_control_out.csv create mode 100644 test/tests/chaincontrols/scale_old_chain_control/scale_old_chain_control.i create mode 100644 test/tests/chaincontrols/scale_old_chain_control/tests diff --git a/framework/doc/content/source/chaincontrols/ScaleOldChainControl.md b/framework/doc/content/source/chaincontrols/ScaleOldChainControl.md new file mode 100644 index 000000000000..69ce4691e428 --- /dev/null +++ b/framework/doc/content/source/chaincontrols/ScaleOldChainControl.md @@ -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 `:value`, where `` is the +user-given name of the control. +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 `:value`. + +!syntax parameters /ChainControls/ScaleOldChainControl + +!syntax inputs /ChainControls/ScaleOldChainControl + +!syntax children /ChainControls/ScaleOldChainControl diff --git a/framework/include/chaincontrols/ScaleOldChainControl.h b/framework/include/chaincontrols/ScaleOldChainControl.h new file mode 100644 index 000000000000..d7ffea58b1c4 --- /dev/null +++ b/framework/include/chaincontrols/ScaleOldChainControl.h @@ -0,0 +1,33 @@ +//* 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" + +/** + * Scales an old control value by another control value. + */ +class ScaleOldChainControl : public ChainControl +{ +public: + static InputParameters validParams(); + + ScaleOldChainControl(const InputParameters & parameters); + + virtual void execute() override; + +protected: + /// Control value after scaling + Real & _value; + /// Control value before scaling + const Real & _value_old; + /// Factor by which to scale control value + const Real & _scale_factor; +}; diff --git a/framework/src/chaincontrols/ScaleOldChainControl.C b/framework/src/chaincontrols/ScaleOldChainControl.C new file mode 100644 index 000000000000..f0df2dbf5754 --- /dev/null +++ b/framework/src/chaincontrols/ScaleOldChainControl.C @@ -0,0 +1,45 @@ +//* 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 + +#include "ScaleOldChainControl.h" + +registerMooseObject("MooseApp", ScaleOldChainControl); + +InputParameters +ScaleOldChainControl::validParams() +{ + InputParameters params = ChainControl::validParams(); + + params.addClassDescription("Scales an old control value by another control value."); + + params.addParam("control_data", + "Control data whose old value is to be scaled. If no name is " + "provided, this control data is used."); + params.addRequiredParam("scale_factor", "Control data by which to scale value"); + params.addRequiredParam("initial_value", "Initial value if scaling this control data"); + + return params; +} + +ScaleOldChainControl::ScaleOldChainControl(const InputParameters & parameters) + : ChainControl(parameters), + _value(declareChainControlData("value")), + _value_old(getChainControlDataOldByName(isParamValid("control_data") + ? getParam("control_data") + : fullControlDataName("value"))), + _scale_factor(getChainControlData("scale_factor")) +{ + _value = getParam("initial_value"); +} + +void +ScaleOldChainControl::execute() +{ + _value = _scale_factor * _value_old; +} diff --git a/test/tests/chaincontrols/scale_old_chain_control/gold/scale_old_chain_control_out.csv b/test/tests/chaincontrols/scale_old_chain_control/gold/scale_old_chain_control_out.csv new file mode 100644 index 000000000000..dc1a9885e677 --- /dev/null +++ b/test/tests/chaincontrols/scale_old_chain_control/gold/scale_old_chain_control_out.csv @@ -0,0 +1,5 @@ +time,scale_ctrl_value +0,3 +1,6 +2,18 +3,72 diff --git a/test/tests/chaincontrols/scale_old_chain_control/scale_old_chain_control.i b/test/tests/chaincontrols/scale_old_chain_control/scale_old_chain_control.i new file mode 100644 index 000000000000..53158a390ec6 --- /dev/null +++ b/test/tests/chaincontrols/scale_old_chain_control/scale_old_chain_control.i @@ -0,0 +1,72 @@ +# Tests ScaleOldChainControl +# +# The following test function is used: +# scale_fn: y(t) = t + 1 +# +# Note controls execute BEFORE post-processors, except for INITIAL, so here +# the initial PP value is incorrect, but the others are correct: +# INITIAL: +# scale_ctrl_value <- scale_ctrl:value = 1 +# scale_factor_ctrl:value <- y(0) = 1 +# scale_ctrl:value <- 3 * scale_factor_ctrl:value = 3 +# TIMESTEP_END (t = 1): +# scale_factor_ctrl:value <- y(1) = 2 +# scale_ctrl:value <- 3 * scale_factor_ctrl:value = 6 +# scale_ctrl_value <- scale_ctrl:value = 6 +# TIMESTEP_END (t = 2): +# scale_factor_ctrl:value <- y(2) = 3 +# scale_ctrl:value <- 6 * scale_factor_ctrl:value = 18 +# scale_ctrl_value <- scale_ctrl:value = 18 +# TIMESTEP_END (t = 3): +# scale_factor_ctrl:value <- y(1) = 4 +# scale_ctrl:value <- 18 * scale_factor_ctrl:value = 72 +# scale_ctrl_value <- scale_ctrl:value = 72 + +[Mesh] + type = GeneratedMesh + dim = 1 + nx = 1 +[] + +[Functions] + [scale_fn] + type = ParsedFunction + expression = 't + 1' + [] +[] + +[Postprocessors] + [scale_ctrl_value] + type = ChainControlDataPostprocessor + chain_control_data_name = scale_ctrl:value + execute_on = 'INITIAL TIMESTEP_END' + [] +[] + +[ChainControls] + [scale_factor_ctrl] + type = GetFunctionValueChainControl + function = scale_fn + point = '0 0 0' + [] + [scale_ctrl] + type = ScaleOldChainControl + initial_value = 3 + scale_factor = scale_factor_ctrl:value + control_data = scale_ctrl:value + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + dt = 1 + num_steps = 3 +[] + +[Outputs] + csv = true +[] diff --git a/test/tests/chaincontrols/scale_old_chain_control/tests b/test/tests/chaincontrols/scale_old_chain_control/tests new file mode 100644 index 000000000000..d76da14e8831 --- /dev/null +++ b/test/tests/chaincontrols/scale_old_chain_control/tests @@ -0,0 +1,10 @@ +[Tests] + design = 'ScaleOldChainControl.md' + issues = '#28948' + [test] + type = CSVDiff + input = 'scale_old_chain_control.i' + csvdiff = 'scale_old_chain_control_out.csv' + requirement = 'The system shall be able to scale a chain control data by another chain control data.' + [] +[] From 095e7ee4f72066a5cc994957447189c5228e8db0 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Tue, 26 Nov 2024 08:14:32 -0600 Subject: [PATCH 05/14] Added LimitChainControl Refs #28948 --- .../source/chaincontrols/LimitChainControl.md | 12 ++++ .../include/chaincontrols/LimitChainControl.h | 35 ++++++++++++ .../src/chaincontrols/LimitChainControl.C | 43 +++++++++++++++ .../gold/limit_chain_control_out.csv | 12 ++++ .../limit_chain_control/limit_chain_control.i | 55 +++++++++++++++++++ .../chaincontrols/limit_chain_control/tests | 10 ++++ 6 files changed, 167 insertions(+) create mode 100644 framework/doc/content/source/chaincontrols/LimitChainControl.md create mode 100644 framework/include/chaincontrols/LimitChainControl.h create mode 100644 framework/src/chaincontrols/LimitChainControl.C create mode 100644 test/tests/chaincontrols/limit_chain_control/gold/limit_chain_control_out.csv create mode 100644 test/tests/chaincontrols/limit_chain_control/limit_chain_control.i create mode 100644 test/tests/chaincontrols/limit_chain_control/tests diff --git a/framework/doc/content/source/chaincontrols/LimitChainControl.md b/framework/doc/content/source/chaincontrols/LimitChainControl.md new file mode 100644 index 000000000000..99d6fb561177 --- /dev/null +++ b/framework/doc/content/source/chaincontrols/LimitChainControl.md @@ -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 `:value`, where `` is the +user-given name of the control. + +!syntax parameters /ChainControls/LimitChainControl + +!syntax inputs /ChainControls/LimitChainControl + +!syntax children /ChainControls/LimitChainControl diff --git a/framework/include/chaincontrols/LimitChainControl.h b/framework/include/chaincontrols/LimitChainControl.h new file mode 100644 index 000000000000..56c2663df1a4 --- /dev/null +++ b/framework/include/chaincontrols/LimitChainControl.h @@ -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: + /// Minimum value to apply to control data + const Real _min_value; + /// Maximum value to apply to control data + const Real _max_value; + /// Control value before limiting + const Real & _unlimited_value; + /// Control value after limiting + Real & _limited_value; +}; diff --git a/framework/src/chaincontrols/LimitChainControl.C b/framework/src/chaincontrols/LimitChainControl.C new file mode 100644 index 000000000000..1bd19e17b4c2 --- /dev/null +++ b/framework/src/chaincontrols/LimitChainControl.C @@ -0,0 +1,43 @@ +//* 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 + +#include "LimitChainControl.h" + +registerMooseObject("MooseApp", LimitChainControl); + +InputParameters +LimitChainControl::validParams() +{ + InputParameters params = ChainControl::validParams(); + + params.addClassDescription("Limits a control value by a range."); + + params.addRequiredParam("control_data", "Control data to limit"); + params.addParam( + "min_value", std::numeric_limits::lowest(), "Minimum value for the control data"); + params.addParam( + "max_value", std::numeric_limits::max(), "Maximum value for the control data"); + + return params; +} + +LimitChainControl::LimitChainControl(const InputParameters & parameters) + : ChainControl(parameters), + _min_value(getParam("min_value")), + _max_value(getParam("max_value")), + _unlimited_value(getChainControlData("control_data")), + _limited_value(declareChainControlData("value")) +{ +} + +void +LimitChainControl::execute() +{ + _limited_value = std::max(std::min(_unlimited_value, _max_value), _min_value); +} diff --git a/test/tests/chaincontrols/limit_chain_control/gold/limit_chain_control_out.csv b/test/tests/chaincontrols/limit_chain_control/gold/limit_chain_control_out.csv new file mode 100644 index 000000000000..bf578f3fc431 --- /dev/null +++ b/test/tests/chaincontrols/limit_chain_control/gold/limit_chain_control_out.csv @@ -0,0 +1,12 @@ +time,limited_value,unlimited_value +0,0,0 +0.1,0.6,0.9317179826494 +0.2,0.25382919418613,0.25382919418613 +0.3,-0.2,-0.63332386876162 +0.4,-0.2,-0.99834605415192 +0.5,-0.2,-0.54030230586814 +0.6,0.3631825998141,0.3631825998141 +0.7,0.6,0.96724905798808 +0.8,0.6,0.77388686334425 +0.9,-0.057490487554809,-0.057490487554809 +1,-0.2,-0.8414709848079 diff --git a/test/tests/chaincontrols/limit_chain_control/limit_chain_control.i b/test/tests/chaincontrols/limit_chain_control/limit_chain_control.i new file mode 100644 index 000000000000..0730859c1b37 --- /dev/null +++ b/test/tests/chaincontrols/limit_chain_control/limit_chain_control.i @@ -0,0 +1,55 @@ +# Tests LimitChainControl + +[Mesh] + type = GeneratedMesh + dim = 1 + nx = 1 +[] + +[Functions] + [test_fn] + type = ParsedFunction + expression = 'sin(3*pi*t+1)' + [] +[] + +[Postprocessors] + [unlimited_value] + type = ChainControlDataPostprocessor + chain_control_data_name = unlimited_ctrl:value + execute_on = 'INITIAL TIMESTEP_END' + [] + [limited_value] + type = ChainControlDataPostprocessor + chain_control_data_name = limited_ctrl:value + execute_on = 'INITIAL TIMESTEP_END' + [] +[] + +[ChainControls] + [unlimited_ctrl] + type = GetFunctionValueChainControl + function = test_fn + point = '0 0 0' + [] + [limited_ctrl] + type = LimitChainControl + control_data = unlimited_ctrl:value + min_value = -0.2 + max_value = 0.6 + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + dt = 0.1 + num_steps = 10 +[] + +[Outputs] + csv = true +[] diff --git a/test/tests/chaincontrols/limit_chain_control/tests b/test/tests/chaincontrols/limit_chain_control/tests new file mode 100644 index 000000000000..61446df98307 --- /dev/null +++ b/test/tests/chaincontrols/limit_chain_control/tests @@ -0,0 +1,10 @@ +[Tests] + design = 'LimitChainControl.md' + issues = '#28948' + [test] + type = CSVDiff + input = 'limit_chain_control.i' + csvdiff = 'limit_chain_control_out.csv' + requirement = 'The system shall be able to limit a chain control data between a minimum and maximum value.' + [] +[] From ac5a3f3b89f3a9aaa04cff816ea64856055bb265 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Wed, 27 Nov 2024 14:12:47 -0600 Subject: [PATCH 06/14] Added RealToBoolChainControl Refs #28948 --- .../chaincontrols/RealToBoolChainControl.md | 15 ++++ .../chaincontrols/RealToBoolChainControl.h | 31 ++++++++ .../chaincontrols/RealToBoolChainControl.C | 44 +++++++++++ .../gold/real_to_bool_chain_control_out.csv | 5 ++ .../real_to_bool_chain_control.i | 74 +++++++++++++++++++ .../real_to_bool_chain_control/tests | 17 +++++ 6 files changed, 186 insertions(+) create mode 100644 framework/doc/content/source/chaincontrols/RealToBoolChainControl.md create mode 100644 framework/include/chaincontrols/RealToBoolChainControl.h create mode 100644 framework/src/chaincontrols/RealToBoolChainControl.C create mode 100644 test/tests/chaincontrols/real_to_bool_chain_control/gold/real_to_bool_chain_control_out.csv create mode 100644 test/tests/chaincontrols/real_to_bool_chain_control/real_to_bool_chain_control.i create mode 100644 test/tests/chaincontrols/real_to_bool_chain_control/tests diff --git a/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md b/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md new file mode 100644 index 000000000000..1a008937c172 --- /dev/null +++ b/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md @@ -0,0 +1,15 @@ +# RealToBoolChainControl + +This [ChainControl](syntax/ChainControls/index.md) converts a `Real`-valued +[chain control data](/ChainControlData.md) to a `bool` data, with the name +`:value`, where `` is the user-given name of the control: + +- A value of 1 converts to `true`. +- A value of 0 converts to `false`. +- Other values result in an error. + +!syntax parameters /ChainControls/RealToBoolChainControl + +!syntax inputs /ChainControls/RealToBoolChainControl + +!syntax children /ChainControls/RealToBoolChainControl diff --git a/framework/include/chaincontrols/RealToBoolChainControl.h b/framework/include/chaincontrols/RealToBoolChainControl.h new file mode 100644 index 000000000000..e9adda7d3708 --- /dev/null +++ b/framework/include/chaincontrols/RealToBoolChainControl.h @@ -0,0 +1,31 @@ +//* 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" + +/** + * Converts a Real-valued chain control data to boolean. + */ +class RealToBoolChainControl : public ChainControl +{ +public: + static InputParameters validParams(); + + RealToBoolChainControl(const InputParameters & parameters); + + virtual void execute() override; + +protected: + /// The value before conversion + const Real & _input; + /// The converted value + bool & _output; +}; diff --git a/framework/src/chaincontrols/RealToBoolChainControl.C b/framework/src/chaincontrols/RealToBoolChainControl.C new file mode 100644 index 000000000000..3ef36247a81a --- /dev/null +++ b/framework/src/chaincontrols/RealToBoolChainControl.C @@ -0,0 +1,44 @@ +//* 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 + +#include "RealToBoolChainControl.h" +#include "MooseUtils.h" + +registerMooseObject("MooseApp", RealToBoolChainControl); + +InputParameters +RealToBoolChainControl::validParams() +{ + InputParameters params = ChainControl::validParams(); + + params.addClassDescription("Converts a Real-valued chain control data to boolean."); + + params.addRequiredParam("input", + "The Real-valued chain control data to convert to boolean."); + + return params; +} + +RealToBoolChainControl::RealToBoolChainControl(const InputParameters & parameters) + : ChainControl(parameters), + _input(getChainControlData("input")), + _output(declareChainControlData("value")) +{ +} + +void +RealToBoolChainControl::execute() +{ + if (MooseUtils::absoluteFuzzyEqual(_input, 1.0)) + _output = true; + else if (MooseUtils::absoluteFuzzyEqual(_input, 0.0)) + _output = false; + else + mooseError("The current input value (", _input, ") is not equal to 1 or 0."); +} diff --git a/test/tests/chaincontrols/real_to_bool_chain_control/gold/real_to_bool_chain_control_out.csv b/test/tests/chaincontrols/real_to_bool_chain_control/gold/real_to_bool_chain_control_out.csv new file mode 100644 index 000000000000..9c4bd1d65c0b --- /dev/null +++ b/test/tests/chaincontrols/real_to_bool_chain_control/gold/real_to_bool_chain_control_out.csv @@ -0,0 +1,5 @@ +time,bool_value +0,0 +1,1 +2,0 +3,1 diff --git a/test/tests/chaincontrols/real_to_bool_chain_control/real_to_bool_chain_control.i b/test/tests/chaincontrols/real_to_bool_chain_control/real_to_bool_chain_control.i new file mode 100644 index 000000000000..488827ce1a76 --- /dev/null +++ b/test/tests/chaincontrols/real_to_bool_chain_control/real_to_bool_chain_control.i @@ -0,0 +1,74 @@ +# Tests RealToBoolChainControl +# +# The following test function is used: +# test_fn: y(t) = { 1 t = 0 +# { 1 t = 1 +# { 0 t = 2 +# { 1 t = 3 +# +# Note controls execute BEFORE post-processors, except for INITIAL, so here +# the initial PP value is incorrect, but the others are correct: +# INITIAL: +# bool_value <- bool_ctrl:value = 0 +# real_ctrl:value <- y(0) = 1 +# bool_ctrl:value <- bool(real_ctrl:value) = true +# TIMESTEP_END (t = 1): +# real_ctrl:value <- y(1) = 1 +# bool_ctrl:value <- bool(real_ctrl:value) = true +# bool_value <- bool_ctrl:value = 1 +# TIMESTEP_END (t = 2): +# real_ctrl:value <- y(2) = 0 +# bool_ctrl:value <- bool(real_ctrl:value) = false +# bool_value <- bool_ctrl:value = 0 +# TIMESTEP_END (t = 3): +# real_ctrl:value <- y(3) = 1 +# bool_ctrl:value <- bool(real_ctrl:value) = true +# bool_value <- bool_ctrl:value = 1 + +[Mesh] + type = GeneratedMesh + dim = 1 + nx = 1 +[] + +[Functions] + [test_fn] + type = PiecewiseLinear + x = '0 1 2 3' + y = '1 1 0 1' + [] +[] + +[ChainControls] + [real_ctrl] + type = GetFunctionValueChainControl + function = test_fn + point = '0 0 0' + [] + [bool_ctrl] + type = RealToBoolChainControl + input = real_ctrl:value + [] +[] + +[Postprocessors] + [bool_value] + type = ChainControlDataPostprocessor + chain_control_data_name = bool_ctrl:value + execute_on = 'INITIAL TIMESTEP_END' + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + dt = 1 + num_steps = 3 +[] + +[Outputs] + csv = true +[] diff --git a/test/tests/chaincontrols/real_to_bool_chain_control/tests b/test/tests/chaincontrols/real_to_bool_chain_control/tests new file mode 100644 index 000000000000..d7b7eb9145f9 --- /dev/null +++ b/test/tests/chaincontrols/real_to_bool_chain_control/tests @@ -0,0 +1,17 @@ +[Tests] + design = 'RealToBoolChainControl.md' + issues = '#28948' + [test] + type = CSVDiff + input = 'real_to_bool_chain_control.i' + csvdiff = 'real_to_bool_chain_control_out.csv' + requirement = 'The system shall be able to convert a floating point chain control data to a boolean chain control data.' + [] + [invalid_input_value] + type = RunException + input = 'real_to_bool_chain_control.i' + cli_args = "Functions/test_fn/y='1 0.1 0 1'" + expect_err = "The current input value \(0.1\) is not equal to 1 or 0" + requirement = 'The system shall be able to convert a floating point chain control data to a boolean chain control data.' + [] +[] From f759e2535bdcb8e81add4dd41b9fed1a90b3f9bb Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Wed, 27 Nov 2024 14:13:48 -0600 Subject: [PATCH 07/14] Added UnitTripChainControl Refs #28948 --- .../chaincontrols/UnitTripChainControl.md | 22 ++++ .../include/chaincontrols/ChainControl.h | 14 ++- .../include/chaincontrols/ChainControlData.h | 3 +- .../chaincontrols/UnitTripChainControl.h | 33 ++++++ .../src/chaincontrols/UnitTripChainControl.C | 48 ++++++++ .../gold/unit_trip_chain_control_out.csv | 6 + .../unit_trip_chain_control/tests | 17 +++ .../unit_trip_chain_control.i | 104 ++++++++++++++++++ 8 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 framework/doc/content/source/chaincontrols/UnitTripChainControl.md create mode 100644 framework/include/chaincontrols/UnitTripChainControl.h create mode 100644 framework/src/chaincontrols/UnitTripChainControl.C create mode 100644 test/tests/chaincontrols/unit_trip_chain_control/gold/unit_trip_chain_control_out.csv create mode 100644 test/tests/chaincontrols/unit_trip_chain_control/tests create mode 100644 test/tests/chaincontrols/unit_trip_chain_control/unit_trip_chain_control.i diff --git a/framework/doc/content/source/chaincontrols/UnitTripChainControl.md b/framework/doc/content/source/chaincontrols/UnitTripChainControl.md new file mode 100644 index 000000000000..eea022f1cba9 --- /dev/null +++ b/framework/doc/content/source/chaincontrols/UnitTripChainControl.md @@ -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 `:tripped`, where `` is the +user-given name of the control. +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 diff --git a/framework/include/chaincontrols/ChainControl.h b/framework/include/chaincontrols/ChainControl.h index 4f3219c01bb8..f53c334403b2 100644 --- a/framework/include/chaincontrols/ChainControl.h +++ b/framework/include/chaincontrols/ChainControl.h @@ -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, @@ -138,7 +139,18 @@ template const T & ChainControl::getChainControlDataByName(const std::string & data_name) { - auto & data = getMooseApp().getChainControlDataSystem().getChainControlData(data_name); + auto & system = getMooseApp().getChainControlDataSystem(); + + if (system.hasChainControlData(data_name) && !system.hasChainControlDataOfType(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(), + "'."); + + auto & data = system.getChainControlData(data_name); addChainControlDataDependency(data_name); diff --git a/framework/include/chaincontrols/ChainControlData.h b/framework/include/chaincontrols/ChainControlData.h index 6aae08481a3c..50d533d0a79a 100644 --- a/framework/include/chaincontrols/ChainControlData.h +++ b/framework/include/chaincontrols/ChainControlData.h @@ -10,6 +10,7 @@ #pragma once #include "Restartable.h" +#include "MooseUtils.h" class ChainControl; @@ -131,7 +132,7 @@ template inline std::string ChainControlData::type() { - return typeid(T).name(); + return MooseUtils::prettyCppType(); } template diff --git a/framework/include/chaincontrols/UnitTripChainControl.h b/framework/include/chaincontrols/UnitTripChainControl.h new file mode 100644 index 000000000000..2d4513c43638 --- /dev/null +++ b/framework/include/chaincontrols/UnitTripChainControl.h @@ -0,0 +1,33 @@ +//* 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" + +/** + * Trips a boolean value if an input boolean value is a certain value. + */ +class UnitTripChainControl : public ChainControl +{ +public: + static InputParameters validParams(); + + UnitTripChainControl(const InputParameters & parameters); + + virtual void execute() override; + +protected: + /// Whether to trip on true or false value + const bool _trip_on_true; + /// Value to check for trip + const bool & _input; + /// Tripped status + bool & _tripped; +}; diff --git a/framework/src/chaincontrols/UnitTripChainControl.C b/framework/src/chaincontrols/UnitTripChainControl.C new file mode 100644 index 000000000000..905b489cc694 --- /dev/null +++ b/framework/src/chaincontrols/UnitTripChainControl.C @@ -0,0 +1,48 @@ +//* 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 + +#include "UnitTripChainControl.h" + +registerMooseObject("MooseApp", UnitTripChainControl); + +InputParameters +UnitTripChainControl::validParams() +{ + InputParameters params = ChainControl::validParams(); + + params.addClassDescription("Trips a boolean value if an input boolean value is a certain value."); + + params.addRequiredParam("input", + "The boolean chain control data to determine if tripped"); + params.addParam("trip_on_true", + true, + "If set to 'true', the trip occurs if the input has a value of 'true'; " + "else the trip occurs if the input has a value of 'false'."); + + return params; +} + +UnitTripChainControl::UnitTripChainControl(const InputParameters & parameters) + : ChainControl(parameters), + _trip_on_true(getParam("trip_on_true")), + _input(getChainControlData("input")), + _tripped(declareChainControlData("tripped")) +{ + _tripped = false; +} + +void +UnitTripChainControl::execute() +{ + if (_trip_on_true && _input) + _tripped = true; + + if (!_trip_on_true && !_input) + _tripped = true; +} diff --git a/test/tests/chaincontrols/unit_trip_chain_control/gold/unit_trip_chain_control_out.csv b/test/tests/chaincontrols/unit_trip_chain_control/gold/unit_trip_chain_control_out.csv new file mode 100644 index 000000000000..1203b348013f --- /dev/null +++ b/test/tests/chaincontrols/unit_trip_chain_control/gold/unit_trip_chain_control_out.csv @@ -0,0 +1,6 @@ +time,false_trip,true_trip +0,0,0 +1,0,0 +2,1,0 +3,1,1 +4,1,1 diff --git a/test/tests/chaincontrols/unit_trip_chain_control/tests b/test/tests/chaincontrols/unit_trip_chain_control/tests new file mode 100644 index 000000000000..df711abc3ccd --- /dev/null +++ b/test/tests/chaincontrols/unit_trip_chain_control/tests @@ -0,0 +1,17 @@ +[Tests] + design = 'UnitTripChainControl.md' + issues = '#28948' + [test] + type = CSVDiff + input = 'unit_trip_chain_control.i' + csvdiff = 'unit_trip_chain_control_out.csv' + requirement = 'The system shall provide a unit trip chain control that stays in a tripped state after the trip occurs.' + [] + [wrong_type] + type = RunException + input = 'unit_trip_chain_control.i' + cli_args = "ChainControls/true_trip_ctrl/input=true_trip_fn_ctrl:value" + expect_err = "The chain control data 'true_trip_fn_ctrl:value' has the type 'double', but this chain control requires its type to be 'bool'" + requirement = 'The system shall report an error if the wrong type of input data is provided to a unit trip chain control.' + [] +[] diff --git a/test/tests/chaincontrols/unit_trip_chain_control/unit_trip_chain_control.i b/test/tests/chaincontrols/unit_trip_chain_control/unit_trip_chain_control.i new file mode 100644 index 000000000000..c2a32456f98e --- /dev/null +++ b/test/tests/chaincontrols/unit_trip_chain_control/unit_trip_chain_control.i @@ -0,0 +1,104 @@ +# Tests RealToBoolChainControl +# +# Note controls execute BEFORE post-processors, except for INITIAL, so here +# the initial PP value is incorrect, but the others are correct: +# INITIAL: +# true_trip <- true_trip_ctrl:value = 0 +# false_trip <- false_trip_ctrl:value = 0 +# true_trip_ctrl:value <- false +# false_trip_ctrl:value <- false +# TIMESTEP_END (t = 1): +# true_trip_ctrl:value <- false +# false_trip_ctrl:value <- false +# true_trip <- true_trip_ctrl:value = 0 +# false_trip <- false_trip_ctrl:value = 0 +# TIMESTEP_END (t = 2): +# true_trip_ctrl:value <- false +# false_trip_ctrl:value <- true +# true_trip <- true_trip_ctrl:value = 0 +# false_trip <- false_trip_ctrl:value = 1 +# TIMESTEP_END (t = 3): +# true_trip_ctrl:value <- true +# false_trip_ctrl:value <- true +# true_trip <- true_trip_ctrl:value = 1 +# false_trip <- false_trip_ctrl:value = 1 +# TIMESTEP_END (t = 4): +# true_trip_ctrl:value <- true +# false_trip_ctrl:value <- true +# true_trip <- true_trip_ctrl:value = 1 +# false_trip <- false_trip_ctrl:value = 1 + +[Mesh] + type = GeneratedMesh + dim = 1 + nx = 1 +[] + +[Functions] + [true_trip_fn] + type = PiecewiseLinear + x = '0 1 2 3 4' + y = '0 0 0 1 0' + [] + [false_trip_fn] + type = PiecewiseLinear + x = '0 1 2 3 4' + y = '1 1 0 1 1' + [] +[] + +[ChainControls] + [true_trip_fn_ctrl] + type = GetFunctionValueChainControl + function = true_trip_fn + [] + [false_trip_fn_ctrl] + type = GetFunctionValueChainControl + function = false_trip_fn + [] + [true_trip_bool_ctrl] + type = RealToBoolChainControl + input = true_trip_fn_ctrl:value + [] + [false_trip_bool_ctrl] + type = RealToBoolChainControl + input = false_trip_fn_ctrl:value + [] + [true_trip_ctrl] + type = UnitTripChainControl + input = true_trip_bool_ctrl:value + trip_on_true = true + [] + [false_trip_ctrl] + type = UnitTripChainControl + input = false_trip_bool_ctrl:value + trip_on_true = false + [] +[] + +[Postprocessors] + [true_trip] + type = ChainControlDataPostprocessor + chain_control_data_name = true_trip_ctrl:tripped + execute_on = 'INITIAL TIMESTEP_END' + [] + [false_trip] + type = ChainControlDataPostprocessor + chain_control_data_name = false_trip_ctrl:tripped + execute_on = 'INITIAL TIMESTEP_END' + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + dt = 1 + num_steps = 4 +[] + +[Outputs] + csv = true +[] From 10e2385b56d2b0576ff8d62c68af6a2c0b1bc9c3 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Wed, 27 Nov 2024 15:22:36 -0600 Subject: [PATCH 08/14] Added PIDChainControl Refs #28948 --- .../source/chaincontrols/PIDChainControl.md | 64 +++++++++++++++++++ .../include/chaincontrols/PIDChainControl.h | 54 ++++++++++++++++ framework/src/chaincontrols/PIDChainControl.C | 59 +++++++++++++++++ .../gold/pid_chain_control_out.csv | 52 +++++++++++++++ .../pid_chain_control/pid_chain_control.i | 57 +++++++++++++++++ .../chaincontrols/pid_chain_control/tests | 10 +++ 6 files changed, 296 insertions(+) create mode 100644 framework/doc/content/source/chaincontrols/PIDChainControl.md create mode 100644 framework/include/chaincontrols/PIDChainControl.h create mode 100644 framework/src/chaincontrols/PIDChainControl.C create mode 100644 test/tests/chaincontrols/pid_chain_control/gold/pid_chain_control_out.csv create mode 100644 test/tests/chaincontrols/pid_chain_control/pid_chain_control.i create mode 100644 test/tests/chaincontrols/pid_chain_control/tests diff --git a/framework/doc/content/source/chaincontrols/PIDChainControl.md b/framework/doc/content/source/chaincontrols/PIDChainControl.md new file mode 100644 index 000000000000..d33354699cb3 --- /dev/null +++ b/framework/doc/content/source/chaincontrols/PIDChainControl.md @@ -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 `:value`, where `` + is the user-given name of the control object. + +!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 diff --git a/framework/include/chaincontrols/PIDChainControl.h b/framework/include/chaincontrols/PIDChainControl.h new file mode 100644 index 000000000000..07cab460e60b --- /dev/null +++ b/framework/include/chaincontrols/PIDChainControl.h @@ -0,0 +1,54 @@ +//* 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" + +/** + * Implements a proportional-integral-derivative (PID) controller. + */ +class PIDChainControl : public ChainControl +{ +public: + static InputParameters validParams(); + + PIDChainControl(const InputParameters & parameters); + + virtual void execute() override; + +protected: + /// input data + const Real & _input; + /// set point + const Real & _set_point; + /// The coefficient for the proportional term + const Real & _K_p; + /// The coefficient for the integral term + const Real & _K_i; + /// The coefficient for the derivative term + const Real & _K_d; + + /// The current value of the error + Real & _error; + /// The old value of the error + const Real & _error_old; + + /// The proportional component + Real & _proportional; + /// The integral component + Real & _integral; + /// The old value of \c _integral + const Real & _integral_old; + /// The derivative component + Real & _derivative; + + /// The output computed by the PID controller + Real & _output; +}; diff --git a/framework/src/chaincontrols/PIDChainControl.C b/framework/src/chaincontrols/PIDChainControl.C new file mode 100644 index 000000000000..438ad0057073 --- /dev/null +++ b/framework/src/chaincontrols/PIDChainControl.C @@ -0,0 +1,59 @@ +//* 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 + +#include "PIDChainControl.h" + +registerMooseObject("MooseApp", PIDChainControl); + +InputParameters +PIDChainControl::validParams() +{ + InputParameters params = ChainControl::validParams(); + + params.addClassDescription("Implements a proportional-integral-derivative (PID) controller."); + + params.addRequiredParam("input", "Input control data"); + params.addRequiredParam("set_point", "Set point control data"); + params.addParam("initial_integral", 0.0, "Initial value for the integral component"); + params.addRequiredParam("K_p", "Coefficient for the proportional term"); + params.addRequiredParam("K_i", "Coefficient for the integral term"); + params.addRequiredParam("K_d", "Coefficient for the derivative term"); + + return params; +} + +PIDChainControl::PIDChainControl(const InputParameters & parameters) + : ChainControl(parameters), + _input(getChainControlData("input")), + _set_point(getChainControlData("set_point")), + _K_p(getParam("K_p")), + _K_i(getParam("K_i")), + _K_d(getParam("K_d")), + _error(declareChainControlData("error")), + _error_old(getChainControlDataOldByName(fullControlDataName("error"))), + _proportional(declareChainControlData("proportional")), + _integral(declareChainControlData("integral")), + _integral_old(getChainControlDataOldByName(fullControlDataName("integral"))), + _derivative(declareChainControlData("derivative")), + _output(declareChainControlData("value")) +{ + _integral = getParam("initial_integral"); +} + +void +PIDChainControl::execute() +{ + _error = _set_point - _input; + + _proportional = _K_p * _error; + _integral = _integral_old + _K_i * (_error * _dt); + _derivative = _K_d * (_error - _error_old) / _dt; + + _output = _proportional + _integral + _derivative; +} diff --git a/test/tests/chaincontrols/pid_chain_control/gold/pid_chain_control_out.csv b/test/tests/chaincontrols/pid_chain_control/gold/pid_chain_control_out.csv new file mode 100644 index 000000000000..7e3de486f69c --- /dev/null +++ b/test/tests/chaincontrols/pid_chain_control/gold/pid_chain_control_out.csv @@ -0,0 +1,52 @@ +time,pid +0,0 +1,2.75 +2,2.0925 +3,2.72457325 +4,2.5335790726461 +5,2.8603066874179 +6,2.8245939220233 +7,3.0347665154606 +8,3.0551757345161 +9,3.210477510423 +10,3.2516113832507 +11,3.3763731064325 +12,3.4240711960446 +13,3.5294172459587 +14,3.5775155875617 +15,3.6692531500248 +16,3.7149091810977 +17,3.7964672179247 +18,3.8383194575783 +19,3.9119700047426 +20,3.949340804225 +21,4.0167598252515 +22,4.0492767273709 +23,4.111829896963 +24,4.1392259316177 +25,4.1981339660993 +26,4.2201260169629 +27,4.2765779276254 +28,4.2927760190116 +29,4.3480245216194 +30,4.3578463789645 +31,4.4133061808244 +32,4.4158794424525 +33,4.4732448152774 +34,4.4672807495646 +35,4.5286794628989 +36,4.5122994252546 +37,4.5805044412438 +38,4.5509940844949 +39,4.629722476961 +40,4.58317830081 +41,4.6775196544384 +42,4.6083363386246 +43,4.7253722621867 +44,4.6254948562475 +45,4.7752000602772 +46,4.6330286760548 +47,4.8295863577061 +48,4.628367040742 +49,4.8920922443363 +50,4.6075489928787 diff --git a/test/tests/chaincontrols/pid_chain_control/pid_chain_control.i b/test/tests/chaincontrols/pid_chain_control/pid_chain_control.i new file mode 100644 index 000000000000..3c3196c5f5cf --- /dev/null +++ b/test/tests/chaincontrols/pid_chain_control/pid_chain_control.i @@ -0,0 +1,57 @@ +# Tests PIDChainControl +# +# The PID controller is used to solve the equation y(alpha) = alpha^2 = 25 for alpha. +# Each time step takes one iteration, and these iterations should be converging to alpha = 5. + +[Mesh] + type = GeneratedMesh + dim = 1 + nx = 1 +[] + +[ChainControls] + [get_alpha_ctrl] + type = GetPostprocessorChainControl + postprocessor = pid + [] + [y_ctrl] + type = ParsedChainControl + expression = 'alpha^2' + symbol_names = 'alpha' + symbol_values = 'get_alpha_ctrl:value' + [] + [y_set_ctrl] + type = ParsedChainControl + expression = '25' + [] + [pid_ctrl] + type = PIDChainControl + input = y_ctrl:value + set_point = y_set_ctrl:value + K_p = 0.1 + K_i = 0.01 + K_d = 0.01 + [] +[] + +[Postprocessors] + [pid] + type = ChainControlDataPostprocessor + chain_control_data_name = pid_ctrl:value + execute_on = 'INITIAL TIMESTEP_END' + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + dt = 1 + num_steps = 50 +[] + +[Outputs] + csv = true +[] diff --git a/test/tests/chaincontrols/pid_chain_control/tests b/test/tests/chaincontrols/pid_chain_control/tests new file mode 100644 index 000000000000..de584cfdfd86 --- /dev/null +++ b/test/tests/chaincontrols/pid_chain_control/tests @@ -0,0 +1,10 @@ +[Tests] + design = 'PIDChainControl.md' + issues = '#28948' + [test] + type = CSVDiff + input = 'pid_chain_control.i' + csvdiff = 'pid_chain_control_out.csv' + requirement = 'The system shall be able to compute chain control data using a proportional-integral-derivative controller.' + [] +[] From e601cf9572cf92a004ba5c9a786d1bd134953d97 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Wed, 27 Nov 2024 16:11:30 -0600 Subject: [PATCH 09/14] Added TerminateChainControl Refs #28948 --- .../chaincontrols/TerminateChainControl.md | 22 ++++++ .../chaincontrols/TerminateChainControl.h | 43 ++++++++++++ .../src/chaincontrols/TerminateChainControl.C | 67 +++++++++++++++++++ .../terminate_chain_control.i | 43 ++++++++++++ .../terminate_chain_control/tests | 27 ++++++++ 5 files changed, 202 insertions(+) create mode 100644 framework/doc/content/source/chaincontrols/TerminateChainControl.md create mode 100644 framework/include/chaincontrols/TerminateChainControl.h create mode 100644 framework/src/chaincontrols/TerminateChainControl.C create mode 100644 test/tests/chaincontrols/terminate_chain_control/terminate_chain_control.i create mode 100644 test/tests/chaincontrols/terminate_chain_control/tests diff --git a/framework/doc/content/source/chaincontrols/TerminateChainControl.md b/framework/doc/content/source/chaincontrols/TerminateChainControl.md new file mode 100644 index 000000000000..3224bf8721c3 --- /dev/null +++ b/framework/doc/content/source/chaincontrols/TerminateChainControl.md @@ -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 diff --git a/framework/include/chaincontrols/TerminateChainControl.h b/framework/include/chaincontrols/TerminateChainControl.h new file mode 100644 index 000000000000..243bc5d9406c --- /dev/null +++ b/framework/include/chaincontrols/TerminateChainControl.h @@ -0,0 +1,43 @@ +//* 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" + +/** + * Terminates the simulation when a boolean chain control data has a certain value. + */ +class TerminateChainControl : public ChainControl +{ +public: + static InputParameters validParams(); + + TerminateChainControl(const InputParameters & parameters); + + virtual void execute() override; + +protected: + /** + * Performs termination + */ + void terminate(); + + /// Whether to terminate on true or false + const bool _terminate_on_true; + + /// Flag to throw an error if the terminate condition is met + const bool _throw_error; + + /// Message to use if termination occurs + const std::string & _termination_message; + + /// The control data that indicates if the simulation should be terminated + const bool & _input; +}; diff --git a/framework/src/chaincontrols/TerminateChainControl.C b/framework/src/chaincontrols/TerminateChainControl.C new file mode 100644 index 000000000000..17674a460514 --- /dev/null +++ b/framework/src/chaincontrols/TerminateChainControl.C @@ -0,0 +1,67 @@ +//* 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 + +#include "TerminateChainControl.h" + +registerMooseObject("MooseApp", TerminateChainControl); + +InputParameters +TerminateChainControl::validParams() +{ + InputParameters params = ChainControl::validParams(); + + params.addClassDescription( + "Terminates the simulation when a boolean chain control data has a certain value."); + + params.addRequiredParam( + "input", "Boolean control data indicating if the simulation should be terminated"); + params.addParam("terminate_on_true", + true, + "If set to 'true', termination occurs if the input has a value of 'true'; " + "else termination occurs if the input has a value of 'false'"); + params.addParam("throw_error", + false, + "Flag to throw an error on termination; else just signal the problem to " + "terminate the solve."); + params.addRequiredParam("termination_message", + "Message to use if termination occurs"); + return params; +} + +TerminateChainControl::TerminateChainControl(const InputParameters & parameters) + : ChainControl(parameters), + + _terminate_on_true(getParam("terminate_on_true")), + _throw_error(getParam("throw_error")), + _termination_message(getParam("termination_message")), + _input(getChainControlData("input")) +{ +} + +void +TerminateChainControl::execute() +{ + if (_terminate_on_true && _input) + terminate(); + + if (!_terminate_on_true && !_input) + terminate(); +} + +void +TerminateChainControl::terminate() +{ + if (_throw_error) + mooseError(_termination_message); + else + { + _console << _termination_message << std::endl; + _fe_problem.terminateSolve(); + } +} diff --git a/test/tests/chaincontrols/terminate_chain_control/terminate_chain_control.i b/test/tests/chaincontrols/terminate_chain_control/terminate_chain_control.i new file mode 100644 index 000000000000..0e3171cd64eb --- /dev/null +++ b/test/tests/chaincontrols/terminate_chain_control/terminate_chain_control.i @@ -0,0 +1,43 @@ +# Tests TerminateChainControl + +[Mesh] + type = GeneratedMesh + dim = 1 + nx = 1 +[] + +[Functions] + [test_fn] + type = PiecewiseLinear + x = '0 1 2 3' + y = '0 0 1 0' + [] +[] + +[ChainControls] + [test_fn_ctrl] + type = GetFunctionValueChainControl + function = test_fn + [] + [input_ctrl] + type = RealToBoolChainControl + input = test_fn_ctrl:value + [] + [terminate_ctrl] + type = TerminateChainControl + input = input_ctrl:value + terminate_on_true = true + throw_error = true + termination_message = 'Hasta la vista, baby' + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + dt = 1 + num_steps = 3 +[] diff --git a/test/tests/chaincontrols/terminate_chain_control/tests b/test/tests/chaincontrols/terminate_chain_control/tests new file mode 100644 index 000000000000..78e8758e3b5d --- /dev/null +++ b/test/tests/chaincontrols/terminate_chain_control/tests @@ -0,0 +1,27 @@ +[Tests] + design = 'TerminateChainControl.md' + issues = '#28948' + [tests] + requirement = 'The system shall be able to use a chain control to terminate a simulation' + [throw_error] + type = RunException + input = 'terminate_chain_control.i' + expect_err = 'Hasta la vista, baby' + detail = 'by throwing an error.' + [] + [no_throw_error] + type = RunApp + input = 'terminate_chain_control.i' + cli_args = "ChainControls/terminate_ctrl/throw_error=false" + expect_out = 'Hasta la vista, baby' + detail = 'gracefully.' + [] + [terminate_on_false] + type = RunException + input = 'terminate_chain_control.i' + cli_args = "ChainControls/terminate_ctrl/terminate_on_true=false" + expect_err = 'Hasta la vista, baby' + detail = 'when the data has a value of false.' + [] + [] +[] From db63326a6099f50640b22b577cdff22d52962d70 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Wed, 27 Nov 2024 16:47:53 -0600 Subject: [PATCH 10/14] Added SmootherChainControl Refs #28948 --- .../chaincontrols/SmootherChainControl.md | 20 +++++++ .../chaincontrols/SmootherChainControl.h | 36 +++++++++++++ .../src/chaincontrols/SmootherChainControl.C | 47 +++++++++++++++++ .../gold/smoother_chain_control_out.csv | 5 ++ .../smoother_chain_control/gold/test_out.csv | 7 +++ .../smoother_chain_control.i | 52 +++++++++++++++++++ .../smoother_chain_control/tests | 10 ++++ 7 files changed, 177 insertions(+) create mode 100644 framework/doc/content/source/chaincontrols/SmootherChainControl.md create mode 100644 framework/include/chaincontrols/SmootherChainControl.h create mode 100644 framework/src/chaincontrols/SmootherChainControl.C create mode 100644 test/tests/chaincontrols/smoother_chain_control/gold/smoother_chain_control_out.csv create mode 100644 test/tests/chaincontrols/smoother_chain_control/gold/test_out.csv create mode 100644 test/tests/chaincontrols/smoother_chain_control/smoother_chain_control.i create mode 100644 test/tests/chaincontrols/smoother_chain_control/tests diff --git a/framework/doc/content/source/chaincontrols/SmootherChainControl.md b/framework/doc/content/source/chaincontrols/SmootherChainControl.md new file mode 100644 index 000000000000..1243e5f9e326 --- /dev/null +++ b/framework/doc/content/source/chaincontrols/SmootherChainControl.md @@ -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 `:value`, where `` is the +user-given name of the control. +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 diff --git a/framework/include/chaincontrols/SmootherChainControl.h b/framework/include/chaincontrols/SmootherChainControl.h new file mode 100644 index 000000000000..132049772d50 --- /dev/null +++ b/framework/include/chaincontrols/SmootherChainControl.h @@ -0,0 +1,36 @@ +//* 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" + +/** + * Computes a moving average of the input control with a user-specified + * number of points to average. + **/ +class SmootherChainControl : public ChainControl +{ +public: + static InputParameters validParams(); + + SmootherChainControl(const InputParameters & parameters); + + virtual void execute() override; + +protected: + /// Input data + const Real & _input; + /// The number of points to use in the moving average + const unsigned int _n_points; + /// Output control value + Real & _output; + /// Vector to store values + std::vector & _values; +}; diff --git a/framework/src/chaincontrols/SmootherChainControl.C b/framework/src/chaincontrols/SmootherChainControl.C new file mode 100644 index 000000000000..8c100c55db06 --- /dev/null +++ b/framework/src/chaincontrols/SmootherChainControl.C @@ -0,0 +1,47 @@ +//* 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 + +#include "SmootherChainControl.h" + +registerMooseObject("MooseApp", SmootherChainControl); + +InputParameters +SmootherChainControl::validParams() +{ + InputParameters params = ChainControl::validParams(); + + params.addClassDescription("Computes a moving average of the input control with a user-specified " + "number of points to average."); + + params.addRequiredParam("input", "Control data value to smooth."); + params.addRequiredParam("n_points", + "The number of points to use in the moving average."); + + return params; +} + +SmootherChainControl::SmootherChainControl(const InputParameters & parameters) + : ChainControl(parameters), + _input(getChainControlData("input")), + _n_points(getParam("n_points")), + _output(declareChainControlData("value")), + _values(declareRestartableData>("values")) +{ +} + +void +SmootherChainControl::execute() +{ + if (_values.size() == _n_points) + _values.erase(_values.begin()); + + _values.push_back(_input); + + _output = std::accumulate(_values.begin(), _values.end(), 0.0) / _values.size(); +} diff --git a/test/tests/chaincontrols/smoother_chain_control/gold/smoother_chain_control_out.csv b/test/tests/chaincontrols/smoother_chain_control/gold/smoother_chain_control_out.csv new file mode 100644 index 000000000000..586f4c2fed74 --- /dev/null +++ b/test/tests/chaincontrols/smoother_chain_control/gold/smoother_chain_control_out.csv @@ -0,0 +1,5 @@ +time,smoothed_value +0,0 +1,4 +2,5 +3,4 diff --git a/test/tests/chaincontrols/smoother_chain_control/gold/test_out.csv b/test/tests/chaincontrols/smoother_chain_control/gold/test_out.csv new file mode 100644 index 000000000000..0ab972cdc57d --- /dev/null +++ b/test/tests/chaincontrols/smoother_chain_control/gold/test_out.csv @@ -0,0 +1,7 @@ +time,control_value +0,0 +1,-3.2 +2,-1.05 +3,1 +4,1.6 +5,1.3333333333333 diff --git a/test/tests/chaincontrols/smoother_chain_control/smoother_chain_control.i b/test/tests/chaincontrols/smoother_chain_control/smoother_chain_control.i new file mode 100644 index 000000000000..76a7c6ddc38b --- /dev/null +++ b/test/tests/chaincontrols/smoother_chain_control/smoother_chain_control.i @@ -0,0 +1,52 @@ +# Tests SmootherChainControl +# +# Note that since post-processors execute before controls on INITIAL, +# the first value in the gold file is 0. + +[Mesh] + type = GeneratedMesh + dim = 1 + nx = 1 +[] + +[Functions] + [test_fn] + type = PiecewiseLinear + x = '0 1 2 3' + y = '5 3 7 2' # corresponding 3-point averages are: 5, 4, 5, 4 + [] +[] + +[ChainControls] + [input_ctrl] + type = GetFunctionValueChainControl + function = test_fn + [] + [smoother_ctrl] + type = SmootherChainControl + input = input_ctrl:value + n_points = 3 + [] +[] + +[Postprocessors] + [smoothed_value] + type = ChainControlDataPostprocessor + chain_control_data_name = smoother_ctrl:value + execute_on = 'INITIAL TIMESTEP_END' + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + dt = 1 + num_steps = 3 +[] + +[Outputs] + csv = true +[] diff --git a/test/tests/chaincontrols/smoother_chain_control/tests b/test/tests/chaincontrols/smoother_chain_control/tests new file mode 100644 index 000000000000..0a61dbdba3f0 --- /dev/null +++ b/test/tests/chaincontrols/smoother_chain_control/tests @@ -0,0 +1,10 @@ +[Tests] + design = 'SmootherChainControl.md' + issues = '#28948' + [test] + type = CSVDiff + input = 'smoother_chain_control.i' + csvdiff = 'smoother_chain_control_out.csv' + requirement = 'The system shall be able to smooth an input chain control data using a moving average.' + [] +[] From 7076583681659dc06cb5fbd91e1c2517b60fb98e Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Mon, 2 Dec 2024 09:23:04 -0600 Subject: [PATCH 11/14] Fixed new chain controls tests Refs #28948 --- .../include/chaincontrols/PIDChainControl.h | 6 ++++++ .../chaincontrols/SmootherChainControl.h | 5 +++++ framework/src/chaincontrols/PIDChainControl.C | 19 +++++++++++++++++-- .../src/chaincontrols/SmootherChainControl.C | 14 +++++++++++++- .../real_to_bool_chain_control/tests | 2 +- 5 files changed, 42 insertions(+), 4 deletions(-) diff --git a/framework/include/chaincontrols/PIDChainControl.h b/framework/include/chaincontrols/PIDChainControl.h index 07cab460e60b..9449ecd7b052 100644 --- a/framework/include/chaincontrols/PIDChainControl.h +++ b/framework/include/chaincontrols/PIDChainControl.h @@ -24,6 +24,9 @@ class PIDChainControl : public ChainControl virtual void execute() override; protected: + /// Updates all control data values + void updateValues(); + /// input data const Real & _input; /// set point @@ -51,4 +54,7 @@ class PIDChainControl : public ChainControl /// The output computed by the PID controller Real & _output; + + /// Previous time for which value was computed + Real & _previous_time; }; diff --git a/framework/include/chaincontrols/SmootherChainControl.h b/framework/include/chaincontrols/SmootherChainControl.h index 132049772d50..37a8f495b3a7 100644 --- a/framework/include/chaincontrols/SmootherChainControl.h +++ b/framework/include/chaincontrols/SmootherChainControl.h @@ -25,6 +25,9 @@ class SmootherChainControl : public ChainControl virtual void execute() override; protected: + /// Performs the main execution + void executeInner(); + /// Input data const Real & _input; /// The number of points to use in the moving average @@ -33,4 +36,6 @@ class SmootherChainControl : public ChainControl Real & _output; /// Vector to store values std::vector & _values; + /// Previous time for which value was cached + Real & _previous_time; }; diff --git a/framework/src/chaincontrols/PIDChainControl.C b/framework/src/chaincontrols/PIDChainControl.C index 438ad0057073..8fd821bd8704 100644 --- a/framework/src/chaincontrols/PIDChainControl.C +++ b/framework/src/chaincontrols/PIDChainControl.C @@ -8,6 +8,7 @@ //* https://www.gnu.org/licenses/lgpl-2.1.html #include "PIDChainControl.h" +#include "MooseUtils.h" registerMooseObject("MooseApp", PIDChainControl); @@ -41,19 +42,33 @@ PIDChainControl::PIDChainControl(const InputParameters & parameters) _integral(declareChainControlData("integral")), _integral_old(getChainControlDataOldByName(fullControlDataName("integral"))), _derivative(declareChainControlData("derivative")), - _output(declareChainControlData("value")) + _output(declareChainControlData("value")), + _previous_time(declareRestartableData("previous_time")) { _integral = getParam("initial_integral"); + _previous_time = std::numeric_limits::max(); } void PIDChainControl::execute() +{ + if (!MooseUtils::absoluteFuzzyEqual(_t, _previous_time)) + updateValues(); + + _previous_time = _t; +} + +void +PIDChainControl::updateValues() { _error = _set_point - _input; _proportional = _K_p * _error; _integral = _integral_old + _K_i * (_error * _dt); - _derivative = _K_d * (_error - _error_old) / _dt; + if (MooseUtils::absoluteFuzzyEqual(_dt, 0.0)) + _derivative = 0.0; + else + _derivative = _K_d * (_error - _error_old) / _dt; _output = _proportional + _integral + _derivative; } diff --git a/framework/src/chaincontrols/SmootherChainControl.C b/framework/src/chaincontrols/SmootherChainControl.C index 8c100c55db06..206844e9a5c7 100644 --- a/framework/src/chaincontrols/SmootherChainControl.C +++ b/framework/src/chaincontrols/SmootherChainControl.C @@ -8,6 +8,7 @@ //* https://www.gnu.org/licenses/lgpl-2.1.html #include "SmootherChainControl.h" +#include "MooseUtils.h" registerMooseObject("MooseApp", SmootherChainControl); @@ -31,12 +32,23 @@ SmootherChainControl::SmootherChainControl(const InputParameters & parameters) _input(getChainControlData("input")), _n_points(getParam("n_points")), _output(declareChainControlData("value")), - _values(declareRestartableData>("values")) + _values(declareRestartableData>("values")), + _previous_time(declareRestartableData("previous_time")) { + _previous_time = std::numeric_limits::max(); } void SmootherChainControl::execute() +{ + if (!MooseUtils::absoluteFuzzyEqual(_t, _previous_time)) + executeInner(); + + _previous_time = _t; +} + +void +SmootherChainControl::executeInner() { if (_values.size() == _n_points) _values.erase(_values.begin()); diff --git a/test/tests/chaincontrols/real_to_bool_chain_control/tests b/test/tests/chaincontrols/real_to_bool_chain_control/tests index d7b7eb9145f9..cbf6da3defac 100644 --- a/test/tests/chaincontrols/real_to_bool_chain_control/tests +++ b/test/tests/chaincontrols/real_to_bool_chain_control/tests @@ -12,6 +12,6 @@ input = 'real_to_bool_chain_control.i' cli_args = "Functions/test_fn/y='1 0.1 0 1'" expect_err = "The current input value \(0.1\) is not equal to 1 or 0" - requirement = 'The system shall be able to convert a floating point chain control data to a boolean chain control data.' + requirement = 'The system shall report an error if a value other than 0 or 1 is requested to be converted to a boolean chain control data.' [] [] From 8e663980e94175e9c304f3fee94872b0a7508b16 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Mon, 2 Dec 2024 10:23:20 -0600 Subject: [PATCH 12/14] Stabilized PID chain control test Refs #28948 --- .../gold/pid_chain_control_out.csv | 98 +++++++++---------- .../pid_chain_control/pid_chain_control.i | 2 +- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/test/tests/chaincontrols/pid_chain_control/gold/pid_chain_control_out.csv b/test/tests/chaincontrols/pid_chain_control/gold/pid_chain_control_out.csv index 7e3de486f69c..261b5045676e 100644 --- a/test/tests/chaincontrols/pid_chain_control/gold/pid_chain_control_out.csv +++ b/test/tests/chaincontrols/pid_chain_control/gold/pid_chain_control_out.csv @@ -1,52 +1,52 @@ time,pid 0,0 1,2.75 -2,2.0925 -3,2.72457325 -4,2.5335790726461 -5,2.8603066874179 -6,2.8245939220233 -7,3.0347665154606 -8,3.0551757345161 -9,3.210477510423 -10,3.2516113832507 -11,3.3763731064325 -12,3.4240711960446 -13,3.5294172459587 -14,3.5775155875617 -15,3.6692531500248 -16,3.7149091810977 -17,3.7964672179247 -18,3.8383194575783 -19,3.9119700047426 -20,3.949340804225 -21,4.0167598252515 -22,4.0492767273709 -23,4.111829896963 -24,4.1392259316177 -25,4.1981339660993 -26,4.2201260169629 -27,4.2765779276254 -28,4.2927760190116 -29,4.3480245216194 -30,4.3578463789645 -31,4.4133061808244 -32,4.4158794424525 -33,4.4732448152774 -34,4.4672807495646 -35,4.5286794628989 -36,4.5122994252546 -37,4.5805044412438 -38,4.5509940844949 -39,4.629722476961 -40,4.58317830081 -41,4.6775196544384 -42,4.6083363386246 -43,4.7253722621867 -44,4.6254948562475 -45,4.7752000602772 -46,4.6330286760548 -47,4.8295863577061 -48,4.628367040742 -49,4.8920922443363 -50,4.6075489928787 +2,2.1605625 +3,2.6637861348789 +4,2.5947337476189 +5,2.81650949015 +6,2.8656107885233 +7,3.0065146712945 +8,3.0828344330724 +9,3.1916846519567 +10,3.2712996200986 +11,3.3629990118508 +12,3.4389714625262 +13,3.5191215774723 +14,3.5894692854152 +15,3.6606766993981 +16,3.7250285546926 +17,3.7887827740948 +18,3.8473265540615 +19,3.9046346579664 +20,3.9577507164896 +21,4.0093775482596 +22,4.0575010072844 +23,4.1040703645717 +24,4.1476366426403 +25,4.1896787122161 +26,4.2291018140475 +27,4.2670779718636 +28,4.3027424434232 +29,4.3370597205796 +30,4.3693185454681 +31,4.4003389837142 +32,4.4295141089279 +33,4.4575613761066 +34,4.4839453777215 +35,4.5093097888062 +36,4.5331679830962 +37,4.5561105157415 +38,4.5776831846797 +39,4.5984388112829 +40,4.6179433842362 +41,4.6367239079092 +42,4.6543570262116 +43,4.6713535367792 +44,4.6872929705011 +45,4.7026779970274 +46,4.7170844049218 +47,4.7310138181602 +48,4.7440323527123 +49,4.7566470567291 +50,4.7684088215926 diff --git a/test/tests/chaincontrols/pid_chain_control/pid_chain_control.i b/test/tests/chaincontrols/pid_chain_control/pid_chain_control.i index 3c3196c5f5cf..2e8003dd930e 100644 --- a/test/tests/chaincontrols/pid_chain_control/pid_chain_control.i +++ b/test/tests/chaincontrols/pid_chain_control/pid_chain_control.i @@ -30,7 +30,7 @@ set_point = y_set_ctrl:value K_p = 0.1 K_i = 0.01 - K_d = 0.01 + K_d = 0.001 [] [] From 72e989e47f8cfa185b579337e8a38bd1a81b4421 Mon Sep 17 00:00:00 2001 From: "Joshua E. Hansel" Date: Mon, 2 Dec 2024 10:53:48 -0600 Subject: [PATCH 13/14] Improved chain control doc Refs #28948 --- .../source/chaincontrols/GetFunctionValueChainControl.md | 4 ++-- .../source/chaincontrols/GetPostprocessorChainControl.md | 2 +- .../doc/content/source/chaincontrols/LimitChainControl.md | 2 +- framework/doc/content/source/chaincontrols/PIDChainControl.md | 2 +- .../doc/content/source/chaincontrols/ParsedChainControl.md | 2 +- .../content/source/chaincontrols/RealToBoolChainControl.md | 2 +- .../doc/content/source/chaincontrols/ScaleOldChainControl.md | 2 +- .../doc/content/source/chaincontrols/SmootherChainControl.md | 2 +- .../doc/content/source/chaincontrols/UnitTripChainControl.md | 2 +- framework/include/chaincontrols/LimitChainControl.h | 4 ++-- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/framework/doc/content/source/chaincontrols/GetFunctionValueChainControl.md b/framework/doc/content/source/chaincontrols/GetFunctionValueChainControl.md index 387d1bf019be..9b53accfc899 100644 --- a/framework/doc/content/source/chaincontrols/GetFunctionValueChainControl.md +++ b/framework/doc/content/source/chaincontrols/GetFunctionValueChainControl.md @@ -1,8 +1,8 @@ # GetFunctionValueChainControl This [ChainControl](syntax/ChainControls/index.md) creates a new [/ChainControlData.md] -named `:value`, where `` is the name of the `ChainControl` -object, and it computes its value by evaluating a given [Function](syntax/Functions/index.md) +named `:value`, where `` 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 diff --git a/framework/doc/content/source/chaincontrols/GetPostprocessorChainControl.md b/framework/doc/content/source/chaincontrols/GetPostprocessorChainControl.md index 53a47138fb3a..fb3a95b99800 100644 --- a/framework/doc/content/source/chaincontrols/GetPostprocessorChainControl.md +++ b/framework/doc/content/source/chaincontrols/GetPostprocessorChainControl.md @@ -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 `:value`, where `` -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. diff --git a/framework/doc/content/source/chaincontrols/LimitChainControl.md b/framework/doc/content/source/chaincontrols/LimitChainControl.md index 99d6fb561177..d9e041f0c84f 100644 --- a/framework/doc/content/source/chaincontrols/LimitChainControl.md +++ b/framework/doc/content/source/chaincontrols/LimitChainControl.md @@ -3,7 +3,7 @@ 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 `:value`, where `` is the -user-given name of the control. +user-given name of the `LimitChainControl`. !syntax parameters /ChainControls/LimitChainControl diff --git a/framework/doc/content/source/chaincontrols/PIDChainControl.md b/framework/doc/content/source/chaincontrols/PIDChainControl.md index d33354699cb3..28a1b3925d72 100644 --- a/framework/doc/content/source/chaincontrols/PIDChainControl.md +++ b/framework/doc/content/source/chaincontrols/PIDChainControl.md @@ -35,7 +35,7 @@ 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 `:value`, where `` - is the user-given name of the control object. + 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$, diff --git a/framework/doc/content/source/chaincontrols/ParsedChainControl.md b/framework/doc/content/source/chaincontrols/ParsedChainControl.md index ece47f94a311..1dccf7e553dd 100644 --- a/framework/doc/content/source/chaincontrols/ParsedChainControl.md +++ b/framework/doc/content/source/chaincontrols/ParsedChainControl.md @@ -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 `:value`, where `` is the user-given name of the control. +named `:value`, where `` 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) diff --git a/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md b/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md index 1a008937c172..2b47b11b2fc9 100644 --- a/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md +++ b/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md @@ -2,7 +2,7 @@ This [ChainControl](syntax/ChainControls/index.md) converts a `Real`-valued [chain control data](/ChainControlData.md) to a `bool` data, with the name -`:value`, where `` is the user-given name of the control: +`:value`, where `` is the user-given name of the `RealToBoolChainControl`: - A value of 1 converts to `true`. - A value of 0 converts to `false`. diff --git a/framework/doc/content/source/chaincontrols/ScaleOldChainControl.md b/framework/doc/content/source/chaincontrols/ScaleOldChainControl.md index 69ce4691e428..5028abeebf12 100644 --- a/framework/doc/content/source/chaincontrols/ScaleOldChainControl.md +++ b/framework/doc/content/source/chaincontrols/ScaleOldChainControl.md @@ -4,7 +4,7 @@ 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 `:value`, where `` is the -user-given name of the control. +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. diff --git a/framework/doc/content/source/chaincontrols/SmootherChainControl.md b/framework/doc/content/source/chaincontrols/SmootherChainControl.md index 1243e5f9e326..f9fed769a7a4 100644 --- a/framework/doc/content/source/chaincontrols/SmootherChainControl.md +++ b/framework/doc/content/source/chaincontrols/SmootherChainControl.md @@ -10,7 +10,7 @@ values $y$: where $i$ represents the time index. The resulting value is named `:value`, where `` is the -user-given name of the control. +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 diff --git a/framework/doc/content/source/chaincontrols/UnitTripChainControl.md b/framework/doc/content/source/chaincontrols/UnitTripChainControl.md index eea022f1cba9..e08c7d145da8 100644 --- a/framework/doc/content/source/chaincontrols/UnitTripChainControl.md +++ b/framework/doc/content/source/chaincontrols/UnitTripChainControl.md @@ -4,7 +4,7 @@ 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 `:tripped`, where `` is the -user-given name of the control. +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` diff --git a/framework/include/chaincontrols/LimitChainControl.h b/framework/include/chaincontrols/LimitChainControl.h index 56c2663df1a4..77bdcbee93e3 100644 --- a/framework/include/chaincontrols/LimitChainControl.h +++ b/framework/include/chaincontrols/LimitChainControl.h @@ -24,9 +24,9 @@ class LimitChainControl : public ChainControl virtual void execute() override; protected: - /// Minimum value to apply to control data + /// Lower bound to apply to control data const Real _min_value; - /// Maximum value to apply to control data + /// Upper bound to apply to control data const Real _max_value; /// Control value before limiting const Real & _unlimited_value; From 4ac8a27ce91a578b26d6d88fd25372fbb8c6aee9 Mon Sep 17 00:00:00 2001 From: joshuahansel Date: Mon, 2 Dec 2024 10:56:04 -0600 Subject: [PATCH 14/14] Apply suggestions from code review Co-authored-by: Guillaume Giudicelli --- .../doc/content/source/chaincontrols/RealToBoolChainControl.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md b/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md index 2b47b11b2fc9..f4dba0edf93e 100644 --- a/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md +++ b/framework/doc/content/source/chaincontrols/RealToBoolChainControl.md @@ -8,6 +8,8 @@ This [ChainControl](syntax/ChainControls/index.md) converts a `Real`-valued - A value of 0 converts to `false`. - Other values result in an error. +Note that the tolerance on the value is 1e-12 in a double-precision MOOSE build. + !syntax parameters /ChainControls/RealToBoolChainControl !syntax inputs /ChainControls/RealToBoolChainControl