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