LCOV - code coverage report
Current view: top level - src/outputs - CSV.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 145 147 98.6 %
Date: 2025-07-17 01:28:37 Functions: 11 11 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 "CSV.h"
      12             : #include "FEProblem.h"
      13             : #include "MooseApp.h"
      14             : 
      15             : registerMooseObject("MooseApp", CSV);
      16             : 
      17             : InputParameters
      18       42708 : CSV::validParams()
      19             : {
      20             :   // Get the parameters from the parent object
      21       42708 :   InputParameters params = TableOutput::validParams();
      22       42708 :   params.addClassDescription("Output for postprocessors, vector postprocessors, and scalar "
      23             :                              "variables using comma seperated values (CSV).");
      24       42708 :   params.addParam<bool>("sort_columns", false, "Toggle the sorting of columns alphabetically.");
      25             : 
      26             :   // Options for aligning csv output with whitespace padding
      27      128124 :   params.addParam<bool>(
      28             :       "align",
      29       85416 :       false,
      30             :       "Align the outputted csv data by padding the numbers with trailing whitespace");
      31       42708 :   params.addParam<std::string>("delimiter", ",", "Assign the delimiter (default is ','");
      32       42708 :   params.addParam<unsigned int>("precision", 14, "Set the output precision");
      33      128124 :   params.addParam<bool>("create_final_symlink",
      34       85416 :                         false,
      35             :                         "Enable/disable the creation of a _FINAL symlink for vector postprocessor "
      36             :                         "data with 'execute_on' includes 'FINAL'.");
      37      128124 :   params.addParam<bool>(
      38             :       "create_latest_symlink",
      39       85416 :       false,
      40             :       "Enable/disable the creation of a _LATEST symlink for vector postprocessor data.");
      41             : 
      42       42708 :   params.addParamNamesToGroup("sort_columns align delimiter precision", "Table formatting");
      43       42708 :   params.addParamNamesToGroup("create_latest_symlink create_final_symlink", "Symbolic links");
      44             :   // Suppress unused parameters
      45       42708 :   params.suppressParameter<unsigned int>("padding");
      46             : 
      47             :   // Done
      48       42708 :   return params;
      49           0 : }
      50             : 
      51       14147 : CSV::CSV(const InputParameters & parameters)
      52             :   : TableOutput(parameters),
      53       14147 :     _align(getParam<bool>("align")),
      54       14147 :     _precision(getParam<unsigned int>("precision")),
      55       14147 :     _delimiter(getParam<std::string>("delimiter")),
      56       14147 :     _write_all_table(false),
      57       14147 :     _write_vector_table(false),
      58       14147 :     _sort_columns(getParam<bool>("sort_columns")),
      59       14147 :     _recovering(_app.isRecovering()),
      60       14147 :     _create_final_symlink(getParam<bool>("create_final_symlink")),
      61       28294 :     _create_latest_symlink(getParam<bool>("create_latest_symlink"))
      62             : {
      63       14147 : }
      64             : 
      65             : void
      66       13998 : CSV::initialSetup()
      67             : {
      68             :   // Call the base class method
      69       13998 :   TableOutput::initialSetup();
      70             : 
      71             :   // Set the delimiter
      72       13998 :   _all_data_table.setDelimiter(_delimiter);
      73             : 
      74             :   // Set the precision
      75       13998 :   _all_data_table.setPrecision(_precision);
      76             : 
      77       13998 :   if (_recovering)
      78         832 :     _all_data_table.append(true);
      79             : 
      80             :   // Clear any existing symbolic links to LATEST and/or FINAL
      81       13998 :   if (processor_id() == 0)
      82             :   {
      83       10946 :     const std::set<std::string> & out = getVectorPostprocessorOutput();
      84       13240 :     for (const auto & vpp_name : out)
      85             :     {
      86        2294 :       std::string short_name = MooseUtils::shortName(vpp_name);
      87        2294 :       std::string out_latest = _file_base + "_" + short_name + "_LATEST.csv";
      88        2294 :       std::string out_final = _file_base + "_" + short_name + "_FINAL.csv";
      89        2294 :       MooseUtils::clearSymlink(out_latest);
      90        2294 :       MooseUtils::clearSymlink(out_final);
      91        2294 :     }
      92             :   }
      93             : 
      94             :   // See https://github.com/idaholab/moose/issues/25211.
      95             :   mooseAssert(advancedExecuteOn().contains("postprocessors"),
      96             :               "Missing expected postprocessors key");
      97             :   mooseAssert(advancedExecuteOn().contains("scalars"), "Missing expected scalars key");
      98             :   mooseAssert(advancedExecuteOn().contains("reporters"), "Missing expected reporters key");
      99       13998 :   const auto pp_execute_on = advancedExecuteOn().find("postprocessors")->second;
     100       13998 :   const auto scalar_execute_on = advancedExecuteOn().find("scalars")->second;
     101       13998 :   const auto reporter_execute_on = advancedExecuteOn().find("reporters")->second;
     102       13998 :   const auto n_pps = getPostprocessorOutput().size();
     103       13998 :   const auto n_scalars = getScalarOutput().size();
     104       13998 :   const auto n_reporters = getReporterOutput().size();
     105       13998 :   const bool pp_active = n_pps > 0 && !pp_execute_on.isValueSet(EXEC_NONE);
     106       13998 :   const bool scalar_active = n_scalars > 0 && !scalar_execute_on.isValueSet(EXEC_NONE);
     107       13998 :   const bool reporter_active = n_reporters > 0 && !reporter_execute_on.isValueSet(EXEC_NONE);
     108       27992 :   if ((pp_execute_on != scalar_execute_on && pp_active && scalar_active) ||
     109       13994 :       (pp_execute_on != reporter_execute_on && pp_active && reporter_active))
     110           8 :     mooseError("The parameters 'execute_postprocessors_on', 'execute_scalars_on', and "
     111             :                "'execute_reporters_on' must be the same for CSV output.");
     112       13990 : }
     113             : 
     114             : std::string
     115       63266 : CSV::filename()
     116             : {
     117       63266 :   return _file_base + ".csv";
     118             : }
     119             : 
     120             : void
     121       11570 : CSV::outputScalarVariables()
     122             : {
     123       11570 :   TableOutput::outputScalarVariables();
     124       11570 :   _write_all_table = true;
     125       11570 : }
     126             : 
     127             : void
     128       60769 : CSV::outputPostprocessors()
     129             : {
     130       60769 :   TableOutput::outputPostprocessors();
     131       60769 :   _write_all_table = true;
     132       60769 : }
     133             : 
     134             : void
     135        6913 : CSV::outputVectorPostprocessors()
     136             : {
     137        6913 :   TableOutput::outputVectorPostprocessors();
     138        6913 :   _write_vector_table = true;
     139        6913 : }
     140             : 
     141             : void
     142         981 : CSV::outputReporters()
     143             : {
     144         981 :   TableOutput::outputReporters();
     145         981 :   _write_all_table = true;
     146         981 :   _write_vector_table = true;
     147         981 : }
     148             : 
     149             : std::string
     150        5905 : CSV::getVectorPostprocessorFileName(const std::string & vpp_name,
     151             :                                     bool include_time_step,
     152             :                                     bool is_distributed)
     153             : {
     154        5905 :   std::ostringstream file_name;
     155        5905 :   file_name << _file_base;
     156             : 
     157        5905 :   auto short_name = MooseUtils::shortName(vpp_name);
     158        5905 :   if (short_name.size())
     159        5905 :     file_name << '_' << short_name;
     160             : 
     161        5905 :   if (include_time_step)
     162             :   {
     163        5673 :     file_name << '_' << std::setw(_padding) << std::setprecision(0) << std::setfill('0')
     164        5673 :               << std::right << timeStep();
     165             : 
     166        5673 :     if (_current_execute_flag == EXEC_NONLINEAR || _current_execute_flag == EXEC_LINEAR)
     167             :     {
     168         917 :       file_name << '_' << std::setw(_padding) << std::setprecision(0) << std::setfill('0')
     169         917 :                 << std::right << _nonlinear_iter;
     170             :     }
     171        5673 :     if (_current_execute_flag == EXEC_LINEAR)
     172             :     {
     173         765 :       file_name << '_' << std::setw(_padding) << std::setprecision(0) << std::setfill('0')
     174         765 :                 << std::right << _linear_iter;
     175             :     }
     176             :   }
     177             : 
     178        5905 :   file_name << ".csv";
     179             : 
     180        5905 :   if (is_distributed)
     181             :   {
     182         144 :     int digits = MooseUtils::numDigits(n_processors());
     183         144 :     file_name << "." << std::setw(digits) << std::setfill('0') << processor_id();
     184             :   }
     185       11810 :   return file_name.str();
     186        5905 : }
     187             : 
     188             : void
     189       70263 : CSV::output()
     190             : {
     191             :   // Call the base class output (populates tables)
     192       70263 :   TableOutput::output();
     193             : 
     194             :   // Print the table containing all the data to a file
     195       70263 :   if (_write_all_table && !_all_data_table.empty() && processor_id() == 0)
     196             :   {
     197       49268 :     if (_sort_columns)
     198           8 :       _all_data_table.sortColumns();
     199       49268 :     _all_data_table.printCSV(filename(), 1, _align);
     200             :   }
     201             : 
     202             :   // Output each VectorPostprocessor's data to a file
     203       70263 :   if (_write_vector_table)
     204             :   {
     205             :     // The VPP table will not write the same data twice, so to get the symlinks correct
     206             :     // for EXEC_FINAL (when other flags exist) whenever files are written the names must
     207             :     // be stored. These stored names are then used outside of this loop when the EXEC_FINAL call is
     208             :     // made.
     209        7680 :     _latest_vpp_filenames.clear();
     210             : 
     211       15755 :     for (auto & it : _vector_postprocessor_tables)
     212             :     {
     213        8075 :       const auto & vpp_name = it.first;
     214        8075 :       it.second.setDelimiter(_delimiter);
     215        8075 :       it.second.setPrecision(_precision);
     216        8075 :       if (_sort_columns)
     217           0 :         it.second.sortColumns();
     218             : 
     219        8075 :       bool include_time_suffix = true;
     220        8075 :       bool is_distributed = _reporter_data.hasReporterWithMode(vpp_name, REPORTER_MODE_DISTRIBUTED);
     221        8075 :       if (hasVectorPostprocessorByName(vpp_name))
     222             :       {
     223             :         const VectorPostprocessor & vpp_obj =
     224        7625 :             _problem_ptr->getVectorPostprocessorObjectByName(vpp_name);
     225        7625 :         include_time_suffix = !vpp_obj.containsCompleteHistory();
     226             :       }
     227             : 
     228        8075 :       if (is_distributed || processor_id() == 0)
     229             :       {
     230             :         std::string fname =
     231        5905 :             getVectorPostprocessorFileName(vpp_name, include_time_suffix, is_distributed);
     232        5905 :         std::string fprefix = getVectorPostprocessorFilePrefix(vpp_name);
     233             : 
     234        5905 :         _latest_vpp_filenames.emplace_back(fname, fprefix, is_distributed);
     235             : 
     236        5905 :         it.second.printCSV(fname, 1, _align);
     237             : 
     238        5905 :         if (_create_latest_symlink)
     239             :         {
     240         104 :           std::ostringstream out_latest;
     241         104 :           out_latest << fprefix << "_LATEST.csv";
     242         104 :           if (is_distributed)
     243             :           {
     244          24 :             int digits = MooseUtils::numDigits(n_processors());
     245          24 :             out_latest << "." << std::setw(digits) << std::setfill('0') << processor_id();
     246             :           }
     247         104 :           MooseUtils::createSymlink(fname, out_latest.str());
     248         104 :         }
     249             : 
     250        5905 :         if (_time_data)
     251          88 :           _vector_postprocessor_time_tables[vpp_name].printCSV(fprefix + "_time.csv");
     252        5905 :       }
     253             :     }
     254             :   }
     255             : 
     256       70263 :   if (_current_execute_flag == EXEC_FINAL && _create_final_symlink)
     257             :   {
     258          86 :     for (const auto & name_tuple : _latest_vpp_filenames)
     259             :     {
     260          40 :       std::ostringstream out_final;
     261          40 :       out_final << std::get<1>(name_tuple) << "_FINAL.csv";
     262          40 :       if (std::get<2>(name_tuple))
     263             :       {
     264          24 :         int digits = MooseUtils::numDigits(n_processors());
     265          24 :         out_final << "." << std::setw(digits) << std::setfill('0') << processor_id();
     266          24 :         MooseUtils::createSymlink(std::get<0>(name_tuple), out_final.str());
     267             :       }
     268          16 :       else if (processor_id() == 0)
     269          16 :         MooseUtils::createSymlink(std::get<0>(name_tuple), out_final.str());
     270          40 :     }
     271             :   }
     272             : 
     273             :   // Re-set write flags
     274       70263 :   _write_all_table = false;
     275       70263 :   _write_vector_table = false;
     276       70263 : }
     277             : 
     278             : std::string
     279        5905 : CSV::getVectorPostprocessorFilePrefix(const std::string & vpp_name)
     280             : {
     281       11810 :   return _file_base + "_" + MooseUtils::shortName(vpp_name);
     282             : }

Generated by: LCOV version 1.14