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