Line data Source code
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 "CrystalPlasticityStressUpdateBase.h"
11 :
12 : #include "libmesh/utility.h"
13 : #include "libmesh/int_range.h"
14 : #include "Conversion.h"
15 : #include "MooseException.h"
16 :
17 : InputParameters
18 1522 : CrystalPlasticityStressUpdateBase::validParams()
19 : {
20 1522 : InputParameters params = Material::validParams();
21 3044 : params.addParam<std::string>(
22 : "base_name",
23 : "Optional parameter that allows the user to define multiple crystal plasticity mechanisms");
24 1522 : params.addClassDescription(
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 1522 : params.set<bool>("compute") = false;
31 1522 : params.suppressParameter<bool>("compute");
32 :
33 3044 : params.addParam<MooseEnum>(
34 : "crystal_lattice_type",
35 4566 : MooseEnum("BCC FCC HCP", "FCC"),
36 : "Crystal lattice type or representative unit cell, i.e., BCC, FCC, HCP, etc.");
37 :
38 6088 : params.addRangeCheckedParam<std::vector<Real>>(
39 : "unit_cell_dimension",
40 3044 : 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 3044 : params.addRequiredParam<unsigned int>(
48 : "number_slip_systems",
49 : "The total number of possible active slip systems for the crystalline material");
50 3044 : 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 3044 : params.addParam<Real>("number_cross_slip_directions",
55 3044 : 0,
56 : "Quanity of unique slip directions, used to determine cross slip familes");
57 3044 : params.addParam<Real>("number_cross_slip_planes",
58 3044 : 0,
59 : "Quanity of slip planes belonging to a single cross slip direction; used "
60 : "to determine cross slip families");
61 3044 : params.addParam<Real>(
62 : "slip_increment_tolerance",
63 3044 : 2e-2,
64 : "Maximum allowable slip in an increment for each individual constitutive model");
65 3044 : params.addParam<Real>(
66 3044 : "stol", 1e-2, "Constitutive internal state variable relative change tolerance");
67 3044 : params.addParam<Real>("resistance_tol",
68 3044 : 1.0e-2,
69 : "Constitutive slip system resistance relative residual tolerance for each "
70 : "individual constitutive model");
71 3044 : params.addParam<Real>("zero_tol",
72 3044 : 1e-12,
73 : "Tolerance for residual check when variable value is zero for each "
74 : "individual constitutive model");
75 3044 : params.addParam<bool>(
76 : "print_state_variable_convergence_error_messages",
77 3044 : 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 1522 : return params;
81 0 : }
82 :
83 1144 : CrystalPlasticityStressUpdateBase::CrystalPlasticityStressUpdateBase(
84 1144 : const InputParameters & parameters)
85 : : Material(parameters),
86 1576 : _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
87 1144 : _crystal_lattice_type(
88 1144 : getParam<MooseEnum>("crystal_lattice_type").getEnum<CrystalLatticeType>()),
89 2288 : _unit_cell_dimension(getParam<std::vector<Real>>("unit_cell_dimension")),
90 2288 : _number_slip_systems(getParam<unsigned int>("number_slip_systems")),
91 2288 : _slip_sys_file_name(getParam<FileName>("slip_sys_file_name")),
92 2288 : _number_cross_slip_directions(getParam<Real>("number_cross_slip_directions")),
93 2288 : _number_cross_slip_planes(getParam<Real>("number_cross_slip_planes")),
94 :
95 2288 : _rel_state_var_tol(getParam<Real>("stol")),
96 2288 : _slip_incr_tol(getParam<Real>("slip_increment_tolerance")),
97 2288 : _resistance_tol(getParam<Real>("resistance_tol")),
98 2288 : _zero_tol(getParam<Real>("zero_tol")),
99 :
100 1144 : _slip_resistance(declareProperty<std::vector<Real>>(_base_name + "slip_resistance")),
101 2288 : _slip_resistance_old(getMaterialPropertyOld<std::vector<Real>>(_base_name + "slip_resistance")),
102 1144 : _slip_increment(declareProperty<std::vector<Real>>(_base_name + "slip_increment")),
103 :
104 1144 : _slip_direction(_number_slip_systems),
105 1144 : _slip_plane_normal(_number_slip_systems),
106 1144 : _flow_direction(declareProperty<std::vector<RankTwoTensor>>(_base_name + "flow_direction")),
107 1144 : _tau(declareProperty<std::vector<Real>>(_base_name + "applied_shear_stress")),
108 3432 : _print_convergence_message(getParam<bool>("print_state_variable_convergence_error_messages"))
109 : {
110 1144 : getSlipSystems();
111 1136 : sortCrossSlipFamilies();
112 :
113 2272 : if (parameters.isParamSetByUser("number_cross_slip_directions"))
114 0 : _calculate_cross_slip = true;
115 : else
116 1136 : _calculate_cross_slip = false;
117 1136 : }
118 :
119 : void
120 50816 : CrystalPlasticityStressUpdateBase::initQpStatefulProperties()
121 : {
122 50816 : setMaterialVectorSize();
123 50816 : }
124 :
125 : void
126 2081270 : CrystalPlasticityStressUpdateBase::setMaterialVectorSize()
127 : {
128 2081270 : _tau[_qp].resize(_number_slip_systems);
129 2081270 : _flow_direction[_qp].resize(_number_slip_systems);
130 26799306 : for (const auto i : make_range(_number_slip_systems))
131 : {
132 24718036 : _flow_direction[_qp][i].zero();
133 24718036 : _tau[_qp][i] = 0.0;
134 : }
135 :
136 2081270 : _slip_resistance[_qp].resize(_number_slip_systems);
137 2081270 : _slip_increment[_qp].resize(_number_slip_systems);
138 2081270 : }
139 :
140 : void
141 1144 : CrystalPlasticityStressUpdateBase::getSlipSystems()
142 : {
143 : bool orthonormal_error = false;
144 :
145 : // read in the slip system data from auxiliary text file
146 1144 : MooseUtils::DelimitedFileReader _reader(_slip_sys_file_name);
147 : _reader.setFormatFlag(MooseUtils::DelimitedFileReader::FormatFlag::ROWS);
148 1144 : _reader.read();
149 :
150 : // check the size of the input
151 1144 : if (_reader.getData().size() != _number_slip_systems)
152 0 : paramError(
153 : "number_slip_systems",
154 : "The number of rows in the slip system file should match the number of slip system.");
155 :
156 14396 : for (const auto i : make_range(_number_slip_systems))
157 : {
158 : // initialize to zero
159 13252 : _slip_direction[i].zero();
160 : _slip_plane_normal[i].zero();
161 : }
162 :
163 1144 : if (_crystal_lattice_type == CrystalLatticeType::HCP)
164 328 : transformHexagonalMillerBravaisSlipSystems(_reader);
165 816 : else if (_crystal_lattice_type == CrystalLatticeType::BCC ||
166 : _crystal_lattice_type == CrystalLatticeType::FCC)
167 : {
168 10320 : 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 66528 : for (const auto j : index_range(_reader.getData(i)))
172 : {
173 57024 : if (j < LIBMESH_DIM)
174 28512 : _slip_plane_normal[i](j) = _reader.getData(i)[j] / _unit_cell_dimension[j];
175 : else
176 28512 : _slip_direction[i](j - LIBMESH_DIM) =
177 28512 : _reader.getData(i)[j] * _unit_cell_dimension[j - LIBMESH_DIM];
178 : }
179 : }
180 : }
181 :
182 14342 : for (const auto i : make_range(_number_slip_systems))
183 : {
184 : // normalize
185 13206 : _slip_plane_normal[i] /= _slip_plane_normal[i].norm();
186 13206 : _slip_direction[i] /= _slip_direction[i].norm();
187 :
188 13206 : if (_crystal_lattice_type != CrystalLatticeType::HCP)
189 : {
190 : const auto magnitude = _slip_plane_normal[i] * _slip_direction[i];
191 9504 : if (std::abs(magnitude) > libMesh::TOLERANCE)
192 : {
193 : orthonormal_error = true;
194 : break;
195 : }
196 : }
197 : }
198 :
199 1136 : if (orthonormal_error)
200 0 : 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 1136 : }
204 :
205 : void
206 328 : CrystalPlasticityStressUpdateBase::transformHexagonalMillerBravaisSlipSystems(
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 :
214 328 : if (_unit_cell_dimension[0] != _unit_cell_dimension[1] ||
215 328 : _unit_cell_dimension[0] == _unit_cell_dimension[2])
216 2 : mooseError("CrystalPlasticityStressUpdateBase Error: The specified unit cell dimensions are "
217 : "not consistent with expectations for "
218 : "HCP crystal hexagonal lattices.");
219 326 : else if (reader.getData(0).size() != miller_bravais_indices * 2)
220 2 : 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 324 : RankTwoTensor transform_matrix;
227 : transform_matrix.zero();
228 324 : transform_matrix(0, 0) = 1.0 / _unit_cell_dimension[0];
229 324 : transform_matrix(1, 0) = 1.0 / (_unit_cell_dimension[0] * std::sqrt(3.0));
230 324 : transform_matrix(1, 1) = 2.0 / (_unit_cell_dimension[0] * std::sqrt(3.0));
231 324 : transform_matrix(2, 2) = 1.0 / (_unit_cell_dimension[2]);
232 :
233 4026 : for (const auto i : make_range(_number_slip_systems))
234 : {
235 : // read in raw data from file and store in the temporary vectors
236 33322 : 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 118480 : for (const auto k : make_range(LIBMESH_DIM))
241 88860 : basal_pl_sum += reader.getData(i)[k];
242 :
243 29620 : if (basal_pl_sum > _zero_tol)
244 2 : mooseError(
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 118472 : for (const auto k : make_range(miller_bravais_indices, miller_bravais_indices + LIBMESH_DIM))
251 88854 : basal_dir_sum += reader.getData(i)[k];
252 :
253 29618 : if (basal_dir_sum > _zero_tol)
254 2 : 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 29616 : 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 14808 : if (j < 2)
265 7404 : temporary_slip_plane(j) = reader.getData(i)[j];
266 : // Store the c-axis index as the third entry in the orthorombic index convention
267 7404 : else if (j == 3)
268 3702 : temporary_slip_plane(j - 1) = reader.getData(i)[j];
269 : }
270 : else
271 : {
272 14808 : 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 14808 : if (direction_j < 2)
276 7404 : 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 7404 : else if (direction_j == 3)
279 3702 : temporary_slip_direction(direction_j - 1) = reader.getData(i)[j];
280 : }
281 : }
282 :
283 : // perform transformation calculation
284 3702 : _slip_direction[i] = transform_matrix * temporary_slip_direction;
285 3702 : _slip_plane_normal[i] = transform_matrix * temporary_slip_plane;
286 : }
287 320 : }
288 :
289 : void
290 1136 : CrystalPlasticityStressUpdateBase::sortCrossSlipFamilies()
291 : {
292 1136 : if (_number_cross_slip_directions == 0)
293 : {
294 1136 : _cross_slip_familes.resize(0);
295 1136 : return;
296 : }
297 :
298 : // If cross slip does occur, then set up the system of vectors for the families
299 0 : _cross_slip_familes.resize(_number_cross_slip_directions);
300 : // and set the first index of each inner vector
301 0 : for (unsigned int i = 0; i < _number_cross_slip_directions; ++i)
302 0 : _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 0 : _cross_slip_familes[0][0] = 0;
307 :
308 0 : for (unsigned int i = 1; i < _number_slip_systems; ++i)
309 : {
310 0 : 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 0 : for (const auto k : make_range(Moose::dim))
316 : {
317 0 : unsigned int check_family_index = _cross_slip_familes[j][0];
318 0 : 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 0 : if (MooseUtils::absoluteFuzzyEqual(dot_product, 0.0))
322 : {
323 0 : _cross_slip_familes[j].push_back(i);
324 0 : if (_cross_slip_familes[j].size() > _number_cross_slip_planes)
325 0 : mooseError(
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 0 : else if (j == (family_counter - 1) && !MooseUtils::absoluteFuzzyEqual(dot_product, 0.0))
333 : {
334 0 : if (family_counter > _number_cross_slip_directions)
335 0 : mooseError("Exceeds the number of cross slip directions specified for this material");
336 :
337 0 : _cross_slip_familes[family_counter][0] = i;
338 0 : family_counter++;
339 0 : break;
340 : }
341 : }
342 : }
343 :
344 0 : if (_print_convergence_message)
345 : {
346 0 : mooseWarning("Checking the slip system ordering now:");
347 0 : for (unsigned int i = 0; i < _number_cross_slip_directions; ++i)
348 : {
349 : Moose::out << "In cross slip family " << i << std::endl;
350 0 : for (unsigned int j = 0; j < _number_cross_slip_planes; ++j)
351 0 : Moose::out << " is the slip direction number " << _cross_slip_familes[i][j] << std::endl;
352 : }
353 : }
354 : }
355 :
356 : unsigned int
357 0 : CrystalPlasticityStressUpdateBase::identifyCrossSlipFamily(const unsigned int index)
358 : {
359 0 : for (unsigned int i = 0; i < _number_cross_slip_directions; ++i)
360 0 : for (unsigned int j = 0; j < _number_cross_slip_planes; ++j)
361 0 : if (_cross_slip_familes[i][j] == index)
362 0 : return i;
363 :
364 : // Should never reach this statement
365 0 : mooseError("The supplied slip system index is not among the slip system families sorted.");
366 : }
367 :
368 : void
369 2027894 : CrystalPlasticityStressUpdateBase::calculateFlowDirection(const RankTwoTensor & crysrot)
370 : {
371 2027894 : calculateSchmidTensor(
372 2027894 : _number_slip_systems, _slip_plane_normal, _slip_direction, _flow_direction[_qp], crysrot);
373 2027894 : }
374 :
375 : void
376 2027894 : CrystalPlasticityStressUpdateBase::calculateSchmidTensor(
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 2027894 : local_direction_vector.resize(number_slip_systems);
385 2027894 : local_plane_normal.resize(number_slip_systems);
386 :
387 : // Update slip direction and normal with crystal orientation
388 26116554 : for (const auto i : make_range(_number_slip_systems))
389 : {
390 24088660 : local_direction_vector[i].zero();
391 : local_plane_normal[i].zero();
392 :
393 96354640 : for (const auto j : make_range(LIBMESH_DIM))
394 289063920 : for (const auto k : make_range(LIBMESH_DIM))
395 : {
396 216797940 : local_direction_vector[i](j) =
397 216797940 : local_direction_vector[i](j) + crysrot(j, k) * direction_vector[i](k);
398 :
399 216797940 : local_plane_normal[i](j) =
400 216797940 : local_plane_normal[i](j) + crysrot(j, k) * plane_normal_vector[i](k);
401 : }
402 :
403 : // Calculate Schmid tensor
404 96354640 : for (const auto j : make_range(LIBMESH_DIM))
405 289063920 : for (const auto k : make_range(LIBMESH_DIM))
406 : {
407 216797940 : schmid_tensor[i](j, k) = local_direction_vector[i](j) * local_plane_normal[i](k);
408 : }
409 : }
410 2027894 : }
411 :
412 : void
413 20524900 : CrystalPlasticityStressUpdateBase::calculateShearStress(
414 : const RankTwoTensor & pk2,
415 : const RankTwoTensor & inverse_eigenstrain_deformation_grad,
416 : const unsigned int & num_eigenstrains)
417 : {
418 20524900 : if (!num_eigenstrains)
419 : {
420 175258402 : for (const auto i : make_range(_number_slip_systems))
421 159536730 : _tau[_qp][i] = pk2.doubleContraction(_flow_direction[_qp][i]);
422 :
423 15721672 : return;
424 : }
425 :
426 4803228 : RankTwoTensor eigenstrain_deformation_grad = inverse_eigenstrain_deformation_grad.inverse();
427 69696492 : for (const auto i : make_range(_number_slip_systems))
428 : {
429 : // compute PK2_hat using deformation gradient
430 64893264 : RankTwoTensor pk2_hat = eigenstrain_deformation_grad.det() *
431 64893264 : eigenstrain_deformation_grad.transpose() * pk2 *
432 64893264 : inverse_eigenstrain_deformation_grad.transpose();
433 64893264 : _tau[_qp][i] = pk2_hat.doubleContraction(_flow_direction[_qp][i]);
434 : }
435 : }
436 :
437 : void
438 20314262 : CrystalPlasticityStressUpdateBase::calculateTotalPlasticDeformationGradientDerivative(
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 20314262 : std::vector<Real> dslip_dtau(_number_slip_systems, 0.0);
445 20314262 : std::vector<RankTwoTensor> dtaudpk2(_number_slip_systems);
446 20314262 : std::vector<RankTwoTensor> dfpinvdslip(_number_slip_systems);
447 :
448 20314262 : calculateConstitutiveSlipDerivative(dslip_dtau);
449 :
450 241824878 : for (const auto j : make_range(_number_slip_systems))
451 : {
452 221510616 : if (num_eigenstrains)
453 : {
454 : RankTwoTensor eigenstrain_deformation_grad_old =
455 62010384 : inverse_eigenstrain_deformation_grad_old.inverse();
456 62010384 : dtaudpk2[j] = eigenstrain_deformation_grad_old.det() * eigenstrain_deformation_grad_old *
457 62010384 : _flow_direction[_qp][j] * inverse_eigenstrain_deformation_grad_old;
458 : }
459 : else
460 159500232 : dtaudpk2[j] = _flow_direction[_qp][j];
461 221510616 : dfpinvdslip[j] = -inverse_plastic_deformation_grad_old * _flow_direction[_qp][j];
462 221510616 : dfpinvdpk2 += (dfpinvdslip[j] * dslip_dtau[j] * _substep_dt).outerProduct(dtaudpk2[j]);
463 : }
464 20314262 : }
465 :
466 : void
467 17889094 : CrystalPlasticityStressUpdateBase::calculateEquivalentSlipIncrement(
468 : RankTwoTensor & equivalent_slip_increment)
469 : {
470 : // Sum up the slip increments to find the equivalent plastic strain due to slip
471 207556858 : for (const auto i : make_range(_number_slip_systems))
472 189667764 : equivalent_slip_increment += _flow_direction[_qp][i] * _slip_increment[_qp][i] * _substep_dt;
473 17889094 : }
474 :
475 : void
476 2055862 : CrystalPlasticityStressUpdateBase::setQp(const unsigned int & qp)
477 : {
478 2055862 : _qp = qp;
479 2055862 : }
480 :
481 : void
482 2194146 : CrystalPlasticityStressUpdateBase::setSubstepDt(const Real & substep_dt)
483 : {
484 2194146 : _substep_dt = substep_dt;
485 2194146 : }
486 :
487 : bool
488 4802878 : CrystalPlasticityStressUpdateBase::isConstitutiveStateVariableConverged(
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 4802878 : 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 62774398 : for (const auto i : make_range(sz))
505 : {
506 57971520 : diff_val = std::abs(var_before_update[i] - current_var[i]);
507 57971520 : abs_prev_substep_val = std::abs(previous_substep_var[i]);
508 :
509 : // set to false if the state variable is not converged
510 57971520 : if (abs_prev_substep_val < _zero_tol && diff_val > _zero_tol)
511 : is_converged = false;
512 57820060 : else if (abs_prev_substep_val > _zero_tol && diff_val > tolerance * abs_prev_substep_val)
513 : is_converged = false;
514 : }
515 4802878 : return is_converged;
516 : }
|