https://mooseframework.inl.gov
Loading...
Searching...
No Matches
FunctionParserUtils.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "FunctionParserUtils.h"
11
12// MOOSE includes
13#include "InputParameters.h"
14#include "MooseEnum.h"
15
16template <bool is_ad>
19{
21
22 params.addParam<bool>(
23 "enable_jit",
24#ifdef LIBMESH_HAVE_FPARSER_JIT
25 true,
26#else
27 false,
28#endif
29 "Enable just-in-time compilation of function expressions for faster evaluation");
30 params.addParam<bool>(
31 "enable_ad_cache", true, "Enable caching of function derivatives for faster startup time");
32 params.addParam<bool>(
33 "enable_auto_optimize", true, "Enable automatic immediate optimization of derivatives");
34 params.addParam<bool>(
35 "disable_fpoptimizer", false, "Disable the function parser algebraic optimizer");
36 MooseEnum evalerror("nan nan_warning error exception", "nan");
37 params.addParam<MooseEnum>("evalerror_behavior",
38 evalerror,
39 "What to do if evaluation error occurs. Options are to pass a nan, "
40 "pass a nan with a warning, throw a error, or throw an exception");
41
43 "enable_jit enable_ad_cache enable_auto_optimize disable_fpoptimizer evalerror_behavior",
44 "Parsed expression advanced");
45 params.addParam<Real>("epsilon", 0, "Fuzzy comparison tolerance");
46 return params;
47}
48
49template <bool is_ad>
51 "Unknown",
52 "Division by zero",
53 "Square root of a negative value",
54 "Logarithm of negative value",
55 "Trigonometric error (asin or acos of illegal value)",
56 "Maximum recursion level reached"};
57
58template <bool is_ad>
60 : _enable_jit(parameters.isParamValid("enable_jit") && parameters.get<bool>("enable_jit")),
61 _enable_ad_cache(parameters.get<bool>("enable_ad_cache")),
62 _disable_fpoptimizer(parameters.get<bool>("disable_fpoptimizer")),
63 _enable_auto_optimize(parameters.get<bool>("enable_auto_optimize") && !_disable_fpoptimizer),
64 _evalerror_behavior(parameters.get<MooseEnum>("evalerror_behavior").getEnum<FailureMethod>()),
65 _quiet_nan(std::numeric_limits<Real>::quiet_NaN()),
66 _epsilon(parameters.get<Real>("epsilon"))
67{
68#ifndef LIBMESH_HAVE_FPARSER_JIT
69 if (_enable_jit)
70 {
71 mooseWarning("Tried to enable FParser JIT but libmesh does not have it compiled in.");
72 _enable_jit = false;
73 }
74#endif
75}
76
77template <bool is_ad>
78void
79FunctionParserUtils<is_ad>::setParserFeatureFlags(SymFunctionPtr & parser) const
80{
81 parser->SetADFlags(SymFunction::ADCacheDerivatives, _enable_ad_cache);
82 parser->SetADFlags(SymFunction::ADAutoOptimize, _enable_auto_optimize);
83}
84
85template <bool is_ad>
87FunctionParserUtils<is_ad>::evaluate(SymFunctionPtr & parser, const std::string & name)
88{
89 return evaluate(parser, _func_params, name);
90}
91
92template <bool is_ad>
94FunctionParserUtils<is_ad>::evaluate(SymFunctionPtr & parser,
95 const std::vector<GenericReal<is_ad>> & func_params,
96 const std::string & name)
97{
98 using std::isnan;
99
100 // null pointer is a shortcut for vanishing derivatives, see functionsOptimize()
101 if (parser == NULL)
102 return 0.0;
103
104 // set desired epsilon
105 auto tmp_eps = parser->epsilon();
106 parser->setEpsilon(_epsilon);
107
108 // evaluate expression
109 auto result = parser->Eval(func_params.data());
110
111 // restore epsilon
112 parser->setEpsilon(tmp_eps);
113
114 // fetch fparser evaluation error (set to unknown if the JIT result is nan)
115 int error_code = _enable_jit ? (isnan(result) ? -1 : 0) : parser->EvalError();
116
117 // no error
118 if (error_code == 0)
119 return result;
120
121 // hard fail or return not a number
122 switch (_evalerror_behavior)
123 {
124 case FailureMethod::nan:
125 return _quiet_nan;
126
127 case FailureMethod::nan_warning:
128 mooseWarning("In ",
129 name,
130 ": Parsed function evaluation encountered an error: ",
131 _eval_error_msg[(error_code < 0 || error_code > 5) ? 0 : error_code]);
132 return _quiet_nan;
133
134 case FailureMethod::error:
135 mooseError("In ",
136 name,
137 ": Parsed function evaluation encountered an error: ",
138 _eval_error_msg[(error_code < 0 || error_code > 5) ? 0 : error_code]);
139
140 case FailureMethod::exception:
141 mooseException("In ",
142 name,
143 ": Parsed function evaluation encountered an error: ",
144 _eval_error_msg[(error_code < 0 || error_code > 5) ? 0 : error_code],
145 "\n Cutting timestep");
146 }
147
148 return _quiet_nan;
149}
150
151template <bool is_ad>
152void
154 SymFunctionPtr & parser,
155 const std::vector<std::string> & constant_names,
156 const std::vector<std::string> & constant_expressions) const
157{
158 // check constant vectors
159 unsigned int nconst = constant_expressions.size();
160 if (nconst != constant_names.size())
161 mooseError("The parameter vectors constant_names (size " +
162 std::to_string(constant_names.size()) + ") and constant_expressions (size " +
163 std::to_string(nconst) + ") must have equal length.");
164
165 // previously evaluated constant_expressions may be used in following constant_expressions
166 std::vector<Real> constant_values(nconst);
167
168 for (unsigned int i = 0; i < nconst; ++i)
169 {
170 // no need to use dual numbers for the constant expressions
171 auto expression = std::make_shared<FunctionParserADBase<Real>>();
172
173 // add previously evaluated constants
174 for (unsigned int j = 0; j < i; ++j)
175 if (!expression->AddConstant(constant_names[j], constant_values[j]))
176 mooseError("Invalid constant name: ", constant_names[j], " and value ", constant_values[j]);
177
178 // build the temporary constant expression function
179 if (expression->Parse(constant_expressions[i], "") >= 0)
180 mooseError("Invalid constant expression\n",
181 constant_expressions[i],
182 "\n in parsed function object.\n",
183 expression->ErrorMsg());
184
185 constant_values[i] = expression->Eval(NULL);
186
187 if (!parser->AddConstant(constant_names[i], constant_values[i]))
188 mooseError("Invalid constant name in parsed function object");
189 }
190}
191
192template <>
193void
194FunctionParserUtils<false>::functionsOptimize(SymFunctionPtr & parsed_function)
195{
196 // set desired epsilon for optimization!
197 auto tmp_eps = parsed_function->epsilon();
198 parsed_function->setEpsilon(_epsilon);
199
200 // base function
201 if (!_disable_fpoptimizer)
202 parsed_function->Optimize();
203 if (_enable_jit && !parsed_function->JITCompile())
204 mooseInfo("Failed to JIT compile expression, falling back to byte code interpretation.");
205
206 parsed_function->setEpsilon(tmp_eps);
207}
208
209template <>
210void
212{
213 // set desired epsilon for optimization!
214 auto tmp_eps = parsed_function->epsilon();
215 parsed_function->setEpsilon(_epsilon);
216
217 // base function
218 if (!_disable_fpoptimizer)
219 parsed_function->Optimize();
220 if (!_enable_jit || !parsed_function->JITCompile())
221 mooseError("AD parsed objects require JIT compilation to be enabled and working.");
222
223 parsed_function->setEpsilon(tmp_eps);
224}
225
226template <bool is_ad>
227void
229 SymFunctionPtr & function,
230 const std::string & expression,
231 const std::string & variables,
232 const std::vector<std::string> & constant_names,
233 const std::vector<std::string> & constant_expressions,
234 const libMesh::Parallel::Communicator & comm) const
235{
236 // set FParser internal feature flags
237 setParserFeatureFlags(function);
238
239 // add the constant expressions
240 addFParserConstants(function, constant_names, constant_expressions);
241
242 // parse function
243 if (function->Parse(expression, variables) >= 0)
244 mooseError("Invalid function\n", expression, "\nError:\n", function->ErrorMsg());
245
246 // optimize
247 if (!_disable_fpoptimizer)
248 function->Optimize();
249
250 // just-in-time compile
251 if (_enable_jit)
252 {
253 // let rank 0 do the JIT compilation first
254 if (comm.rank() != 0)
255 comm.barrier();
256
257 function->JITCompile();
258
259 // wait for ranks > 0 to catch up
260 if (comm.rank() == 0)
261 comm.barrier();
262 }
263}
264
265// explicit instantiation
266template class FunctionParserUtils<false>;
267template class FunctionParserUtils<true>;
InputParameters emptyInputParameters()
void mooseInfo(Args &&... args)
Emit an informational message with the given stringified, concatenated args.
Definition MooseError.h:401
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
T evaluate(Real, const Point &)
The general evaluation method is not defined.
Moose::GenericType< Real, is_ad > GenericReal
Definition MooseTypes.h:698
void addFParserConstants(SymFunctionPtr &parser, const std::vector< std::string > &constant_names, const std::vector< std::string > &constant_expressions) const
add constants (which can be complex expressions) to the parser object
std::shared_ptr< SymFunction > SymFunctionPtr
Shorthand for an smart pointer to an autodiff function parser object.
void setParserFeatureFlags(SymFunctionPtr &) const
apply input parameters to internal feature flags of the parser object
virtual void functionsOptimize(SymFunctionPtr &parsed_function)
run FPOptimizer on the parsed function
void parsedFunctionSetup(SymFunctionPtr &function, const std::string &expression, const std::string &variables, const std::vector< std::string > &constant_names, const std::vector< std::string > &constant_expressions, const libMesh::Parallel::Communicator &comm) const
Performs setup steps on a SymFunction.
FunctionParserUtils(const InputParameters &parameters)
GenericReal< is_ad > evaluate(SymFunctionPtr &, const std::string &object_name="")
Evaluate FParser object and check EvalError.
static InputParameters validParams()
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
processor_id_type rank() const
const Elem & get(const ElemType type_in)
bool isnan(std::complex< T > a)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real