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 "SolutionInvalidity.h"
11 :
12 : // MOOSE Includes
13 : #include "MooseError.h"
14 : #include "MooseApp.h"
15 : #include "VariadicTable.h"
16 :
17 : // System Includes
18 : #include <chrono>
19 : #include <memory>
20 : #include <timpi/parallel_sync.h>
21 : #include <numeric>
22 :
23 : // libMesh Includes
24 : #include "libmesh/parallel_algebra.h"
25 : #include "libmesh/parallel_sync.h"
26 :
27 67610 : SolutionInvalidity::SolutionInvalidity(MooseApp & app)
28 : : ConsoleStreamInterface(app),
29 : ParallelObject(app.comm()),
30 67610 : _solution_invalidity_registry(moose::internal::getSolutionInvalidityRegistry()),
31 67610 : _has_synced(true),
32 67610 : _has_solution_warning(false),
33 135220 : _has_solution_error(false)
34 : {
35 67610 : }
36 :
37 : void
38 102073 : SolutionInvalidity::flagInvalidSolutionInternal(const InvalidSolutionID _invalid_solution_id)
39 : {
40 102073 : std::lock_guard<std::mutex> lock_id(_invalid_mutex);
41 102073 : if (_counts.size() <= _invalid_solution_id)
42 291 : _counts.resize(_invalid_solution_id + 1);
43 :
44 102073 : ++_counts[_invalid_solution_id].current_counts;
45 102073 : }
46 :
47 : bool
48 377312 : SolutionInvalidity::hasInvalidSolutionWarning() const
49 : {
50 : mooseAssert(_has_synced, "Has not synced");
51 377312 : return _has_solution_warning;
52 : }
53 :
54 : bool
55 711889 : SolutionInvalidity::hasInvalidSolutionError() const
56 : {
57 : mooseAssert(_has_synced, "Has not synced");
58 711889 : return _has_solution_error;
59 : }
60 :
61 : bool
62 377312 : SolutionInvalidity::hasInvalidSolution() const
63 : {
64 377312 : return hasInvalidSolutionWarning() || hasInvalidSolutionError();
65 : }
66 :
67 : void
68 3907319 : SolutionInvalidity::resetSolutionInvalidCurrentIteration()
69 : {
70 : // Zero current counts
71 3911258 : for (auto & entry : _counts)
72 3939 : entry.current_counts = 0;
73 3907319 : }
74 :
75 : void
76 279417 : SolutionInvalidity::resetSolutionInvalidTimeStep()
77 : {
78 : // Reset that we have synced because we're on a new iteration
79 279417 : _has_synced = false;
80 :
81 280514 : for (auto & entry : _counts)
82 1097 : entry.current_timestep_counts = 0;
83 279417 : }
84 :
85 : void
86 3799686 : SolutionInvalidity::solutionInvalidAccumulation()
87 : {
88 3803818 : for (auto & entry : _counts)
89 4132 : entry.current_timestep_counts += entry.current_counts;
90 3799686 : }
91 :
92 : void
93 311110 : SolutionInvalidity::solutionInvalidAccumulationTimeStep(const unsigned int timestep_index)
94 : {
95 312400 : for (auto & entry : _counts)
96 1290 : if (entry.current_timestep_counts)
97 : {
98 1591 : if (entry.timestep_counts.empty() ||
99 728 : entry.timestep_counts.back().timestep_index != timestep_index)
100 247 : entry.timestep_counts.emplace_back(timestep_index);
101 863 : entry.timestep_counts.back().counts = entry.current_timestep_counts;
102 863 : entry.total_counts += entry.current_timestep_counts;
103 : }
104 311110 : }
105 :
106 : void
107 0 : SolutionInvalidity::computeTotalCounts()
108 : {
109 : mooseAssert(_has_synced, "Has not synced");
110 :
111 0 : for (auto & entry : _counts)
112 : {
113 0 : entry.total_counts = 0;
114 0 : for (auto & time_counts : entry.timestep_counts)
115 0 : entry.total_counts += time_counts.counts;
116 : }
117 0 : }
118 :
119 : void
120 687 : SolutionInvalidity::print(const ConsoleStream & console) const
121 : {
122 687 : console << "\nSolution Invalid Warnings:\n";
123 687 : summaryTable().print(console);
124 687 : }
125 :
126 : void
127 626 : SolutionInvalidity::printHistory(const ConsoleStream & console,
128 : unsigned int & timestep_interval_size) const
129 : {
130 626 : console << "\nSolution Invalid Warnings History:\n";
131 626 : transientTable(timestep_interval_size).print(console);
132 626 : }
133 :
134 : void
135 4165226 : SolutionInvalidity::syncIteration()
136 : {
137 : std::map<processor_id_type, std::vector<std::tuple<std::string, std::string, int, unsigned int>>>
138 4165226 : data_to_send;
139 :
140 : // Reset this as we need to see if we have new counts
141 4165226 : _has_solution_warning = false;
142 4165226 : _has_solution_error = false;
143 :
144 4171693 : for (const auto id : index_range(_counts))
145 : {
146 6467 : auto & entry = _counts[id];
147 6467 : if (entry.current_counts)
148 : {
149 5260 : const auto & info = _solution_invalidity_registry.item(id);
150 5260 : data_to_send[0].emplace_back(
151 5260 : info.object_type, info.message, info.warning, entry.current_counts);
152 5260 : entry.current_counts = 0;
153 : }
154 : }
155 :
156 29203 : const auto receive_data = [this](const processor_id_type libmesh_dbg_var(pid), const auto & data)
157 : {
158 : mooseAssert(processor_id() == 0, "Should only receive on processor 0");
159 :
160 8163 : for (const auto & [object_type, message, warning_int, counts] : data)
161 : {
162 : mooseAssert(counts, "Should not send data without counts");
163 :
164 : // We transfer this as an integer (which is guaranteed by the standard to cast to a bool)
165 : // because TIMPI doesn't currently support transferring bools
166 5260 : const bool warning = warning_int;
167 :
168 5260 : InvalidSolutionID main_id = 0;
169 5260 : const moose::internal::SolutionInvalidityName name(object_type, message);
170 5260 : if (_solution_invalidity_registry.keyExists(name))
171 : {
172 5253 : main_id = _solution_invalidity_registry.id(name);
173 : mooseAssert(_solution_invalidity_registry.item(main_id).warning == warning,
174 : "Inconsistent registration of invalidity warning and error");
175 : }
176 : else
177 : {
178 : mooseAssert(pid != 0, "Should only hit on other processors");
179 7 : main_id = moose::internal::getSolutionInvalidityRegistry().registerInvalidity(
180 : object_type, message, warning);
181 : }
182 5260 : if (_counts.size() <= main_id)
183 7 : _counts.resize(main_id + 1);
184 :
185 5260 : _counts[main_id].current_counts += counts;
186 :
187 5260 : if (warning)
188 497 : _has_solution_warning = true;
189 : else
190 4763 : _has_solution_error = true;
191 : }
192 2903 : };
193 :
194 : // Communicate the counts
195 4165226 : TIMPI::push_parallel_vector_data(comm(), data_to_send, receive_data);
196 :
197 : // Set the state across all processors
198 4165226 : comm().max(_has_solution_warning);
199 4165226 : comm().max(_has_solution_error);
200 :
201 : // We've now synced
202 4165226 : _has_synced = true;
203 4165226 : }
204 :
205 : void
206 672 : SolutionInvalidity::printDebug(InvalidSolutionID _invalid_solution_id) const
207 : {
208 672 : const auto & info = _solution_invalidity_registry.item(_invalid_solution_id);
209 672 : _console << info.object_type << ": " << info.message << "\n" << std::flush;
210 672 : }
211 :
212 : SolutionInvalidity::FullTable
213 687 : SolutionInvalidity::summaryTable() const
214 : {
215 : mooseAssert(_has_synced, "Has not synced");
216 :
217 4122 : FullTable vtable({"Object", "Converged", "Timestep", "Total", "Message"}, 4);
218 :
219 687 : vtable.setColumnFormat({
220 : VariadicTableColumnFormat::AUTO, // Object Type
221 : VariadicTableColumnFormat::AUTO, // Converged Iteration Warnings
222 : VariadicTableColumnFormat::AUTO, // Latest Time Step Warnings
223 : VariadicTableColumnFormat::AUTO, // Total Simulation Warnings
224 : VariadicTableColumnFormat::AUTO, // Message
225 : });
226 :
227 687 : vtable.setColumnPrecision({
228 : 1, // Object Name
229 : 0, // Converged Iteration Warnings
230 : 0, // Latest Time Step Warnings
231 : 0, // Total Simulation Warnings
232 : 1, // Message
233 : });
234 :
235 687 : if (processor_id() == 0)
236 : {
237 1334 : for (const auto id : index_range(_counts))
238 : {
239 859 : const auto & entry = _counts[id];
240 859 : if (entry.current_counts)
241 : {
242 859 : const auto & info = _solution_invalidity_registry.item(id);
243 859 : vtable.addRow(info.object_type, // Object Type
244 859 : entry.current_counts, // Converged Iteration Warnings
245 859 : entry.current_timestep_counts, // Latest Time Step Warnings
246 859 : entry.total_counts, // Total Iteration Warnings
247 859 : info.message // Message
248 : );
249 : }
250 : }
251 : }
252 :
253 687 : return vtable;
254 1374 : }
255 :
256 : SolutionInvalidity::TimeTable
257 626 : SolutionInvalidity::transientTable(unsigned int & step_interval) const
258 : {
259 : mooseAssert(_has_synced, "Has not synced");
260 :
261 3130 : TimeTable vtable({"Object", "Time", "Stepinterval Count", "Total Count"}, 4);
262 :
263 626 : vtable.setColumnFormat({
264 : VariadicTableColumnFormat::AUTO, // Object information
265 : VariadicTableColumnFormat::AUTO, // Simulation Time Step
266 : VariadicTableColumnFormat::AUTO, // Latest Time Step Warnings
267 : VariadicTableColumnFormat::AUTO, // Total Iteration Warnings
268 : });
269 :
270 626 : vtable.setColumnPrecision({
271 : 1, // Object information
272 : 1, // Simulation Time Step
273 : 0, // Latest Time Step Warnings
274 : 0, // Total Iteration Warnings
275 : });
276 :
277 626 : if (processor_id() == 0)
278 : {
279 1249 : for (const auto id : index_range(_counts))
280 : {
281 825 : const auto & entry = _counts[id];
282 825 : const auto & info = _solution_invalidity_registry.item(id);
283 825 : std::vector<unsigned int> interval_counts;
284 825 : std::vector<unsigned int> total_counts;
285 :
286 825 : if (!entry.timestep_counts.empty())
287 : {
288 1779 : for (unsigned int timestep = 0; timestep < entry.timestep_counts.back().timestep_index;
289 956 : timestep += step_interval)
290 : {
291 :
292 956 : auto start_it = timestep;
293 956 : auto end_it = (timestep + step_interval < entry.timestep_counts.back().timestep_index)
294 1779 : ? start_it + step_interval
295 823 : : entry.timestep_counts.back().timestep_index;
296 :
297 956 : int interval_sum = 0;
298 2409 : for (auto ts_count : entry.timestep_counts)
299 : {
300 1453 : if (ts_count.timestep_index >= start_it && ts_count.timestep_index < end_it)
301 126 : interval_sum += ts_count.counts;
302 : }
303 :
304 956 : interval_counts.push_back(interval_sum);
305 : }
306 : }
307 :
308 825 : unsigned int interval_sum = 0;
309 1781 : for (unsigned int interval_index : index_range(interval_counts))
310 : {
311 : std::string interval_index_str =
312 956 : std::to_string(interval_index) + "-" + std::to_string(interval_index + step_interval);
313 :
314 956 : interval_sum += interval_counts[interval_index];
315 956 : vtable.addRow(info.object_type + " : " + info.message, // Object information
316 : interval_index_str, // Interval Index
317 956 : interval_counts[interval_index], // Interval Counts
318 : interval_sum // Total Iteration Warnings
319 :
320 : );
321 956 : }
322 825 : }
323 : }
324 626 : return vtable;
325 1252 : }
326 :
327 : // Define data store structure for TimestepCounts
328 : void
329 44 : dataStore(std::ostream & stream,
330 : SolutionInvalidity::TimestepCounts & timestep_counts,
331 : void * context)
332 : {
333 44 : dataStore(stream, timestep_counts.timestep_index, context);
334 44 : dataStore(stream, timestep_counts.counts, context);
335 44 : }
336 :
337 : // Define data load structure for TimestepCounts
338 : void
339 30 : dataLoad(std::istream & stream,
340 : SolutionInvalidity::TimestepCounts & timestep_counts,
341 : void * context)
342 : {
343 30 : dataLoad(stream, timestep_counts.timestep_index, context);
344 30 : dataLoad(stream, timestep_counts.counts, context);
345 30 : }
346 :
347 : void
348 45214 : dataStore(std::ostream & stream, SolutionInvalidity & solution_invalidity, void * context)
349 : {
350 45214 : solution_invalidity.syncIteration();
351 :
352 45214 : if (solution_invalidity.processor_id() != 0)
353 5749 : return;
354 :
355 : // Build data structure for store
356 39465 : std::size_t size = solution_invalidity._counts.size();
357 39465 : dataStore(stream, size, context);
358 :
359 39504 : for (const auto id : index_range(solution_invalidity._counts))
360 : {
361 39 : auto & entry = solution_invalidity._counts[id];
362 39 : const auto & info = solution_invalidity._solution_invalidity_registry.item(id);
363 39 : std::string type = info.object_type;
364 39 : std::string message = info.message;
365 39 : bool warning = info.warning;
366 39 : dataStore(stream, type, context);
367 39 : dataStore(stream, message, context);
368 39 : dataStore(stream, warning, context);
369 39 : dataStore(stream, entry.current_counts, context);
370 39 : dataStore(stream, entry.current_timestep_counts, context);
371 39 : dataStore(stream, entry.timestep_counts, context);
372 39 : dataStore(stream, entry.total_counts, context);
373 39 : }
374 : }
375 :
376 : void
377 13740 : dataLoad(std::istream & stream, SolutionInvalidity & solution_invalidity, void * context)
378 : {
379 13740 : if (solution_invalidity.processor_id() != 0)
380 2652 : return;
381 :
382 : std::size_t num_counts;
383 : // load data block size
384 11088 : dataLoad(stream, num_counts, context);
385 :
386 11088 : std::string object_type, message;
387 : bool warning;
388 : InvalidSolutionID id;
389 :
390 : // loop over and load stored data
391 11113 : for (size_t i = 0; i < num_counts; i++)
392 : {
393 25 : dataLoad(stream, object_type, context);
394 25 : dataLoad(stream, message, context);
395 25 : dataLoad(stream, warning, context);
396 :
397 25 : const moose::internal::SolutionInvalidityName name(object_type, message);
398 25 : if (solution_invalidity._solution_invalidity_registry.keyExists(name))
399 0 : id = solution_invalidity._solution_invalidity_registry.id(name);
400 : else
401 25 : id = moose::internal::getSolutionInvalidityRegistry().registerInvalidity(
402 : object_type, message, warning);
403 :
404 25 : if (solution_invalidity._counts.size() <= id)
405 25 : solution_invalidity._counts.resize(id + 1);
406 :
407 25 : auto & entry = solution_invalidity._counts[id];
408 25 : dataLoad(stream, entry.current_counts, context);
409 25 : dataLoad(stream, entry.current_timestep_counts, context);
410 25 : dataLoad(stream, entry.timestep_counts, context);
411 25 : dataLoad(stream, entry.total_counts, context);
412 25 : }
413 11088 : }
|