https://mooseframework.inl.gov
ParsedODEKernel.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 "ParsedODEKernel.h"
11 
12 // MOOSE includes
13 #include "MooseVariableScalar.h"
14 #include "SystemBase.h"
15 #include "MooseApp.h"
16 
17 #include "libmesh/fparser_ad.hh"
18 
20 
23 {
26  params.addClassDescription("Parsed expression ODE kernel.");
27 
28  params.addRequiredCustomTypeParam<std::string>(
29  "function", "FunctionExpression", "function expression");
30  params.deprecateParam("function", "expression", "02/07/2024");
31  params.addCoupledVar("args", "Scalar variables coupled in the parsed expression.");
32  params.deprecateCoupledVar("args", "coupled_variables", "02/07/2024");
33  params.addParam<std::vector<std::string>>(
34  "constant_names", {}, "Vector of constants used in the parsed expression");
35  params.addParam<std::vector<std::string>>(
36  "constant_expressions",
37  {},
38  "Vector of values for the constants in constant_names (can be an FParser expression)");
39  params.addParam<std::vector<PostprocessorName>>(
40  "postprocessors", {}, "Vector of postprocessor names used in the function expression");
41 
42  return params;
43 }
44 
46  : ODEKernel(parameters),
47  FunctionParserUtils(parameters),
48  _function(getParam<std::string>("expression")),
49  _nargs(isCoupledScalar("coupled_variables") ? coupledScalarComponents("coupled_variables") : 0),
50  _args(_nargs),
51  _arg_names(_nargs),
52  _func_dFdarg(_nargs),
53  _number_of_nl_variables(_sys.nVariables()),
54  _arg_index(_number_of_nl_variables, -1)
55 {
56  // build variables argument (start with variable the kernel is operating on)
57  std::string variables = _var.name();
58 
59  // add additional coupled variables
60  for (unsigned int i = 0; i < _nargs; ++i)
61  {
62  _arg_names[i] = getScalarVar("coupled_variables", i)->name();
63  variables += "," + _arg_names[i];
64  _args[i] = &coupledScalarValue("coupled_variables", i);
65 
66  // populate number -> arg index lookup table skipping aux variables
67  unsigned int number = coupledScalar("coupled_variables", i);
68  if (number < _number_of_nl_variables)
69  _arg_index[number] = i;
70  }
71 
72  // add postprocessors
73  auto pp_names = getParam<std::vector<PostprocessorName>>("postprocessors");
74  _pp.resize(pp_names.size());
75  for (unsigned int i = 0; i < pp_names.size(); ++i)
76  {
77  variables += "," + pp_names[i];
78  _pp[i] = &getPostprocessorValueByName(pp_names[i]);
79  }
80 
81  // Note: we do not use the FunctionParsedUtils::parsedFunctionSetup because we are building
82  // multiple expressions, and we can share the MPI barriers by keeping the code here.
83  // base function object
84  _func_F = std::make_shared<SymFunction>();
85 
86  // set FParser interneal feature flags
88 
89  // add the constant expressions
91  getParam<std::vector<std::string>>("constant_names"),
92  getParam<std::vector<std::string>>("constant_expressions"));
93 
94  // parse function
95  if (_func_F->Parse(_function, variables) >= 0)
96  mooseError("Invalid function\n",
97  _function,
98  "\nin ParsedODEKernel ",
99  name(),
100  ".\n",
101  _func_F->ErrorMsg());
102 
103  // on-diagonal derivative
104  _func_dFdu = std::make_shared<SymFunction>(*_func_F);
105 
106  // let rank 0 do the work first (diff and JIT) to populate caches
107  if (_communicator.rank() != 0)
109 
110  if (_func_dFdu->AutoDiff(_var.name()) != -1)
111  mooseError("Failed to take first derivative w.r.t. ", _var.name());
112 
113  // off-diagonal derivatives
114  for (unsigned int i = 0; i < _nargs; ++i)
115  {
116  _func_dFdarg[i] = std::make_shared<SymFunction>(*_func_F);
117 
118  if (_func_dFdarg[i]->AutoDiff(_arg_names[i]) != -1)
119  mooseError("Failed to take first derivative w.r.t. ", _arg_names[i]);
120  }
121 
122  // optimize
124  {
125  _func_F->Optimize();
126  _func_dFdu->Optimize();
127  for (unsigned int i = 0; i < _nargs; ++i)
128  _func_dFdarg[i]->Optimize();
129  }
130 
131  // just-in-time compile
132  if (_enable_jit)
133  {
134  _func_F->JITCompile();
135  _func_dFdu->JITCompile();
136  for (unsigned int i = 0; i < _nargs; ++i)
137  _func_dFdarg[i]->JITCompile();
138  }
139 
140  // wait for ranks > 0 to catch up
141  if (_communicator.rank() == 0)
143 
144  // reserve storage for parameter passing buffer
145  _func_params.resize(1 + _nargs + _pp.size());
146 }
147 
148 void
150 {
151  _func_params[0] = _u[_i];
152 
153  for (unsigned int j = 0; j < _nargs; ++j)
154  _func_params[j + 1] = (*_args[j])[_i];
155  for (unsigned int j = 0; j < _pp.size(); ++j)
156  _func_params[j + 1 + _nargs] = *_pp[j];
157 }
158 
159 Real
161 {
162  updateParams();
163  return evaluate(_func_F);
164 }
165 
166 Real
168 {
169  updateParams();
170  return evaluate(_func_dFdu);
171 }
172 
173 Real
175 {
176  int i = _arg_index[jvar];
177  if (i < 0)
178  return 0.0;
179 
180  updateParams();
181  return evaluate(_func_dFdarg[i]);
182 }
std::vector< std::string > _arg_names
GenericReal< is_ad > evaluate(SymFunctionPtr &, const std::string &object_name="")
Evaluate FParser object and check EvalError.
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
Parsed ODE function kernel.
std::vector< SymFunctionPtr > _func_dFdarg
function parser objects for the Jacobian
std::vector< const PostprocessorValue * > _pp
coupled postprocessors
const std::string & name() const override
Get the variable name.
processor_id_type rank() const
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
std::string _function
function expression
MooseVariableScalar & _var
Scalar variable.
SymFunctionPtr _func_dFdu
std::vector< unsigned int > _arg_index
Vector to look up the internal coupled variable index into arg* through the libMesh variable number...
const Parallel::Communicator & _communicator
registerMooseObject("MooseApp", ParsedODEKernel)
ParsedODEKernel(const InputParameters &parameters)
virtual const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:57
virtual Real computeQpOffDiagJacobianScalar(unsigned int jvar) override
virtual Real computeQpJacobian() override
void deprecateParam(const std::string &old_name, const std::string &new_name, const std::string &removal_date)
const VariableValue & coupledScalarValue(const std::string &var_name, unsigned int comp=0) const
Returns value of a scalar coupled variable.
SymFunctionPtr _func_F
function parser object for the residual and on-diagonal Jacobian
const unsigned int _number_of_nl_variables
number of non-linear variables in the problem
const MooseVariableScalar * getScalarVar(const std::string &var_name, unsigned int comp) const
Extract pointer to a scalar coupled variable.
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
void deprecateCoupledVar(const std::string &old_name, const std::string &new_name, const std::string &removal_date)
unsigned int coupledScalar(const std::string &var_name, unsigned int comp=0) const
Returns the index for a scalar coupled variable by name.
const VariableValue & _u
The current solution (old solution if explicit)
Definition: ScalarKernel.h:28
void addCoupledVar(const std::string &name, const std::string &doc_string)
This method adds a coupled variable name pair.
virtual const PostprocessorValue & getPostprocessorValueByName(const PostprocessorName &name) const
Retrieve the value of the Postprocessor.
virtual Real computeQpResidual() override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::vector< GenericReal< is_ad > > _func_params
Array to stage the parameters passed to the functions when calling Eval.
unsigned int _nargs
coupled variables
static InputParameters validParams()
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
void addRequiredCustomTypeParam(const std::string &name, const std::string &custom_type, const std::string &doc_string)
These methods add an option parameter and with a customer type to the InputParameters object...
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
static InputParameters validParams()
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...
static InputParameters validParams()
Definition: ODEKernel.C:18
std::vector< const VariableValue * > _args
void setParserFeatureFlags(SymFunctionPtr &) const
apply input parameters to internal feature flags of the parser object