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