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 169015 : TableOutput::validParams()
27 : {
28 : // Base class parameters
29 169015 : InputParameters params = AdvancedOutput::validParams();
30 338030 : params += AdvancedOutput::enableOutputTypes("postprocessor scalar vector_postprocessor reporter");
31 :
32 : // Option for writing vector_postprocessor time file
33 507045 : params.addParam<bool>("time_data",
34 338030 : 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 676060 : params.addParam<bool>("append_restart", false, "Append existing file on restart");
41 :
42 507045 : params.addParam<bool>(
43 : "time_column",
44 338030 : true,
45 : "Whether or not the 'time' column should be written for Postprocessor CSV files");
46 :
47 676060 : MooseEnum new_row_detection_columns("time all", "time");
48 676060 : 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 676060 : 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 676060 : 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 507045 : params.addParam<Real>("new_row_tolerance",
60 338030 : 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 507045 : params.addParamNamesToGroup("new_row_detection_columns new_row_tolerance time_data time_column",
65 : "Table formatting");
66 :
67 338030 : return params;
68 169015 : }
69 :
70 : void
71 497646 : TableOutput::addMultiAppFixedPointIterationEndExecFlag(InputParameters & params,
72 : const std::string & param)
73 : {
74 497646 : ExecFlagEnum & execute_on = params.set<ExecFlagEnum>(param, true);
75 497646 : execute_on.addAvailableFlags(EXEC_MULTIAPP_FIXED_POINT_ITERATION_END);
76 497646 : params.setDocString(param, execute_on.getDocString());
77 497646 : }
78 :
79 75528 : TableOutput::TableOutput(const InputParameters & parameters)
80 : : AdvancedOutput(parameters),
81 75528 : _tables_restartable(getParam<bool>("append_restart")),
82 151056 : _postprocessor_table(_tables_restartable
83 151068 : ? declareRestartableData<FormattedTable>("postprocessor_table")
84 226560 : : declareRecoverableData<FormattedTable>("postprocessor_table")),
85 75528 : _vector_postprocessor_time_tables(
86 151068 : _tables_restartable ? declareRestartableData<std::map<std::string, FormattedTable>>(
87 : "vector_postprocessor_time_table")
88 302076 : : declareRecoverableData<std::map<std::string, FormattedTable>>(
89 : "vector_postprocessor_time_table")),
90 151068 : _scalar_table(_tables_restartable ? declareRestartableData<FormattedTable>("scalar_table")
91 226560 : : declareRecoverableData<FormattedTable>("scalar_table")),
92 151068 : _reporter_table(_tables_restartable ? declareRestartableData<FormattedTable>("reporter_table")
93 226560 : : declareRecoverableData<FormattedTable>("reporter_table")),
94 151068 : _all_data_table(_tables_restartable ? declareRestartableData<FormattedTable>("all_data_table")
95 226560 : : declareRecoverableData<FormattedTable>("all_data_table")),
96 151056 : _check_all_columns_for_new_row(getParam<MooseEnum>("new_row_detection_columns") == "all"),
97 151056 : _new_row_tol(getParam<Real>("new_row_tolerance")),
98 151056 : _time_data(getParam<bool>("time_data")),
99 302112 : _time_column(getParam<bool>("time_column"))
100 :
101 : {
102 : // Set a Boolean indicating whether or not we will output the time column
103 75528 : _reporter_table.outputTimeColumn(_time_column);
104 75528 : _postprocessor_table.outputTimeColumn(_time_column);
105 75528 : _all_data_table.outputTimeColumn(_time_column);
106 75528 : }
107 :
108 : void
109 167976 : TableOutput::outputPostprocessors()
110 : {
111 167976 : if (shouldOutputPostprocessorsRow(_postprocessor_table))
112 167298 : outputPostprocessorsRow(_postprocessor_table);
113 :
114 167976 : if (shouldOutputPostprocessorsRow(_all_data_table))
115 167298 : outputPostprocessorsRow(_all_data_table);
116 167976 : }
117 :
118 : bool
119 335952 : TableOutput::shouldOutputPostprocessorsRow(const FormattedTable & table)
120 : {
121 335952 : if (table.empty())
122 61262 : return true;
123 :
124 : // Check time column; all options will output row if time is new
125 274690 : const Real old_time = table.getLastTime();
126 274690 : const Real new_time = getOutputTime();
127 274690 : if (!MooseUtils::absoluteFuzzyEqual(old_time, new_time, _new_row_tol))
128 272982 : return true;
129 :
130 : // Check PP columns if that option enabled
131 1708 : if (_check_all_columns_for_new_row)
132 : {
133 352 : bool all_columns_are_identical = true;
134 352 : for (const auto & pp_name : getPostprocessorOutput())
135 : {
136 352 : const Real old_pp_value = table.getLastData(pp_name);
137 352 : const Real new_pp_value = _problem_ptr->getPostprocessorValueByName(pp_name);
138 352 : if (!MooseUtils::absoluteFuzzyEqual(old_pp_value, new_pp_value, _new_row_tol))
139 : {
140 352 : all_columns_are_identical = false;
141 352 : break;
142 : }
143 : }
144 352 : return !all_columns_are_identical;
145 : }
146 : else
147 1356 : return false;
148 : }
149 :
150 : void
151 334596 : TableOutput::outputPostprocessorsRow(FormattedTable & table)
152 : {
153 334596 : table.addRow(getOutputTime());
154 :
155 1031032 : for (const auto & pp_name : getPostprocessorOutput())
156 696436 : table.addData(pp_name, _problem_ptr->getPostprocessorValueByName(pp_name));
157 334596 : }
158 :
159 : void
160 7006 : TableOutput::outputReporters()
161 : {
162 : // List of VPP objects with output
163 7006 : const std::set<std::string> & vpps = getVectorPostprocessorOutput();
164 :
165 28738 : for (const auto & combined_name : getReporterOutput())
166 : {
167 21732 : ReporterName r_name(combined_name);
168 :
169 21732 : outputReporter<bool>(r_name);
170 21732 : outputReporter<unsigned short int>(r_name);
171 21732 : outputReporter<unsigned int>(r_name);
172 21732 : outputReporter<unsigned long int>(r_name);
173 21732 : outputReporter<unsigned long long int>(r_name);
174 21732 : outputReporter<short int>(r_name);
175 21732 : outputReporter<int>(r_name);
176 21732 : outputReporter<long int>(r_name);
177 21732 : outputReporter<long long int>(r_name);
178 21732 : outputReporter<float>(r_name);
179 21732 : outputReporter<long double>(r_name);
180 21732 : outputReporter<char>(r_name);
181 21732 : outputReporter<std::string>(r_name);
182 :
183 : // Need to check for reals because PPs and VPPs might have already been outputted
184 65152 : if (!hasPostprocessorByName(r_name.getObjectName()) &&
185 43420 : vpps.find(r_name.getObjectName()) == vpps.end())
186 21688 : outputReporter<Real>(r_name);
187 21732 : }
188 7006 : }
189 :
190 : void
191 7848 : TableOutput::outputVectorPostprocessors()
192 : {
193 : // List of VPP objects with output
194 7848 : const std::set<std::string> & out = getVectorPostprocessorOutput();
195 :
196 49029 : for (const auto & r_name : _reporter_data.getReporterNames())
197 : {
198 41181 : const std::string & vpp_name = r_name.getObjectName();
199 41181 : const std::string & vec_name = r_name.getValueName();
200 41181 : const bool vpp_out = out.find(vpp_name) != out.end();
201 41181 : if (vpp_out && (_reporter_data.hasReporterValue<VectorPostprocessorValue>(r_name)))
202 : {
203 : auto insert_pair =
204 37623 : moose_try_emplace(_vector_postprocessor_tables, vpp_name, FormattedTable());
205 :
206 37623 : FormattedTable & table = insert_pair.first->second;
207 37623 : table.outputTimeColumn(false);
208 :
209 37623 : const auto & vector = _reporter_data.getReporterValue<VectorPostprocessorValue>(r_name);
210 37623 : table.addData(vec_name, vector);
211 :
212 37623 : if (_time_data)
213 : {
214 726 : FormattedTable & t_table = _vector_postprocessor_time_tables[vpp_name];
215 2178 : t_table.addData("timestep", _t_step, _time);
216 : }
217 : }
218 7848 : }
219 7848 : }
220 :
221 : void
222 23358 : TableOutput::outputScalarVariables()
223 : {
224 : // List of scalar variables
225 23358 : const std::set<std::string> & out = getScalarOutput();
226 :
227 : // Loop through each variable
228 54847 : for (const auto & out_name : out)
229 : {
230 : // Get reference to the variable (0 is for TID)
231 31489 : 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 31489 : 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 31489 : VariableValue value(scalar_var.sln());
244 31489 : 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 31489 : const std::vector<dof_id_type> & dof_indices = scalar_var.dofIndices();
249 31489 : auto dof_size = dof_indices.size();
250 31489 : 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 31489 : 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 31489 : const DofMap & dof_map = scalar_var.sys().dofMap();
266 66661 : for (decltype(dof_size) i = 0; i < dof_size; ++i)
267 : {
268 35172 : const processor_id_type pid = dof_map.dof_owner(dof_indices[i]);
269 35172 : this->comm().broadcast(value[i], pid);
270 : }
271 :
272 : // If the variable has a single component, simply output the value with the name
273 31489 : if (dof_size == 1)
274 : {
275 29143 : _scalar_table.addData(out_name, value[0], getOutputTime());
276 29143 : _all_data_table.addData(out_name, value[0], getOutputTime());
277 : }
278 :
279 : // Multi-component variables are appended with the component index
280 : else
281 8375 : for (decltype(dof_size) i = 0; i < dof_size; ++i)
282 : {
283 6029 : std::ostringstream os;
284 6029 : os << out_name << "_" << i;
285 6029 : _scalar_table.addData(os.str(), value[i], getOutputTime());
286 6029 : _all_data_table.addData(os.str(), value[i], getOutputTime());
287 6029 : }
288 :
289 : // If we ended up reallocating, we'll need to release memory or leak it
290 31489 : if (need_release)
291 0 : value.release();
292 31489 : }
293 23358 : }
294 :
295 : void
296 4898 : TableOutput::clear()
297 : {
298 4898 : _reporter_table.clear();
299 4898 : _postprocessor_table.clear();
300 5008 : for (auto & pair : _vector_postprocessor_tables)
301 110 : pair.second.clear();
302 4898 : for (auto & pair : _vector_postprocessor_time_tables)
303 0 : pair.second.clear();
304 4898 : _scalar_table.clear();
305 4898 : _all_data_table.clear();
306 4898 : }
|