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