LCOV - code coverage report
Current view: top level - src/outputs - TableOutput.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 147 151 97.4 %
Date: 2025-08-08 20:01:16 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      215863 : TableOutput::validParams()
      27             : {
      28             :   // Base class parameters
      29      215863 :   InputParameters params = AdvancedOutput::validParams();
      30      215863 :   params += AdvancedOutput::enableOutputTypes("postprocessor scalar vector_postprocessor reporter");
      31             : 
      32             :   // Option for writing vector_postprocessor time file
      33      647589 :   params.addParam<bool>("time_data",
      34      431726 :                         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      215863 :   params.addParam<bool>("append_restart", false, "Append existing file on restart");
      41             : 
      42      647589 :   params.addParam<bool>(
      43             :       "time_column",
      44      431726 :       true,
      45             :       "Whether or not the 'time' column should be written for Postprocessor CSV files");
      46             : 
      47      215863 :   MooseEnum new_row_detection_columns("time all", "time");
      48      215863 :   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      215863 :   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      215863 :   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      647589 :   params.addParam<Real>("new_row_tolerance",
      60      431726 :                         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      215863 :   params.addParamNamesToGroup("new_row_detection_columns new_row_tolerance time_data time_column",
      65             :                               "Table formatting");
      66             : 
      67      431726 :   return params;
      68      215863 : }
      69             : 
      70             : void
      71      604560 : TableOutput::addMultiAppFixedPointIterationEndExecFlag(InputParameters & params,
      72             :                                                        const std::string & param)
      73             : {
      74      604560 :   ExecFlagEnum & execute_on = params.set<ExecFlagEnum>(param, true);
      75      604560 :   execute_on.addAvailableFlags(EXEC_MULTIAPP_FIXED_POINT_ITERATION_END);
      76      604560 :   params.setDocString(param, execute_on.getDocString());
      77      604560 : }
      78             : 
      79       76567 : TableOutput::TableOutput(const InputParameters & parameters)
      80             :   : AdvancedOutput(parameters),
      81       76567 :     _tables_restartable(getParam<bool>("append_restart")),
      82      153134 :     _postprocessor_table(_tables_restartable
      83      153134 :                              ? declareRestartableData<FormattedTable>("postprocessor_table")
      84       76567 :                              : declareRecoverableData<FormattedTable>("postprocessor_table")),
      85       76567 :     _vector_postprocessor_time_tables(
      86      153134 :         _tables_restartable ? declareRestartableData<std::map<std::string, FormattedTable>>(
      87             :                                   "vector_postprocessor_time_table")
      88       76567 :                             : declareRecoverableData<std::map<std::string, FormattedTable>>(
      89             :                                   "vector_postprocessor_time_table")),
      90      153134 :     _scalar_table(_tables_restartable ? declareRestartableData<FormattedTable>("scalar_table")
      91       76567 :                                       : declareRecoverableData<FormattedTable>("scalar_table")),
      92      153134 :     _reporter_table(_tables_restartable ? declareRestartableData<FormattedTable>("reporter_table")
      93       76567 :                                         : declareRecoverableData<FormattedTable>("reporter_table")),
      94      153134 :     _all_data_table(_tables_restartable ? declareRestartableData<FormattedTable>("all_data_table")
      95       76567 :                                         : declareRecoverableData<FormattedTable>("all_data_table")),
      96       76567 :     _check_all_columns_for_new_row(getParam<MooseEnum>("new_row_detection_columns") == "all"),
      97       76567 :     _new_row_tol(getParam<Real>("new_row_tolerance")),
      98       76567 :     _time_data(getParam<bool>("time_data")),
      99      229701 :     _time_column(getParam<bool>("time_column"))
     100             : 
     101             : {
     102             :   // Set a Boolean indicating whether or not we will output the time column
     103       76567 :   _reporter_table.outputTimeColumn(_time_column);
     104       76567 :   _postprocessor_table.outputTimeColumn(_time_column);
     105       76567 :   _all_data_table.outputTimeColumn(_time_column);
     106       76567 : }
     107             : 
     108             : void
     109      182066 : TableOutput::outputPostprocessors()
     110             : {
     111      182066 :   if (shouldOutputPostprocessorsRow(_postprocessor_table))
     112      181329 :     outputPostprocessorsRow(_postprocessor_table);
     113             : 
     114      182066 :   if (shouldOutputPostprocessorsRow(_all_data_table))
     115      181329 :     outputPostprocessorsRow(_all_data_table);
     116      182066 : }
     117             : 
     118             : bool
     119      364132 : TableOutput::shouldOutputPostprocessorsRow(const FormattedTable & table)
     120             : {
     121      364132 :   if (table.empty())
     122       65812 :     return true;
     123             : 
     124             :   // Check time column; all options will output row if time is new
     125      298320 :   const Real old_time = table.getLastTime();
     126      298320 :   const Real new_time = getOutputTime();
     127      298320 :   if (!MooseUtils::absoluteFuzzyEqual(old_time, new_time, _new_row_tol))
     128      296702 :     return true;
     129             : 
     130             :   // Check PP columns if that option enabled
     131        1618 :   if (_check_all_columns_for_new_row)
     132             :   {
     133         144 :     bool all_columns_are_identical = true;
     134         144 :     for (const auto & pp_name : getPostprocessorOutput())
     135             :     {
     136         144 :       const Real old_pp_value = table.getLastData(pp_name);
     137         144 :       const Real new_pp_value = _problem_ptr->getPostprocessorValueByName(pp_name);
     138         144 :       if (!MooseUtils::absoluteFuzzyEqual(old_pp_value, new_pp_value, _new_row_tol))
     139             :       {
     140         144 :         all_columns_are_identical = false;
     141         144 :         break;
     142             :       }
     143             :     }
     144         144 :     return !all_columns_are_identical;
     145             :   }
     146             :   else
     147        1474 :     return false;
     148             : }
     149             : 
     150             : void
     151      362658 : TableOutput::outputPostprocessorsRow(FormattedTable & table)
     152             : {
     153      362658 :   table.addRow(getOutputTime());
     154             : 
     155     1123620 :   for (const auto & pp_name : getPostprocessorOutput())
     156      760962 :     table.addData(pp_name, _problem_ptr->getPostprocessorValueByName(pp_name));
     157      362658 : }
     158             : 
     159             : void
     160        7008 : TableOutput::outputReporters()
     161             : {
     162             :   // List of VPP objects with output
     163        7008 :   const std::set<std::string> & vpps = getVectorPostprocessorOutput();
     164             : 
     165       29466 :   for (const auto & combined_name : getReporterOutput())
     166             :   {
     167       22458 :     ReporterName r_name(combined_name);
     168             : 
     169       22458 :     outputReporter<bool>(r_name);
     170       22458 :     outputReporter<unsigned short int>(r_name);
     171       22458 :     outputReporter<unsigned int>(r_name);
     172       22458 :     outputReporter<unsigned long int>(r_name);
     173       22458 :     outputReporter<unsigned long long int>(r_name);
     174       22458 :     outputReporter<short int>(r_name);
     175       22458 :     outputReporter<int>(r_name);
     176       22458 :     outputReporter<long int>(r_name);
     177       22458 :     outputReporter<long long int>(r_name);
     178       22458 :     outputReporter<float>(r_name);
     179       22458 :     outputReporter<long double>(r_name);
     180       22458 :     outputReporter<char>(r_name);
     181       22458 :     outputReporter<std::string>(r_name);
     182             : 
     183             :     // Need to check for reals because PPs and VPPs might have already been outputted
     184       67326 :     if (!hasPostprocessorByName(r_name.getObjectName()) &&
     185       44868 :         vpps.find(r_name.getObjectName()) == vpps.end())
     186       22410 :       outputReporter<Real>(r_name);
     187       22458 :   }
     188        7008 : }
     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       47937 :   for (const auto & r_name : _reporter_data.getReporterNames())
     197             :   {
     198       40421 :     const std::string & vpp_name = r_name.getObjectName();
     199       40421 :     const std::string & vec_name = r_name.getValueName();
     200       40421 :     const bool vpp_out = out.find(vpp_name) != out.end();
     201       40421 :     if (vpp_out && (_reporter_data.hasReporterValue<VectorPostprocessorValue>(r_name)))
     202             :     {
     203             :       auto insert_pair =
     204       36578 :           moose_try_emplace(_vector_postprocessor_tables, vpp_name, FormattedTable());
     205             : 
     206       36578 :       FormattedTable & table = insert_pair.first->second;
     207       36578 :       table.outputTimeColumn(false);
     208             : 
     209       36578 :       const auto & vector = _reporter_data.getReporterValue<VectorPostprocessorValue>(r_name);
     210       36578 :       table.addData(vec_name, vector);
     211             : 
     212       36578 :       if (_time_data)
     213             :       {
     214         792 :         FormattedTable & t_table = _vector_postprocessor_time_tables[vpp_name];
     215         792 :         t_table.addData("timestep", _t_step, _time);
     216             :       }
     217             :     }
     218        7516 :   }
     219        7516 : }
     220             : 
     221             : void
     222       31133 : TableOutput::outputScalarVariables()
     223             : {
     224             :   // List of scalar variables
     225       31133 :   const std::set<std::string> & out = getScalarOutput();
     226             : 
     227             :   // Loop through each variable
     228       72855 :   for (const auto & out_name : out)
     229             :   {
     230             :     // Get reference to the variable (0 is for TID)
     231       41722 :     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       41722 :     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       41722 :     VariableValue value(scalar_var.sln());
     244       41722 :     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       41722 :     const std::vector<dof_id_type> & dof_indices = scalar_var.dofIndices();
     249       41722 :     auto dof_size = dof_indices.size();
     250       41722 :     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       41722 :     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       41722 :     const DofMap & dof_map = scalar_var.sys().dofMap();
     266       87979 :     for (decltype(dof_size) i = 0; i < dof_size; ++i)
     267             :     {
     268       46257 :       const processor_id_type pid = dof_map.dof_owner(dof_indices[i]);
     269       46257 :       this->comm().broadcast(value[i], pid);
     270             :     }
     271             : 
     272             :     // If the variable has a single component, simply output the value with the name
     273       41722 :     if (dof_size == 1)
     274             :     {
     275       38667 :       _scalar_table.addData(out_name, value[0], getOutputTime());
     276       38667 :       _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       41722 :     if (need_release)
     291           0 :       value.release();
     292       41722 :   }
     293       31133 : }
     294             : 
     295             : void
     296        4568 : TableOutput::clear()
     297             : {
     298        4568 :   _reporter_table.clear();
     299        4568 :   _postprocessor_table.clear();
     300        4688 :   for (auto & pair : _vector_postprocessor_tables)
     301         120 :     pair.second.clear();
     302        4568 :   for (auto & pair : _vector_postprocessor_time_tables)
     303           0 :     pair.second.clear();
     304        4568 :   _scalar_table.clear();
     305        4568 :   _all_data_table.clear();
     306        4568 : }

Generated by: LCOV version 1.14