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