LCOV - code coverage report
Current view: top level - src/neml2/actions - NEML2Action.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 218 350 62.3 %
Date: 2026-05-29 20:35:17 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14