https://mooseframework.inl.gov
DerivativeParsedMaterialHelper.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 
11 #include "Conversion.h"
12 
13 #include <deque>
14 
15 #include "libmesh/quadrature.h"
16 
17 template <bool is_ad>
20 {
22  params.addClassDescription("Parsed Function Material with automatic derivatives.");
23  params.addParam<unsigned int>("derivative_order", 3, "Maximum order of derivatives taken");
24  params.addParam<std::vector<SymbolName>>(
25  "additional_derivative_symbols",
26  {},
27  "A list of additional (non-variable) symbols (such as material property or postprocessor "
28  "names) to take derivatives w.r.t.");
29  return params;
30 }
31 
32 template <bool is_ad>
34  const InputParameters & parameters,
35  const VariableNameMappingMode map_mode,
36  const std::optional<std::string> & function_param_name /* = {} */)
37  : ParsedMaterialHelper<is_ad>(parameters, map_mode, function_param_name),
38  _derivative_order(this->template getParam<unsigned int>("derivative_order")),
39  _dmatvar_base("matpropautoderiv"),
40  _dmatvar_index(0)
41 {
42 }
43 
44 template <bool is_ad>
45 void
47 {
48  // set up the list of all FParser symbols to derive w.r.t.
49  auto additional_derivative_symbols =
50  this->template getParam<std::vector<SymbolName>>("additional_derivative_symbols");
51 
52  // build a list of indices into _symbol_table for all symbols we want to derive w.r.t.
53  // we start with all MOOSE variables, which we _always_ take the derivatives w.r.t.
54  _derivative_symbol_table.reserve(_nargs + additional_derivative_symbols.size());
55  for (unsigned i = 0; i < _nargs; ++i)
56  _derivative_symbol_table.push_back(i);
57 
58  // then we add the additional derivative symbols
59  for (auto & ads : additional_derivative_symbols)
60  {
61  // find the index of the symbol if it exists
62  auto it = std::find(_symbol_names.begin(), _symbol_names.end(), ads);
63  if (it == _symbol_names.end())
64  this->paramError("additional_derivative_symbols", "Invalid symbol name '", ads, "'.");
65  auto idx = std::distance(_symbol_names.begin(), it);
66 
67  // make sure it is not a MOOSE variable (we already added those) - their index is < nargs
68  if (idx < _nargs)
69  this->paramError(
70  "additional_derivative_symbols",
71  "Symbol name '",
72  ads,
73  "' is a coupled variable. Derivatives w.r.t. coupled variables are always taken "
74  "and they must not be specified again.");
75 
76  // check that the user did not specify any duplicates in the additional_derivative_symbols
77  // parameter
78  if (std::count(
79  additional_derivative_symbols.begin(), additional_derivative_symbols.end(), ads) > 1)
80  this->paramError(
81  "additional_derivative_symbols", "Symbol name '", ads, "' was given more than once.");
82 
83  // if all checks passed, add the symbol index to the list
84  _derivative_symbol_table.push_back(idx);
85  }
86 
87  // optimize base function
89 
90  // generate derivatives
91  assembleDerivatives();
92 
93  // force a value update to get the property at least once and register it for the dependencies
94  for (auto & mpd : _mat_prop_descriptors)
95  mpd.value();
96 
97  // batch compilation
98 }
99 
100 template <bool is_ad>
101 void
103  unsigned int var, unsigned int order, const MatPropDescriptorList & parent_mpd_list)
104 {
105  // quit if we have exceeded the requested derivative order
106  if (order > _derivative_order)
107  return;
108 
109  // FParser symbol we are deriving w.r.t.
110  auto derivative_var = _derivative_symbol_table[var];
111  auto derivative_symbol = _symbol_names[derivative_var];
112 
113  // generate parent material property descriptors derivatives
114  MatPropDescriptorList mpd_list;
115  for (const auto & parent_mpd : parent_mpd_list)
116  {
117  // if this material property does not depend on the variable we are deriving w.r.t. skip it
118  if (!parent_mpd.dependsOn(derivative_symbol))
119  continue;
120 
121  // otherwise add it to _mat_prop_descriptors
123  mpd.addDerivative(derivative_symbol);
124 
125  // create a new symbol name for it
126  std::string newvarname = _dmatvar_base + Moose::stringify(_dmatvar_index++);
127  mpd.setSymbolName(newvarname);
128 
129  // add the new mpd and register it as the current variable derivative of the parent mpd
130  _bulk_rules.emplace_back(parent_mpd.getSymbolName(), derivative_symbol, newvarname);
131 
132  // append to list
133  mpd_list.push_back(mpd);
134  }
135 
136  // append material property descriptors
137  for (const auto & mpd : mpd_list)
138  _mat_prop_descriptors.push_back(mpd);
139 
140  // go one order deeper
141  for (unsigned int i = var; i < _derivative_symbol_table.size(); ++i)
142  recurseMatProps(i, order + 1, mpd_list);
143 }
144 
145 template <bool is_ad>
146 void
148  unsigned int order,
149  const Derivative & parent_derivative)
150 {
151  // quit if we have exceeded the requested derivative order
152  if (order > _derivative_order)
153  return;
154 
155  // FParser symbol we are deriving w.r.t.
156  auto derivative_var = _derivative_symbol_table[var];
157  auto derivative_symbol = _symbol_names[derivative_var];
158 
159  // current derivative starts off of the parent function
160  Derivative current;
161  current._darg_names = parent_derivative._darg_names;
162 
163  // the moose variable name goes into the derivative property name
164  current._darg_names.push_back(derivative_var < _nargs ? _arg_names[derivative_var]
165  : derivative_symbol);
166 
167  current._F = std::make_shared<SymFunction>(*parent_derivative._F);
168 
169  // execute derivative
170  if (current._F->AutoDiff(derivative_symbol) != -1)
171  mooseError("Failed to take order ", order, " derivative in material ", _name);
172 
173  // optimize
174  if (!_disable_fpoptimizer)
175  current._F->Optimize();
176 
177  // proceed only if the derivative is not zero
178  if (!current._F->isZero() || is_ad)
179  {
180  // compile
181  if (_enable_jit && !current._F->JITCompile())
182  mooseInfo("Failed to JIT compile expression, falling back to byte code interpretation.");
183 
184  // go one order deeper
185  for (unsigned int i = var; i < _derivative_symbol_table.size(); ++i)
186  recurseDerivative(i, order + 1, current);
187 
188  // set up a material property for the derivative
189  current._mat_prop =
190  &this->template declarePropertyDerivative<Real, is_ad>(_F_name, current._darg_names);
191 
192  // save off current derivative
193  _derivatives.push_back(current);
194  }
195 }
196 
200 template <bool is_ad>
201 void
203 {
204  // need to check for zero derivatives here, otherwise at least one order is generated
205  if (_derivative_order < 1)
206  return;
207 
208  // if we are not on thread 0 we fetch all data from the thread 0 copy that already did all the
209  // work
210  if (_tid > 0)
211  {
212  // get the master object from thread 0
213  const MaterialWarehouse & material_warehouse = this->_fe_problem.getMaterialWarehouse();
214  const MooseObjectWarehouse<MaterialBase> & warehouse = material_warehouse[_material_data_type];
215 
216  MooseSharedPointer<DerivativeParsedMaterialHelperTempl> master =
218  warehouse.getActiveObject(name()));
219 
220  // copy parsers and declare properties
221  for (const auto & D : master->_derivatives)
222  {
223  Derivative newderivative;
224  newderivative._mat_prop =
225  &this->template declarePropertyDerivative<Real, is_ad>(_F_name, D._darg_names);
226  newderivative._F = std::make_shared<SymFunction>(*D._F);
227  _derivatives.push_back(newderivative);
228  }
229 
230  // copy coupled material properties
231  auto start = _mat_prop_descriptors.size();
232  for (MooseIndex(master->_mat_prop_descriptors) i = start;
233  i < master->_mat_prop_descriptors.size();
234  ++i)
235  {
236  FunctionMaterialPropertyDescriptor<is_ad> newdescriptor(master->_mat_prop_descriptors[i],
237  this);
238  _mat_prop_descriptors.push_back(newdescriptor);
239  }
240 
241  // size parameter buffer
242  _func_params.resize(master->_func_params.size());
243  return;
244  }
245 
246  // generate all coupled material property mappings
247  for (unsigned int i = 0; i < _derivative_symbol_table.size(); ++i)
248  recurseMatProps(i, 1, _mat_prop_descriptors);
249 
250  // bulk register material property derivative rules to avoid repeated calls
251  // to the (slow) AddVariable method
252  if (!_bulk_rules.empty())
253  {
254  std::string vars = _bulk_rules[0]._child;
255  for (MooseIndex(_bulk_rules) i = 1; i < _bulk_rules.size(); ++i)
256  vars += ',' + _bulk_rules[i]._child;
257  _func_F->AddVariable(vars);
258 
259  for (const auto & rule : _bulk_rules)
260  _func_F->RegisterDerivative(rule._parent, rule._var, rule._child);
261  }
262 
263  // generate all derivatives
264  Derivative root;
265  root._F = _func_F;
266  root._mat_prop = nullptr;
267  for (unsigned int i = 0; i < _derivative_symbol_table.size(); ++i)
268  recurseDerivative(i, 1, root);
269 
270  // increase the parameter buffer to provide storage for the material property derivatives
271  _func_params.resize(_nargs + _mat_prop_descriptors.size() + _postprocessor_values.size() +
272  _extra_symbols.size() + _functors.size());
273 }
274 
275 template <bool is_ad>
276 void
278 {
279  computeQpProperties();
280 }
281 
282 template <bool is_ad>
283 void
285 {
287 
288  // set derivatives
289  for (auto & D : _derivatives)
290  (*D._mat_prop)[_qp] = evaluate(D._F, _name);
291 }
292 
293 // explicit instantiation
std::string name(const ElemQuality q)
Material properties get fully described using this structure, including their dependent variables and...
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:333
void computeQpProperties() override
Users must override this method.
void computeQpProperties() override
Users must override this method.
char ** vars
void assembleDerivatives()
Perform construction of all requested derivatives.
virtual void functionsOptimize(SymFunctionPtr &parsed_function)
run FPOptimizer on the parsed function
void setSymbolName(const std::string &n)
set the fparser symbol name
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
void addDerivative(const SymbolName &symbol)
take another derivative
MaterialBase objects are special in that they have additional objects created automatically (see FEPr...
Helper class to perform the auto derivative taking.
static InputParameters validParams()
void recurseMatProps(unsigned int var, unsigned int order, const MatPropDescriptorList &parent_mpd)
void mooseInfo(Args &&... args)
Emit an informational message with the given stringified, concatenated args.
Definition: MooseError.h:400
std::shared_ptr< T > getActiveObject(const std::string &name, THREAD_ID tid=0) const
GenericMaterialProperty< Real, is_ad > * _mat_prop
T evaluate(Real, const Point &)
The general evaluation method is not defined.
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
Helper class to perform the parsing and optimization of the function expression.
void recurseDerivative(unsigned int var, unsigned int order, const Derivative &parent_derivative)
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...
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...
void initQpStatefulProperties() override
Initialize stateful properties at quadrature points.
DerivativeParsedMaterialHelperTempl(const InputParameters &parameters, const VariableNameMappingMode map_mode=VariableNameMappingMode::USE_PARAM_NAMES, const std::optional< std::string > &function_param_name={})
void ErrorVector unsigned int
std::vector< FunctionMaterialPropertyDescriptor< is_ad > > MatPropDescriptorList
convenience typedef for the material property descriptors
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)