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/drivers/solid_mechanics/LDISolidMechanicsDriver.h"
26 : #include "neml2/misc/assertions.h"
27 : #include "neml2/base/LabeledAxis.h"
28 : #include "neml2/models/Model.h"
29 :
30 : namespace neml2
31 : {
32 : register_NEML2_object(LDISolidMechanicsDriver);
33 :
34 : OptionSet
35 2 : LDISolidMechanicsDriver::expected_options()
36 : {
37 2 : OptionSet options = SolidMechanicsDriver::expected_options();
38 2 : options.doc() +=
39 2 : " This driver is specialized for large deformation models using the incremental formulation.";
40 :
41 6 : options.set<VariableName>("deformation_rate") = VariableName(FORCES, "deformation_rate");
42 4 : options.set("deformation_rate").doc() = "Deformation rate";
43 4 : options.set<TensorName<SR2>>("prescribed_deformation_rate");
44 4 : options.set("prescribed_deformation_rate").doc() =
45 2 : "Prescribed deformation rate (when control = STRAIN)";
46 :
47 6 : options.set<VariableName>("cauchy_stress_rate") = VariableName(FORCES, "cauchy_stress_rate");
48 4 : options.set("cauchy_stress_rate").doc() = "Cauchy stress rate";
49 4 : options.set<TensorName<SR2>>("prescribed_cauchy_stress_rate");
50 4 : options.set("prescribed_cauchy_stress_rate").doc() =
51 2 : "Prescribed cauchy stress rate (when control = STRESS)";
52 :
53 6 : options.set<VariableName>("vorticity") = VariableName(FORCES, "vorticity");
54 4 : options.set("vorticity").doc() = "Vorticity";
55 4 : options.set<TensorName<WR2>>("prescribed_vorticity");
56 4 : options.set("prescribed_vorticity").doc() = "Prescribed vorticity";
57 :
58 4 : options.set<bool>("cp_warmup") = false;
59 6 : options.set("cp_warmup").doc() =
60 : "Whether to perform a warm-up step for crystal plasticity models. The warm-up step uses a "
61 2 : "relaxed/damped elastic predictor for the very first time step.";
62 4 : options.set<double>("cp_warmup_elastic_scale") = 1.0;
63 4 : options.set("cp_warmup_elastic_scale").doc() =
64 2 : "Elastic step scale factor used for the crystal plasticity warm-up step";
65 6 : options.set<VariableName>("cp_warmup_elastic_strain") = VariableName(STATE, "elastic_strain");
66 4 : options.set("cp_warmup_elastic_strain").doc() =
67 2 : "Elastic strain name used for the CP warm-up step";
68 :
69 2 : return options;
70 0 : }
71 :
72 1 : LDISolidMechanicsDriver::LDISolidMechanicsDriver(const OptionSet & options)
73 : : SolidMechanicsDriver(options),
74 1 : _vorticity_prescribed(options.get("prescribed_vorticity").user_specified()),
75 2 : _cp_warmup(options.get<bool>("cp_warmup")),
76 2 : _cp_warmup_elastic_scale(options.get<double>("cp_warmup_elastic_scale")),
77 3 : _cp_warmup_elastic_strain(options.get<VariableName>("cp_warmup_elastic_strain"))
78 : {
79 1 : }
80 :
81 : void
82 1 : LDISolidMechanicsDriver::setup()
83 : {
84 1 : SolidMechanicsDriver::setup();
85 1 : init_vorticity_control(input_options());
86 1 : }
87 :
88 : void
89 1 : LDISolidMechanicsDriver::init_strain_control(const OptionSet & options)
90 : {
91 1 : _driving_force_name = options.get<VariableName>("deformation_rate");
92 2 : _driving_force = resolve_tensor<SR2>("prescribed_deformation_rate");
93 1 : _driving_force = _driving_force.to(_device);
94 1 : }
95 :
96 : void
97 0 : LDISolidMechanicsDriver::init_stress_control(const OptionSet & options)
98 : {
99 0 : _driving_force_name = options.get<VariableName>("cauchy_stress_rate");
100 0 : _driving_force = resolve_tensor<SR2>("prescribed_cauchy_stress_rate");
101 0 : _driving_force = _driving_force.to(_device);
102 0 : }
103 :
104 : void
105 1 : LDISolidMechanicsDriver::init_vorticity_control(const OptionSet & options)
106 : {
107 1 : _vorticity_name = options.get<VariableName>("vorticity");
108 2 : _vorticity = resolve_tensor<WR2>("prescribed_vorticity");
109 1 : _vorticity = _vorticity.to(_device);
110 1 : }
111 :
112 : void
113 1 : LDISolidMechanicsDriver::diagnose() const
114 : {
115 1 : SolidMechanicsDriver::diagnose();
116 :
117 1 : if (_vorticity_prescribed)
118 : {
119 1 : diagnostic_assert(_vorticity.batch_dim() >= 1,
120 : "Input vorticity should have at least one batch dimension but instead "
121 : "has batch dimension ",
122 1 : _vorticity.batch_dim());
123 1 : diagnostic_assert(
124 :
125 1 : _vorticity.batch_size(0) == _time.batch_size(0),
126 : "Input vorticity should have the same number of steps steps as time, but instead has ",
127 2 : _vorticity.batch_size(0),
128 : " time steps");
129 : }
130 :
131 1 : if (_cp_warmup)
132 : {
133 1 : diagnostic_assert(_control == "STRAIN", "CP warm-up step is only supported for STRAIN control");
134 1 : diagnostic_assert(_model->input_axis().has_variable(_cp_warmup_elastic_strain),
135 : "Model's input axis should have variable ",
136 1 : _cp_warmup_elastic_strain,
137 : " for the CP warm-up step but it does not");
138 : }
139 1 : }
140 :
141 : void
142 10 : LDISolidMechanicsDriver::update_forces()
143 : {
144 10 : SolidMechanicsDriver::update_forces();
145 20 : _in[_vorticity_name] = _vorticity.batch_index({_step_count});
146 20 : }
147 :
148 : void
149 9 : LDISolidMechanicsDriver::apply_predictor()
150 : {
151 9 : SolidMechanicsDriver::apply_predictor();
152 :
153 9 : if (_cp_warmup && (_step_count == 1))
154 : {
155 1 : const auto D = SR2(_in[_driving_force_name]);
156 1 : const auto t = Scalar(_in[_time_name]);
157 1 : const auto t_n = Scalar(_result_in[_step_count - 1][_time_name]);
158 1 : _in[_cp_warmup_elastic_strain] = D * (t - t_n) * _cp_warmup_elastic_scale;
159 1 : }
160 9 : }
161 :
162 : } // namespace neml2
|