xref: /petsc/src/sys/error/err.c (revision 57b47c28e1f7534921d70b049522292aa9665180)
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   PetscIntViewNumColumns - Prints an array of integers; useful for debugging.
432 
433   Collective
434 
435   Input Parameters:
436 + N      - number of integers in array
437 . Ncol   - number of integers to print per row
438 . idx    - array of integers
439 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
440 
441   Level: intermediate
442 
443   Note:
444   This may be called from within the debugger, passing 0 as the viewer
445 
446   Developer Note:
447   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
448 
449 .seealso: `PetscViewer`, `PetscIntView()`, `PetscRealView()`
450 @*/
451 PetscErrorCode PetscIntViewNumColumns(PetscInt N, PetscInt Ncol, const PetscInt idx[], PetscViewer viewer)
452 {
453   PetscMPIInt rank, size;
454   PetscInt    j, i, n = N / Ncol, p = N % Ncol;
455   PetscBool   iascii, isbinary;
456   MPI_Comm    comm;
457 
458   PetscFunctionBegin;
459   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
460   if (N) PetscAssertPointer(idx, 3);
461   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
462   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
463   PetscCallMPI(MPI_Comm_size(comm, &size));
464   PetscCallMPI(MPI_Comm_rank(comm, &rank));
465 
466   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
467   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
468   if (iascii) {
469     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
470     for (i = 0; i < n; i++) {
471       if (size > 1) {
472         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":", rank, Ncol * i));
473       } else {
474         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":", Ncol * i));
475       }
476       for (j = 0; j < Ncol; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, idx[i * Ncol + j]));
477       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
478     }
479     if (p) {
480       if (size > 1) {
481         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":", rank, Ncol * n));
482       } else {
483         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":", Ncol * n));
484       }
485       for (i = 0; i < p; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, idx[Ncol * n + i]));
486       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
487     }
488     PetscCall(PetscViewerFlush(viewer));
489     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
490   } else if (isbinary) {
491     PetscMPIInt *sizes, Ntotal, *displs, NN;
492     PetscInt    *array;
493 
494     PetscCall(PetscMPIIntCast(N, &NN));
495 
496     if (size > 1) {
497       if (rank) {
498         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
499         PetscCallMPI(MPI_Gatherv(idx, NN, MPIU_INT, NULL, NULL, NULL, MPIU_INT, 0, comm));
500       } else {
501         PetscCall(PetscMalloc1(size, &sizes));
502         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
503         Ntotal = sizes[0];
504         PetscCall(PetscMalloc1(size, &displs));
505         displs[0] = 0;
506         for (i = 1; i < size; i++) {
507           Ntotal += sizes[i];
508           displs[i] = displs[i - 1] + sizes[i - 1];
509         }
510         PetscCall(PetscMalloc1(Ntotal, &array));
511         PetscCallMPI(MPI_Gatherv(idx, NN, MPIU_INT, array, sizes, displs, MPIU_INT, 0, comm));
512         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_INT));
513         PetscCall(PetscFree(sizes));
514         PetscCall(PetscFree(displs));
515         PetscCall(PetscFree(array));
516       }
517     } else {
518       PetscCall(PetscViewerBinaryWrite(viewer, idx, N, PETSC_INT));
519     }
520   } else {
521     const char *tname;
522     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
523     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
524   }
525   PetscFunctionReturn(PETSC_SUCCESS);
526 }
527 
528 /*@
529   PetscRealViewNumColumns - Prints an array of doubles; useful for debugging.
530 
531   Collective
532 
533   Input Parameters:
534 + N      - number of `PetscReal` in array
535 . Ncol   - number of `PetscReal` to print per row
536 . idx    - array of `PetscReal`
537 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
538 
539   Level: intermediate
540 
541   Note:
542   This may be called from within the debugger, passing 0 as the viewer
543 
544   Developer Note:
545   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
546 
547 .seealso: `PetscViewer`, `PetscRealView()`, `PetscIntView()`
548 @*/
549 PetscErrorCode PetscRealViewNumColumns(PetscInt N, PetscInt Ncol, const PetscReal idx[], PetscViewer viewer)
550 {
551   PetscMPIInt rank, size;
552   PetscInt    j, i, n = N / Ncol, p = N % Ncol;
553   PetscBool   iascii, isbinary;
554   MPI_Comm    comm;
555 
556   PetscFunctionBegin;
557   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
558   if (N) PetscAssertPointer(idx, 3);
559   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
560   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
561   PetscCallMPI(MPI_Comm_size(comm, &size));
562   PetscCallMPI(MPI_Comm_rank(comm, &rank));
563 
564   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
565   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
566   if (iascii) {
567     PetscInt tab;
568 
569     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
570     PetscCall(PetscViewerASCIIGetTab(viewer, &tab));
571     for (i = 0; i < n; i++) {
572       PetscCall(PetscViewerASCIISetTab(viewer, tab));
573       if (size > 1) {
574         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, Ncol * i));
575       } else {
576         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", Ncol * i));
577       }
578       PetscCall(PetscViewerASCIISetTab(viewer, 0));
579       for (j = 0; j < Ncol; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[i * Ncol + j]));
580       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
581     }
582     if (p) {
583       PetscCall(PetscViewerASCIISetTab(viewer, tab));
584       if (size > 1) {
585         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, Ncol * n));
586       } else {
587         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", Ncol * n));
588       }
589       PetscCall(PetscViewerASCIISetTab(viewer, 0));
590       for (i = 0; i < p; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[Ncol * n + i]));
591       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
592     }
593     PetscCall(PetscViewerFlush(viewer));
594     PetscCall(PetscViewerASCIISetTab(viewer, tab));
595     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
596   } else if (isbinary) {
597     PetscMPIInt *sizes, *displs, Ntotal, NN;
598     PetscReal   *array;
599 
600     PetscCall(PetscMPIIntCast(N, &NN));
601 
602     if (size > 1) {
603       if (rank) {
604         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
605         PetscCallMPI(MPI_Gatherv(idx, NN, MPIU_REAL, NULL, NULL, NULL, MPIU_REAL, 0, comm));
606       } else {
607         PetscCall(PetscMalloc1(size, &sizes));
608         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
609         Ntotal = sizes[0];
610         PetscCall(PetscMalloc1(size, &displs));
611         displs[0] = 0;
612         for (i = 1; i < size; i++) {
613           Ntotal += sizes[i];
614           displs[i] = displs[i - 1] + sizes[i - 1];
615         }
616         PetscCall(PetscMalloc1(Ntotal, &array));
617         PetscCallMPI(MPI_Gatherv(idx, NN, MPIU_REAL, array, sizes, displs, MPIU_REAL, 0, comm));
618         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_REAL));
619         PetscCall(PetscFree(sizes));
620         PetscCall(PetscFree(displs));
621         PetscCall(PetscFree(array));
622       }
623     } else {
624       PetscCall(PetscViewerBinaryWrite(viewer, (void *)idx, N, PETSC_REAL));
625     }
626   } else {
627     const char *tname;
628     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
629     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
630   }
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633 
634 /*@
635   PetscScalarViewNumColumns - Prints an array of doubles; useful for debugging.
636 
637   Collective
638 
639   Input Parameters:
640 + N      - number of `PetscScalar` in array
641 . Ncol   - number of `PetscScalar` to print per row
642 . idx    - array of `PetscScalar`
643 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
644 
645   Level: intermediate
646 
647   Note:
648   This may be called from within the debugger, passing 0 as the viewer
649 
650   Developer Note:
651   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
652 
653 .seealso: `PetscViewer`, `PetscRealView()`, `PetscScalarView()`, `PetscIntView()`
654 @*/
655 PetscErrorCode PetscScalarViewNumColumns(PetscInt N, PetscInt Ncol, const PetscScalar idx[], PetscViewer viewer)
656 {
657   PetscMPIInt rank, size;
658   PetscInt    j, i, n = N / Ncol, p = N % Ncol;
659   PetscBool   iascii, isbinary;
660   MPI_Comm    comm;
661 
662   PetscFunctionBegin;
663   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
664   if (N) PetscAssertPointer(idx, 3);
665   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4);
666   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
667   PetscCallMPI(MPI_Comm_size(comm, &size));
668   PetscCallMPI(MPI_Comm_rank(comm, &rank));
669 
670   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
671   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
672   if (iascii) {
673     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
674     for (i = 0; i < n; i++) {
675       if (size > 1) {
676         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, Ncol * i));
677       } else {
678         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", Ncol * i));
679       }
680       for (j = 0; j < Ncol; j++) {
681 #if defined(PETSC_USE_COMPLEX)
682         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%12.4e,%12.4e)", (double)PetscRealPart(idx[i * Ncol + j]), (double)PetscImaginaryPart(idx[i * Ncol + j])));
683 #else
684         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[i * Ncol + j]));
685 #endif
686       }
687       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
688     }
689     if (p) {
690       if (size > 1) {
691         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, Ncol * n));
692       } else {
693         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", Ncol * n));
694       }
695       for (i = 0; i < p; i++) {
696 #if defined(PETSC_USE_COMPLEX)
697         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%12.4e,%12.4e)", (double)PetscRealPart(idx[n * Ncol + i]), (double)PetscImaginaryPart(idx[n * Ncol + i])));
698 #else
699         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[Ncol * n + i]));
700 #endif
701       }
702       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
703     }
704     PetscCall(PetscViewerFlush(viewer));
705     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
706   } else if (isbinary) {
707     PetscMPIInt *sizes, Ntotal, *displs, NN;
708     PetscScalar *array;
709 
710     PetscCall(PetscMPIIntCast(N, &NN));
711 
712     if (size > 1) {
713       if (rank) {
714         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
715         PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_SCALAR, NULL, NULL, NULL, MPIU_SCALAR, 0, comm));
716       } else {
717         PetscCall(PetscMalloc1(size, &sizes));
718         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
719         Ntotal = sizes[0];
720         PetscCall(PetscMalloc1(size, &displs));
721         displs[0] = 0;
722         for (i = 1; i < size; i++) {
723           Ntotal += sizes[i];
724           displs[i] = displs[i - 1] + sizes[i - 1];
725         }
726         PetscCall(PetscMalloc1(Ntotal, &array));
727         PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_SCALAR, array, sizes, displs, MPIU_SCALAR, 0, comm));
728         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_SCALAR));
729         PetscCall(PetscFree(sizes));
730         PetscCall(PetscFree(displs));
731         PetscCall(PetscFree(array));
732       }
733     } else {
734       PetscCall(PetscViewerBinaryWrite(viewer, (void *)idx, N, PETSC_SCALAR));
735     }
736   } else {
737     const char *tname;
738     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
739     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
740   }
741   PetscFunctionReturn(PETSC_SUCCESS);
742 }
743 
744 /*@
745   PetscIntView - Prints an array of integers; useful for debugging.
746 
747   Collective
748 
749   Input Parameters:
750 + N      - number of integers in array
751 . idx    - array of integers
752 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
753 
754   Level: intermediate
755 
756   Note:
757   This may be called from within the debugger, passing 0 as the viewer
758 
759   Same as `PetscIntViewNumColumns()` with 20 values per row
760 
761   Developer Note:
762   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
763 
764 .seealso: `PetscViewer`, `PetscIntViewNumColumns()`, `PetscRealView()`
765 @*/
766 PetscErrorCode PetscIntView(PetscInt N, const PetscInt idx[], PetscViewer viewer)
767 {
768   PetscFunctionBegin;
769   PetscCall(PetscIntViewNumColumns(N, 20, idx, viewer));
770   PetscFunctionReturn(PETSC_SUCCESS);
771 }
772 
773 /*@
774   PetscRealView - Prints an array of doubles; useful for debugging.
775 
776   Collective
777 
778   Input Parameters:
779 + N      - number of `PetscReal` in array
780 . idx    - array of `PetscReal`
781 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
782 
783   Level: intermediate
784 
785   Note:
786   This may be called from within the debugger, passing 0 as the viewer
787 
788   Same as `PetscRealViewNumColumns()` with 5 values per row
789 
790   Developer Note:
791   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
792 
793 .seealso: `PetscViewer`, `PetscIntView()`
794 @*/
795 PetscErrorCode PetscRealView(PetscInt N, const PetscReal idx[], PetscViewer viewer)
796 {
797   PetscFunctionBegin;
798   PetscCall(PetscRealViewNumColumns(N, 5, idx, viewer));
799   PetscFunctionReturn(PETSC_SUCCESS);
800 }
801 
802 /*@
803   PetscScalarView - Prints an array of `PetscScalar`; useful for debugging.
804 
805   Collective
806 
807   Input Parameters:
808 + N      - number of scalars in array
809 . idx    - array of scalars
810 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
811 
812   Level: intermediate
813 
814   Note:
815   This may be called from within the debugger, passing 0 as the viewer
816 
817   Same as `PetscScalarViewNumColumns()` with 3 values per row
818 
819   Developer Note:
820   `idx` cannot be const because may be passed to binary viewer where byte swapping may be done
821 
822 .seealso: `PetscViewer`, `PetscIntView()`, `PetscRealView()`
823 @*/
824 PetscErrorCode PetscScalarView(PetscInt N, const PetscScalar idx[], PetscViewer viewer)
825 {
826   PetscFunctionBegin;
827   PetscCall(PetscScalarViewNumColumns(N, 3, idx, viewer));
828   PetscFunctionReturn(PETSC_SUCCESS);
829 }
830 
831 #if defined(PETSC_HAVE_CUDA)
832   #include <petscdevice_cuda.h>
833 PETSC_EXTERN const char *PetscCUBLASGetErrorName(cublasStatus_t status)
834 {
835   switch (status) {
836   #if (CUDART_VERSION >= 8000) /* At least CUDA 8.0 of Sep. 2016 had these */
837   case CUBLAS_STATUS_SUCCESS:
838     return "CUBLAS_STATUS_SUCCESS";
839   case CUBLAS_STATUS_NOT_INITIALIZED:
840     return "CUBLAS_STATUS_NOT_INITIALIZED";
841   case CUBLAS_STATUS_ALLOC_FAILED:
842     return "CUBLAS_STATUS_ALLOC_FAILED";
843   case CUBLAS_STATUS_INVALID_VALUE:
844     return "CUBLAS_STATUS_INVALID_VALUE";
845   case CUBLAS_STATUS_ARCH_MISMATCH:
846     return "CUBLAS_STATUS_ARCH_MISMATCH";
847   case CUBLAS_STATUS_MAPPING_ERROR:
848     return "CUBLAS_STATUS_MAPPING_ERROR";
849   case CUBLAS_STATUS_EXECUTION_FAILED:
850     return "CUBLAS_STATUS_EXECUTION_FAILED";
851   case CUBLAS_STATUS_INTERNAL_ERROR:
852     return "CUBLAS_STATUS_INTERNAL_ERROR";
853   case CUBLAS_STATUS_NOT_SUPPORTED:
854     return "CUBLAS_STATUS_NOT_SUPPORTED";
855   case CUBLAS_STATUS_LICENSE_ERROR:
856     return "CUBLAS_STATUS_LICENSE_ERROR";
857   #endif
858   default:
859     return "unknown error";
860   }
861 }
862 PETSC_EXTERN const char *PetscCUSolverGetErrorName(cusolverStatus_t status)
863 {
864   switch (status) {
865   #if (CUDART_VERSION >= 8000) /* At least CUDA 8.0 of Sep. 2016 had these */
866   case CUSOLVER_STATUS_SUCCESS:
867     return "CUSOLVER_STATUS_SUCCESS";
868   case CUSOLVER_STATUS_NOT_INITIALIZED:
869     return "CUSOLVER_STATUS_NOT_INITIALIZED";
870   case CUSOLVER_STATUS_INVALID_VALUE:
871     return "CUSOLVER_STATUS_INVALID_VALUE";
872   case CUSOLVER_STATUS_ARCH_MISMATCH:
873     return "CUSOLVER_STATUS_ARCH_MISMATCH";
874   case CUSOLVER_STATUS_INTERNAL_ERROR:
875     return "CUSOLVER_STATUS_INTERNAL_ERROR";
876     #if (CUDART_VERSION >= 9000) /* CUDA 9.0 had these defined on June 2021 */
877   case CUSOLVER_STATUS_ALLOC_FAILED:
878     return "CUSOLVER_STATUS_ALLOC_FAILED";
879   case CUSOLVER_STATUS_MAPPING_ERROR:
880     return "CUSOLVER_STATUS_MAPPING_ERROR";
881   case CUSOLVER_STATUS_EXECUTION_FAILED:
882     return "CUSOLVER_STATUS_EXECUTION_FAILED";
883   case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
884     return "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED";
885   case CUSOLVER_STATUS_NOT_SUPPORTED:
886     return "CUSOLVER_STATUS_NOT_SUPPORTED ";
887   case CUSOLVER_STATUS_ZERO_PIVOT:
888     return "CUSOLVER_STATUS_ZERO_PIVOT";
889   case CUSOLVER_STATUS_INVALID_LICENSE:
890     return "CUSOLVER_STATUS_INVALID_LICENSE";
891     #endif
892   #endif
893   default:
894     return "unknown error";
895   }
896 }
897 PETSC_EXTERN const char *PetscCUFFTGetErrorName(cufftResult result)
898 {
899   switch (result) {
900   case CUFFT_SUCCESS:
901     return "CUFFT_SUCCESS";
902   case CUFFT_INVALID_PLAN:
903     return "CUFFT_INVALID_PLAN";
904   case CUFFT_ALLOC_FAILED:
905     return "CUFFT_ALLOC_FAILED";
906   case CUFFT_INVALID_TYPE:
907     return "CUFFT_INVALID_TYPE";
908   case CUFFT_INVALID_VALUE:
909     return "CUFFT_INVALID_VALUE";
910   case CUFFT_INTERNAL_ERROR:
911     return "CUFFT_INTERNAL_ERROR";
912   case CUFFT_EXEC_FAILED:
913     return "CUFFT_EXEC_FAILED";
914   case CUFFT_SETUP_FAILED:
915     return "CUFFT_SETUP_FAILED";
916   case CUFFT_INVALID_SIZE:
917     return "CUFFT_INVALID_SIZE";
918   case CUFFT_UNALIGNED_DATA:
919     return "CUFFT_UNALIGNED_DATA";
920   case CUFFT_INCOMPLETE_PARAMETER_LIST:
921     return "CUFFT_INCOMPLETE_PARAMETER_LIST";
922   case CUFFT_INVALID_DEVICE:
923     return "CUFFT_INVALID_DEVICE";
924   case CUFFT_PARSE_ERROR:
925     return "CUFFT_PARSE_ERROR";
926   case CUFFT_NO_WORKSPACE:
927     return "CUFFT_NO_WORKSPACE";
928   case CUFFT_NOT_IMPLEMENTED:
929     return "CUFFT_NOT_IMPLEMENTED";
930   case CUFFT_LICENSE_ERROR:
931     return "CUFFT_LICENSE_ERROR";
932   case CUFFT_NOT_SUPPORTED:
933     return "CUFFT_NOT_SUPPORTED";
934   default:
935     return "unknown error";
936   }
937 }
938 #endif
939 
940 #if defined(PETSC_HAVE_HIP)
941   #include <petscdevice_hip.h>
942 PETSC_EXTERN const char *PetscHIPBLASGetErrorName(hipblasStatus_t status)
943 {
944   switch (status) {
945   case HIPBLAS_STATUS_SUCCESS:
946     return "HIPBLAS_STATUS_SUCCESS";
947   case HIPBLAS_STATUS_NOT_INITIALIZED:
948     return "HIPBLAS_STATUS_NOT_INITIALIZED";
949   case HIPBLAS_STATUS_ALLOC_FAILED:
950     return "HIPBLAS_STATUS_ALLOC_FAILED";
951   case HIPBLAS_STATUS_INVALID_VALUE:
952     return "HIPBLAS_STATUS_INVALID_VALUE";
953   case HIPBLAS_STATUS_ARCH_MISMATCH:
954     return "HIPBLAS_STATUS_ARCH_MISMATCH";
955   case HIPBLAS_STATUS_MAPPING_ERROR:
956     return "HIPBLAS_STATUS_MAPPING_ERROR";
957   case HIPBLAS_STATUS_EXECUTION_FAILED:
958     return "HIPBLAS_STATUS_EXECUTION_FAILED";
959   case HIPBLAS_STATUS_INTERNAL_ERROR:
960     return "HIPBLAS_STATUS_INTERNAL_ERROR";
961   case HIPBLAS_STATUS_NOT_SUPPORTED:
962     return "HIPBLAS_STATUS_NOT_SUPPORTED";
963   default:
964     return "unknown error";
965   }
966 }
967 PETSC_EXTERN const char *PetscHIPSPARSEGetErrorName(hipsparseStatus_t status)
968 {
969   switch (status) {
970   case HIPSPARSE_STATUS_SUCCESS:
971     return "HIPSPARSE_STATUS_SUCCESS";
972   case HIPSPARSE_STATUS_NOT_INITIALIZED:
973     return "HIPSPARSE_STATUS_NOT_INITIALIZED";
974   case HIPSPARSE_STATUS_ALLOC_FAILED:
975     return "HIPSPARSE_STATUS_ALLOC_FAILED";
976   case HIPSPARSE_STATUS_INVALID_VALUE:
977     return "HIPSPARSE_STATUS_INVALID_VALUE";
978   case HIPSPARSE_STATUS_ARCH_MISMATCH:
979     return "HIPSPARSE_STATUS_ARCH_MISMATCH";
980   case HIPSPARSE_STATUS_MAPPING_ERROR:
981     return "HIPSPARSE_STATUS_MAPPING_ERROR";
982   case HIPSPARSE_STATUS_EXECUTION_FAILED:
983     return "HIPSPARSE_STATUS_EXECUTION_FAILED";
984   case HIPSPARSE_STATUS_INTERNAL_ERROR:
985     return "HIPSPARSE_STATUS_INTERNAL_ERROR";
986   case HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
987     return "HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED";
988   case HIPSPARSE_STATUS_ZERO_PIVOT:
989     return "HIPSPARSE_STATUS_ZERO_PIVOT";
990   case HIPSPARSE_STATUS_NOT_SUPPORTED:
991     return "HIPSPARSE_STATUS_NOT_SUPPORTED";
992   case HIPSPARSE_STATUS_INSUFFICIENT_RESOURCES:
993     return "HIPSPARSE_STATUS_INSUFFICIENT_RESOURCES";
994   default:
995     return "unknown error";
996   }
997 }
998 PETSC_EXTERN const char *PetscHIPSolverGetErrorName(hipsolverStatus_t status)
999 {
1000   switch (status) {
1001   case HIPSOLVER_STATUS_SUCCESS:
1002     return "HIPSOLVER_STATUS_SUCCESS";
1003   case HIPSOLVER_STATUS_NOT_INITIALIZED:
1004     return "HIPSOLVER_STATUS_NOT_INITIALIZED";
1005   case HIPSOLVER_STATUS_ALLOC_FAILED:
1006     return "HIPSOLVER_STATUS_ALLOC_FAILED";
1007   case HIPSOLVER_STATUS_MAPPING_ERROR:
1008     return "HIPSOLVER_STATUS_MAPPING_ERROR";
1009   case HIPSOLVER_STATUS_INVALID_VALUE:
1010     return "HIPSOLVER_STATUS_INVALID_VALUE";
1011   case HIPSOLVER_STATUS_EXECUTION_FAILED:
1012     return "HIPSOLVER_STATUS_EXECUTION_FAILED";
1013   case HIPSOLVER_STATUS_INTERNAL_ERROR:
1014     return "HIPSOLVER_STATUS_INTERNAL_ERROR";
1015   case HIPSOLVER_STATUS_NOT_SUPPORTED:
1016     return "HIPSOLVER_STATUS_NOT_SUPPORTED ";
1017   case HIPSOLVER_STATUS_ARCH_MISMATCH:
1018     return "HIPSOLVER_STATUS_ARCH_MISMATCH";
1019   case HIPSOLVER_STATUS_HANDLE_IS_NULLPTR:
1020     return "HIPSOLVER_STATUS_HANDLE_IS_NULLPTR";
1021   case HIPSOLVER_STATUS_INVALID_ENUM:
1022     return "HIPSOLVER_STATUS_INVALID_ENUM";
1023   case HIPSOLVER_STATUS_UNKNOWN:
1024   default:
1025     return "HIPSOLVER_STATUS_UNKNOWN";
1026   }
1027 }
1028 #endif
1029 
1030 /*@C
1031   PetscMPIErrorString - Given an MPI error code returns the `MPI_Error_string()` appropriately
1032   formatted for displaying with the PETSc error handlers.
1033 
1034   Not Collective, No Fortran Support
1035 
1036   Input Parameters:
1037 + err  - the MPI error code
1038 - slen - length of `string`, should be at least as large as `MPI_MAX_ERROR_STRING`
1039 
1040   Output Parameter:
1041 . string - the MPI error message
1042 
1043   Level: developer
1044 
1045   Note:
1046   Does not return an error code or do error handling because it may be called from inside an error handler
1047 
1048 .seealso: `PetscErrorCode` `PetscErrorMessage()`
1049 @*/
1050 void PetscMPIErrorString(PetscMPIInt err, size_t slen, char *string)
1051 {
1052   char        errorstring[MPI_MAX_ERROR_STRING];
1053   PetscMPIInt len;
1054   size_t      j = 0;
1055 
1056   MPI_Error_string(err, (char *)errorstring, &len);
1057   for (PetscMPIInt i = 0; i < len && j < slen - 2; i++) {
1058     string[j++] = errorstring[i];
1059     if (errorstring[i] == '\n') {
1060       for (PetscMPIInt k = 0; k < 16 && j < slen - 2; k++) string[j++] = ' ';
1061     }
1062   }
1063   string[j] = 0;
1064 }
1065