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 : }
|