LCOV - code coverage report
Current view: top level - src/actions - MaterialOutputAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31653 (2d163b) with base 0cc44f Lines: 227 238 95.4 %
Date: 2025-11-04 20:38:02 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       69457 : MaterialOutputAction::validParams()
      33             : {
      34       69457 :   InputParameters params = Action::validParams();
      35       69457 :   params.addClassDescription("Outputs material properties to various Outputs objects, based on the "
      36             :                              "parameters set in each Material");
      37             :   /// A flag to tell this action whether or not to print the unsupported properties
      38             :   /// Note: A derived class can set this to false, override materialOutput and output
      39             :   ///       a particular property that is not supported by this class.
      40      208371 :   params.addPrivateParam("print_unsupported_prop_names", true);
      41      138914 :   params.addParam<bool>("print_automatic_aux_variable_creation",
      42      138914 :                         true,
      43             :                         "Flag to print list of aux variables created for automatic output by "
      44             :                         "MaterialOutputAction.");
      45       69457 :   return params;
      46           0 : }
      47             : 
      48       69252 : MaterialOutputAction::MaterialOutputAction(const InputParameters & params)
      49             :   : Action(params),
      50       69252 :     _block_material_data(nullptr),
      51       69252 :     _boundary_material_data(nullptr),
      52       69252 :     _output_warehouse(_app.getOutputWarehouse()),
      53      138504 :     _output_only_on_timestep_end(_app.parameters().get<bool>("use_legacy_material_output"))
      54             : {
      55       69252 : }
      56             : 
      57             : void
      58      126560 : 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      379680 :   if (!_app.actionWarehouse().hasActions("add_output"))
      65           0 :     return;
      66             : 
      67      126560 :   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      126560 :   _block_material_data = &_problem->getMaterialData(Moose::BLOCK_MATERIAL_DATA);
      72      126560 :   _boundary_material_data = &_problem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA);
      73             : 
      74             :   // A complete list of all MaterialBase objects
      75      126560 :   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      126560 :   bool outputs_has_properties = false;
      83      126560 :   std::set<std::string> output_object_properties;
      84             : 
      85      253120 :   const auto & output_actions = _app.actionWarehouse().getActionListByName("add_output");
      86      747814 :   for (const auto & act : output_actions)
      87             :   {
      88             :     // Extract the Output action
      89      621254 :     AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
      90      621254 :     if (!action)
      91      130168 :       continue;
      92             : 
      93             :     // Add the material property names from the output object parameters to the list of properties
      94             :     // to output
      95      491086 :     InputParameters & params = action->getObjectParams();
      96     2042006 :     if (params.isParamValid("output_material_properties") &&
      97      568748 :         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      126560 :   std::set<std::string> material_names;
     108      126560 :   std::set<std::string> unsupported_names;
     109      156806 :   for (const auto & mat : material_ptrs)
     110             :   {
     111             :     // Extract the names of the output objects to which the material properties will be exported
     112       30250 :     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       60500 :         mat->getParam<std::vector<std::string>>("output_properties");
     117             : 
     118             :     // Append the properties listed in the Outputs block
     119       30250 :     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       30250 :     _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       30250 :     if (outputs_has_properties || outputs.find("none") == outputs.end())
     135             :     {
     136             :       // Get all material properties supplied by this material as a starting point
     137        4580 :       std::set<std::string> names = mat->getSuppliedItems();
     138        4580 :       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       18154 :       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       18464 :         if (output_properties.empty() ||
     147        4890 :             std::find(output_properties.begin(), output_properties.end(), name) !=
     148       18464 :                 output_properties.end())
     149             :         {
     150             :           // Add the material property for output
     151       10612 :           auto curr_material_names = materialOutput(name, *mat, get_names_only);
     152       10612 :           if (curr_material_names.size() == 0)
     153          60 :             unsupported_names.insert(name);
     154       10612 :           material_names.insert(curr_material_names.begin(), curr_material_names.end());
     155       10612 :         }
     156             :       }
     157             :       // If the material object has explicitly defined outputs, store the variables associated with
     158             :       // the output objects
     159        4580 :       if (outputs.find("none") == outputs.end())
     160             :       {
     161             :         // Get all available output names from OutputWarehouse that support material output
     162        4420 :         const auto & all_output_names = _output_warehouse.getAllMaterialPropertyOutputNames();
     163             : 
     164             :         // For reserved name "all", set outputs to match all available output names
     165        4420 :         if (outputs.find("all") != outputs.end())
     166        2040 :           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        8764 :         for (const auto & output_name : all_output_names)
     171             :         {
     172        4344 :           if (outputs.find(output_name) != outputs.end())
     173        3029 :             _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        4420 :       }
     179        4580 :     }
     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       30246 :   }
     185      126586 :   if (unsupported_names.size() > 0 && get_names_only &&
     186      126646 :       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      126556 :   if (_current_task == "add_output_aux_variables")
     201             :   {
     202      190308 :     auto params = _factory.getValidParams("MooseVariableConstMonomial");
     203             :     // currently only elemental variables are supported for material property output
     204      253744 :     params.set<MooseEnum>("order") = "CONSTANT";
     205      190308 :     params.set<MooseEnum>("family") = "MONOMIAL";
     206             : 
     207             :     // Create the AuxVariables
     208       63436 :     std::ostringstream oss;
     209       92073 :     for (const auto & var_name : material_names)
     210             :     {
     211       28641 :       oss << "\n  " << var_name;
     212       28641 :       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       85911 :       _problem->addAuxVariable("MooseVariableConstMonomial", var_name, params);
     218             :     }
     219             : 
     220       66288 :     if (material_names.size() > 0 && getParam<bool>("print_automatic_aux_variable_creation"))
     221        1418 :       _console << COLOR_CYAN << "The following total " << material_names.size()
     222        2836 :                << " aux variables:" << oss.str() << "\nare added for automatic output by " << type()
     223        1418 :                << "." << COLOR_DEFAULT << std::endl;
     224       63432 :   }
     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       65818 :     for (const auto & it : _material_variable_names_map)
     231             :     {
     232        2698 :       std::set<std::string> hide;
     233        2698 :       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        2698 :       _output_warehouse.addInterfaceHideVariables(it.first, hide);
     240        2698 :     }
     241             :   }
     242      126552 : }
     243             : 
     244             : std::vector<std::string>
     245       10612 : MaterialOutputAction::materialOutput(const std::string & property_name,
     246             :                                      const MaterialBase & material,
     247             :                                      bool get_names_only)
     248             : {
     249       10612 :   std::vector<std::string> names;
     250             : 
     251             :   // Material Properties
     252       10612 :   if (hasProperty<Real>(property_name))
     253       10452 :     names = outputHelper(
     254        5226 :         {"MaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
     255             : 
     256        5386 :   else if (hasADProperty<Real>(property_name))
     257        4636 :     names = outputHelper(
     258        2318 :         {"ADMaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
     259             : 
     260        3068 :   else if (hasProperty<RealVectorValue>(property_name))
     261         686 :     names = outputHelper({"MaterialRealVectorValueAux", "xyz", {"component"}},
     262             :                          property_name,
     263        1372 :                          property_name + "_",
     264             :                          material,
     265         686 :                          get_names_only);
     266             : 
     267        2382 :   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        2174 :   else if (hasProperty<std::vector<Real>>(property_name))
     275         112 :     names = outputHelper({"MaterialStdVectorAux", "variable_size", {"index"}},
     276             :                          property_name,
     277         224 :                          property_name + "_",
     278             :                          material,
     279         112 :                          get_names_only);
     280             : 
     281        2062 :   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        2010 :   else if (hasProperty<RealTensorValue>(property_name))
     289         452 :     names = outputHelper({"MaterialRealTensorValueAux", "012", {"row", "column"}},
     290             :                          property_name,
     291         904 :                          property_name + "_",
     292             :                          material,
     293         452 :                          get_names_only);
     294             : 
     295        1558 :   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        1532 :   else if (hasProperty<RankTwoTensor>(property_name))
     303         344 :     names = outputHelper({"MaterialRankTwoTensorAux", "012", {"i", "j"}},
     304             :                          property_name,
     305         688 :                          property_name + "_",
     306             :                          material,
     307         344 :                          get_names_only);
     308             : 
     309        1188 :   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        1110 :   else if (hasProperty<RankFourTensor>(property_name))
     317         292 :     names = outputHelper({"MaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
     318             :                          property_name,
     319         584 :                          property_name + "_",
     320             :                          material,
     321         292 :                          get_names_only);
     322             : 
     323         818 :   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         792 :   else if (hasProperty<SymmetricRankTwoTensor>(property_name))
     331         318 :     names = outputHelper({"MaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
     332             :                          property_name,
     333         636 :                          property_name + "_",
     334             :                          material,
     335         318 :                          get_names_only);
     336             : 
     337         474 :   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         422 :   else if (hasProperty<SymmetricRankFourTensor>(property_name))
     345         292 :     names = outputHelper({"MaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
     346             :                          property_name,
     347         584 :                          property_name + "_",
     348             :                          material,
     349         292 :                          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       10612 :   return names;
     388       34852 : }
     389             : 
     390             : std::vector<std::string>
     391       10612 : 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       10612 :   const auto & [kernel_name, index_symbols, param_names] = metadata;
     398       10612 :   const auto dim = param_names.size();
     399       10612 :   const auto size = index_symbols.size();
     400       10612 :   auto size_inner = size;
     401             : 
     402             :   // Handle the case the material property is of a variable input-defined size
     403       10612 :   bool variable_size = false;
     404       10612 :   std::string variable_size_symbols;
     405       10612 :   if (index_symbols == "variable_size")
     406             :   {
     407         164 :     variable_size = true;
     408         164 :     size_inner = 0;
     409         164 :     const auto * const vsmi =
     410         164 :         dynamic_cast<const VariableSizeMaterialPropertiesInterface *>(&material);
     411         164 :     if (vsmi)
     412         104 :       size_inner = vsmi->getVectorPropertySize(property_name);
     413             : 
     414         164 :     if (!size_inner)
     415             :     {
     416          60 :       mooseWarning("Vector material property '" + property_name + "' will not be output as we " +
     417             :                    (vsmi ? "have a 0-size vector during the simulation setup."
     418             :                          : "do not know the size of the vector at initialization. Add the "
     419             :                            "'VariableSizeMaterialPropertiesInterface' as a base class of the "
     420             :                            "Material defining the vector property and implement the "
     421             :                            "get...Size(property_name) routine. Note that "
     422             :                            "the size must be known during the simulation setup phase."));
     423          60 :       return {};
     424             :     }
     425             :     // Use indices as symbols
     426         364 :     for (const auto i : make_range(size_inner))
     427         260 :       variable_size_symbols += std::to_string(i);
     428             :   }
     429             : 
     430       10552 :   std::vector<std::string> names;
     431             :   // general 0 to 4 dimensional loop
     432             :   std::array<std::size_t, 4> i;
     433       21740 :   for (i[3] = 0; i[3] < (dim < 4 ? 1 : size); ++i[3])
     434       24284 :     for (i[2] = 0; i[2] < (dim < 3 ? 1 : size); ++i[2])
     435       35306 :       for (i[1] = 0; i[1] < (dim < 2 ? 1 : size); ++i[1])
     436       80430 :         for (i[0] = 0; i[0] < (dim < 1 ? 1 : size_inner); ++i[0])
     437             :         {
     438       58220 :           std::string var_name = var_name_base;
     439       58220 :           const auto & symbols = variable_size ? variable_size_symbols : index_symbols;
     440      205666 :           for (const auto j : make_range(dim))
     441      147446 :             var_name += Moose::stringify(symbols[i[j]]);
     442             : 
     443       58220 :           names.push_back(var_name);
     444             : 
     445       58220 :           if (!get_names_only)
     446             :           {
     447       29084 :             auto params = getParams(kernel_name, property_name, var_name, material);
     448      102765 :             for (const auto j : make_range(dim))
     449       73681 :               params.template set<unsigned int>(param_names[j]) = i[j];
     450       29084 :             _problem->addAuxKernel(kernel_name, material.name() + var_name, params);
     451       29084 :           }
     452       58220 :         }
     453       10552 :   return names;
     454       10612 : }
     455             : 
     456             : InputParameters
     457       29084 : MaterialOutputAction::getParams(const std::string & type,
     458             :                                 const std::string & property_name,
     459             :                                 const std::string & variable_name,
     460             :                                 const MaterialBase & material)
     461             : {
     462             :   // Append the list of output variables for the current material
     463       29084 :   _material_variable_names.insert(variable_name);
     464             : 
     465             :   // Set the action parameters
     466       29084 :   InputParameters params = _factory.getValidParams(type);
     467       29084 :   if (params.have_parameter<MaterialPropertyName>("property"))
     468       86940 :     params.set<MaterialPropertyName>("property") = property_name;
     469         104 :   else if (params.have_parameter<MooseFunctorName>("functor"))
     470         312 :     params.set<MooseFunctorName>("functor") = property_name;
     471             :   else
     472           0 :     mooseError("Internal error. AuxKernel has neither a `functor` nor a `property` parameter.");
     473             : 
     474       87252 :   params.set<AuxVariableName>("variable") = variable_name;
     475       29084 :   if (_output_only_on_timestep_end)
     476           0 :     params.set<ExecFlagEnum>("execute_on") = EXEC_TIMESTEP_END;
     477             :   else
     478      116336 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END};
     479             : 
     480       29084 :   if (material.boundaryRestricted())
     481         543 :     params.set<std::vector<BoundaryName>>("boundary") = material.boundaryNames();
     482             :   else
     483       86709 :     params.set<std::vector<SubdomainName>>("block") = material.blocks();
     484             : 
     485       29084 :   return params;
     486       29084 : }

Generated by: LCOV version 1.14