xref: /petsc/include/petsc/private/kspimpl.h (revision 69eda9da2cab3444df2acd68fbbc2fdf1947414f)
1 
2 #ifndef _KSPIMPL_H
3   #define _KSPIMPL_H
4 
5   #include <petscksp.h>
6   #include <petscds.h>
7   #include <petsc/private/petscimpl.h>
8 
9 /* SUBMANSEC = KSP */
10 
11 PETSC_EXTERN PetscBool      KSPRegisterAllCalled;
12 PETSC_EXTERN PetscBool      KSPMonitorRegisterAllCalled;
13 PETSC_EXTERN PetscErrorCode KSPRegisterAll(void);
14 PETSC_EXTERN PetscErrorCode KSPMonitorRegisterAll(void);
15 PETSC_EXTERN PetscErrorCode KSPGuessRegisterAll(void);
16 PETSC_EXTERN PetscErrorCode KSPMatRegisterAll(void);
17 
18 typedef struct _KSPOps *KSPOps;
19 
20 struct _KSPOps {
21   PetscErrorCode (*buildsolution)(KSP, Vec, Vec *);      /* Returns a pointer to the solution, or
22                                                           calculates the solution in a
23                                                           user-provided area. */
24   PetscErrorCode (*buildresidual)(KSP, Vec, Vec, Vec *); /* Returns a pointer to the residual, or
25                                                           calculates the residual in a
26                                                           user-provided area.  */
27   PetscErrorCode (*solve)(KSP);                          /* actual solver */
28   PetscErrorCode (*matsolve)(KSP, Mat, Mat);             /* multiple dense RHS solver */
29   PetscErrorCode (*setup)(KSP);
30   PetscErrorCode (*setfromoptions)(KSP, PetscOptionItems *);
31   PetscErrorCode (*publishoptions)(KSP);
32   PetscErrorCode (*computeextremesingularvalues)(KSP, PetscReal *, PetscReal *);
33   PetscErrorCode (*computeeigenvalues)(KSP, PetscInt, PetscReal *, PetscReal *, PetscInt *);
34   PetscErrorCode (*computeritz)(KSP, PetscBool, PetscBool, PetscInt *, Vec[], PetscReal *, PetscReal *);
35   PetscErrorCode (*destroy)(KSP);
36   PetscErrorCode (*view)(KSP, PetscViewer);
37   PetscErrorCode (*reset)(KSP);
38   PetscErrorCode (*load)(KSP, PetscViewer);
39 };
40 
41 typedef struct _KSPGuessOps *KSPGuessOps;
42 
43 struct _KSPGuessOps {
44   PetscErrorCode (*formguess)(KSPGuess, Vec, Vec); /* Form initial guess */
45   PetscErrorCode (*update)(KSPGuess, Vec, Vec);    /* Update database */
46   PetscErrorCode (*setfromoptions)(KSPGuess);
47   PetscErrorCode (*settolerance)(KSPGuess, PetscReal);
48   PetscErrorCode (*setup)(KSPGuess);
49   PetscErrorCode (*destroy)(KSPGuess);
50   PetscErrorCode (*view)(KSPGuess, PetscViewer);
51   PetscErrorCode (*reset)(KSPGuess);
52 };
53 
54 /*
55    Defines the KSPGuess data structure.
56 */
57 struct _p_KSPGuess {
58   PETSCHEADER(struct _KSPGuessOps);
59   KSP              ksp;       /* the parent KSP */
60   Mat              A;         /* the current linear operator */
61   PetscObjectState omatstate; /* previous linear operator state */
62   void            *data;      /* pointer to the specific implementation */
63 };
64 
65 PETSC_EXTERN PetscErrorCode KSPGuessCreate_Fischer(KSPGuess);
66 PETSC_EXTERN PetscErrorCode KSPGuessCreate_POD(KSPGuess);
67 
68   /*
69      Maximum number of monitors you can run with a single KSP
70 */
71   #define MAXKSPMONITORS    5
72   #define MAXKSPREASONVIEWS 5
73 typedef enum {
74   KSP_SETUP_NEW,
75   KSP_SETUP_NEWMATRIX,
76   KSP_SETUP_NEWRHS
77 } KSPSetUpStage;
78 
79 /*
80    Defines the KSP data structure.
81 */
82 struct _p_KSP {
83   PETSCHEADER(struct _KSPOps);
84   DM        dm;
85   PetscBool dmAuto;   /* DM was created automatically by KSP */
86   PetscBool dmActive; /* KSP should use DM for computing operators */
87   /*------------------------- User parameters--------------------------*/
88   PetscInt  max_it; /* maximum number of iterations */
89   KSPGuess  guess;
90   PetscBool guess_zero,                                  /* flag for whether initial guess is 0 */
91     calc_sings,                                          /* calculate extreme Singular Values */
92     calc_ritz,                                           /* calculate (harmonic) Ritz pairs */
93     guess_knoll;                                         /* use initial guess of PCApply(ksp->B,b */
94   PCSide    pc_side;                                     /* flag for left, right, or symmetric preconditioning */
95   PetscInt  normsupporttable[KSP_NORM_MAX][PC_SIDE_MAX]; /* Table of supported norms and pc_side, see KSPSetSupportedNorm() */
96   PetscReal rtol,                                        /* relative tolerance */
97     abstol,                                              /* absolute tolerance */
98     ttol,                                                /* (not set by user)  */
99     divtol;                                              /* divergence tolerance */
100   PetscReal          rnorm0;                             /* initial residual norm (used for divergence testing) */
101   PetscReal          rnorm;                              /* current residual norm */
102   KSPConvergedReason reason;
103   PetscBool          errorifnotconverged; /* create an error if the KSPSolve() does not converge */
104 
105   Vec        vec_sol, vec_rhs; /* pointer to where user has stashed
106                                       the solution and rhs, these are
107                                       never touched by the code, only
108                                       passed back to the user */
109   PetscReal *res_hist;         /* If !0 stores residual each at iteration */
110   PetscReal *res_hist_alloc;   /* If !0 means user did not provide buffer, needs deallocation */
111   size_t     res_hist_len;     /* current size of residual history array */
112   size_t     res_hist_max;     /* actual amount of storage in residual history */
113   PetscBool  res_hist_reset;   /* reset history to length zero for each new solve */
114   PetscReal *err_hist;         /* If !0 stores error at each iteration */
115   PetscReal *err_hist_alloc;   /* If !0 means user did not provide buffer, needs deallocation */
116   size_t     err_hist_len;     /* current size of error history array */
117   size_t     err_hist_max;     /* actual amount of storage in error history */
118   PetscBool  err_hist_reset;   /* reset history to length zero for each new solve */
119 
120   PetscInt  chknorm; /* only compute/check norm if iterations is great than this */
121   PetscBool lagnorm; /* Lag the residual norm calculation so that it is computed as part of the
122                                         MPI_Allreduce() for computing the inner products for the next iteration. */
123 
124   PetscInt nmax; /* maximum number of right-hand sides to be handled simultaneously */
125 
126   /* --------User (or default) routines (most return -1 on error) --------*/
127   PetscErrorCode (*monitor[MAXKSPMONITORS])(KSP, PetscInt, PetscReal, void *); /* returns control to user after */
128   PetscErrorCode (*monitordestroy[MAXKSPMONITORS])(void **);                   /* */
129   void     *monitorcontext[MAXKSPMONITORS];                                    /* residual calculation, allows user */
130   PetscInt  numbermonitors;                                                    /* to, for instance, print residual norm, etc. */
131   PetscBool pauseFinal;                                                        /* Pause all drawing monitor at the final iterate */
132 
133   PetscErrorCode (*reasonview[MAXKSPREASONVIEWS])(KSP, void *);    /* KSP converged reason view */
134   PetscErrorCode (*reasonviewdestroy[MAXKSPREASONVIEWS])(void **); /* Optional destroy routine */
135   void    *reasonviewcontext[MAXKSPREASONVIEWS];                   /* User context */
136   PetscInt numberreasonviews;                                      /* Number if reason viewers */
137 
138   PetscErrorCode (*converged)(KSP, PetscInt, PetscReal, KSPConvergedReason *, void *);
139   PetscErrorCode (*convergeddestroy)(void *);
140   void *cnvP;
141 
142   void *user; /* optional user-defined context */
143 
144   PC pc;
145 
146   void *data; /* holder for misc stuff associated
147                                    with a particular iterative solver */
148 
149   PetscBool         view, viewPre, viewRate, viewMat, viewPMat, viewRhs, viewSol, viewMatExp, viewEV, viewSV, viewEVExp, viewFinalRes, viewPOpExp, viewDScale;
150   PetscViewer       viewer, viewerPre, viewerRate, viewerMat, viewerPMat, viewerRhs, viewerSol, viewerMatExp, viewerEV, viewerSV, viewerEVExp, viewerFinalRes, viewerPOpExp, viewerDScale;
151   PetscViewerFormat format, formatPre, formatRate, formatMat, formatPMat, formatRhs, formatSol, formatMatExp, formatEV, formatSV, formatEVExp, formatFinalRes, formatPOpExp, formatDScale;
152 
153   /* ----------------Default work-area management -------------------- */
154   PetscInt nwork;
155   Vec     *work;
156 
157   KSPSetUpStage setupstage;
158   PetscBool     setupnewmatrix; /* true if we need to call ksp->ops->setup with KSP_SETUP_NEWMATRIX */
159 
160   PetscInt its;      /* number of iterations so far computed in THIS linear solve*/
161   PetscInt totalits; /* number of iterations used by this KSP object since it was created */
162 
163   PetscBool transpose_solve; /* solve transpose system instead */
164   struct {
165     Mat       AT, BT;
166     PetscBool use_explicittranspose; /* transpose the system explicitly in KSPSolveTranspose */
167     PetscBool reuse_transpose;       /* reuse the previous transposed system */
168   } transpose;
169 
170   KSPNormType normtype; /* type of norm used for convergence tests */
171 
172   PCSide      pc_side_set;  /* PC type set explicitly by user */
173   KSPNormType normtype_set; /* Norm type set explicitly by user */
174 
175   /*   Allow diagonally scaling the matrix before computing the preconditioner or using
176        the Krylov method. Note this is NOT just Jacobi preconditioning */
177 
178   PetscBool dscale;     /* diagonal scale system; used with KSPSetDiagonalScale() */
179   PetscBool dscalefix;  /* unscale system after solve */
180   PetscBool dscalefix2; /* system has been unscaled */
181   Vec       diagonal;   /* 1/sqrt(diag of matrix) */
182   Vec       truediagonal;
183 
184   PetscInt  setfromoptionscalled;
185   PetscBool skippcsetfromoptions; /* if set then KSPSetFromOptions() does not call PCSetFromOptions() */
186 
187   PetscViewer eigviewer; /* Viewer where computed eigenvalues are displayed */
188 
189   PetscErrorCode (*presolve)(KSP, Vec, Vec, void *);
190   PetscErrorCode (*postsolve)(KSP, Vec, Vec, void *);
191   void *prectx, *postctx;
192 };
193 
194 typedef struct { /* dummy data structure used in KSPMonitorDynamicTolerance() */
195   PetscReal coef;
196   PetscReal bnrm;
197 } KSPDynTolCtx;
198 
199 typedef struct {
200   PetscBool initialrtol;    /* default relative residual decrease is computed from initial residual, not rhs */
201   PetscBool mininitialrtol; /* default relative residual decrease is computed from min of initial residual and rhs */
202   PetscBool convmaxits;     /* if true, the convergence test returns KSP_CONVERGED_ITS if the maximum number of iterations is reached */
203   Vec       work;
204 } KSPConvergedDefaultCtx;
205 
206 static inline PetscErrorCode KSPLogResidualHistory(KSP ksp, PetscReal norm)
207 {
208   PetscFunctionBegin;
209   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
210   if (ksp->res_hist && ksp->res_hist_max > ksp->res_hist_len) ksp->res_hist[ksp->res_hist_len++] = norm;
211   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
212   PetscFunctionReturn(0);
213 }
214 
215 static inline PetscErrorCode KSPLogErrorHistory(KSP ksp)
216 {
217   DM dm;
218 
219   PetscFunctionBegin;
220   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
221   PetscCall(KSPGetDM(ksp, &dm));
222   if (dm && ksp->err_hist && ksp->err_hist_max > ksp->err_hist_len) {
223     PetscSimplePointFunc exactSol;
224     void                *exactCtx;
225     PetscDS              ds;
226     Vec                  u;
227     PetscReal            error;
228     PetscInt             Nf;
229 
230     PetscCall(KSPBuildSolution(ksp, NULL, &u));
231     /* TODO Was needed to correct for Newton solution, but I just need to set a solution */
232     //PetscCall(VecScale(u, -1.0));
233     /* TODO Case when I have a solution */
234     if (0) {
235       PetscCall(DMGetDS(dm, &ds));
236       PetscCall(PetscDSGetNumFields(ds, &Nf));
237       PetscCheck(Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle number of fields %" PetscInt_FMT " > 1 right now", Nf);
238       PetscCall(PetscDSGetExactSolution(ds, 0, &exactSol, &exactCtx));
239       PetscCall(DMComputeL2FieldDiff(dm, 0.0, &exactSol, &exactCtx, u, &error));
240     } else {
241       /* The null solution A 0 = 0 */
242       PetscCall(VecNorm(u, NORM_2, &error));
243     }
244     ksp->err_hist[ksp->err_hist_len++] = error;
245   }
246   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
247   PetscFunctionReturn(0);
248 }
249 
250 static inline PetscScalar KSPNoisyHash_Private(PetscInt xx)
251 {
252   unsigned int x = (unsigned int)xx;
253   x              = ((x >> 16) ^ x) * 0x45d9f3b;
254   x              = ((x >> 16) ^ x) * 0x45d9f3b;
255   x              = ((x >> 16) ^ x);
256   return (PetscScalar)((PetscInt64)x - 2147483648) * 5.e-10; /* center around zero, scaled about -1. to 1.*/
257 }
258 
259 static inline PetscErrorCode KSPSetNoisy_Private(Vec v)
260 {
261   PetscScalar *a;
262   PetscInt     n, istart;
263 
264   PetscFunctionBegin;
265   PetscCall(VecGetOwnershipRange(v, &istart, NULL));
266   PetscCall(VecGetLocalSize(v, &n));
267   PetscCall(VecGetArrayWrite(v, &a));
268   for (PetscInt i = 0; i < n; ++i) a[i] = KSPNoisyHash_Private(i + istart);
269   PetscCall(VecRestoreArrayWrite(v, &a));
270   PetscFunctionReturn(0);
271 }
272 
273 PETSC_INTERN PetscErrorCode KSPSetUpNorms_Private(KSP, PetscBool, KSPNormType *, PCSide *);
274 
275 PETSC_INTERN PetscErrorCode KSPPlotEigenContours_Private(KSP, PetscInt, const PetscReal *, const PetscReal *);
276 
277 typedef struct _p_DMKSP  *DMKSP;
278 typedef struct _DMKSPOps *DMKSPOps;
279 struct _DMKSPOps {
280   PetscErrorCode (*computeoperators)(KSP, Mat, Mat, void *);
281   PetscErrorCode (*computerhs)(KSP, Vec, void *);
282   PetscErrorCode (*computeinitialguess)(KSP, Vec, void *);
283   PetscErrorCode (*destroy)(DMKSP *);
284   PetscErrorCode (*duplicate)(DMKSP, DMKSP);
285 };
286 
287 struct _p_DMKSP {
288   PETSCHEADER(struct _DMKSPOps);
289   void *operatorsctx;
290   void *rhsctx;
291   void *initialguessctx;
292   void *data;
293 
294   /* This is NOT reference counted. The DM on which this context was first created is cached here to implement one-way
295    * copy-on-write. When DMGetDMKSPWrite() sees a request using a different DM, it makes a copy. Thus, if a user
296    * only interacts directly with one level, e.g., using KSPSetComputeOperators(), then coarse levels are constructed by
297    * PCMG, then the user changes the routine with another call to KSPSetComputeOperators(), it automatically propagates
298    * to all the levels. If instead, they get out a specific level and set the routines on that level, subsequent changes
299    * to the original level will no longer propagate to that level.
300    */
301   DM originaldm;
302 
303   void (*fortran_func_pointers[3])(void); /* Store our own function pointers so they are associated with the DMKSP instead of the DM */
304 };
305 PETSC_EXTERN PetscErrorCode DMGetDMKSP(DM, DMKSP *);
306 PETSC_EXTERN PetscErrorCode DMGetDMKSPWrite(DM, DMKSP *);
307 PETSC_EXTERN PetscErrorCode DMCopyDMKSP(DM, DM);
308 
309 /*
310        These allow the various Krylov methods to apply to either the linear system or its transpose.
311 */
312 static inline PetscErrorCode KSP_RemoveNullSpace(KSP ksp, Vec y)
313 {
314   PetscFunctionBegin;
315   if (ksp->pc_side == PC_LEFT) {
316     Mat          A;
317     MatNullSpace nullsp;
318 
319     PetscCall(PCGetOperators(ksp->pc, &A, NULL));
320     PetscCall(MatGetNullSpace(A, &nullsp));
321     if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, y));
322   }
323   PetscFunctionReturn(0);
324 }
325 
326 static inline PetscErrorCode KSP_RemoveNullSpaceTranspose(KSP ksp, Vec y)
327 {
328   PetscFunctionBegin;
329   if (ksp->pc_side == PC_LEFT) {
330     Mat          A;
331     MatNullSpace nullsp;
332 
333     PetscCall(PCGetOperators(ksp->pc, &A, NULL));
334     PetscCall(MatGetTransposeNullSpace(A, &nullsp));
335     if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, y));
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 static inline PetscErrorCode KSP_MatMult(KSP ksp, Mat A, Vec x, Vec y)
341 {
342   PetscFunctionBegin;
343   if (ksp->transpose_solve) PetscCall(MatMultTranspose(A, x, y));
344   else PetscCall(MatMult(A, x, y));
345   PetscFunctionReturn(0);
346 }
347 
348 static inline PetscErrorCode KSP_MatMultTranspose(KSP ksp, Mat A, Vec x, Vec y)
349 {
350   PetscFunctionBegin;
351   if (ksp->transpose_solve) PetscCall(MatMult(A, x, y));
352   else PetscCall(MatMultTranspose(A, x, y));
353   PetscFunctionReturn(0);
354 }
355 
356 static inline PetscErrorCode KSP_MatMultHermitianTranspose(KSP ksp, Mat A, Vec x, Vec y)
357 {
358   PetscFunctionBegin;
359   if (!ksp->transpose_solve) PetscCall(MatMultHermitianTranspose(A, x, y));
360   else {
361     Vec w;
362 
363     PetscCall(VecDuplicate(x, &w));
364     PetscCall(VecCopy(x, w));
365     PetscCall(VecConjugate(w));
366     PetscCall(MatMult(A, w, y));
367     PetscCall(VecDestroy(&w));
368     PetscCall(VecConjugate(y));
369   }
370   PetscFunctionReturn(0);
371 }
372 
373 static inline PetscErrorCode KSP_PCApply(KSP ksp, Vec x, Vec y)
374 {
375   PetscFunctionBegin;
376   if (ksp->transpose_solve) {
377     PetscCall(PCApplyTranspose(ksp->pc, x, y));
378     PetscCall(KSP_RemoveNullSpaceTranspose(ksp, y));
379   } else {
380     PetscCall(PCApply(ksp->pc, x, y));
381     PetscCall(KSP_RemoveNullSpace(ksp, y));
382   }
383   PetscFunctionReturn(0);
384 }
385 
386 static inline PetscErrorCode KSP_PCApplyTranspose(KSP ksp, Vec x, Vec y)
387 {
388   PetscFunctionBegin;
389   if (ksp->transpose_solve) {
390     PetscCall(PCApply(ksp->pc, x, y));
391     PetscCall(KSP_RemoveNullSpace(ksp, y));
392   } else {
393     PetscCall(PCApplyTranspose(ksp->pc, x, y));
394     PetscCall(KSP_RemoveNullSpaceTranspose(ksp, y));
395   }
396   PetscFunctionReturn(0);
397 }
398 
399 static inline PetscErrorCode KSP_PCApplyHermitianTranspose(KSP ksp, Vec x, Vec y)
400 {
401   PetscFunctionBegin;
402   PetscCall(VecConjugate(x));
403   PetscCall(KSP_PCApplyTranspose(ksp, x, y));
404   PetscCall(VecConjugate(x));
405   PetscCall(VecConjugate(y));
406   PetscFunctionReturn(0);
407 }
408 
409 static inline PetscErrorCode KSP_PCApplyBAorAB(KSP ksp, Vec x, Vec y, Vec w)
410 {
411   PetscFunctionBegin;
412   if (ksp->transpose_solve) {
413     PetscCall(PCApplyBAorABTranspose(ksp->pc, ksp->pc_side, x, y, w));
414     PetscCall(KSP_RemoveNullSpaceTranspose(ksp, y));
415   } else {
416     PetscCall(PCApplyBAorAB(ksp->pc, ksp->pc_side, x, y, w));
417     PetscCall(KSP_RemoveNullSpace(ksp, y));
418   }
419   PetscFunctionReturn(0);
420 }
421 
422 static inline PetscErrorCode KSP_PCApplyBAorABTranspose(KSP ksp, Vec x, Vec y, Vec w)
423 {
424   PetscFunctionBegin;
425   if (ksp->transpose_solve) PetscCall(PCApplyBAorAB(ksp->pc, ksp->pc_side, x, y, w));
426   else PetscCall(PCApplyBAorABTranspose(ksp->pc, ksp->pc_side, x, y, w));
427   PetscFunctionReturn(0);
428 }
429 
430 PETSC_EXTERN PetscLogEvent KSP_GMRESOrthogonalization;
431 PETSC_EXTERN PetscLogEvent KSP_SetUp;
432 PETSC_EXTERN PetscLogEvent KSP_Solve;
433 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_0;
434 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_1;
435 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_2;
436 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_3;
437 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_4;
438 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_S;
439 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_L;
440 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_U;
441 PETSC_EXTERN PetscLogEvent KSP_SolveTranspose;
442 PETSC_EXTERN PetscLogEvent KSP_MatSolve;
443 
444 PETSC_INTERN PetscErrorCode MatGetSchurComplement_Basic(Mat, IS, IS, IS, IS, MatReuse, Mat *, MatSchurComplementAinvType, MatReuse, Mat *);
445 PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC, PetscBool *);
446 
447   /*MC
448    KSPCheckDot - Checks if the result of a dot product used by the corresponding `KSP` contains Inf or NaN. These indicate that the previous
449       application of the preconditioner generated an error. Sets a `KSPConvergedReason` and returns if the `PC` set a `PCFailedReason`.
450 
451    Collective
452 
453    Input Parameter:
454 .  ksp - the linear solver `KSP` context.
455 
456    Output Parameter:
457 .  beta - the result of the inner product
458 
459    Level: developer
460 
461    Developer Notes:
462    Used to manage returning from `KSP` solvers whose preconditioners have failed, possibly only a subset of MPI ranks, in some way
463 
464    It uses the fact that `KSP` piggy-backs the collectivity of certain error conditions on the results of norms and inner products.
465 
466 .seealso: `PCFailedReason`, `KSPConvergedReason`, `PCGetFailedReasonRank()`, `KSP`, `KSPCreate()`, `KSPSetType()`, `KSP`, `KSPCheckNorm()`, `KSPCheckSolve()`
467 M*/
468   #define KSPCheckDot(ksp, beta) \
469     do { \
470       if (PetscIsInfOrNanScalar(beta)) { \
471         PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "KSPSolve has not converged due to Nan or Inf inner product"); \
472         { \
473           PCFailedReason pcreason; \
474           PetscInt       sendbuf, recvbuf; \
475           PetscCall(PCGetFailedReasonRank(ksp->pc, &pcreason)); \
476           sendbuf = (PetscInt)pcreason; \
477           PetscCallMPI(MPI_Allreduce(&sendbuf, &recvbuf, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)ksp))); \
478           if (recvbuf) { \
479             PetscCall(PCSetFailedReason(ksp->pc, (PCFailedReason)recvbuf)); \
480             ksp->reason = KSP_DIVERGED_PC_FAILED; \
481             PetscCall(VecSetInf(ksp->vec_sol)); \
482           } else { \
483             ksp->reason = KSP_DIVERGED_NANORINF; \
484           } \
485           PetscFunctionReturn(0); \
486         } \
487       } \
488     } while (0)
489 
490   /*MC
491    KSPCheckNorm - Checks if the result of a norm used by the corresponding `KSP` contains `inf` or `NaN`. These indicate that the previous
492       application of the preconditioner generated an error. Sets a `KSPConvergedReason` and returns if the `PC` set a `PCFailedReason`.
493 
494    Collective
495 
496    Input Parameter:
497 .  ksp - the linear solver `KSP` context.
498 
499    Output Parameter:
500 .  beta - the result of the norm
501 
502    Level: developer
503 
504    Developer Notes:
505    Used to manage returning from `KSP` solvers whose preconditioners have failed, possibly only a subset of MPI ranks, in some way.
506 
507    It uses the fact that `KSP` piggy-backs the collectivity of certain error conditions on the results of norms and inner products.
508 
509 .seealso: `PCFailedReason`, `KSPConvergedReason`, `PCGetFailedReasonRank()`, `KSP`, `KSPCreate()`, `KSPSetType()`, `KSP`, `KSPCheckDot()`, `KSPCheckSolve()`
510 M*/
511   #define KSPCheckNorm(ksp, beta) \
512     do { \
513       if (PetscIsInfOrNanReal(beta)) { \
514         PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "KSPSolve has not converged due to Nan or Inf norm"); \
515         { \
516           PCFailedReason pcreason; \
517           PetscInt       sendbuf, recvbuf; \
518           PetscCall(PCGetFailedReasonRank(ksp->pc, &pcreason)); \
519           sendbuf = (PetscInt)pcreason; \
520           PetscCallMPI(MPI_Allreduce(&sendbuf, &recvbuf, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)ksp))); \
521           if (recvbuf) { \
522             PetscCall(PCSetFailedReason(ksp->pc, (PCFailedReason)recvbuf)); \
523             ksp->reason = KSP_DIVERGED_PC_FAILED; \
524             PetscCall(VecSetInf(ksp->vec_sol)); \
525             ksp->rnorm = beta; \
526           } else { \
527             PetscCall(PCSetFailedReason(ksp->pc, PC_NOERROR)); \
528             ksp->reason = KSP_DIVERGED_NANORINF; \
529             ksp->rnorm  = beta; \
530           } \
531           PetscFunctionReturn(0); \
532         } \
533       } \
534     } while (0)
535 
536 #endif
537 
538 PETSC_INTERN PetscErrorCode KSPMonitorMakeKey_Internal(const char[], PetscViewerType, PetscViewerFormat, char[]);
539 PETSC_INTERN PetscErrorCode KSPMonitorRange_Private(KSP, PetscInt, PetscReal *);
540