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