LCOV - code coverage report
Current view: top level - src/actions - MaterialOutputAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 203 214 94.9 %
Date: 2025-07-17 01:28:37 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             : 
      25             : #include "libmesh/utility.h"
      26             : 
      27             : registerMooseAction("MooseApp", MaterialOutputAction, "add_output_aux_variables");
      28             : registerMooseAction("MooseApp", MaterialOutputAction, "add_aux_kernel");
      29             : 
      30             : InputParameters
      31       62220 : MaterialOutputAction::validParams()
      32             : {
      33       62220 :   InputParameters params = Action::validParams();
      34       62220 :   params.addClassDescription("Outputs material properties to various Outputs objects, based on the "
      35             :                              "parameters set in each Material");
      36             :   /// A flag to tell this action whether or not to print the unsupported properties
      37             :   /// Note: A derived class can set this to false, override materialOutput and output
      38             :   ///       a particular property that is not supported by this class.
      39       62220 :   params.addPrivateParam("print_unsupported_prop_names", true);
      40      186660 :   params.addParam<bool>("print_automatic_aux_variable_creation",
      41      124440 :                         true,
      42             :                         "Flag to print list of aux variables created for automatic output by "
      43             :                         "MaterialOutputAction.");
      44       62220 :   return params;
      45           0 : }
      46             : 
      47       62016 : MaterialOutputAction::MaterialOutputAction(const InputParameters & params)
      48             :   : Action(params),
      49       62016 :     _block_material_data(nullptr),
      50       62016 :     _boundary_material_data(nullptr),
      51       62016 :     _output_warehouse(_app.getOutputWarehouse()),
      52      124032 :     _output_only_on_timestep_end(_app.parameters().get<bool>("use_legacy_material_output"))
      53             : {
      54       62016 : }
      55             : 
      56             : void
      57      113230 : MaterialOutputAction::act()
      58             : {
      59             :   mooseAssert(_problem,
      60             :               "FEProblemBase pointer is nullptr, it is needed for auto material property output");
      61             : 
      62             :   // Do nothing if the application does not have output
      63      113230 :   if (!_app.actionWarehouse().hasActions("add_output"))
      64           0 :     return;
      65             : 
      66      113230 :   bool get_names_only = _current_task == "add_output_aux_variables" ? true : false;
      67             : 
      68             :   // Set the pointers to the MaterialData objects (Note, these pointers are not available at
      69             :   // construction)
      70      113230 :   _block_material_data = &_problem->getMaterialData(Moose::BLOCK_MATERIAL_DATA);
      71      113230 :   _boundary_material_data = &_problem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA);
      72             : 
      73             :   // A complete list of all MaterialBase objects
      74      113230 :   const auto & material_ptrs = _problem->getMaterialWarehouse().getObjects();
      75             : 
      76             :   // Handle setting of material property output in [Outputs] sub-blocks
      77             :   // Output objects can enable material property output, the following code examines the parameters
      78             :   // for each Output object and sets a flag if any Output object has output set and also builds a
      79             :   // list if the
      80             :   // properties are limited via the 'show_material_properties' parameters
      81      113230 :   bool outputs_has_properties = false;
      82      113230 :   std::set<std::string> output_object_properties;
      83             : 
      84      113230 :   const auto & output_actions = _app.actionWarehouse().getActionListByName("add_output");
      85      668312 :   for (const auto & act : output_actions)
      86             :   {
      87             :     // Extract the Output action
      88      555082 :     AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
      89      555082 :     if (!action)
      90      116436 :       continue;
      91             : 
      92             :     // Add the material property names from the output object parameters to the list of properties
      93             :     // to output
      94      438646 :     InputParameters & params = action->getObjectParams();
      95      946626 :     if (params.isParamValid("output_material_properties") &&
      96      507980 :         params.get<bool>("output_material_properties"))
      97             :     {
      98         124 :       outputs_has_properties = true;
      99             :       std::vector<std::string> prop_names =
     100         124 :           params.get<std::vector<std::string>>("show_material_properties");
     101         124 :       output_object_properties.insert(prop_names.begin(), prop_names.end());
     102         124 :     }
     103             :   }
     104             : 
     105             :   // Loop through each material object
     106      113230 :   std::set<std::string> material_names;
     107      113230 :   std::set<std::string> unsupported_names;
     108      139112 :   for (const auto & mat : material_ptrs)
     109             :   {
     110             :     // Extract the names of the output objects to which the material properties will be exported
     111       25886 :     std::set<OutputName> outputs = mat->getOutputs();
     112             : 
     113             :     // Extract the property names that will actually be output
     114             :     std::vector<std::string> output_properties =
     115       25886 :         mat->getParam<std::vector<std::string>>("output_properties");
     116             : 
     117             :     // Append the properties listed in the Outputs block
     118       25886 :     if (outputs_has_properties)
     119         148 :       output_properties.insert(output_properties.end(),
     120             :                                output_object_properties.begin(),
     121             :                                output_object_properties.end());
     122             : 
     123             :     // Clear the list of variable names for the current material object, this list will be populated
     124             :     // with all the
     125             :     // variables names for the current material object and is needed for purposes of controlling the
     126             :     // which output objects
     127             :     // show the material property data
     128       25886 :     _material_variable_names.clear();
     129             : 
     130             :     // Create necessary outputs for the properties if:
     131             :     //   (1) The Outputs block has material output enabled
     132             :     //   (2) If the MaterialBase object itself has set the 'outputs' parameter
     133       25886 :     if (outputs_has_properties || outputs.find("none") == outputs.end())
     134             :     {
     135             :       // Get all material properties supplied by this material as a starting point
     136        4186 :       std::set<std::string> names = mat->getSuppliedItems();
     137        4186 :       if (const auto fmat_ptr = dynamic_cast<const FunctorMaterial *>(mat.get()))
     138          96 :         names.insert(fmat_ptr->getSuppliedFunctors().begin(),
     139          96 :                      fmat_ptr->getSuppliedFunctors().end());
     140             : 
     141       16646 :       for (const auto & name : names)
     142             :       {
     143             :         // Output the property only if the name is contained in the 'output_properties'
     144             :         // list or if the list is empty (all properties)
     145       16968 :         if (output_properties.empty() ||
     146        4508 :             std::find(output_properties.begin(), output_properties.end(), name) !=
     147       16968 :                 output_properties.end())
     148             :         {
     149             :           // Add the material property for output
     150        9728 :           auto curr_material_names = materialOutput(name, *mat, get_names_only);
     151        9728 :           if (curr_material_names.size() == 0)
     152          60 :             unsupported_names.insert(name);
     153        9728 :           material_names.insert(curr_material_names.begin(), curr_material_names.end());
     154        9728 :         }
     155             :       }
     156             :       // If the material object has explicitly defined outputs, store the variables associated with
     157             :       // the output objects
     158        4186 :       if (outputs.find("none") == outputs.end())
     159             :       {
     160             :         // Get all available output names from OutputWarehouse that support material output
     161        4038 :         const auto & all_output_names = _output_warehouse.getAllMaterialPropertyOutputNames();
     162             : 
     163             :         // For reserved name "all", set outputs to match all available output names
     164        4038 :         if (outputs.find("all") != outputs.end())
     165        1828 :           outputs = all_output_names;
     166             : 
     167             :         // Iterate through all available output names and update _material_variable_names_map
     168             :         // based on which of these output names are found in 'outputs' parameter
     169        7998 :         for (const auto & output_name : all_output_names)
     170             :         {
     171        3960 :           if (outputs.find(output_name) != outputs.end())
     172        2739 :             _material_variable_names_map[output_name].insert(_material_variable_names.begin(),
     173             :                                                              _material_variable_names.end());
     174             :           else
     175        1221 :             _material_variable_names_map[output_name].insert({});
     176             :         }
     177        4038 :       }
     178        4186 :     }
     179       21700 :     else if (output_properties.size())
     180          76 :       mooseWarning("Material properties output specified is not created because 'outputs' is not "
     181             :                    "set in the Material, and neither is Outputs/output_material_properties");
     182       25882 :   }
     183      113256 :   if (unsupported_names.size() > 0 && get_names_only &&
     184      113256 :       getParam<bool>("print_unsupported_prop_names"))
     185             :   {
     186          30 :     std::ostringstream oss;
     187          60 :     for (const auto & name : unsupported_names)
     188          30 :       oss << "\n  " << name;
     189          60 :     mooseWarning("The types for total ",
     190          30 :                  unsupported_names.size(),
     191             :                  " material properties:",
     192          60 :                  oss.str(),
     193             :                  "\nare not supported for automatic output by ",
     194          30 :                  type(),
     195             :                  ".");
     196          30 :   }
     197             : 
     198      113226 :   if (_current_task == "add_output_aux_variables")
     199             :   {
     200       56761 :     auto params = _factory.getValidParams("MooseVariableConstMonomial");
     201             :     // currently only elemental variables are supported for material property output
     202       56761 :     params.set<MooseEnum>("order") = "CONSTANT";
     203       56761 :     params.set<MooseEnum>("family") = "MONOMIAL";
     204             : 
     205             :     // Create the AuxVariables
     206       56761 :     std::ostringstream oss;
     207       83529 :     for (const auto & var_name : material_names)
     208             :     {
     209       26772 :       oss << "\n  " << var_name;
     210       26772 :       if (_problem->hasVariable(var_name))
     211           4 :         mooseError("The material property output " + var_name +
     212             :                    " has the same name as an existing variable, either use the material"
     213             :                    " declare_suffix parameter to disambiguate or the output_properties parameter"
     214             :                    " to restrict the material properties to output");
     215       26768 :       _problem->addAuxVariable("MooseVariableConstMonomial", var_name, params);
     216             :     }
     217             : 
     218       56757 :     if (material_names.size() > 0 && getParam<bool>("print_automatic_aux_variable_creation"))
     219        1285 :       _console << COLOR_CYAN << "The following total " << material_names.size()
     220        2570 :                << " aux variables:" << oss.str() << "\nare added for automatic output by " << type()
     221        1285 :                << "." << COLOR_DEFAULT << std::endl;
     222       56757 :   }
     223             :   else
     224             :   {
     225             :     // When a MaterialBase object has 'output_properties' defined all other properties not listed
     226             :     // must be added to the hide list for the output objects so that properties that are not desired
     227             :     // do not appear.
     228       58903 :     for (const auto & it : _material_variable_names_map)
     229             :     {
     230        2438 :       std::set<std::string> hide;
     231        2438 :       std::set_difference(material_names.begin(),
     232             :                           material_names.end(),
     233             :                           it.second.begin(),
     234             :                           it.second.end(),
     235             :                           std::inserter(hide, hide.begin()));
     236             : 
     237        2438 :       _output_warehouse.addInterfaceHideVariables(it.first, hide);
     238        2438 :     }
     239             :   }
     240      113222 : }
     241             : 
     242             : std::vector<std::string>
     243        9728 : MaterialOutputAction::materialOutput(const std::string & property_name,
     244             :                                      const MaterialBase & material,
     245             :                                      bool get_names_only)
     246             : {
     247        9728 :   std::vector<std::string> names;
     248             : 
     249             :   // Material Properties
     250        9728 :   if (hasProperty<Real>(property_name))
     251        4820 :     names = outputHelper(
     252        4820 :         {"MaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
     253             : 
     254        4908 :   else if (hasADProperty<Real>(property_name))
     255        2128 :     names = outputHelper(
     256        2128 :         {"ADMaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
     257             : 
     258        2780 :   else if (hasProperty<RealVectorValue>(property_name))
     259        1280 :     names = outputHelper({"MaterialRealVectorValueAux", "xyz", {"component"}},
     260             :                          property_name,
     261        1280 :                          property_name + "_",
     262             :                          material,
     263         640 :                          get_names_only);
     264             : 
     265        2140 :   else if (hasADProperty<RealVectorValue>(property_name))
     266         384 :     names = outputHelper({"ADMaterialRealVectorValueAux", "xyz", {"component"}},
     267             :                          property_name,
     268         384 :                          property_name + "_",
     269             :                          material,
     270         192 :                          get_names_only);
     271             : 
     272        1948 :   else if (hasProperty<RealTensorValue>(property_name))
     273        1272 :     names = outputHelper({"MaterialRealTensorValueAux", "012", {"row", "column"}},
     274             :                          property_name,
     275         848 :                          property_name + "_",
     276             :                          material,
     277         424 :                          get_names_only);
     278             : 
     279        1524 :   else if (hasADProperty<RealTensorValue>(property_name))
     280          72 :     names = outputHelper({"ADMaterialRealTensorValueAux", "012", {"row", "column"}},
     281             :                          property_name,
     282          48 :                          property_name + "_",
     283             :                          material,
     284          24 :                          get_names_only);
     285             : 
     286        1500 :   else if (hasProperty<RankTwoTensor>(property_name))
     287         972 :     names = outputHelper({"MaterialRankTwoTensorAux", "012", {"i", "j"}},
     288             :                          property_name,
     289         648 :                          property_name + "_",
     290             :                          material,
     291         324 :                          get_names_only);
     292             : 
     293        1176 :   else if (hasADProperty<RankTwoTensor>(property_name))
     294         216 :     names = outputHelper({"ADMaterialRankTwoTensorAux", "012", {"i", "j"}},
     295             :                          property_name,
     296         144 :                          property_name + "_",
     297             :                          material,
     298          72 :                          get_names_only);
     299             : 
     300        1104 :   else if (hasProperty<RankFourTensor>(property_name))
     301        1380 :     names = outputHelper({"MaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
     302             :                          property_name,
     303         552 :                          property_name + "_",
     304             :                          material,
     305         276 :                          get_names_only);
     306             : 
     307         828 :   else if (hasADProperty<RankFourTensor>(property_name))
     308         120 :     names = outputHelper({"ADMaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
     309             :                          property_name,
     310          48 :                          property_name + "_",
     311             :                          material,
     312          24 :                          get_names_only);
     313             : 
     314         804 :   else if (hasProperty<SymmetricRankTwoTensor>(property_name))
     315         600 :     names = outputHelper({"MaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
     316             :                          property_name,
     317         600 :                          property_name + "_",
     318             :                          material,
     319         300 :                          get_names_only);
     320             : 
     321         504 :   else if (hasADProperty<SymmetricRankTwoTensor>(property_name))
     322          96 :     names = outputHelper({"ADMaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
     323             :                          property_name,
     324          96 :                          property_name + "_",
     325             :                          material,
     326          48 :                          get_names_only);
     327             : 
     328         456 :   else if (hasProperty<SymmetricRankFourTensor>(property_name))
     329         828 :     names = outputHelper({"MaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
     330             :                          property_name,
     331         552 :                          property_name + "_",
     332             :                          material,
     333         276 :                          get_names_only);
     334             : 
     335         180 :   else if (hasADProperty<SymmetricRankFourTensor>(property_name))
     336          72 :     names = outputHelper({"ADMaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
     337             :                          property_name,
     338          48 :                          property_name + "_",
     339             :                          material,
     340          24 :                          get_names_only);
     341             : 
     342             :   // Functors
     343         156 :   else if (hasFunctorProperty<Real>(property_name))
     344          48 :     names = outputHelper({"FunctorMaterialRealAux", "", {}},
     345             :                          property_name,
     346          96 :                          property_name + "_out",
     347             :                          material,
     348          48 :                          get_names_only);
     349             : 
     350         108 :   else if (hasFunctorProperty<ADReal>(property_name))
     351           0 :     names = outputHelper({"ADFunctorMaterialRealAux", "", {}},
     352             :                          property_name,
     353           0 :                          property_name + "_out",
     354             :                          material,
     355           0 :                          get_names_only);
     356             : 
     357         108 :   else if (hasFunctorProperty<RealVectorValue>(property_name))
     358          96 :     names = outputHelper({"FunctorMaterialRealVectorValueAux", "xyz", {"component"}},
     359             :                          property_name,
     360          96 :                          property_name + "_out_",
     361             :                          material,
     362          48 :                          get_names_only);
     363             : 
     364          60 :   else if (hasFunctorProperty<ADRealVectorValue>(property_name))
     365           0 :     names = outputHelper({"ADFunctorMaterialRealVectorValueAux", "xyz", {"component"}},
     366             :                          property_name,
     367           0 :                          property_name + "_out_",
     368             :                          material,
     369           0 :                          get_names_only);
     370             : 
     371        9728 :   return names;
     372       24052 : }
     373             : 
     374             : std::vector<std::string>
     375        9668 : MaterialOutputAction::outputHelper(const MaterialOutputAction::OutputMetaData & metadata,
     376             :                                    const std::string & property_name,
     377             :                                    const std::string & var_name_base,
     378             :                                    const MaterialBase & material,
     379             :                                    bool get_names_only)
     380             : {
     381        9668 :   const auto & [kernel_name, index_symbols, param_names] = metadata;
     382        9668 :   const auto dim = param_names.size();
     383        9668 :   const auto size = index_symbols.size();
     384             : 
     385        9668 :   std::vector<std::string> names;
     386             :   // general 0 to 4 dimensional loop
     387             :   std::array<std::size_t, 4> i;
     388       19936 :   for (i[3] = 0; i[3] < (dim < 4 ? 1 : size); ++i[3])
     389       22336 :     for (i[2] = 0; i[2] < (dim < 3 ? 1 : size); ++i[2])
     390       32724 :       for (i[1] = 0; i[1] < (dim < 2 ? 1 : size); ++i[1])
     391       75076 :         for (i[0] = 0; i[0] < (dim < 1 ? 1 : size); ++i[0])
     392             :         {
     393       54420 :           std::string var_name = var_name_base;
     394      193140 :           for (const auto j : make_range(dim))
     395      138720 :             var_name += Moose::stringify(index_symbols[i[j]]);
     396       54420 :           names.push_back(var_name);
     397             : 
     398       54420 :           if (!get_names_only)
     399             :           {
     400       27184 :             auto params = getParams(kernel_name, property_name, var_name, material);
     401       96502 :             for (const auto j : make_range(dim))
     402       69318 :               params.template set<unsigned int>(param_names[j]) = i[j];
     403       27184 :             _problem->addAuxKernel(kernel_name, material.name() + var_name, params);
     404       27184 :           }
     405       54420 :         }
     406       19336 :   return names;
     407           0 : }
     408             : 
     409             : InputParameters
     410       27184 : MaterialOutputAction::getParams(const std::string & type,
     411             :                                 const std::string & property_name,
     412             :                                 const std::string & variable_name,
     413             :                                 const MaterialBase & material)
     414             : {
     415             :   // Append the list of output variables for the current material
     416       27184 :   _material_variable_names.insert(variable_name);
     417             : 
     418             :   // Set the action parameters
     419       27184 :   InputParameters params = _factory.getValidParams(type);
     420       27184 :   if (params.have_parameter<MaterialPropertyName>("property"))
     421       27088 :     params.set<MaterialPropertyName>("property") = property_name;
     422          96 :   else if (params.have_parameter<MooseFunctorName>("functor"))
     423          96 :     params.set<MooseFunctorName>("functor") = property_name;
     424             :   else
     425           0 :     mooseError("Internal error. AuxKernel has neither a `functor` nor a `property` parameter.");
     426             : 
     427       27184 :   params.set<AuxVariableName>("variable") = variable_name;
     428       27184 :   if (_output_only_on_timestep_end)
     429           0 :     params.set<ExecFlagEnum>("execute_on") = EXEC_TIMESTEP_END;
     430             :   else
     431       81552 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END};
     432             : 
     433       27184 :   if (material.boundaryRestricted())
     434         168 :     params.set<std::vector<BoundaryName>>("boundary") = material.boundaryNames();
     435             :   else
     436       27016 :     params.set<std::vector<SubdomainName>>("block") = material.blocks();
     437             : 
     438       27184 :   return params;
     439       27184 : }

Generated by: LCOV version 1.14