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