MFEM  v4.6.0
Finite element discretization library
error.hpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #ifndef MFEM_ERROR_HPP
13 #define MFEM_ERROR_HPP
14 
15 #include "../config/config.hpp"
16 #include <iomanip>
17 #include <sstream>
18 #ifdef MFEM_USE_HIP
19 #include <hip/hip_runtime.h>
20 #endif
21 
22 namespace mfem
23 {
24 
25 /// Action to take when MFEM encounters an error.
27 {
28  MFEM_ERROR_ABORT = 0, /**<
29  Abort execution using abort() or MPI_Abort(). This is the default error
30  action when the build option MFEM_USE_EXCEPTIONS is set to NO. */
32  Throw an ErrorException. Requires the build option MFEM_USE_EXCEPTIONS=YES
33  in which case it is also the default error action. */
34 };
35 
36 /// Set the action MFEM takes when an error is encountered.
37 void set_error_action(ErrorAction action);
38 /// Get the action MFEM takes when an error is encountered.
40 
41 #ifdef MFEM_USE_EXCEPTIONS
42 /** @brief Exception class thrown when MFEM encounters an error and the current
43  ErrorAction is set to MFEM_ERROR_THROW. */
44 class ErrorException: public std::exception
45 {
46 private:
47  std::string msg;
48 public:
49  explicit ErrorException(const std::string & in_msg) : msg(in_msg) { }
50  virtual ~ErrorException() throw() { }
51  virtual const char* what() const throw();
52 };
53 #endif
54 
55 void mfem_backtrace(int mode = 0, int depth = -1);
56 
57 /** @brief Function called when an error is encountered. Used by the macros
58  MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY. */
59 void mfem_error(const char *msg = NULL);
60 
61 /// Function called by the macro MFEM_WARNING.
62 void mfem_warning(const char *msg = NULL);
63 
64 #ifdef MFEM_USE_ENZYME
65 static void* __enzyme_inactive_global_err = (void*)mfem_error;
66 static void* __enzyme_inactive_global_warn = (void*)mfem_warning;
67 #endif
68 }
69 
70 #ifndef _MFEM_FUNC_NAME
71 #ifndef _MSC_VER
72 // This is nice because it shows the class and method name
73 #define _MFEM_FUNC_NAME __PRETTY_FUNCTION__
74 // This one is C99 standard.
75 //#define _MFEM_FUNC_NAME __func__
76 #else
77 // for Visual Studio C++
78 #define _MFEM_FUNC_NAME __FUNCSIG__
79 #endif
80 #endif
81 
82 #define MFEM_LOCATION \
83  "\n ... in function: " << _MFEM_FUNC_NAME << \
84  "\n ... in file: " << __FILE__ << ':' << __LINE__ << '\n'
85 
86 // Common error message and abort macro
87 #define _MFEM_MESSAGE(msg, warn) \
88  { \
89  std::ostringstream mfemMsgStream; \
90  mfemMsgStream << std::setprecision(16); \
91  mfemMsgStream << std::setiosflags(std::ios_base::scientific); \
92  mfemMsgStream << msg << MFEM_LOCATION; \
93  if (!(warn)) \
94  mfem::mfem_error(mfemMsgStream.str().c_str()); \
95  else \
96  mfem::mfem_warning(mfemMsgStream.str().c_str()); \
97  }
98 
99 // Outputs lots of useful information and aborts.
100 // For all of these functions, "msg" is pushed to an ostream, so you can
101 // write useful (if complicated) error messages instead of writing
102 // out to the screen first, then calling abort. For example:
103 // MFEM_ABORT( "Unknown geometry type: " << type );
104 #define MFEM_ABORT(msg) _MFEM_MESSAGE("MFEM abort: " << msg, 0)
105 
106 // Does a check, and then outputs lots of useful information if the test fails
107 #define MFEM_VERIFY(x, msg) \
108  if (!(x)) \
109  { \
110  _MFEM_MESSAGE("Verification failed: (" \
111  << #x << ") is false:\n --> " << msg, 0); \
112  }
113 
114 // Use this if the only place your variable is used is in ASSERTs
115 // For example, this code snippet:
116 // int err = MPI_Reduce(ldata, maxdata, 5, MPI_INT, MPI_MAX, 0, MyComm);
117 // MFEM_CONTRACT_VAR(err);
118 // MFEM_ASSERT( err == 0, "MPI_Reduce gave an error with length "
119 // << ldata );
120 #define MFEM_CONTRACT_VAR(x) (void)(x)
121 
122 // Now set up some optional checks, but only if the right flags are on
123 #ifdef MFEM_DEBUG
124 
125 #define MFEM_ASSERT(x, msg) \
126  if (!(x)) \
127  { \
128  _MFEM_MESSAGE("Assertion failed: (" \
129  << #x << ") is false:\n --> " << msg, 0); \
130  }
131 
132 // A macro that exposes its argument in debug mode only.
133 #define MFEM_DEBUG_DO(x) x
134 
135 #else
136 
137 // Get rid of all this code, since we're not checking.
138 #define MFEM_ASSERT(x, msg)
139 
140 // A macro that exposes its argument in debug mode only.
141 #define MFEM_DEBUG_DO(x)
142 
143 #endif
144 
145 // Generate a warning message - always generated, regardless of MFEM_DEBUG.
146 #define MFEM_WARNING(msg) _MFEM_MESSAGE("MFEM Warning: " << msg, 1)
147 
148 // Macro that checks (in MFEM_DEBUG mode) that i is in the range [imin,imax).
149 #define MFEM_ASSERT_INDEX_IN_RANGE(i,imin,imax) \
150  MFEM_ASSERT((imin) <= (i) && (i) < (imax), \
151  "invalid index " #i << " = " << (i) << \
152  ", valid range is [" << (imin) << ',' << (imax) << ')')
153 
154 
155 // Additional abort functions for HIP
156 #if defined(MFEM_USE_HIP)
157 template<typename T>
158 __host__ void abort_msg(T & msg)
159 {
160  MFEM_ABORT(msg);
161 }
162 
163 template<typename T>
164 __device__ void abort_msg(T & msg)
165 {
166  abort();
167 }
168 #endif
169 
170 // Abort inside a device kernel
171 #if defined(__CUDA_ARCH__)
172 #define MFEM_ABORT_KERNEL(...) \
173  { \
174  printf(__VA_ARGS__); \
175  asm("trap;"); \
176  }
177 #elif defined(MFEM_USE_HIP)
178 #define MFEM_ABORT_KERNEL(...) \
179  { \
180  printf(__VA_ARGS__); \
181  abort_msg(""); \
182  }
183 #else
184 #define MFEM_ABORT_KERNEL(...) \
185  { \
186  printf(__VA_ARGS__); \
187  MFEM_ABORT(""); \
188  }
189 #endif
190 
191 // Verify inside a device kernel
192 #define MFEM_VERIFY_KERNEL(x,...) \
193  if (!(x)) \
194  { \
195  MFEM_ABORT_KERNEL(__VA_ARGS__) \
196  }
197 
198 // Assert inside a device kernel
199 #ifdef MFEM_DEBUG
200 #define MFEM_ASSERT_KERNEL(x,...) \
201  if (!(x)) \
202  { \
203  MFEM_ABORT_KERNEL(__VA_ARGS__) \
204  }
205 #else
206 #define MFEM_ASSERT_KERNEL(x,...)
207 #endif
208 
209 #endif
virtual const char * what() const
Definition: error.cpp:39
ErrorAction get_error_action()
Get the action MFEM takes when an error is encountered.
Definition: error.cpp:72
Exception class thrown when MFEM encounters an error and the current ErrorAction is set to MFEM_ERROR...
Definition: error.hpp:44
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:154
virtual ~ErrorException()
Definition: error.hpp:50
void set_error_action(ErrorAction action)
Set the action MFEM takes when an error is encountered.
Definition: error.cpp:49
ErrorAction
Action to take when MFEM encounters an error.
Definition: error.hpp:26
ErrorException(const std::string &in_msg)
Definition: error.hpp:49
__host__ void abort_msg(T &msg)
Definition: error.hpp:158
void mfem_warning(const char *msg)
Function called by the macro MFEM_WARNING.
Definition: error.cpp:187
void mfem_backtrace(int mode, int depth)
Definition: error.cpp:83