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 69941 : SolutionInvalidity::SolutionInvalidity(MooseApp & app)
28 : : ConsoleStreamInterface(app),
29 : ParallelObject(app.comm()),
30 69941 : _solution_invalidity_registry(moose::internal::getSolutionInvalidityRegistry()),
31 69941 : _has_synced(true),
32 69941 : _has_solution_warning(false),
33 139882 : _has_solution_error(false)
34 : {
35 69941 : }
36 :
37 : void
38 106083 : SolutionInvalidity::flagInvalidSolutionInternal(const InvalidSolutionID _invalid_solution_id)
39 : {
40 106083 : std::lock_guard<std::mutex> lock_id(_invalid_mutex);
41 106083 : if (_counts.size() <= _invalid_solution_id)
42 3083 : _counts.resize(_invalid_solution_id + 1);
43 :
44 106083 : ++_counts[_invalid_solution_id].current_counts;
45 106083 : }
46 :
47 : bool
48 384675 : SolutionInvalidity::hasInvalidSolutionWarning() const
49 : {
50 : mooseAssert(_has_synced, "Has not synced");
51 384675 : return _has_solution_warning;
52 : }
53 :
54 : bool
55 724448 : SolutionInvalidity::hasInvalidSolutionError() const
56 : {
57 : mooseAssert(_has_synced, "Has not synced");
58 724448 : return _has_solution_error;
59 : }
60 :
61 : bool
62 384675 : SolutionInvalidity::hasInvalidSolution() const
63 : {
64 384675 : return hasInvalidSolutionWarning() || hasInvalidSolutionError();
65 : }
66 :
67 : void
68 3977702 : SolutionInvalidity::resetSolutionInvalidCurrentIteration()
69 : {
70 : // Zero current counts
71 4444901 : for (auto & entry : _counts)
72 467199 : entry.current_counts = 0;
73 3977702 : }
74 :
75 : void
76 283776 : SolutionInvalidity::resetSolutionInvalidTimeStep()
77 : {
78 : // Reset that we have synced because we're on a new iteration
79 283776 : _has_synced = false;
80 :
81 318104 : for (auto & entry : _counts)
82 34328 : entry.current_timestep_counts = 0;
83 283776 : }
84 :
85 : void
86 3926666 : SolutionInvalidity::solutionInvalidAccumulation()
87 : {
88 4396497 : for (auto & entry : _counts)
89 469831 : entry.current_timestep_counts += entry.current_counts;
90 3926666 : }
91 :
92 : void
93 372622 : SolutionInvalidity::solutionInvalidAccumulationTimeStep(const unsigned int timestep_index)
94 : {
95 410513 : for (auto & entry : _counts)
96 37891 : if (entry.current_timestep_counts)
97 : {
98 4672 : if (entry.timestep_counts.empty() ||
99 1357 : entry.timestep_counts.back().timestep_index != timestep_index)
100 2519 : entry.timestep_counts.emplace_back(timestep_index);
101 3315 : entry.timestep_counts.back().counts = entry.current_timestep_counts;
102 3315 : entry.total_counts += entry.current_timestep_counts;
103 : }
104 372622 : }
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 714 : SolutionInvalidity::printHistory(const ConsoleStream & console,
128 : unsigned int & timestep_interval_size) const
129 : {
130 714 : console << "\nSolution Invalid Warnings History:\n";
131 714 : transientTable(timestep_interval_size).print(console);
132 714 : }
133 :
134 : void
135 4298414 : SolutionInvalidity::syncIteration()
136 : {
137 : std::map<processor_id_type, std::vector<std::tuple<std::string, std::string, int, unsigned int>>>
138 4298414 : data_to_send;
139 :
140 : // Reset this as we need to see if we have new counts
141 4298414 : _has_solution_warning = false;
142 4298414 : _has_solution_error = false;
143 :
144 4805053 : for (const auto id : index_range(_counts))
145 : {
146 506639 : auto & entry = _counts[id];
147 506639 : if (entry.current_counts)
148 : {
149 7764 : const auto & info = _solution_invalidity_registry.item(id);
150 7764 : data_to_send[0].emplace_back(
151 7764 : info.object_type, info.message, info.warning, entry.current_counts);
152 7764 : entry.current_counts = 0;
153 : }
154 : }
155 :
156 4366 : 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 12130 : 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 7764 : const bool warning = warning_int;
167 :
168 7764 : InvalidSolutionID main_id = 0;
169 7764 : const moose::internal::SolutionInvalidityName name(object_type, message);
170 7764 : if (_solution_invalidity_registry.keyExists(name))
171 : {
172 7757 : 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 7764 : if (_counts.size() <= main_id)
183 7 : _counts.resize(main_id + 1);
184 :
185 7764 : _counts[main_id].current_counts += counts;
186 :
187 7764 : if (warning)
188 3001 : _has_solution_warning = true;
189 : else
190 4763 : _has_solution_error = true;
191 : }
192 4366 : };
193 :
194 : // Communicate the counts
195 4298414 : TIMPI::push_parallel_vector_data(comm(), data_to_send, receive_data);
196 :
197 : // Set the state across all processors
198 4298414 : comm().max(_has_solution_warning);
199 4298414 : comm().max(_has_solution_error);
200 :
201 : // We've now synced
202 4298414 : _has_synced = true;
203 4298414 : }
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 1374 : FullTable vtable({"Object", "Converged", "Timestep", "Total", "Message"}, 4);
218 :
219 1374 : 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 1374 : 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 0 : }
255 :
256 : SolutionInvalidity::TimeTable
257 714 : SolutionInvalidity::transientTable(unsigned int & step_interval) const
258 : {
259 : mooseAssert(_has_synced, "Has not synced");
260 :
261 1428 : TimeTable vtable({"Object", "Time", "Stepinterval Count", "Total Count"}, 4);
262 :
263 1428 : 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 1428 : 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 714 : if (processor_id() == 0)
278 : {
279 1426 : for (const auto id : index_range(_counts))
280 : {
281 938 : const auto & entry = _counts[id];
282 938 : const auto & info = _solution_invalidity_registry.item(id);
283 938 : std::vector<unsigned int> interval_counts;
284 938 : std::vector<unsigned int> total_counts;
285 :
286 938 : if (!entry.timestep_counts.empty())
287 : {
288 : // Allow warnings from the setup step
289 2828 : for (unsigned int timestep = 0; timestep <= entry.timestep_counts.back().timestep_index;
290 1892 : timestep += step_interval)
291 : {
292 :
293 1892 : auto start_it = timestep;
294 1892 : auto end_it = (timestep + step_interval < entry.timestep_counts.back().timestep_index)
295 3651 : ? start_it + step_interval
296 1759 : : entry.timestep_counts.back().timestep_index;
297 :
298 1892 : int interval_sum = 0;
299 4407 : for (auto ts_count : entry.timestep_counts)
300 : {
301 : // Allow warnings from the setup step
302 2515 : if (ts_count.timestep_index >= start_it &&
303 2277 : (ts_count.timestep_index < end_it || start_it == end_it))
304 1062 : interval_sum += ts_count.counts;
305 : }
306 :
307 1892 : interval_counts.push_back(interval_sum);
308 : }
309 : }
310 :
311 938 : unsigned int interval_sum = 0;
312 2830 : for (unsigned int interval_index : index_range(interval_counts))
313 : {
314 : std::string interval_index_str =
315 1892 : std::to_string(interval_index) + "-" + std::to_string(interval_index + step_interval);
316 :
317 1892 : interval_sum += interval_counts[interval_index];
318 1892 : vtable.addRow(info.object_type + " : " + info.message, // Object information
319 : interval_index_str, // Interval Index
320 1892 : interval_counts[interval_index], // Interval Counts
321 : interval_sum // Total Iteration Warnings
322 :
323 : );
324 1892 : }
325 938 : }
326 : }
327 714 : return vtable;
328 0 : }
329 :
330 : // Define data store structure for TimestepCounts
331 : void
332 426 : dataStore(std::ostream & stream,
333 : SolutionInvalidity::TimestepCounts & timestep_counts,
334 : void * context)
335 : {
336 426 : dataStore(stream, timestep_counts.timestep_index, context);
337 426 : dataStore(stream, timestep_counts.counts, context);
338 426 : }
339 :
340 : // Define data load structure for TimestepCounts
341 : void
342 226 : dataLoad(std::istream & stream,
343 : SolutionInvalidity::TimestepCounts & timestep_counts,
344 : void * context)
345 : {
346 226 : dataLoad(stream, timestep_counts.timestep_index, context);
347 226 : dataLoad(stream, timestep_counts.counts, context);
348 226 : }
349 :
350 : void
351 45800 : dataStore(std::ostream & stream, SolutionInvalidity & solution_invalidity, void * context)
352 : {
353 45800 : solution_invalidity.syncIteration();
354 :
355 45800 : if (solution_invalidity.processor_id() != 0)
356 5778 : return;
357 :
358 : // Build data structure for store
359 40022 : std::size_t size = solution_invalidity._counts.size();
360 40022 : dataStore(stream, size, context);
361 :
362 40396 : for (const auto id : index_range(solution_invalidity._counts))
363 : {
364 374 : auto & entry = solution_invalidity._counts[id];
365 374 : const auto & info = solution_invalidity._solution_invalidity_registry.item(id);
366 374 : std::string type = info.object_type;
367 374 : std::string message = info.message;
368 374 : bool warning = info.warning;
369 374 : dataStore(stream, type, context);
370 374 : dataStore(stream, message, context);
371 374 : dataStore(stream, warning, context);
372 374 : dataStore(stream, entry.current_counts, context);
373 374 : dataStore(stream, entry.current_timestep_counts, context);
374 374 : dataStore(stream, entry.timestep_counts, context);
375 374 : dataStore(stream, entry.total_counts, context);
376 374 : }
377 : }
378 :
379 : void
380 13984 : dataLoad(std::istream & stream, SolutionInvalidity & solution_invalidity, void * context)
381 : {
382 13984 : if (solution_invalidity.processor_id() != 0)
383 2670 : return;
384 :
385 : std::size_t num_counts;
386 : // load data block size
387 11314 : dataLoad(stream, num_counts, context);
388 :
389 11314 : std::string object_type, message;
390 : bool warning;
391 : InvalidSolutionID id;
392 :
393 : // loop over and load stored data
394 11502 : for (size_t i = 0; i < num_counts; i++)
395 : {
396 188 : dataLoad(stream, object_type, context);
397 188 : dataLoad(stream, message, context);
398 188 : dataLoad(stream, warning, context);
399 :
400 188 : const moose::internal::SolutionInvalidityName name(object_type, message);
401 188 : if (solution_invalidity._solution_invalidity_registry.keyExists(name))
402 136 : id = solution_invalidity._solution_invalidity_registry.id(name);
403 : else
404 52 : id = moose::internal::getSolutionInvalidityRegistry().registerInvalidity(
405 : object_type, message, warning);
406 :
407 188 : if (solution_invalidity._counts.size() <= id)
408 52 : solution_invalidity._counts.resize(id + 1);
409 :
410 188 : auto & entry = solution_invalidity._counts[id];
411 188 : dataLoad(stream, entry.current_counts, context);
412 188 : dataLoad(stream, entry.current_timestep_counts, context);
413 188 : dataLoad(stream, entry.timestep_counts, context);
414 188 : dataLoad(stream, entry.total_counts, context);
415 188 : }
416 11314 : }
|