15 #include <initializer_list> 16 #include <torch/torch.h> 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" 32 auto options = Model::expected_options();
34 "Multilinear interpolation over six dimensions (von_mises_stress, temperature, " 35 "equivalent_plastic_strain, cell_dislocation_density, wall_dislocation_density, env_factor)";
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");
46 options.add_output(
"output_rate",
"The output rate");
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");
54 options.set<
bool>(
"jit",
false);
55 options.suppress(
"jit");
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"))
70 std::string filename = options.get<std::string>(
"model_file_name");
71 std::ifstream model_file(filename.c_str());
123 throw NEMLException(
"This ouput variable is not implemented, model_file_variable_name: " +
134 std::vector<const VariableBase *> inputs = {&
_vm_stress};
149 if (
name ==
"COMPRESS")
151 else if (
name ==
"DECOMPRESS")
153 else if (
name ==
"LOG10BOUNDED")
155 else if (
name ==
"EXP10BOUNDED")
157 else if (
name ==
"MINMAX")
160 throw NEMLException(
"Unrecognized transform: " + std::string(
name));
163 std::pair<Scalar, Scalar>
165 const Scalar & interp_points)
const 169 auto left_idx = Scalar(torch::searchsorted(grid, interp_points) - 1, 0);
172 left_idx = Scalar(torch::clamp(left_idx, 0, grid.sizes()[0] - 2), 0);
174 auto left_coord = grid.dynamic_index({left_idx});
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);
179 return {left_idx, neml2::dynamic_stack({left_fraction, 1 - left_fraction}, -1)};
184 const std::vector<std::pair<Scalar, Scalar>> index_and_fraction,
const Scalar grid_values)
const 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})
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;
223 const auto cell_dd_transformed =
225 const auto wall_dd_transformed =
227 const auto vm_stress_transformed =
231 const auto temperature_transformed =
233 const auto env_fac_transformed =
236 std::vector<std::pair<Scalar, Scalar>> left_index_weight;
239 left_index_weight.push_back(
245 Scalar transformed_result =
247 return transformed_result;
252 const std::vector<double> & param,
255 switch (transform_type)
279 const std::vector<double> & param)
const 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;
291 const std::vector<double> & param)
const 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;
303 const std::vector<double> & param)
const 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;
319 const std::vector<double> & param)
const 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;
334 const std::vector<double> & param)
const 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;
348 if (!
_json.contains(key))
349 throw NEMLException(
"The key '" + std::string(key) +
"' is missing from the JSON data file.");
351 std::string
name =
_json[key].get<std::string>();
358 if (!
_json.contains(key))
359 throw NEMLException(
"The key '" + std::string(key) +
"' is missing from the JSON data file.");
361 std::vector<double> data_vec =
_json[key].get<std::vector<double>>();
368 if (!
_json.contains(key))
369 throw NEMLException(
"The key '" + std::string(key) +
"' is missing from the JSON data file.");
371 std::vector<double> in_data =
_json[key].get<std::vector<double>>();
372 return Scalar::create(in_data).clone();
379 if (!
_json.contains(key))
380 throw NEMLException(
"The key '" + std::string(key) +
"' is missing from the JSON data file.");
382 vector<vector<vector<vector<vector<vector<double>>>>>> out_data =
383 _json[key].get<vector<vector<vector<vector<vector<vector<double>>>>>>>();
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();
392 auto check_level_size =
393 [](
const int64_t current_vec_size,
const int64_t sz_level,
const std::string & key)
395 if (current_vec_size != sz_level)
396 throw NEMLException(
"Incorrect JSON interpolation grid size for '" + key +
"'.");
399 std::vector<double> linearize_values;
400 check_level_size(out_data.size(), sz_l0, key);
401 for (
auto && level1 : out_data)
403 check_level_size(level1.size(), sz_l1, key);
404 for (
auto && level2 : level1)
406 check_level_size(level2.size(), sz_l2, key);
407 for (
auto && level3 : level2)
409 check_level_size(level3.size(), sz_l3, key);
410 for (
auto && level4 : level3)
412 check_level_size(level4.size(), sz_l4, key);
413 for (
auto && level5 : level4)
415 check_level_size(level5.size(), sz_l5, key);
416 for (
auto &&
value : level5)
417 linearize_values.push_back(
value);
424 return Scalar::create(linearize_values)
425 .dynamic_reshape({sz_l0, sz_l1, sz_l2, sz_l3, sz_l4, sz_l5})
std::vector< double > _wall_transform_values
Scalar transform_data(const Scalar &data, const std::vector< double > ¶m, TransformEnum transform_type) const
transform data
TransformEnum _output_transform_enum
output transform enum
TransformEnum _temperature_transform_enum
const Variable< Scalar > & _temperature
Temperature.
std::string json_to_string(const std::string &key) const
read in json axes transform name
TransformEnum _cell_transform_enum
static OptionSet expected_options()
TransformEnum get_transform_enum(const std::string &name) const
const Variable< Scalar > & _wall_dd
wall dislocation density
TransformEnum _wall_transform_enum
std::vector< double > _cell_transform_values
const Variable< Scalar > & _cell_dd
cell dislocation density
TransformEnum _plastic_strain_transform_enum
std::vector< double > _plastic_strain_transform_values
register_NEML2_object(LibtorchModel)
const Variable< Scalar > & _env_fac
environmental factor
std::string _output_rate_name
output transform rate name
Scalar transform_exp10_bounded(const Scalar &data, const std::vector< double > ¶ms) const
std::vector< double > _stress_transform_values
input transform values
TransformEnum _env_transform_enum
std::pair< Scalar, Scalar > findLeftIndexAndFraction(const Scalar &grid, const Scalar &interp_points) const
find index of input point
TransformEnum _stress_transform_enum
input transform enums
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
Scalar compute_interpolation(const std::vector< std::pair< Scalar, Scalar >> index_and_fraction, const Scalar grid_values) const
compute interpolated value
Scalar json_6Dvector_to_torch(const std::string &key) const
read 6D grid date from json and store in Torch tensor
Scalar _grid_values
grid values being interpolated
const Variable< Scalar > & _vm_stress
Model input for interpolation.
void set_value(bool, bool, bool) override
Scalar _stress_grid
grid for interpolation
Scalar transform_decompress(const Scalar &data, const std::vector< double > ¶ms) const
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
Scalar transform_min_max(const Scalar &data, const std::vector< double > ¶ms) const
LAROMANCE6DInterpolation(const OptionSet &options)
std::vector< double > _env_transform_values
Scalar json_vector_to_torch(const std::string &key) const
read 1D vector of grid points from json and store in Torch tensor
nlohmann::json _json
JSON object containing interpolation grid and values.
Scalar transform_compress(const Scalar &data, const std::vector< double > ¶ms) const
LAROMANCE transforms for input axes and output axis.
std::vector< double > _output_transform_values
output transform values
std::vector< double > json_to_vector(const std::string &key) const
read in json axes transform constants
Scalar interpolate_and_transform() const
compute interpolated value and transform results
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
Scalar transform_log10_bounded(const Scalar &data, const std::vector< double > ¶ms) const
Variable< Scalar > & _output_rate
Model output.
std::vector< double > _temperature_transform_values
const Variable< Scalar > & _ep_strain
The creep strain.
static const std::string k
void request_AD() override
Scalar _plastic_strain_grid