opm-simulators
DeferredLoggingErrorHelpers.hpp
1 /*
2  Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
3 
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 #ifndef OPM_DEFERREDLOGGINGERRORHELPERS_HPP
22 #define OPM_DEFERREDLOGGINGERRORHELPERS_HPP
23 
24 #include <opm/common/Exceptions.hpp>
25 
26 #include <opm/simulators/utils/DeferredLogger.hpp>
27 #include <opm/simulators/utils/gatherDeferredLogger.hpp>
28 
29 #include <opm/simulators/utils/ParallelCommunication.hpp>
30 
31 #include <string>
32 #include <exception>
33 #include <stdexcept>
34 
35 // Macro to log an error and throw an exception.
36 // Inspired by ErrorMacros.hpp in opm-common.
37 // NOTE: For this macro to work, the
38 // exception class must exhibit a constructor with the signature
39 // (const std::string &message). Since this condition is not fulfilled
40 // for the std::exception, you should use this macro with some
41 // exception class derived from either std::logic_error or
42 // std::runtime_error.
43 //
44 // Usage: OPM_DEFLOG_THROW(ExceptionClass, "Error message", DeferredLogger);
45 #define OPM_DEFLOG_THROW(Exception, message, deferred_logger) \
46  do { \
47  std::string oss_ = std::string{"["} + __FILE__ + ":" + \
48  std::to_string(__LINE__) + "] " + \
49  message; \
50  deferred_logger.error(oss_); \
51  throw Exception(oss_); \
52  } while (false)
53 
54 // Macro to log a problem and throw an exception.
55 // Idenitical to OPM_DEFLOG_THROW() except for using
56 // the "problem" category instead of "error" for the
57 // log message. The Exception argument will typically
58 // be NumericalProblem.
59 //
60 // Usage: OPM_DEFLOG_PROBLEM(ExceptionClass, "Error message", DeferredLogger);
61 #define OPM_DEFLOG_PROBLEM(Exception, message, deferred_logger) \
62  do { \
63  std::string oss_ = std::string{"["} + __FILE__ + ":" + \
64  std::to_string(__LINE__) + "] " + \
65  message; \
66  deferred_logger.problem(oss_); \
67  throw Exception(oss_); \
68  } while (false)
69 
70 
71 namespace {
72 
73 void _throw(Opm::ExceptionType::ExcEnum exc_type,
74  const std::string& message,
75  Opm::Parallel::Communication comm)
76 {
77  auto global_exc = comm.max(exc_type);
78 
79  switch (global_exc) {
80  case Opm::ExceptionType::NONE:
81  break;
82  case Opm::ExceptionType::RUNTIME_ERROR:
83  throw std::runtime_error(message);
84  break;
85  case Opm::ExceptionType::INVALID_ARGUMENT:
86  throw std::invalid_argument(message);
87  break;
88  case Opm::ExceptionType::NUMERICAL_ISSUE:
89  throw Opm::NumericalProblem(message);
90  break;
91  case Opm::ExceptionType::DEFAULT:
92  case Opm::ExceptionType::LOGIC_ERROR:
93  throw std::logic_error(message);
94  break;
95  default:
96  throw std::logic_error(message);
97  }
98 }
99 
100 } // anonymous namespace
101 
102 
103 
104 inline void checkForExceptionsAndThrow(Opm::ExceptionType::ExcEnum exc_type,
105  const std::string& message,
106  Opm::Parallel::Communication comm)
107 {
108  _throw(exc_type, message, comm);
109 }
110 
111 inline void logAndCheckForExceptionsAndThrow(Opm::DeferredLogger& deferred_logger,
112  Opm::ExceptionType::ExcEnum exc_type,
113  const std::string& message,
114  const bool terminal_output,
115  Opm::Parallel::Communication comm)
116 {
117  // add exception message to logger in order to display message from all ranks
118  if (exc_type != Opm::ExceptionType::NONE && comm.size() > 1) {
119  deferred_logger.error("[Exception on rank " + std::to_string(comm.rank()) + "]: " + message);
120  }
121  Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(deferred_logger, comm);
122 
123  if (terminal_output) {
124  global_deferredLogger.logMessages();
125  }
126  // Now that all messages have been logged, they are automatically
127  // cleared from the global logger, but we must also clear them
128  // from the local logger.
129  deferred_logger.clearMessages();
130  _throw(exc_type, message, comm);
131 }
132 
133 inline void logAndCheckForProblemsAndThrow(Opm::DeferredLogger& deferred_logger,
134  Opm::ExceptionType::ExcEnum exc_type,
135  const std::string& message,
136  const bool terminal_output,
137  Opm::Parallel::Communication comm)
138 {
139  // add exception message to logger in order to display message from all ranks
140  if (exc_type != Opm::ExceptionType::NONE && comm.size() > 1) {
141  deferred_logger.problem("[Exception on rank " + std::to_string(comm.rank()) + "]: " + message);
142  }
143  Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(deferred_logger, comm);
144 
145  if (terminal_output) {
146  global_deferredLogger.logMessages();
147  }
148  // Now that all messages have been logged, they are automatically
149  // cleared from the global logger, but we must also clear them
150  // from the local logger.
151  deferred_logger.clearMessages();
152  _throw(exc_type, message, comm);
153 }
158 #define OPM_BEGIN_PARALLEL_TRY_CATCH() \
159 std::string obptc_exc_msg; \
160 auto obptc_exc_type = Opm::ExceptionType::NONE; \
161 try {
162 
166 #define OPM_PARALLEL_CATCH_CLAUSE(obptc_exc_type, \
167  obptc_exc_msg) \
168 catch (const Opm::NumericalProblem& e){ \
169  obptc_exc_type = Opm::ExceptionType::NUMERICAL_ISSUE; \
170  obptc_exc_msg = e.what(); \
171 } catch (const std::runtime_error& e) { \
172  obptc_exc_type = Opm::ExceptionType::RUNTIME_ERROR; \
173  obptc_exc_msg = e.what(); \
174 } catch (const std::invalid_argument& e) { \
175  obptc_exc_type = Opm::ExceptionType::INVALID_ARGUMENT; \
176  obptc_exc_msg = e.what(); \
177 } catch (const std::logic_error& e) { \
178  obptc_exc_type = Opm::ExceptionType::LOGIC_ERROR; \
179  obptc_exc_msg = e.what(); \
180 } catch (const std::exception& e) { \
181  obptc_exc_type = Opm::ExceptionType::DEFAULT; \
182  obptc_exc_msg = e.what(); \
183 } catch (...) { \
184  obptc_exc_type = Opm::ExceptionType::DEFAULT; \
185  obptc_exc_msg = "Unknown exception was thrown"; \
186 }
187 
192 #define OPM_END_PARALLEL_TRY_CATCH(prefix, comm) \
193 } \
194 OPM_PARALLEL_CATCH_CLAUSE(obptc_exc_type, obptc_exc_msg);\
195 checkForExceptionsAndThrow(obptc_exc_type, \
196  prefix + obptc_exc_msg, comm);
197 
202 #define OPM_END_PARALLEL_TRY_CATCH_LOG(obptc_logger, obptc_prefix, obptc_output, comm)\
203 } \
204 OPM_PARALLEL_CATCH_CLAUSE(obptc_exc_type, obptc_exc_msg); \
205 logAndCheckForExceptionsAndThrow(obptc_logger, obptc_exc_type, \
206  obptc_prefix + obptc_exc_msg, obptc_output, comm);
207 #endif // OPM_DEFERREDLOGGINGERRORHELPERS_HPP
void clearMessages()
Clear the message container without logging them.
Definition: DeferredLogger.cpp:100
Definition: DeferredLogger.hpp:56
void logMessages()
Log all messages to the OpmLog backends, and clear the message container.
Definition: DeferredLogger.cpp:92
Opm::DeferredLogger gatherDeferredLogger(const Opm::DeferredLogger &local_deferredlogger, Opm::Parallel::Communication)
Create a global log combining local logs.
Definition: gatherDeferredLogger.cpp:168