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 62755 : SolutionInvalidity::SolutionInvalidity(MooseApp & app)
28 : : ConsoleStreamInterface(app),
29 : ParallelObject(app.comm()),
30 62755 : _solution_invalidity_registry(moose::internal::getSolutionInvalidityRegistry()),
31 62755 : _has_synced(true),
32 62755 : _has_solution_warning(false),
33 125510 : _has_solution_error(false)
34 : {
35 62755 : }
36 :
37 : void
38 94744 : SolutionInvalidity::flagInvalidSolutionInternal(const InvalidSolutionID _invalid_solution_id)
39 : {
40 94744 : std::lock_guard<std::mutex> lock_id(_invalid_mutex);
41 94744 : if (_counts.size() <= _invalid_solution_id)
42 280 : _counts.resize(_invalid_solution_id + 1);
43 :
44 94744 : ++_counts[_invalid_solution_id].current_counts;
45 94744 : }
46 :
47 : bool
48 346131 : SolutionInvalidity::hasInvalidSolutionWarning() const
49 : {
50 : mooseAssert(_has_synced, "Has not synced");
51 346131 : return _has_solution_warning;
52 : }
53 :
54 : bool
55 650455 : SolutionInvalidity::hasInvalidSolutionError() const
56 : {
57 : mooseAssert(_has_synced, "Has not synced");
58 650455 : return _has_solution_error;
59 : }
60 :
61 : bool
62 346131 : SolutionInvalidity::hasInvalidSolution() const
63 : {
64 346131 : return hasInvalidSolutionWarning() || hasInvalidSolutionError();
65 : }
66 :
67 : void
68 3621545 : SolutionInvalidity::resetSolutionInvalidCurrentIteration()
69 : {
70 : // Zero current counts
71 3625424 : for (auto & entry : _counts)
72 3879 : entry.current_counts = 0;
73 3621545 : }
74 :
75 : void
76 255948 : SolutionInvalidity::resetSolutionInvalidTimeStep()
77 : {
78 : // Reset that we have synced because we're on a new iteration
79 255948 : _has_synced = false;
80 :
81 257041 : for (auto & entry : _counts)
82 1093 : entry.current_timestep_counts = 0;
83 255948 : }
84 :
85 : void
86 3521569 : SolutionInvalidity::solutionInvalidAccumulation()
87 : {
88 3525639 : for (auto & entry : _counts)
89 4070 : entry.current_timestep_counts += entry.current_counts;
90 3521569 : }
91 :
92 : void
93 285162 : SolutionInvalidity::solutionInvalidAccumulationTimeStep(const unsigned int timestep_index)
94 : {
95 286446 : for (auto & entry : _counts)
96 1284 : if (entry.current_timestep_counts)
97 : {
98 1589 : if (entry.timestep_counts.empty() ||
99 728 : entry.timestep_counts.back().timestep_index != timestep_index)
100 245 : entry.timestep_counts.emplace_back(timestep_index);
101 861 : entry.timestep_counts.back().counts = entry.current_timestep_counts;
102 861 : entry.total_counts += entry.current_timestep_counts;
103 : }
104 285162 : }
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 686 : SolutionInvalidity::print(const ConsoleStream & console) const
121 : {
122 686 : console << "\nSolution Invalid Warnings:\n";
123 686 : summaryTable().print(console);
124 686 : }
125 :
126 : void
127 625 : SolutionInvalidity::printHistory(const ConsoleStream & console,
128 : unsigned int & timestep_interval_size) const
129 : {
130 625 : console << "\nSolution Invalid Warnings History:\n";
131 625 : transientTable(timestep_interval_size).print(console);
132 625 : }
133 :
134 : void
135 3857334 : SolutionInvalidity::syncIteration()
136 : {
137 : std::map<processor_id_type, std::vector<std::tuple<std::string, std::string, int, unsigned int>>>
138 3857334 : data_to_send;
139 :
140 : // Reset this as we need to see if we have new counts
141 3857334 : _has_solution_warning = false;
142 3857334 : _has_solution_error = false;
143 :
144 3863733 : for (const auto id : index_range(_counts))
145 : {
146 6399 : auto & entry = _counts[id];
147 6399 : if (entry.current_counts)
148 : {
149 5252 : const auto & info = _solution_invalidity_registry.item(id);
150 5252 : data_to_send[0].emplace_back(
151 5252 : info.object_type, info.message, info.warning, entry.current_counts);
152 5252 : entry.current_counts = 0;
153 : }
154 : }
155 :
156 29159 : 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 8151 : 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 5252 : const bool warning = warning_int;
167 :
168 5252 : InvalidSolutionID main_id = 0;
169 5252 : const moose::internal::SolutionInvalidityName name(object_type, message);
170 5252 : if (_solution_invalidity_registry.keyExists(name))
171 : {
172 5245 : 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 5252 : if (_counts.size() <= main_id)
183 7 : _counts.resize(main_id + 1);
184 :
185 5252 : _counts[main_id].current_counts += counts;
186 :
187 5252 : if (warning)
188 497 : _has_solution_warning = true;
189 : else
190 4755 : _has_solution_error = true;
191 : }
192 2899 : };
193 :
194 : // Communicate the counts
195 3857334 : TIMPI::push_parallel_vector_data(comm(), data_to_send, receive_data);
196 :
197 : // Set the state across all processors
198 3857334 : comm().max(_has_solution_warning);
199 3857334 : comm().max(_has_solution_error);
200 :
201 : // We've now synced
202 3857334 : _has_synced = true;
203 3857334 : }
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 686 : SolutionInvalidity::summaryTable() const
214 : {
215 : mooseAssert(_has_synced, "Has not synced");
216 :
217 4116 : FullTable vtable({"Object", "Converged", "Timestep", "Total", "Message"}, 4);
218 :
219 686 : 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 686 : 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 686 : if (processor_id() == 0)
236 : {
237 1331 : for (const auto id : index_range(_counts))
238 : {
239 857 : const auto & entry = _counts[id];
240 857 : if (entry.current_counts)
241 : {
242 857 : const auto & info = _solution_invalidity_registry.item(id);
243 857 : vtable.addRow(info.object_type, // Object Type
244 857 : entry.current_counts, // Converged Iteration Warnings
245 857 : entry.current_timestep_counts, // Latest Time Step Warnings
246 857 : entry.total_counts, // Total Iteration Warnings
247 857 : info.message // Message
248 : );
249 : }
250 : }
251 : }
252 :
253 686 : return vtable;
254 1372 : }
255 :
256 : SolutionInvalidity::TimeTable
257 625 : SolutionInvalidity::transientTable(unsigned int & step_interval) const
258 : {
259 : mooseAssert(_has_synced, "Has not synced");
260 :
261 3125 : TimeTable vtable({"Object", "Time", "Stepinterval Count", "Total Count"}, 4);
262 :
263 625 : 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 625 : 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 625 : if (processor_id() == 0)
278 : {
279 1246 : for (const auto id : index_range(_counts))
280 : {
281 823 : const auto & entry = _counts[id];
282 823 : const auto & info = _solution_invalidity_registry.item(id);
283 823 : std::vector<unsigned int> interval_counts;
284 823 : std::vector<unsigned int> total_counts;
285 :
286 823 : if (!entry.timestep_counts.empty())
287 : {
288 1775 : for (unsigned int timestep = 0; timestep < entry.timestep_counts.back().timestep_index;
289 954 : timestep += step_interval)
290 : {
291 :
292 954 : auto start_it = timestep;
293 954 : auto end_it = (timestep + step_interval < entry.timestep_counts.back().timestep_index)
294 1775 : ? start_it + step_interval
295 821 : : entry.timestep_counts.back().timestep_index;
296 :
297 954 : int interval_sum = 0;
298 2405 : for (auto ts_count : entry.timestep_counts)
299 : {
300 1451 : if (ts_count.timestep_index >= start_it && ts_count.timestep_index < end_it)
301 126 : interval_sum += ts_count.counts;
302 : }
303 :
304 954 : interval_counts.push_back(interval_sum);
305 : }
306 : }
307 :
308 823 : unsigned int interval_sum = 0;
309 1777 : for (unsigned int interval_index : index_range(interval_counts))
310 : {
311 : std::string interval_index_str =
312 954 : std::to_string(interval_index) + "-" + std::to_string(interval_index + step_interval);
313 :
314 954 : interval_sum += interval_counts[interval_index];
315 954 : vtable.addRow(info.object_type + " : " + info.message, // Object information
316 : interval_index_str, // Interval Index
317 954 : interval_counts[interval_index], // Interval Counts
318 : interval_sum // Total Iteration Warnings
319 :
320 : );
321 954 : }
322 823 : }
323 : }
324 625 : return vtable;
325 1250 : }
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 41839 : dataStore(std::ostream & stream, SolutionInvalidity & solution_invalidity, void * context)
349 : {
350 41839 : solution_invalidity.syncIteration();
351 :
352 41839 : if (solution_invalidity.processor_id() != 0)
353 5703 : return;
354 :
355 : // Build data structure for store
356 36136 : std::size_t size = solution_invalidity._counts.size();
357 36136 : dataStore(stream, size, context);
358 :
359 36175 : 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 12748 : dataLoad(std::istream & stream, SolutionInvalidity & solution_invalidity, void * context)
378 : {
379 12748 : if (solution_invalidity.processor_id() != 0)
380 2665 : return;
381 :
382 : std::size_t num_counts;
383 : // load data block size
384 10083 : dataLoad(stream, num_counts, context);
385 :
386 10083 : std::string object_type, message;
387 : bool warning;
388 : InvalidSolutionID id;
389 :
390 : // loop over and load stored data
391 10108 : 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 10083 : }
|