Loading [MathJax]/jax/input/TeX/config.js
PISM, A Parallel Ice Sheet Model 2.2.2-d6b3a29ca committed by Constantine Khrulev on 2025-03-28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
error_handling.cc
Go to the documentation of this file.
1/* Copyright (C) 2014, 2015, 2016, 2017, 2021, 2023 PISM Authors
2 *
3 * This file is part of PISM.
4 *
5 * PISM is free software; you can redistribute it and/or modify it under the
6 * terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * PISM is distributed in the hope that it will be useful, but WITHOUT ANY
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with PISM; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include "pism/util/error_handling.hh"
21#include <petsc.h>
22
23#include <stdexcept>
24#include <stdarg.h>
25
26namespace pism {
27
29 : filename(NULL), line_number(0) {
30 // empty
31}
32
33ErrorLocation::ErrorLocation(const char *name, int line)
34 : filename(name), line_number(line) {
35 // empty
36}
37
39
40RuntimeError::RuntimeError(const ErrorLocation &location, const std::string &message)
41 : std::runtime_error(message), m_location(location) {
42 if (sm_hook != NULL) {
43 sm_hook(this);
44 }
45}
46
47RuntimeError RuntimeError::formatted(const ErrorLocation &location, const char format[], ...) {
48 char buffer[8192];
49 va_list argp;
50
51 va_start(argp, format);
52 vsnprintf(buffer, sizeof(buffer), format, argp);
53 va_end(argp);
54
55 return RuntimeError(location, buffer);
56}
57
58void RuntimeError::set_hook(Hook new_hook) {
59 sm_hook = new_hook;
60}
61
63 // empty
64}
65
66void RuntimeError::add_context(const std::string &message) {
67 m_context.push_back(message);
68}
69
70void RuntimeError::add_context(const char format[], ...) {
71 char buffer[8192];
72 va_list argp;
73
74 va_start(argp, format);
75 vsnprintf(buffer, sizeof(buffer), format, argp);
76 va_end(argp);
77
78 // convert to std::string to avoid recursion
79 this->add_context(std::string(buffer));
80}
81
82void RuntimeError::print(MPI_Comm com) {
83 PetscErrorCode ierr = 0;
84 std::string error = "PISM ERROR: ";
85 std::string message = this->what();
86
87 std::string padding = std::string(error.size(), ' ');
88
89 // replace newlines with newlines plus padding
90 size_t k = message.find('\n', 0);
91 while (k != std::string::npos) {
92 message.insert(k+1, padding);
93 k = message.find('\n', k+1);
94 }
95
96 // print the error message with "PISM ERROR:" in front:
97 ierr = PetscPrintf(com,
98 "%s%s\n", error.c_str(), message.c_str()); CHKERRCONTINUE(ierr);
99
100 // compute how much padding we need to align things:
101 std::string while_str = std::string(error.size(), ' ') + "while ";
102 padding = std::string(while_str.size() + 1, ' '); // 1 extra space
103
104 // loop over "context" messages
105 for (const auto &j : m_context) {
106 message = j;
107
108 // replace newlines with newlines plus padding
109 k = message.find('\n', 0);
110 while (k != std::string::npos) {
111 message.insert(k+1, padding);
112 k = message.find('\n', k+1);
113 }
114
115 // print a "context" message
116 ierr = PetscPrintf(com,
117 "%s%s\n", while_str.c_str(), message.c_str()); CHKERRCONTINUE(ierr);
118 }
119
120 if (m_location.filename != NULL) {
121 padding = std::string(error.size(), ' ');
122 ierr = PetscPrintf(com,
123 "%sError location: %s, line %d\n",
124 padding.c_str(), m_location.filename, m_location.line_number); CHKERRCONTINUE(ierr);
125 }
126}
127
128/** Handle fatal PISM errors by printing an informative error message.
129 *
130 * (Since these are fatal there is nothing else that can be done.)
131 *
132 * Should be called from a catch(...) block *only*.
133 */
134void handle_fatal_errors(MPI_Comm com) {
135 PetscErrorCode ierr;
136 try {
137 throw; // re-throw the current exception
138 }
139 catch (RuntimeError &e) {
140 e.print(com);
141 }
142 catch (std::exception &e) {
143 ierr = PetscPrintf(PETSC_COMM_SELF,
144 "\n"
145 "PISM ERROR: Caught a C++ standard library exception: \"%s\".\n"
146 " This is probably a bug in PISM.\n"
147 " Please send a report to uaf-pism@alaska.edu\n"
148 "\n",
149 e.what()); CHKERRCONTINUE(ierr);
150 } catch (...) {
151 ierr = PetscPrintf(PETSC_COMM_SELF,
152 "\n"
153 "PISM ERROR: Caught an unexpected exception.\n"
154 " This is probably a bug in PISM.\n"
155 " Please send a report to uaf-pism@alaska.edu\n"
156 "\n");
157 CHKERRCONTINUE(ierr);
158 }
159}
160
161void check_c_call(int errcode, int success,
162 const char* function_name, const char *file, int line) {
163 if (errcode != success) {
164 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "External library function %s failed at %s:%d",
165 function_name, file, line);
166 }
167}
168
169void check_petsc_call(int errcode,
170 const char* function_name, const char *file, int line) {
171 // tell PETSc to print the error message
172 CHKERRCONTINUE(errcode);
173 check_c_call(errcode, 0, function_name, file, line);
174}
175
177 : m_failed(false), m_com(com) {
178 // empty
179}
180
181//! @brief Indicates a failure of a parallel section.
182/*!
183 * This should be called from a `catch (...) { ... }` block **only**.
184 */
186 int rank = 0;
187 MPI_Comm_rank(m_com, &rank);
188
189 PetscFPrintf(MPI_COMM_SELF, stderr,
190 "PISM ERROR: Rank %d failed with the following message.\n", rank);
191
192 handle_fatal_errors(MPI_COMM_SELF);
193
194 m_failed = true;
195}
196
198 m_failed = false;
199}
200
202#if (Pism_DEBUG==1)
203 int success_flag = m_failed ? 0 : 1;
204 int success_flag_global = 0;
205
206 MPI_Allreduce(&success_flag, &success_flag_global, 1, MPI_INT, MPI_LAND, m_com);
207
208 if (success_flag_global == 0) {
209 throw RuntimeError(PISM_ERROR_LOCATION, "Failure in a parallel section. See error messages above for more.");
210 }
211#endif
212}
213
214} // end of namespace pism
ParallelSection(MPI_Comm com)
void failed()
Indicates a failure of a parallel section.
ErrorLocation m_location
void(* Hook)(RuntimeError *)
RuntimeError(const ErrorLocation &location, const std::string &message)
static RuntimeError static void set_hook(Hook new_hook)
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
std::vector< std::string > m_context
void void print(MPI_Comm com)
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
#define PISM_ERROR_LOCATION
static const double k
Definition exactTestP.cc:42
void check_c_call(int errcode, int success, const char *function_name, const char *file, int line)
void handle_fatal_errors(MPI_Comm com)
void check_petsc_call(int errcode, const char *function_name, const char *file, int line)