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