Line data Source code
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 :
10 : #include "NEML2Action.h"
11 : #include "NEML2ActionCommon.h"
12 : #include "FEProblem.h"
13 : #include "Factory.h"
14 : #include "NEML2Utils.h"
15 : #include "InputParameterWarehouse.h"
16 :
17 : #ifdef NEML2_ENABLED
18 : #include "neml2/base/Parser.h"
19 : #endif
20 :
21 : registerMooseAction("MooseApp", NEML2Action, "parse_neml2");
22 : registerMooseAction("MooseApp", NEML2Action, "add_material");
23 : registerMooseAction("MooseApp", NEML2Action, "add_user_object");
24 :
25 : #ifdef NEML2_ENABLED
26 : // NEML2 variable type --> MOOSE type
27 : const std::map<neml2::TensorType, std::string> tensor_type_map = {
28 : {neml2::TensorType::kScalar, "Real"},
29 : {neml2::TensorType::kSR2, "SymmetricRankTwoTensor"},
30 : {neml2::TensorType::kR2, "RankTwoTensor"},
31 : {neml2::TensorType::kSSR4, "SymmetricRankFourTensor"},
32 : {neml2::TensorType::kR4, "RankFourTensor"},
33 : {neml2::TensorType::kRot, "RealVectorValue"}};
34 : // NEML2 (output, input) type --> NEML2 derivative type
35 : const std::map<std::pair<neml2::TensorType, neml2::TensorType>, neml2::TensorType> deriv_type_map =
36 : {
37 : {{neml2::TensorType::kScalar, neml2::TensorType::kScalar}, neml2::TensorType::kScalar},
38 : {{neml2::TensorType::kSR2, neml2::TensorType::kSR2}, neml2::TensorType::kSSR4},
39 : {{neml2::TensorType::kSR2, neml2::TensorType::kScalar}, neml2::TensorType::kSR2},
40 : {{neml2::TensorType::kScalar, neml2::TensorType::kSR2}, neml2::TensorType::kSR2},
41 : {{neml2::TensorType::kR2, neml2::TensorType::kR2}, neml2::TensorType::kR4},
42 : {{neml2::TensorType::kR2, neml2::TensorType::kScalar}, neml2::TensorType::kR2},
43 : {{neml2::TensorType::kScalar, neml2::TensorType::kR2}, neml2::TensorType::kR2},
44 : };
45 : #endif
46 :
47 : InputParameters
48 225 : NEML2Action::validParams()
49 : {
50 225 : InputParameters params = NEML2ActionCommon::commonParams();
51 225 : params.addClassDescription(NEML2Utils::docstring("Set up the NEML2 material model"));
52 225 : params.addParam<std::string>(
53 : "executor_name",
54 450 : NEML2Utils::docstring("Name of the NEML2ModelExecutor user object. The default name is "
55 : "'neml2_<model-name>_<block-name>' where <model-name> is the NEML2 "
56 : "model's name, and <block-name> is this action sub-block's name."));
57 225 : params.addParam<std::string>(
58 : "batch_index_generator_name",
59 450 : NEML2Utils::docstring(
60 : "Name of the NEML2BatchIndexGenerator user object. The default name is "
61 : "'neml2_index_<model-name>_<block-name>' where <model-name> is the NEML2 model's name, "
62 : "and <block-name> is this action sub-block's name."));
63 225 : params.addParam<std::vector<SubdomainName>>(
64 : "block",
65 : {},
66 450 : NEML2Utils::docstring("List of blocks (subdomains) where the material model is defined"));
67 225 : return params;
68 0 : }
69 :
70 22 : NEML2Action::NEML2Action(const InputParameters & params)
71 : : Action(params),
72 66 : _executor_name(isParamValid("executor_name")
73 88 : ? getParam<std::string>("executor_name")
74 44 : : "neml2_" + getParam<std::string>("model") + "_" + name()),
75 66 : _idx_generator_name(isParamValid("batch_index_generator_name")
76 88 : ? getParam<std::string>("batch_index_generator_name")
77 44 : : "neml2_index_" + getParam<std::string>("model") + "_" + name()),
78 44 : _block(getParam<std::vector<SubdomainName>>("block"))
79 : {
80 22 : NEML2Utils::assertNEML2Enabled();
81 :
82 : // Apply parameters under the common area, i.e., under [NEML2]
83 22 : const auto & all_params = _app.getInputParameterWarehouse().getInputParameters();
84 22 : auto & sub_block_params = *(all_params.find(uniqueActionName())->second.get());
85 22 : const auto & common_action = getCommonAction();
86 22 : sub_block_params.applyParameters(common_action.parameters());
87 :
88 : // Set up optional output variable initialization
89 22 : auto init_vars = getParam<std::vector<MaterialPropertyName>>("initialize_outputs");
90 22 : auto init_vals = getParam<std::vector<MaterialPropertyName>>("initialize_output_values");
91 22 : if (init_vars.size() != init_vals.size())
92 0 : paramError("initialize_outputs",
93 : "initialize_outputs should have the same length as initialize_output_values");
94 22 : for (auto i : index_range(init_vars))
95 0 : _initialize_output_values[init_vars[i]] = init_vals[i];
96 :
97 : // Set up additional outputs for each requested material property
98 22 : auto outputs = getParam<std::vector<MaterialPropertyName>>("export_outputs");
99 22 : auto output_targets = getParam<std::vector<std::vector<OutputName>>>("export_output_targets");
100 22 : if (outputs.size() != output_targets.size())
101 0 : paramError("export_outputs",
102 : "export_outputs should have the same length as export_output_targets");
103 76 : for (auto i : index_range(outputs))
104 54 : _export_output_targets[outputs[i]] = output_targets[i];
105 :
106 : #ifdef NEML2_ENABLED
107 : // File name and CLI args
108 22 : _fname = getParam<DataFileName>("input");
109 22 : _cli_args = getParam<std::vector<std::string>>("cli_args");
110 :
111 : // Load input file
112 22 : auto factory = neml2::load_input(std::string(_fname), neml2::utils::join(_cli_args, " "));
113 22 : _model = NEML2Utils::getModel(*factory, getParam<std::string>("model"));
114 : #endif
115 22 : }
116 :
117 : const NEML2ActionCommon &
118 22 : NEML2Action::getCommonAction() const
119 : {
120 22 : auto common_block = _awh.getActions<NEML2ActionCommon>();
121 : mooseAssert(common_block.size() == 1, "There must exist one and only one common NEML2 action.");
122 44 : return *common_block[0];
123 22 : }
124 :
125 : #ifndef NEML2_ENABLED
126 :
127 : void
128 0 : NEML2Action::act()
129 : {
130 0 : }
131 :
132 : #else
133 :
134 : void
135 66 : NEML2Action::act()
136 : {
137 66 : if (_current_task == "parse_neml2")
138 : {
139 22 : if (_app.parameters().have_parameter<bool>("parse_neml2_only"))
140 22 : if (!_app.parameters().get<bool>("parse_neml2_only"))
141 22 : return;
142 0 : printSummary();
143 : }
144 :
145 44 : if (_current_task == "add_user_object")
146 : {
147 22 : setupInputMappings(*_model);
148 22 : setupParameterMappings(*_model);
149 22 : setupOutputMappings(*_model);
150 22 : setupDerivativeMappings(*_model);
151 22 : setupParameterDerivativeMappings(*_model);
152 :
153 22 : printSummary();
154 :
155 : // MOOSEToNEML2 input gatherers
156 22 : std::vector<UserObjectName> gatherers;
157 57 : for (const auto & input : _inputs)
158 : {
159 35 : if (input.moose.type == MOOSEIOType::MATERIAL)
160 : {
161 26 : auto obj_name = "__moose(" + input.moose.name + ")->neml2(" +
162 39 : neml2::utils::stringify(input.neml2.name) + ")_" + name() + "__";
163 13 : if (!tensor_type_map.count(input.neml2.type))
164 0 : mooseError("NEML2 type ", input.neml2.type, " not yet mapped to MOOSE");
165 13 : auto obj_moose_type = tensor_type_map.at(input.neml2.type) + "MaterialProperty";
166 13 : if (input.neml2.name.is_old_force() || input.neml2.name.is_old_state())
167 0 : obj_moose_type = "Old" + obj_moose_type;
168 13 : auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2";
169 13 : auto obj_params = _factory.getValidParams(obj_type);
170 13 : obj_params.set<MaterialPropertyName>("from_moose") = input.moose.name;
171 13 : obj_params.set<std::string>("to_neml2") = neml2::utils::stringify(input.neml2.name);
172 13 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
173 13 : _problem->addUserObject(obj_type, obj_name, obj_params);
174 13 : gatherers.push_back(obj_name);
175 13 : }
176 22 : else if (input.moose.type == MOOSEIOType::VARIABLE)
177 : {
178 44 : auto obj_name = "__moose(" + input.moose.name + ")->neml2(" +
179 66 : neml2::utils::stringify(input.neml2.name) + ")_" + name() + "__";
180 22 : std::string obj_moose_type = "Variable";
181 22 : if (input.neml2.name.is_old_force() || input.neml2.name.is_old_state())
182 0 : obj_moose_type = "Old" + obj_moose_type;
183 22 : auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2";
184 22 : auto obj_params = _factory.getValidParams(obj_type);
185 44 : obj_params.set<std::vector<VariableName>>("from_moose") = {input.moose.name};
186 22 : obj_params.set<std::string>("to_neml2") = neml2::utils::stringify(input.neml2.name);
187 22 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
188 22 : _problem->addUserObject(obj_type, obj_name, obj_params);
189 22 : gatherers.push_back(obj_name);
190 22 : }
191 0 : else if (input.moose.type == MOOSEIOType::POSTPROCESSOR)
192 : {
193 0 : auto obj_name = "__moose(" + input.moose.name + ")->neml2(" +
194 0 : neml2::utils::stringify(input.neml2.name) + ")" + name() + "__";
195 0 : auto obj_moose_type = std::string("Postprocessor");
196 0 : if (input.neml2.name.is_old_force() || input.neml2.name.is_old_state())
197 0 : obj_moose_type = "Old" + obj_moose_type;
198 0 : auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2";
199 0 : auto obj_params = _factory.getValidParams(obj_type);
200 0 : obj_params.set<PostprocessorName>("from_moose") = input.moose.name;
201 0 : obj_params.set<std::string>("to_neml2") = neml2::utils::stringify(input.neml2.name);
202 0 : _problem->addUserObject(obj_type, obj_name, obj_params);
203 0 : gatherers.push_back(obj_name);
204 0 : }
205 : else
206 0 : paramError("moose_input_types",
207 : "Unsupported type corresponding to the moose input ",
208 0 : input.moose.name);
209 : }
210 :
211 : // MOOSEToNEML2 parameter gatherers
212 22 : std::vector<UserObjectName> param_gatherers;
213 24 : for (const auto & param : _params)
214 : {
215 2 : if (param.moose.type == MOOSEIOType::MATERIAL)
216 : {
217 : auto obj_name =
218 1 : "__moose(" + param.moose.name + ")->neml2(" + param.neml2.name + ")_" + name() + "__";
219 1 : if (!tensor_type_map.count(param.neml2.type))
220 0 : mooseError("NEML2 type ", param.neml2.type, " not yet mapped to MOOSE");
221 1 : auto obj_moose_type = tensor_type_map.at(param.neml2.type);
222 1 : auto obj_type = "MOOSE" + obj_moose_type + "MaterialPropertyToNEML2";
223 1 : auto obj_params = _factory.getValidParams(obj_type);
224 1 : obj_params.set<MaterialPropertyName>("from_moose") = param.moose.name;
225 1 : obj_params.set<std::string>("to_neml2") = param.neml2.name;
226 1 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
227 1 : _problem->addUserObject(obj_type, obj_name, obj_params);
228 1 : param_gatherers.push_back(obj_name);
229 1 : }
230 1 : else if (param.moose.type == MOOSEIOType::VARIABLE)
231 : {
232 : auto obj_name =
233 1 : "__moose(" + param.moose.name + ")->neml2(" + param.neml2.name + ")_" + name() + "__";
234 1 : auto obj_type = "MOOSEVariableToNEML2";
235 1 : auto obj_params = _factory.getValidParams(obj_type);
236 2 : obj_params.set<std::vector<VariableName>>("from_moose") = {param.moose.name};
237 1 : obj_params.set<std::string>("to_neml2") = neml2::utils::stringify(param.neml2.name);
238 1 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
239 1 : _problem->addUserObject(obj_type, obj_name, obj_params);
240 1 : param_gatherers.push_back(obj_name);
241 1 : }
242 0 : else if (param.moose.type == MOOSEIOType::POSTPROCESSOR)
243 : {
244 : auto obj_name =
245 0 : "__moose(" + param.moose.name + ")->neml2(" + param.neml2.name + ")" + name() + "__";
246 0 : auto obj_moose_type = std::string("Postprocessor");
247 0 : auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2";
248 0 : auto obj_params = _factory.getValidParams(obj_type);
249 0 : obj_params.set<PostprocessorName>("from_moose") = param.moose.name;
250 0 : obj_params.set<std::string>("to_neml2") = param.neml2.name;
251 0 : _problem->addUserObject(obj_type, obj_name, obj_params);
252 0 : param_gatherers.push_back(obj_name);
253 0 : }
254 : else
255 0 : paramError("moose_parameter_types",
256 : "Unsupported type corresponding to the moose parameter ",
257 0 : param.moose.name);
258 : }
259 :
260 : // The index generator UO
261 : {
262 22 : auto type = "NEML2BatchIndexGenerator";
263 22 : auto params = _factory.getValidParams(type);
264 22 : params.applyParameters(parameters());
265 22 : _problem->addUserObject(type, _idx_generator_name, params);
266 22 : }
267 :
268 : // The Executor UO
269 : {
270 22 : auto type = "NEML2ModelExecutor";
271 22 : auto params = _factory.getValidParams(type);
272 22 : params.applyParameters(parameters());
273 22 : params.set<UserObjectName>("batch_index_generator") = _idx_generator_name;
274 22 : params.set<std::vector<UserObjectName>>("gatherers") = gatherers;
275 22 : params.set<std::vector<UserObjectName>>("param_gatherers") = param_gatherers;
276 22 : _problem->addUserObject(type, _executor_name, params);
277 22 : }
278 22 : }
279 :
280 44 : if (_current_task == "add_material")
281 : {
282 : // NEML2ToMOOSE output retrievers
283 57 : for (const auto & output : _outputs)
284 : {
285 35 : if (output.moose.type == MOOSEIOType::MATERIAL)
286 : {
287 70 : auto obj_name = "__neml2(" + neml2::utils::stringify(output.neml2.name) + ")->moose(" +
288 70 : output.moose.name + ")_" + name() + "__";
289 35 : if (!tensor_type_map.count(output.neml2.type))
290 0 : mooseError("NEML2 type ", output.neml2.type, " not yet mapped to MOOSE");
291 35 : auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(output.neml2.type) + "MaterialProperty";
292 35 : auto obj_params = _factory.getValidParams(obj_type);
293 35 : obj_params.set<UserObjectName>("neml2_executor") = _executor_name;
294 35 : obj_params.set<MaterialPropertyName>("to_moose") = output.moose.name;
295 35 : obj_params.set<std::string>("from_neml2") = neml2::utils::stringify(output.neml2.name);
296 35 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
297 35 : if (_initialize_output_values.count(output.moose.name))
298 0 : obj_params.set<MaterialPropertyName>("moose_material_property_init") =
299 0 : _initialize_output_values[output.moose.name];
300 35 : if (_export_output_targets.count(output.moose.name))
301 66 : obj_params.set<std::vector<OutputName>>("outputs") =
302 99 : _export_output_targets[output.moose.name];
303 35 : _problem->addMaterial(obj_type, obj_name, obj_params);
304 35 : }
305 : else
306 0 : paramError("moose_output_types",
307 : "Unsupported type corresponding to the moose output ",
308 0 : output.moose.name);
309 : }
310 :
311 : // NEML2ToMOOSE derivative retrievers
312 44 : for (const auto & deriv : _derivs)
313 : {
314 22 : if (deriv.moose.type == MOOSEIOType::MATERIAL)
315 : {
316 44 : auto obj_name = "__neml2(d(" + neml2::utils::stringify(deriv.neml2.y.name) + ")/d(" +
317 66 : neml2::utils::stringify(deriv.neml2.x.name) + "))->moose(" +
318 44 : deriv.moose.name + ")_" + name() + "__";
319 22 : if (!deriv_type_map.count({deriv.neml2.y.type, deriv.neml2.x.type}))
320 0 : mooseError("NEML2 derivative type for d(",
321 0 : deriv.neml2.y.type,
322 : ")/d(",
323 0 : deriv.neml2.x.type,
324 : ") not yet mapped to MOOSE");
325 22 : auto deriv_type = deriv_type_map.at({deriv.neml2.y.type, deriv.neml2.x.type});
326 22 : if (!tensor_type_map.count(deriv_type))
327 0 : mooseError("NEML2 type ", deriv_type, " not yet mapped to MOOSE");
328 22 : auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(deriv_type) + "MaterialProperty";
329 22 : auto obj_params = _factory.getValidParams(obj_type);
330 22 : obj_params.set<UserObjectName>("neml2_executor") = _executor_name;
331 22 : obj_params.set<MaterialPropertyName>("to_moose") = deriv.moose.name;
332 22 : obj_params.set<std::string>("from_neml2") = neml2::utils::stringify(deriv.neml2.y.name);
333 44 : obj_params.set<std::string>("neml2_input_derivative") =
334 66 : neml2::utils::stringify(deriv.neml2.x.name);
335 22 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
336 22 : if (_export_output_targets.count(deriv.moose.name))
337 24 : obj_params.set<std::vector<OutputName>>("outputs") =
338 36 : _export_output_targets[deriv.moose.name];
339 22 : _problem->addMaterial(obj_type, obj_name, obj_params);
340 22 : }
341 : else
342 0 : paramError("moose_derivative_types",
343 : "Unsupported type corresponding to the moose derivative ",
344 0 : deriv.moose.name);
345 : }
346 :
347 : // NEML2ToMOOSE parameter derivative retrievers
348 22 : for (const auto & param_deriv : _param_derivs)
349 : {
350 0 : if (param_deriv.moose.type == MOOSEIOType::MATERIAL)
351 : {
352 0 : auto obj_name = "__neml2(d(" + neml2::utils::stringify(param_deriv.neml2.y.name) + ")/d(" +
353 0 : param_deriv.neml2.x.name + "))->moose(" + param_deriv.moose.name + ")_" +
354 0 : name() + "__";
355 0 : if (!deriv_type_map.count({param_deriv.neml2.y.type, param_deriv.neml2.x.type}))
356 0 : mooseError("NEML2 derivative type for d(",
357 0 : param_deriv.neml2.y.type,
358 : ")/d(",
359 0 : param_deriv.neml2.x.type,
360 : ") not yet mapped to MOOSE");
361 0 : auto deriv_type = deriv_type_map.at({param_deriv.neml2.y.type, param_deriv.neml2.x.type});
362 0 : if (!tensor_type_map.count(deriv_type))
363 0 : mooseError("NEML2 type ", deriv_type, " not yet mapped to MOOSE");
364 0 : auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(deriv_type) + "MaterialProperty";
365 0 : auto obj_params = _factory.getValidParams(obj_type);
366 0 : obj_params.set<UserObjectName>("neml2_executor") = _executor_name;
367 0 : obj_params.set<MaterialPropertyName>("to_moose") = param_deriv.moose.name;
368 0 : obj_params.set<std::string>("from_neml2") =
369 0 : neml2::utils::stringify(param_deriv.neml2.y.name);
370 0 : obj_params.set<std::string>("neml2_parameter_derivative") = param_deriv.neml2.x.name;
371 0 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
372 0 : if (_export_output_targets.count(param_deriv.moose.name))
373 0 : obj_params.set<std::vector<OutputName>>("outputs") =
374 0 : _export_output_targets[param_deriv.moose.name];
375 0 : _problem->addMaterial(obj_type, obj_name, obj_params);
376 0 : }
377 : else
378 0 : paramError("moose_parameter_derivative_types",
379 : "Unsupported type corresponding to the moose parameter derivative ",
380 0 : param_deriv.moose.name);
381 : }
382 : }
383 23 : }
384 :
385 : void
386 22 : NEML2Action::setupInputMappings(const neml2::Model & model)
387 : {
388 22 : const auto [moose_input_types, moose_inputs, neml2_inputs] =
389 : getInputParameterMapping<MOOSEIOType, std::string, std::string>(
390 22 : "moose_input_types", "moose_inputs", "neml2_inputs");
391 :
392 57 : for (auto i : index_range(moose_inputs))
393 : {
394 35 : auto neml2_input = NEML2Utils::parseVariableName(neml2_inputs[i]);
395 35 : _inputs.push_back({
396 35 : {moose_inputs[i], moose_input_types[i]},
397 35 : {neml2_input, model.input_variable(neml2_input).type()},
398 : });
399 35 : }
400 92 : }
401 :
402 : void
403 22 : NEML2Action::setupParameterMappings(const neml2::Model & model)
404 : {
405 22 : const auto [moose_param_types, moose_params, neml2_params] =
406 : getInputParameterMapping<MOOSEIOType, std::string, std::string>(
407 22 : "moose_parameter_types", "moose_parameters", "neml2_parameters");
408 :
409 24 : for (auto i : index_range(moose_params))
410 4 : _params.push_back({{moose_params[i], moose_param_types[i]},
411 2 : {neml2_params[i], model.get_parameter(neml2_params[i]).type()}});
412 26 : }
413 :
414 : void
415 22 : NEML2Action::setupOutputMappings(const neml2::Model & model)
416 : {
417 22 : const auto [moose_output_types, moose_outputs, neml2_outputs] =
418 : getInputParameterMapping<MOOSEIOType, std::string, std::string>(
419 22 : "moose_output_types", "moose_outputs", "neml2_outputs");
420 :
421 57 : for (auto i : index_range(moose_outputs))
422 : {
423 35 : auto neml2_output = NEML2Utils::parseVariableName(neml2_outputs[i]);
424 35 : _outputs.push_back({
425 35 : {moose_outputs[i], moose_output_types[i]},
426 35 : {neml2_output, model.output_variable(neml2_output).type()},
427 : });
428 35 : }
429 92 : }
430 :
431 : void
432 22 : NEML2Action::setupDerivativeMappings(const neml2::Model & model)
433 : {
434 22 : const auto [moose_deriv_types, moose_derivs, neml2_derivs] =
435 : getInputParameterMapping<MOOSEIOType, std::string, std::vector<std::string>>(
436 22 : "moose_derivative_types", "moose_derivatives", "neml2_derivatives");
437 :
438 44 : for (auto i : index_range(moose_derivs))
439 : {
440 22 : if (neml2_derivs[i].size() != 2)
441 0 : paramError("neml2_derivatives", "The length of each pair in neml2_derivatives must be 2.");
442 :
443 22 : auto neml2_y = NEML2Utils::parseVariableName(neml2_derivs[i][0]);
444 22 : auto neml2_x = NEML2Utils::parseVariableName(neml2_derivs[i][1]);
445 22 : _derivs.push_back({
446 22 : {moose_derivs[i], moose_deriv_types[i]},
447 22 : {{neml2_y, model.output_variable(neml2_y).type()},
448 22 : {neml2_x, model.input_variable(neml2_x).type()}},
449 : });
450 22 : }
451 88 : }
452 :
453 : void
454 22 : NEML2Action::setupParameterDerivativeMappings(const neml2::Model & model)
455 : {
456 22 : const auto [moose_param_deriv_types, moose_param_derivs, neml2_param_derivs] =
457 : getInputParameterMapping<MOOSEIOType, std::string, std::vector<std::string>>(
458 : "moose_parameter_derivative_types",
459 : "moose_parameter_derivatives",
460 22 : "neml2_parameter_derivatives");
461 :
462 22 : for (auto i : index_range(moose_param_derivs))
463 : {
464 0 : if (neml2_param_derivs[i].size() != 2)
465 0 : paramError("neml2_parameter_derivatives",
466 : "The length of each pair in neml2_parameter_derivatives must be 2.");
467 :
468 0 : auto neml2_y = NEML2Utils::parseVariableName(neml2_param_derivs[i][0]);
469 0 : auto neml2_x = neml2_param_derivs[i][1];
470 0 : _param_derivs.push_back({
471 0 : {moose_param_derivs[i], moose_param_deriv_types[i]},
472 0 : {{neml2_y, model.output_variable(neml2_y).type()},
473 0 : {neml2_x, model.get_parameter(neml2_x).type()}},
474 : });
475 0 : }
476 22 : }
477 :
478 : void
479 22 : NEML2Action::printSummary() const
480 : {
481 22 : if (!_app.parameters().have_parameter<bool>("parse_neml2_only"))
482 0 : return;
483 :
484 : // Save formatting of the output stream so that we can restore it later
485 22 : const auto flags = _console.flags();
486 :
487 : // Default width for the summary
488 22 : const int width = 79;
489 :
490 22 : _console << std::endl;
491 22 : _console << COLOR_CYAN << std::setw(width) << std::setfill('*') << std::left
492 22 : << "NEML2 MATERIAL MODEL SUMMARY BEGIN " << std::setfill(' ') << COLOR_DEFAULT
493 22 : << std::endl;
494 :
495 : // Metadata
496 22 : _console << "NEML2 input file location: " << fname() << std::endl;
497 22 : _console << "NEML2 action path: " << parameters().blockFullpath() << std::endl;
498 :
499 : // List inputs, outputs, and parameters of the model
500 22 : _console << COLOR_CYAN << std::setw(width) << std::setfill('-') << std::left
501 22 : << "Material model structure " << std::setfill(' ') << COLOR_DEFAULT << std::endl;
502 22 : _console << *_model;
503 :
504 : // List transfer between MOOSE and NEML2
505 22 : if (!_app.parameters().get<bool>("parse_neml2_only"))
506 : {
507 22 : _console << COLOR_CYAN << std::setw(width) << std::setfill('-') << std::left
508 22 : << "Transfer between MOOSE and NEML2 " << std::setfill(' ') << COLOR_DEFAULT
509 22 : << std::endl;
510 :
511 : // Figure out the longest name length so that we could align the arrows
512 22 : const auto max_moose_name_length = getLongestMOOSEName();
513 :
514 : // List input transfer, MOOSE -> NEML2
515 57 : for (const auto & input : _inputs)
516 : {
517 35 : _console << std::setw(max_moose_name_length) << std::right
518 70 : << (input.neml2.name.is_old_force() || input.neml2.name.is_old_state()
519 70 : ? ("(old) " + input.moose.name)
520 35 : : input.moose.name)
521 35 : << " --> " << input.neml2.name << std::endl;
522 : }
523 :
524 : // List parameter transfer, MOOSE -> NEML2
525 24 : for (const auto & param : _params)
526 2 : _console << std::setw(max_moose_name_length) << std::right << param.moose.name << " --> "
527 2 : << param.neml2.name << std::endl;
528 :
529 : // List output transfer, NEML2 -> MOOSE
530 57 : for (const auto & output : _outputs)
531 35 : _console << std::setw(max_moose_name_length) << std::right << output.moose.name << " <-- "
532 35 : << output.neml2.name << std::endl;
533 :
534 : // List derivative transfer, NEML2 -> MOOSE
535 44 : for (const auto & deriv : _derivs)
536 22 : _console << std::setw(max_moose_name_length) << std::right << deriv.moose.name << " <-- d("
537 22 : << deriv.neml2.y.name << ")/d(" << deriv.neml2.x.name << ")" << std::endl;
538 :
539 : // List parameter derivative transfer, NEML2 -> MOOSE
540 22 : for (const auto & param_deriv : _param_derivs)
541 0 : _console << std::setw(max_moose_name_length) << std::right << param_deriv.moose.name
542 0 : << " <-- d(" << param_deriv.neml2.y.name << ")/d(" << param_deriv.neml2.x.name << ")"
543 0 : << std::endl;
544 : }
545 :
546 22 : _console << COLOR_CYAN << std::setw(width) << std::setfill('*') << std::left
547 22 : << "NEML2 MATERIAL MODEL SUMMARY END " << std::setfill(' ') << COLOR_DEFAULT << std::endl
548 22 : << std::endl;
549 :
550 : // Restore the formatting of the output stream
551 22 : _console.flags(flags);
552 : }
553 :
554 : std::size_t
555 22 : NEML2Action::getLongestMOOSEName() const
556 : {
557 22 : std::size_t max_moose_name_length = 0;
558 57 : for (const auto & input : _inputs)
559 35 : max_moose_name_length =
560 70 : std::max(max_moose_name_length,
561 70 : input.neml2.name.is_old_force() || input.neml2.name.is_old_state()
562 70 : ? input.moose.name.size() + 6
563 35 : : input.moose.name.size()); // 6 is the length of "(old) "
564 24 : for (const auto & param : _params)
565 2 : max_moose_name_length = std::max(max_moose_name_length, param.moose.name.size());
566 57 : for (const auto & output : _outputs)
567 35 : max_moose_name_length = std::max(max_moose_name_length, output.moose.name.size());
568 44 : for (const auto & deriv : _derivs)
569 22 : max_moose_name_length = std::max(max_moose_name_length, deriv.moose.name.size());
570 22 : for (const auto & param_deriv : _param_derivs)
571 0 : max_moose_name_length = std::max(max_moose_name_length, param_deriv.moose.name.size());
572 22 : return max_moose_name_length;
573 : }
574 : #endif // NEML2_ENABLED
|