13 #include "MathUtils.h"
17 template <ComputeStage compute_stage>
22 params.addClassDescription(
23 "Calculates the effective creep strain based on the rates predicted by a material "
24 "specific Los Alamos Reduced Order Model derived from a Visco-Plastic Self Consistent "
27 params.addRequiredCoupledVar(
"temperature",
"The coupled temperature (K)");
28 params.addCoupledVar(
"environmental_factor", 0.0,
"Optional coupled environmental factor");
29 params.addRangeCheckedParam<Real>(
"input_window_limit",
31 "input_window_limit>0.0",
32 "Multiplier for the input minium/maximum input window");
33 MooseEnum window_failure(
"ERROR WARN IGNORE",
"WARN");
34 params.addParam<MooseEnum>(
"input_window_failure_action",
36 "What to do if ROM input is outside the window of applicability.");
37 params.addParam<
bool>(
"extrapolate_to_zero_stress",
39 "Flag to allow for extrapolation of input J2 stress to zero");
41 params.addRangeCheckedParam<Real>(
"initial_mobile_dislocation_density",
43 "initial_mobile_dislocation_density >= 0.0",
44 "Initial density of mobile (glissile) dislocations (1/m^2)");
45 params.addRangeCheckedParam<Real>(
46 "max_relative_mobile_dislocation_increment",
48 "max_relative_mobile_dislocation_increment > 0.0",
49 "Maximum increment of density of mobile (glissile) dislocations.");
50 params.addParam<FunctionName>(
51 "mobile_dislocation_density_forcing_function",
52 "Optional forcing function for immobile dislocation. If provided, the immobile dislocation "
53 "density will be reset to the function value at the beginning of the timestep. Used for "
54 "testing purposes only.");
55 params.addRangeCheckedParam<Real>(
"initial_immobile_dislocation_density",
57 "initial_immobile_dislocation_density >= 0.0",
58 "Immobile (locked) dislocation density initial value (1/m^2).");
59 params.addRangeCheckedParam<Real>(
60 "max_relative_immobile_dislocation_increment",
62 "max_relative_immobile_dislocation_increment > 0.0",
63 "Maximum increment of immobile (locked) dislocation density initial value (1/m^2).");
64 params.addParam<FunctionName>(
65 "immobile_dislocation_density_forcing_function",
66 "Optional forcing function for immobile dislocation. If provided, the immobile dislocation "
67 "density will be reset to the function value at the beginning of the timestep. Used for "
68 "testing purposes only.");
70 params.addParam<FunctionName>(
71 "old_creep_strain_forcing_function",
72 "Optional forcing function for the creep strain from the previous timestep. If provided, "
73 "the old creep strain will be reset to the function value at the beginning of the "
74 "timestep. Used for testing purposes only.");
76 params.addParam<
bool>(
"verbose",
false,
"Flag to add verbose output");
78 params.addParamNamesToGroup(
79 "mobile_dislocation_density_forcing_function immobile_dislocation_density_forcing_function "
80 "old_creep_strain_forcing_function",
85 template <ComputeStage compute_stage>
87 const InputParameters & parameters)
89 _temperature(adCoupledValue(
"temperature")),
90 _environmental(adCoupledValue(
"environmental_factor")),
91 _window(getParam<Real>(
"input_window_limit")),
93 parameters.get<MooseEnum>(
"input_window_failure_action").getEnum<
WindowFailure>()),
94 _extrapolate_stress(getParam<bool>(
"extrapolate_to_zero_stress")),
95 _verbose(getParam<bool>(
"verbose")),
96 _mobile_dislocations(declareADProperty<Real>(_base_name +
"mobile_dislocations")),
97 _mobile_dislocations_old(getMaterialPropertyOld<Real>(_base_name +
"mobile_dislocations")),
98 _initial_mobile_dislocations(getParam<Real>(
"initial_mobile_dislocation_density")),
99 _max_mobile_increment(getParam<Real>(
"max_relative_mobile_dislocation_increment")),
100 _mobile_function(isParamValid(
"mobile_dislocation_density_forcing_function")
101 ? &getFunction(
"mobile_dislocation_density_forcing_function")
103 _mobile_dislocation_increment(0.0),
105 _immobile_dislocations(declareADProperty<Real>(_base_name +
"immobile_dislocations")),
106 _immobile_dislocations_old(getMaterialPropertyOld<Real>(_base_name +
"immobile_dislocations")),
107 _initial_immobile_dislocations(getParam<Real>(
"initial_immobile_dislocation_density")),
108 _max_immobile_increment(getParam<Real>(
"max_relative_immobile_dislocation_increment")),
109 _immobile_function(isParamValid(
"immobile_dislocation_density_forcing_function")
110 ? &getFunction(
"immobile_dislocation_density_forcing_function")
112 _immobile_dislocation_increment(0.0),
116 _creep_strain_old_forcing_function(isParamValid(
"old_creep_strain_forcing_function")
117 ? &getFunction(
"old_creep_strain_forcing_function")
120 _creep_rate(declareADProperty<Real>(_base_name +
"creep_rate")),
121 _failed(declareProperty<Real>(
"ROM_failure")),
127 template <ComputeStage compute_stage>
131 _transform = getTransform();
133 _num_outputs = _transform.size();
134 if (_num_outputs != 3)
135 mooseError(
"In ", _name,
": _num_outputs (", _num_outputs,
") is not 3");
137 _num_inputs = _transform[0].size();
138 if (_num_inputs != 5 && _num_inputs != 6)
139 mooseError(
"In ", _name,
": _num_inputs (", _num_inputs,
") is not 5 or 6");
140 _use_env = _num_inputs == 6 ? true :
false;
142 _transform_coefs = getTransformCoefs();
143 if (_transform_coefs.size() != _num_outputs || _transform_coefs[0].size() != _num_inputs)
144 mooseError(
"In ", _name,
": transform_coef is the wrong shape!");
146 _input_limits = getInputLimits();
147 if (_input_limits.size() != _num_inputs || _input_limits[0].size() != 2)
148 mooseError(
"In ", _name,
": input_limits is the wrong shape!");
151 if (_coefs.size() != _num_outputs)
152 mooseError(
"In ", _name,
": coefs is the wrong shape!");
154 _num_coefs = _coefs[0].size();
155 _degree =
std::pow(_num_coefs, 1.0 / _num_inputs);
156 if (!_degree || _degree > 4)
157 mooseError(
"In ", _name,
": degree must be 1, 2, 3 or 4.");
159 _transformed_limits = getTransformedLimits();
160 _makeframe_helper = getMakeFrameHelper();
162 Moose::out <<
"ROM model info:\n name:\t" << _name <<
"\n number of outputs:\t" << _num_outputs
163 <<
"\n number of inputs:\t" << _num_inputs
164 <<
"\n degree (max Legendre degree + constant):\t" << _degree
165 <<
"\n number of coefficients:\t" << _num_coefs << std::endl;
168 template <ComputeStage compute_stage>
172 _mobile_dislocations[_qp] = _initial_mobile_dislocations;
173 _immobile_dislocations[_qp] = _initial_immobile_dislocations;
178 template <ComputeStage compute_stage>
181 const ADReal & scalar)
183 if (_immobile_function)
184 _immobile_old = _immobile_function->value(_t, _q_point[_qp]);
186 _immobile_old = _immobile_dislocations_old[_qp];
188 if (_mobile_function)
189 _mobile_old = _mobile_function->value(_t, _q_point[_qp]);
191 _mobile_old = _mobile_dislocations_old[_qp];
193 const ADReal trial_stress_mpa = (effective_trial_stress - _three_shear_modulus * scalar) * 1.0e-6;
195 if (trial_stress_mpa < 0.0)
196 mooseException(
"In ",
198 ": previously calculated scalar (",
199 MetaPhysicL::raw_value(scalar),
200 ") is too high resulting in a negative trial stress (",
201 MetaPhysicL::raw_value(trial_stress_mpa),
202 "). Cutting timestep.");
204 Real effective_strain_old;
205 if (_creep_strain_old_forcing_function)
206 effective_strain_old = _creep_strain_old_forcing_function->value(_t, _q_point[_qp]);
208 effective_strain_old =
209 std::sqrt(_creep_strain_old[_qp].doubleContraction(_creep_strain_old[_qp]) / 1.5);
211 ADReal rom_effective_strain = 0.0;
212 ADReal derivative_rom_effective_strain = 0.0;
214 computeROMStrainRate(_dt,
218 effective_strain_old,
221 _mobile_dislocation_increment,
222 _immobile_dislocation_increment,
223 rom_effective_strain,
224 derivative_rom_effective_strain);
226 if (_verbose && compute_stage == RESIDUAL)
228 Moose::out <<
"Verbose information from " << _name <<
": \n";
229 Moose::out <<
" dt: " << _dt <<
"\n";
230 Moose::out <<
" old mobile disl: " << _mobile_old <<
"\n";
231 Moose::out <<
" old immobile disl: " << _immobile_old <<
"\n";
232 Moose::out <<
" initial stress (MPa): " << effective_trial_stress * 1.0e-6 <<
"\n";
233 Moose::out <<
" temperature: " << _temperature[_qp] <<
"\n";
234 Moose::out <<
" environmental factor: " << _environmental[_qp] <<
"\n";
235 Moose::out <<
" calculated scalar strain value: " << scalar <<
"\n";
236 Moose::out <<
" trial stress into rom (MPa): " << trial_stress_mpa <<
"\n";
237 Moose::out <<
" old effective strain: " << effective_strain_old <<
"\n";
238 Moose::out <<
" ROM outputs \n";
239 Moose::out <<
" effective incremental strain from rom: " << rom_effective_strain <<
"\n";
240 Moose::out <<
" new effective strain: " << effective_strain_old + rom_effective_strain <<
"\n";
241 Moose::out <<
" new mobile dislocations: " << _mobile_old + _mobile_dislocation_increment
243 Moose::out <<
" new immobile dislocations: " << _immobile_old + _immobile_dislocation_increment
248 _creep_rate[_qp] = rom_effective_strain / _dt;
249 _derivative = derivative_rom_effective_strain * -_three_shear_modulus * 1.0e-6 - 1.0;
251 return rom_effective_strain - scalar;
254 template <ComputeStage compute_stage>
257 const ADRankTwoTensor & plastic_strain_increment)
259 _mobile_dislocations[_qp] = _mobile_old + _mobile_dislocation_increment;
260 _immobile_dislocations[_qp] = _immobile_old + _immobile_dislocation_increment;
262 if (_verbose && compute_stage == RESIDUAL)
264 Moose::out <<
"Finalized verbose information from " << _name <<
"\n";
265 Moose::out <<
" increment effective creep strain: "
266 << std::sqrt(2.0 / 3.0 *
267 plastic_strain_increment.doubleContraction(plastic_strain_increment))
269 Moose::out <<
" effective_creep_strain: "
270 << std::sqrt(2.0 / 3.0 * _creep_strain[_qp].doubleContraction(_creep_strain[_qp]))
272 Moose::out <<
" new mobile dislocations: " << _mobile_dislocations[_qp] <<
"\n";
273 Moose::out <<
" new immobile dislocations: " << _immobile_dislocations[_qp] <<
"\n"
278 plastic_strain_increment);
281 template <ComputeStage compute_stage>
287 Real mobile_strain_inc = std::abs(MetaPhysicL::raw_value(_mobile_dislocation_increment));
288 if (mobile_strain_inc && _mobile_old)
290 std::min(limited_dt, _dt * _max_mobile_increment * _mobile_old / mobile_strain_inc);
291 Real immobile_strain_inc = std::abs(MetaPhysicL::raw_value(_immobile_dislocation_increment));
292 if (immobile_strain_inc && _immobile_old)
294 std::min(limited_dt, _dt * _max_immobile_increment * _immobile_old / immobile_strain_inc);
299 template <ComputeStage compute_stage>
303 const Real & mobile_dislocations_old,
304 const Real & immobile_dislocations_old,
305 const ADReal & trial_stress,
306 const Real & effective_strain_old,
308 const ADReal & environmental,
309 ADReal & mobile_dislocation_increment,
310 ADReal & immobile_dislocation_increment,
311 ADReal & rom_effective_strain,
312 ADReal & rom_effective_strain_derivative)
315 std::vector<ADReal> input_values = {mobile_dislocations_old,
316 immobile_dislocations_old,
318 effective_strain_old,
321 input_values.push_back(environmental);
323 std::vector<std::vector<ADReal>> rom_inputs(_num_outputs, std::vector<ADReal>(_num_inputs));
324 std::vector<std::vector<ADReal>> drom_inputs(_num_outputs, std::vector<ADReal>(_num_inputs));
326 checkInputWindows(input_values);
327 convertInput(input_values, rom_inputs, drom_inputs);
329 std::vector<ADReal> old_input_values = {
330 mobile_dislocations_old, immobile_dislocations_old, effective_strain_old};
332 std::vector<std::vector<std::vector<ADReal>>> polynomial_inputs(
333 _num_outputs, std::vector<std::vector<ADReal>>(_num_inputs, std::vector<ADReal>(_degree)));
334 std::vector<ADReal> rom_outputs(_num_outputs);
335 std::vector<ADReal> input_value_increments(_num_outputs);
337 std::vector<std::vector<std::vector<ADReal>>> dpolynomial_inputs(
338 _num_outputs, std::vector<std::vector<ADReal>>(_num_inputs, std::vector<ADReal>(_degree)));
339 std::vector<ADReal> drom_outputs(_num_outputs);
340 std::vector<ADReal> dinput_value_increments(_num_outputs);
342 buildPolynomials(rom_inputs, drom_inputs, polynomial_inputs, dpolynomial_inputs);
343 computeValues(_coefs, polynomial_inputs, dpolynomial_inputs, rom_outputs, drom_outputs);
348 input_value_increments,
349 dinput_value_increments);
351 mobile_dislocation_increment = input_value_increments[0];
352 immobile_dislocation_increment = input_value_increments[1];
353 rom_effective_strain = input_value_increments[2];
355 rom_effective_strain_derivative = dinput_value_increments[2];
358 template <ComputeStage compute_stage>
362 if (compute_stage != RESIDUAL)
366 for (
unsigned int i = 0; i < _num_outputs; ++i)
368 for (
unsigned int j = 0; j < _num_inputs; ++j)
370 Real high_limit = _input_limits[j][1] * _window;
371 Real low_limit = _input_limits[j][0] * (2.0 - _window);
372 if (j == _stress_index && _extrapolate_stress)
374 if (input[j] < low_limit || input[j] > high_limit)
376 _failed[_qp] += (j + 1) * (j + 1);
377 if (_window_failure == WindowFailure::WARN)
380 ": input parameter number input=",
386 ") is out of range (",
393 else if (_window_failure == WindowFailure::ERROR)
396 ": input parameter number input=",
402 ") is out of range (",
414 template <ComputeStage compute_stage>
417 const std::vector<ADReal> & input,
418 std::vector<std::vector<ADReal>> & converted,
419 std::vector<std::vector<ADReal>> & dconverted)
421 for (
unsigned int i = 0; i < _num_outputs; ++i)
423 for (
unsigned int j = 0; j < _num_inputs; ++j)
429 x = std::exp(x / _transform_coefs[i][j]);
430 dx = x / _transform_coefs[i][j];
434 dx = 1.0 / (x + _transform_coefs[i][j]);
435 x = std::log(x + _transform_coefs[i][j]);
438 converted[i][j] = 2.0 * (x - _transformed_limits[i][j][0]) /
439 (_transformed_limits[i][j][1] - _transformed_limits[i][j][0]) -
441 if (j == _stress_index)
442 dconverted[i][j] = dx * 2.0 / (_transformed_limits[i][j][1] - _transformed_limits[i][j][0]);
444 dconverted[i][j] = 0.0;
449 template <ComputeStage compute_stage>
452 const std::vector<std::vector<ADReal>> & rom_inputs,
453 const std::vector<std::vector<ADReal>> & drom_inputs,
454 std::vector<std::vector<std::vector<ADReal>>> & polynomial_inputs,
455 std::vector<std::vector<std::vector<ADReal>>> & dpolynomial_inputs)
457 for (
unsigned int i = 0; i < _num_outputs; ++i)
459 for (
unsigned int j = 0; j < _num_inputs; ++j)
461 for (
unsigned int k = 0; k < _degree; ++k)
463 polynomial_inputs[i][j][k] = computePolynomial(rom_inputs[i][j], k);
465 if (j != _stress_index)
466 dpolynomial_inputs[i][j][k] = 0.0;
470 dpolynomial_inputs[i][j][k] = drom_inputs[i][j] *
471 computePolynomial(rom_inputs[i][j], k,
true) /
472 polynomial_inputs[i][j][k];
479 template <ComputeStage compute_stage>
482 const std::vector<std::vector<Real>> & coefs,
483 const std::vector<std::vector<std::vector<ADReal>>> & polynomial_inputs,
484 const std::vector<std::vector<std::vector<ADReal>>> & dpolynomial_inputs,
485 std::vector<ADReal> & rom_outputs,
486 std::vector<ADReal> & drom_outputs)
488 for (
unsigned int i = 0; i < _num_outputs; ++i)
490 rom_outputs[i] = 0.0;
491 drom_outputs[i] = 0.0;
492 for (
unsigned int j = 0; j < _num_coefs; ++j)
494 ADReal xvals = coefs[i][j];
496 for (
unsigned int k = 0; k < _num_inputs; ++k)
498 xvals *= polynomial_inputs[i][k][_makeframe_helper[j][k]];
499 dxvals += dpolynomial_inputs[i][k][_makeframe_helper[j][k]];
502 rom_outputs[i] += xvals;
503 drom_outputs[i] += dxvals * xvals;
508 template <ComputeStage compute_stage>
512 const std::vector<ADReal> & old_input_values,
513 const std::vector<ADReal> & rom_outputs,
514 const std::vector<ADReal> & drom_outputs,
515 std::vector<ADReal> & input_value_increments,
516 std::vector<ADReal> & dinput_value_increments)
518 for (
unsigned int i = 0; i < _num_outputs; ++i)
520 input_value_increments[i] = std::exp(rom_outputs[i]) * dt;
521 if (i == 0 || i == 1)
523 dinput_value_increments[i] = 0.0;
524 input_value_increments[i] *= old_input_values[i];
526 input_value_increments[i] *= -1.0;
529 dinput_value_increments[i] = input_value_increments[i] * drom_outputs[i];
533 template <ComputeStage compute_stage>
536 const unsigned int degree,
537 const bool derivative)
545 else if (degree == 1)
551 else if (degree == 2)
555 return 1.5 * Utility::pow<2>(value) - 0.5;
560 return 7.5 * Utility::pow<2>(value) - 1.5;
561 return 2.5 * Utility::pow<3>(value) - 1.5 * value;
565 template <ComputeStage compute_stage>
566 std::vector<std::vector<std::vector<Real>>>
569 std::vector<std::vector<std::vector<Real>>> transformed_limits(
570 _num_outputs, std::vector<std::vector<Real>>(_num_inputs, std::vector<Real>(2)));
572 for (
unsigned int i = 0; i < _num_outputs; ++i)
574 for (
unsigned int j = 0; j < _num_inputs; ++j)
576 for (
unsigned int k = 0; k < 2; ++k)
579 transformed_limits[i][j][k] = std::exp(_input_limits[j][k] / _transform_coefs[i][j]);
581 transformed_limits[i][j][k] = std::log(_input_limits[j][k] + _transform_coefs[i][j]);
583 transformed_limits[i][j][k] = _input_limits[j][k];
588 return transformed_limits;
591 template <ComputeStage compute_stage>
592 std::vector<std::vector<unsigned int>>
595 std::vector<std::vector<unsigned int>> v(_num_coefs, std::vector<unsigned int>(_num_inputs));
597 for (
unsigned int numcoeffs = 0; numcoeffs < _num_coefs; ++numcoeffs)
598 for (
unsigned int invar = 0; invar < _num_inputs; ++invar)
599 v[numcoeffs][invar] = numcoeffs /
MathUtils::pow(_degree, invar) % _degree;