https://mooseframework.inl.gov
Loading...
Searching...
No Matches
LAROMANCE6DInterpolation.C
Go to the documentation of this file.
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
11
12#ifdef NEML2_ENABLED
13
14#include <fstream>
15#include <initializer_list>
16#include <torch/torch.h>
17
18#include "neml2/tensors/functions/sign.h"
19#include "neml2/tensors/functions/abs.h"
20#include "neml2/tensors/functions/pow.h"
21#include "neml2/tensors/functions/log10.h"
22#include "neml2/tensors/functions/clamp.h"
23#include "neml2/tensors/functions/stack.h"
24
25namespace neml2
26{
28
29OptionSet
31{
32 auto options = Model::expected_options();
33 options.doc() =
34 "Multilinear interpolation over six dimensions (von_mises_stress, temperature, "
35 "equivalent_plastic_strain, cell_dislocation_density, wall_dislocation_density, env_factor)";
36
37 // Model inputs
38 options.add_input("equivalent_plastic_strain", "The equivalent plastic strain");
39 options.add_input("von_mises_stress", "The von Mises stress");
40 options.add_input("cell_dislocation_density", "The cell dislocation density");
41 options.add_input("wall_dislocation_density", "The wall dislocation density");
42 options.add_input("temperature", "The temperature");
43 options.add_input("env_factor", "The environment factor");
44
45 // Model Outputs
46 options.add_output("output_rate", "The output rate");
47
48 // JSON
49 options.add<std::string>("model_file_name", "The name of the model file");
50 options.add<std::string>("model_file_variable_name",
51 "The name of the variable in the model file");
52
53 // jit does not currently work with this
54 options.set<bool>("jit", false);
55 options.suppress("jit");
56
57 return options;
58}
59
61 : Model(options),
62 _vm_stress(declare_input_variable<Scalar>("von_mises_stress")),
63 _temperature(declare_input_variable<Scalar>("temperature")),
64 _ep_strain(declare_input_variable<Scalar>("equivalent_plastic_strain")),
65 _cell_dd(declare_input_variable<Scalar>("cell_dislocation_density")),
66 _wall_dd(declare_input_variable<Scalar>("wall_dislocation_density")),
67 _env_fac(declare_input_variable<Scalar>("env_factor")),
68 _output_rate(declare_output_variable<Scalar>("output_rate"))
69{
70 std::string filename = options.get<std::string>("model_file_name");
71 std::ifstream model_file(filename.c_str());
72 model_file >> _json;
73
74 // storing grid points for indexing.
75 // these should be stored differently so that they are all read in at once. The order of this can
76 // get messed up easily
78 _temperature_grid = json_vector_to_torch("in_temperature");
79 _plastic_strain_grid = json_vector_to_torch("in_plastic_strain");
83
84 // Read in grid axes transform enums
85 _stress_transform_enum = get_transform_enum(json_to_string("in_stress_transform_type"));
86 _temperature_transform_enum = get_transform_enum(json_to_string("in_temperature_transform_type"));
88 get_transform_enum(json_to_string("in_plastic_strain_transform_type"));
89 _cell_transform_enum = get_transform_enum(json_to_string("in_cell_transform_type"));
90 _wall_transform_enum = get_transform_enum(json_to_string("in_wall_transform_type"));
91 _env_transform_enum = get_transform_enum(json_to_string("in_env_transform_type"));
92
93 // Read in grid axes transform values
94 _stress_transform_values = json_to_vector("in_stress_transform_values");
95 _temperature_transform_values = json_to_vector("in_temperature_transform_values");
96 _plastic_strain_transform_values = json_to_vector("in_plastic_strain_transform_values");
97 _cell_transform_values = json_to_vector("in_cell_transform_values");
98 _wall_transform_values = json_to_vector("in_wall_transform_values");
99 _env_transform_values = json_to_vector("in_env_transform_values");
100
101 // Storing values for interpolation
102 _output_rate_name = options.get<std::string>("model_file_variable_name");
104
105 // set up output transforms
106 if (_output_rate_name == "out_ep")
107 {
108 _output_transform_enum = get_transform_enum(json_to_string("out_strain_rate_transform_type"));
109 _output_transform_values = json_to_vector("out_strain_rate_transform_values");
110 }
111 else if (_output_rate_name == "out_cell")
112 {
113 _output_transform_enum = get_transform_enum(json_to_string("out_cell_rate_transform_type"));
114 _output_transform_values = json_to_vector("out_cell_rate_transform_values");
115 }
116 else if (_output_rate_name == "out_wall")
117 {
118 _output_transform_enum = get_transform_enum(json_to_string("out_wall_rate_transform_type"));
119 _output_transform_values = json_to_vector("out_wall_rate_transform_values");
120 }
121 else
122 {
123 throw NEMLException("This ouput variable is not implemented, model_file_variable_name: " +
124 std::string(_output_rate_name));
125 }
126}
127
128void
130{
131 // only using first derivatives of out_ep, not out_cell and out_wall
132 if (_output_rate_name == "out_ep")
133 {
134 std::vector<const VariableBase *> inputs = {&_vm_stress};
135 _output_rate.request_AD(inputs);
136 }
137}
138
139void
140LAROMANCE6DInterpolation::set_value(bool out, bool /*dout_din*/, bool /*d2out_din2*/)
141{
142 if (out)
144}
145
148{
149 if (name == "COMPRESS")
151 else if (name == "DECOMPRESS")
153 else if (name == "LOG10BOUNDED")
155 else if (name == "EXP10BOUNDED")
157 else if (name == "MINMAX")
159
160 throw NEMLException("Unrecognized transform: " + std::string(name));
161}
162
163std::pair<Scalar, Scalar>
165 const Scalar & interp_points) const
166{
167 // idx is for the left grid point.
168 // searchsorted returns the right idx so -1 makes it the left
169 auto left_idx = Scalar(torch::searchsorted(grid, interp_points) - 1, 0);
170
171 // this allows us to extrapolate
172 left_idx = Scalar(torch::clamp(left_idx, 0, grid.sizes()[0] - 2), 0);
173
174 auto left_coord = grid.dynamic_index({left_idx});
175 auto right_coord =
176 grid.dynamic_index({left_idx + torch::tensor(1, default_integer_tensor_options())});
177 auto left_fraction = (right_coord - interp_points) / (right_coord - left_coord);
178
179 return {left_idx, neml2::dynamic_stack({left_fraction, 1 - left_fraction}, -1)};
180}
181
182Scalar
184 const std::vector<std::pair<Scalar, Scalar>> index_and_fraction, const Scalar grid_values) const
185{
186 Scalar result = Scalar::zeros_like(_temperature());
187 for (const auto i : {0, 1})
188 for (const auto j : {0, 1})
189 for (const auto k : {0, 1})
190 for (const auto l : {0, 1})
191 for (const auto m : {0, 1})
192 for (const auto n : {0, 1})
193 {
194 auto vertex_value =
195 grid_values.index({(index_and_fraction[0].first +
196 torch::tensor(i, default_integer_tensor_options())),
197 (index_and_fraction[1].first +
198 torch::tensor(j, default_integer_tensor_options())),
199 (index_and_fraction[2].first +
200 torch::tensor(k, default_integer_tensor_options())),
201 (index_and_fraction[3].first +
202 torch::tensor(l, default_integer_tensor_options())),
203 (index_and_fraction[4].first +
204 torch::tensor(m, default_integer_tensor_options())),
205 (index_and_fraction[5].first +
206 torch::tensor(n, default_integer_tensor_options()))});
207 auto weight = index_and_fraction[0].second.select(-1, i) *
208 index_and_fraction[1].second.select(-1, j) *
209 index_and_fraction[2].second.select(-1, k) *
210 index_and_fraction[3].second.select(-1, l) *
211 index_and_fraction[4].second.select(-1, m) *
212 index_and_fraction[5].second.select(-1, n);
213 result += vertex_value * weight;
214 }
215 return result;
216}
217
219Scalar
221{
222 // These transform constants should be given in the json file.
223 const auto cell_dd_transformed =
225 const auto wall_dd_transformed =
227 const auto vm_stress_transformed =
229 const auto ep_strain_transformed = transform_data(
231 const auto temperature_transformed =
233 const auto env_fac_transformed =
235
236 std::vector<std::pair<Scalar, Scalar>> left_index_weight;
237 left_index_weight.push_back(findLeftIndexAndFraction(_stress_grid, vm_stress_transformed));
238 left_index_weight.push_back(findLeftIndexAndFraction(_temperature_grid, temperature_transformed));
239 left_index_weight.push_back(
240 findLeftIndexAndFraction(_plastic_strain_grid, ep_strain_transformed));
241 left_index_weight.push_back(findLeftIndexAndFraction(_cell_grid, cell_dd_transformed));
242 left_index_weight.push_back(findLeftIndexAndFraction(_wall_grid, wall_dd_transformed));
243 left_index_weight.push_back(findLeftIndexAndFraction(_env_grid, env_fac_transformed));
244 Scalar interpolated_result = compute_interpolation(left_index_weight, _grid_values);
245 Scalar transformed_result =
247 return transformed_result;
248}
249
250Scalar
252 const std::vector<double> & param,
253 TransformEnum transform_type) const
254{
255 switch (transform_type)
256 {
258 return transform_compress(data, param);
259
261 return transform_decompress(data, param);
262
264 return transform_log10_bounded(data, param);
265
267 return transform_exp10_bounded(data, param);
268
270 return transform_min_max(data, param);
271
272 default:
273 return data;
274 }
275}
276
277Scalar
279 const std::vector<double> & param) const
280{
281 double factor = param[0];
282 double compressor = param[1];
283 double original_min = param[2];
284 auto d1 = neml2::sign(data) * neml2::pow(neml2::abs(data * factor), compressor);
285 auto transformed_data = neml2::log10(1.0 + d1 - original_min);
286 return transformed_data;
287}
288
289Scalar
291 const std::vector<double> & param) const
292{
293 double factor = param[0];
294 double compressor = param[1];
295 double original_min = param[2];
296 auto d1 = neml2::pow(10.0, data) - 1.0 + original_min;
297 auto transformed_data = neml2::sign(d1) * neml2::pow(neml2::abs(d1), 1.0 / compressor) / factor;
298 return transformed_data;
299}
300
301Scalar
303 const std::vector<double> & param) const
304
305{
306 double factor = param[0];
307 double lowerbound = param[1];
308 double upperbound = param[2];
309 double logmin = param[3];
310 double logmax = param[4];
311 double range = upperbound - lowerbound;
312 auto transformed_data =
313 range * (neml2::log10(data + factor) - logmin) / (logmax - logmin) + lowerbound;
314 return transformed_data;
315}
316
317Scalar
319 const std::vector<double> & param) const
320{
321 double factor = param[0];
322 double lowerbound = param[1];
323 double upperbound = param[2];
324 double logmin = param[3];
325 double logmax = param[4];
326 double range = upperbound - lowerbound;
327 auto transformed_data =
328 (neml2::pow(10.0, ((data - lowerbound) * (logmax - logmin) / range) + logmin) - factor);
329 return transformed_data;
330}
331
332Scalar
334 const std::vector<double> & param) const
335{
336 double data_min = param[0];
337 double data_max = param[1];
338 double scaled_min = param[2];
339 double scaled_max = param[3];
340 auto transformed_data =
341 ((data - data_min) / (data_max - data_min)) * (scaled_max - scaled_min) + scaled_min;
342 return transformed_data;
343}
344
345std::string
346LAROMANCE6DInterpolation::json_to_string(const std::string & key) const
347{
348 if (!_json.contains(key))
349 throw NEMLException("The key '" + std::string(key) + "' is missing from the JSON data file.");
350
351 std::string name = _json[key].get<std::string>();
352 return name;
353}
354
355std::vector<double>
356LAROMANCE6DInterpolation::json_to_vector(const std::string & key) const
357{
358 if (!_json.contains(key))
359 throw NEMLException("The key '" + std::string(key) + "' is missing from the JSON data file.");
360
361 std::vector<double> data_vec = _json[key].get<std::vector<double>>();
362 return data_vec;
363}
364
365Scalar
367{
368 if (!_json.contains(key))
369 throw NEMLException("The key '" + std::string(key) + "' is missing from the JSON data file.");
370
371 std::vector<double> in_data = _json[key].get<std::vector<double>>();
372 return Scalar::create(in_data).clone();
373}
374
375Scalar
377{
378 using std::vector;
379 if (!_json.contains(key))
380 throw NEMLException("The key '" + std::string(key) + "' is missing from the JSON data file.");
381
382 vector<vector<vector<vector<vector<vector<double>>>>>> out_data =
383 _json[key].get<vector<vector<vector<vector<vector<vector<double>>>>>>>();
384
385 const int64_t sz_l0 = out_data.size();
386 const int64_t sz_l1 = out_data[0].size();
387 const int64_t sz_l2 = out_data[0][0].size();
388 const int64_t sz_l3 = out_data[0][0][0].size();
389 const int64_t sz_l4 = out_data[0][0][0][0].size();
390 const int64_t sz_l5 = out_data[0][0][0][0][0].size();
391
392 auto check_level_size =
393 [](const int64_t current_vec_size, const int64_t sz_level, const std::string & key)
394 {
395 if (current_vec_size != sz_level)
396 throw NEMLException("Incorrect JSON interpolation grid size for '" + key + "'.");
397 };
398
399 std::vector<double> linearize_values;
400 check_level_size(out_data.size(), sz_l0, key);
401 for (auto && level1 : out_data)
402 {
403 check_level_size(level1.size(), sz_l1, key);
404 for (auto && level2 : level1)
405 {
406 check_level_size(level2.size(), sz_l2, key);
407 for (auto && level3 : level2)
408 {
409 check_level_size(level3.size(), sz_l3, key);
410 for (auto && level4 : level3)
411 {
412 check_level_size(level4.size(), sz_l4, key);
413 for (auto && level5 : level4)
414 {
415 check_level_size(level5.size(), sz_l5, key);
416 for (auto && value : level5)
417 linearize_values.push_back(value);
418 }
419 }
420 }
421 }
422 }
423
424 return Scalar::create(linearize_values)
425 .dynamic_reshape({sz_l0, sz_l1, sz_l2, sz_l3, sz_l4, sz_l5})
426 .clone();
427}
428
429} // namespace neml2
430
431#endif
const std::string name
Definition Setup.h:21
std::vector< double > _temperature_transform_values
Scalar transform_decompress(const Scalar &data, const std::vector< double > &params) const
std::pair< Scalar, Scalar > findLeftIndexAndFraction(const Scalar &grid, const Scalar &interp_points) const
find index of input point
const Variable< Scalar > & _temperature
Temperature.
const Variable< Scalar > & _cell_dd
cell dislocation density
const Variable< Scalar > & _wall_dd
wall dislocation density
Scalar transform_log10_bounded(const Scalar &data, const std::vector< double > &params) const
Scalar transform_data(const Scalar &data, const std::vector< double > &param, TransformEnum transform_type) const
transform data
const Variable< Scalar > & _vm_stress
Model input for interpolation.
Scalar transform_min_max(const Scalar &data, const std::vector< double > &params) const
nlohmann::json _json
JSON object containing interpolation grid and values.
TransformEnum _output_transform_enum
output transform enum
Scalar interpolate_and_transform() const
compute interpolated value and transform results
Scalar _grid_values
grid values being interpolated
std::vector< double > json_to_vector(const std::string &key) const
read in json axes transform constants
Scalar json_vector_to_torch(const std::string &key) const
read 1D vector of grid points from json and store in Torch tensor
std::vector< double > _output_transform_values
output transform values
Scalar compute_interpolation(const std::vector< std::pair< Scalar, Scalar > > index_and_fraction, const Scalar grid_values) const
compute interpolated value
void set_value(bool, bool, bool) override
LAROMANCE6DInterpolation(const OptionSet &options)
Variable< Scalar > & _output_rate
Model output.
Scalar _stress_grid
grid for interpolation
Scalar transform_exp10_bounded(const Scalar &data, const std::vector< double > &params) const
std::string json_to_string(const std::string &key) const
read in json axes transform name
Scalar json_6Dvector_to_torch(const std::string &key) const
read 6D grid date from json and store in Torch tensor
std::vector< double > _stress_transform_values
input transform values
TransformEnum _stress_transform_enum
input transform enums
std::vector< double > _plastic_strain_transform_values
const Variable< Scalar > & _env_fac
environmental factor
const Variable< Scalar > & _ep_strain
The creep strain.
Scalar transform_compress(const Scalar &data, const std::vector< double > &params) const
LAROMANCE transforms for input axes and output axis.
std::string _output_rate_name
output transform rate name
TransformEnum get_transform_enum(const std::string &name) const
register_NEML2_object(LibtorchModel)