https://mooseframework.inl.gov
ParsedMaterialHelper.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 "ParsedMaterialHelper.h"
11 
12 #include "libmesh/quadrature.h"
13 #include "Conversion.h"
14 
15 template <bool is_ad>
18 {
21  params.addClassDescription("Parsed Function Material.");
22  params.addParam<bool>("error_on_missing_material_properties",
23  true,
24  "Throw an error if any explicitly requested material property does not "
25  "exist. Otherwise assume it to be zero.");
26  MultiMooseEnum extra_symbols("x y z t dt");
27  params.addParam<MultiMooseEnum>(
28  "extra_symbols",
29  extra_symbols,
30  "Special symbols, like point coordinates, time, and timestep size.");
31  params.addParam<std::vector<MaterialName>>(
32  "upstream_materials",
33  std::vector<MaterialName>(),
34  "List of upstream material properties that must be evaluated when compute=false");
35  return params;
36 }
37 
38 template <bool is_ad>
40  const InputParameters & parameters,
41  const VariableNameMappingMode map_mode,
42  const std::optional<std::string> & function_param_name /* = {} */)
43  : FunctionMaterialBase<is_ad>(parameters),
44  FunctionParserUtils<is_ad>(parameters),
45  _symbol_names(_nargs),
46  _extra_symbols(this->template getParam<MultiMooseEnum>("extra_symbols")
47  .template getSetValueIDs<ExtraSymbols>()),
48  _tol(0),
49  _map_mode(map_mode),
50  _function_param_name(function_param_name),
51  _upstream_mat_names(this->template getParam<std::vector<MaterialName>>("upstream_materials")),
52  _error_on_missing_material_properties(
53  this->template getParam<bool>("error_on_missing_material_properties")),
54  _params(parameters)
55 {
57  mooseAssert(_params.have_parameter<std::string>(*_function_param_name),
58  "Does not have parameter");
59 }
60 
61 template <bool is_ad>
62 void
63 ParsedMaterialHelper<is_ad>::insertReservedNames(std::set<std::string> & reserved_names)
64 {
65  for (const auto symbol : _extra_symbols)
66  switch (symbol)
67  {
68  case ExtraSymbols::x:
69  reserved_names.insert("x");
70  break;
71  case ExtraSymbols::y:
72  reserved_names.insert("y");
73  break;
74  case ExtraSymbols::z:
75  reserved_names.insert("z");
76  break;
77  case ExtraSymbols::t:
78  reserved_names.insert("t");
79  break;
80  case ExtraSymbols::dt:
81  reserved_names.insert("dt");
82  break;
83  };
84 }
85 
86 template <bool is_ad>
87 void
88 ParsedMaterialHelper<is_ad>::functionParse(const std::string & function_expression)
89 {
90  const std::vector<std::string> empty_string_vector;
91  functionParse(function_expression, empty_string_vector, empty_string_vector);
92 }
93 
94 template <bool is_ad>
95 void
96 ParsedMaterialHelper<is_ad>::functionParse(const std::string & function_expression,
97  const std::vector<std::string> & constant_names,
98  const std::vector<std::string> & constant_expressions)
99 {
100  const std::vector<std::string> empty_string_vector;
101  const std::vector<Real> empty_real_vector;
102  functionParse(function_expression,
103  constant_names,
104  constant_expressions,
105  empty_string_vector,
106  empty_string_vector,
107  empty_real_vector);
108 }
109 
110 template <bool is_ad>
111 void
112 ParsedMaterialHelper<is_ad>::functionParse(const std::string & function_expression,
113  const std::vector<std::string> & constant_names,
114  const std::vector<std::string> & constant_expressions,
115  const std::vector<std::string> & mat_prop_expressions,
116  const std::vector<std::string> & tol_names,
117  const std::vector<Real> & tol_values)
118 {
119  const std::vector<PostprocessorName> empty_pp_name_vector;
120  functionParse(function_expression,
121  constant_names,
122  constant_expressions,
123  mat_prop_expressions,
124  empty_pp_name_vector,
125  tol_names,
126  tol_values);
127 }
128 
129 template <bool is_ad>
130 void
132  const std::string & function_expression,
133  const std::vector<std::string> & constant_names,
134  const std::vector<std::string> & constant_expressions,
135  const std::vector<std::string> & mat_prop_expressions,
136  const std::vector<PostprocessorName> & postprocessor_names,
137  const std::vector<std::string> & tol_names,
138  const std::vector<Real> & tol_values)
139 {
140  const std::vector<MooseFunctorName> empty_functor_vector;
141  const std::vector<std::string> empty_string_vector;
142  functionParse(function_expression,
143  constant_names,
144  constant_expressions,
145  mat_prop_expressions,
146  postprocessor_names,
147  tol_names,
148  tol_values,
149  empty_functor_vector,
150  empty_string_vector);
151 }
152 
153 template <bool is_ad>
154 void
156  const std::string & function_expression,
157  const std::vector<std::string> & constant_names,
158  const std::vector<std::string> & constant_expressions,
159  const std::vector<std::string> & mat_prop_expressions,
160  const std::vector<PostprocessorName> & postprocessor_names,
161  const std::vector<std::string> & tol_names,
162  const std::vector<Real> & tol_values,
163  const std::vector<MooseFunctorName> & functor_names,
164  const std::vector<std::string> & functor_symbols)
165 {
166  // build base function object
167  _func_F = std::make_shared<SymFunction>();
168 
169  // set FParser internal feature flags
170  setParserFeatureFlags(_func_F);
171 
172  // initialize constants
173  addFParserConstants(_func_F, constant_names, constant_expressions);
174 
175  // add further constants coming from default value coupling
176  if (_map_mode == VariableNameMappingMode::USE_PARAM_NAMES)
177  for (const auto & acd : _arg_constant_defaults)
178  if (!_func_F->AddConstant(acd, this->_pars.defaultCoupledValue(acd)))
179  _params.mooseError("Invalid constant name in parsed function object");
180 
181  // set variable names based on map_mode
182  switch (_map_mode)
183  {
184  case VariableNameMappingMode::USE_MOOSE_NAMES:
185  for (unsigned int i = 0; i < _nargs; ++i)
186  _symbol_names[i] = _arg_names[i];
187  break;
188 
189  case VariableNameMappingMode::USE_PARAM_NAMES:
190  for (unsigned i = 0; i < _nargs; ++i)
191  {
192  if (_arg_param_numbers[i] < 0)
193  _symbol_names[i] = _arg_param_names[i];
194  else
195  _symbol_names[i] = _arg_param_names[i] + std::to_string(_arg_param_numbers[i]);
196  }
197  break;
198 
199  default:
200  _params.mooseError("Unknown variable mapping mode.");
201  }
202 
203  // tolerance vectors
204  if (tol_names.size() != tol_values.size())
205  _params.mooseError("The parameter vectors tol_names and tol_values must have equal length.");
206 
207  // set tolerances
208  _tol.resize(_nargs);
209  for (const auto i : make_range(_nargs))
210  {
211  _tol[i] = -1.0;
212 
213  // for every argument look through the entire tolerance vector to find a match
214  for (const auto j : index_range(tol_names))
215  if (_symbol_names[i] == tol_names[j])
216  {
217  _tol[i] = tol_values[j];
218  break;
219  }
220  }
221 
222  // get all material properties
223  unsigned int nmat_props = mat_prop_expressions.size();
224  for (const auto i : make_range(nmat_props))
225  {
226  // parse the material property parameter entry into a FunctionMaterialPropertyDescriptor
227  _mat_prop_descriptors.emplace_back(
228  mat_prop_expressions[i], this, _error_on_missing_material_properties);
229 
230  // get the fparser symbol name for the new material property
231  _symbol_names.push_back(_mat_prop_descriptors.back().getSymbolName());
232  }
233 
234  // get all coupled postprocessors
235  for (const auto & pp : postprocessor_names)
236  {
237  _postprocessor_values.push_back(&this->getPostprocessorValueByName(pp));
238  _symbol_names.push_back(pp);
239  }
240 
241  // get all extra symbols
242  for (const auto symbol : _extra_symbols)
243  switch (symbol)
244  {
245  case ExtraSymbols::x:
246  _symbol_names.push_back("x");
247  break;
248  case ExtraSymbols::y:
249  _symbol_names.push_back("y");
250  break;
251  case ExtraSymbols::z:
252  _symbol_names.push_back("z");
253  break;
254  case ExtraSymbols::t:
255  _symbol_names.push_back("t");
256  break;
257  case ExtraSymbols::dt:
258  _symbol_names.push_back("dt");
259  break;
260  }
261 
262  // get all functors
263  if (!functor_symbols.empty() && functor_symbols.size() != functor_names.size())
264  _params.mooseError(
265  "The parameter vector functor_symbols must be of same length as functor_names, if "
266  "not empty.");
267  _functors.resize(functor_names.size());
268  for (const auto i : index_range(functor_names))
269  {
270  if (functor_symbols.empty())
271  {
272  auto functor_name = functor_names[i];
273  _symbol_names.push_back(functor_name);
274  _functors[i] = &FunctorInterface::getFunctor<Real>(functor_name);
275  }
276  else
277  {
278  auto functor_name = functor_names[i];
279  auto symbol_name = functor_symbols[i];
280  _symbol_names.push_back(symbol_name);
281  _functors[i] = &FunctorInterface::getFunctor<Real>(functor_name);
282  }
283  }
284 
285  // build 'variables' argument for fparser
286  std::string variables = Moose::stringify(_symbol_names);
287 
288  // build the base function
289  if (_func_F->Parse(function_expression, variables) >= 0)
290  parseError("Invalid parsed material function \"" + function_expression +
291  "\" with variables \"" + variables + "\"; " + _func_F->ErrorMsg());
292 
293  // create parameter passing buffer
294  _func_params.resize(_nargs + nmat_props + _postprocessor_values.size() + _extra_symbols.size() +
295  functor_names.size());
296 
297  // perform next steps (either optimize or take derivatives and then optimize)
298 
299  // let rank 0 do the work first to populate caches
300  if (_communicator.rank() != 0)
301  _communicator.barrier();
302 
303  functionsPostParse();
304 
305  // wait for ranks > 0 to catch up
306  if (_communicator.rank() == 0)
307  _communicator.barrier();
308 }
309 
310 template <bool is_ad>
311 void
313 {
314  functionsOptimize(_func_F);
315 
316  // force a value update to get the property at least once and register it for the dependencies
317  for (auto & mpd : _mat_prop_descriptors)
318  mpd.value();
319 }
320 
321 template <bool is_ad>
322 void
324 {
325  _upstream_mat.resize(_upstream_mat_names.size());
326  for (const auto i : make_range(_upstream_mat_names.size()))
327  _upstream_mat[i] = &this->getMaterialByName(_upstream_mat_names[i]);
328 }
329 
330 template <bool is_ad>
331 void
333 {
334  computeQpProperties();
335 }
336 
337 template <bool is_ad>
338 void
340 {
341  if (!(this->_compute))
342  {
343  for (const auto i : make_range(_upstream_mat_names.size()))
344  _upstream_mat[i]->computePropertiesAtQp(_qp);
345  }
346 
347  // fill the parameter vector, apply tolerances
348  for (const auto i : make_range(_nargs))
349  {
350  if (_tol[i] < 0.0)
351  _func_params[i] = (*_args[i])[_qp];
352  else
353  {
354  auto a = (*_args[i])[_qp];
355  _func_params[i] = a < _tol[i] ? _tol[i] : (a > 1.0 - _tol[i] ? 1.0 - _tol[i] : a);
356  }
357  }
358  auto offset = _nargs;
359 
360  // insert material property values
361  for (const auto i : index_range(_mat_prop_descriptors))
362  _func_params[i + offset] = _mat_prop_descriptors[i].value(_qp);
363  offset += _mat_prop_descriptors.size();
364 
365  // insert postprocessor values
366  auto npps = _postprocessor_values.size();
367  for (MooseIndex(_postprocessor_values) i = 0; i < npps; ++i)
368  _func_params[i + offset] = *_postprocessor_values[i];
369  offset += _postprocessor_values.size();
370 
371  // insert extra symbol values
372  for (const auto i : index_range(_extra_symbols))
373  {
374  const auto j = offset + i;
375  switch (_extra_symbols[i])
376  {
377  case ExtraSymbols::x:
378  _func_params[j] = _q_point[_qp](0);
379  break;
380  case ExtraSymbols::y:
381  _func_params[j] = _q_point[_qp](1);
382  break;
383  case ExtraSymbols::z:
384  _func_params[j] = _q_point[_qp](2);
385  break;
386  case ExtraSymbols::t:
387  _func_params[j] = _t;
388  break;
389  case ExtraSymbols::dt:
390  _func_params[j] = _dt;
391  break;
392  }
393  }
394  offset += _extra_symbols.size();
395 
396  // insert functor values
397  const auto & state = TransientInterface::determineState();
398  const Moose::ElemQpArg qp_arg = {_current_elem, _qp, _qrule, _q_point[_qp]};
399  for (const auto i : index_range(_functors))
400  _func_params[offset + i] = (*_functors[i])(qp_arg, state);
401 
402  // set function value
403  if (_prop_F)
404  (*_prop_F)[_qp] = evaluate(_func_F, _name);
405 }
406 
407 template <bool is_ad>
408 void
409 ParsedMaterialHelper<is_ad>::parseError(const std::string & message) const
410 {
411  if (_function_param_name)
412  _params.paramError(*_function_param_name, message);
413  else
414  _params.mooseError(message);
415 }
416 
417 // explicit instantiation
418 template class ParsedMaterialHelper<false>;
419 template class ParsedMaterialHelper<true>;
void insertReservedNames(std::set< std::string > &reserved_names)
Populates the given set with names not to be used as user-defined symbol (e.g.
virtual void initialSetup() override final
Gets called at the beginning of the simulation before this object is asked to do its job...
ParsedMaterialHelper(const InputParameters &parameters, const VariableNameMappingMode map_mode, const std::optional< std::string > &function_param_name={})
void computeQpProperties() override
Users must override this method.
Material base class, central to all Materials that provide a Function as a material property value...
Moose::StateArg determineState() const
Create a functor state argument that corresponds to the implicit state of this object.
const InputParameters & _params
The underlying parameters.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
static InputParameters validParams()
static InputParameters validParams()
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
void parseError(const std::string &message) const
Helper for reporting a parse error with a much as context as possible.
Argument for requesting functor evaluation at a quadrature point location in an element.
T evaluate(Real, const Point &)
The general evaluation method is not defined.
void initQpStatefulProperties() override
Initialize stateful properties at quadrature points.
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
bool have_parameter(std::string_view name) const
A wrapper around the Parameters base class method.
Helper class to perform the parsing and optimization of the function expression.
IntRange< T > make_range(T beg, T end)
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...
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type...
auto index_range(const T &sizable)
virtual void functionsPostParse()
void functionParse(const std::string &function_expression)
This method sets up and parses the function string given by the user.
const std::optional< std::string > _function_param_name
Optional parameter name that represents the function to associate errors with.