LCOV - code coverage report
Current view: top level - src/actions - MaterialOutputAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31761 (28487c) with base 701993 Lines: 226 237 95.4 %
Date: 2025-11-11 13:51:07 Functions: 6 6 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             : // MOOSE includes
      11             : #include "MaterialOutputAction.h"
      12             : #include "FEProblem.h"
      13             : #include "FEProblemBase.h"
      14             : #include "MooseApp.h"
      15             : #include "AddOutputAction.h"
      16             : #include "MaterialBase.h"
      17             : #include "RankTwoTensor.h"
      18             : #include "SymmetricRankTwoTensor.h"
      19             : #include "RankFourTensor.h"
      20             : #include "SymmetricRankFourTensor.h"
      21             : #include "MooseEnum.h"
      22             : #include "MooseVariableConstMonomial.h"
      23             : #include "FunctorMaterial.h"
      24             : #include "VariableSizeMaterialPropertiesInterface.h"
      25             : 
      26             : #include "libmesh/utility.h"
      27             : 
      28             : registerMooseAction("MooseApp", MaterialOutputAction, "add_output_aux_variables");
      29             : registerMooseAction("MooseApp", MaterialOutputAction, "add_aux_kernel");
      30             : 
      31             : InputParameters
      32       69547 : MaterialOutputAction::validParams()
      33             : {
      34       69547 :   InputParameters params = Action::validParams();
      35      139094 :   params.addClassDescription("Outputs material properties to various Outputs objects, based on the "
      36             :                              "parameters set in each Material");
      37      208641 :   params.addParam<bool>(
      38             :       "print_unsupported_prop_names",
      39      139094 :       true,
      40             :       "Flag to tell this action whether or not to print the unsupported properties.");
      41      139094 :   params.addParam<bool>("print_automatic_aux_variable_creation",
      42      139094 :                         true,
      43             :                         "Flag to print list of aux variables created for automatic output by "
      44             :                         "MaterialOutputAction.");
      45       69547 :   return params;
      46           0 : }
      47             : 
      48       69342 : MaterialOutputAction::MaterialOutputAction(const InputParameters & params)
      49             :   : Action(params),
      50       69342 :     _block_material_data(nullptr),
      51       69342 :     _boundary_material_data(nullptr),
      52       69342 :     _output_warehouse(_app.getOutputWarehouse()),
      53      138684 :     _output_only_on_timestep_end(_app.parameters().get<bool>("use_legacy_material_output"))
      54             : {
      55       69342 : }
      56             : 
      57             : void
      58      126740 : MaterialOutputAction::act()
      59             : {
      60             :   mooseAssert(_problem,
      61             :               "FEProblemBase pointer is nullptr, it is needed for auto material property output");
      62             : 
      63             :   // Do nothing if the application does not have output
      64      380220 :   if (!_app.actionWarehouse().hasActions("add_output"))
      65           0 :     return;
      66             : 
      67      126740 :   bool get_names_only = _current_task == "add_output_aux_variables" ? true : false;
      68             : 
      69             :   // Set the pointers to the MaterialData objects (Note, these pointers are not available at
      70             :   // construction)
      71      126740 :   _block_material_data = &_problem->getMaterialData(Moose::BLOCK_MATERIAL_DATA);
      72      126740 :   _boundary_material_data = &_problem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA);
      73             : 
      74             :   // A complete list of all MaterialBase objects
      75      126740 :   const auto & material_ptrs = _problem->getMaterialWarehouse().getObjects();
      76             : 
      77             :   // Handle setting of material property output in [Outputs] sub-blocks
      78             :   // Output objects can enable material property output, the following code examines the parameters
      79             :   // for each Output object and sets a flag if any Output object has output set and also builds a
      80             :   // list if the
      81             :   // properties are limited via the 'show_material_properties' parameters
      82      126740 :   bool outputs_has_properties = false;
      83      126740 :   std::set<std::string> output_object_properties;
      84             : 
      85      253480 :   const auto & output_actions = _app.actionWarehouse().getActionListByName("add_output");
      86      748894 :   for (const auto & act : output_actions)
      87             :   {
      88             :     // Extract the Output action
      89      622154 :     AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
      90      622154 :     if (!action)
      91      130348 :       continue;
      92             : 
      93             :     // Add the material property names from the output object parameters to the list of properties
      94             :     // to output
      95      491806 :     InputParameters & params = action->getObjectParams();
      96     2044932 :     if (params.isParamValid("output_material_properties") &&
      97      569514 :         params.get<bool>("output_material_properties"))
      98             :     {
      99         134 :       outputs_has_properties = true;
     100             :       std::vector<std::string> prop_names =
     101         134 :           params.get<std::vector<std::string>>("show_material_properties");
     102         134 :       output_object_properties.insert(prop_names.begin(), prop_names.end());
     103         134 :     }
     104             :   }
     105             : 
     106             :   // Loop through each material object
     107      126740 :   std::set<std::string> material_names;
     108      126740 :   std::set<std::string> unsupported_names;
     109      157032 :   for (const auto & mat : material_ptrs)
     110             :   {
     111             :     // Extract the names of the output objects to which the material properties will be exported
     112       30296 :     std::set<OutputName> outputs = mat->getOutputs();
     113             : 
     114             :     // Extract the property names that will actually be output
     115             :     std::vector<std::string> output_properties =
     116       60592 :         mat->getParam<std::vector<std::string>>("output_properties");
     117             : 
     118             :     // Append the properties listed in the Outputs block
     119       30296 :     if (outputs_has_properties)
     120         160 :       output_properties.insert(output_properties.end(),
     121             :                                output_object_properties.begin(),
     122             :                                output_object_properties.end());
     123             : 
     124             :     // Clear the list of variable names for the current material object, this list will be populated
     125             :     // with all the
     126             :     // variables names for the current material object and is needed for purposes of controlling the
     127             :     // which output objects
     128             :     // show the material property data
     129       30296 :     _material_variable_names.clear();
     130             : 
     131             :     // Create necessary outputs for the properties if:
     132             :     //   (1) The Outputs block has material output enabled
     133             :     //   (2) If the MaterialBase object itself has set the 'outputs' parameter
     134       30296 :     if (outputs_has_properties || outputs.find("none") == outputs.end())
     135             :     {
     136             :       // Get all material properties supplied by this material as a starting point
     137        4626 :       std::set<std::string> names = mat->getSuppliedItems();
     138        4626 :       if (const auto fmat_ptr = dynamic_cast<const FunctorMaterial *>(mat.get()))
     139         104 :         names.insert(fmat_ptr->getSuppliedFunctors().begin(),
     140         104 :                      fmat_ptr->getSuppliedFunctors().end());
     141             : 
     142       18386 :       for (const auto & name : names)
     143             :       {
     144             :         // Output the property only if the name is contained in the 'output_properties'
     145             :         // list or if the list is empty (all properties)
     146       18650 :         if (output_properties.empty() ||
     147        4890 :             std::find(output_properties.begin(), output_properties.end(), name) !=
     148       18650 :                 output_properties.end())
     149             :         {
     150             :           // Add the material property for output
     151       10798 :           auto curr_material_names = materialOutput(name, *mat, get_names_only);
     152       10798 :           if (curr_material_names.size() == 0)
     153          80 :             unsupported_names.insert(name);
     154       10798 :           material_names.insert(curr_material_names.begin(), curr_material_names.end());
     155       10798 :         }
     156             :       }
     157             :       // If the material object has explicitly defined outputs, store the variables associated with
     158             :       // the output objects
     159        4626 :       if (outputs.find("none") == outputs.end())
     160             :       {
     161             :         // Get all available output names from OutputWarehouse that support material output
     162        4466 :         const auto & all_output_names = _output_warehouse.getAllMaterialPropertyOutputNames();
     163             : 
     164             :         // For reserved name "all", set outputs to match all available output names
     165        4466 :         if (outputs.find("all") != outputs.end())
     166        2086 :           outputs = all_output_names;
     167             : 
     168             :         // Iterate through all available output names and update _material_variable_names_map
     169             :         // based on which of these output names are found in 'outputs' parameter
     170        8856 :         for (const auto & output_name : all_output_names)
     171             :         {
     172        4390 :           if (outputs.find(output_name) != outputs.end())
     173        3075 :             _material_variable_names_map[output_name].insert(_material_variable_names.begin(),
     174             :                                                              _material_variable_names.end());
     175             :           else
     176        1315 :             _material_variable_names_map[output_name].insert({});
     177             :         }
     178        4466 :       }
     179        4626 :     }
     180       25670 :     else if (output_properties.size())
     181          82 :       mooseWarning("Material properties output specified is not created because 'outputs' is not "
     182             :                    "set in the Material, and neither is output_material_properties in any of the "
     183             :                    "outputs in the [Outputs] block");
     184       30292 :   }
     185      126776 :   if (unsupported_names.size() > 0 && get_names_only &&
     186      126856 :       getParam<bool>("print_unsupported_prop_names"))
     187             :   {
     188          30 :     std::ostringstream oss;
     189          60 :     for (const auto & name : unsupported_names)
     190          30 :       oss << "\n  " << name;
     191          60 :     mooseWarning("The types for total ",
     192          30 :                  unsupported_names.size(),
     193             :                  " material properties:",
     194          60 :                  oss.str(),
     195             :                  "\nare not supported for automatic output by ",
     196          30 :                  type(),
     197             :                  ".");
     198          30 :   }
     199             : 
     200      126736 :   if (_current_task == "add_output_aux_variables")
     201             :   {
     202      190578 :     auto params = _factory.getValidParams("MooseVariableConstMonomial");
     203             :     // currently only elemental variables are supported for material property output
     204      254104 :     params.set<MooseEnum>("order") = "CONSTANT";
     205      190578 :     params.set<MooseEnum>("family") = "MONOMIAL";
     206             : 
     207             :     // Create the AuxVariables
     208       63526 :     std::ostringstream oss;
     209       93769 :     for (const auto & var_name : material_names)
     210             :     {
     211       30247 :       oss << "\n  " << var_name;
     212       30247 :       if (_problem->hasVariable(var_name))
     213           4 :         mooseError("The material property output " + var_name +
     214             :                    " has the same name as an existing variable, either use the material"
     215             :                    " declare_suffix parameter to disambiguate or the output_properties parameter"
     216             :                    " to restrict the material properties to output");
     217       90729 :       _problem->addAuxVariable("MooseVariableConstMonomial", var_name, params);
     218             :     }
     219             : 
     220       66424 :     if (material_names.size() > 0 && getParam<bool>("print_automatic_aux_variable_creation"))
     221        1441 :       _console << COLOR_CYAN << "The following total " << material_names.size()
     222        2882 :                << " aux variables:" << oss.str() << "\nare added for automatic output by " << type()
     223        1441 :                << "." << COLOR_DEFAULT << std::endl;
     224       63522 :   }
     225             :   else
     226             :   {
     227             :     // When a MaterialBase object has 'output_properties' defined all other properties not listed
     228             :     // must be added to the hide list for the output objects so that properties that are not desired
     229             :     // do not appear.
     230       65954 :     for (const auto & it : _material_variable_names_map)
     231             :     {
     232        2744 :       std::set<std::string> hide;
     233        2744 :       std::set_difference(material_names.begin(),
     234             :                           material_names.end(),
     235             :                           it.second.begin(),
     236             :                           it.second.end(),
     237             :                           std::inserter(hide, hide.begin()));
     238             : 
     239        2744 :       _output_warehouse.addInterfaceHideVariables(it.first, hide);
     240        2744 :     }
     241             :   }
     242      126732 : }
     243             : 
     244             : std::vector<std::string>
     245       10798 : MaterialOutputAction::materialOutput(const std::string & property_name,
     246             :                                      const MaterialBase & material,
     247             :                                      bool get_names_only)
     248             : {
     249       10798 :   std::vector<std::string> names;
     250             : 
     251             :   // Material Properties
     252       10798 :   if (hasProperty<Real>(property_name))
     253       10492 :     names = outputHelper(
     254        5246 :         {"MaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
     255             : 
     256        5552 :   else if (hasADProperty<Real>(property_name))
     257        4636 :     names = outputHelper(
     258        2318 :         {"ADMaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
     259             : 
     260        3234 :   else if (hasProperty<RealVectorValue>(property_name))
     261         706 :     names = outputHelper({"MaterialRealVectorValueAux", "xyz", {"component"}},
     262             :                          property_name,
     263        1412 :                          property_name + "_",
     264             :                          material,
     265         706 :                          get_names_only);
     266             : 
     267        2528 :   else if (hasADProperty<RealVectorValue>(property_name))
     268         208 :     names = outputHelper({"ADMaterialRealVectorValueAux", "xyz", {"component"}},
     269             :                          property_name,
     270         416 :                          property_name + "_",
     271             :                          material,
     272         208 :                          get_names_only);
     273             : 
     274        2320 :   else if (hasProperty<std::vector<Real>>(property_name))
     275         158 :     names = outputHelper({"MaterialStdVectorAux", "variable_size", {"index"}},
     276             :                          property_name,
     277         316 :                          property_name + "_",
     278             :                          material,
     279         158 :                          get_names_only);
     280             : 
     281        2162 :   else if (hasADProperty<std::vector<Real>>(property_name))
     282          52 :     names = outputHelper({"ADMaterialStdVectorAux", "variable_size", {"index"}},
     283             :                          property_name,
     284         104 :                          property_name + "_",
     285             :                          material,
     286          52 :                          get_names_only);
     287             : 
     288        2110 :   else if (hasProperty<RealTensorValue>(property_name))
     289         472 :     names = outputHelper({"MaterialRealTensorValueAux", "012", {"row", "column"}},
     290             :                          property_name,
     291         944 :                          property_name + "_",
     292             :                          material,
     293         472 :                          get_names_only);
     294             : 
     295        1638 :   else if (hasADProperty<RealTensorValue>(property_name))
     296          26 :     names = outputHelper({"ADMaterialRealTensorValueAux", "012", {"row", "column"}},
     297             :                          property_name,
     298          52 :                          property_name + "_",
     299             :                          material,
     300          26 :                          get_names_only);
     301             : 
     302        1612 :   else if (hasProperty<RankTwoTensor>(property_name))
     303         364 :     names = outputHelper({"MaterialRankTwoTensorAux", "012", {"i", "j"}},
     304             :                          property_name,
     305         728 :                          property_name + "_",
     306             :                          material,
     307         364 :                          get_names_only);
     308             : 
     309        1248 :   else if (hasADProperty<RankTwoTensor>(property_name))
     310          78 :     names = outputHelper({"ADMaterialRankTwoTensorAux", "012", {"i", "j"}},
     311             :                          property_name,
     312         156 :                          property_name + "_",
     313             :                          material,
     314          78 :                          get_names_only);
     315             : 
     316        1170 :   else if (hasProperty<RankFourTensor>(property_name))
     317         312 :     names = outputHelper({"MaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
     318             :                          property_name,
     319         624 :                          property_name + "_",
     320             :                          material,
     321         312 :                          get_names_only);
     322             : 
     323         858 :   else if (hasADProperty<RankFourTensor>(property_name))
     324          26 :     names = outputHelper({"ADMaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
     325             :                          property_name,
     326          52 :                          property_name + "_",
     327             :                          material,
     328          26 :                          get_names_only);
     329             : 
     330         832 :   else if (hasProperty<SymmetricRankTwoTensor>(property_name))
     331         338 :     names = outputHelper({"MaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
     332             :                          property_name,
     333         676 :                          property_name + "_",
     334             :                          material,
     335         338 :                          get_names_only);
     336             : 
     337         494 :   else if (hasADProperty<SymmetricRankTwoTensor>(property_name))
     338          52 :     names = outputHelper({"ADMaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
     339             :                          property_name,
     340         104 :                          property_name + "_",
     341             :                          material,
     342          52 :                          get_names_only);
     343             : 
     344         442 :   else if (hasProperty<SymmetricRankFourTensor>(property_name))
     345         312 :     names = outputHelper({"MaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
     346             :                          property_name,
     347         624 :                          property_name + "_",
     348             :                          material,
     349         312 :                          get_names_only);
     350             : 
     351         130 :   else if (hasADProperty<SymmetricRankFourTensor>(property_name))
     352          26 :     names = outputHelper({"ADMaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
     353             :                          property_name,
     354          52 :                          property_name + "_",
     355             :                          material,
     356          26 :                          get_names_only);
     357             : 
     358             :   // Functors
     359         104 :   else if (hasFunctorProperty<Real>(property_name))
     360          52 :     names = outputHelper({"FunctorMaterialRealAux", "", {}},
     361             :                          property_name,
     362         104 :                          property_name + "_out",
     363             :                          material,
     364          52 :                          get_names_only);
     365             : 
     366          52 :   else if (hasFunctorProperty<ADReal>(property_name))
     367           0 :     names = outputHelper({"ADFunctorMaterialRealAux", "", {}},
     368             :                          property_name,
     369           0 :                          property_name + "_out",
     370             :                          material,
     371           0 :                          get_names_only);
     372             : 
     373          52 :   else if (hasFunctorProperty<RealVectorValue>(property_name))
     374          52 :     names = outputHelper({"FunctorMaterialRealVectorValueAux", "xyz", {"component"}},
     375             :                          property_name,
     376         104 :                          property_name + "_out_",
     377             :                          material,
     378          52 :                          get_names_only);
     379             : 
     380           0 :   else if (hasFunctorProperty<ADRealVectorValue>(property_name))
     381           0 :     names = outputHelper({"ADFunctorMaterialRealVectorValueAux", "xyz", {"component"}},
     382             :                          property_name,
     383           0 :                          property_name + "_out_",
     384             :                          material,
     385           0 :                          get_names_only);
     386             : 
     387       10798 :   return names;
     388       35576 : }
     389             : 
     390             : std::vector<std::string>
     391       10798 : MaterialOutputAction::outputHelper(const MaterialOutputAction::OutputMetaData & metadata,
     392             :                                    const std::string & property_name,
     393             :                                    const std::string & var_name_base,
     394             :                                    const MaterialBase & material,
     395             :                                    bool get_names_only)
     396             : {
     397       10798 :   const auto & [kernel_name, index_symbols, param_names] = metadata;
     398       10798 :   const auto dim = param_names.size();
     399       10798 :   const auto size = index_symbols.size();
     400       10798 :   auto size_inner = size;
     401             : 
     402             :   // Handle the case the material property is of a variable input-defined size
     403       10798 :   bool variable_size = false;
     404       10798 :   if (index_symbols == "variable_size")
     405             :   {
     406         210 :     variable_size = true;
     407         210 :     size_inner = 0;
     408         210 :     const auto * const vsmi =
     409         210 :         dynamic_cast<const VariableSizeMaterialPropertiesInterface *>(&material);
     410         210 :     if (vsmi)
     411         130 :       size_inner = vsmi->getVectorPropertySize(property_name);
     412             : 
     413         210 :     if (!size_inner)
     414             :     {
     415          80 :       mooseWarning("Vector material property '" + property_name + "' will not be output as we " +
     416             :                    (vsmi ? "have a 0-size vector during the simulation setup."
     417             :                          : "do not know the size of the vector at initialization. Add the "
     418             :                            "'VariableSizeMaterialPropertiesInterface' as a base class of the "
     419             :                            "Material defining the vector property and implement the "
     420             :                            "get...Size(property_name) routine. Note that "
     421             :                            "the size must be known during the simulation setup phase."));
     422          80 :       return {};
     423             :     }
     424             :   }
     425             : 
     426       10718 :   std::vector<std::string> names;
     427             :   // general 0 to 4 dimensional loop
     428             :   std::array<std::size_t, 4> i;
     429       22112 :   for (i[3] = 0; i[3] < (dim < 4 ? 1 : size); ++i[3])
     430       24816 :     for (i[2] = 0; i[2] < (dim < 3 ? 1 : size); ++i[2])
     431       36498 :       for (i[1] = 0; i[1] < (dim < 2 ? 1 : size); ++i[1])
     432       84508 :         for (i[0] = 0; i[0] < (dim < 1 ? 1 : size_inner); ++i[0])
     433             :         {
     434       61432 :           std::string var_name = var_name_base;
     435      218010 :           for (const auto j : make_range(dim))
     436      156578 :             if (variable_size)
     437         572 :               var_name += Moose::stringify(i[j]);
     438             :             else
     439      156006 :               var_name += Moose::stringify(index_symbols[i[j]]);
     440             : 
     441       61432 :           names.push_back(var_name);
     442             : 
     443       61432 :           if (!get_names_only)
     444             :           {
     445       30690 :             auto params = getParams(kernel_name, property_name, var_name, material);
     446      108937 :             for (const auto j : make_range(dim))
     447       78247 :               params.template set<unsigned int>(param_names[j]) = i[j];
     448       30690 :             _problem->addAuxKernel(kernel_name, material.name() + "_" + var_name, params);
     449       30690 :           }
     450       61432 :         }
     451       10718 :   return names;
     452       10718 : }
     453             : 
     454             : InputParameters
     455       30690 : MaterialOutputAction::getParams(const std::string & type,
     456             :                                 const std::string & property_name,
     457             :                                 const std::string & variable_name,
     458             :                                 const MaterialBase & material)
     459             : {
     460             :   // Append the list of output variables for the current material
     461       30690 :   _material_variable_names.insert(variable_name);
     462             : 
     463             :   // Set the action parameters
     464       30690 :   InputParameters params = _factory.getValidParams(type);
     465       30690 :   if (params.have_parameter<MaterialPropertyName>("property"))
     466       91758 :     params.set<MaterialPropertyName>("property") = property_name;
     467         104 :   else if (params.have_parameter<MooseFunctorName>("functor"))
     468         312 :     params.set<MooseFunctorName>("functor") = property_name;
     469             :   else
     470           0 :     mooseError("Internal error. AuxKernel has neither a `functor` nor a `property` parameter.");
     471             : 
     472       92070 :   params.set<AuxVariableName>("variable") = variable_name;
     473       30690 :   if (_output_only_on_timestep_end)
     474           0 :     params.set<ExecFlagEnum>("execute_on") = EXEC_TIMESTEP_END;
     475             :   else
     476      122760 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END};
     477             : 
     478       30690 :   if (material.boundaryRestricted())
     479         543 :     params.set<std::vector<BoundaryName>>("boundary") = material.boundaryNames();
     480             :   else
     481       91527 :     params.set<std::vector<SubdomainName>>("block") = material.blocks();
     482             : 
     483       30690 :   return params;
     484       30690 : }

Generated by: LCOV version 1.14