LCOV - code coverage report
Current view: top level - src/outputs - TableOutput.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31405 (292dce) with base fef103 Lines: 147 151 97.4 %
Date: 2025-09-04 07:52:05 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "TableOutput.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "Conversion.h"
      14             : #include "FEProblem.h"
      15             : #include "Executioner.h"
      16             : #include "MooseApp.h"
      17             : #include "MooseVariableScalar.h"
      18             : #include "PetscSupport.h"
      19             : #include "Postprocessor.h"
      20             : #include "SystemBase.h"
      21             : 
      22             : #include "libmesh/dof_map.h"
      23             : #include "libmesh/string_to_enum.h"
      24             : 
      25             : InputParameters
      26      218011 : TableOutput::validParams()
      27             : {
      28             :   // Base class parameters
      29      218011 :   InputParameters params = AdvancedOutput::validParams();
      30      436022 :   params += AdvancedOutput::enableOutputTypes("postprocessor scalar vector_postprocessor reporter");
      31             : 
      32             :   // Option for writing vector_postprocessor time file
      33      654033 :   params.addParam<bool>("time_data",
      34      436022 :                         false,
      35             :                         "When true and VectorPostprocessor data exists, write "
      36             :                         "a csv file containing the timestep and time "
      37             :                         "information.");
      38             : 
      39             :   // Add option for appending file on restart
      40      872044 :   params.addParam<bool>("append_restart", false, "Append existing file on restart");
      41             : 
      42      654033 :   params.addParam<bool>(
      43             :       "time_column",
      44      436022 :       true,
      45             :       "Whether or not the 'time' column should be written for Postprocessor CSV files");
      46             : 
      47      872044 :   MooseEnum new_row_detection_columns("time all", "time");
      48      872044 :   new_row_detection_columns.addDocumentation(
      49             :       "time",
      50             :       "If the time for a new row would match the previous row's time within 'new_row_tolerance', "
      51             :       "do not add the row.");
      52      872044 :   new_row_detection_columns.addDocumentation(
      53             :       "all",
      54             :       "If all columns for a new row would match the previous row's columns within "
      55             :       "'new_row_tolerance', do not add the row.");
      56      872044 :   params.addParam<MooseEnum>("new_row_detection_columns",
      57             :                              new_row_detection_columns,
      58             :                              "Columns to check for duplicate rows; duplicate rows are not output.");
      59      654033 :   params.addParam<Real>("new_row_tolerance",
      60      436022 :                         libMesh::TOLERANCE * libMesh::TOLERANCE,
      61             :                         "The independent variable tolerance for determining when a new row should "
      62             :                         "be added to the table (Note: This value must be set independently for "
      63             :                         "Postprocessor output to type=Console and type=CSV file separately.");
      64      654033 :   params.addParamNamesToGroup("new_row_detection_columns new_row_tolerance time_data time_column",
      65             :                               "Table formatting");
      66             : 
      67      436022 :   return params;
      68      218011 : }
      69             : 
      70             : void
      71      611004 : TableOutput::addMultiAppFixedPointIterationEndExecFlag(InputParameters & params,
      72             :                                                        const std::string & param)
      73             : {
      74      611004 :   ExecFlagEnum & execute_on = params.set<ExecFlagEnum>(param, true);
      75      611004 :   execute_on.addAvailableFlags(EXEC_MULTIAPP_FIXED_POINT_ITERATION_END);
      76      611004 :   params.setDocString(param, execute_on.getDocString());
      77      611004 : }
      78             : 
      79       77570 : TableOutput::TableOutput(const InputParameters & parameters)
      80             :   : AdvancedOutput(parameters),
      81       77570 :     _tables_restartable(getParam<bool>("append_restart")),
      82      155140 :     _postprocessor_table(_tables_restartable
      83      155153 :                              ? declareRestartableData<FormattedTable>("postprocessor_table")
      84      232684 :                              : declareRecoverableData<FormattedTable>("postprocessor_table")),
      85       77570 :     _vector_postprocessor_time_tables(
      86      155153 :         _tables_restartable ? declareRestartableData<std::map<std::string, FormattedTable>>(
      87             :                                   "vector_postprocessor_time_table")
      88      310241 :                             : declareRecoverableData<std::map<std::string, FormattedTable>>(
      89             :                                   "vector_postprocessor_time_table")),
      90      155153 :     _scalar_table(_tables_restartable ? declareRestartableData<FormattedTable>("scalar_table")
      91      232684 :                                       : declareRecoverableData<FormattedTable>("scalar_table")),
      92      155153 :     _reporter_table(_tables_restartable ? declareRestartableData<FormattedTable>("reporter_table")
      93      232684 :                                         : declareRecoverableData<FormattedTable>("reporter_table")),
      94      155153 :     _all_data_table(_tables_restartable ? declareRestartableData<FormattedTable>("all_data_table")
      95      232684 :                                         : declareRecoverableData<FormattedTable>("all_data_table")),
      96      155140 :     _check_all_columns_for_new_row(getParam<MooseEnum>("new_row_detection_columns") == "all"),
      97      155140 :     _new_row_tol(getParam<Real>("new_row_tolerance")),
      98      155140 :     _time_data(getParam<bool>("time_data")),
      99      310280 :     _time_column(getParam<bool>("time_column"))
     100             : 
     101             : {
     102             :   // Set a Boolean indicating whether or not we will output the time column
     103       77570 :   _reporter_table.outputTimeColumn(_time_column);
     104       77570 :   _postprocessor_table.outputTimeColumn(_time_column);
     105       77570 :   _all_data_table.outputTimeColumn(_time_column);
     106       77570 : }
     107             : 
     108             : void
     109      183810 : TableOutput::outputPostprocessors()
     110             : {
     111      183810 :   if (shouldOutputPostprocessorsRow(_postprocessor_table))
     112      183073 :     outputPostprocessorsRow(_postprocessor_table);
     113             : 
     114      183810 :   if (shouldOutputPostprocessorsRow(_all_data_table))
     115      183073 :     outputPostprocessorsRow(_all_data_table);
     116      183810 : }
     117             : 
     118             : bool
     119      367620 : TableOutput::shouldOutputPostprocessorsRow(const FormattedTable & table)
     120             : {
     121      367620 :   if (table.empty())
     122       66818 :     return true;
     123             : 
     124             :   // Check time column; all options will output row if time is new
     125      300802 :   const Real old_time = table.getLastTime();
     126      300802 :   const Real new_time = getOutputTime();
     127      300802 :   if (!MooseUtils::absoluteFuzzyEqual(old_time, new_time, _new_row_tol))
     128      298944 :     return true;
     129             : 
     130             :   // Check PP columns if that option enabled
     131        1858 :   if (_check_all_columns_for_new_row)
     132             :   {
     133         384 :     bool all_columns_are_identical = true;
     134         384 :     for (const auto & pp_name : getPostprocessorOutput())
     135             :     {
     136         384 :       const Real old_pp_value = table.getLastData(pp_name);
     137         384 :       const Real new_pp_value = _problem_ptr->getPostprocessorValueByName(pp_name);
     138         384 :       if (!MooseUtils::absoluteFuzzyEqual(old_pp_value, new_pp_value, _new_row_tol))
     139             :       {
     140         384 :         all_columns_are_identical = false;
     141         384 :         break;
     142             :       }
     143             :     }
     144         384 :     return !all_columns_are_identical;
     145             :   }
     146             :   else
     147        1474 :     return false;
     148             : }
     149             : 
     150             : void
     151      366146 : TableOutput::outputPostprocessorsRow(FormattedTable & table)
     152             : {
     153      366146 :   table.addRow(getOutputTime());
     154             : 
     155     1134644 :   for (const auto & pp_name : getPostprocessorOutput())
     156      768498 :     table.addData(pp_name, _problem_ptr->getPostprocessorValueByName(pp_name));
     157      366146 : }
     158             : 
     159             : void
     160        7447 : TableOutput::outputReporters()
     161             : {
     162             :   // List of VPP objects with output
     163        7447 :   const std::set<std::string> & vpps = getVectorPostprocessorOutput();
     164             : 
     165       30716 :   for (const auto & combined_name : getReporterOutput())
     166             :   {
     167       23269 :     ReporterName r_name(combined_name);
     168             : 
     169       23269 :     outputReporter<bool>(r_name);
     170       23269 :     outputReporter<unsigned short int>(r_name);
     171       23269 :     outputReporter<unsigned int>(r_name);
     172       23269 :     outputReporter<unsigned long int>(r_name);
     173       23269 :     outputReporter<unsigned long long int>(r_name);
     174       23269 :     outputReporter<short int>(r_name);
     175       23269 :     outputReporter<int>(r_name);
     176       23269 :     outputReporter<long int>(r_name);
     177       23269 :     outputReporter<long long int>(r_name);
     178       23269 :     outputReporter<float>(r_name);
     179       23269 :     outputReporter<long double>(r_name);
     180       23269 :     outputReporter<char>(r_name);
     181       23269 :     outputReporter<std::string>(r_name);
     182             : 
     183             :     // Need to check for reals because PPs and VPPs might have already been outputted
     184       69759 :     if (!hasPostprocessorByName(r_name.getObjectName()) &&
     185       46490 :         vpps.find(r_name.getObjectName()) == vpps.end())
     186       23221 :       outputReporter<Real>(r_name);
     187       23269 :   }
     188        7447 : }
     189             : 
     190             : void
     191        7516 : TableOutput::outputVectorPostprocessors()
     192             : {
     193             :   // List of VPP objects with output
     194        7516 :   const std::set<std::string> & out = getVectorPostprocessorOutput();
     195             : 
     196       47957 :   for (const auto & r_name : _reporter_data.getReporterNames())
     197             :   {
     198       40441 :     const std::string & vpp_name = r_name.getObjectName();
     199       40441 :     const std::string & vec_name = r_name.getValueName();
     200       40441 :     const bool vpp_out = out.find(vpp_name) != out.end();
     201       40441 :     if (vpp_out && (_reporter_data.hasReporterValue<VectorPostprocessorValue>(r_name)))
     202             :     {
     203             :       auto insert_pair =
     204       36598 :           moose_try_emplace(_vector_postprocessor_tables, vpp_name, FormattedTable());
     205             : 
     206       36598 :       FormattedTable & table = insert_pair.first->second;
     207       36598 :       table.outputTimeColumn(false);
     208             : 
     209       36598 :       const auto & vector = _reporter_data.getReporterValue<VectorPostprocessorValue>(r_name);
     210       36598 :       table.addData(vec_name, vector);
     211             : 
     212       36598 :       if (_time_data)
     213             :       {
     214         792 :         FormattedTable & t_table = _vector_postprocessor_time_tables[vpp_name];
     215        2376 :         t_table.addData("timestep", _t_step, _time);
     216             :       }
     217             :     }
     218        7516 :   }
     219        7516 : }
     220             : 
     221             : void
     222       31229 : TableOutput::outputScalarVariables()
     223             : {
     224             :   // List of scalar variables
     225       31229 :   const std::set<std::string> & out = getScalarOutput();
     226             : 
     227             :   // Loop through each variable
     228       73047 :   for (const auto & out_name : out)
     229             :   {
     230             :     // Get reference to the variable (0 is for TID)
     231       41818 :     MooseVariableScalar & scalar_var = _problem_ptr->getScalarVariable(0, out_name);
     232             : 
     233             :     // Make sure the value of the variable is in sync with the solution vector
     234       41818 :     scalar_var.reinit();
     235             : 
     236             :     // Next we need to make sure all processors agree on the value of
     237             :     // the variable - not all processors may be able to see all
     238             :     // scalars!
     239             : 
     240             :     // Make a copy rather than taking a reference to the MooseArray,
     241             :     // because if a processor can't see that scalar variable's values
     242             :     // then we'll need to do our own communication of them.
     243       41818 :     VariableValue value(scalar_var.sln());
     244       41818 :     auto value_size = value.size();
     245             : 
     246             :     // libMesh *does* currently guarantee that all processors can
     247             :     // calculate all scalar DoF indices, so this is a const reference
     248       41818 :     const std::vector<dof_id_type> & dof_indices = scalar_var.dofIndices();
     249       41818 :     auto dof_size = dof_indices.size();
     250       41818 :     bool need_release = false;
     251             : 
     252             :     // In dbg mode, if we don't see a scalar we might not even have
     253             :     // its array allocated to full length yet.
     254       41818 :     if (dof_size > value_size)
     255             :     {
     256           0 :       value.resize(dof_size);
     257           0 :       need_release = true;
     258             :     }
     259             : 
     260             :     // Finally, let's just let the owners broadcast their values.
     261             :     // There's probably lots of room to optimize this communication
     262             :     // via merging broadcasts and making them asynchronous, but this
     263             :     // code path shouldn't be hit often enough for that to matter.
     264             : 
     265       41818 :     const DofMap & dof_map = scalar_var.sys().dofMap();
     266       88171 :     for (decltype(dof_size) i = 0; i < dof_size; ++i)
     267             :     {
     268       46353 :       const processor_id_type pid = dof_map.dof_owner(dof_indices[i]);
     269       46353 :       this->comm().broadcast(value[i], pid);
     270             :     }
     271             : 
     272             :     // If the variable has a single component, simply output the value with the name
     273       41818 :     if (dof_size == 1)
     274             :     {
     275       38763 :       _scalar_table.addData(out_name, value[0], getOutputTime());
     276       38763 :       _all_data_table.addData(out_name, value[0], getOutputTime());
     277             :     }
     278             : 
     279             :     // Multi-component variables are appended with the component index
     280             :     else
     281       10645 :       for (decltype(dof_size) i = 0; i < dof_size; ++i)
     282             :       {
     283        7590 :         std::ostringstream os;
     284        7590 :         os << out_name << "_" << i;
     285        7590 :         _scalar_table.addData(os.str(), value[i], getOutputTime());
     286        7590 :         _all_data_table.addData(os.str(), value[i], getOutputTime());
     287        7590 :       }
     288             : 
     289             :     // If we ended up reallocating, we'll need to release memory or leak it
     290       41818 :     if (need_release)
     291           0 :       value.release();
     292       41818 :   }
     293       31229 : }
     294             : 
     295             : void
     296        4691 : TableOutput::clear()
     297             : {
     298        4691 :   _reporter_table.clear();
     299        4691 :   _postprocessor_table.clear();
     300        4811 :   for (auto & pair : _vector_postprocessor_tables)
     301         120 :     pair.second.clear();
     302        4691 :   for (auto & pair : _vector_postprocessor_time_tables)
     303           0 :     pair.second.clear();
     304        4691 :   _scalar_table.clear();
     305        4691 :   _all_data_table.clear();
     306        4691 : }

Generated by: LCOV version 1.14