xref: /petsc/src/sys/error/err.c (revision dc97da86830806a16cfaacfab740baa2e54c8135)
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