https://mooseframework.inl.gov
Loading...
Searching...
No Matches
CrystalPlasticityStressUpdateBase.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
11
12#include "libmesh/utility.h"
13#include "libmesh/int_range.h"
14#include "Conversion.h"
15#include "MooseException.h"
16
19{
21 params.addParam<std::string>(
22 "base_name",
23 "Optional parameter that allows the user to define multiple crystal plasticity mechanisms");
25 "Crystal Plasticity base class: handles the Newton iteration over the stress residual and "
26 "calculates the Jacobian based on constitutive laws provided by inheriting classes");
27
28 // The return stress increment classes are intended to be iterative materials, so must set compute
29 // = false for all inheriting classes
30 params.set<bool>("compute") = false;
31 params.suppressParameter<bool>("compute");
32
33 params.addParam<MooseEnum>(
34 "crystal_lattice_type",
35 MooseEnum("BCC FCC HCP", "FCC"),
36 "Crystal lattice type or representative unit cell, i.e., BCC, FCC, HCP, etc.");
37
38 params.addRangeCheckedParam<std::vector<Real>>(
39 "unit_cell_dimension",
40 std::vector<Real>{1.0, 1.0, 1.0},
41 "unit_cell_dimension_size = 3",
42 "The dimension of the unit cell along three directions, where a cubic unit cell is assumed "
43 "for cubic crystals and a hexagonal unit cell (a, a, c) is assumed for HCP crystals. These "
44 "dimensions will be taken into account while computing the slip systems."
45 " Default size is 1.0 along all three directions.");
46
47 params.addRequiredParam<unsigned int>(
48 "number_slip_systems",
49 "The total number of possible active slip systems for the crystalline material");
50 params.addRequiredParam<FileName>(
51 "slip_sys_file_name",
52 "Name of the file containing the slip systems, one slip system per row, with the slip plane "
53 "normal given before the slip plane direction.");
54 params.addParam<Real>("number_cross_slip_directions",
55 0,
56 "Quanity of unique slip directions, used to determine cross slip familes");
57 params.addParam<Real>("number_cross_slip_planes",
58 0,
59 "Quanity of slip planes belonging to a single cross slip direction; used "
60 "to determine cross slip families");
61 params.addParam<Real>(
62 "slip_increment_tolerance",
63 2e-2,
64 "Maximum allowable slip in an increment for each individual constitutive model");
65 params.addParam<Real>(
66 "stol", 1e-2, "Constitutive internal state variable relative change tolerance");
67 params.addParam<Real>("resistance_tol",
68 1.0e-2,
69 "Constitutive slip system resistance relative residual tolerance for each "
70 "individual constitutive model");
71 params.addParam<Real>("zero_tol",
72 1e-12,
73 "Tolerance for residual check when variable value is zero for each "
74 "individual constitutive model");
75 params.addParam<bool>(
76 "print_state_variable_convergence_error_messages",
77 false,
78 "Whether or not to print warning messages from the crystal plasticity specific convergence "
79 "checks on both the constiutive model internal state variables.");
80 return params;
81}
82
84 const InputParameters & parameters)
85 : Material(parameters),
86 _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
87 _crystal_lattice_type(
88 getParam<MooseEnum>("crystal_lattice_type").getEnum<CrystalLatticeType>()),
89 _unit_cell_dimension(getParam<std::vector<Real>>("unit_cell_dimension")),
90 _number_slip_systems(getParam<unsigned int>("number_slip_systems")),
91 _slip_sys_file_name(getParam<FileName>("slip_sys_file_name")),
92 _number_cross_slip_directions(getParam<Real>("number_cross_slip_directions")),
93 _number_cross_slip_planes(getParam<Real>("number_cross_slip_planes")),
94
95 _rel_state_var_tol(getParam<Real>("stol")),
96 _slip_incr_tol(getParam<Real>("slip_increment_tolerance")),
97 _resistance_tol(getParam<Real>("resistance_tol")),
98 _zero_tol(getParam<Real>("zero_tol")),
99
100 _slip_resistance(declareProperty<std::vector<Real>>(_base_name + "slip_resistance")),
101 _slip_resistance_old(getMaterialPropertyOld<std::vector<Real>>(_base_name + "slip_resistance")),
102 _slip_increment(declareProperty<std::vector<Real>>(_base_name + "slip_increment")),
103
104 _slip_direction(_number_slip_systems),
105 _slip_plane_normal(_number_slip_systems),
106 _flow_direction(declareProperty<std::vector<RankTwoTensor>>(_base_name + "flow_direction")),
107 _tau(declareProperty<std::vector<Real>>(_base_name + "applied_shear_stress")),
108 _print_convergence_message(getParam<bool>("print_state_variable_convergence_error_messages"))
109{
112
113 if (parameters.isParamSetByUser("number_cross_slip_directions"))
115 else
116 _calculate_cross_slip = false;
117}
118
119void
124
125void
139
140void
142{
143 bool orthonormal_error = false;
144
145 // read in the slip system data from auxiliary text file
147 _reader.setFormatFlag(MooseUtils::DelimitedFileReader::FormatFlag::ROWS);
148 _reader.read();
149
150 // check the size of the input
151 if (_reader.getData().size() != _number_slip_systems)
153 "number_slip_systems",
154 "The number of rows in the slip system file should match the number of slip system.");
155
156 for (const auto i : make_range(_number_slip_systems))
157 {
158 // initialize to zero
159 _slip_direction[i].zero();
160 _slip_plane_normal[i].zero();
161 }
162
167 {
168 for (const auto i : make_range(_number_slip_systems))
169 {
170 // directly grab the raw data and scale it by the unit cell dimension
171 for (const auto j : index_range(_reader.getData(i)))
172 {
173 if (j < LIBMESH_DIM)
174 _slip_plane_normal[i](j) = _reader.getData(i)[j] / _unit_cell_dimension[j];
175 else
176 _slip_direction[i](j - LIBMESH_DIM) =
177 _reader.getData(i)[j] * _unit_cell_dimension[j - LIBMESH_DIM];
178 }
179 }
180 }
181
182 for (const auto i : make_range(_number_slip_systems))
183 {
184 // normalize
186 _slip_direction[i] /= _slip_direction[i].norm();
187
189 {
190 const auto magnitude = _slip_plane_normal[i] * _slip_direction[i];
191 if (std::abs(magnitude) > libMesh::TOLERANCE)
192 {
193 orthonormal_error = true;
194 break;
195 }
196 }
197 }
198
199 if (orthonormal_error)
200 mooseError("CrystalPlasticityStressUpdateBase Error: The slip system file contains a slip "
201 "direction and plane normal pair that are not orthonormal in the Cartesian "
202 "coordinate system.");
203}
204
205void
207 const MooseUtils::DelimitedFileReader & reader)
208{
209 const unsigned int miller_bravais_indices = 4;
210 RealVectorValue temporary_slip_direction, temporary_slip_plane;
211 // temporary_slip_plane.resize(LIBMESH_DIM);
212 // temporary_slip_direction.resize(LIBMESH_DIM);
213
216 mooseError("CrystalPlasticityStressUpdateBase Error: The specified unit cell dimensions are "
217 "not consistent with expectations for "
218 "HCP crystal hexagonal lattices.");
219 else if (reader.getData(0).size() != miller_bravais_indices * 2)
220 mooseError("CrystalPlasticityStressUpdateBase Error: The number of entries in the first row of "
221 "the slip system file is not consistent with the expectations for the 4-index "
222 "Miller-Bravais assumption for HCP crystals. This file should represent both the "
223 "slip plane normal and the slip direction with 4-indices each.");
224
225 // set up the tranformation matrices
226 RankTwoTensor transform_matrix;
227 transform_matrix.zero();
228 transform_matrix(0, 0) = 1.0 / _unit_cell_dimension[0];
229 transform_matrix(1, 0) = 1.0 / (_unit_cell_dimension[0] * std::sqrt(3.0));
230 transform_matrix(1, 1) = 2.0 / (_unit_cell_dimension[0] * std::sqrt(3.0));
231 transform_matrix(2, 2) = 1.0 / (_unit_cell_dimension[2]);
232
233 for (const auto i : make_range(_number_slip_systems))
234 {
235 // read in raw data from file and store in the temporary vectors
236 for (const auto j : index_range(reader.getData(i)))
237 {
238 // Check that the slip plane normal indices of the basal plane sum to zero for consistency
239 Real basal_pl_sum = 0.0;
240 for (const auto k : make_range(Moose::dim))
241 basal_pl_sum += reader.getData(i)[k];
242
243 if (basal_pl_sum > _zero_tol)
245 "CrystalPlasticityStressUpdateBase Error: The specified HCP basal plane Miller-Bravais "
246 "indices do not sum to zero. Check the values supplied in the associated text file.");
247
248 // Check that the slip direction indices of the basal plane sum to zero for consistency
249 Real basal_dir_sum = 0.0;
250 for (const auto k : make_range(miller_bravais_indices, miller_bravais_indices + LIBMESH_DIM))
251 basal_dir_sum += reader.getData(i)[k];
252
253 if (basal_dir_sum > _zero_tol)
254 mooseError("CrystalPlasticityStressUpdateBase Error: The specified HCP slip direction "
255 "Miller-Bravais indices in the basal plane (U, V, and T) do not sum to zero "
256 "within the user specified tolerance (try loosing zero_tol if using the default "
257 "value). Check the values supplied in the associated text file.");
258
259 if (j < miller_bravais_indices)
260 {
261 // Planes are directly copied over, per a_1 = x convention used here:
262 // Store the first two indices for the basal plane, (h and k), and drop
263 // the redundant third basal plane index (i)
264 if (j < 2)
265 temporary_slip_plane(j) = reader.getData(i)[j];
266 // Store the c-axis index as the third entry in the orthorombic index convention
267 else if (j == 3)
268 temporary_slip_plane(j - 1) = reader.getData(i)[j];
269 }
270 else
271 {
272 const auto direction_j = j - miller_bravais_indices;
273 // Store the first two indices for the slip direction in the basal plane,
274 //(U, V), and drop the redundant third basal plane index (T)
275 if (direction_j < 2)
276 temporary_slip_direction(direction_j) = reader.getData(i)[j];
277 // Store the c-axis index as the third entry in the orthorombic index convention
278 else if (direction_j == 3)
279 temporary_slip_direction(direction_j - 1) = reader.getData(i)[j];
280 }
281 }
282
283 // perform transformation calculation
284 _slip_direction[i] = transform_matrix * temporary_slip_direction;
285 _slip_plane_normal[i] = transform_matrix * temporary_slip_plane;
286 }
287}
288
289void
291{
293 {
294 _cross_slip_familes.resize(0);
295 return;
296 }
297
298 // If cross slip does occur, then set up the system of vectors for the families
300 // and set the first index of each inner vector
301 for (unsigned int i = 0; i < _number_cross_slip_directions; ++i)
302 _cross_slip_familes[i].resize(1);
303
304 // Sort the index of the slip system based vectors into separte families
305 unsigned int family_counter = 1;
306 _cross_slip_familes[0][0] = 0;
307
308 for (unsigned int i = 1; i < _number_slip_systems; ++i)
309 {
310 for (unsigned int j = 0; j < family_counter; ++j)
311 {
312 // check to see if the slip system direction i matches any of the existing slip directions
313 // First calculate the dot product
314 Real dot_product = 0.0;
315 for (const auto k : make_range(Moose::dim))
316 {
317 unsigned int check_family_index = _cross_slip_familes[j][0];
318 dot_product += std::abs(_slip_direction[check_family_index](k) - _slip_direction[i](k));
319 }
320 // Then check if the dot product is one, if yes, add to family and break
321 if (MooseUtils::absoluteFuzzyEqual(dot_product, 0.0))
322 {
323 _cross_slip_familes[j].push_back(i);
326 "Exceeded the number of cross slip planes allowed in a single cross slip family");
327
328 break; // exit the loop over the exisiting cross slip families and move to the next slip
329 // direction
330 }
331 // The slip system in question does not belong to an existing family
332 else if (j == (family_counter - 1) && !MooseUtils::absoluteFuzzyEqual(dot_product, 0.0))
333 {
334 if (family_counter > _number_cross_slip_directions)
335 mooseError("Exceeds the number of cross slip directions specified for this material");
336
337 _cross_slip_familes[family_counter][0] = i;
338 family_counter++;
339 break;
340 }
341 }
342 }
343
345 {
346 mooseWarning("Checking the slip system ordering now:");
347 for (unsigned int i = 0; i < _number_cross_slip_directions; ++i)
348 {
349 Moose::out << "In cross slip family " << i << std::endl;
350 for (unsigned int j = 0; j < _number_cross_slip_planes; ++j)
351 Moose::out << " is the slip direction number " << _cross_slip_familes[i][j] << std::endl;
352 }
353 }
354}
355
356unsigned int
358{
359 for (unsigned int i = 0; i < _number_cross_slip_directions; ++i)
360 for (unsigned int j = 0; j < _number_cross_slip_planes; ++j)
361 if (_cross_slip_familes[i][j] == index)
362 return i;
363
364 // Should never reach this statement
365 mooseError("The supplied slip system index is not among the slip system families sorted.");
366}
367
368void
374
375void
377 const unsigned int & number_slip_systems,
378 const std::vector<RealVectorValue> & plane_normal_vector,
379 const std::vector<RealVectorValue> & direction_vector,
380 std::vector<RankTwoTensor> & schmid_tensor,
381 const RankTwoTensor & crysrot)
382{
383 std::vector<RealVectorValue> local_direction_vector, local_plane_normal;
384 local_direction_vector.resize(number_slip_systems);
385 local_plane_normal.resize(number_slip_systems);
386
387 // Update slip direction and normal with crystal orientation
388 for (const auto i : make_range(_number_slip_systems))
389 {
390 local_direction_vector[i].zero();
391 local_plane_normal[i].zero();
392
393 for (const auto j : make_range(Moose::dim))
394 for (const auto k : make_range(Moose::dim))
395 {
396 local_direction_vector[i](j) =
397 local_direction_vector[i](j) + crysrot(j, k) * direction_vector[i](k);
398
399 local_plane_normal[i](j) =
400 local_plane_normal[i](j) + crysrot(j, k) * plane_normal_vector[i](k);
401 }
402
403 // Calculate Schmid tensor
404 for (const auto j : make_range(Moose::dim))
405 for (const auto k : make_range(Moose::dim))
406 {
407 schmid_tensor[i](j, k) = local_direction_vector[i](j) * local_plane_normal[i](k);
408 }
409 }
410}
411
412void
414 const RankTwoTensor & pk2,
415 const RankTwoTensor & inverse_eigenstrain_deformation_grad,
416 const unsigned int & num_eigenstrains)
417{
418 if (!num_eigenstrains)
419 {
420 for (const auto i : make_range(_number_slip_systems))
422
423 return;
424 }
425
426 RankTwoTensor eigenstrain_deformation_grad = inverse_eigenstrain_deformation_grad.inverse();
427 for (const auto i : make_range(_number_slip_systems))
428 {
429 // compute PK2_hat using deformation gradient
430 RankTwoTensor pk2_hat = eigenstrain_deformation_grad.det() *
431 eigenstrain_deformation_grad.transpose() * pk2 *
432 inverse_eigenstrain_deformation_grad.transpose();
433 _tau[_qp][i] = pk2_hat.doubleContraction(_flow_direction[_qp][i]);
434 }
435}
436
437void
439 RankFourTensor & dfpinvdpk2,
440 const RankTwoTensor & inverse_plastic_deformation_grad_old,
441 const RankTwoTensor & inverse_eigenstrain_deformation_grad_old,
442 const unsigned int & num_eigenstrains)
443{
444 std::vector<Real> dslip_dtau(_number_slip_systems, 0.0);
445 std::vector<RankTwoTensor> dtaudpk2(_number_slip_systems);
446 std::vector<RankTwoTensor> dfpinvdslip(_number_slip_systems);
447
449
450 for (const auto j : make_range(_number_slip_systems))
451 {
452 if (num_eigenstrains)
453 {
454 RankTwoTensor eigenstrain_deformation_grad_old =
455 inverse_eigenstrain_deformation_grad_old.inverse();
456 dtaudpk2[j] = eigenstrain_deformation_grad_old.det() * eigenstrain_deformation_grad_old *
457 _flow_direction[_qp][j] * inverse_eigenstrain_deformation_grad_old;
458 }
459 else
460 dtaudpk2[j] = _flow_direction[_qp][j];
461 dfpinvdslip[j] = -inverse_plastic_deformation_grad_old * _flow_direction[_qp][j];
462 dfpinvdpk2 += (dfpinvdslip[j] * dslip_dtau[j] * _substep_dt).outerProduct(dtaudpk2[j]);
463 }
464}
465
466void
468 RankTwoTensor & equivalent_slip_increment)
469{
470 // Sum up the slip increments to find the equivalent plastic strain due to slip
471 for (const auto i : make_range(_number_slip_systems))
472 equivalent_slip_increment += _flow_direction[_qp][i] * _slip_increment[_qp][i] * _substep_dt;
473}
474
475void
477{
478 _qp = qp;
479}
480
481void
483{
484 _substep_dt = substep_dt;
485}
486
487bool
489 const std::vector<Real> & current_var,
490 const std::vector<Real> & var_before_update,
491 const std::vector<Real> & previous_substep_var,
492 const Real & tolerance)
493{
494 // sometimes the state variable size may not equal to the number of slip systems
495 unsigned int sz = current_var.size();
496 mooseAssert(current_var.size() == sz, "Current variable size does not match");
497 mooseAssert(var_before_update.size() == sz, "Variable before update size does not match");
498 mooseAssert(previous_substep_var.size() == sz, "Previous substep variable size does not match");
499
500 bool is_converged = true;
501
502 Real diff_val = 0.0;
503 Real abs_prev_substep_val = 0.0;
504 for (const auto i : make_range(sz))
505 {
506 diff_val = std::abs(var_before_update[i] - current_var[i]);
507 abs_prev_substep_val = std::abs(previous_substep_var[i]);
508
509 // set to false if the state variable is not converged
510 if (abs_prev_substep_val < _zero_tol && diff_val > _zero_tol)
511 is_converged = false;
512 else if (abs_prev_substep_val > _zero_tol && diff_val > tolerance * abs_prev_substep_val)
513 is_converged = false;
514 }
515 return is_converged;
516}
void ErrorVector unsigned int
virtual void calculateEquivalentSlipIncrement(RankTwoTensor &)
const unsigned int _number_slip_systems
Maximum number of active slip systems for the crystalline material being modeled.
MaterialProperty< std::vector< Real > > & _slip_resistance
Slip system resistance.
virtual void calculateTotalPlasticDeformationGradientDerivative(RankFourTensor &dfpinvdpk2, const RankTwoTensor &inverse_plastic_deformation_grad_old, const RankTwoTensor &inverse_eigenstrain_deformation_grad_old, const unsigned int &num_eigenstrains)
Calculates the total value of $\frac{d\mathbf{F}^P^{-1}}{d\mathbf{PK2}}$ and is intended to be an ove...
CrystalPlasticityStressUpdateBase(const InputParameters &parameters)
const Real _number_cross_slip_directions
Parameters to characterize the cross slip behavior of the crystal.
void setQp(const unsigned int &qp)
Sets the value of the global variable _qp for inheriting classes.
unsigned int identifyCrossSlipFamily(const unsigned int index)
A helper method for inherting classes to identify to which cross slip family vector a particular slip...
const bool _print_convergence_message
Flag to print to console warning messages on stress, constitutive model convergence.
MaterialProperty< std::vector< Real > > & _slip_increment
Current slip increment material property.
void sortCrossSlipFamilies()
A helper method to sort the slip systems of a crystal into cross slip families based on common slip d...
Real _substep_dt
Substepping time step value used within the inheriting constitutive models.
void transformHexagonalMillerBravaisSlipSystems(const MooseUtils::DelimitedFileReader &reader)
A helper method to transform the Miller-Bravais 4-index notation for HCP crystals into a a 3-index Ca...
virtual void initQpStatefulProperties() override
initializes the stateful properties such as PK2 stress, resolved shear stress, plastic deformation gr...
enum CrystalPlasticityStressUpdateBase::CrystalLatticeType _crystal_lattice_type
Real _zero_tol
Residual tolerance when variable value is zero. Default 1e-12.
MaterialProperty< std::vector< RankTwoTensor > > & _flow_direction
void calculateShearStress(const RankTwoTensor &pk2, const RankTwoTensor &inverse_eigenstrain_deformation_grad, const unsigned int &num_eigenstrains)
Computes the shear stess for each slip system.
void setSubstepDt(const Real &substep_dt)
Sets the value of the _substep_dt for inheriting classes.
void calculateFlowDirection(const RankTwoTensor &crysrot)
Computes the Schmid tensor (m x n) for the original (reference) crystal lattice orientation for each ...
std::vector< std::vector< unsigned int > > _cross_slip_familes
Sorted slip system indices into cross slip family groups.
MaterialProperty< std::vector< Real > > & _tau
Resolved shear stress on each slip system.
bool _calculate_cross_slip
Flag to run the cross slip calculations if cross slip numbers are specified.
std::string _slip_sys_file_name
File should contain slip plane normal and direction.
virtual void calculateConstitutiveSlipDerivative(std::vector< Real > &)=0
This virtual method is called to find the derivative of the slip increment with respect to the applie...
void calculateSchmidTensor(const unsigned int &number_dislocation_systems, const std::vector< RealVectorValue > &plane_normal_vector, const std::vector< RealVectorValue > &direction_vector, std::vector< RankTwoTensor > &schmid_tensor, const RankTwoTensor &crysrot)
A helper method to rotate the a direction and plane normal system set into the local crystal llatice ...
std::vector< RealVectorValue > _slip_direction
Slip system direction and normal and associated Schmid tensors.
virtual bool isConstitutiveStateVariableConverged(const std::vector< Real > &current_var, const std::vector< Real > &var_before_update, const std::vector< Real > &previous_substep_var, const Real &tolerance)
Check if a typical state variable, e.g.
virtual void getSlipSystems()
A helper method to read in plane normal and direction vectors from a file and to normalize the vector...
void suppressParameter(const std::string &name)
bool isParamSetByUser(const std::string &name) const
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)
T & set(const std::string &name, bool quiet_mode=false)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
unsigned int _qp
virtual unsigned int size() const override final
virtual void resize(const std::size_t size) override final
static InputParameters validParams()
const InputParameters & parameters() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
void mooseWarning(Args &&... args) const
const std::vector< std::vector< T > > & getData() const
void setFormatFlag(FormatFlag value)
T doubleContraction(const RankTwoTensorTempl< T > &a) const
RankTwoTensorTempl< T > inverse() const
RankTwoTensorTempl< T > transpose() const
static constexpr std::size_t dim
static constexpr Real TOLERANCE