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