b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2material_solid_mechanics_umat.H
1//------------------------------------------------------------------------
2// b2material_solid_mechanics_umat.H --
3//
4// UMAT material api wrapper.
5//
6// written by Mathias Doreille
7// Neda Ebrahimi Pour <neda.ebrahimipour@dlr.de>
8//
9// (c) 2009,2016 SMR Engineering & Development SA
10// 2502 Bienne, Switzerland
11//
12// (c) 2023 Deutsches Zentrum für Luft- und Raumfahrt (DLR) e.V.
13// Linder Höhe, 51147 Köln
14//
15// All Rights Reserved. Proprietary source code. The contents of
16// this file may not be disclosed to third parties, copied or
17// duplicated in any form, in whole or in part, without the prior
18// written permission of SMR.
19//------------------------------------------------------------------------
20
21// TODO: set DROT, apply the rot to the strain, stress and ddsdde
22// Thus this wrapper is only valid for small displacement.
23
24#include "elements/properties/b2fortran_element_property.H"
25#include "elements/properties/b2solid_mechanics.H"
26#include "io/b2000_db/b2000_db_v3/b2fortran_element_property.H"
27#include "ip/b2ip_constants.H"
28#include "model/b2solution.H"
29
30#ifndef B2_MATERIAL_SOLID_MECHANICS_UMAT_H_
31#define B2_MATERIAL_SOLID_MECHANICS_UMAT_H_
32
33namespace b2000 { namespace element {
34
35typedef void(umat_subroutine_f)(
36 // Output in all situations (at the and of the increment).
37 double* STRESS, // (NTENS), stress at the end of the increment
38 double* STATEV, // (NSTATV), solution-dependent state variables
39 double* DDSDDE, // (NTENS,NTENS), Jacobian matrix of the constitutive model
40 double* SSE, // elastic strain energy
41 double* SPD, // plastic dissipation
42 double* SCD, // “creep” dissipation
43 // Output, only in a fully coupled temperature-displacement analysis
44 double* RPL, // volumetric heat generation per unit time
45 double*
46 DDSDDT, // (NTENS), variation of the stress increments with respect to the temperature
47 double* DRPLDE, // (NTENS), variation of RPL with respect to the strain increments
48 double* DRPLDT, // variation of RPL with respect to the temperature
49 // Input (at the beginning of the increment)
50 const double* STRAN, // (NTENS), total strains at the beginning of the increment
51 const double* DSTRAN, // (NTENS), strains increment
52 const double TIME[2], // step time and total time
53 const double* DTIME, // time increment
54 const double* TEMP, // temperature
55 const double* DTEMP, // temperature increment
56 const double* PREDEF, // array of interpolated values of predefined field variables at this
57 // point at the start of the increment
58 const double* DPRED, // array of increments of predefined field variables
59 const char* CMNAME, // Name given on the *MATERIAL option
60 const int* NDI, // number of direct stress components at this point
61 const int* NSHR, // number of engineering shear stress components at this point
62 const int* NTENS, // size of the stress or strain component array
63 const int* NSTATV, // number of solution-dependent state variables that are associated with
64 // this material type
65 const double* PROPS, // array of material constants
66 const int* NPROPS, // number of material constants
67 const double COORDS[3], // array containing the coordinates of this point
68 const double DROT[3][3], // rotation increment matrix
69 double* PNEWDT, // ratio of suggested new time increment
70 const double* CELENT, // characteristic element length
71 const double DFGRD0[3][3], // deformation gradient at the beginning of the increment
72 const double DFGRD1[3][3], // deformation gradient at the end of the increment
73 const int* NOEL, // element number
74 const int* NPT, // integration point number
75 const int* LAYER, // layer number
76 const int* KSPT, // section point number
77 const int* KSTEP, // step number
78 const int* KINC, // increment number
79 const int CNAME_len);
80
81template <umat_subroutine_f UMAT_SUBROUTINE, const char MATERIAL_TYPE_NAME[], int NSTATV>
82class MaterialSolidMechanics3DUMAT_copy;
83
84template <umat_subroutine_f UMAT_SUBROUTINE, const char MATERIAL_TYPE_NAME[], int NSTATV>
85class MaterialSolidMechanics3DUMAT : virtual public b2000::b2dbv3::FortranElementProperty,
87public:
88 LinearType linear(const int layer_id = -1) const { return nonlinear; }
89
90 bool path_dependent(const int layer_id = -1) const { return true; }
91
92 SolidMechanics3D* copy(int layer_) {
93 return new MaterialSolidMechanics3DUMAT_copy<UMAT_SUBROUTINE, MATERIAL_TYPE_NAME, NSTATV>(
94 *this);
95 }
96
97 bool isotropic(const int layer_id = -1) const { return false; }
98
99 void get_dynamic_nonlinear_stress(
100 Model* model, const Element* element,
101 b2000::b2linalg::Vector<double, b2000::b2linalg::Vdense_constref> nodes_interpolation,
102 const double element_coordinate[3], const int layer_id,
103 const double covariant_natural_base[3][3], const double displacement_gradient[3][3],
104 const double green_lagrange_strain[6], const double green_lagrange_strain_dot[6],
105 const double velocity[3], const double acceleration[3], const double time,
106 const double delta_time, const double area,
107 const EquilibriumSolution equilibrium_solution, double piola_kirchhoff_stress[6],
108 double d_piola_kirchhoff_stress_d_strain[21],
109 double d_piola_kirchhoff_stress_d_strain_dot[21],
110 double d_piola_kirchhoff_stress_d_time[6], double inertial_force[3], double& density,
111 GradientContainer* gradient_container, SolverHints* solver_hints,
112 const double covariant_base[3][3], const double contravariant_base[3][3]) {
113 get_static_nonlinear_stress(
114 model, element, nodes_interpolation, element_coordinate, layer_id,
115 covariant_natural_base, displacement_gradient, green_lagrange_strain, time,
116 delta_time, area, equilibrium_solution, piola_kirchhoff_stress,
117 d_piola_kirchhoff_stress_d_strain, d_piola_kirchhoff_stress_d_time,
118 gradient_container, solver_hints, covariant_base, contravariant_base);
119 }
120
121 void get_static_nonlinear_stress(
122 Model* model, const Element* element, Vector<double, Vdense_constref> nodes_interpolation,
123 const double element_coordinate[3], const int layer_id,
124 const double covariant_natural_base[3][3], const double displacement_gradient[3][3],
125 const double green_lagrange_strain[6], const double time, const double delta_time,
126 const double area, const EquilibriumSolution equilibrium_solution,
127 double piola_kirchhoff_stress[6], double d_piola_kirchhoff_stress_d_strain[21],
128 double d_piola_kirchhoff_stress_d_time[6], GradientContainer* gradient_container,
129 SolverHints* solver_hints, const double covariant_base[3][3] = 0,
130 const double contravariant_base[3][3] = 0) {
131 Exception() << "A copy of the object must be used." << THROW;
132 }
133
134 typedef ObjectTypeComplete<
135 MaterialSolidMechanics3DUMAT<UMAT_SUBROUTINE, MATERIAL_TYPE_NAME, NSTATV>,
136 FortranElementProperty::type_t>
137 type_t;
138 static type_t type;
139};
140
141template <umat_subroutine_f UMAT_SUBROUTINE, const char MATERIAL_TYPE_NAME[], int NSTATV>
142typename MaterialSolidMechanics3DUMAT<UMAT_SUBROUTINE, MATERIAL_TYPE_NAME, NSTATV>::type_t
143 MaterialSolidMechanics3DUMAT<UMAT_SUBROUTINE, MATERIAL_TYPE_NAME, NSTATV>::type(
144 MATERIAL_TYPE_NAME, "", StringList(), element::module, &b2000::ElementProperty::type);
145
146template <umat_subroutine_f UMAT_SUBROUTINE, const char MATERIAL_TYPE_NAME[], int NSTATV>
147class MaterialSolidMechanics3DUMAT_copy : public b2000::SolidMechanics3D {
148public:
149 typedef MaterialSolidMechanics3DUMAT<UMAT_SUBROUTINE, MATERIAL_TYPE_NAME, NSTATV> parent_type;
150
151 MaterialSolidMechanics3DUMAT_copy(parent_type& parent_)
152 : parent(parent_), conv_time(0), conv_sse(0), conv_spd(0), conv_scd(0) {
153 std::fill(conv_deformation_gradient[0], conv_deformation_gradient[3], 0);
154 std::fill(conv_strain_ea, conv_strain_ea + 6, 0);
155 std::fill(conv_stress_ea, conv_stress_ea + 6, 0);
156 std::fill(conv_statv, conv_statv + NSTATV, 0);
157 }
158
159 LinearType linear(const int layer_id = -1) const { return nonlinear; }
160
161 bool path_dependent(const int layer_id = -1) const { return true; }
162
163 SolidMechanics3D* copy(int layer_) { return new MaterialSolidMechanics3DUMAT_copy(*this); }
164
165 bool isotropic(const int layer_id = -1) const { return false; }
166
167 void get_dynamic_nonlinear_stress(
168 Model* model, const Element* element, Vector<double, Vdense_constref> nodes_interpolation,
169 const double element_coordinate[3], const int layer_id,
170 const double covariant_natural_base[3][3], const double displacement_gradient[3][3],
171 const double green_lagrange_strain[6], const double green_lagrange_strain_dot[6],
172 const double velocity[3], const double acceleration[3], const double time,
173 const double delta_time, const double area,
174 const EquilibriumSolution equilibrium_solution, double piola_kirchhoff_stress[6],
175 double d_piola_kirchhoff_stress_d_strain[21],
176 double d_piola_kirchhoff_stress_d_strain_dot[21],
177 double d_piola_kirchhoff_stress_d_time[6], double inertial_force[3], double& density,
178 GradientContainer* gradient_container, SolverHints* solver_hints,
179 const double covariant_base[3][3], const double contravariant_base[3][3]) {
180 get_static_nonlinear_stress(
181 model, element, nodes_interpolation, element_coordinate, layer_id,
182 covariant_natural_base, displacement_gradient, green_lagrange_strain, time,
183 delta_time, area, equilibrium_solution, piola_kirchhoff_stress,
184 d_piola_kirchhoff_stress_d_strain, d_piola_kirchhoff_stress_d_time,
185 gradient_container, solver_hints, covariant_base, contravariant_base);
186 }
187
188 void get_static_nonlinear_stress(
189 Model* model, const Element* element, Vector<double, Vdense_constref> nodes_interpolation,
190 const double element_coordinate[3], const int layer_id,
191 const double covariant_natural_base[3][3], const double displacement_gradient[3][3],
192 const double green_lagrange_strain[6], const double time, const double delta_time,
193 const double area, const EquilibriumSolution equilibrium_solution,
194 double piola_kirchhoff_stress[6], double d_piola_kirchhoff_stress_d_strain[21],
195 double d_piola_kirchhoff_stress_d_time[6], GradientContainer* gradient_container,
196 SolverHints* solver_hints, const double covariant_base[3][3] = 0,
197 const double contravariant_base[3][3] = 0) {
198 // Obtain info on the material constant and orientation of the material.
199 bool material_ref_identity;
200 double material_ref[3][3];
201 const double* props = parent.get_material_and_material_referential(
202 element, layer_id, covariant_natural_base, material_ref, material_ref_identity, true);
203 const int nprops = int(props[B2MATPOSSTART]);
204
205 // Compute the Linear/Green-Lagrange strain in the branch-global
206 // orthogonal system.
207 double strain_bg[6];
208 if (green_lagrange_strain == 0) {
209 std::fill_n(strain_bg, 6, 0.0);
210 } else if (covariant_base == 0) {
211 std::copy(green_lagrange_strain, green_lagrange_strain + 6, strain_bg);
212 } else {
213 transform_strain_from_base_A_to_I(covariant_base, green_lagrange_strain, strain_bg)
214 :
215
216 // Compute the Linear/Green-Lagrange strain in the element-aligned
217 // orthogonal system.
218 double strain_ea[6];
219 }
220 if (material_ref_identity) {
221 std::copy(strain_bg, strain_bg + 6, strain_ea);
222 } else {
223 transform_strain_from_I_to_base_B(material_ref, strain_bg, strain_ea);
224 }
225
226 // Compute the strain increment in the element-aligned
227 // orthogonal system.
228 double dstrain[6];
229 for (int i = 0; i != 6; ++i) { dstrain[i] = strain_ea[i] - conv_strain_ea[i]; }
230
231 // Get the integration point coordinates.
232 double coords[3] = {};
233 std::pair<int, Node* const*> nodes = element->get_nodes();
234 for (int i = 0; i != nodes.first; ++i) {
235 const double* c = nodes.second[i]->get_coor().second;
236 for (int j = 0; j != 3; ++j) { coords[j] += nodes_interpolation[i] * c[j]; }
237 }
238
239 // Compute the deformation gradient
240 double deformation_gradient[3][3];
241 for (int i = 0; i != 3; ++i) {
242 for (int j = 0; j != 3; ++j) {
243 deformation_gradient[j][i] = displacement_gradient[j][i];
244 }
245 deformation_gradient[i][i] += 1;
246 }
247
248 double dtime = time - conv_time;
249
250 double pnewdt = delta_time;
251
252 double statv[NSTATV];
253 std::copy(conv_statv, conv_statv + NSTATV, statv);
254
255 double sse = conv_sse;
256 double spd = conv_spd;
257 double scd = conv_scd;
258
259 double stress_ea[6];
260 std::copy(conv_stress_ea, conv_stress_ea + 6, stress_ea);
261
262 double drot[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
263 const double celent = area;
264
265 const int noel = element->get_id();
266 const int ntp = 0;
267 const int layer = layer_id + 1;
268
269 const int val3 = 3;
270 const int val6 = 6;
271 const int nstatv = NSTATV;
272 const int val_unknown = 0;
273 const double time_all[2] = {conv_time, conv_time};
274
275 double ddsdde[6][6];
276
277 // Call the Fortran umat subroutine.
278 UMAT_SUBROUTINE(
279 stress_ea, statv, ddsdde[0], &sse, &spd, &scd, 0, 0, 0,
280 0, // no coupled temperature-displacement analysis
281 conv_strain_ea, dstrain, time_all, &dtime, 0,
282 0, // no coupled temperature-displacement analysis
283 0, 0, // no array of interpolated values of predefined field
284 MATERIAL_TYPE_NAME, &val3, &val3, &val6, &nstatv, props + B2MATPOSSTART + 1, &nprops,
285 coords, drot, &pnewdt, &celent, conv_deformation_gradient, deformation_gradient,
286 &noel, &val_unknown, &layer, &val_unknown, &val_unknown, &val_unknown,
287 strlen(MATERIAL_TYPE_NAME));
288
289 if (equilibrium_solution) {
290 std::copy(
291 deformation_gradient[0], deformation_gradient[3], conv_deformation_gradient[0]);
292 std::copy(strain_ea, strain_ea + 6, conv_strain_ea);
293 std::copy(stress_ea, stress_ea + 6, conv_stress_ea);
294 conv_time = time;
295 std::copy(statv, statv + NSTATV, conv_statv);
296 }
297
298 double G[3][3];
299 if (covariant_base != 0) {
300 copy_3_3(covariant_base, G);
301 } else {
303 }
304 double G_d[3][3];
305 get_base_opposite_variance(G, G_d);
306
307 //
308 // Transform the Jacobian matrix of the constitutive model
309 // either to the branch-global orthogonal system or to
310 // system required by the element and store it in the
311 // 'd_stress_d_strain' array.
312 //
313 if (d_piola_kirchhoff_stress_d_strain != NULL) {
314 double d_stress_d_strain_ea[21];
315 // Convert the ddsdde rectangular 6x6 matrix to the
316 // d_stress_d_strain_ea lower packed matrix.
317 // The symmetric part of the matrix is calculated by taking one
318 // half the sum of the ddsdde matrix and its transpose.
319 {
320 double* ptr = d_stress_d_strain_ea;
321 for (int j = 0; j != 6; ++j) {
322 for (int i = j; i != 6; ++i, ++ptr) {
323 *ptr = 0.5 * (ddsdde[j][i] + ddsdde[i][j]);
324 }
325 }
326 }
327
328 // Transform the constitutive tensor from the element
329 // covariant basis to the material reference frame.
330 transform_constitutive_tensor_from_base_A_to_base_B(
331 G, material_ref, d_stress_d_strain_ea, d_piola_kirchhoff_stress_d_strain);
332 }
333
334 // Compute the Linear/2nd-Piola-Kirchhoff stress in the
335 // branch-global orthogonal system.
336 double stress_bg[6];
337 transform_stress_from_base_A_to_I(material_ref, stress_ea, stress_bg);
338
339 // Store the Linear/2nd-Piola-Kirchhoff stress in the 'stress'
340 // array, either in the branch-global orthogonal system or in the
341 // contravariant base given by the element.
342 if (piola_kirchhoff_stress != 0) {
343 transform_stress_from_I_to_base_B(G_d, stress_bg, piola_kirchhoff_stress);
344 }
345
346 if (gradient_container == 0) { return; }
347
348 // Remove the x2 in the shear components of the
349 // Linear/Green-Lagrange strain in the branch-global orthogonal
350 // system.
351 double strain_bg_storage[6];
352 std::copy(strain_bg, strain_bg + 6, strain_bg_storage);
353 for (int i = 3; i != 6; ++i) { strain_bg_storage[i] *= 0.5; }
354
355 // Transform the Linear/2nd-Piola-Kirchhoff stress to the
356 // Linear/Cauchy stress in branch-global orthogonal system.
357 double stress_bg_storage[6];
358 if (!nonlinear) {
359 std::copy(stress_bg, stress_bg + 6, stress_bg_storage);
360 } else {
361 // Transform the 2nd-Piola-Kirchhoff stress in the
362 // element-aligned orthogonal system to the Cauchy stress in
363 // the branch-global orthogonal system.
364
365 // 1. Compute the deformation gradient from the displacement
366 // gradient.
367 double deformation_gradient[3][3];
368 if (displacement_gradient != NULL) {
369 if (contravariant_base) {
371 displacement_gradient, contravariant_base, deformation_gradient);
372 } else {
373 std::copy(
374 displacement_gradient[0], displacement_gradient[3],
375 deformation_gradient[0]);
376 }
377 } else {
378 std::fill(deformation_gradient[0], deformation_gradient[3], 0);
379 }
380 deformation_gradient[0][0] += 1;
381 deformation_gradient[1][1] += 1;
382 deformation_gradient[2][2] += 1;
383
384 // 2. Compute the inverse of the determinant of the
385 // deformation gradient.
386 const double det_inv = 1.0 / determinant_3_3(deformation_gradient);
387
388 // 3. Compute X*S*X^T.
389 if (material_ref_identity) {
390 transform_stress_from_base_A_ov_to_I(
391 deformation_gradient, stress_ea, stress_bg_storage);
392 } else {
393 double deformation_gradient_aligned_ortho[3][3];
395 deformation_gradient, material_ref, deformation_gradient_aligned_ortho);
396 transform_stress_from_base_A_ov_to_I(
397 deformation_gradient_aligned_ortho, stress_ea, stress_bg_storage);
398 }
399
400 // 4. Divide by the determinant of the deformation gradient.
401 for (int i = 0; i != 6; ++i) { stress_bg_storage[i] *= det_inv; }
402 }
403
404 //
405 // Storage in the database.
406 //
407 static const GradientContainer::FieldDescription strain_descr = {
408 "STRAIN",
409 "Exx.Eyy.Ezz.Exy.Eyz.Exz",
410 (nonlinear ? "Green Lagrange strain" : "Linear strain"),
411 3,
412 6,
413 2,
414 3,
415 true,
416 typeid(double)};
417
418 static const GradientContainer::FieldDescription stress_descr = {
419 "STRESS",
420 "Sxx.Syy.Szz.Sxy.Syz.Sxz",
421 (nonlinear ? "Cauchy stress" : "Linear stress"),
422 3,
423 6,
424 2,
425 3,
426 true,
427 typeid(double)};
428
429 // Fill strain and stress into the GradientContainer object.
430 if (gradient_container->compute_field_value(strain_descr.name)) {
431 gradient_container->set_field_value(strain_descr, strain_bg_storage);
432 }
433 if (gradient_container->compute_field_value(stress_descr.name)) {
434 gradient_container->set_field_value(stress_descr, stress_bg_storage);
435 }
436 }
437
438private:
439 parent_type& parent;
440 double conv_deformation_gradient[3][3];
441 double conv_strain_ea[6];
442 double conv_stress_ea[6];
443 double conv_time;
444 double conv_statv[NSTATV];
445 double conv_sse;
446 double conv_spd;
447 double conv_scd;
448};
449
450}} // namespace b2000::element
451
452#define DEFINE_NEW_MATERIAL_SOLID_MECHANICS_3D_UMAT( \
453 subroutine_name, SUBROUTINE_NAME, material_name, NSTATV) \
454 extern "C" b2000::element::umat_subroutine_f FC_GLOBAL(subroutine_name, SUBROUTINE_NAME); \
455 namespace { \
456 char mname[] = material_name; \
457 } \
458 template class b2000::element::MaterialSolidMechanics3DUMAT< \
459 FC_GLOBAL(subroutine_name, SUBROUTINE_NAME), mname, NSTATV>;
460
461#endif // B2_MATERIAL_SOLID_MECHANICS_UMAT_H_
#define THROW
Definition b2exception.H:198
Definition b2solid_mechanics.H:113
Definition b2fortran_element_property.H:53
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32
void set_identity_3_3(T1 a[3][3])
Definition b2tensor_calculus.H:511
void inner_product_3_3_NN(const T a[3][3], const T b[3][3], T c[3][3])
Definition b2tensor_calculus.H:808
T determinant_3_3(const T a[3][3])
Definition b2tensor_calculus.H:669
void copy_3_3(const T1 a[3][3], T1 b[3][3])
Definition b2tensor_calculus.H:525