1 /* 2 Code that allows one to set the error handlers 3 Portions of this code are under: 4 Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved. 5 */ 6 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/ 7 #include <petscviewer.h> 8 9 typedef struct _EH *EH; 10 struct _EH { 11 PetscErrorCode (*handler)(MPI_Comm, int, const char *, const char *, PetscErrorCode, PetscErrorType, const char *, void *); 12 void *ctx; 13 EH previous; 14 }; 15 16 /* This is here to allow the traceback error handler (or potentially other error handlers) 17 to certify that PETSCABORT is being called on all MPI processes, and that it should be possible to call 18 MPI_Finalize() and exit(). This should only be used when `PetscCIEnabledPortabeErrorOutput == PETSC_TRUE` 19 to allow testing of error messages. Do not rely on this for clean exit in production. */ 20 PetscBool petscabortmpifinalize = PETSC_FALSE; 21 22 static EH eh = NULL; 23 24 /*@C 25 PetscEmacsClientErrorHandler - Error handler that uses the emacsclient program to 26 load the file where the error occurred. Then calls the "previous" error handler. 27 28 Not Collective, No Fortran Support 29 30 Input Parameters: 31 + comm - communicator over which error occurred 32 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine) 33 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine) 34 . fun - the function name of the calling routine 35 . mess - an error text string, usually just printed to the screen 36 . n - the generic error number 37 . p - `PETSC_ERROR_INITIAL` indicates this is the first time the error handler is being called while `PETSC_ERROR_REPEAT` indicates it was previously called 38 - ctx - error handler context 39 40 Options Database Key: 41 . -on_error_emacs <machinename> - will contact machinename to open the Emacs client there 42 43 Level: developer 44 45 Note: 46 You must put (server-start) in your .emacs file for the emacsclient software to work 47 48 Developer Note: 49 Since this is an error handler it cannot call `PetscCall()`; thus we just return if an error is detected. 50 But some of the functions it calls do perform error checking that may not be appropriate in a error handler call. 51 52 .seealso: `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscAttachDebuggerErrorHandler()`, 53 `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscTraceBackErrorHandler()`, `PetscReturnErrorHandler()`, 54 `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`, `PetscErrorCode` 55 @*/ 56 PetscErrorCode PetscEmacsClientErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx) 57 { 58 PetscErrorCode ierr; 59 char command[PETSC_MAX_PATH_LEN]; 60 const char *pdir; 61 FILE *fp; 62 63 ierr = PetscGetPetscDir(&pdir); 64 if (ierr) return ierr; 65 ierr = PetscSNPrintf(command, PETSC_STATIC_ARRAY_LENGTH(command), "cd %s; emacsclient --no-wait +%d %s\n", pdir, line, file); 66 if (ierr) return ierr; 67 #if defined(PETSC_HAVE_POPEN) 68 ierr = PetscPOpen(MPI_COMM_WORLD, (char *)ctx, command, "r", &fp); 69 if (ierr) return ierr; 70 ierr = PetscPClose(MPI_COMM_WORLD, fp); 71 if (ierr) return ierr; 72 #else 73 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine"); 74 #endif 75 ierr = PetscPopErrorHandler(); 76 if (ierr) return ierr; /* remove this handler from the stack of handlers */ 77 if (!eh) { 78 ierr = PetscTraceBackErrorHandler(comm, line, fun, file, n, p, mess, NULL); 79 if (ierr) return ierr; 80 } else { 81 ierr = (*eh->handler)(comm, line, fun, file, n, p, mess, eh->ctx); 82 if (ierr) return ierr; 83 } 84 return PETSC_SUCCESS; 85 } 86 87 /*@C 88 PetscPushErrorHandler - Sets a routine to be called on detection of errors. 89 90 Not Collective, No Fortran Support 91 92 Input Parameters: 93 + handler - error handler routine 94 - ctx - optional handler context that contains information needed by the handler (for 95 example file pointers for error messages etc.) 96 97 Calling sequence of `handler`: 98 + comm - communicator over which error occurred 99 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine) 100 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine) 101 . fun - the function name of the calling routine 102 . n - the generic error number (see list defined in include/petscerror.h) 103 . p - `PETSC_ERROR_INITIAL` if error just detected, otherwise `PETSC_ERROR_REPEAT` 104 . mess - an error text string, usually just printed to the screen 105 - ctx - the error handler context 106 107 Options Database Keys: 108 + -on_error_attach_debugger <noxterm,lldb or gdb> - starts up the debugger if an error occurs 109 - -on_error_abort - aborts the program if an error occurs 110 111 Level: intermediate 112 113 Note: 114 The currently available PETSc error handlers include `PetscTraceBackErrorHandler()`, 115 `PetscAttachDebuggerErrorHandler()`, `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, and `PetscReturnErrorHandler()`. 116 117 Fortran Note: 118 You can only push a single error handler from Fortran before popping it. 119 120 .seealso: `PetscPopErrorHandler()`, `PetscAttachDebuggerErrorHandler()`, `PetscAbortErrorHandler()`, `PetscTraceBackErrorHandler()`, `PetscPushSignalHandler()`, 121 `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`, `PetscErrorCode` 122 @*/ 123 PetscErrorCode PetscPushErrorHandler(PetscErrorCode (*handler)(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx), void *ctx) 124 { 125 EH neweh; 126 127 PetscFunctionBegin; 128 PetscCall(PetscNew(&neweh)); 129 if (eh) neweh->previous = eh; 130 else neweh->previous = NULL; 131 neweh->handler = handler; 132 neweh->ctx = ctx; 133 eh = neweh; 134 PetscFunctionReturn(PETSC_SUCCESS); 135 } 136 137 /*@ 138 PetscPopErrorHandler - Removes the latest error handler that was 139 pushed with `PetscPushErrorHandler()`. 140 141 Not Collective 142 143 Level: intermediate 144 145 .seealso: `PetscPushErrorHandler()` 146 @*/ 147 PetscErrorCode PetscPopErrorHandler(void) 148 { 149 EH tmp; 150 151 PetscFunctionBegin; 152 if (!eh) PetscFunctionReturn(PETSC_SUCCESS); 153 tmp = eh; 154 eh = eh->previous; 155 PetscCall(PetscFree(tmp)); 156 PetscFunctionReturn(PETSC_SUCCESS); 157 } 158 159 /*@C 160 PetscReturnErrorHandler - Error handler that causes a return without printing an error message. 161 162 Not Collective, No Fortran Support 163 164 Input Parameters: 165 + comm - communicator over which error occurred 166 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine) 167 . fun - the function name 168 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine) 169 . mess - an error text string, usually just printed to the screen 170 . n - the generic error number 171 . p - `PETSC_ERROR_INITIAL` indicates this is the first time the error handler is being called while `PETSC_ERROR_REPEAT` indicates it was previously called 172 - ctx - error handler context 173 174 Level: developer 175 176 Notes: 177 Users do not directly employ this routine 178 179 Use `PetscPushErrorHandler()` to set the desired error handler. The 180 currently available PETSc error handlers include `PetscTraceBackErrorHandler()`, 181 `PetscAttachDebuggerErrorHandler()`, and `PetscAbortErrorHandler()`. 182 183 .seealso: `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscError()`, `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscTraceBackErrorHandler()`, 184 `PetscAttachDebuggerErrorHandler()`, `PetscEmacsClientErrorHandler()`, 185 `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`, `PetscErrorCode` 186 @*/ 187 PetscErrorCode PetscReturnErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx) 188 { 189 (void)comm; 190 (void)line; 191 (void)fun; 192 (void)file; 193 (void)p; 194 (void)mess; 195 (void)ctx; 196 return n; 197 } 198 199 static char PetscErrorBaseMessage[1024]; 200 /* 201 The numerical values for these are defined in include/petscerror.h; any changes 202 there must also be made here 203 */ 204 static const char *PetscErrorStrings[] = { 205 /*55 */ "Out of memory", 206 "No support for this operation for this object type", 207 "No support for this operation on this system", 208 /*58 */ "Operation done in wrong order", 209 /*59 */ "Signal received", 210 /*60 */ "Nonconforming object sizes", 211 "Argument aliasing not permitted", 212 "Invalid argument", 213 /*63 */ "Argument out of range", 214 "Corrupt argument: https://petsc.org/release/faq/#valgrind", 215 "Unable to open file", 216 "Read from file failed", 217 "Write to file failed", 218 "Invalid pointer", 219 /*69 */ "Arguments must have same type", 220 /*70 */ "Attempt to use a pointer that does not point to a valid accessible location", 221 /*71 */ "Zero pivot in LU factorization: https://petsc.org/release/faq/#zeropivot", 222 /*72 */ "Floating point exception", 223 /*73 */ "Object is in wrong state", 224 "Corrupted Petsc object", 225 "Arguments are incompatible", 226 "Error in external library", 227 /*77 */ "Petsc has generated inconsistent data", 228 "Memory corruption: https://petsc.org/release/faq/#valgrind", 229 "Unexpected data in file", 230 /*80 */ "Arguments must have same communicators", 231 /*81 */ "Zero pivot in Cholesky factorization: https://petsc.org/release/faq/#zeropivot", 232 "", 233 "", 234 "Overflow in integer operation: https://petsc.org/release/faq/#64-bit-indices", 235 /*85 */ "Null argument, when expecting valid pointer", 236 /*86 */ "Unknown type. Check for miss-spelling or missing package: https://petsc.org/release/install/install/#external-packages", 237 /*87 */ "MPI library at runtime is not compatible with MPI used at compile time", 238 /*88 */ "Error in system call", 239 /*89 */ "Object Type not set: https://petsc.org/release/faq/#object-type-not-set", 240 /*90 */ "", 241 /* */ "", 242 /*92 */ "See https://petsc.org/release/overview/linear_solve_table/ for possible LU and Cholesky solvers", 243 /*93 */ "You cannot overwrite this option since that will conflict with other previously set options", 244 /*94 */ "Example/application run with number of MPI ranks it does not support", 245 /*95 */ "Missing or incorrect user input", 246 /*96 */ "GPU resources unavailable", 247 /*97 */ "GPU error", 248 /*98 */ "General MPI error", 249 /*99 */ "PetscError() incorrectly returned an error code of 0"}; 250 251 /*@C 252 PetscErrorMessage - Returns the text string associated with a PETSc error code. 253 254 Not Collective, No Fortran Support 255 256 Input Parameter: 257 . errnum - the error code 258 259 Output Parameters: 260 + text - the error message (`NULL` if not desired) 261 - specific - the specific error message that was set with `SETERRQ()` or 262 `PetscError()`. (`NULL` if not desired) 263 264 Level: developer 265 266 .seealso: `PetscErrorCode`, `PetscPushErrorHandler()`, `PetscAttachDebuggerErrorHandler()`, 267 `PetscError()`, `SETERRQ()`, `PetscCall()` `PetscAbortErrorHandler()`, 268 `PetscTraceBackErrorHandler()` 269 @*/ 270 PetscErrorCode PetscErrorMessage(PetscErrorCode errnum, const char *text[], char *specific[]) 271 { 272 PetscFunctionBegin; 273 if (text) { 274 if (errnum > PETSC_ERR_MIN_VALUE && errnum < PETSC_ERR_MAX_VALUE) { 275 size_t len; 276 277 *text = PetscErrorStrings[errnum - PETSC_ERR_MIN_VALUE - 1]; 278 PetscCall(PetscStrlen(*text, &len)); 279 if (!len) *text = NULL; 280 } else if (errnum == PETSC_ERR_BOOLEAN_MACRO_FAILURE) { 281 /* this "error code" arises from failures in boolean macros, where the || operator is 282 used to short-circuit the macro call in case of error. This has the side effect of 283 "returning" either 0 (PETSC_SUCCESS) or 1 (PETSC_ERR_UNKNONWN): 284 285 #define PETSC_FOO(x) ((PetscErrorCode)(PetscBar(x) || PetscBaz(x))) 286 287 If PetscBar() fails (returns nonzero) PetscBaz() is not executed but the result of 288 this expression is boolean false, hence PETSC_ERR_UNNOWN 289 */ 290 *text = "Error occurred in boolean shortcuit in macro"; 291 } else { 292 *text = NULL; 293 } 294 } 295 if (specific) *specific = PetscErrorBaseMessage; 296 PetscFunctionReturn(PETSC_SUCCESS); 297 } 298 299 #if defined(PETSC_CLANGUAGE_CXX) 300 /* C++ exceptions are formally not allowed to propagate through extern "C" code. In practice, far too much software 301 * would be broken if implementations did not handle it in some common cases. However, keep in mind 302 * 303 * Rule 62. Don't allow exceptions to propagate across module boundaries 304 * 305 * in "C++ Coding Standards" by Sutter and Alexandrescu. (This accounts for part of the ongoing C++ binary interface 306 * instability.) Having PETSc raise errors as C++ exceptions was probably misguided and should eventually be removed. 307 * 308 * Here is the problem: You have a C++ function call a PETSc function, and you would like to maintain the error message 309 * and stack information from the PETSc error. You could make everyone write exactly this code in their C++, but that 310 * seems crazy to me. 311 */ 312 #include <sstream> 313 #include <stdexcept> 314 static void PetscCxxErrorThrow() 315 { 316 const char *str; 317 if (eh && eh->ctx) { 318 std::ostringstream *msg; 319 msg = (std::ostringstream *)eh->ctx; 320 str = msg->str().c_str(); 321 } else str = "Error detected in C PETSc"; 322 323 throw std::runtime_error(str); 324 } 325 #endif 326 327 /*@C 328 PetscError - Routine that is called when an error has been detected, usually called through the macro `SETERRQ`(`PETSC_COMM_SELF`,)` or by `PetscCall()`. 329 330 Collective 331 332 Input Parameters: 333 + comm - communicator over which error occurred. ALL MPI processes of this communicator MUST call this routine 334 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine) 335 . func - the function name in which the error was detected 336 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine) 337 . n - the generic error number 338 . p - `PETSC_ERROR_INITIAL` indicates the error was initially detected, `PETSC_ERROR_REPEAT` indicates this is a traceback from a previously detected error 339 - mess - formatted message string - aka printf 340 341 Options Database Keys: 342 + -error_output_stdout - output the error messages to `stdout` instead of the default `stderr` 343 - -error_output_none - do not output the error messages 344 345 Level: intermediate 346 347 Notes: 348 PETSc error handling is done with error return codes. A non-zero return indicates an error 349 was detected. The return-value of this routine is what is ultimately returned by 350 `SETERRQ()`. 351 352 Numerical errors (potential divide by zero, for example) are not managed by the 353 error return codes; they are managed via, for example, `KSPGetConvergedReason()` that 354 indicates if the solve was successful or not. The option `-ksp_error_if_not_converged`, for 355 example, turns numerical failures into hard errors managed via `PetscError()`. 356 357 PETSc provides a rich supply of error handlers, see the list below, and users can also 358 provide their own error handlers. 359 360 If the user sets their own error handler (via `PetscPushErrorHandler()`) they may return any 361 arbitrary value from it, but are encouraged to return nonzero values. If the return value is 362 zero, `SETERRQ()` will ignore the value and return `PETSC_ERR_RETURN` (a nonzero value) 363 instead. 364 365 Most users need not directly use this routine and the error handlers, but can instead use 366 the simplified interface `PetscCall()` or `SETERRQ()`. 367 368 Fortran Note: 369 This routine is used differently from Fortran 370 .vb 371 PetscError(MPI_Comm comm, PetscErrorCode n, PetscErrorType p, char *message) 372 .ve 373 374 Developer Note: 375 Since this is called after an error condition it should not be calling any error handlers (currently it ignores any error codes) 376 BUT this routine does call regular PETSc functions that may call error handlers, this is problematic and could be fixed by never calling other PETSc routines 377 but this annoying. 378 379 .seealso: `PetscErrorCode`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscTraceBackErrorHandler()`, `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, 380 `PetscReturnErrorHandler()`, `PetscAttachDebuggerErrorHandler()`, `PetscEmacsClientErrorHandler()`, 381 `SETERRQ()`, `PetscCall()`, `CHKMEMQ`, `PetscErrorMessage()`, `PETSCABORT()`, `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT` 382 @*/ 383 PetscErrorCode PetscError(MPI_Comm comm, int line, const char *func, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, ...) 384 { 385 va_list Argp; 386 size_t fullLength; 387 char buf[2048], *lbuf = NULL; 388 PetscBool ismain; 389 PetscErrorCode ierr; 390 391 if (!PetscErrorHandlingInitialized) return n; 392 if (comm == MPI_COMM_NULL) comm = PETSC_COMM_SELF; 393 394 /* Compose the message evaluating the print format */ 395 if (mess) { 396 va_start(Argp, mess); 397 (void)PetscVSNPrintf(buf, 2048, mess, &fullLength, Argp); 398 va_end(Argp); 399 lbuf = buf; 400 if (p == PETSC_ERROR_INITIAL) (void)PetscStrncpy(PetscErrorBaseMessage, lbuf, sizeof(PetscErrorBaseMessage)); 401 } 402 403 if (p == PETSC_ERROR_INITIAL && n != PETSC_ERR_MEMC) (void)PetscMallocValidate(__LINE__, PETSC_FUNCTION_NAME, __FILE__); 404 405 if (!eh) ierr = PetscTraceBackErrorHandler(comm, line, func, file, n, p, lbuf, NULL); 406 else ierr = (*eh->handler)(comm, line, func, file, n, p, lbuf, eh->ctx); 407 PetscStackClearTop; 408 409 /* 410 If this is called from the main() routine we abort the program. 411 We cannot just return because them some MPI processes may continue to attempt to run 412 while this process simply exits. 413 */ 414 if (func) { 415 (void)PetscStrncmp(func, "main", 4, &ismain); 416 if (ismain) { 417 if (petscwaitonerrorflg) (void)PetscSleep(1000); 418 PETSCABORT(comm, ierr); 419 } 420 } 421 #if defined(PETSC_CLANGUAGE_CXX) 422 if (p == PETSC_ERROR_IN_CXX) PetscCxxErrorThrow(); 423 #endif 424 return ierr; 425 } 426 427 /*@ 428 PetscIntView - Prints an array of integers; useful for debugging. 429 430 Collective 431 432 Input Parameters: 433 + N - number of integers in array 434 . idx - array of integers 435 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0 436 437 Level: intermediate 438 439 Note: 440 This may be called from within the debugger, passing 0 as the viewer 441 442 Developer Note: 443 `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done 444 445 .seealso: `PetscViewer`, `PetscRealView()` 446 @*/ 447 PetscErrorCode PetscIntView(PetscInt N, const PetscInt idx[], PetscViewer viewer) 448 { 449 PetscMPIInt rank, size; 450 PetscInt j, i, n = N / 20, p = N % 20; 451 PetscBool iascii, isbinary; 452 MPI_Comm comm; 453 454 PetscFunctionBegin; 455 if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF; 456 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 3); 457 if (N) PetscAssertPointer(idx, 2); 458 PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm)); 459 PetscCallMPI(MPI_Comm_size(comm, &size)); 460 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 461 462 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 463 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 464 if (iascii) { 465 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 466 for (i = 0; i < n; i++) { 467 if (size > 1) { 468 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":", rank, 20 * i)); 469 } else { 470 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":", 20 * i)); 471 } 472 for (j = 0; j < 20; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, idx[i * 20 + j])); 473 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 474 } 475 if (p) { 476 if (size > 1) { 477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":", rank, 20 * n)); 478 } else { 479 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":", 20 * n)); 480 } 481 for (i = 0; i < p; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, idx[20 * n + i])); 482 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 483 } 484 PetscCall(PetscViewerFlush(viewer)); 485 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 486 } else if (isbinary) { 487 PetscMPIInt *sizes, Ntotal, *displs, NN; 488 PetscInt *array; 489 490 PetscCall(PetscMPIIntCast(N, &NN)); 491 492 if (size > 1) { 493 if (rank) { 494 PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm)); 495 PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_INT, NULL, NULL, NULL, MPIU_INT, 0, comm)); 496 } else { 497 PetscCall(PetscMalloc1(size, &sizes)); 498 PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm)); 499 Ntotal = sizes[0]; 500 PetscCall(PetscMalloc1(size, &displs)); 501 displs[0] = 0; 502 for (i = 1; i < size; i++) { 503 Ntotal += sizes[i]; 504 displs[i] = displs[i - 1] + sizes[i - 1]; 505 } 506 PetscCall(PetscMalloc1(Ntotal, &array)); 507 PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_INT, array, sizes, displs, MPIU_INT, 0, comm)); 508 PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_INT)); 509 PetscCall(PetscFree(sizes)); 510 PetscCall(PetscFree(displs)); 511 PetscCall(PetscFree(array)); 512 } 513 } else { 514 PetscCall(PetscViewerBinaryWrite(viewer, idx, N, PETSC_INT)); 515 } 516 } else { 517 const char *tname; 518 PetscCall(PetscObjectGetName((PetscObject)viewer, &tname)); 519 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname); 520 } 521 PetscFunctionReturn(PETSC_SUCCESS); 522 } 523 524 /*@ 525 PetscRealView - Prints an array of doubles; useful for debugging. 526 527 Collective 528 529 Input Parameters: 530 + N - number of `PetscReal` in array 531 . idx - array of `PetscReal` 532 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0 533 534 Level: intermediate 535 536 Note: 537 This may be called from within the debugger, passing 0 as the viewer 538 539 Developer Note: 540 `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done 541 542 .seealso: `PetscViewer`, `PetscIntView()` 543 @*/ 544 PetscErrorCode PetscRealView(PetscInt N, const PetscReal idx[], PetscViewer viewer) 545 { 546 PetscMPIInt rank, size; 547 PetscInt j, i, n = N / 5, p = N % 5; 548 PetscBool iascii, isbinary; 549 MPI_Comm comm; 550 551 PetscFunctionBegin; 552 if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF; 553 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 3); 554 PetscAssertPointer(idx, 2); 555 PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm)); 556 PetscCallMPI(MPI_Comm_size(comm, &size)); 557 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 558 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 561 if (iascii) { 562 PetscInt tab; 563 564 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 565 PetscCall(PetscViewerASCIIGetTab(viewer, &tab)); 566 for (i = 0; i < n; i++) { 567 PetscCall(PetscViewerASCIISetTab(viewer, tab)); 568 if (size > 1) { 569 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 5 * i)); 570 } else { 571 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 5 * i)); 572 } 573 PetscCall(PetscViewerASCIISetTab(viewer, 0)); 574 for (j = 0; j < 5; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[i * 5 + j])); 575 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 576 } 577 if (p) { 578 PetscCall(PetscViewerASCIISetTab(viewer, tab)); 579 if (size > 1) { 580 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 5 * n)); 581 } else { 582 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 5 * n)); 583 } 584 PetscCall(PetscViewerASCIISetTab(viewer, 0)); 585 for (i = 0; i < p; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[5 * n + i])); 586 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 587 } 588 PetscCall(PetscViewerFlush(viewer)); 589 PetscCall(PetscViewerASCIISetTab(viewer, tab)); 590 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 591 } else if (isbinary) { 592 PetscMPIInt *sizes, *displs, Ntotal, NN; 593 PetscReal *array; 594 595 PetscCall(PetscMPIIntCast(N, &NN)); 596 597 if (size > 1) { 598 if (rank) { 599 PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm)); 600 PetscCallMPI(MPI_Gatherv((PetscReal *)idx, NN, MPIU_REAL, NULL, NULL, NULL, MPIU_REAL, 0, comm)); 601 } else { 602 PetscCall(PetscMalloc1(size, &sizes)); 603 PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm)); 604 Ntotal = sizes[0]; 605 PetscCall(PetscMalloc1(size, &displs)); 606 displs[0] = 0; 607 for (i = 1; i < size; i++) { 608 Ntotal += sizes[i]; 609 displs[i] = displs[i - 1] + sizes[i - 1]; 610 } 611 PetscCall(PetscMalloc1(Ntotal, &array)); 612 PetscCallMPI(MPI_Gatherv((PetscReal *)idx, NN, MPIU_REAL, array, sizes, displs, MPIU_REAL, 0, comm)); 613 PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_REAL)); 614 PetscCall(PetscFree(sizes)); 615 PetscCall(PetscFree(displs)); 616 PetscCall(PetscFree(array)); 617 } 618 } else { 619 PetscCall(PetscViewerBinaryWrite(viewer, (void *)idx, N, PETSC_REAL)); 620 } 621 } else { 622 const char *tname; 623 PetscCall(PetscObjectGetName((PetscObject)viewer, &tname)); 624 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 /*@ 630 PetscScalarView - Prints an array of `PetscScalar`; useful for debugging. 631 632 Collective 633 634 Input Parameters: 635 + N - number of scalars in array 636 . idx - array of scalars 637 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0 638 639 Level: intermediate 640 641 Note: 642 This may be called from within the debugger, passing 0 as the viewer 643 644 Developer Note: 645 `idx` cannot be const because may be passed to binary viewer where byte swapping may be done 646 647 .seealso: `PetscViewer`, `PetscIntView()`, `PetscRealView()` 648 @*/ 649 PetscErrorCode PetscScalarView(PetscInt N, const PetscScalar idx[], PetscViewer viewer) 650 { 651 PetscMPIInt rank, size; 652 PetscInt j, i, n = N / 3, p = N % 3; 653 PetscBool iascii, isbinary; 654 MPI_Comm comm; 655 656 PetscFunctionBegin; 657 if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF; 658 PetscValidHeader(viewer, 3); 659 if (N) PetscAssertPointer(idx, 2); 660 PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm)); 661 PetscCallMPI(MPI_Comm_size(comm, &size)); 662 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 663 664 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 665 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 666 if (iascii) { 667 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 668 for (i = 0; i < n; i++) { 669 if (size > 1) { 670 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 3 * i)); 671 } else { 672 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 3 * i)); 673 } 674 for (j = 0; j < 3; j++) { 675 #if defined(PETSC_USE_COMPLEX) 676 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%12.4e,%12.4e)", (double)PetscRealPart(idx[i * 3 + j]), (double)PetscImaginaryPart(idx[i * 3 + j]))); 677 #else 678 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[i * 3 + j])); 679 #endif 680 } 681 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 682 } 683 if (p) { 684 if (size > 1) { 685 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 3 * n)); 686 } else { 687 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 3 * n)); 688 } 689 for (i = 0; i < p; i++) { 690 #if defined(PETSC_USE_COMPLEX) 691 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%12.4e,%12.4e)", (double)PetscRealPart(idx[n * 3 + i]), (double)PetscImaginaryPart(idx[n * 3 + i]))); 692 #else 693 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[3 * n + i])); 694 #endif 695 } 696 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 697 } 698 PetscCall(PetscViewerFlush(viewer)); 699 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 700 } else if (isbinary) { 701 PetscMPIInt *sizes, Ntotal, *displs, NN; 702 PetscScalar *array; 703 704 PetscCall(PetscMPIIntCast(N, &NN)); 705 706 if (size > 1) { 707 if (rank) { 708 PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm)); 709 PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_SCALAR, NULL, NULL, NULL, MPIU_SCALAR, 0, comm)); 710 } else { 711 PetscCall(PetscMalloc1(size, &sizes)); 712 PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm)); 713 Ntotal = sizes[0]; 714 PetscCall(PetscMalloc1(size, &displs)); 715 displs[0] = 0; 716 for (i = 1; i < size; i++) { 717 Ntotal += sizes[i]; 718 displs[i] = displs[i - 1] + sizes[i - 1]; 719 } 720 PetscCall(PetscMalloc1(Ntotal, &array)); 721 PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_SCALAR, array, sizes, displs, MPIU_SCALAR, 0, comm)); 722 PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_SCALAR)); 723 PetscCall(PetscFree(sizes)); 724 PetscCall(PetscFree(displs)); 725 PetscCall(PetscFree(array)); 726 } 727 } else { 728 PetscCall(PetscViewerBinaryWrite(viewer, (void *)idx, N, PETSC_SCALAR)); 729 } 730 } else { 731 const char *tname; 732 PetscCall(PetscObjectGetName((PetscObject)viewer, &tname)); 733 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname); 734 } 735 PetscFunctionReturn(PETSC_SUCCESS); 736 } 737 738 #if defined(PETSC_HAVE_CUDA) 739 #include <petscdevice_cuda.h> 740 PETSC_EXTERN const char *PetscCUBLASGetErrorName(cublasStatus_t status) 741 { 742 switch (status) { 743 #if (CUDART_VERSION >= 8000) /* At least CUDA 8.0 of Sep. 2016 had these */ 744 case CUBLAS_STATUS_SUCCESS: 745 return "CUBLAS_STATUS_SUCCESS"; 746 case CUBLAS_STATUS_NOT_INITIALIZED: 747 return "CUBLAS_STATUS_NOT_INITIALIZED"; 748 case CUBLAS_STATUS_ALLOC_FAILED: 749 return "CUBLAS_STATUS_ALLOC_FAILED"; 750 case CUBLAS_STATUS_INVALID_VALUE: 751 return "CUBLAS_STATUS_INVALID_VALUE"; 752 case CUBLAS_STATUS_ARCH_MISMATCH: 753 return "CUBLAS_STATUS_ARCH_MISMATCH"; 754 case CUBLAS_STATUS_MAPPING_ERROR: 755 return "CUBLAS_STATUS_MAPPING_ERROR"; 756 case CUBLAS_STATUS_EXECUTION_FAILED: 757 return "CUBLAS_STATUS_EXECUTION_FAILED"; 758 case CUBLAS_STATUS_INTERNAL_ERROR: 759 return "CUBLAS_STATUS_INTERNAL_ERROR"; 760 case CUBLAS_STATUS_NOT_SUPPORTED: 761 return "CUBLAS_STATUS_NOT_SUPPORTED"; 762 case CUBLAS_STATUS_LICENSE_ERROR: 763 return "CUBLAS_STATUS_LICENSE_ERROR"; 764 #endif 765 default: 766 return "unknown error"; 767 } 768 } 769 PETSC_EXTERN const char *PetscCUSolverGetErrorName(cusolverStatus_t status) 770 { 771 switch (status) { 772 #if (CUDART_VERSION >= 8000) /* At least CUDA 8.0 of Sep. 2016 had these */ 773 case CUSOLVER_STATUS_SUCCESS: 774 return "CUSOLVER_STATUS_SUCCESS"; 775 case CUSOLVER_STATUS_NOT_INITIALIZED: 776 return "CUSOLVER_STATUS_NOT_INITIALIZED"; 777 case CUSOLVER_STATUS_INVALID_VALUE: 778 return "CUSOLVER_STATUS_INVALID_VALUE"; 779 case CUSOLVER_STATUS_ARCH_MISMATCH: 780 return "CUSOLVER_STATUS_ARCH_MISMATCH"; 781 case CUSOLVER_STATUS_INTERNAL_ERROR: 782 return "CUSOLVER_STATUS_INTERNAL_ERROR"; 783 #if (CUDART_VERSION >= 9000) /* CUDA 9.0 had these defined on June 2021 */ 784 case CUSOLVER_STATUS_ALLOC_FAILED: 785 return "CUSOLVER_STATUS_ALLOC_FAILED"; 786 case CUSOLVER_STATUS_MAPPING_ERROR: 787 return "CUSOLVER_STATUS_MAPPING_ERROR"; 788 case CUSOLVER_STATUS_EXECUTION_FAILED: 789 return "CUSOLVER_STATUS_EXECUTION_FAILED"; 790 case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED: 791 return "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED"; 792 case CUSOLVER_STATUS_NOT_SUPPORTED: 793 return "CUSOLVER_STATUS_NOT_SUPPORTED "; 794 case CUSOLVER_STATUS_ZERO_PIVOT: 795 return "CUSOLVER_STATUS_ZERO_PIVOT"; 796 case CUSOLVER_STATUS_INVALID_LICENSE: 797 return "CUSOLVER_STATUS_INVALID_LICENSE"; 798 #endif 799 #endif 800 default: 801 return "unknown error"; 802 } 803 } 804 PETSC_EXTERN const char *PetscCUFFTGetErrorName(cufftResult result) 805 { 806 switch (result) { 807 case CUFFT_SUCCESS: 808 return "CUFFT_SUCCESS"; 809 case CUFFT_INVALID_PLAN: 810 return "CUFFT_INVALID_PLAN"; 811 case CUFFT_ALLOC_FAILED: 812 return "CUFFT_ALLOC_FAILED"; 813 case CUFFT_INVALID_TYPE: 814 return "CUFFT_INVALID_TYPE"; 815 case CUFFT_INVALID_VALUE: 816 return "CUFFT_INVALID_VALUE"; 817 case CUFFT_INTERNAL_ERROR: 818 return "CUFFT_INTERNAL_ERROR"; 819 case CUFFT_EXEC_FAILED: 820 return "CUFFT_EXEC_FAILED"; 821 case CUFFT_SETUP_FAILED: 822 return "CUFFT_SETUP_FAILED"; 823 case CUFFT_INVALID_SIZE: 824 return "CUFFT_INVALID_SIZE"; 825 case CUFFT_UNALIGNED_DATA: 826 return "CUFFT_UNALIGNED_DATA"; 827 case CUFFT_INCOMPLETE_PARAMETER_LIST: 828 return "CUFFT_INCOMPLETE_PARAMETER_LIST"; 829 case CUFFT_INVALID_DEVICE: 830 return "CUFFT_INVALID_DEVICE"; 831 case CUFFT_PARSE_ERROR: 832 return "CUFFT_PARSE_ERROR"; 833 case CUFFT_NO_WORKSPACE: 834 return "CUFFT_NO_WORKSPACE"; 835 case CUFFT_NOT_IMPLEMENTED: 836 return "CUFFT_NOT_IMPLEMENTED"; 837 case CUFFT_LICENSE_ERROR: 838 return "CUFFT_LICENSE_ERROR"; 839 case CUFFT_NOT_SUPPORTED: 840 return "CUFFT_NOT_SUPPORTED"; 841 default: 842 return "unknown error"; 843 } 844 } 845 #endif 846 847 #if defined(PETSC_HAVE_HIP) 848 #include <petscdevice_hip.h> 849 PETSC_EXTERN const char *PetscHIPBLASGetErrorName(hipblasStatus_t status) 850 { 851 switch (status) { 852 case HIPBLAS_STATUS_SUCCESS: 853 return "HIPBLAS_STATUS_SUCCESS"; 854 case HIPBLAS_STATUS_NOT_INITIALIZED: 855 return "HIPBLAS_STATUS_NOT_INITIALIZED"; 856 case HIPBLAS_STATUS_ALLOC_FAILED: 857 return "HIPBLAS_STATUS_ALLOC_FAILED"; 858 case HIPBLAS_STATUS_INVALID_VALUE: 859 return "HIPBLAS_STATUS_INVALID_VALUE"; 860 case HIPBLAS_STATUS_ARCH_MISMATCH: 861 return "HIPBLAS_STATUS_ARCH_MISMATCH"; 862 case HIPBLAS_STATUS_MAPPING_ERROR: 863 return "HIPBLAS_STATUS_MAPPING_ERROR"; 864 case HIPBLAS_STATUS_EXECUTION_FAILED: 865 return "HIPBLAS_STATUS_EXECUTION_FAILED"; 866 case HIPBLAS_STATUS_INTERNAL_ERROR: 867 return "HIPBLAS_STATUS_INTERNAL_ERROR"; 868 case HIPBLAS_STATUS_NOT_SUPPORTED: 869 return "HIPBLAS_STATUS_NOT_SUPPORTED"; 870 default: 871 return "unknown error"; 872 } 873 } 874 PETSC_EXTERN const char *PetscHIPSPARSEGetErrorName(hipsparseStatus_t status) 875 { 876 switch (status) { 877 case HIPSPARSE_STATUS_SUCCESS: 878 return "HIPSPARSE_STATUS_SUCCESS"; 879 case HIPSPARSE_STATUS_NOT_INITIALIZED: 880 return "HIPSPARSE_STATUS_NOT_INITIALIZED"; 881 case HIPSPARSE_STATUS_ALLOC_FAILED: 882 return "HIPSPARSE_STATUS_ALLOC_FAILED"; 883 case HIPSPARSE_STATUS_INVALID_VALUE: 884 return "HIPSPARSE_STATUS_INVALID_VALUE"; 885 case HIPSPARSE_STATUS_ARCH_MISMATCH: 886 return "HIPSPARSE_STATUS_ARCH_MISMATCH"; 887 case HIPSPARSE_STATUS_MAPPING_ERROR: 888 return "HIPSPARSE_STATUS_MAPPING_ERROR"; 889 case HIPSPARSE_STATUS_EXECUTION_FAILED: 890 return "HIPSPARSE_STATUS_EXECUTION_FAILED"; 891 case HIPSPARSE_STATUS_INTERNAL_ERROR: 892 return "HIPSPARSE_STATUS_INTERNAL_ERROR"; 893 case HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED: 894 return "HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED"; 895 case HIPSPARSE_STATUS_ZERO_PIVOT: 896 return "HIPSPARSE_STATUS_ZERO_PIVOT"; 897 case HIPSPARSE_STATUS_NOT_SUPPORTED: 898 return "HIPSPARSE_STATUS_NOT_SUPPORTED"; 899 case HIPSPARSE_STATUS_INSUFFICIENT_RESOURCES: 900 return "HIPSPARSE_STATUS_INSUFFICIENT_RESOURCES"; 901 default: 902 return "unknown error"; 903 } 904 } 905 PETSC_EXTERN const char *PetscHIPSolverGetErrorName(hipsolverStatus_t status) 906 { 907 switch (status) { 908 case HIPSOLVER_STATUS_SUCCESS: 909 return "HIPSOLVER_STATUS_SUCCESS"; 910 case HIPSOLVER_STATUS_NOT_INITIALIZED: 911 return "HIPSOLVER_STATUS_NOT_INITIALIZED"; 912 case HIPSOLVER_STATUS_ALLOC_FAILED: 913 return "HIPSOLVER_STATUS_ALLOC_FAILED"; 914 case HIPSOLVER_STATUS_MAPPING_ERROR: 915 return "HIPSOLVER_STATUS_MAPPING_ERROR"; 916 case HIPSOLVER_STATUS_INVALID_VALUE: 917 return "HIPSOLVER_STATUS_INVALID_VALUE"; 918 case HIPSOLVER_STATUS_EXECUTION_FAILED: 919 return "HIPSOLVER_STATUS_EXECUTION_FAILED"; 920 case HIPSOLVER_STATUS_INTERNAL_ERROR: 921 return "HIPSOLVER_STATUS_INTERNAL_ERROR"; 922 case HIPSOLVER_STATUS_NOT_SUPPORTED: 923 return "HIPSOLVER_STATUS_NOT_SUPPORTED "; 924 case HIPSOLVER_STATUS_ARCH_MISMATCH: 925 return "HIPSOLVER_STATUS_ARCH_MISMATCH"; 926 case HIPSOLVER_STATUS_HANDLE_IS_NULLPTR: 927 return "HIPSOLVER_STATUS_HANDLE_IS_NULLPTR"; 928 case HIPSOLVER_STATUS_INVALID_ENUM: 929 return "HIPSOLVER_STATUS_INVALID_ENUM"; 930 case HIPSOLVER_STATUS_UNKNOWN: 931 default: 932 return "HIPSOLVER_STATUS_UNKNOWN"; 933 } 934 } 935 #endif 936 937 /*@C 938 PetscMPIErrorString - Given an MPI error code returns the `MPI_Error_string()` appropriately 939 formatted for displaying with the PETSc error handlers. 940 941 Not Collective, No Fortran Support 942 943 Input Parameters: 944 + err - the MPI error code 945 - slen - length of `string`, should be at least as large as `MPI_MAX_ERROR_STRING` 946 947 Output Parameter: 948 . string - the MPI error message 949 950 Level: developer 951 952 Note: 953 Does not return an error code or do error handling because it may be called from inside an error handler 954 955 .seealso: `PetscErrorCode` `PetscErrorMessage()` 956 @*/ 957 void PetscMPIErrorString(PetscMPIInt err, size_t slen, char *string) 958 { 959 char errorstring[MPI_MAX_ERROR_STRING]; 960 PetscMPIInt len; 961 size_t j = 0; 962 963 MPI_Error_string(err, (char *)errorstring, &len); 964 for (PetscMPIInt i = 0; i < len && j < slen - 2; i++) { 965 string[j++] = errorstring[i]; 966 if (errorstring[i] == '\n') { 967 for (PetscMPIInt k = 0; k < 16 && j < slen - 2; k++) string[j++] = ' '; 968 } 969 } 970 string[j] = 0; 971 } 972