My Project
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/simulators/utils/DeferredLogger.hpp>
25 #include <opm/simulators/utils/gatherDeferredLogger.hpp>
26 
27 #include <opm/material/common/Exceptions.hpp>
28 
29 #include <opm/simulators/utils/ParallelCommunication.hpp>
30 
31 #include <string>
32 #include <sstream>
33 #include <exception>
34 #include <stdexcept>
35 
36 // Macro to throw an exception.
37 // Inspired by ErrorMacros.hpp in opm-common.
38 // NOTE: For this macro to work, the
39 // exception class must exhibit a constructor with the signature
40 // (const std::string &message). Since this condition is not fulfilled
41 // for the std::exception, you should use this macro with some
42 // exception class derived from either std::logic_error or
43 // std::runtime_error.
44 //
45 // Usage: OPM_DEFLOG_THROW(ExceptionClass, "Error message " << value, DeferredLogger);
46 #define OPM_DEFLOG_THROW(Exception, message, deferred_logger) \
47  do { \
48  std::ostringstream oss__; \
49  oss__ << "[" << __FILE__ << ":" << __LINE__ << "] " << message; \
50  deferred_logger.error(oss__.str()); \
51  throw Exception(oss__.str()); \
52  } while (false)
53 
54 namespace {
55 
56 void _throw(Opm::ExceptionType::ExcEnum exc_type,
57  const std::string& message,
58  Opm::Parallel::Communication comm)
59 {
60  auto global_exc = comm.max(exc_type);
61 
62  switch (global_exc) {
63  case Opm::ExceptionType::NONE:
64  break;
65  case Opm::ExceptionType::RUNTIME_ERROR:
66  throw std::runtime_error(message);
67  break;
68  case Opm::ExceptionType::INVALID_ARGUMENT:
69  throw std::invalid_argument(message);
70  break;
71  case Opm::ExceptionType::NUMERICAL_ISSUE:
72  throw Opm::NumericalIssue(message);
73  break;
74  case Opm::ExceptionType::DEFAULT:
75  case Opm::ExceptionType::LOGIC_ERROR:
76  throw std::logic_error(message);
77  break;
78  default:
79  throw std::logic_error(message);
80  }
81 }
82 
83 } // anonymous namespace
84 
85 
86 
87 inline void checkForExceptionsAndThrow(Opm::ExceptionType::ExcEnum exc_type,
88  const std::string& message,
89  Opm::Parallel::Communication comm)
90 {
91  _throw(exc_type, message, comm);
92 }
93 
94 inline void logAndCheckForExceptionsAndThrow(Opm::DeferredLogger& deferred_logger,
95  Opm::ExceptionType::ExcEnum exc_type,
96  const std::string& message,
97  const bool terminal_output,
98  Opm::Parallel::Communication comm)
99 {
100  Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(deferred_logger, comm);
101 
102  if (terminal_output) {
103  global_deferredLogger.logMessages();
104  }
105  // Now that all messages have been logged, they are automatically
106  // cleared from the global logger, but we must also clear them
107  // from the local logger.
108  deferred_logger.clearMessages();
109  _throw(exc_type, message, comm);
110 }
111 
112 
117 #define OPM_BEGIN_PARALLEL_TRY_CATCH() \
118 std::string obptc_exc_msg; \
119 auto obptc_exc_type = Opm::ExceptionType::NONE; \
120 try {
121 
125 #define OPM_PARALLEL_CATCH_CLAUSE(obptc_exc_type, \
126  obptc_exc_msg) \
127 catch (const Opm::NumericalIssue& e){ \
128  obptc_exc_type = Opm::ExceptionType::NUMERICAL_ISSUE; \
129  obptc_exc_msg = e.what(); \
130 } catch (const std::runtime_error& e) { \
131  obptc_exc_type = Opm::ExceptionType::RUNTIME_ERROR; \
132  obptc_exc_msg = e.what(); \
133 } catch (const std::invalid_argument& e) { \
134  obptc_exc_type = Opm::ExceptionType::INVALID_ARGUMENT; \
135  obptc_exc_msg = e.what(); \
136 } catch (const std::logic_error& e) { \
137  obptc_exc_type = Opm::ExceptionType::LOGIC_ERROR; \
138  obptc_exc_msg = e.what(); \
139 } catch (const std::exception& e) { \
140  obptc_exc_type = Opm::ExceptionType::DEFAULT; \
141  obptc_exc_msg = e.what(); \
142 } catch (...) { \
143  obptc_exc_type = Opm::ExceptionType::DEFAULT; \
144  obptc_exc_msg = "Unknown exception was thrown"; \
145 }
146 
151 #define OPM_END_PARALLEL_TRY_CATCH(prefix, comm) \
152 } \
153 OPM_PARALLEL_CATCH_CLAUSE(obptc_exc_type, obptc_exc_msg);\
154 checkForExceptionsAndThrow(obptc_exc_type, \
155  prefix + obptc_exc_msg, comm);
156 
161 #define OPM_END_PARALLEL_TRY_CATCH_LOG(obptc_logger, obptc_prefix, obptc_output, comm)\
162 } \
163 OPM_PARALLEL_CATCH_CLAUSE(obptc_exc_type, obptc_exc_msg); \
164 logAndCheckForExceptionsAndThrow(obptc_logger, obptc_exc_type, \
165  obptc_prefix + obptc_exc_msg, obptc_output, comm);
166 #endif // OPM_DEFERREDLOGGINGERRORHELPERS_HPP
Definition: DeferredLogger.hpp:57
void logMessages()
Log all messages to the OpmLog backends, and clear the message container.
Definition: DeferredLogger.cpp:85
void clearMessages()
Clear the message container without logging them.
Definition: DeferredLogger.cpp:93
Opm::DeferredLogger gatherDeferredLogger(const Opm::DeferredLogger &local_deferredlogger, Opm::Parallel::Communication)
Create a global log combining local logs.
Definition: gatherDeferredLogger.cpp:168