Line data Source code
1 : // Copyright 2024, UChicago Argonne, LLC
2 : // All Rights Reserved
3 : // Software Name: NEML2 -- the New Engineering material Model Library, version 2
4 : // By: Argonne National Laboratory
5 : // OPEN SOURCE LICENSE (MIT)
6 : //
7 : // Permission is hereby granted, free of charge, to any person obtaining a copy
8 : // of this software and associated documentation files (the "Software"), to deal
9 : // in the Software without restriction, including without limitation the rights
10 : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 : // copies of the Software, and to permit persons to whom the Software is
12 : // furnished to do so, subject to the following conditions:
13 : //
14 : // The above copyright notice and this permission notice shall be included in
15 : // all copies or substantial portions of the Software.
16 : //
17 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 : // THE SOFTWARE.
24 :
25 : #include "neml2/models/solid_mechanics/FredrickArmstrongPlasticHardening.h"
26 : #include "neml2/tensors/Scalar.h"
27 : #include "neml2/tensors/SR2.h"
28 : #include "neml2/tensors/SSR4.h"
29 :
30 : namespace neml2
31 : {
32 : register_NEML2_object(FredrickArmstrongPlasticHardening);
33 :
34 : OptionSet
35 4 : FredrickArmstrongPlasticHardening::expected_options()
36 : {
37 4 : OptionSet options = FlowRule::expected_options();
38 4 : options.doc() +=
39 : " This object defines the non-associative Fredrick-Armstrong kinematic hardening. In the "
40 : "model, back stress is directly treated as an internal variable. Rate of back stress is "
41 : "given as \\f$ \\dot{\\boldsymbol{X}} = \\left( \\frac{2}{3} C \\frac{\\partial f}{\\partial "
42 : "\\boldsymbol{M}} - g \\boldsymbol{X} \\right) \\dot{\\gamma} \\f$."
43 : "\\f$ \\frac{\\partial f}{\\partial \\boldsymbol{M}} \\f$ is the flow "
44 : "direction, \\f$ \\dot{\\gamma} \\f$ is the flow rate, and \\f$ C \\f$ and \\f$ g \\f$ are "
45 4 : "material parameters.";
46 :
47 12 : options.set_input("back_stress") = VariableName(STATE, "internal", "X");
48 8 : options.set("back_stress").doc() = "Back stress";
49 :
50 8 : options.set_output("back_stress_rate");
51 4 : options.set("back_stress_rate").doc() = "Back stress rate, defaults to back_stress + _rate";
52 :
53 12 : options.set_input("flow_direction") = VariableName(STATE, "internal", "NM");
54 8 : options.set("flow_direction").doc() = "Flow direction";
55 :
56 8 : options.set_parameter<TensorName<Scalar>>("C");
57 8 : options.set("C").doc() = "Kinematic hardening coefficient";
58 :
59 8 : options.set_parameter<TensorName<Scalar>>("g");
60 4 : options.set("g").doc() = "Dynamic recovery coefficient";
61 :
62 4 : return options;
63 0 : }
64 :
65 6 : FredrickArmstrongPlasticHardening::FredrickArmstrongPlasticHardening(const OptionSet & options)
66 : : FlowRule(options),
67 6 : _X(declare_input_variable<SR2>("back_stress")),
68 6 : _NM(declare_input_variable<SR2>("flow_direction")),
69 24 : _X_dot(declare_output_variable<SR2>(options.get<VariableName>("back_stress_rate").empty()
70 24 : ? _X.name().with_suffix("_rate")
71 : : options.get<VariableName>("back_stress_rate"))),
72 24 : _C(declare_parameter<Scalar>("C", "C", true)),
73 30 : _g(declare_parameter<Scalar>("g", "g", true))
74 : {
75 6 : }
76 :
77 : void
78 4 : FredrickArmstrongPlasticHardening::set_value(bool out, bool dout_din, bool /*d2out_din2*/)
79 : {
80 4 : auto eps = machine_precision(_X.scalar_type());
81 : // The effective stress
82 4 : auto s = SR2(_X).norm(eps);
83 : // The part that's proportional to the plastic strain rate
84 4 : auto g_term = 2.0 / 3.0 * _C * _NM - _g * _X;
85 :
86 4 : if (out)
87 3 : _X_dot = g_term * _gamma_dot;
88 :
89 4 : if (dout_din)
90 : {
91 2 : auto I = SR2::identity_map(_X.options());
92 :
93 2 : if (_gamma_dot.is_dependent())
94 2 : _X_dot.d(_gamma_dot) = g_term;
95 :
96 2 : if (_NM.is_dependent())
97 2 : _X_dot.d(_NM) = 2.0 / 3.0 * _C * _gamma_dot * I;
98 :
99 2 : if (_X.is_dependent())
100 2 : _X_dot.d(_X) = -_g * _gamma_dot * I;
101 :
102 6 : if (const auto * const C = nl_param("C"))
103 1 : _X_dot.d(*C) = 2.0 / 3.0 * _NM * _gamma_dot;
104 :
105 6 : if (const auto * const g = nl_param("g"))
106 1 : _X_dot.d(*g) = -_X * _gamma_dot;
107 2 : }
108 4 : }
109 :
110 : } // namespace neml2
|