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 : #pragma once
11 :
12 : #include "Moose.h"
13 : #include "MooseException.h"
14 : #include "libmesh/threads.h"
15 :
16 : #include "libmesh/print_trace.h"
17 : #include "libmesh/libmesh_common.h"
18 :
19 : // C++ includes
20 : #include <cstdlib>
21 : #include <tuple>
22 : #include <type_traits>
23 :
24 : // Used in numerous downstream classes without 'libMesh::' prefix
25 : using libMesh::demangle;
26 :
27 : namespace MetaPhysicL
28 : {
29 : class LogicError;
30 : }
31 :
32 : namespace hit
33 : {
34 : class Node;
35 : }
36 :
37 : // this function allows streaming tuples to ostreams
38 : template <size_t n, typename... T>
39 : void
40 : print_tuple(std::ostream & os, const std::tuple<T...> & tup)
41 : {
42 : if constexpr (n < sizeof...(T))
43 : {
44 : if (n != 0)
45 : os << ", ";
46 : os << std::get<n>(tup);
47 : print_tuple<n + 1>(os, tup);
48 : }
49 : }
50 : template <typename... T>
51 : std::ostream &
52 : operator<<(std::ostream & os, const std::tuple<T...> & tup)
53 : {
54 : os << "[";
55 : print_tuple<0>(os, tup);
56 : return os << "]";
57 : }
58 :
59 : /// Application abort macro. Uses MPI_Abort if available, std::abort otherwise
60 : #if defined(LIBMESH_HAVE_MPI)
61 : #define MOOSE_ABORT \
62 : do \
63 : { \
64 : MPI_Abort(libMesh::GLOBAL_COMM_WORLD, 1); \
65 : std::abort(); \
66 : } while (0)
67 : #else
68 : #define MOOSE_ABORT \
69 : do \
70 : { \
71 : std::abort(); \
72 : } while (0)
73 : #endif
74 :
75 : #define mooseDoOnce(do_this) \
76 : do \
77 : { \
78 : static bool did_this_already = false; \
79 : if (Moose::show_multiple || !did_this_already) \
80 : { \
81 : did_this_already = true; \
82 : do_this; \
83 : } \
84 : } while (0)
85 :
86 : #define mooseCheckMPIErr(err) \
87 : do \
88 : { \
89 : if (err != MPI_SUCCESS) \
90 : moose::internal::mooseErrorRaw(""); \
91 : } while (0)
92 :
93 : #define mooseException(...) \
94 : do \
95 : { \
96 : throw MooseException(__VA_ARGS__); \
97 : } while (0)
98 :
99 : #ifdef NDEBUG
100 : #define mooseAssert(asserted, msg) ((void)0)
101 : #else
102 : #define mooseAssert(asserted, msg) \
103 : do \
104 : { \
105 : if (!(asserted)) \
106 : { \
107 : std::ostringstream _assert_oss_; \
108 : _assert_oss_ << COLOR_RED << "\n\nAssertion `" #asserted "' failed\n" \
109 : << msg << "\nat " << __FILE__ << ", line " << __LINE__ << COLOR_DEFAULT \
110 : << std::endl; \
111 : if (Moose::_throw_on_error) \
112 : throw std::runtime_error(_assert_oss_.str()); \
113 : else \
114 : { \
115 : Moose::err << _assert_oss_.str() << std::flush; \
116 : moose::internal::mooseErrorRaw(""); \
117 : } \
118 : } \
119 : } while (0)
120 : #endif
121 :
122 : template <typename... Args>
123 : [[noreturn]] void mooseError(Args &&... args);
124 :
125 : /**
126 : * Exception to be thrown whenever we have _throw_on_error set and a
127 : * mooseError() is emitted.
128 : *
129 : * Enables adding the context of the hit node from the location in input
130 : * associated with the error, which can be used in the MooseServer to
131 : * produce diagnostics without parsing messages.
132 : */
133 : class MooseRuntimeError : public std::runtime_error
134 : {
135 : public:
136 243 : MooseRuntimeError(const std::string & message, const hit::Node * const node)
137 243 : : runtime_error(message), _node(node)
138 : {
139 243 : }
140 :
141 : /// Get the associated hit node, if any
142 1 : const hit::Node * getNode() const { return _node; }
143 :
144 : private:
145 : /// The associated hit node, if any
146 : const hit::Node * const _node;
147 : };
148 :
149 : class MooseVariableFieldBase;
150 :
151 : namespace moose
152 : {
153 :
154 : namespace internal
155 : {
156 : inline libMesh::Threads::spin_mutex moose_stream_lock;
157 :
158 : /// Builds and returns a string of the form:
159 : ///
160 : /// [var1-elemtype],ORDER[var1-order] != [var2-elemtype],ORDER[var2-order]
161 : ///
162 : /// This is a convenience function to be used when error messages (especially with paramError)
163 : /// need to report that variable types are incompatible (e.g. with residual save-in).
164 : std::string incompatVarMsg(MooseVariableFieldBase & var1, MooseVariableFieldBase & var2);
165 :
166 : /**
167 : * Format a message for output with a title
168 : * @param msg The message to print
169 : * @param title The title that will go on a line before the message
170 : * @param color The color to print the message in
171 : * @return The formatted message
172 : */
173 : std::string
174 : mooseMsgFmt(const std::string & msg, const std::string & title, const std::string & color);
175 :
176 : /**
177 : * Format a message for output without a title
178 : * @param msg The message to print
179 : * @param color The color to print the message in
180 : * @return The formatted message
181 : */
182 : std::string mooseMsgFmt(const std::string & msg, const std::string & color);
183 :
184 : /**
185 : * Main callback for emitting a moose error.
186 : * @param msg The error message
187 : * @param prefix Optional prefix to add to every line of the error (for multiapp prefixes)
188 : * @param node Optional HIT node to associate with the error, adding file path context
189 : */
190 : [[noreturn]] void
191 : mooseErrorRaw(std::string msg, const std::string & prefix = "", const hit::Node * node = nullptr);
192 :
193 : /**
194 : * All of the following are not meant to be called directly - they are called by the normal macros
195 : * (mooseError(), etc.) down below
196 : * @{
197 : */
198 : void mooseStreamAll(std::ostringstream & ss);
199 :
200 : template <typename T, typename... Args>
201 : void
202 74593 : mooseStreamAll(std::ostringstream & ss, T && val, Args &&... args)
203 : {
204 74593 : ss << val;
205 74593 : mooseStreamAll(ss, std::forward<Args>(args)...);
206 74593 : }
207 :
208 : template <typename S, typename... Args>
209 : void
210 3769 : mooseWarningStream(S & oss, Args &&... args)
211 : {
212 3769 : if (Moose::_warnings_are_errors)
213 195 : mooseError(std::forward<Args>(args)...);
214 :
215 3574 : std::ostringstream ss;
216 3574 : mooseStreamAll(ss, args...);
217 10722 : std::string msg = mooseMsgFmt(ss.str(), "*** Warning ***", COLOR_YELLOW);
218 3574 : if (Moose::_throw_on_warning)
219 1 : throw std::runtime_error(msg);
220 :
221 : {
222 3573 : libMesh::Threads::spin_mutex::scoped_lock lock(moose_stream_lock);
223 3573 : oss << msg << std::flush;
224 3573 : }
225 3575 : }
226 :
227 : template <typename S, typename... Args>
228 : void
229 51 : mooseUnusedStream(S & oss, Args &&... args)
230 : {
231 51 : std::ostringstream ss;
232 51 : mooseStreamAll(ss, args...);
233 153 : std::string msg = mooseMsgFmt(ss.str(), "*** Warning ***", COLOR_YELLOW);
234 51 : if (Moose::_throw_on_warning)
235 0 : throw std::runtime_error(msg);
236 :
237 : {
238 51 : libMesh::Threads::spin_mutex::scoped_lock lock(moose_stream_lock);
239 51 : oss << msg << std::flush;
240 51 : }
241 51 : }
242 :
243 : template <typename S, typename... Args>
244 : void
245 21473 : mooseInfoStreamRepeated(S & oss, Args &&... args)
246 : {
247 21473 : std::ostringstream ss;
248 21473 : mooseStreamAll(ss, args...);
249 64419 : std::string msg = mooseMsgFmt(ss.str(), "*** Info ***", COLOR_CYAN);
250 : {
251 21473 : libMesh::Threads::spin_mutex::scoped_lock lock(moose_stream_lock);
252 21473 : oss << msg << std::flush;
253 21473 : }
254 21473 : }
255 :
256 : template <typename S, typename... Args>
257 : void
258 11890 : mooseInfoStream(S & oss, Args &&... args)
259 : {
260 11890 : mooseDoOnce(mooseInfoStreamRepeated(oss, args...););
261 11890 : }
262 :
263 : template <typename S, typename... Args>
264 : void
265 14665 : mooseDeprecatedStream(S & oss, const bool expired, const bool print_title, Args &&... args)
266 : {
267 14665 : if (Moose::_deprecated_is_error)
268 13 : mooseError("\n\nDeprecated code:\n", std::forward<Args>(args)...);
269 :
270 14652 : std::ostringstream ss;
271 14652 : mooseStreamAll(ss, args...);
272 :
273 14652 : const auto color = expired ? COLOR_RED : COLOR_YELLOW;
274 58608 : std::string msg = print_title ? mooseMsgFmt(ss.str(), "*** Deprecation Warning ***", color)
275 : : mooseMsgFmt(ss.str(), color);
276 14652 : oss << msg;
277 14652 : ss.str("");
278 14652 : if (Moose::show_trace)
279 : {
280 12118 : if (libMesh::global_n_processors() == 1)
281 6858 : libMesh::print_trace(ss);
282 : else
283 5260 : libMesh::write_traceout();
284 : {
285 12118 : libMesh::Threads::spin_mutex::scoped_lock lock(moose_stream_lock);
286 12118 : oss << ss.str() << std::endl;
287 12118 : };
288 : };
289 14652 : }
290 : /**
291 : * @}
292 : */
293 :
294 : /**
295 : * Formats a documented error. A documented error is an error that has
296 : * an issue associated with it.
297 : *
298 : * The repository name \p repo_name links a named repository to a URL
299 : * and should be registered at the application level with registerRepository().
300 : * See Moose.C for an example of the "moose" repository registration.
301 : *
302 : * @param repo_name The repository name where the issue resides
303 : * @param issue_num The number of the issue
304 : * @param msg The specific error message
305 : */
306 : std::string formatMooseDocumentedError(const std::string & repo_name,
307 : const unsigned int issue_num,
308 : const std::string & msg);
309 : } // namespace internal
310 :
311 : /**
312 : * emit a relatively clear error message when we catch a MetaPhysicL logic error
313 : */
314 : void translateMetaPhysicLError(const MetaPhysicL::LogicError &);
315 :
316 : } // namespace moose
317 :
318 : /// Emit an error message with the given stringified, concatenated args and
319 : /// terminate the application. Inside static functions, you will need to
320 : /// explicitly scope your mooseError call - i.e. do "::mooseError(arg1, ...);".
321 : template <typename... Args>
322 : [[noreturn]] void
323 1224 : mooseError(Args &&... args)
324 : {
325 1224 : std::ostringstream oss;
326 1224 : moose::internal::mooseStreamAll(oss, std::forward<Args>(args)...);
327 1602 : moose::internal::mooseErrorRaw(oss.str());
328 189 : }
329 :
330 : /**
331 : * Emit a documented error message with the given stringified, concatenated args
332 : * and terminate the application. Inside static functions, you will need to
333 : * explicitly scope your mooseError call - i.e. do "::mooseError(arg1, ...);".
334 : *
335 : * Here, a documented error message is one with an associated issue. See
336 : * formatMooseDocumentedError for more information.
337 : *
338 : * @param repo_name The repository name where the issue resides
339 : * @param issue_num The number of the issue
340 : * @param args The error message to stringify
341 : **/
342 : template <typename... Args>
343 : [[noreturn]] void
344 1 : mooseDocumentedError(const std::string & repo_name, const unsigned int issue_num, Args &&... args)
345 : {
346 1 : std::ostringstream oss;
347 1 : moose::internal::mooseStreamAll(oss, std::forward<Args>(args)...);
348 4 : moose::internal::mooseErrorRaw(
349 : moose::internal::formatMooseDocumentedError(repo_name, issue_num, oss.str()));
350 1 : }
351 :
352 : /// Emit a warning message with the given stringified, concatenated args.
353 : /// Inside static functions, you will need to explicitly scope your
354 : /// mooseWarning call - i.e. do "::mooseWarning(arg1, ...);".
355 : template <typename... Args>
356 : void
357 1104 : mooseWarning(Args &&... args)
358 : {
359 1104 : moose::internal::mooseWarningStream(Moose::out, std::forward<Args>(args)...);
360 1081 : }
361 :
362 : /// Warning message used to notify the users of unused parts of their input files
363 : /// Really used internally by the parser and shouldn't really be called elsewhere
364 : template <typename... Args>
365 : void
366 51 : mooseUnused(Args &&... args)
367 : {
368 51 : moose::internal::mooseUnusedStream(Moose::out, std::forward<Args>(args)...);
369 51 : }
370 :
371 : /// Emit a deprecated code/feature message with the given stringified, concatenated args.
372 : template <typename... Args>
373 : void
374 11204 : mooseDeprecated(Args &&... args)
375 : {
376 11204 : moose::internal::mooseDeprecatedStream(Moose::out, false, true, std::forward<Args>(args)...);
377 11204 : }
378 :
379 : /// Emit a deprecated code/feature message with the given stringified, concatenated args.
380 : template <typename... Args>
381 : void
382 1095 : mooseDeprecationExpired(Args &&... args)
383 : {
384 1095 : moose::internal::mooseDeprecatedStream(Moose::out, true, true, std::forward<Args>(args)...);
385 1091 : }
386 :
387 : /// Emit an informational message with the given stringified, concatenated args.
388 : template <typename... Args>
389 : void
390 617 : mooseInfo(Args &&... args)
391 : {
392 617 : moose::internal::mooseInfoStream(Moose::out, std::forward<Args>(args)...);
393 617 : }
394 :
395 : /// Emit an informational message with the given stringified, concatenated args.
396 : template <typename... Args>
397 : void
398 12115 : mooseInfoRepeated(Args &&... args)
399 : {
400 12115 : moose::internal::mooseInfoStreamRepeated(Moose::out, std::forward<Args>(args)...);
401 12115 : }
|