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 1738 : CrystalPlasticityStressUpdateBase::validParams()
19 : {
20 1738 : InputParameters params = Material::validParams();
21 3476 : params.addParam<std::string>(
22 : "base_name",
23 : "Optional parameter that allows the user to define multiple crystal plasticity mechanisms");
24 1738 : 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 1738 : params.set<bool>("compute") = false;
31 1738 : params.suppressParameter<bool>("compute");
32 :
33 3476 : params.addParam<MooseEnum>(
34 : "crystal_lattice_type",
35 5214 : MooseEnum("BCC FCC HCP", "FCC"),
36 : "Crystal lattice type or representative unit cell, i.e., BCC, FCC, HCP, etc.");
37 :
38 5214 : params.addRangeCheckedParam<std::vector<Real>>(
39 : "unit_cell_dimension",
40 3476 : 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 3476 : params.addRequiredParam<unsigned int>(
48 : "number_slip_systems",
49 : "The total number of possible active slip systems for the crystalline material");
50 3476 : 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 3476 : params.addParam<Real>("number_cross_slip_directions",
55 3476 : 0,
56 : "Quanity of unique slip directions, used to determine cross slip familes");
57 3476 : params.addParam<Real>("number_cross_slip_planes",
58 3476 : 0,
59 : "Quanity of slip planes belonging to a single cross slip direction; used "
60 : "to determine cross slip families");
61 3476 : params.addParam<Real>(
62 : "slip_increment_tolerance",
63 3476 : 2e-2,
64 : "Maximum allowable slip in an increment for each individual constitutive model");
65 3476 : params.addParam<Real>(
66 3476 : "stol", 1e-2, "Constitutive internal state variable relative change tolerance");
67 3476 : params.addParam<Real>("resistance_tol",
68 3476 : 1.0e-2,
69 : "Constitutive slip system resistance relative residual tolerance for each "
70 : "individual constitutive model");
71 3476 : params.addParam<Real>("zero_tol",
72 3476 : 1e-12,
73 : "Tolerance for residual check when variable value is zero for each "
74 : "individual constitutive model");
75 3476 : params.addParam<bool>(
76 : "print_state_variable_convergence_error_messages",
77 3476 : 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 1738 : return params;
81 0 : }
82 :
83 1306 : CrystalPlasticityStressUpdateBase::CrystalPlasticityStressUpdateBase(
84 1306 : const InputParameters & parameters)
85 : : Material(parameters),
86 1804 : _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
87 1306 : _crystal_lattice_type(
88 1306 : getParam<MooseEnum>("crystal_lattice_type").getEnum<CrystalLatticeType>()),
89 2612 : _unit_cell_dimension(getParam<std::vector<Real>>("unit_cell_dimension")),
90 2612 : _number_slip_systems(getParam<unsigned int>("number_slip_systems")),
91 2612 : _slip_sys_file_name(getParam<FileName>("slip_sys_file_name")),
92 2612 : _number_cross_slip_directions(getParam<Real>("number_cross_slip_directions")),
93 2612 : _number_cross_slip_planes(getParam<Real>("number_cross_slip_planes")),
94 :
95 2612 : _rel_state_var_tol(getParam<Real>("stol")),
96 2612 : _slip_incr_tol(getParam<Real>("slip_increment_tolerance")),
97 2612 : _resistance_tol(getParam<Real>("resistance_tol")),
98 2612 : _zero_tol(getParam<Real>("zero_tol")),
99 :
100 1306 : _slip_resistance(declareProperty<std::vector<Real>>(_base_name + "slip_resistance")),
101 2612 : _slip_resistance_old(getMaterialPropertyOld<std::vector<Real>>(_base_name + "slip_resistance")),
102 1306 : _slip_increment(declareProperty<std::vector<Real>>(_base_name + "slip_increment")),
103 :
104 1306 : _slip_direction(_number_slip_systems),
105 1306 : _slip_plane_normal(_number_slip_systems),
106 1306 : _flow_direction(declareProperty<std::vector<RankTwoTensor>>(_base_name + "flow_direction")),
107 1306 : _tau(declareProperty<std::vector<Real>>(_base_name + "applied_shear_stress")),
108 3918 : _print_convergence_message(getParam<bool>("print_state_variable_convergence_error_messages"))
109 : {
110 1306 : getSlipSystems();
111 1298 : sortCrossSlipFamilies();
112 :
113 2596 : if (parameters.isParamSetByUser("number_cross_slip_directions"))
114 0 : _calculate_cross_slip = true;
115 : else
116 1298 : _calculate_cross_slip = false;
117 1298 : }
118 :
119 : void
120 62368 : CrystalPlasticityStressUpdateBase::initQpStatefulProperties()
121 : {
122 62368 : setMaterialVectorSize();
123 62368 : }
124 :
125 : void
126 2604065 : CrystalPlasticityStressUpdateBase::setMaterialVectorSize()
127 : {
128 2604065 : _tau[_qp].resize(_number_slip_systems);
129 2604065 : _flow_direction[_qp].resize(_number_slip_systems);
130 33549456 : for (const auto i : make_range(_number_slip_systems))
131 : {
132 30945391 : _flow_direction[_qp][i].zero();
133 30945391 : _tau[_qp][i] = 0.0;
134 : }
135 :
136 2604065 : _slip_resistance[_qp].resize(_number_slip_systems);
137 2604065 : _slip_increment[_qp].resize(_number_slip_systems);
138 2604065 : }
139 :
140 : void
141 1306 : CrystalPlasticityStressUpdateBase::getSlipSystems()
142 : {
143 : bool orthonormal_error = false;
144 :
145 : // read in the slip system data from auxiliary text file
146 1306 : MooseUtils::DelimitedFileReader _reader(_slip_sys_file_name);
147 : _reader.setFormatFlag(MooseUtils::DelimitedFileReader::FormatFlag::ROWS);
148 1306 : _reader.read();
149 :
150 : // check the size of the input
151 1306 : 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 16442 : for (const auto i : make_range(_number_slip_systems))
157 : {
158 : // initialize to zero
159 15136 : _slip_direction[i].zero();
160 : _slip_plane_normal[i].zero();
161 : }
162 :
163 1306 : if (_crystal_lattice_type == CrystalLatticeType::HCP)
164 364 : transformHexagonalMillerBravaisSlipSystems(_reader);
165 942 : else if (_crystal_lattice_type == CrystalLatticeType::BCC ||
166 : _crystal_lattice_type == CrystalLatticeType::FCC)
167 : {
168 11910 : 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 76776 : for (const auto j : index_range(_reader.getData(i)))
172 : {
173 65808 : if (j < LIBMESH_DIM)
174 32904 : _slip_plane_normal[i](j) = _reader.getData(i)[j] / _unit_cell_dimension[j];
175 : else
176 32904 : _slip_direction[i](j - LIBMESH_DIM) =
177 32904 : _reader.getData(i)[j] * _unit_cell_dimension[j - LIBMESH_DIM];
178 : }
179 : }
180 : }
181 :
182 16388 : for (const auto i : make_range(_number_slip_systems))
183 : {
184 : // normalize
185 15090 : _slip_plane_normal[i] /= _slip_plane_normal[i].norm();
186 15090 : _slip_direction[i] /= _slip_direction[i].norm();
187 :
188 15090 : if (_crystal_lattice_type != CrystalLatticeType::HCP)
189 : {
190 : const auto magnitude = _slip_plane_normal[i] * _slip_direction[i];
191 10968 : if (std::abs(magnitude) > libMesh::TOLERANCE)
192 : {
193 : orthonormal_error = true;
194 : break;
195 : }
196 : }
197 : }
198 :
199 1298 : 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 1298 : }
204 :
205 : void
206 364 : 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 364 : if (_unit_cell_dimension[0] != _unit_cell_dimension[1] ||
215 364 : _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 362 : 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 360 : RankTwoTensor transform_matrix;
227 : transform_matrix.zero();
228 360 : transform_matrix(0, 0) = 1.0 / _unit_cell_dimension[0];
229 360 : transform_matrix(1, 0) = 1.0 / (_unit_cell_dimension[0] * std::sqrt(3.0));
230 360 : transform_matrix(1, 1) = 2.0 / (_unit_cell_dimension[0] * std::sqrt(3.0));
231 360 : transform_matrix(2, 2) = 1.0 / (_unit_cell_dimension[2]);
232 :
233 4482 : for (const auto i : make_range(_number_slip_systems))
234 : {
235 : // read in raw data from file and store in the temporary vectors
236 37102 : 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 131920 : for (const auto k : make_range(LIBMESH_DIM))
241 98940 : basal_pl_sum += reader.getData(i)[k];
242 :
243 32980 : 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 131912 : for (const auto k : make_range(miller_bravais_indices, miller_bravais_indices + LIBMESH_DIM))
251 98934 : basal_dir_sum += reader.getData(i)[k];
252 :
253 32978 : 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 32976 : 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 16488 : if (j < 2)
265 8244 : temporary_slip_plane(j) = reader.getData(i)[j];
266 : // Store the c-axis index as the third entry in the orthorombic index convention
267 8244 : else if (j == 3)
268 4122 : temporary_slip_plane(j - 1) = reader.getData(i)[j];
269 : }
270 : else
271 : {
272 16488 : 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 16488 : if (direction_j < 2)
276 8244 : 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 8244 : else if (direction_j == 3)
279 4122 : temporary_slip_direction(direction_j - 1) = reader.getData(i)[j];
280 : }
281 : }
282 :
283 : // perform transformation calculation
284 4122 : _slip_direction[i] = transform_matrix * temporary_slip_direction;
285 4122 : _slip_plane_normal[i] = transform_matrix * temporary_slip_plane;
286 : }
287 356 : }
288 :
289 : void
290 1298 : CrystalPlasticityStressUpdateBase::sortCrossSlipFamilies()
291 : {
292 1298 : if (_number_cross_slip_directions == 0)
293 : {
294 1298 : _cross_slip_familes.resize(0);
295 1298 : 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 2538497 : CrystalPlasticityStressUpdateBase::calculateFlowDirection(const RankTwoTensor & crysrot)
370 : {
371 2538497 : calculateSchmidTensor(
372 2538497 : _number_slip_systems, _slip_plane_normal, _slip_direction, _flow_direction[_qp], crysrot);
373 2538497 : }
374 :
375 : void
376 2538497 : 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 2538497 : local_direction_vector.resize(number_slip_systems);
385 2538497 : local_plane_normal.resize(number_slip_systems);
386 :
387 : // Update slip direction and normal with crystal orientation
388 32711760 : for (const auto i : make_range(_number_slip_systems))
389 : {
390 30173263 : local_direction_vector[i].zero();
391 : local_plane_normal[i].zero();
392 :
393 120693052 : for (const auto j : make_range(LIBMESH_DIM))
394 362079156 : for (const auto k : make_range(LIBMESH_DIM))
395 : {
396 271559367 : local_direction_vector[i](j) =
397 271559367 : local_direction_vector[i](j) + crysrot(j, k) * direction_vector[i](k);
398 :
399 271559367 : local_plane_normal[i](j) =
400 271559367 : local_plane_normal[i](j) + crysrot(j, k) * plane_normal_vector[i](k);
401 : }
402 :
403 : // Calculate Schmid tensor
404 120693052 : for (const auto j : make_range(LIBMESH_DIM))
405 362079156 : for (const auto k : make_range(LIBMESH_DIM))
406 : {
407 271559367 : schmid_tensor[i](j, k) = local_direction_vector[i](j) * local_plane_normal[i](k);
408 : }
409 : }
410 2538497 : }
411 :
412 : void
413 25248283 : CrystalPlasticityStressUpdateBase::calculateShearStress(
414 : const RankTwoTensor & pk2,
415 : const RankTwoTensor & inverse_eigenstrain_deformation_grad,
416 : const unsigned int & num_eigenstrains)
417 : {
418 25248283 : if (!num_eigenstrains)
419 : {
420 216154536 : for (const auto i : make_range(_number_slip_systems))
421 196922128 : _tau[_qp][i] = pk2.doubleContraction(_flow_direction[_qp][i]);
422 :
423 19232408 : return;
424 : }
425 :
426 6015875 : RankTwoTensor eigenstrain_deformation_grad = inverse_eigenstrain_deformation_grad.inverse();
427 87429479 : for (const auto i : make_range(_number_slip_systems))
428 : {
429 : // compute PK2_hat using deformation gradient
430 81413604 : RankTwoTensor pk2_hat = eigenstrain_deformation_grad.det() *
431 81413604 : eigenstrain_deformation_grad.transpose() * pk2 *
432 81413604 : inverse_eigenstrain_deformation_grad.transpose();
433 81413604 : _tau[_qp][i] = pk2_hat.doubleContraction(_flow_direction[_qp][i]);
434 : }
435 : }
436 :
437 : void
438 24981724 : 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 24981724 : std::vector<Real> dslip_dtau(_number_slip_systems, 0.0);
445 24981724 : std::vector<RankTwoTensor> dtaudpk2(_number_slip_systems);
446 24981724 : std::vector<RankTwoTensor> dfpinvdslip(_number_slip_systems);
447 :
448 24981724 : calculateConstitutiveSlipDerivative(dslip_dtau);
449 :
450 299619308 : for (const auto j : make_range(_number_slip_systems))
451 : {
452 274637584 : if (num_eigenstrains)
453 : {
454 : RankTwoTensor eigenstrain_deformation_grad_old =
455 77761044 : inverse_eigenstrain_deformation_grad_old.inverse();
456 77761044 : dtaudpk2[j] = eigenstrain_deformation_grad_old.det() * eigenstrain_deformation_grad_old *
457 77761044 : _flow_direction[_qp][j] * inverse_eigenstrain_deformation_grad_old;
458 : }
459 : else
460 196876540 : dtaudpk2[j] = _flow_direction[_qp][j];
461 274637584 : dfpinvdslip[j] = -inverse_plastic_deformation_grad_old * _flow_direction[_qp][j];
462 274637584 : dfpinvdpk2 += (dfpinvdslip[j] * dslip_dtau[j] * _substep_dt).outerProduct(dtaudpk2[j]);
463 : }
464 24981724 : }
465 :
466 : void
467 22070699 : CrystalPlasticityStressUpdateBase::calculateEquivalentSlipIncrement(
468 : RankTwoTensor & equivalent_slip_increment)
469 : {
470 : // Sum up the slip increments to find the equivalent plastic strain due to slip
471 258838773 : for (const auto i : make_range(_number_slip_systems))
472 236768074 : equivalent_slip_increment += _flow_direction[_qp][i] * _slip_increment[_qp][i] * _substep_dt;
473 22070699 : }
474 :
475 : void
476 2572881 : CrystalPlasticityStressUpdateBase::setQp(const unsigned int & qp)
477 : {
478 2572881 : _qp = qp;
479 2572881 : }
480 :
481 : void
482 2749728 : CrystalPlasticityStressUpdateBase::setSubstepDt(const Real & substep_dt)
483 : {
484 2749728 : _substep_dt = substep_dt;
485 2749728 : }
486 :
487 : bool
488 6023418 : 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 6023418 : 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 78856276 : for (const auto i : make_range(sz))
505 : {
506 72832858 : diff_val = std::abs(var_before_update[i] - current_var[i]);
507 72832858 : abs_prev_substep_val = std::abs(previous_substep_var[i]);
508 :
509 : // set to false if the state variable is not converged
510 72832858 : if (abs_prev_substep_val < _zero_tol && diff_val > _zero_tol)
511 : is_converged = false;
512 72629888 : else if (abs_prev_substep_val > _zero_tol && diff_val > tolerance * abs_prev_substep_val)
513 : is_converged = false;
514 : }
515 6023418 : return is_converged;
516 : }
|