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