xref: /petsc/src/sys/error/err.c (revision 835f2295474254850a9de28f274be7ce943244c7)
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   /*101*/ "Unhandled Python Exception",
252   NULL};
253 
254 /*@C
255   PetscErrorMessage - Returns the text string associated with a PETSc error code.
256 
257   Not Collective, No Fortran Support
258 
259   Input Parameter:
260 . errnum - the error code
261 
262   Output Parameters:
263 + text     - the error message (`NULL` if not desired)
264 - specific - the specific error message that was set with `SETERRQ()` or
265              `PetscError()`. (`NULL` if not desired)
266 
267   Level: developer
268 
269 .seealso: `PetscErrorCode`, `PetscPushErrorHandler()`, `PetscAttachDebuggerErrorHandler()`,
270 `PetscError()`, `SETERRQ()`, `PetscCall()` `PetscAbortErrorHandler()`,
271 `PetscTraceBackErrorHandler()`
272 @*/
273 PetscErrorCode PetscErrorMessage(PetscErrorCode errnum, const char *text[], char *specific[])
274 {
275   PetscFunctionBegin;
276   if (text) {
277     if (errnum > PETSC_ERR_MIN_VALUE && errnum < PETSC_ERR_MAX_VALUE) {
278       size_t len;
279 
280       *text = PetscErrorStrings[errnum - PETSC_ERR_MIN_VALUE - 1];
281       PetscCall(PetscStrlen(*text, &len));
282       if (!len) *text = NULL;
283     } else if (errnum == PETSC_ERR_BOOLEAN_MACRO_FAILURE) {
284       /* this "error code" arises from failures in boolean macros, where the || operator is
285          used to short-circuit the macro call in case of error. This has the side effect of
286          "returning" either 0 (PETSC_SUCCESS) or 1 (PETSC_ERR_UNKNONWN):
287 
288          #define PETSC_FOO(x) ((PetscErrorCode)(PetscBar(x) || PetscBaz(x)))
289 
290          If PetscBar() fails (returns nonzero) PetscBaz() is not executed but the result of
291          this expression is boolean false, hence PETSC_ERR_UNNOWN
292        */
293       *text = "Error occurred in boolean shortcuit in macro";
294     } else {
295       *text = NULL;
296     }
297   }
298   if (specific) *specific = PetscErrorBaseMessage;
299   PetscFunctionReturn(PETSC_SUCCESS);
300 }
301 
302 #if defined(PETSC_CLANGUAGE_CXX)
303   /* C++ exceptions are formally not allowed to propagate through extern "C" code. In practice, far too much software
304  * would be broken if implementations did not handle it in some common cases. However, keep in mind
305  *
306  *   Rule 62. Don't allow exceptions to propagate across module boundaries
307  *
308  * in "C++ Coding Standards" by Sutter and Alexandrescu. (This accounts for part of the ongoing C++ binary interface
309  * instability.) Having PETSc raise errors as C++ exceptions was probably misguided and should eventually be removed.
310  *
311  * Here is the problem: You have a C++ function call a PETSc function, and you would like to maintain the error message
312  * and stack information from the PETSc error. You could make everyone write exactly this code in their C++, but that
313  * seems crazy to me.
314  */
315   #include <sstream>
316   #include <stdexcept>
317 static void PetscCxxErrorThrow()
318 {
319   const char *str;
320   if (eh && eh->ctx) {
321     std::ostringstream *msg;
322     msg = (std::ostringstream *)eh->ctx;
323     str = msg->str().c_str();
324   } else str = "Error detected in C PETSc";
325 
326   throw std::runtime_error(str);
327 }
328 #endif
329 
330 /*@C
331   PetscError - Routine that is called when an error has been detected, usually called through the macro `SETERRQ`(`PETSC_COMM_SELF`,)` or by `PetscCall()`.
332 
333   Collective
334 
335   Input Parameters:
336 + comm - communicator over which error occurred.  ALL MPI processes of this communicator MUST call this routine
337 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine)
338 . func - the function name in which the error was detected
339 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine)
340 . n    - the generic error number
341 . p    - `PETSC_ERROR_INITIAL` indicates the error was initially detected, `PETSC_ERROR_REPEAT` indicates this is a traceback from a previously detected error
342 - mess - formatted message string - aka printf
343 
344   Options Database Keys:
345 + -error_output_stdout - output the error messages to `stdout` instead of the default `stderr`
346 - -error_output_none   - do not output the error messages
347 
348   Level: intermediate
349 
350   Notes:
351   PETSc error handling is done with error return codes. A non-zero return indicates an error
352   was detected. The return-value of this routine is what is ultimately returned by
353   `SETERRQ()`.
354 
355   Numerical errors (potential divide by zero, for example) are not managed by the
356   error return codes; they are managed via, for example, `KSPGetConvergedReason()` that
357   indicates if the solve was successful or not. The option `-ksp_error_if_not_converged`, for
358   example, turns numerical failures into hard errors managed via `PetscError()`.
359 
360   PETSc provides a rich supply of error handlers, see the list below, and users can also
361   provide their own error handlers.
362 
363   If the user sets their own error handler (via `PetscPushErrorHandler()`) they may return any
364   arbitrary value from it, but are encouraged to return nonzero values. If the return value is
365   zero, `SETERRQ()` will ignore the value and return `PETSC_ERR_RETURN` (a nonzero value)
366   instead.
367 
368   Most users need not directly use this routine and the error handlers, but can instead use
369   the simplified interface `PetscCall()` or `SETERRQ()`.
370 
371   Fortran Note:
372   This routine is used differently from Fortran
373 .vb
374   PetscError(MPI_Comm comm, PetscErrorCode n, PetscErrorType p, char *message)
375 .ve
376 
377   Developer Note:
378   Since this is called after an error condition it should not be calling any error handlers (currently it ignores any error codes)
379   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
380   but this annoying.
381 
382 .seealso: `PetscErrorCode`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscTraceBackErrorHandler()`, `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`,
383           `PetscReturnErrorHandler()`, `PetscAttachDebuggerErrorHandler()`, `PetscEmacsClientErrorHandler()`,
384           `SETERRQ()`, `PetscCall()`, `CHKMEMQ`, `PetscErrorMessage()`, `PETSCABORT()`, `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`
385 @*/
386 PetscErrorCode PetscError(MPI_Comm comm, int line, const char *func, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, ...)
387 {
388   va_list        Argp;
389   size_t         fullLength;
390   char           buf[2048], *lbuf = NULL;
391   PetscBool      ismain;
392   PetscErrorCode ierr;
393 
394   if (!PetscErrorHandlingInitialized) return n;
395   if (comm == MPI_COMM_NULL) comm = PETSC_COMM_SELF;
396 
397   /* Compose the message evaluating the print format */
398   if (mess) {
399     va_start(Argp, mess);
400     (void)PetscVSNPrintf(buf, 2048, mess, &fullLength, Argp);
401     va_end(Argp);
402     lbuf = buf;
403     if (p == PETSC_ERROR_INITIAL) (void)PetscStrncpy(PetscErrorBaseMessage, lbuf, sizeof(PetscErrorBaseMessage));
404   }
405 
406   if (p == PETSC_ERROR_INITIAL && n != PETSC_ERR_MEMC) (void)PetscMallocValidate(__LINE__, PETSC_FUNCTION_NAME, __FILE__);
407 
408   if (!eh) ierr = PetscTraceBackErrorHandler(comm, line, func, file, n, p, lbuf, NULL);
409   else ierr = (*eh->handler)(comm, line, func, file, n, p, lbuf, eh->ctx);
410   PetscStackClearTop;
411 
412   /*
413       If this is called from the main() routine we abort the program.
414       We cannot just return because them some MPI processes may continue to attempt to run
415       while this process simply exits.
416   */
417   if (func) {
418     (void)PetscStrncmp(func, "main", 4, &ismain);
419     if (ismain) {
420       if (petscwaitonerrorflg) (void)PetscSleep(1000);
421       PETSCABORT(comm, ierr);
422     }
423   }
424 #if defined(PETSC_CLANGUAGE_CXX)
425   if (p == PETSC_ERROR_IN_CXX) PetscCxxErrorThrow();
426 #endif
427   return ierr;
428 }
429 
430 /*@
431   PetscIntView - Prints an array of integers; useful for debugging.
432 
433   Collective
434 
435   Input Parameters:
436 + N      - number of integers in array
437 . idx    - array of integers
438 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
439 
440   Level: intermediate
441 
442   Note:
443   This may be called from within the debugger, passing 0 as the viewer
444 
445   Developer Note:
446   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
447 
448 .seealso: `PetscViewer`, `PetscRealView()`
449 @*/
450 PetscErrorCode PetscIntView(PetscInt N, const PetscInt idx[], PetscViewer viewer)
451 {
452   PetscMPIInt rank, size;
453   PetscInt    j, i, n = N / 20, p = N % 20;
454   PetscBool   iascii, isbinary;
455   MPI_Comm    comm;
456 
457   PetscFunctionBegin;
458   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
459   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 3);
460   if (N) PetscAssertPointer(idx, 2);
461   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
462   PetscCallMPI(MPI_Comm_size(comm, &size));
463   PetscCallMPI(MPI_Comm_rank(comm, &rank));
464 
465   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
466   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
467   if (iascii) {
468     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
469     for (i = 0; i < n; i++) {
470       if (size > 1) {
471         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":", rank, 20 * i));
472       } else {
473         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":", 20 * i));
474       }
475       for (j = 0; j < 20; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, idx[i * 20 + j]));
476       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
477     }
478     if (p) {
479       if (size > 1) {
480         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":", rank, 20 * n));
481       } else {
482         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":", 20 * n));
483       }
484       for (i = 0; i < p; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, idx[20 * n + i]));
485       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
486     }
487     PetscCall(PetscViewerFlush(viewer));
488     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
489   } else if (isbinary) {
490     PetscMPIInt *sizes, Ntotal, *displs, NN;
491     PetscInt    *array;
492 
493     PetscCall(PetscMPIIntCast(N, &NN));
494 
495     if (size > 1) {
496       if (rank) {
497         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
498         PetscCallMPI(MPI_Gatherv(idx, NN, MPIU_INT, NULL, NULL, NULL, MPIU_INT, 0, comm));
499       } else {
500         PetscCall(PetscMalloc1(size, &sizes));
501         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
502         Ntotal = sizes[0];
503         PetscCall(PetscMalloc1(size, &displs));
504         displs[0] = 0;
505         for (i = 1; i < size; i++) {
506           Ntotal += sizes[i];
507           displs[i] = displs[i - 1] + sizes[i - 1];
508         }
509         PetscCall(PetscMalloc1(Ntotal, &array));
510         PetscCallMPI(MPI_Gatherv(idx, NN, MPIU_INT, array, sizes, displs, MPIU_INT, 0, comm));
511         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_INT));
512         PetscCall(PetscFree(sizes));
513         PetscCall(PetscFree(displs));
514         PetscCall(PetscFree(array));
515       }
516     } else {
517       PetscCall(PetscViewerBinaryWrite(viewer, idx, N, PETSC_INT));
518     }
519   } else {
520     const char *tname;
521     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
522     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
523   }
524   PetscFunctionReturn(PETSC_SUCCESS);
525 }
526 
527 /*@
528   PetscRealView - Prints an array of doubles; useful for debugging.
529 
530   Collective
531 
532   Input Parameters:
533 + N      - number of `PetscReal` in array
534 . idx    - array of `PetscReal`
535 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
536 
537   Level: intermediate
538 
539   Note:
540   This may be called from within the debugger, passing 0 as the viewer
541 
542   Developer Note:
543   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
544 
545 .seealso: `PetscViewer`, `PetscIntView()`
546 @*/
547 PetscErrorCode PetscRealView(PetscInt N, const PetscReal idx[], PetscViewer viewer)
548 {
549   PetscMPIInt rank, size;
550   PetscInt    j, i, n = N / 5, p = N % 5;
551   PetscBool   iascii, isbinary;
552   MPI_Comm    comm;
553 
554   PetscFunctionBegin;
555   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
556   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 3);
557   PetscAssertPointer(idx, 2);
558   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
559   PetscCallMPI(MPI_Comm_size(comm, &size));
560   PetscCallMPI(MPI_Comm_rank(comm, &rank));
561 
562   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
563   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
564   if (iascii) {
565     PetscInt tab;
566 
567     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
568     PetscCall(PetscViewerASCIIGetTab(viewer, &tab));
569     for (i = 0; i < n; i++) {
570       PetscCall(PetscViewerASCIISetTab(viewer, tab));
571       if (size > 1) {
572         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 5 * i));
573       } else {
574         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 5 * i));
575       }
576       PetscCall(PetscViewerASCIISetTab(viewer, 0));
577       for (j = 0; j < 5; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[i * 5 + j]));
578       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
579     }
580     if (p) {
581       PetscCall(PetscViewerASCIISetTab(viewer, tab));
582       if (size > 1) {
583         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 5 * n));
584       } else {
585         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 5 * n));
586       }
587       PetscCall(PetscViewerASCIISetTab(viewer, 0));
588       for (i = 0; i < p; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[5 * n + i]));
589       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
590     }
591     PetscCall(PetscViewerFlush(viewer));
592     PetscCall(PetscViewerASCIISetTab(viewer, tab));
593     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
594   } else if (isbinary) {
595     PetscMPIInt *sizes, *displs, Ntotal, NN;
596     PetscReal   *array;
597 
598     PetscCall(PetscMPIIntCast(N, &NN));
599 
600     if (size > 1) {
601       if (rank) {
602         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
603         PetscCallMPI(MPI_Gatherv(idx, NN, MPIU_REAL, NULL, NULL, NULL, MPIU_REAL, 0, comm));
604       } else {
605         PetscCall(PetscMalloc1(size, &sizes));
606         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
607         Ntotal = sizes[0];
608         PetscCall(PetscMalloc1(size, &displs));
609         displs[0] = 0;
610         for (i = 1; i < size; i++) {
611           Ntotal += sizes[i];
612           displs[i] = displs[i - 1] + sizes[i - 1];
613         }
614         PetscCall(PetscMalloc1(Ntotal, &array));
615         PetscCallMPI(MPI_Gatherv(idx, NN, MPIU_REAL, array, sizes, displs, MPIU_REAL, 0, comm));
616         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_REAL));
617         PetscCall(PetscFree(sizes));
618         PetscCall(PetscFree(displs));
619         PetscCall(PetscFree(array));
620       }
621     } else {
622       PetscCall(PetscViewerBinaryWrite(viewer, (void *)idx, N, PETSC_REAL));
623     }
624   } else {
625     const char *tname;
626     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
627     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
628   }
629   PetscFunctionReturn(PETSC_SUCCESS);
630 }
631 
632 /*@
633   PetscScalarView - Prints an array of `PetscScalar`; useful for debugging.
634 
635   Collective
636 
637   Input Parameters:
638 + N      - number of scalars in array
639 . idx    - array of scalars
640 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
641 
642   Level: intermediate
643 
644   Note:
645   This may be called from within the debugger, passing 0 as the viewer
646 
647   Developer Note:
648   `idx` cannot be const because may be passed to binary viewer where byte swapping may be done
649 
650 .seealso: `PetscViewer`, `PetscIntView()`, `PetscRealView()`
651 @*/
652 PetscErrorCode PetscScalarView(PetscInt N, const PetscScalar idx[], PetscViewer viewer)
653 {
654   PetscMPIInt rank, size;
655   PetscInt    j, i, n = N / 3, p = N % 3;
656   PetscBool   iascii, isbinary;
657   MPI_Comm    comm;
658 
659   PetscFunctionBegin;
660   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
661   PetscValidHeader(viewer, 3);
662   if (N) PetscAssertPointer(idx, 2);
663   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
664   PetscCallMPI(MPI_Comm_size(comm, &size));
665   PetscCallMPI(MPI_Comm_rank(comm, &rank));
666 
667   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
668   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
669   if (iascii) {
670     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
671     for (i = 0; i < n; i++) {
672       if (size > 1) {
673         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 3 * i));
674       } else {
675         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 3 * i));
676       }
677       for (j = 0; j < 3; j++) {
678 #if defined(PETSC_USE_COMPLEX)
679         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%12.4e,%12.4e)", (double)PetscRealPart(idx[i * 3 + j]), (double)PetscImaginaryPart(idx[i * 3 + j])));
680 #else
681         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[i * 3 + j]));
682 #endif
683       }
684       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
685     }
686     if (p) {
687       if (size > 1) {
688         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 3 * n));
689       } else {
690         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 3 * n));
691       }
692       for (i = 0; i < p; i++) {
693 #if defined(PETSC_USE_COMPLEX)
694         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%12.4e,%12.4e)", (double)PetscRealPart(idx[n * 3 + i]), (double)PetscImaginaryPart(idx[n * 3 + i])));
695 #else
696         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[3 * n + i]));
697 #endif
698       }
699       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
700     }
701     PetscCall(PetscViewerFlush(viewer));
702     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
703   } else if (isbinary) {
704     PetscMPIInt *sizes, Ntotal, *displs, NN;
705     PetscScalar *array;
706 
707     PetscCall(PetscMPIIntCast(N, &NN));
708 
709     if (size > 1) {
710       if (rank) {
711         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
712         PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_SCALAR, NULL, NULL, NULL, MPIU_SCALAR, 0, comm));
713       } else {
714         PetscCall(PetscMalloc1(size, &sizes));
715         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
716         Ntotal = sizes[0];
717         PetscCall(PetscMalloc1(size, &displs));
718         displs[0] = 0;
719         for (i = 1; i < size; i++) {
720           Ntotal += sizes[i];
721           displs[i] = displs[i - 1] + sizes[i - 1];
722         }
723         PetscCall(PetscMalloc1(Ntotal, &array));
724         PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_SCALAR, array, sizes, displs, MPIU_SCALAR, 0, comm));
725         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_SCALAR));
726         PetscCall(PetscFree(sizes));
727         PetscCall(PetscFree(displs));
728         PetscCall(PetscFree(array));
729       }
730     } else {
731       PetscCall(PetscViewerBinaryWrite(viewer, (void *)idx, N, PETSC_SCALAR));
732     }
733   } else {
734     const char *tname;
735     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
736     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
737   }
738   PetscFunctionReturn(PETSC_SUCCESS);
739 }
740 
741 #if defined(PETSC_HAVE_CUDA)
742   #include <petscdevice_cuda.h>
743 PETSC_EXTERN const char *PetscCUBLASGetErrorName(cublasStatus_t status)
744 {
745   switch (status) {
746   #if (CUDART_VERSION >= 8000) /* At least CUDA 8.0 of Sep. 2016 had these */
747   case CUBLAS_STATUS_SUCCESS:
748     return "CUBLAS_STATUS_SUCCESS";
749   case CUBLAS_STATUS_NOT_INITIALIZED:
750     return "CUBLAS_STATUS_NOT_INITIALIZED";
751   case CUBLAS_STATUS_ALLOC_FAILED:
752     return "CUBLAS_STATUS_ALLOC_FAILED";
753   case CUBLAS_STATUS_INVALID_VALUE:
754     return "CUBLAS_STATUS_INVALID_VALUE";
755   case CUBLAS_STATUS_ARCH_MISMATCH:
756     return "CUBLAS_STATUS_ARCH_MISMATCH";
757   case CUBLAS_STATUS_MAPPING_ERROR:
758     return "CUBLAS_STATUS_MAPPING_ERROR";
759   case CUBLAS_STATUS_EXECUTION_FAILED:
760     return "CUBLAS_STATUS_EXECUTION_FAILED";
761   case CUBLAS_STATUS_INTERNAL_ERROR:
762     return "CUBLAS_STATUS_INTERNAL_ERROR";
763   case CUBLAS_STATUS_NOT_SUPPORTED:
764     return "CUBLAS_STATUS_NOT_SUPPORTED";
765   case CUBLAS_STATUS_LICENSE_ERROR:
766     return "CUBLAS_STATUS_LICENSE_ERROR";
767   #endif
768   default:
769     return "unknown error";
770   }
771 }
772 PETSC_EXTERN const char *PetscCUSolverGetErrorName(cusolverStatus_t status)
773 {
774   switch (status) {
775   #if (CUDART_VERSION >= 8000) /* At least CUDA 8.0 of Sep. 2016 had these */
776   case CUSOLVER_STATUS_SUCCESS:
777     return "CUSOLVER_STATUS_SUCCESS";
778   case CUSOLVER_STATUS_NOT_INITIALIZED:
779     return "CUSOLVER_STATUS_NOT_INITIALIZED";
780   case CUSOLVER_STATUS_INVALID_VALUE:
781     return "CUSOLVER_STATUS_INVALID_VALUE";
782   case CUSOLVER_STATUS_ARCH_MISMATCH:
783     return "CUSOLVER_STATUS_ARCH_MISMATCH";
784   case CUSOLVER_STATUS_INTERNAL_ERROR:
785     return "CUSOLVER_STATUS_INTERNAL_ERROR";
786     #if (CUDART_VERSION >= 9000) /* CUDA 9.0 had these defined on June 2021 */
787   case CUSOLVER_STATUS_ALLOC_FAILED:
788     return "CUSOLVER_STATUS_ALLOC_FAILED";
789   case CUSOLVER_STATUS_MAPPING_ERROR:
790     return "CUSOLVER_STATUS_MAPPING_ERROR";
791   case CUSOLVER_STATUS_EXECUTION_FAILED:
792     return "CUSOLVER_STATUS_EXECUTION_FAILED";
793   case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
794     return "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED";
795   case CUSOLVER_STATUS_NOT_SUPPORTED:
796     return "CUSOLVER_STATUS_NOT_SUPPORTED ";
797   case CUSOLVER_STATUS_ZERO_PIVOT:
798     return "CUSOLVER_STATUS_ZERO_PIVOT";
799   case CUSOLVER_STATUS_INVALID_LICENSE:
800     return "CUSOLVER_STATUS_INVALID_LICENSE";
801     #endif
802   #endif
803   default:
804     return "unknown error";
805   }
806 }
807 PETSC_EXTERN const char *PetscCUFFTGetErrorName(cufftResult result)
808 {
809   switch (result) {
810   case CUFFT_SUCCESS:
811     return "CUFFT_SUCCESS";
812   case CUFFT_INVALID_PLAN:
813     return "CUFFT_INVALID_PLAN";
814   case CUFFT_ALLOC_FAILED:
815     return "CUFFT_ALLOC_FAILED";
816   case CUFFT_INVALID_TYPE:
817     return "CUFFT_INVALID_TYPE";
818   case CUFFT_INVALID_VALUE:
819     return "CUFFT_INVALID_VALUE";
820   case CUFFT_INTERNAL_ERROR:
821     return "CUFFT_INTERNAL_ERROR";
822   case CUFFT_EXEC_FAILED:
823     return "CUFFT_EXEC_FAILED";
824   case CUFFT_SETUP_FAILED:
825     return "CUFFT_SETUP_FAILED";
826   case CUFFT_INVALID_SIZE:
827     return "CUFFT_INVALID_SIZE";
828   case CUFFT_UNALIGNED_DATA:
829     return "CUFFT_UNALIGNED_DATA";
830   case CUFFT_INCOMPLETE_PARAMETER_LIST:
831     return "CUFFT_INCOMPLETE_PARAMETER_LIST";
832   case CUFFT_INVALID_DEVICE:
833     return "CUFFT_INVALID_DEVICE";
834   case CUFFT_PARSE_ERROR:
835     return "CUFFT_PARSE_ERROR";
836   case CUFFT_NO_WORKSPACE:
837     return "CUFFT_NO_WORKSPACE";
838   case CUFFT_NOT_IMPLEMENTED:
839     return "CUFFT_NOT_IMPLEMENTED";
840   case CUFFT_LICENSE_ERROR:
841     return "CUFFT_LICENSE_ERROR";
842   case CUFFT_NOT_SUPPORTED:
843     return "CUFFT_NOT_SUPPORTED";
844   default:
845     return "unknown error";
846   }
847 }
848 #endif
849 
850 #if defined(PETSC_HAVE_HIP)
851   #include <petscdevice_hip.h>
852 PETSC_EXTERN const char *PetscHIPBLASGetErrorName(hipblasStatus_t status)
853 {
854   switch (status) {
855   case HIPBLAS_STATUS_SUCCESS:
856     return "HIPBLAS_STATUS_SUCCESS";
857   case HIPBLAS_STATUS_NOT_INITIALIZED:
858     return "HIPBLAS_STATUS_NOT_INITIALIZED";
859   case HIPBLAS_STATUS_ALLOC_FAILED:
860     return "HIPBLAS_STATUS_ALLOC_FAILED";
861   case HIPBLAS_STATUS_INVALID_VALUE:
862     return "HIPBLAS_STATUS_INVALID_VALUE";
863   case HIPBLAS_STATUS_ARCH_MISMATCH:
864     return "HIPBLAS_STATUS_ARCH_MISMATCH";
865   case HIPBLAS_STATUS_MAPPING_ERROR:
866     return "HIPBLAS_STATUS_MAPPING_ERROR";
867   case HIPBLAS_STATUS_EXECUTION_FAILED:
868     return "HIPBLAS_STATUS_EXECUTION_FAILED";
869   case HIPBLAS_STATUS_INTERNAL_ERROR:
870     return "HIPBLAS_STATUS_INTERNAL_ERROR";
871   case HIPBLAS_STATUS_NOT_SUPPORTED:
872     return "HIPBLAS_STATUS_NOT_SUPPORTED";
873   default:
874     return "unknown error";
875   }
876 }
877 PETSC_EXTERN const char *PetscHIPSPARSEGetErrorName(hipsparseStatus_t status)
878 {
879   switch (status) {
880   case HIPSPARSE_STATUS_SUCCESS:
881     return "HIPSPARSE_STATUS_SUCCESS";
882   case HIPSPARSE_STATUS_NOT_INITIALIZED:
883     return "HIPSPARSE_STATUS_NOT_INITIALIZED";
884   case HIPSPARSE_STATUS_ALLOC_FAILED:
885     return "HIPSPARSE_STATUS_ALLOC_FAILED";
886   case HIPSPARSE_STATUS_INVALID_VALUE:
887     return "HIPSPARSE_STATUS_INVALID_VALUE";
888   case HIPSPARSE_STATUS_ARCH_MISMATCH:
889     return "HIPSPARSE_STATUS_ARCH_MISMATCH";
890   case HIPSPARSE_STATUS_MAPPING_ERROR:
891     return "HIPSPARSE_STATUS_MAPPING_ERROR";
892   case HIPSPARSE_STATUS_EXECUTION_FAILED:
893     return "HIPSPARSE_STATUS_EXECUTION_FAILED";
894   case HIPSPARSE_STATUS_INTERNAL_ERROR:
895     return "HIPSPARSE_STATUS_INTERNAL_ERROR";
896   case HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
897     return "HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED";
898   case HIPSPARSE_STATUS_ZERO_PIVOT:
899     return "HIPSPARSE_STATUS_ZERO_PIVOT";
900   case HIPSPARSE_STATUS_NOT_SUPPORTED:
901     return "HIPSPARSE_STATUS_NOT_SUPPORTED";
902   case HIPSPARSE_STATUS_INSUFFICIENT_RESOURCES:
903     return "HIPSPARSE_STATUS_INSUFFICIENT_RESOURCES";
904   default:
905     return "unknown error";
906   }
907 }
908 PETSC_EXTERN const char *PetscHIPSolverGetErrorName(hipsolverStatus_t status)
909 {
910   switch (status) {
911   case HIPSOLVER_STATUS_SUCCESS:
912     return "HIPSOLVER_STATUS_SUCCESS";
913   case HIPSOLVER_STATUS_NOT_INITIALIZED:
914     return "HIPSOLVER_STATUS_NOT_INITIALIZED";
915   case HIPSOLVER_STATUS_ALLOC_FAILED:
916     return "HIPSOLVER_STATUS_ALLOC_FAILED";
917   case HIPSOLVER_STATUS_MAPPING_ERROR:
918     return "HIPSOLVER_STATUS_MAPPING_ERROR";
919   case HIPSOLVER_STATUS_INVALID_VALUE:
920     return "HIPSOLVER_STATUS_INVALID_VALUE";
921   case HIPSOLVER_STATUS_EXECUTION_FAILED:
922     return "HIPSOLVER_STATUS_EXECUTION_FAILED";
923   case HIPSOLVER_STATUS_INTERNAL_ERROR:
924     return "HIPSOLVER_STATUS_INTERNAL_ERROR";
925   case HIPSOLVER_STATUS_NOT_SUPPORTED:
926     return "HIPSOLVER_STATUS_NOT_SUPPORTED ";
927   case HIPSOLVER_STATUS_ARCH_MISMATCH:
928     return "HIPSOLVER_STATUS_ARCH_MISMATCH";
929   case HIPSOLVER_STATUS_HANDLE_IS_NULLPTR:
930     return "HIPSOLVER_STATUS_HANDLE_IS_NULLPTR";
931   case HIPSOLVER_STATUS_INVALID_ENUM:
932     return "HIPSOLVER_STATUS_INVALID_ENUM";
933   case HIPSOLVER_STATUS_UNKNOWN:
934   default:
935     return "HIPSOLVER_STATUS_UNKNOWN";
936   }
937 }
938 #endif
939 
940 /*@C
941   PetscMPIErrorString - Given an MPI error code returns the `MPI_Error_string()` appropriately
942   formatted for displaying with the PETSc error handlers.
943 
944   Not Collective, No Fortran Support
945 
946   Input Parameters:
947 + err  - the MPI error code
948 - slen - length of `string`, should be at least as large as `MPI_MAX_ERROR_STRING`
949 
950   Output Parameter:
951 . string - the MPI error message
952 
953   Level: developer
954 
955   Note:
956   Does not return an error code or do error handling because it may be called from inside an error handler
957 
958 .seealso: `PetscErrorCode` `PetscErrorMessage()`
959 @*/
960 void PetscMPIErrorString(PetscMPIInt err, size_t slen, char *string)
961 {
962   char        errorstring[MPI_MAX_ERROR_STRING];
963   PetscMPIInt len;
964   size_t      j = 0;
965 
966   MPI_Error_string(err, (char *)errorstring, &len);
967   for (PetscMPIInt i = 0; i < len && j < slen - 2; i++) {
968     string[j++] = errorstring[i];
969     if (errorstring[i] == '\n') {
970       for (PetscMPIInt k = 0; k < 16 && j < slen - 2; k++) string[j++] = ' ';
971     }
972   }
973   string[j] = 0;
974 }
975