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 220 : NEML2Action::validParams()
49 : {
50 220 : InputParameters params = NEML2ActionCommon::commonParams();
51 220 : params.addClassDescription(NEML2Utils::docstring("Set up the NEML2 material model"));
52 220 : params.addParam<std::string>(
53 : "executor_name",
54 440 : 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 220 : params.addParam<std::string>(
58 : "batch_index_generator_name",
59 440 : 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 220 : params.addParam<std::vector<SubdomainName>>(
64 : "block",
65 : {},
66 440 : NEML2Utils::docstring("List of blocks (subdomains) where the material model is defined"));
67 220 : return params;
68 0 : }
69 :
70 17 : NEML2Action::NEML2Action(const InputParameters & params)
71 : : Action(params),
72 51 : _executor_name(isParamValid("executor_name")
73 68 : ? getParam<std::string>("executor_name")
74 34 : : "neml2_" + getParam<std::string>("model") + "_" + name()),
75 51 : _idx_generator_name(isParamValid("batch_index_generator_name")
76 68 : ? getParam<std::string>("batch_index_generator_name")
77 34 : : "neml2_index_" + getParam<std::string>("model") + "_" + name()),
78 34 : _block(getParam<std::vector<SubdomainName>>("block"))
79 : {
80 17 : NEML2Utils::assertNEML2Enabled();
81 :
82 : // Apply parameters under the common area, i.e., under [NEML2]
83 17 : const auto & all_params = _app.getInputParameterWarehouse().getInputParameters();
84 17 : auto & sub_block_params = *(all_params.find(uniqueActionName())->second.get());
85 17 : const auto & common_action = getCommonAction();
86 17 : sub_block_params.applyParameters(common_action.parameters());
87 :
88 : // Set up optional output variable initialization
89 17 : auto init_vars = getParam<std::vector<MaterialPropertyName>>("initialize_outputs");
90 17 : auto init_vals = getParam<std::vector<MaterialPropertyName>>("initialize_output_values");
91 17 : 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 17 : 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 17 : auto outputs = getParam<std::vector<MaterialPropertyName>>("export_outputs");
99 17 : auto output_targets = getParam<std::vector<std::vector<OutputName>>>("export_output_targets");
100 17 : if (outputs.size() != output_targets.size())
101 0 : paramError("export_outputs",
102 : "export_outputs should have the same length as export_output_targets");
103 61 : for (auto i : index_range(outputs))
104 44 : _export_output_targets[outputs[i]] = output_targets[i];
105 :
106 : #ifdef NEML2_ENABLED
107 : // File name and CLI args
108 17 : _fname = getParam<DataFileName>("input");
109 17 : _cli_args = getParam<std::vector<std::string>>("cli_args");
110 :
111 : // Load input file
112 17 : auto factory = neml2::load_input(std::string(_fname), neml2::utils::join(_cli_args, " "));
113 17 : _model = NEML2Utils::getModel(*factory, getParam<std::string>("model"));
114 : #endif
115 17 : }
116 :
117 : const NEML2ActionCommon &
118 17 : NEML2Action::getCommonAction() const
119 : {
120 17 : auto common_block = _awh.getActions<NEML2ActionCommon>();
121 : mooseAssert(common_block.size() == 1, "There must exist one and only one common NEML2 action.");
122 34 : return *common_block[0];
123 17 : }
124 :
125 : #ifndef NEML2_ENABLED
126 :
127 : void
128 0 : NEML2Action::act()
129 : {
130 0 : }
131 :
132 : #else
133 :
134 : void
135 51 : NEML2Action::act()
136 : {
137 51 : if (_current_task == "parse_neml2")
138 : {
139 17 : if (_app.parameters().have_parameter<bool>("parse_neml2_only"))
140 17 : if (!_app.parameters().get<bool>("parse_neml2_only"))
141 17 : return;
142 0 : printSummary();
143 : }
144 :
145 34 : if (_current_task == "add_user_object")
146 : {
147 17 : setupInputMappings(*_model);
148 17 : setupParameterMappings(*_model);
149 17 : setupOutputMappings(*_model);
150 17 : setupDerivativeMappings(*_model);
151 17 : setupParameterDerivativeMappings(*_model);
152 :
153 17 : printSummary();
154 :
155 : // MOOSEToNEML2 input gatherers
156 17 : std::vector<UserObjectName> gatherers;
157 47 : for (const auto & input : _inputs)
158 : {
159 30 : 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 17 : else if (input.moose.type == MOOSEIOType::VARIABLE)
177 : {
178 34 : auto obj_name = "__moose(" + input.moose.name + ")->neml2(" +
179 51 : neml2::utils::stringify(input.neml2.name) + ")_" + name() + "__";
180 17 : std::string obj_moose_type = "Variable";
181 17 : if (input.neml2.name.is_old_force() || input.neml2.name.is_old_state())
182 0 : obj_moose_type = "Old" + obj_moose_type;
183 17 : auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2";
184 17 : auto obj_params = _factory.getValidParams(obj_type);
185 34 : obj_params.set<std::vector<VariableName>>("from_moose") = {input.moose.name};
186 17 : obj_params.set<std::string>("to_neml2") = neml2::utils::stringify(input.neml2.name);
187 17 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
188 17 : _problem->addUserObject(obj_type, obj_name, obj_params);
189 17 : gatherers.push_back(obj_name);
190 17 : }
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 17 : std::vector<UserObjectName> param_gatherers;
213 19 : 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 17 : auto type = "NEML2BatchIndexGenerator";
263 17 : auto params = _factory.getValidParams(type);
264 17 : params.applyParameters(parameters());
265 17 : _problem->addUserObject(type, _idx_generator_name, params);
266 17 : }
267 :
268 : // The Executor UO
269 : {
270 17 : auto type = "NEML2ModelExecutor";
271 17 : auto params = _factory.getValidParams(type);
272 17 : params.applyParameters(parameters());
273 17 : params.set<UserObjectName>("batch_index_generator") = _idx_generator_name;
274 17 : params.set<std::vector<UserObjectName>>("gatherers") = gatherers;
275 17 : params.set<std::vector<UserObjectName>>("param_gatherers") = param_gatherers;
276 17 : _problem->addUserObject(type, _executor_name, params);
277 17 : }
278 17 : }
279 :
280 34 : if (_current_task == "add_material")
281 : {
282 : // NEML2ToMOOSE output retrievers
283 47 : for (const auto & output : _outputs)
284 : {
285 30 : if (output.moose.type == MOOSEIOType::MATERIAL)
286 : {
287 60 : auto obj_name = "__neml2(" + neml2::utils::stringify(output.neml2.name) + ")->moose(" +
288 60 : output.moose.name + ")_" + name() + "__";
289 30 : if (!tensor_type_map.count(output.neml2.type))
290 0 : mooseError("NEML2 type ", output.neml2.type, " not yet mapped to MOOSE");
291 30 : auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(output.neml2.type) + "MaterialProperty";
292 30 : auto obj_params = _factory.getValidParams(obj_type);
293 30 : obj_params.set<UserObjectName>("neml2_executor") = _executor_name;
294 30 : obj_params.set<MaterialPropertyName>("to_moose") = output.moose.name;
295 30 : obj_params.set<std::string>("from_neml2") = neml2::utils::stringify(output.neml2.name);
296 30 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
297 30 : 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 30 : if (_export_output_targets.count(output.moose.name))
301 56 : obj_params.set<std::vector<OutputName>>("outputs") =
302 84 : _export_output_targets[output.moose.name];
303 30 : _problem->addMaterial(obj_type, obj_name, obj_params);
304 30 : }
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 34 : for (const auto & deriv : _derivs)
313 : {
314 17 : if (deriv.moose.type == MOOSEIOType::MATERIAL)
315 : {
316 34 : auto obj_name = "__neml2(d(" + neml2::utils::stringify(deriv.neml2.y.name) + ")/d(" +
317 51 : neml2::utils::stringify(deriv.neml2.x.name) + "))->moose(" +
318 34 : deriv.moose.name + ")_" + name() + "__";
319 17 : 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 17 : auto deriv_type = deriv_type_map.at({deriv.neml2.y.type, deriv.neml2.x.type});
326 17 : if (!tensor_type_map.count(deriv_type))
327 0 : mooseError("NEML2 type ", deriv_type, " not yet mapped to MOOSE");
328 17 : auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(deriv_type) + "MaterialProperty";
329 17 : auto obj_params = _factory.getValidParams(obj_type);
330 17 : obj_params.set<UserObjectName>("neml2_executor") = _executor_name;
331 17 : obj_params.set<MaterialPropertyName>("to_moose") = deriv.moose.name;
332 17 : obj_params.set<std::string>("from_neml2") = neml2::utils::stringify(deriv.neml2.y.name);
333 34 : obj_params.set<std::string>("neml2_input_derivative") =
334 51 : neml2::utils::stringify(deriv.neml2.x.name);
335 17 : obj_params.set<std::vector<SubdomainName>>("block") = _block;
336 17 : 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 17 : _problem->addMaterial(obj_type, obj_name, obj_params);
340 17 : }
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 17 : 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 18 : }
384 :
385 : void
386 17 : NEML2Action::setupInputMappings(const neml2::Model & model)
387 : {
388 17 : const auto [moose_input_types, moose_inputs, neml2_inputs] =
389 : getInputParameterMapping<MOOSEIOType, std::string, std::string>(
390 17 : "moose_input_types", "moose_inputs", "neml2_inputs");
391 :
392 47 : for (auto i : index_range(moose_inputs))
393 : {
394 30 : auto neml2_input = NEML2Utils::parseVariableName(neml2_inputs[i]);
395 30 : _inputs.push_back({
396 30 : {moose_inputs[i], moose_input_types[i]},
397 30 : {neml2_input, model.input_variable(neml2_input).type()},
398 : });
399 30 : }
400 77 : }
401 :
402 : void
403 17 : NEML2Action::setupParameterMappings(const neml2::Model & model)
404 : {
405 17 : const auto [moose_param_types, moose_params, neml2_params] =
406 : getInputParameterMapping<MOOSEIOType, std::string, std::string>(
407 17 : "moose_parameter_types", "moose_parameters", "neml2_parameters");
408 :
409 19 : 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 21 : }
413 :
414 : void
415 17 : NEML2Action::setupOutputMappings(const neml2::Model & model)
416 : {
417 17 : const auto [moose_output_types, moose_outputs, neml2_outputs] =
418 : getInputParameterMapping<MOOSEIOType, std::string, std::string>(
419 17 : "moose_output_types", "moose_outputs", "neml2_outputs");
420 :
421 47 : for (auto i : index_range(moose_outputs))
422 : {
423 30 : auto neml2_output = NEML2Utils::parseVariableName(neml2_outputs[i]);
424 30 : _outputs.push_back({
425 30 : {moose_outputs[i], moose_output_types[i]},
426 30 : {neml2_output, model.output_variable(neml2_output).type()},
427 : });
428 30 : }
429 77 : }
430 :
431 : void
432 17 : NEML2Action::setupDerivativeMappings(const neml2::Model & model)
433 : {
434 17 : const auto [moose_deriv_types, moose_derivs, neml2_derivs] =
435 : getInputParameterMapping<MOOSEIOType, std::string, std::vector<std::string>>(
436 17 : "moose_derivative_types", "moose_derivatives", "neml2_derivatives");
437 :
438 34 : for (auto i : index_range(moose_derivs))
439 : {
440 17 : if (neml2_derivs[i].size() != 2)
441 0 : paramError("neml2_derivatives", "The length of each pair in neml2_derivatives must be 2.");
442 :
443 17 : auto neml2_y = NEML2Utils::parseVariableName(neml2_derivs[i][0]);
444 17 : auto neml2_x = NEML2Utils::parseVariableName(neml2_derivs[i][1]);
445 17 : _derivs.push_back({
446 17 : {moose_derivs[i], moose_deriv_types[i]},
447 17 : {{neml2_y, model.output_variable(neml2_y).type()},
448 17 : {neml2_x, model.input_variable(neml2_x).type()}},
449 : });
450 17 : }
451 68 : }
452 :
453 : void
454 17 : NEML2Action::setupParameterDerivativeMappings(const neml2::Model & model)
455 : {
456 17 : 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 17 : "neml2_parameter_derivatives");
461 :
462 17 : 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 17 : }
477 :
478 : void
479 17 : NEML2Action::printSummary() const
480 : {
481 17 : 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 17 : const auto flags = _console.flags();
486 :
487 : // Default width for the summary
488 17 : const int width = 79;
489 :
490 17 : _console << std::endl;
491 17 : _console << COLOR_CYAN << std::setw(width) << std::setfill('*') << std::left
492 17 : << "NEML2 MATERIAL MODEL SUMMARY BEGIN " << std::setfill(' ') << COLOR_DEFAULT
493 17 : << std::endl;
494 :
495 : // Metadata
496 17 : _console << "NEML2 input file location: " << fname() << std::endl;
497 17 : _console << "NEML2 action path: " << parameters().blockFullpath() << std::endl;
498 :
499 : // List inputs, outputs, and parameters of the model
500 17 : _console << COLOR_CYAN << std::setw(width) << std::setfill('-') << std::left
501 17 : << "Material model structure " << std::setfill(' ') << COLOR_DEFAULT << std::endl;
502 17 : _console << *_model;
503 :
504 : // List transfer between MOOSE and NEML2
505 17 : if (!_app.parameters().get<bool>("parse_neml2_only"))
506 : {
507 17 : _console << COLOR_CYAN << std::setw(width) << std::setfill('-') << std::left
508 17 : << "Transfer between MOOSE and NEML2 " << std::setfill(' ') << COLOR_DEFAULT
509 17 : << std::endl;
510 :
511 : // Figure out the longest name length so that we could align the arrows
512 17 : const auto max_moose_name_length = getLongestMOOSEName();
513 :
514 : // List input transfer, MOOSE -> NEML2
515 47 : for (const auto & input : _inputs)
516 : {
517 30 : _console << std::setw(max_moose_name_length) << std::right
518 60 : << (input.neml2.name.is_old_force() || input.neml2.name.is_old_state()
519 60 : ? ("(old) " + input.moose.name)
520 30 : : input.moose.name)
521 30 : << " --> " << input.neml2.name << std::endl;
522 : }
523 :
524 : // List parameter transfer, MOOSE -> NEML2
525 19 : 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 47 : for (const auto & output : _outputs)
531 30 : _console << std::setw(max_moose_name_length) << std::right << output.moose.name << " <-- "
532 30 : << output.neml2.name << std::endl;
533 :
534 : // List derivative transfer, NEML2 -> MOOSE
535 34 : for (const auto & deriv : _derivs)
536 17 : _console << std::setw(max_moose_name_length) << std::right << deriv.moose.name << " <-- d("
537 17 : << deriv.neml2.y.name << ")/d(" << deriv.neml2.x.name << ")" << std::endl;
538 :
539 : // List parameter derivative transfer, NEML2 -> MOOSE
540 17 : 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 17 : _console << COLOR_CYAN << std::setw(width) << std::setfill('*') << std::left
547 17 : << "NEML2 MATERIAL MODEL SUMMARY END " << std::setfill(' ') << COLOR_DEFAULT << std::endl
548 17 : << std::endl;
549 :
550 : // Restore the formatting of the output stream
551 17 : _console.flags(flags);
552 : }
553 :
554 : std::size_t
555 17 : NEML2Action::getLongestMOOSEName() const
556 : {
557 17 : std::size_t max_moose_name_length = 0;
558 47 : for (const auto & input : _inputs)
559 30 : max_moose_name_length =
560 60 : std::max(max_moose_name_length,
561 60 : input.neml2.name.is_old_force() || input.neml2.name.is_old_state()
562 60 : ? input.moose.name.size() + 6
563 30 : : input.moose.name.size()); // 6 is the length of "(old) "
564 19 : for (const auto & param : _params)
565 2 : max_moose_name_length = std::max(max_moose_name_length, param.moose.name.size());
566 47 : for (const auto & output : _outputs)
567 30 : max_moose_name_length = std::max(max_moose_name_length, output.moose.name.size());
568 34 : for (const auto & deriv : _derivs)
569 17 : max_moose_name_length = std::max(max_moose_name_length, deriv.moose.name.size());
570 17 : 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 17 : return max_moose_name_length;
573 : }
574 : #endif // NEML2_ENABLED
|