www.mooseframework.org
DerivativeParsedMaterialHelper.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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, VariableNameMappingMode map_mode)
35  : ParsedMaterialHelper<is_ad>(parameters, map_mode),
36  _derivative_order(this->template getParam<unsigned int>("derivative_order")),
37  _dmatvar_base("matpropautoderiv"),
38  _dmatvar_index(0)
39 {
40 }
41 
42 template <bool is_ad>
43 void
45 {
46  // set up the list of all FParser symbols to derive w.r.t.
47  auto additional_derivative_symbols =
48  this->template getParam<std::vector<SymbolName>>("additional_derivative_symbols");
49 
50  // build a list of indices into _symbol_table for all symbols we want to derive w.r.t.
51  // we start with all MOOSE variables, which we _always_ take the derivatives w.r.t.
52  _derivative_symbol_table.reserve(_nargs + additional_derivative_symbols.size());
53  for (unsigned i = 0; i < _nargs; ++i)
54  _derivative_symbol_table.push_back(i);
55 
56  // then we add the additional derivative symbols
57  for (auto & ads : additional_derivative_symbols)
58  {
59  // find the index of the symbol if it exists
60  auto it = std::find(_symbol_names.begin(), _symbol_names.end(), ads);
61  if (it == _symbol_names.end())
62  this->paramError("additional_derivative_symbols", "Invalid symbol name '", ads, "'.");
63  auto idx = std::distance(_symbol_names.begin(), it);
64 
65  // make sure it is not a MOOSE variable (we already added those) - their index is < nargs
66  if (idx < _nargs)
67  this->paramError(
68  "additional_derivative_symbols",
69  "Symbol name '",
70  ads,
71  "' is a coupled variable. Derivatives w.r.t. coupled variables are always taken "
72  "and they must not be specified again.");
73 
74  // check that the user did not specify any duplicates in the additional_derivative_symbols
75  // parameter
76  if (std::count(
77  additional_derivative_symbols.begin(), additional_derivative_symbols.end(), ads) > 1)
78  this->paramError(
79  "additional_derivative_symbols", "Symbol name '", ads, "' was given more than once.");
80 
81  // if all checks passed, add the symbol index to the list
82  _derivative_symbol_table.push_back(idx);
83  }
84 
85  // optimize base function
87 
88  // generate derivatives
89  assembleDerivatives();
90 
91  // force a value update to get the property at least once and register it for the dependencies
92  for (auto & mpd : _mat_prop_descriptors)
93  mpd.value();
94 
95  // batch compilation
96 }
97 
98 template <bool is_ad>
99 void
101  unsigned int var, unsigned int order, const MatPropDescriptorList & parent_mpd_list)
102 {
103  // quit if we have exceeded the requested derivative order
104  if (order > _derivative_order)
105  return;
106 
107  // FParser symbol we are deriving w.r.t.
108  auto derivative_var = _derivative_symbol_table[var];
109  auto derivative_symbol = _symbol_names[derivative_var];
110 
111  // generate parent material property descriptors derivatives
112  MatPropDescriptorList mpd_list;
113  for (const auto & parent_mpd : parent_mpd_list)
114  {
115  // if this material property does not depend on the variable we are deriving w.r.t. skip it
116  if (!parent_mpd.dependsOn(derivative_symbol))
117  continue;
118 
119  // otherwise add it to _mat_prop_descriptors
121  mpd.addDerivative(derivative_symbol);
122 
123  // create a new symbol name for it
124  std::string newvarname = _dmatvar_base + Moose::stringify(_dmatvar_index++);
125  mpd.setSymbolName(newvarname);
126 
127  // add the new mpd and register it as the current variable derivative of the parent mpd
128  _bulk_rules.emplace_back(parent_mpd.getSymbolName(), derivative_symbol, newvarname);
129 
130  // append to list
131  mpd_list.push_back(mpd);
132  }
133 
134  // append material property descriptors
135  for (const auto & mpd : mpd_list)
136  _mat_prop_descriptors.push_back(mpd);
137 
138  // go one order deeper
139  for (unsigned int i = var; i < _derivative_symbol_table.size(); ++i)
140  recurseMatProps(i, order + 1, mpd_list);
141 }
142 
143 template <bool is_ad>
144 void
146  unsigned int order,
147  const Derivative & parent_derivative)
148 {
149  // quit if we have exceeded the requested derivative order
150  if (order > _derivative_order)
151  return;
152 
153  // FParser symbol we are deriving w.r.t.
154  auto derivative_var = _derivative_symbol_table[var];
155  auto derivative_symbol = _symbol_names[derivative_var];
156 
157  // current derivative starts off of the parent function
158  Derivative current;
159  current._darg_names = parent_derivative._darg_names;
160 
161  // the moose variable name goes into the derivative property name
162  current._darg_names.push_back(derivative_var < _nargs ? _arg_names[derivative_var]
163  : derivative_symbol);
164 
165  current._F = std::make_shared<SymFunction>(*parent_derivative._F);
166 
167  // execute derivative
168  if (current._F->AutoDiff(derivative_symbol) != -1)
169  mooseError("Failed to take order ", order, " derivative in material ", _name);
170 
171  // optimize
172  if (!_disable_fpoptimizer)
173  current._F->Optimize();
174 
175  // proceed only if the derivative is not zero
176  if (!current._F->isZero() || is_ad)
177  {
178  // compile
179  if (_enable_jit && !current._F->JITCompile())
180  mooseInfo("Failed to JIT compile expression, falling back to byte code interpretation.");
181 
182  // go one order deeper
183  for (unsigned int i = var; i < _derivative_symbol_table.size(); ++i)
184  recurseDerivative(i, order + 1, current);
185 
186  // set up a material property for the derivative
187  current._mat_prop =
188  &this->template declarePropertyDerivative<Real, is_ad>(_F_name, current._darg_names);
189 
190  // save off current derivative
191  _derivatives.push_back(current);
192  }
193 }
194 
198 template <bool is_ad>
199 void
201 {
202  // need to check for zero derivatives here, otherwise at least one order is generated
203  if (_derivative_order < 1)
204  return;
205 
206  // if we are not on thread 0 we fetch all data from the thread 0 copy that already did all the
207  // work
208  if (_tid > 0)
209  {
210  // get the master object from thread 0
211  const MaterialWarehouse & material_warehouse = this->_fe_problem.getMaterialWarehouse();
212  const MooseObjectWarehouse<MaterialBase> & warehouse = material_warehouse[_material_data_type];
213 
214  MooseSharedPointer<DerivativeParsedMaterialHelperTempl> master =
216  warehouse.getActiveObject(name()));
217 
218  // copy parsers and declare properties
219  for (const auto & D : master->_derivatives)
220  {
221  Derivative newderivative;
222  newderivative._mat_prop =
223  &this->template declarePropertyDerivative<Real, is_ad>(_F_name, D._darg_names);
224  newderivative._F = std::make_shared<SymFunction>(*D._F);
225  _derivatives.push_back(newderivative);
226  }
227 
228  // copy coupled material properties
229  auto start = _mat_prop_descriptors.size();
230  for (MooseIndex(master->_mat_prop_descriptors) i = start;
231  i < master->_mat_prop_descriptors.size();
232  ++i)
233  {
234  FunctionMaterialPropertyDescriptor<is_ad> newdescriptor(master->_mat_prop_descriptors[i],
235  this);
236  _mat_prop_descriptors.push_back(newdescriptor);
237  }
238 
239  // size parameter buffer
240  _func_params.resize(master->_func_params.size());
241  return;
242  }
243 
244  // generate all coupled material property mappings
245  for (unsigned int i = 0; i < _derivative_symbol_table.size(); ++i)
246  recurseMatProps(i, 1, _mat_prop_descriptors);
247 
248  // bulk register material property derivative rules to avoid repeated calls
249  // to the (slow) AddVariable method
250  if (!_bulk_rules.empty())
251  {
252  std::string vars = _bulk_rules[0]._child;
253  for (MooseIndex(_bulk_rules) i = 1; i < _bulk_rules.size(); ++i)
254  vars += ',' + _bulk_rules[i]._child;
255  _func_F->AddVariable(vars);
256 
257  for (const auto & rule : _bulk_rules)
258  _func_F->RegisterDerivative(rule._parent, rule._var, rule._child);
259  }
260 
261  // generate all derivatives
262  Derivative root;
263  root._F = _func_F;
264  root._mat_prop = nullptr;
265  for (unsigned int i = 0; i < _derivative_symbol_table.size(); ++i)
266  recurseDerivative(i, 1, root);
267 
268  // increase the parameter buffer to provide storage for the material property derivatives
269  _func_params.resize(_nargs + _mat_prop_descriptors.size() + _postprocessor_values.size());
270 }
271 
272 template <bool is_ad>
273 void
275 {
276  computeQpProperties();
277 }
278 
279 template <bool is_ad>
280 void
282 {
284 
285  // set derivatives
286  for (auto & D : _derivatives)
287  (*D._mat_prop)[_qp] = evaluate(D._F, _name);
288 }
289 
290 // 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:299
void computeQpProperties() override
Users must override this method.
void computeQpProperties() override
Users must override this method.
void assembleDerivatives()
Perform construction of all requested derivatives.
virtual void functionsOptimize(SymFunctionPtr &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:366
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:62
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 option parameter and a documentation string to the InputParameters object...
void initQpStatefulProperties() override
Initialize stateful properties at quadrature points.
DerivativeParsedMaterialHelperTempl(const InputParameters &parameters, VariableNameMappingMode map_mode=VariableNameMappingMode::USE_PARAM_NAMES)
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)