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  _plastic_dissipation(declareProperty<Real>(_base_name + "plastic_dissipation")),
84  _creep_dissipation(declareProperty<Real>(_base_name + "creep_dissipation")),
85  _material_timestep(declareProperty<Real>(_base_name + "material_timestep_limit")),
86  _rotation_increment(
87  getOptionalMaterialProperty<RankTwoTensor>(_base_name + "rotation_increment")),
88  _rotation_increment_old(
89  getOptionalMaterialPropertyOld<RankTwoTensor>(_base_name + "rotation_increment")),
90  _temperature(coupledValue("temperature")),
91  _temperature_old(coupledValueOld("temperature")),
92  _external_fields(isCoupled("external_fields") ? coupledValues("external_fields")
93  : std::vector<const VariableValue *>{}),
94  _external_fields_old(isCoupled("external_fields") ? coupledValuesOld("external_fields")
95  : std::vector<const VariableValue *>{}),
96  _number_external_fields(_external_fields.size()),
97  _external_property_names(getParam<std::vector<MaterialPropertyName>>("external_properties")),
98  _number_external_properties(_external_property_names.size()),
99  _external_properties(_number_external_properties),
100  _external_properties_old(_number_external_properties),
101  _use_one_based_indexing(getParam<bool>("use_one_based_indexing")),
102  _use_orientation(isParamValid("orientation")),
103  _R(_use_orientation ? getParam<RealVectorValue>("orientation") : RealVectorValue(0.0)),
104  _total_rotation(declareProperty<RankTwoTensor>("total_rotation")),
105  _total_rotation_old(getMaterialPropertyOld<RankTwoTensor>("total_rotation")),
106  _decomposition_method(
107  getParam<MooseEnum>("decomposition_method").getEnum<ComputeFiniteStrain::DecompMethod>())
108 {
109  if (!_use_one_based_indexing)
111  "AbaqusUMATStress has transitioned to 1-based indexing in the element (NOEL) and "
112  "integration point (NPT) numbers to ensure maximum compatibility with legacy UMAT files. "
113  "Please ensure that any new UMAT plugins using these quantities are using the correct "
114  "indexing. 0-based indexing will be deprecated soon.");
115 
116  // get material properties
117  for (std::size_t i = 0; i < _number_external_properties; ++i)
118  {
119  _external_properties[i] = &getMaterialProperty<Real>(_external_property_names[i]);
120  _external_properties_old[i] = &getMaterialPropertyOld<Real>(_external_property_names[i]);
121  }
122 
123  // Read mesh dimension and size UMAT arrays (we always size for full 3D)
124  _aqNTENS = 6; // Size of the stress or strain component array (NDI+NSHR)
125  _aqNSHR = 3; // Number of engineering shear stress components
126  _aqNDI = 3; // Number of direct stress components (always 3)
127 
128  _aqDDSDDT.resize(_aqNTENS);
129  _aqDRPLDE.resize(_aqNTENS);
130  _aqSTRAN.resize(_aqNTENS);
131  _aqDFGRD0.resize(9);
132  _aqDFGRD1.resize(9);
133  _aqDROT.resize(9);
134  _aqSTRESS.resize(_aqNTENS);
135  _aqDDSDDE.resize(_aqNTENS * _aqNTENS);
136  _aqDSTRAN.resize(_aqNTENS);
137  _aqPREDEF.resize(_number_external_fields + _number_external_properties);
138  _aqDPRED.resize(_number_external_fields + _number_external_properties);
139 }
140 
141 void
143 {
144  // The _Fbar, _Fbar_old, and _rotation_increment optional properties are only available when an
145  // incremental strain formulation is used. If they are not avaliable we advide the user to
146  // select an incremental formulation.
148  mooseError("AbaqusUMATStress '",
149  name(),
150  "': Incremental strain quantities are not available. You likely are using a total "
151  "strain formulation. Specify `incremental = true` in the tensor mechanics action, "
152  "or use ComputeIncrementalStrain in your input file.");
153 
154  // Let's automatically detect uos and identify the one we are interested in.
155  // If there is more than one, we assume something is off and error out.
156  if (!isParamSetByUser("analysis_step_user_object"))
158  else
159  _step_user_object = &getUserObject<AnalysisStepUserObject>("analysis_step_user_object");
160 }
161 
162 void
164 {
166 
167  // Initialize state variable vector
169  for (const auto i : make_range(_aqNSTATV))
170  _state_var[_qp][i] = 0.0;
171 
172  // Initialize total rotation tensor
174 }
175 
176 void
178 {
179  // current element "number"
180  _aqNOEL = _current_elem->id() + (_use_one_based_indexing ? 1 : 0);
181 
182  // characteristic element length
183  _aqCELENT = std::pow(_current_elem->volume(), 1.0 / _current_elem->dim());
184 
185  if (!_step_user_object)
186  {
187  // Value of total time at the beginning of the current increment
188  _aqTIME[0] = _t - _dt;
189  }
190  else
191  {
192  const unsigned int start_time_step = _step_user_object->getStep(_t - _dt);
193  const Real step_time = _step_user_object->getStartTime(start_time_step);
194  // Value of step time at the beginning of the current increment
195  _aqTIME[0] = step_time;
196  }
197  // Value of total time at the beginning of the current increment
198  _aqTIME[1] = _t - _dt;
199 
200  // Time increment
201  _aqDTIME = _dt;
202 
203  // Fill unused characters with spaces (Fortran)
204  std::fill(_aqCMNAME, _aqCMNAME + 80, ' ');
205  std::memcpy(_aqCMNAME, name().c_str(), name().size());
206 
208 }
209 
210 void
212 {
213  // C uses row-major, whereas Fortran uses column major
214  // therefore, all unsymmetric matrices must be transposed before passing them to Fortran
215  RankTwoTensor FBar_old_fortran = _Fbar_old[_qp].transpose();
216  RankTwoTensor FBar_fortran = _Fbar[_qp].transpose();
217 
218  // DROT needed by UMAT will depend on kinematics and whether or not an intermediate configuration
219  // is used
220  RankTwoTensor DROT_fortran;
221  if (_use_orientation)
222  {
223  DROT_fortran = RankTwoTensor::Identity();
224  }
225  else
226  {
228  DROT_fortran = _rotation_increment[_qp].transpose();
229  else
230  DROT_fortran = _rotation_increment_old[_qp].transpose();
231  }
232 
233  const Real * myDFGRD0 = &(FBar_old_fortran(0, 0));
234  const Real * myDFGRD1 = &(FBar_fortran(0, 0));
235  const Real * myDROT = &(DROT_fortran(0, 0));
236 
237  // More local copies of materials so we can (optionally) rotate
238  RankTwoTensor stress_old = _stress_old[_qp];
239  RankTwoTensor total_strain_old = _total_strain_old[_qp];
240  RankTwoTensor strain_increment = _strain_increment[_qp];
241 
242  // check if we need to rotate to intermediate configuration
243  if (_use_orientation)
244  {
245  // keep track of total rotation
247  // rotate stress/strain/increment from reference configuration to intermediate configuration
248  stress_old.rotate(_total_rotation_old[_qp].transpose());
249  total_strain_old.rotate(_total_rotation_old[_qp].transpose());
250 
252  strain_increment.rotate(_total_rotation[_qp].transpose());
253  else
254  strain_increment.rotate(_total_rotation_old[_qp].transpose());
255  }
257  // rotate old stress to reference configuration
258  stress_old.rotate(_rotation_increment[_qp]);
259 
260  // copy because UMAT does not guarantee constness
261  for (const auto i : make_range(9))
262  {
263  _aqDFGRD0[i] = myDFGRD0[i];
264  _aqDFGRD1[i] = myDFGRD1[i];
265  _aqDROT[i] = myDROT[i];
266  }
267 
268  // Recover "old" state variables
269  for (const auto i : make_range(_aqNSTATV))
270  _aqSTATEV[i] = _state_var_old[_qp][i];
271 
272  // Pass through updated stress, total strain, and strain increment arrays
273  static const std::array<Real, 6> strain_factor{{1, 1, 1, 2, 2, 2}};
274  // Account for difference in vector order convention: yz, xz, xy (MOOSE) vs xy, xz, yz
275  // (commercial software)
276  static const std::array<std::pair<unsigned int, unsigned int>, 6> component{
277  {{0, 0}, {1, 1}, {2, 2}, {0, 1}, {0, 2}, {1, 2}}};
278 
279  for (const auto i : make_range(_aqNTENS))
280  {
281  const auto a = component[i].first;
282  const auto b = component[i].second;
283  _aqSTRESS[i] = stress_old(a, b);
284  _aqSTRAN[i] = total_strain_old(a, b) * strain_factor[i];
285  _aqDSTRAN[i] = strain_increment(a, b) * strain_factor[i];
286  }
287 
288  // current coordinates
289  for (const auto i : make_range(Moose::dim))
290  _aqCOORDS[i] = _q_point[_qp](i);
291 
292  // zero out Jacobian contribution
293  for (const auto i : make_range(_aqNTENS * _aqNTENS))
294  _aqDDSDDE[i] = 0.0;
295 
296  // Set PNEWDT initially to a large value
297  _aqPNEWDT = std::numeric_limits<Real>::max();
298 
299  // Temperature
301 
302  // Temperature increment
304 
305  for (const auto i : make_range(_number_external_fields))
306  {
307  // External field at this step
308  _aqPREDEF[i] = (*_external_fields_old[i])[_qp];
309 
310  // External field increments
312  }
313 
314  for (const auto i : make_range(_number_external_properties))
315  {
316  // External property at this step
318 
319  // External property increments
322  }
323 
324  // Layer number (not supported)
325  _aqLAYER = -1;
326 
327  // Section point number within the layer (not supported)
328  _aqKSPT = -1;
329 
330  // Increment number
331  _aqKINC = _t_step;
332  _aqKSTEP = 1;
333 
334  // integration point number
335  _aqNPT = _qp + (_use_one_based_indexing ? 1 : 0);
336 
337  // Connection to extern statement
338  _umat(_aqSTRESS.data(),
339  _aqSTATEV.data(),
340  _aqDDSDDE.data(),
344  &_aqRPL,
345  _aqDDSDDT.data(),
346  _aqDRPLDE.data(),
347  &_aqDRPLDT,
348  _aqSTRAN.data(),
349  _aqDSTRAN.data(),
350  _aqTIME.data(),
351  &_aqDTIME,
352  &_aqTEMP,
353  &_aqDTEMP,
354  _aqPREDEF.data(),
355  _aqDPRED.data(),
356  _aqCMNAME,
357  &_aqNDI,
358  &_aqNSHR,
359  &_aqNTENS,
360  &_aqNSTATV,
361  _aqPROPS.data(),
362  &_aqNPROPS,
363  _aqCOORDS.data(),
364  _aqDROT.data(),
365  &_aqPNEWDT,
366  &_aqCELENT,
367  _aqDFGRD0.data(),
368  _aqDFGRD1.data(),
369  &_aqNOEL,
370  &_aqNPT,
371  &_aqLAYER,
372  &_aqKSPT,
373  &_aqKSTEP,
374  &_aqKINC);
375 
376  // Update state variables
377  for (int i = 0; i < _aqNSTATV; ++i)
378  _state_var[_qp][i] = _aqSTATEV[i];
379 
380  // Here, we apply UMAT convention: Always multiply _dt by PNEWDT to determine the material time
381  // step MOOSE time stepper will choose the most limiting of all material time step increments
382  // provided
384 
385  // Get new stress tensor - UMAT should update stress
386  // Account for difference in vector order convention: yz, xz, xy (MOOSE) vs xy, xz, yz
387  // (commercial software)
389  _aqSTRESS[0], _aqSTRESS[1], _aqSTRESS[2], _aqSTRESS[5], _aqSTRESS[4], _aqSTRESS[3]);
390 
391  // Build Jacobian matrix from UMAT's Voigt non-standard order to fourth order tensor.
392  const unsigned int N = Moose::dim;
393  const unsigned int ntens = N * (N + 1) / 2;
394  const int nskip = N - 1;
395 
396  for (const auto i : make_range(N))
397  for (const auto j : make_range(N))
398  for (const auto k : make_range(N))
399  for (const auto l : make_range(N))
400  {
401  if (i == j)
402  _jacobian_mult[_qp](i, j, k, l) =
403  k == l ? _aqDDSDDE[i * ntens + k] : _aqDDSDDE[i * ntens + k + nskip + l];
404  else
405  // i!=j
406  _jacobian_mult[_qp](i, j, k, l) =
407  k == l ? _aqDDSDDE[(nskip + i + j) * ntens + k]
408  : _aqDDSDDE[(nskip + i + j) * ntens + k + nskip + l];
409  }
410 
411  // check if we need to rotate from intermediate reference frame
412  if (_use_orientation)
413  {
414  // rotate to current configuration
415  _stress[_qp].rotate(_total_rotation[_qp]);
417  }
420 }
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
virtual const std::string & name() const
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)
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 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()
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.
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.
bool isParamSetByUser(const std::string &nm) const
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
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.