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