www.mooseframework.org
DerivativeParsedMaterialHelper.C
Go to the documentation of this file.
1 /****************************************************************/
2 /* MOOSE - Multiphysics Object Oriented Simulation Environment */
3 /* */
4 /* All contents are licensed under LGPL V2.1 */
5 /* See LICENSE for full restrictions */
6 /****************************************************************/
7 
9 #include "Conversion.h"
10 
11 #include <deque>
12 
13 #include "libmesh/quadrature.h"
14 
15 template <>
16 InputParameters
18 {
19  InputParameters params = validParams<ParsedMaterialHelper>();
20  params.addClassDescription("Parsed Function Material with automatic derivatives.");
21  params.addDeprecatedParam<bool>("third_derivatives",
22  "Flag to indicate if third derivatives are needed",
23  "Use derivative_order instead.");
24  params.addParam<unsigned int>("derivative_order", 3, "Maximum order of derivatives taken");
25 
26  return params;
27 }
28 
30  VariableNameMappingMode map_mode)
31  : ParsedMaterialHelper(parameters, map_mode),
32  //_derivative_order(getParam<unsigned int>("derivative_order"))
33  _dmatvar_base("matpropautoderiv"),
34  _dmatvar_index(0),
35  _derivative_order(isParamValid("third_derivatives")
36  ? (getParam<bool>("third_derivatives") ? 3 : 2)
37  : getParam<unsigned int>("derivative_order"))
38 {
39 }
40 
41 void
43 {
44  // optimize base function
46 
47  // generate derivatives
49 
50  // force a value update to get the property at least once and register it for the dependencies
51  unsigned int nmat_props = _mat_prop_descriptors.size();
52  for (unsigned int i = 0; i < nmat_props; ++i)
53  _mat_prop_descriptors[i].value();
54 }
55 
56 ParsedMaterialHelper::MatPropDescriptorList::iterator
58 {
59  std::string name = m.getPropertyName();
60  for (MatPropDescriptorList::iterator i = _mat_prop_descriptors.begin();
61  i != _mat_prop_descriptors.end();
62  ++i)
63  if (i->getPropertyName() == name)
64  return i;
65 
66  return _mat_prop_descriptors.end();
67 }
68 
72 void
74 {
75  // need to check for zero derivatives here, otherwise at least one order is generated
76  if (_derivative_order < 1)
77  return;
78 
79  // if we are not on thread 0 we fetch all data from the thread 0 copy that already did all the
80  // work
81  if (_tid > 0)
82  {
83  // get the master object from thread 0
84  const MaterialWarehouse & material_warehouse = _fe_problem.getMaterialWarehouse();
85  const MooseObjectWarehouse<Material> & warehouse = material_warehouse[_material_data_type];
86 
87  MooseSharedPointer<DerivativeParsedMaterialHelper> master =
88  MooseSharedNamespace::dynamic_pointer_cast<DerivativeParsedMaterialHelper>(
89  warehouse.getActiveObject(name()));
90 
91  // copy parsers and declare properties
92  for (unsigned int i = 0; i < master->_derivatives.size(); ++i)
93  {
94  Derivative newderivative;
95  newderivative.first =
96  &declarePropertyDerivative<Real>(_F_name, master->_derivatives[i].darg_names);
97  newderivative.second = ADFunctionPtr(new ADFunction(*master->_derivatives[i].second));
98  _derivatives.push_back(newderivative);
99  }
100 
101  // copy coupled material properties
102  for (unsigned int i = 0; i < master->_mat_prop_descriptors.size(); ++i)
103  {
104  FunctionMaterialPropertyDescriptor newdescriptor(master->_mat_prop_descriptors[i]);
105  _mat_prop_descriptors.push_back(newdescriptor);
106  }
107 
108  // size parameter buffer
109  _func_params.resize(master->_func_params.size());
110  }
111 
112  // set up job queue. We need a deque here to be able to iterate over the currently queued items.
113  std::deque<QueueItem> queue;
114  queue.push_back(QueueItem(_func_F));
115 
116  // generate derivatives until the queue is exhausted
117  while (!queue.empty())
118  {
119  QueueItem current = queue.front();
120 
121  // all permutations of one set of derivatives are equal, so we make sure to generate only one
122  // each
123  unsigned int first = current._dargs.empty() ? 0 : current._dargs.back();
124 
125  // add necessary derivative steps
126  for (unsigned int i = first; i < _nargs; ++i)
127  {
128  // go through list of material properties and check if derivatives are needed
129  unsigned int ndesc = _mat_prop_descriptors.size();
130  for (unsigned int jj = 0; jj < ndesc; ++jj)
131  {
133 
134  // take a property descriptor and check if it depends on the current derivative variable
135  if (j->dependsOn(_arg_names[i]))
136  {
137  FunctionMaterialPropertyDescriptor matderivative(*j);
138  matderivative.addDerivative(_arg_names[i]);
139 
140  // search if this new derivative is not yet in the list of material properties
141  MatPropDescriptorList::iterator m = findMatPropDerivative(matderivative);
142  if (m == _mat_prop_descriptors.end())
143  {
144  // construct new variable name for the material property derivative as base name +
145  // number
146  std::string newvarname = _dmatvar_base + Moose::stringify(_dmatvar_index++);
147  matderivative.setSymbolName(newvarname);
148 
149  // loop over all queue items to register the new dmatvar variable (includes 'current'
150  // which is popped below)
151  for (std::deque<QueueItem>::iterator k = queue.begin(); k != queue.end(); ++k)
152  {
153  k->_F->AddVariable(newvarname);
154  k->_F->RegisterDerivative(j->getSymbolName(), _arg_names[i], newvarname);
155  }
156 
157  _mat_prop_descriptors.push_back(matderivative);
158  }
159  }
160  }
161 
162  // construct new derivative
163  QueueItem newitem = current;
164  newitem._dargs.push_back(i);
165 
166  // build derivative
167  newitem._F = ADFunctionPtr(new ADFunction(*current._F));
168  if (newitem._F->AutoDiff(_variable_names[i]) != -1)
169  mooseError(
170  "Failed to take order ", newitem._dargs.size(), " derivative in material ", _name);
171 
172  // optimize and compile
173  if (!_disable_fpoptimizer)
174  newitem._F->Optimize();
175  if (_enable_jit && !newitem._F->JITCompile())
176  mooseInfo("Failed to JIT compile expression, falling back to byte code interpretation.");
177 
178  // generate material property argument vector
179  std::vector<VariableName> darg_names(0);
180  for (unsigned int j = 0; j < newitem._dargs.size(); ++j)
181  darg_names.push_back(_arg_names[newitem._dargs[j]]);
182 
183  // append to list of derivatives if the derivative is non-vanishing
184  if (!newitem._F->isZero())
185  {
186  Derivative newderivative;
187  newderivative.first = &declarePropertyDerivative<Real>(_F_name, darg_names);
188  newderivative.second = newitem._F;
189  newderivative.darg_names = darg_names;
190  _derivatives.push_back(newderivative);
191  }
192 
193  // push item to queue if further differentiation is required
194  if (newitem._dargs.size() < _derivative_order)
195  queue.push_back(newitem);
196  }
197 
198  // remove the 'current' element from the queue
199  queue.pop_front();
200  }
201 
202  // increase the parameter buffer to provide storage for the material property derivatives
203  _func_params.resize(_nargs + _mat_prop_descriptors.size());
204 }
205 
206 // TODO: computeQpProperties()
207 void
209 {
210  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
211  {
212  // fill the parameter vector, apply tolerances
213  for (unsigned int i = 0; i < _nargs; ++i)
214  {
215  if (_tol[i] < 0.0)
216  _func_params[i] = (*_args[i])[_qp];
217  else
218  {
219  Real a = (*_args[i])[_qp];
220  _func_params[i] = a < _tol[i] ? _tol[i] : (a > 1.0 - _tol[i] ? 1.0 - _tol[i] : a);
221  }
222  }
223 
224  // insert material property values
225  unsigned int nmat_props = _mat_prop_descriptors.size();
226  for (unsigned int i = 0; i < nmat_props; ++i)
227  _func_params[i + _nargs] = _mat_prop_descriptors[i].value()[_qp];
228 
229  // set function value
230  if (_prop_F)
231  (*_prop_F)[_qp] = evaluate(_func_F);
232 
233  // set derivatives
234  for (unsigned int i = 0; i < _derivatives.size(); ++i)
235  (*_derivatives[i].first)[_qp] = evaluate(_derivatives[i].second);
236  }
237 }
Helper class to perform the auto derivative taking.
std::vector< std::string > _variable_names
variable names used in the expression (depends on the map_mode)
Material properties get fully described using this structure, including their dependent variables and...
const std::string getPropertyName() const
get the property name
MatPropDescriptorList::iterator findMatPropDerivative(const FunctionMaterialPropertyDescriptor &)
std::vector< Real > _tol
Tolerance values for all arguments (to protect from log(0)).
const std::string _dmatvar_base
variable base name for the dynamically material property derivatives
void addDerivative(const VariableName &var)
take another derivative
const std::string & getSymbolName() const
get the fparser symbol name
unsigned int _derivative_order
maximum derivative order
InputParameters validParams< ParsedMaterialHelper >()
MaterialProperty< Real > * _prop_F
Material property to store the function value.
DerivativeParsedMaterialHelper(const InputParameters &parameters, VariableNameMappingMode map_mode=USE_PARAM_NAMES)
void assembleDerivatives()
Perform a breadth first construction of all requested derivatives.
unsigned int _nargs
Number of coupled arguments.
InputParameters validParams< DerivativeParsedMaterialHelper >()
void setSymbolName(const std::string &n)
set the fparser symbol name
bool dependsOn(const std::string &var) const
Check if a material property depends on a given variable.
std::string _F_name
Name of the function value material property and used as a base name to concatenate the material prop...
unsigned int _dmatvar_index
next available variable number for automatically created material property derivative variables ...
std::vector< Derivative > _derivatives
The requested derivatives of the free energy.
Helper class to perform the parsing and optimization of the function expression.
MatPropDescriptorList _mat_prop_descriptors
Material property descriptors (obtained by parsing _mat_prop_expressions)
std::vector< const VariableValue * > _args
Coupled variables for function arguments.
virtual void functionsOptimize()
std::vector< std::string > _arg_names
String vector of all argument names.
ADFunctionPtr _func_F
The undiffed free energy function parser object.