forked from idaholab/moose
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
11 changed files
with
518 additions
and
0 deletions.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
framework/doc/content/source/convergence/ParsedConvergence.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# ParsedConvergence | ||
|
||
This [Convergence](Convergence/index.md) allows the user to specify arbitrary expressions | ||
for convergence and divergence criteria. These expressions | ||
([!param](/Convergence/ParsedConvergence/convergence_expression) and [!param](/Convergence/ParsedConvergence/divergence_expression)) | ||
may contain any of the following: | ||
|
||
- `Convergence` objects | ||
- [Functions](Functions/index.md) | ||
- [Post-processors](Postprocessors/index.md) | ||
- Constant values | ||
|
||
The expressions are parsed using the [Function Parser syntax](http://warp.povusers.org/FunctionParser/fparser.html#functionsyntax). | ||
The full library of mathematical operators is valid in the parsed | ||
expression, but for convenience, we list some of the logical and comparison operators here: | ||
|
||
| Syntax | Description | | ||
| :- | :- | | ||
| `()` | Parentheses for order of operations | | ||
| `!A` | *NOT* `A` | | ||
| `A & B` | `A` *AND* `B` | | ||
| `A` I `B` | `A` *OR* `B` | | ||
| `A = B` | `A` *EQUALS* `B` | | ||
| `A != B` | `A` *DOES NOT EQUAL* `B` | | ||
| `A >= B` | `A` *GREATER THAN OR EQUAL TO* `B` | | ||
|
||
The expressions must evaluate to either 1 or 0, which correspond to `true` or `false`, | ||
respectively; if the expression returns another value, an error results. Note | ||
the following rules for the `Convergence` object values: | ||
|
||
- For the convergence expression, `Convergence` objects evaluate to `true` if they | ||
are `CONVERGED` and `false` otherwise (`ITERATING` or `DIVERGED`). | ||
- For the divergence expression, `Convergence` objects evaluate to `true` if they | ||
are `DIVERGED` and `false` otherwise (`ITERATING` or `CONVERGED`). | ||
|
||
The divergence expression is optional. If omitted, divergence occurs if any of | ||
the supplied `Convergence` objects return `DIVERGED`, e.g., | ||
|
||
``` | ||
divergence_expression = 'conv1 | conv2 | conv3' | ||
``` | ||
|
||
if [!param](/Convergence/ParsedConvergence/symbol_values) contains `conv1`, `conv2`, and `conv3`. | ||
|
||
!syntax parameters /Convergence/ParsedConvergence | ||
|
||
!syntax inputs /Convergence/ParsedConvergence | ||
|
||
!syntax children /Convergence/ParsedConvergence |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
//* 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 "Convergence.h" | ||
#include "FunctionParserUtils.h" | ||
|
||
/** | ||
* Evaluates convergence from a parsed expression. | ||
*/ | ||
class ParsedConvergence : public Convergence, public FunctionParserUtils<false> | ||
{ | ||
public: | ||
static InputParameters validParams(); | ||
|
||
ParsedConvergence(const InputParameters & parameters); | ||
|
||
virtual MooseConvergenceStatus checkConvergence(unsigned int iter) override; | ||
|
||
virtual void initialSetup() override; | ||
|
||
protected: | ||
usingFunctionParserUtilsMembers(false); | ||
|
||
/** | ||
* Initializes symbols used in the parsed expression | ||
*/ | ||
void initializeSymbols(); | ||
void initializePostprocessorSymbol(unsigned int i); | ||
void initializeFunctionSymbol(unsigned int i); | ||
void initializeConvergenceSymbol(unsigned int i); | ||
void initializeConstantSymbol(unsigned int i); | ||
|
||
/** | ||
* Makes a parsed function | ||
* | ||
* @param[in] expression expression to parse | ||
*/ | ||
SymFunctionPtr makeParsedFunction(const std::string & expression); | ||
|
||
/** | ||
* Updates non-constant symbol values | ||
* | ||
* @param[in] iter Iteration index | ||
*/ | ||
void updateSymbolValues(unsigned int iter); | ||
void updatePostprocessorSymbolValues(); | ||
void updateFunctionSymbolValues(); | ||
void updateConvergenceSymbolValues(unsigned int iter); | ||
|
||
/** | ||
* Converts a Real value to a bool. Error results if value is not 0 or 1. | ||
* | ||
* @param[in] value Real value to convert | ||
* @param[in] param Name of the corresponding input parameter | ||
*/ | ||
bool convertRealToBool(Real value, const std::string & param) const; | ||
|
||
FEProblemBase & _fe_problem; | ||
|
||
std::vector<std::string> _symbol_names; | ||
std::vector<std::string> _symbol_values; | ||
|
||
/// Expression to parse for convergence | ||
const std::string _convergence_expression; | ||
/// Expression to parse for divergence | ||
const std::string _divergence_expression; | ||
|
||
/// Parsed function for convergence | ||
SymFunctionPtr _convergence_function; | ||
/// Parsed function for divergence | ||
SymFunctionPtr _divergence_function; | ||
|
||
/// Convergence function parameters | ||
std::vector<Real> _convergence_function_params; | ||
/// Divergence function parameters | ||
std::vector<Real> _divergence_function_params; | ||
|
||
/// Post-processor values in the provided symbols | ||
std::vector<const PostprocessorValue *> _pp_values; | ||
std::vector<unsigned int> _pp_indices; | ||
|
||
/// Functions in the provided symbols | ||
std::vector<Function *> _functions; | ||
std::vector<unsigned int> _function_indices; | ||
|
||
/// Convergences in the provided symbols | ||
std::vector<Convergence *> _convergences; | ||
std::vector<std::string> _convergence_symbol_names; | ||
std::vector<unsigned int> _convergence_indices; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
//* 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 "ParsedConvergence.h" | ||
#include "MooseUtils.h" | ||
#include "Function.h" | ||
|
||
registerMooseObject("MooseApp", ParsedConvergence); | ||
|
||
InputParameters | ||
ParsedConvergence::validParams() | ||
{ | ||
InputParameters params = Convergence::validParams(); | ||
params += FunctionParserUtils<false>::validParams(); | ||
|
||
params.addClassDescription("Evaluates convergence from a parsed expression."); | ||
|
||
params.addRequiredCustomTypeParam<std::string>( | ||
"convergence_expression", "FunctionExpression", "Expression to parse for convergence"); | ||
params.addCustomTypeParam<std::string>( | ||
"divergence_expression", "FunctionExpression", "Expression to parse for divergence"); | ||
params.addParam<std::vector<std::string>>( | ||
"symbol_names", {}, "Symbol names to use in the parsed expressions"); | ||
params.addParam<std::vector<std::string>>( | ||
"symbol_values", | ||
{}, | ||
"Values (Convergence names, Postprocessor names, Function names, and constants) " | ||
"corresponding to each entry in 'symbol_names'"); | ||
|
||
return params; | ||
} | ||
|
||
ParsedConvergence::ParsedConvergence(const InputParameters & parameters) | ||
: Convergence(parameters), | ||
FunctionParserUtils<false>(parameters), | ||
_fe_problem(*getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")), | ||
_symbol_names(getParam<std::vector<std::string>>("symbol_names")), | ||
_symbol_values(getParam<std::vector<std::string>>("symbol_values")), | ||
_convergence_function_params(_symbol_names.size(), 0.0), | ||
_divergence_function_params(_symbol_names.size(), 0.0) | ||
{ | ||
if (_symbol_names.size() != _symbol_values.size()) | ||
mooseError("The parameters 'symbol_names' and 'symbol_values' must have the same size."); | ||
} | ||
|
||
void | ||
ParsedConvergence::initialSetup() | ||
{ | ||
Convergence::initialSetup(); | ||
|
||
initializeSymbols(); | ||
|
||
const auto convergence_expression = getParam<std::string>("convergence_expression"); | ||
_convergence_function = makeParsedFunction(convergence_expression); | ||
|
||
const auto divergence_expression = isParamValid("divergence_expression") | ||
? getParam<std::string>("divergence_expression") | ||
: MooseUtils::join(_convergence_symbol_names, "|"); | ||
_divergence_function = makeParsedFunction(divergence_expression); | ||
} | ||
|
||
void | ||
ParsedConvergence::initializeSymbols() | ||
{ | ||
for (const auto i : index_range(_symbol_values)) | ||
{ | ||
ReporterName reporter_name(_symbol_values[i], "value"); | ||
if (_fe_problem.getReporterData().hasReporterValue<PostprocessorValue>(reporter_name)) | ||
initializePostprocessorSymbol(i); | ||
else if (_fe_problem.hasFunction(_symbol_values[i])) | ||
initializeFunctionSymbol(i); | ||
else if (_fe_problem.hasConvergence(_symbol_values[i])) | ||
initializeConvergenceSymbol(i); | ||
else | ||
initializeConstantSymbol(i); | ||
} | ||
} | ||
|
||
void | ||
ParsedConvergence::initializePostprocessorSymbol(unsigned int i) | ||
{ | ||
const PostprocessorValue & pp_value = _fe_problem.getPostprocessorValueByName(_symbol_values[i]); | ||
_pp_values.push_back(&pp_value); | ||
_pp_indices.push_back(i); | ||
} | ||
|
||
void | ||
ParsedConvergence::initializeFunctionSymbol(unsigned int i) | ||
{ | ||
Function & function = _fe_problem.getFunction(_symbol_values[i], _tid); | ||
_functions.push_back(&function); | ||
_function_indices.push_back(i); | ||
} | ||
|
||
void | ||
ParsedConvergence::initializeConvergenceSymbol(unsigned int i) | ||
{ | ||
Convergence & convergence = _fe_problem.getConvergence(_symbol_values[i], _tid); | ||
_convergences.push_back(&convergence); | ||
_convergence_symbol_names.push_back(_symbol_names[i]); | ||
_convergence_indices.push_back(i); | ||
} | ||
|
||
void | ||
ParsedConvergence::initializeConstantSymbol(unsigned int i) | ||
{ | ||
try | ||
{ | ||
const Real value = MooseUtils::convert<Real>(_symbol_values[i], true); | ||
_convergence_function_params[i] = value; | ||
_divergence_function_params[i] = value; | ||
} | ||
catch (const std::invalid_argument & e) | ||
{ | ||
mooseError( | ||
"The 'symbol_values' entry '", | ||
_symbol_values[i], | ||
"' is not a constant value or the name of a Convergence, Postprocessor, or Function.", | ||
e.what()); | ||
} | ||
} | ||
|
||
ParsedConvergence::SymFunctionPtr | ||
ParsedConvergence::makeParsedFunction(const std::string & expression) | ||
{ | ||
auto sym_function = std::make_shared<SymFunction>(); | ||
|
||
setParserFeatureFlags(sym_function); | ||
|
||
// Add constants | ||
sym_function->AddConstant("pi", std::acos(Real(-1))); | ||
sym_function->AddConstant("e", std::exp(Real(1))); | ||
|
||
// Parse the expression | ||
const auto symbols_str = Moose::stringify(_symbol_names); | ||
if (sym_function->Parse(expression, symbols_str) >= 0) | ||
mooseError("The expression\n '", | ||
expression, | ||
"'\nwith symbols\n '", | ||
symbols_str, | ||
"'\ncould not be parsed:\n", | ||
sym_function->ErrorMsg()); | ||
|
||
// Optimize the parsed function | ||
functionsOptimize(sym_function); | ||
|
||
return sym_function; | ||
} | ||
|
||
Convergence::MooseConvergenceStatus | ||
ParsedConvergence::checkConvergence(unsigned int iter) | ||
{ | ||
updateSymbolValues(iter); | ||
|
||
const Real converged_real = evaluate(_convergence_function, _convergence_function_params, name()); | ||
const Real diverged_real = evaluate(_divergence_function, _divergence_function_params, name()); | ||
|
||
if (convertRealToBool(diverged_real, "divergence_expression")) | ||
return MooseConvergenceStatus::DIVERGED; | ||
else if (convertRealToBool(converged_real, "convergence_expression")) | ||
return MooseConvergenceStatus::CONVERGED; | ||
else | ||
return MooseConvergenceStatus::ITERATING; | ||
} | ||
|
||
void | ||
ParsedConvergence::updateSymbolValues(unsigned int iter) | ||
{ | ||
updatePostprocessorSymbolValues(); | ||
updateFunctionSymbolValues(); | ||
updateConvergenceSymbolValues(iter); | ||
} | ||
|
||
void | ||
ParsedConvergence::updatePostprocessorSymbolValues() | ||
{ | ||
for (const auto i : index_range(_pp_indices)) | ||
{ | ||
_convergence_function_params[_pp_indices[i]] = (*_pp_values[i]); | ||
_divergence_function_params[_pp_indices[i]] = (*_pp_values[i]); | ||
} | ||
} | ||
|
||
void | ||
ParsedConvergence::updateFunctionSymbolValues() | ||
{ | ||
for (const auto i : index_range(_function_indices)) | ||
{ | ||
const Real function_value = _functions[i]->value(_t, Point(0, 0, 0)); | ||
_convergence_function_params[_function_indices[i]] = function_value; | ||
_divergence_function_params[_function_indices[i]] = function_value; | ||
} | ||
} | ||
|
||
void | ||
ParsedConvergence::updateConvergenceSymbolValues(unsigned int iter) | ||
{ | ||
for (const auto i : index_range(_convergence_indices)) | ||
{ | ||
const auto status = _convergences[i]->checkConvergence(iter); | ||
_convergence_function_params[_convergence_indices[i]] = | ||
status == MooseConvergenceStatus::CONVERGED; | ||
_divergence_function_params[_convergence_indices[i]] = | ||
status == MooseConvergenceStatus::DIVERGED; | ||
} | ||
} | ||
|
||
bool | ||
ParsedConvergence::convertRealToBool(Real value, const std::string & param) const | ||
{ | ||
if (MooseUtils::absoluteFuzzyEqual(value, 1.0)) | ||
return true; | ||
else if (MooseUtils::absoluteFuzzyEqual(value, 0.0)) | ||
return false; | ||
else | ||
mooseError("The expression parameter '", | ||
param, | ||
"' evaluated to the value ", | ||
value, | ||
", but it must only evaluate to either 0 or 1."); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.