LCOV - code coverage report
Current view: top level - src/actions - MaterialOutputAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 6f668f Lines: 227 238 95.4 %
Date: 2025-09-22 20:01:15 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       68903 : MaterialOutputAction::validParams()
      33             : {
      34       68903 :   InputParameters params = Action::validParams();
      35       68903 :   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      206709 :   params.addPrivateParam("print_unsupported_prop_names", true);
      41      137806 :   params.addParam<bool>("print_automatic_aux_variable_creation",
      42      137806 :                         true,
      43             :                         "Flag to print list of aux variables created for automatic output by "
      44             :                         "MaterialOutputAction.");
      45       68903 :   return params;
      46           0 : }
      47             : 
      48       68699 : MaterialOutputAction::MaterialOutputAction(const InputParameters & params)
      49             :   : Action(params),
      50       68699 :     _block_material_data(nullptr),
      51       68699 :     _boundary_material_data(nullptr),
      52       68699 :     _output_warehouse(_app.getOutputWarehouse()),
      53      137398 :     _output_only_on_timestep_end(_app.parameters().get<bool>("use_legacy_material_output"))
      54             : {
      55       68699 : }
      56             : 
      57             : void
      58      125560 : 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      376680 :   if (!_app.actionWarehouse().hasActions("add_output"))
      65           0 :     return;
      66             : 
      67      125560 :   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      125560 :   _block_material_data = &_problem->getMaterialData(Moose::BLOCK_MATERIAL_DATA);
      72      125560 :   _boundary_material_data = &_problem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA);
      73             : 
      74             :   // A complete list of all MaterialBase objects
      75      125560 :   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      125560 :   bool outputs_has_properties = false;
      83      125560 :   std::set<std::string> output_object_properties;
      84             : 
      85      251120 :   const auto & output_actions = _app.actionWarehouse().getActionListByName("add_output");
      86      741876 :   for (const auto & act : output_actions)
      87             :   {
      88             :     // Extract the Output action
      89      616316 :     AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
      90      616316 :     if (!action)
      91      129142 :       continue;
      92             : 
      93             :     // Add the material property names from the output object parameters to the list of properties
      94             :     // to output
      95      487174 :     InputParameters & params = action->getObjectParams();
      96     2025842 :     if (params.isParamValid("output_material_properties") &&
      97      564320 :         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      125560 :   std::set<std::string> material_names;
     108      125560 :   std::set<std::string> unsupported_names;
     109      155298 :   for (const auto & mat : material_ptrs)
     110             :   {
     111             :     // Extract the names of the output objects to which the material properties will be exported
     112       29742 :     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       59484 :         mat->getParam<std::vector<std::string>>("output_properties");
     117             : 
     118             :     // Append the properties listed in the Outputs block
     119       29742 :     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       29742 :     _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       29742 :     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       25162 :     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 Outputs/output_material_properties");
     183       29738 :   }
     184      125586 :   if (unsupported_names.size() > 0 && get_names_only &&
     185      125646 :       getParam<bool>("print_unsupported_prop_names"))
     186             :   {
     187          30 :     std::ostringstream oss;
     188          60 :     for (const auto & name : unsupported_names)
     189          30 :       oss << "\n  " << name;
     190          60 :     mooseWarning("The types for total ",
     191          30 :                  unsupported_names.size(),
     192             :                  " material properties:",
     193          60 :                  oss.str(),
     194             :                  "\nare not supported for automatic output by ",
     195          30 :                  type(),
     196             :                  ".");
     197          30 :   }
     198             : 
     199      125556 :   if (_current_task == "add_output_aux_variables")
     200             :   {
     201      188796 :     auto params = _factory.getValidParams("MooseVariableConstMonomial");
     202             :     // currently only elemental variables are supported for material property output
     203      251728 :     params.set<MooseEnum>("order") = "CONSTANT";
     204      188796 :     params.set<MooseEnum>("family") = "MONOMIAL";
     205             : 
     206             :     // Create the AuxVariables
     207       62932 :     std::ostringstream oss;
     208       91569 :     for (const auto & var_name : material_names)
     209             :     {
     210       28641 :       oss << "\n  " << var_name;
     211       28641 :       if (_problem->hasVariable(var_name))
     212           4 :         mooseError("The material property output " + var_name +
     213             :                    " has the same name as an existing variable, either use the material"
     214             :                    " declare_suffix parameter to disambiguate or the output_properties parameter"
     215             :                    " to restrict the material properties to output");
     216       85911 :       _problem->addAuxVariable("MooseVariableConstMonomial", var_name, params);
     217             :     }
     218             : 
     219       65784 :     if (material_names.size() > 0 && getParam<bool>("print_automatic_aux_variable_creation"))
     220        1418 :       _console << COLOR_CYAN << "The following total " << material_names.size()
     221        2836 :                << " aux variables:" << oss.str() << "\nare added for automatic output by " << type()
     222        1418 :                << "." << COLOR_DEFAULT << std::endl;
     223       62928 :   }
     224             :   else
     225             :   {
     226             :     // When a MaterialBase object has 'output_properties' defined all other properties not listed
     227             :     // must be added to the hide list for the output objects so that properties that are not desired
     228             :     // do not appear.
     229       65322 :     for (const auto & it : _material_variable_names_map)
     230             :     {
     231        2698 :       std::set<std::string> hide;
     232        2698 :       std::set_difference(material_names.begin(),
     233             :                           material_names.end(),
     234             :                           it.second.begin(),
     235             :                           it.second.end(),
     236             :                           std::inserter(hide, hide.begin()));
     237             : 
     238        2698 :       _output_warehouse.addInterfaceHideVariables(it.first, hide);
     239        2698 :     }
     240             :   }
     241      125552 : }
     242             : 
     243             : std::vector<std::string>
     244       10612 : MaterialOutputAction::materialOutput(const std::string & property_name,
     245             :                                      const MaterialBase & material,
     246             :                                      bool get_names_only)
     247             : {
     248       10612 :   std::vector<std::string> names;
     249             : 
     250             :   // Material Properties
     251       10612 :   if (hasProperty<Real>(property_name))
     252       10452 :     names = outputHelper(
     253        5226 :         {"MaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
     254             : 
     255        5386 :   else if (hasADProperty<Real>(property_name))
     256        4636 :     names = outputHelper(
     257        2318 :         {"ADMaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
     258             : 
     259        3068 :   else if (hasProperty<RealVectorValue>(property_name))
     260         686 :     names = outputHelper({"MaterialRealVectorValueAux", "xyz", {"component"}},
     261             :                          property_name,
     262        1372 :                          property_name + "_",
     263             :                          material,
     264         686 :                          get_names_only);
     265             : 
     266        2382 :   else if (hasADProperty<RealVectorValue>(property_name))
     267         208 :     names = outputHelper({"ADMaterialRealVectorValueAux", "xyz", {"component"}},
     268             :                          property_name,
     269         416 :                          property_name + "_",
     270             :                          material,
     271         208 :                          get_names_only);
     272             : 
     273        2174 :   else if (hasProperty<std::vector<Real>>(property_name))
     274         112 :     names = outputHelper({"MaterialStdVectorAux", "variable_size", {"index"}},
     275             :                          property_name,
     276         224 :                          property_name + "_",
     277             :                          material,
     278         112 :                          get_names_only);
     279             : 
     280        2062 :   else if (hasADProperty<std::vector<Real>>(property_name))
     281          52 :     names = outputHelper({"ADMaterialStdVectorAux", "variable_size", {"index"}},
     282             :                          property_name,
     283         104 :                          property_name + "_",
     284             :                          material,
     285          52 :                          get_names_only);
     286             : 
     287        2010 :   else if (hasProperty<RealTensorValue>(property_name))
     288         452 :     names = outputHelper({"MaterialRealTensorValueAux", "012", {"row", "column"}},
     289             :                          property_name,
     290         904 :                          property_name + "_",
     291             :                          material,
     292         452 :                          get_names_only);
     293             : 
     294        1558 :   else if (hasADProperty<RealTensorValue>(property_name))
     295          26 :     names = outputHelper({"ADMaterialRealTensorValueAux", "012", {"row", "column"}},
     296             :                          property_name,
     297          52 :                          property_name + "_",
     298             :                          material,
     299          26 :                          get_names_only);
     300             : 
     301        1532 :   else if (hasProperty<RankTwoTensor>(property_name))
     302         344 :     names = outputHelper({"MaterialRankTwoTensorAux", "012", {"i", "j"}},
     303             :                          property_name,
     304         688 :                          property_name + "_",
     305             :                          material,
     306         344 :                          get_names_only);
     307             : 
     308        1188 :   else if (hasADProperty<RankTwoTensor>(property_name))
     309          78 :     names = outputHelper({"ADMaterialRankTwoTensorAux", "012", {"i", "j"}},
     310             :                          property_name,
     311         156 :                          property_name + "_",
     312             :                          material,
     313          78 :                          get_names_only);
     314             : 
     315        1110 :   else if (hasProperty<RankFourTensor>(property_name))
     316         292 :     names = outputHelper({"MaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
     317             :                          property_name,
     318         584 :                          property_name + "_",
     319             :                          material,
     320         292 :                          get_names_only);
     321             : 
     322         818 :   else if (hasADProperty<RankFourTensor>(property_name))
     323          26 :     names = outputHelper({"ADMaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
     324             :                          property_name,
     325          52 :                          property_name + "_",
     326             :                          material,
     327          26 :                          get_names_only);
     328             : 
     329         792 :   else if (hasProperty<SymmetricRankTwoTensor>(property_name))
     330         318 :     names = outputHelper({"MaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
     331             :                          property_name,
     332         636 :                          property_name + "_",
     333             :                          material,
     334         318 :                          get_names_only);
     335             : 
     336         474 :   else if (hasADProperty<SymmetricRankTwoTensor>(property_name))
     337          52 :     names = outputHelper({"ADMaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
     338             :                          property_name,
     339         104 :                          property_name + "_",
     340             :                          material,
     341          52 :                          get_names_only);
     342             : 
     343         422 :   else if (hasProperty<SymmetricRankFourTensor>(property_name))
     344         292 :     names = outputHelper({"MaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
     345             :                          property_name,
     346         584 :                          property_name + "_",
     347             :                          material,
     348         292 :                          get_names_only);
     349             : 
     350         130 :   else if (hasADProperty<SymmetricRankFourTensor>(property_name))
     351          26 :     names = outputHelper({"ADMaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
     352             :                          property_name,
     353          52 :                          property_name + "_",
     354             :                          material,
     355          26 :                          get_names_only);
     356             : 
     357             :   // Functors
     358         104 :   else if (hasFunctorProperty<Real>(property_name))
     359          52 :     names = outputHelper({"FunctorMaterialRealAux", "", {}},
     360             :                          property_name,
     361         104 :                          property_name + "_out",
     362             :                          material,
     363          52 :                          get_names_only);
     364             : 
     365          52 :   else if (hasFunctorProperty<ADReal>(property_name))
     366           0 :     names = outputHelper({"ADFunctorMaterialRealAux", "", {}},
     367             :                          property_name,
     368           0 :                          property_name + "_out",
     369             :                          material,
     370           0 :                          get_names_only);
     371             : 
     372          52 :   else if (hasFunctorProperty<RealVectorValue>(property_name))
     373          52 :     names = outputHelper({"FunctorMaterialRealVectorValueAux", "xyz", {"component"}},
     374             :                          property_name,
     375         104 :                          property_name + "_out_",
     376             :                          material,
     377          52 :                          get_names_only);
     378             : 
     379           0 :   else if (hasFunctorProperty<ADRealVectorValue>(property_name))
     380           0 :     names = outputHelper({"ADFunctorMaterialRealVectorValueAux", "xyz", {"component"}},
     381             :                          property_name,
     382           0 :                          property_name + "_out_",
     383             :                          material,
     384           0 :                          get_names_only);
     385             : 
     386       10612 :   return names;
     387       34852 : }
     388             : 
     389             : std::vector<std::string>
     390       10612 : MaterialOutputAction::outputHelper(const MaterialOutputAction::OutputMetaData & metadata,
     391             :                                    const std::string & property_name,
     392             :                                    const std::string & var_name_base,
     393             :                                    const MaterialBase & material,
     394             :                                    bool get_names_only)
     395             : {
     396       10612 :   const auto & [kernel_name, index_symbols, param_names] = metadata;
     397       10612 :   const auto dim = param_names.size();
     398       10612 :   const auto size = index_symbols.size();
     399       10612 :   auto size_inner = size;
     400             : 
     401             :   // Handle the case the material property is of a variable input-defined size
     402       10612 :   bool variable_size = false;
     403       10612 :   std::string variable_size_symbols;
     404       10612 :   if (index_symbols == "variable_size")
     405             :   {
     406         164 :     variable_size = true;
     407         164 :     size_inner = 0;
     408         164 :     const auto * const vsmi =
     409         164 :         dynamic_cast<const VariableSizeMaterialPropertiesInterface *>(&material);
     410         164 :     if (vsmi)
     411         104 :       size_inner = vsmi->getVectorPropertySize(property_name);
     412             : 
     413         164 :     if (!size_inner)
     414             :     {
     415          60 :       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          60 :       return {};
     423             :     }
     424             :     // Use indices as symbols
     425         364 :     for (const auto i : make_range(size_inner))
     426         260 :       variable_size_symbols += std::to_string(i);
     427             :   }
     428             : 
     429       10552 :   std::vector<std::string> names;
     430             :   // general 0 to 4 dimensional loop
     431             :   std::array<std::size_t, 4> i;
     432       21740 :   for (i[3] = 0; i[3] < (dim < 4 ? 1 : size); ++i[3])
     433       24284 :     for (i[2] = 0; i[2] < (dim < 3 ? 1 : size); ++i[2])
     434       35306 :       for (i[1] = 0; i[1] < (dim < 2 ? 1 : size); ++i[1])
     435       80430 :         for (i[0] = 0; i[0] < (dim < 1 ? 1 : size_inner); ++i[0])
     436             :         {
     437       58220 :           std::string var_name = var_name_base;
     438       58220 :           const auto & symbols = variable_size ? variable_size_symbols : index_symbols;
     439      205666 :           for (const auto j : make_range(dim))
     440      147446 :             var_name += Moose::stringify(symbols[i[j]]);
     441             : 
     442       58220 :           names.push_back(var_name);
     443             : 
     444       58220 :           if (!get_names_only)
     445             :           {
     446       29084 :             auto params = getParams(kernel_name, property_name, var_name, material);
     447      102765 :             for (const auto j : make_range(dim))
     448       73681 :               params.template set<unsigned int>(param_names[j]) = i[j];
     449       29084 :             _problem->addAuxKernel(kernel_name, material.name() + var_name, params);
     450       29084 :           }
     451       58220 :         }
     452       10552 :   return names;
     453       10612 : }
     454             : 
     455             : InputParameters
     456       29084 : MaterialOutputAction::getParams(const std::string & type,
     457             :                                 const std::string & property_name,
     458             :                                 const std::string & variable_name,
     459             :                                 const MaterialBase & material)
     460             : {
     461             :   // Append the list of output variables for the current material
     462       29084 :   _material_variable_names.insert(variable_name);
     463             : 
     464             :   // Set the action parameters
     465       29084 :   InputParameters params = _factory.getValidParams(type);
     466       29084 :   if (params.have_parameter<MaterialPropertyName>("property"))
     467       86940 :     params.set<MaterialPropertyName>("property") = property_name;
     468         104 :   else if (params.have_parameter<MooseFunctorName>("functor"))
     469         312 :     params.set<MooseFunctorName>("functor") = property_name;
     470             :   else
     471           0 :     mooseError("Internal error. AuxKernel has neither a `functor` nor a `property` parameter.");
     472             : 
     473       87252 :   params.set<AuxVariableName>("variable") = variable_name;
     474       29084 :   if (_output_only_on_timestep_end)
     475           0 :     params.set<ExecFlagEnum>("execute_on") = EXEC_TIMESTEP_END;
     476             :   else
     477      116336 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END};
     478             : 
     479       29084 :   if (material.boundaryRestricted())
     480         543 :     params.set<std::vector<BoundaryName>>("boundary") = material.boundaryNames();
     481             :   else
     482       86709 :     params.set<std::vector<SubdomainName>>("block") = material.blocks();
     483             : 
     484       29084 :   return params;
     485       29084 : }

Generated by: LCOV version 1.14