https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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"
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
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
144void
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
165void
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
176 _total_rotation[_qp] = _R;
177}
178
179void
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
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
210 ComputeGeneralStressBase::computeProperties();
211}
212
213void
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;
225 {
226 DROT_fortran = RankTwoTensor::Identity();
227 }
228 else
229 {
230 if (_decomposition_method == ComputeFiniteStrain::DecompMethod::HughesWinget)
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
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
254 if (_decomposition_method == ComputeFiniteStrain::DecompMethod::HughesWinget)
255 strain_increment.rotate(_total_rotation[_qp].transpose());
256 else
257 strain_increment.rotate(_total_rotation_old[_qp].transpose());
258 }
259 else if (_decomposition_method == ComputeFiniteStrain::DecompMethod::HughesWinget)
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
319 _aqDPRED[i] = (*_external_fields[i])[_qp] - (*_external_fields_old[i])[_qp];
320 }
321
322 for (const auto i : make_range(_number_external_properties))
323 {
324 // External property at this step
326
327 // External property increments
329 (*_external_properties[i])[_qp] - (*_external_properties_old[i])[_qp];
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(),
351 &_creep_dissipation[_qp],
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
391 _material_timestep[_qp] = _aqPNEWDT * _dt;
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)
396 _stress[_qp] = RankTwoTensor(
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
421 {
422 // rotate to current configuration
423 _stress[_qp].rotate(_total_rotation[_qp]);
424 _jacobian_mult[_qp].rotate(_total_rotation[_qp]);
425 }
426 else if (_decomposition_method != ComputeFiniteStrain::DecompMethod::HughesWinget)
427 _stress[_qp].rotate(_rotation_increment[_qp]);
428}
registerMooseObject("SolidMechanicsApp", AbaqusUMATStress)
void mooseError(Args &&... args)
void mooseDeprecated(Args &&... args)
const std::string name
Definition Setup.h:21
void ErrorVector unsigned int
Coupling material to use Abaqus UMAT models in MOOSE.
const OptionalMaterialProperty< RankTwoTensor > & _strain_increment
void initialSetup() override
check optional material properties for consistency
std::array< Real, 3 > _aqCOORDS
An array containing the coordinates of this point.
MaterialProperty< RankTwoTensor > & _total_rotation
const MaterialProperty< Real > & _plastic_dissipation_old
const VariableValue & _temperature_old
const std::vector< const VariableValue * > _external_fields_old
const OptionalMaterialProperty< RankTwoTensor > & _rotation_increment_old
int _aqNOEL
Element number.
const MaterialProperty< Real > & _creep_dissipation_old
std::vector< Real > _aqDFGRD0
Array containing the deformation gradient at the beginning of the increment.
int _aqKINC
Increment number (_t_step).
const MaterialProperty< RankTwoTensor > & _total_strain_old
int _aqKSTEP
The step number (as per Abaqus definition) can be set by the user.
int _aqLAYER
Layer number (for composite shells and layered solids). (not supported)
std::vector< Real > _aqDROT
Rotation increment matrix.
const RotationTensor _R
std::vector< Real > _aqDDSDDE
Jacobian matrix of the model (out)
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...
std::vector< Real > _aqDRPLDE
Variation of RPL with respect to the strain increments.
const std::vector< const VariableValue * > _external_fields
int _aqNTENS
Size of the stress or strain component array (NDI + NSHR).
const OptionalMaterialProperty< RankTwoTensor > & _rotation_increment
const bool _use_orientation
Rotation information.
std::vector< Real > _aqDFGRD1
Array containing the deformation gradient at the end of the increment.
const std::size_t _number_external_properties
const AnalysisStepUserObject * _step_user_object
User object that determines step number.
void initQpStatefulProperties() override
std::vector< Real > _aqPROPS
User-specified array of material constants associated with this user material.
unsigned int _aqNPT
Integration point number.
MaterialProperty< std::vector< Real > > & _state_var
const MaterialProperty< std::vector< Real > > & _state_var_old
std::vector< Real > _aqDDSDDT
Variation of the stress increments with respect to the temperature.
char _aqCMNAME[80]
Model name buffer.
MaterialProperty< Real > & _creep_dissipation
std::vector< Real > _aqSTRAN
An array containing the total strains at the beginning of the increment.
MaterialProperty< RankFourTensor > & _jacobian_mult
Jacobian multiplier.
const ComputeFiniteStrain::DecompMethod _decomposition_method
Method being used to compute strain and rotation increments.
const VariableValue & _temperature
std::vector< Real > _aqPREDEF
Array of interpolated values of predefined field variables at this point at the start of the incremen...
Real _aqRPL
Volumetric heat generation per unit time at the end of the increment caused by mechanical working of ...
std::vector< Real > _aqSTATEV
const bool _use_one_based_indexing
parameter to assist with the transition to 1-based indexing
const OptionalMaterialProperty< RankTwoTensor > & _Fbar
int _aqNSHR
Number of engineering shear stress components at this point.
const MaterialProperty< RankTwoTensor > & _total_rotation_old
const MaterialProperty< Real > & _elastic_strain_energy_old
std::vector< Real > _aqDSTRAN
Array of strain increments.
const std::size_t _number_external_fields
int _aqNPROPS
User-defined number of material constants associated with this user material.
Real _aqDRPLDT
Variation of the volumetric heat generation (RPL) with respect to the temperature.
Real _aqDTIME
Time increment.
Real _aqTEMP
Temperature at the start of the increment.
int _aqNSTATV
Number of solution-dependent state variables that are associated with this material type.
const MaterialProperty< RankTwoTensor > & _stress_old
void computeProperties() override
perform per-element computation/initialization
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 computeQpStress() override
Compute the stress and store it in the _stress material property for the current quadrature point.
AbaqusUMATStress(const InputParameters &parameters)
std::vector< const MaterialProperty< Real > * > _external_properties
const OptionalMaterialProperty< RankTwoTensor > & _Fbar_old
int _aqNDI
Number of direct stress components at this point.
MaterialProperty< Real > & _elastic_strain_energy
Real _aqDTEMP
Increment of temperature.
MaterialProperty< Real > & _material_timestep
recommended maximum timestep for this model under the current conditions
MaterialProperty< Real > & _plastic_dissipation
int _aqKSPT
Section point number within the current layer. (not supported)
std::vector< Real > _aqDPRED
Array of increments of predefined field variables.
std::vector< Real > _aqSTRESS
Stress tensor (in: old stress, out: updated stress)
Real _aqPNEWDT
Ratio of suggested new time increment to the time increment being used (out)
static InputParameters validParams()
virtual void getAnalysisStepUserObject(const FEProblemBase &fe_problem, const AnalysisStepUserObject *&step_user_object, const std::string &name)
unsigned int getStep(const Real &time) const
Real getStartTime(const unsigned int &step) const
ComputeFiniteStrain defines a strain increment and rotation increment, for finite strains.
static MooseEnum decompositionType()
ComputeGeneralStressBase is the direct base class for stress calculator materials that may leverage q...
virtual void initQpStatefulProperties() override
static InputParameters validParams()
MaterialProperty< RankTwoTensor > & _stress
Stress material property.
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void addCoupledVar(const std::string &name, const std::string &doc_string)
virtual void resize(const std::size_t size) override final
void rotate(const RankTwoTensorTempl< T > &R)
RankTwoTensorTempl< T > transpose() const
static RankTwoTensorTempl Identity()
VariableValueTempl< false > VariableValue
static constexpr std::size_t dim
VectorValue< Real > RealVectorValue