https://mooseframework.inl.gov
AbaqusUMATStress.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 
10 #include "AbaqusUMATStress.h"
11 #include "AnalysisStepUserObject.h"
12 #include "Factory.h"
13 #include "MooseMesh.h"
14 #include "RankTwoTensor.h"
15 #include "RankFourTensor.h"
16 #include "libmesh/int_range.h"
17 #include <string.h>
18 #include <algorithm>
19 
20 #define QUOTE(macro) stringifyName(macro)
21 
22 registerMooseObject("SolidMechanicsApp", AbaqusUMATStress);
23 
26 {
28  params.addClassDescription("Coupling material to use Abaqus UMAT models in MOOSE");
29  params.addRequiredParam<FileName>(
30  "plugin", "The path to the compiled dynamic library for the plugin you want to use");
31  params.addRequiredParam<bool>(
32  "use_one_based_indexing",
33  "Parameter to control whether indexing for element and integration points as presented to "
34  "UMAT models is based on 1 (true) or 0 (false). This does not affect internal MOOSE "
35  "numbering. The option to use 0-based numbering is deprecated and will be removed soon.");
36  params.addRequiredParam<std::vector<Real>>(
37  "constant_properties", "Constant mechanical and thermal material properties (PROPS)");
38  params.addRequiredParam<unsigned int>("num_state_vars",
39  "The number of state variables this UMAT is going to use");
40  params.addCoupledVar("temperature", 0.0, "Coupled temperature");
41  params.addCoupledVar("external_fields",
42  "The external fields that can be used in the UMAT subroutine");
43  params.addParam<std::vector<MaterialPropertyName>>("external_properties", {}, "");
44  params.addParam<MooseEnum>("decomposition_method",
46  "Method to calculate the strain kinematics.");
47  params.addParam<bool>(
48  "use_displaced_mesh",
49  false,
50  "Whether or not this object should use the "
51  "displaced mesh for computing displacements and quantities based on the deformed state.");
52  params.addParam<UserObjectName>(
53  "analysis_step_user_object",
54  "The AnalysisStepUserObject that provides times from simulation loading steps.");
55  params.addParam<RealVectorValue>(
56  "orientation",
57  "Euler angles that describe the orientation of the local material coordinate system.");
58  return params;
59 }
60 
61 #ifndef METHOD
62 #error "The METHOD preprocessor symbol must be supplied by the build system."
63 #endif
64 
66  : ComputeGeneralStressBase(parameters),
67  _plugin(getParam<FileName>("plugin")),
68  _library(_plugin + std::string("-") + QUOTE(METHOD) + ".plugin"),
69  _umat(_library.getFunction<umat_t>("umat_")),
70  _aqNSTATV(getParam<unsigned int>("num_state_vars")),
71  _aqSTATEV(_aqNSTATV),
72  _aqPROPS(getParam<std::vector<Real>>("constant_properties")),
73  _aqNPROPS(_aqPROPS.size()),
74  _stress_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "stress")),
75  _total_strain_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "total_strain")),
76  _strain_increment(getOptionalMaterialProperty<RankTwoTensor>(_base_name + "strain_increment")),
77  _jacobian_mult(declareProperty<RankFourTensor>(_base_name + "Jacobian_mult")),
78  _Fbar(getOptionalMaterialProperty<RankTwoTensor>(_base_name + "deformation_gradient")),
79  _Fbar_old(getOptionalMaterialPropertyOld<RankTwoTensor>(_base_name + "deformation_gradient")),
80  _state_var(declareProperty<std::vector<Real>>(_base_name + "state_var")),
81  _state_var_old(getMaterialPropertyOld<std::vector<Real>>(_base_name + "state_var")),
82  _elastic_strain_energy(declareProperty<Real>(_base_name + "elastic_strain_energy")),
83  _elastic_strain_energy_old(getMaterialPropertyOld<Real>(_base_name + "elastic_strain_energy")),
84  _plastic_dissipation(declareProperty<Real>(_base_name + "plastic_dissipation")),
85  _plastic_dissipation_old(getMaterialPropertyOld<Real>(_base_name + "plastic_dissipation")),
86  _creep_dissipation(declareProperty<Real>(_base_name + "creep_dissipation")),
87  _creep_dissipation_old(getMaterialPropertyOld<Real>(_base_name + "creep_dissipation")),
88  _material_timestep(declareProperty<Real>(_base_name + "material_timestep_limit")),
89  _rotation_increment(
90  getOptionalMaterialProperty<RankTwoTensor>(_base_name + "rotation_increment")),
91  _rotation_increment_old(
92  getOptionalMaterialPropertyOld<RankTwoTensor>(_base_name + "rotation_increment")),
93  _temperature(coupledValue("temperature")),
94  _temperature_old(coupledValueOld("temperature")),
95  _external_fields(isCoupled("external_fields") ? coupledValues("external_fields")
96  : std::vector<const VariableValue *>{}),
97  _external_fields_old(isCoupled("external_fields") ? coupledValuesOld("external_fields")
98  : std::vector<const VariableValue *>{}),
99  _number_external_fields(_external_fields.size()),
100  _external_property_names(getParam<std::vector<MaterialPropertyName>>("external_properties")),
101  _number_external_properties(_external_property_names.size()),
102  _external_properties(_number_external_properties),
103  _external_properties_old(_number_external_properties),
104  _use_one_based_indexing(getParam<bool>("use_one_based_indexing")),
105  _use_orientation(isParamValid("orientation")),
106  _R(_use_orientation ? getParam<RealVectorValue>("orientation") : RealVectorValue(0.0)),
107  _total_rotation(declareProperty<RankTwoTensor>("total_rotation")),
108  _total_rotation_old(getMaterialPropertyOld<RankTwoTensor>("total_rotation")),
109  _decomposition_method(
110  getParam<MooseEnum>("decomposition_method").getEnum<ComputeFiniteStrain::DecompMethod>())
111 {
112  if (!_use_one_based_indexing)
114  "AbaqusUMATStress has transitioned to 1-based indexing in the element (NOEL) and "
115  "integration point (NPT) numbers to ensure maximum compatibility with legacy UMAT files. "
116  "Please ensure that any new UMAT plugins using these quantities are using the correct "
117  "indexing. 0-based indexing will be deprecated soon.");
118 
119  // get material properties
120  for (std::size_t i = 0; i < _number_external_properties; ++i)
121  {
122  _external_properties[i] = &getMaterialProperty<Real>(_external_property_names[i]);
123  _external_properties_old[i] = &getMaterialPropertyOld<Real>(_external_property_names[i]);
124  }
125 
126  // Read mesh dimension and size UMAT arrays (we always size for full 3D)
127  _aqNTENS = 6; // Size of the stress or strain component array (NDI+NSHR)
128  _aqNSHR = 3; // Number of engineering shear stress components
129  _aqNDI = 3; // Number of direct stress components (always 3)
130 
131  _aqDDSDDT.resize(_aqNTENS);
132  _aqDRPLDE.resize(_aqNTENS);
133  _aqSTRAN.resize(_aqNTENS);
134  _aqDFGRD0.resize(9);
135  _aqDFGRD1.resize(9);
136  _aqDROT.resize(9);
137  _aqSTRESS.resize(_aqNTENS);
138  _aqDDSDDE.resize(_aqNTENS * _aqNTENS);
139  _aqDSTRAN.resize(_aqNTENS);
140  _aqPREDEF.resize(_number_external_fields + _number_external_properties);
141  _aqDPRED.resize(_number_external_fields + _number_external_properties);
142 }
143 
144 void
146 {
147  // The _Fbar, _Fbar_old, and _rotation_increment optional properties are only available when an
148  // incremental strain formulation is used. If they are not avaliable we advide the user to
149  // select an incremental formulation.
151  mooseError("AbaqusUMATStress '",
152  name(),
153  "': Incremental strain quantities are not available. You likely are using a total "
154  "strain formulation. Specify `incremental = true` in the tensor mechanics action, "
155  "or use ComputeIncrementalStrain in your input file.");
156 
157  // Let's automatically detect uos and identify the one we are interested in.
158  // If there is more than one, we assume something is off and error out.
159  if (!isParamSetByUser("analysis_step_user_object"))
161  else
162  _step_user_object = &getUserObject<AnalysisStepUserObject>("analysis_step_user_object");
163 }
164 
165 void
167 {
169 
170  // Initialize state variable vector
172  for (const auto i : make_range(_aqNSTATV))
173  _state_var[_qp][i] = 0.0;
174 
175  // Initialize total rotation tensor
177 }
178 
179 void
181 {
182  // current element "number"
183  _aqNOEL = _current_elem->id() + (_use_one_based_indexing ? 1 : 0);
184 
185  // characteristic element length
186  _aqCELENT = std::pow(_current_elem->volume(), 1.0 / _current_elem->dim());
187 
188  if (!_step_user_object)
189  {
190  // Value of total time at the beginning of the current increment
191  _aqTIME[0] = _t - _dt;
192  }
193  else
194  {
195  const unsigned int start_time_step = _step_user_object->getStep(_t - _dt);
196  const Real step_time = _step_user_object->getStartTime(start_time_step);
197  // Value of step time at the beginning of the current increment
198  _aqTIME[0] = step_time;
199  }
200  // Value of total time at the beginning of the current increment
201  _aqTIME[1] = _t - _dt;
202 
203  // Time increment
204  _aqDTIME = _dt;
205 
206  // Fill unused characters with spaces (Fortran)
207  std::fill(_aqCMNAME, _aqCMNAME + 80, ' ');
208  std::memcpy(_aqCMNAME, name().c_str(), name().size());
209 
211 }
212 
213 void
215 {
216  // C uses row-major, whereas Fortran uses column major
217  // therefore, all unsymmetric matrices must be transposed before passing them to Fortran
218  RankTwoTensor FBar_old_fortran = _Fbar_old[_qp].transpose();
219  RankTwoTensor FBar_fortran = _Fbar[_qp].transpose();
220 
221  // DROT needed by UMAT will depend on kinematics and whether or not an intermediate configuration
222  // is used
223  RankTwoTensor DROT_fortran;
224  if (_use_orientation)
225  {
226  DROT_fortran = RankTwoTensor::Identity();
227  }
228  else
229  {
231  DROT_fortran = _rotation_increment[_qp].transpose();
232  else
233  DROT_fortran = _rotation_increment_old[_qp].transpose();
234  }
235 
236  const Real * myDFGRD0 = &(FBar_old_fortran(0, 0));
237  const Real * myDFGRD1 = &(FBar_fortran(0, 0));
238  const Real * myDROT = &(DROT_fortran(0, 0));
239 
240  // More local copies of materials so we can (optionally) rotate
241  RankTwoTensor stress_old = _stress_old[_qp];
242  RankTwoTensor total_strain_old = _total_strain_old[_qp];
243  RankTwoTensor strain_increment = _strain_increment[_qp];
244 
245  // check if we need to rotate to intermediate configuration
246  if (_use_orientation)
247  {
248  // keep track of total rotation
250  // rotate stress/strain/increment from reference configuration to intermediate configuration
251  stress_old.rotate(_total_rotation_old[_qp].transpose());
252  total_strain_old.rotate(_total_rotation_old[_qp].transpose());
253 
255  strain_increment.rotate(_total_rotation[_qp].transpose());
256  else
257  strain_increment.rotate(_total_rotation_old[_qp].transpose());
258  }
260  // rotate old stress to reference configuration
261  stress_old.rotate(_rotation_increment[_qp]);
262 
263  // copy because UMAT does not guarantee constness
264  for (const auto i : make_range(9))
265  {
266  _aqDFGRD0[i] = myDFGRD0[i];
267  _aqDFGRD1[i] = myDFGRD1[i];
268  _aqDROT[i] = myDROT[i];
269  }
270 
271  // Recover "old" state variables
272  for (const auto i : make_range(_aqNSTATV))
273  _aqSTATEV[i] = _state_var_old[_qp][i];
274 
275  // Recover "old" energy quantities
279 
280  // Pass through updated stress, total strain, and strain increment arrays
281  static const std::array<Real, 6> strain_factor{{1, 1, 1, 2, 2, 2}};
282  // Account for difference in vector order convention: yz, xz, xy (MOOSE) vs xy, xz, yz
283  // (commercial software)
284  static const std::array<std::pair<unsigned int, unsigned int>, 6> component{
285  {{0, 0}, {1, 1}, {2, 2}, {0, 1}, {0, 2}, {1, 2}}};
286 
287  for (const auto i : make_range(_aqNTENS))
288  {
289  const auto a = component[i].first;
290  const auto b = component[i].second;
291  _aqSTRESS[i] = stress_old(a, b);
292  _aqSTRAN[i] = total_strain_old(a, b) * strain_factor[i];
293  _aqDSTRAN[i] = strain_increment(a, b) * strain_factor[i];
294  }
295 
296  // current coordinates
297  for (const auto i : make_range(Moose::dim))
298  _aqCOORDS[i] = _q_point[_qp](i);
299 
300  // zero out Jacobian contribution
301  for (const auto i : make_range(_aqNTENS * _aqNTENS))
302  _aqDDSDDE[i] = 0.0;
303 
304  // Set PNEWDT initially to a large value
305  _aqPNEWDT = std::numeric_limits<Real>::max();
306 
307  // Temperature
309 
310  // Temperature increment
312 
313  for (const auto i : make_range(_number_external_fields))
314  {
315  // External field at this step
316  _aqPREDEF[i] = (*_external_fields_old[i])[_qp];
317 
318  // External field increments
320  }
321 
322  for (const auto i : make_range(_number_external_properties))
323  {
324  // External property at this step
326 
327  // External property increments
330  }
331 
332  // Layer number (not supported)
333  _aqLAYER = -1;
334 
335  // Section point number within the layer (not supported)
336  _aqKSPT = -1;
337 
338  // Increment number
339  _aqKINC = _t_step;
340  _aqKSTEP = 1;
341 
342  // integration point number
343  _aqNPT = _qp + (_use_one_based_indexing ? 1 : 0);
344 
345  // Connection to extern statement
346  _umat(_aqSTRESS.data(),
347  _aqSTATEV.data(),
348  _aqDDSDDE.data(),
352  &_aqRPL,
353  _aqDDSDDT.data(),
354  _aqDRPLDE.data(),
355  &_aqDRPLDT,
356  _aqSTRAN.data(),
357  _aqDSTRAN.data(),
358  _aqTIME.data(),
359  &_aqDTIME,
360  &_aqTEMP,
361  &_aqDTEMP,
362  _aqPREDEF.data(),
363  _aqDPRED.data(),
364  _aqCMNAME,
365  &_aqNDI,
366  &_aqNSHR,
367  &_aqNTENS,
368  &_aqNSTATV,
369  _aqPROPS.data(),
370  &_aqNPROPS,
371  _aqCOORDS.data(),
372  _aqDROT.data(),
373  &_aqPNEWDT,
374  &_aqCELENT,
375  _aqDFGRD0.data(),
376  _aqDFGRD1.data(),
377  &_aqNOEL,
378  &_aqNPT,
379  &_aqLAYER,
380  &_aqKSPT,
381  &_aqKSTEP,
382  &_aqKINC);
383 
384  // Update state variables
385  for (int i = 0; i < _aqNSTATV; ++i)
386  _state_var[_qp][i] = _aqSTATEV[i];
387 
388  // Here, we apply UMAT convention: Always multiply _dt by PNEWDT to determine the material time
389  // step MOOSE time stepper will choose the most limiting of all material time step increments
390  // provided
392 
393  // Get new stress tensor - UMAT should update stress
394  // Account for difference in vector order convention: yz, xz, xy (MOOSE) vs xy, xz, yz
395  // (commercial software)
397  _aqSTRESS[0], _aqSTRESS[1], _aqSTRESS[2], _aqSTRESS[5], _aqSTRESS[4], _aqSTRESS[3]);
398 
399  // Build Jacobian matrix from UMAT's Voigt non-standard order to fourth order tensor.
400  const unsigned int N = Moose::dim;
401  const unsigned int ntens = N * (N + 1) / 2;
402  const int nskip = N - 1;
403 
404  for (const auto i : make_range(N))
405  for (const auto j : make_range(N))
406  for (const auto k : make_range(N))
407  for (const auto l : make_range(N))
408  {
409  if (i == j)
410  _jacobian_mult[_qp](i, j, k, l) =
411  k == l ? _aqDDSDDE[i * ntens + k] : _aqDDSDDE[i * ntens + k + nskip + l];
412  else
413  // i!=j
414  _jacobian_mult[_qp](i, j, k, l) =
415  k == l ? _aqDDSDDE[(nskip + i + j) * ntens + k]
416  : _aqDDSDDE[(nskip + i + j) * ntens + k + nskip + l];
417  }
418 
419  // check if we need to rotate from intermediate reference frame
420  if (_use_orientation)
421  {
422  // rotate to current configuration
423  _stress[_qp].rotate(_total_rotation[_qp]);
425  }
428 }
const MooseArray< Point > & _q_point
const MaterialProperty< std::vector< Real > > & _state_var_old
std::vector< Real > _aqSTATEV
Real _aqDTIME
Time increment.
const OptionalMaterialProperty< RankTwoTensor > & _rotation_increment_old
ComputeGeneralStressBase is the direct base class for stress calculator materials that may leverage q...
const VariableValue & _temperature
std::vector< Real > _aqDSTRAN
Array of strain increments.
MaterialProperty< Real > & _material_timestep
recommended maximum timestep for this model under the current conditions
const std::vector< const VariableValue * > _external_fields_old
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
std::vector< Real > _aqSTRESS
Stress tensor (in: old stress, out: updated stress)
std::vector< const MaterialProperty< Real > * > _external_properties_old
Real _aqCELENT
Characteristic element length, which is a typical length of a line across an element for a first-orde...
MaterialProperty< RankFourTensor > & _jacobian_mult
Jacobian multiplier.
static const std::string component
Definition: NS.h:153
std::vector< Real > _aqDPRED
Array of increments of predefined field variables.
const MaterialProperty< RankTwoTensor > & _total_rotation_old
std::array< Real, 3 > _aqCOORDS
An array containing the coordinates of this point.
virtual void computeProperties() override
MaterialProperty< std::vector< Real > > & _state_var
static constexpr std::size_t dim
std::vector< Real > _aqSTRAN
An array containing the total strains at the beginning of the increment.
int _aqKSTEP
The step number (as per Abaqus definition) can be set by the user.
std::vector< Real > _aqDDSDDE
Jacobian matrix of the model (out)
int _aqNDI
Number of direct stress components at this point.
int _aqNTENS
Size of the stress or strain component array (NDI + NSHR).
std::vector< Real > _aqPROPS
User-specified array of material constants associated with this user material.
std::vector< Real > _aqDDSDDT
Variation of the stress increments with respect to the temperature.
const std::size_t _number_external_properties
static RankTwoTensorTempl Identity()
void addRequiredParam(const std::string &name, const std::string &doc_string)
std::vector< Real > _aqDFGRD0
Array containing the deformation gradient at the beginning of the increment.
const std::size_t _number_external_fields
virtual void resize(const std::size_t size) override final
void rotate(const RankTwoTensorTempl< Real > &R)
const MaterialProperty< Real > & _creep_dissipation_old
AbaqusUMATStress(const InputParameters &parameters)
int _aqKINC
Increment number (_t_step).
Real _aqRPL
Volumetric heat generation per unit time at the end of the increment caused by mechanical working of ...
Real getStartTime(const unsigned int &step) const
const std::string & name() const
const OptionalMaterialProperty< RankTwoTensor > & _rotation_increment
const ComputeFiniteStrain::DecompMethod _decomposition_method
Method being used to compute strain and rotation increments.
const MaterialProperty< RankTwoTensor > & _total_strain_old
virtual void initQpStatefulProperties() override
static InputParameters validParams()
const MaterialProperty< Real > & _elastic_strain_energy_old
int _aqLAYER
Layer number (for composite shells and layered solids). (not supported)
std::vector< const MaterialProperty< Real > * > _external_properties
const RotationTensor _R
int _aqKSPT
Section point number within the current layer. (not supported)
Real _aqDRPLDT
Variation of the volumetric heat generation (RPL) with respect to the temperature.
virtual void getAnalysisStepUserObject(const FEProblemBase &fe_problem, const AnalysisStepUserObject *&step_user_object, const std::string &name)
void initialSetup() override
check optional material properties for consistency
std::vector< Real > _aqDRPLDE
Variation of RPL with respect to the strain increments.
static MooseEnum decompositionType()
void mooseDeprecated(Args &&... args)
Real _aqPNEWDT
Ratio of suggested new time increment to the time increment being used (out)
int _aqNSHR
Number of engineering shear stress components at this point.
const MaterialProperty< Real > & _plastic_dissipation_old
std::vector< Real > _aqDFGRD1
Array containing the deformation gradient at the end of the increment.
const bool _use_one_based_indexing
parameter to assist with the transition to 1-based indexing
const OptionalMaterialProperty< RankTwoTensor > & _strain_increment
unsigned int _aqNPT
Integration point number.
Real _aqTEMP
Temperature at the start of the increment.
Coupling material to use Abaqus UMAT models in MOOSE.
const std::vector< const VariableValue * > _external_fields
void addCoupledVar(const std::string &name, const std::string &doc_string)
OutputTools< Real >::VariableValue VariableValue
static InputParameters validParams()
int _aqNOEL
Element number.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
int N
registerMooseObject("SolidMechanicsApp", AbaqusUMATStress)
const bool _use_orientation
Rotation information.
MaterialProperty< Real > & _creep_dissipation
Real _aqDTEMP
Increment of temperature.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
MaterialProperty< Real > & _elastic_strain_energy
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
MaterialProperty< RankTwoTensor > & _stress
Stress material property.
std::array< Real, 2 > _aqTIME
Value of step time at the beginning of the current increment, total time at the beginning of the curr...
void initQpStatefulProperties() override
void computeProperties() override
perform per-element computation/initialization
std::vector< Real > _aqPREDEF
Array of interpolated values of predefined field variables at this point at the start of the incremen...
MaterialProperty< Real > & _plastic_dissipation
unsigned int getStep(const Real &time) const
int _aqNPROPS
User-defined number of material constants associated with this user material.
void computeQpStress() override
Compute the stress and store it in the _stress material property for the current quadrature point...
const OptionalMaterialProperty< RankTwoTensor > & _Fbar_old
const VariableValue & _temperature_old
int _aqNSTATV
Number of solution-dependent state variables that are associated with this material type...
MaterialProperty< RankTwoTensor > & _total_rotation
bool isParamSetByUser(const std::string &name) const
MooseUnits pow(const MooseUnits &, int)
static const std::string k
Definition: NS.h:130
const MaterialProperty< RankTwoTensor > & _stress_old
void ErrorVector unsigned int
const OptionalMaterialProperty< RankTwoTensor > & _Fbar
const AnalysisStepUserObject * _step_user_object
User object that determines step number.
char _aqCMNAME[80]
Model name buffer.
std::vector< Real > _aqDROT
Rotation increment matrix.