xref: /petsc/include/petsc/private/kspimpl.h (revision 11c8a98f607708dcee13afcc724c3f833fe66e89)
1 #pragma once
2 
3 #include <petscksp.h>
4 #include <petscds.h>
5 #include <petsc/private/petscimpl.h>
6 
7 /* SUBMANSEC = KSP */
8 
9 PETSC_EXTERN PetscBool      KSPRegisterAllCalled;
10 PETSC_EXTERN PetscBool      KSPMonitorRegisterAllCalled;
11 PETSC_EXTERN PetscErrorCode KSPRegisterAll(void);
12 PETSC_EXTERN PetscErrorCode KSPMonitorRegisterAll(void);
13 PETSC_EXTERN PetscErrorCode KSPGuessRegisterAll(void);
14 PETSC_EXTERN PetscErrorCode KSPMatRegisterAll(void);
15 
16 typedef struct _KSPOps *KSPOps;
17 
18 struct _KSPOps {
19   PetscErrorCode (*buildsolution)(KSP, Vec, Vec *);      /* Returns a pointer to the solution, or
20                                                           calculates the solution in a
21                                                           user-provided area. */
22   PetscErrorCode (*buildresidual)(KSP, Vec, Vec, Vec *); /* Returns a pointer to the residual, or
23                                                           calculates the residual in a
24                                                           user-provided area.  */
25   PetscErrorCode (*solve)(KSP);                          /* actual solver */
26   PetscErrorCode (*matsolve)(KSP, Mat, Mat);             /* multiple dense RHS solver */
27   PetscErrorCode (*setup)(KSP);
28   PetscErrorCode (*setfromoptions)(KSP, PetscOptionItems *);
29   PetscErrorCode (*publishoptions)(KSP);
30   PetscErrorCode (*computeextremesingularvalues)(KSP, PetscReal *, PetscReal *);
31   PetscErrorCode (*computeeigenvalues)(KSP, PetscInt, PetscReal *, PetscReal *, PetscInt *);
32   PetscErrorCode (*computeritz)(KSP, PetscBool, PetscBool, PetscInt *, Vec[], PetscReal *, PetscReal *);
33   PetscErrorCode (*destroy)(KSP);
34   PetscErrorCode (*view)(KSP, PetscViewer);
35   PetscErrorCode (*reset)(KSP);
36   PetscErrorCode (*load)(KSP, PetscViewer);
37 };
38 
39 typedef struct _KSPGuessOps *KSPGuessOps;
40 
41 struct _KSPGuessOps {
42   PetscErrorCode (*formguess)(KSPGuess, Vec, Vec); /* Form initial guess */
43   PetscErrorCode (*update)(KSPGuess, Vec, Vec);    /* Update database */
44   PetscErrorCode (*setfromoptions)(KSPGuess);
45   PetscErrorCode (*settolerance)(KSPGuess, PetscReal);
46   PetscErrorCode (*setup)(KSPGuess);
47   PetscErrorCode (*destroy)(KSPGuess);
48   PetscErrorCode (*view)(KSPGuess, PetscViewer);
49   PetscErrorCode (*reset)(KSPGuess);
50 };
51 
52 /*
53    Defines the KSPGuess data structure.
54 */
55 struct _p_KSPGuess {
56   PETSCHEADER(struct _KSPGuessOps);
57   KSP              ksp;       /* the parent KSP */
58   Mat              A;         /* the current linear operator */
59   PetscObjectState omatstate; /* previous linear operator state */
60   void            *data;      /* pointer to the specific implementation */
61 };
62 
63 PETSC_EXTERN PetscErrorCode KSPGuessCreate_Fischer(KSPGuess);
64 PETSC_EXTERN PetscErrorCode KSPGuessCreate_POD(KSPGuess);
65 
66 /*
67      Maximum number of monitors you can run with a single KSP
68 */
69 #define MAXKSPMONITORS    5
70 #define MAXKSPREASONVIEWS 5
71 typedef enum {
72   KSP_SETUP_NEW = 0,
73   KSP_SETUP_NEWMATRIX,
74   KSP_SETUP_NEWRHS
75 } KSPSetUpStage;
76 
77 /*
78    Defines the KSP data structure.
79 */
80 struct _p_KSP {
81   PETSCHEADER(struct _KSPOps);
82   DM        dm;
83   PetscBool dmAuto;   /* DM was created automatically by KSP */
84   PetscBool dmActive; /* KSP should use DM for computing operators */
85   /*------------------------- User parameters--------------------------*/
86   PetscObjectParameterDeclare(PetscInt, max_it); /* maximum number of iterations */
87   PetscInt  min_it;                              /* minimum number of iterations */
88   KSPGuess  guess;
89   PetscBool guess_zero,                                 /* flag for whether initial guess is 0 */
90     guess_not_read,                                     /* guess is not read, does not need to be zeroed */
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   PetscObjectParameterDeclare(PetscReal, rtol);         /* relative tolerance */
97   PetscObjectParameterDeclare(PetscReal, abstol);       /* absolute tolerance */
98   PetscObjectParameterDeclare(PetscReal, ttol);         /* (not set by user)  */
99   PetscObjectParameterDeclare(PetscReal, 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   PetscViewer       convergedreasonviewer;
134   PetscViewerFormat convergedreasonformat;
135   PetscErrorCode (*reasonview[MAXKSPREASONVIEWS])(KSP, void *);    /* KSP converged reason view */
136   PetscErrorCode (*reasonviewdestroy[MAXKSPREASONVIEWS])(void **); /* Optional destroy routine */
137   void    *reasonviewcontext[MAXKSPREASONVIEWS];                   /* User context */
138   PetscInt numberreasonviews;                                      /* Number if reason viewers */
139 
140   PetscErrorCode (*converged)(KSP, PetscInt, PetscReal, KSPConvergedReason *, void *);
141   PetscErrorCode (*convergeddestroy)(void *);
142   void *cnvP;
143 
144   void *user; /* optional user-defined context */
145 
146   PC pc;
147 
148   void *data; /* holder for misc stuff associated
149                                    with a particular iterative solver */
150 
151   PetscBool         view, viewPre, viewRate, viewMat, viewPMat, viewRhs, viewSol, viewMatExp, viewEV, viewSV, viewEVExp, viewFinalRes, viewPOpExp, viewDScale;
152   PetscViewer       viewer, viewerPre, viewerRate, viewerMat, viewerPMat, viewerRhs, viewerSol, viewerMatExp, viewerEV, viewerSV, viewerEVExp, viewerFinalRes, viewerPOpExp, viewerDScale;
153   PetscViewerFormat format, formatPre, formatRate, formatMat, formatPMat, formatRhs, formatSol, formatMatExp, formatEV, formatSV, formatEVExp, formatFinalRes, formatPOpExp, formatDScale;
154 
155   /* ----------------Default work-area management -------------------- */
156   PetscInt nwork;
157   Vec     *work;
158 
159   KSPSetUpStage setupstage;
160   PetscBool     setupnewmatrix; /* true if we need to call ksp->ops->setup with KSP_SETUP_NEWMATRIX */
161 
162   PetscInt its;      /* number of iterations so far computed in THIS linear solve*/
163   PetscInt totalits; /* number of iterations used by this KSP object since it was created */
164 
165   PetscBool transpose_solve; /* solve transpose system instead */
166   struct {
167     Mat       AT, BT;
168     PetscBool use_explicittranspose; /* transpose the system explicitly in KSPSolveTranspose */
169     PetscBool reuse_transpose;       /* reuse the previous transposed system */
170   } transpose;
171 
172   KSPNormType normtype; /* type of norm used for convergence tests */
173 
174   PCSide      pc_side_set;  /* PC type set explicitly by user */
175   KSPNormType normtype_set; /* Norm type set explicitly by user */
176 
177   /*   Allow diagonally scaling the matrix before computing the preconditioner or using
178        the Krylov method. Note this is NOT just Jacobi preconditioning */
179 
180   PetscBool dscale;     /* diagonal scale system; used with KSPSetDiagonalScale() */
181   PetscBool dscalefix;  /* unscale system after solve */
182   PetscBool dscalefix2; /* system has been unscaled */
183   Vec       diagonal;   /* 1/sqrt(diag of matrix) */
184   Vec       truediagonal;
185 
186   /* Allow declaring convergence when negative curvature is detected */
187   PetscBool converged_neg_curve;
188 
189   PetscInt  setfromoptionscalled;
190   PetscBool skippcsetfromoptions; /* if set then KSPSetFromOptions() does not call PCSetFromOptions() */
191 
192   PetscErrorCode (*presolve)(KSP, Vec, Vec, void *);
193   PetscErrorCode (*postsolve)(KSP, Vec, Vec, void *);
194   void *prectx, *postctx;
195 
196   PetscInt nestlevel; /* how many levels of nesting does the KSP have */
197 };
198 
199 typedef struct { /* dummy data structure used in KSPMonitorDynamicTolerance() */
200   PetscReal coef;
201   PetscReal bnrm;
202 } KSPDynTolCtx;
203 
204 typedef struct {
205   PetscBool initialrtol;    /* default relative residual decrease is computed from initial residual, not rhs */
206   PetscBool mininitialrtol; /* default relative residual decrease is computed from min of initial residual and rhs */
207   PetscBool convmaxits;     /* if true, the convergence test returns KSP_CONVERGED_ITS if the maximum number of iterations is reached */
208   Vec       work;
209 } KSPConvergedDefaultCtx;
210 
211 static inline PetscErrorCode KSPLogResidualHistory(KSP ksp, PetscReal norm)
212 {
213   PetscFunctionBegin;
214   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
215   if (ksp->res_hist && ksp->res_hist_max > ksp->res_hist_len) ksp->res_hist[ksp->res_hist_len++] = norm;
216   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
217   PetscFunctionReturn(PETSC_SUCCESS);
218 }
219 
220 static inline PetscErrorCode KSPLogErrorHistory(KSP ksp)
221 {
222   DM dm;
223 
224   PetscFunctionBegin;
225   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
226   PetscCall(KSPGetDM(ksp, &dm));
227   if (dm && ksp->err_hist && ksp->err_hist_max > ksp->err_hist_len) {
228     PetscSimplePointFn *exactSol;
229     void               *exactCtx;
230     PetscDS             ds;
231     Vec                 u;
232     PetscReal           error;
233     PetscInt            Nf;
234 
235     PetscCall(KSPBuildSolution(ksp, NULL, &u));
236     /* TODO Was needed to correct for Newton solution, but I just need to set a solution */
237     //PetscCall(VecScale(u, -1.0));
238     /* TODO Case when I have a solution */
239     if (0) {
240       PetscCall(DMGetDS(dm, &ds));
241       PetscCall(PetscDSGetNumFields(ds, &Nf));
242       PetscCheck(Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle number of fields %" PetscInt_FMT " > 1 right now", Nf);
243       PetscCall(PetscDSGetExactSolution(ds, 0, &exactSol, &exactCtx));
244       PetscCall(DMComputeL2FieldDiff(dm, 0.0, &exactSol, &exactCtx, u, &error));
245     } else {
246       /* The null solution A 0 = 0 */
247       PetscCall(VecNorm(u, NORM_2, &error));
248     }
249     ksp->err_hist[ksp->err_hist_len++] = error;
250   }
251   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
252   PetscFunctionReturn(PETSC_SUCCESS);
253 }
254 
255 static inline PetscScalar KSPNoisyHash_Private(PetscInt xx)
256 {
257   unsigned int x = (unsigned int)xx;
258   x              = ((x >> 16) ^ x) * 0x45d9f3b;
259   x              = ((x >> 16) ^ x) * 0x45d9f3b;
260   x              = ((x >> 16) ^ x);
261   return (PetscScalar)(((PetscInt64)x - 2147483648) * 5.e-10); /* center around zero, scaled about -1. to 1.*/
262 }
263 
264 static inline PetscErrorCode KSPSetNoisy_Private(Vec v)
265 {
266   PetscScalar *a;
267   PetscInt     n, istart;
268 
269   PetscFunctionBegin;
270   PetscCall(VecGetOwnershipRange(v, &istart, NULL));
271   PetscCall(VecGetLocalSize(v, &n));
272   PetscCall(VecGetArrayWrite(v, &a));
273   for (PetscInt i = 0; i < n; ++i) a[i] = KSPNoisyHash_Private(i + istart);
274   PetscCall(VecRestoreArrayWrite(v, &a));
275   PetscFunctionReturn(PETSC_SUCCESS);
276 }
277 
278 PETSC_INTERN PetscErrorCode KSPSetUpNorms_Private(KSP, PetscBool, KSPNormType *, PCSide *);
279 
280 PETSC_INTERN PetscErrorCode KSPPlotEigenContours_Private(KSP, PetscInt, const PetscReal *, const PetscReal *);
281 
282 typedef struct _p_DMKSP  *DMKSP;
283 typedef struct _DMKSPOps *DMKSPOps;
284 struct _DMKSPOps {
285   KSPComputeOperatorsFn    *computeoperators;
286   KSPComputeRHSFn          *computerhs;
287   KSPComputeInitialGuessFn *computeinitialguess;
288   PetscErrorCode (*destroy)(DMKSP *);
289   PetscErrorCode (*duplicate)(DMKSP, DMKSP);
290 };
291 
292 /*S
293    DMKSP - Object held by a `DM` that contains all the callback functions and their contexts needed by a `KSP`
294 
295    Level: developer
296 
297    Notes:
298    Users provides callback functions and their contexts to `KSP` using, for example, `KSPSetComputeRHS()`. These values are stored
299    in a `DMKSP` that is contained in the `DM` associated with the `KSP`. If no `DM` was provided by
300    the user with `KSPSetDM()` it is automatically created by `KSPGetDM()` with `DMShellCreate()`.
301 
302    Users very rarely need to worked directly with the `DMKSP` object, rather they work with the `KSP` and the `DM` they created
303 
304    Multiple `DM` can share a single `DMKSP`, often each `DM` is associated with
305    a grid refinement level. `DMGetDMKSP()` returns the `DMKSP` associated with a `DM`. `DMGetDMKSPWrite()` returns a unique
306    `DMKSP` that is only associated with the current `DM`, making a copy of the shared `DMKSP` if needed (copy-on-write).
307 
308    Developer Notes:
309    It is rather subtle why `DMKSP`, `DMSNES`, and `DMTS` are needed instead of simply storing the user callback functions and contexts in `DM` or `KSP`, `SNES`, or `TS`.
310    It is to support composable solvers such as geometric multigrid. We want, by default, the same callback functions and contexts for all the levels in the computation,
311    but we need to also support different callbacks and contexts on each level. The copy-on-write approach of `DMGetDMKSPWrite()` makes this possible.
312 
313    The `originaldm` inside the `DMKSP` is NOT reference counted (to prevent a reference count loop between a `DM` and a `DMKSP`).
314    The `DM` on which this context was first created is cached here to implement one-way
315    copy-on-write. When `DMGetDMKSPWrite()` sees a request using a different `DM`, it makes a copy of the `TSDM`. Thus, if a user
316    only interacts directly with one level, e.g., using `TSSetIFunction()`, then coarse levels of a multilevel item
317    integrator are built, then the user changes the routine with another call to `TSSetIFunction()`, it automatically
318    propagates to all the levels. If instead, they get out a specific level and set the function on that level,
319    subsequent changes to the original level will no longer propagate to that level.
320 
321 .seealso: [](ch_ts), `KSP`, `KSPCreate()`, `DM`, `DMGetDMKSPWrite()`, `DMGetDMKSP()`,  `DMSNES`, `DMTS`, `DMKSPSetComputeOperators()`, `DMKSPGetComputeOperators()`,
322           `DMKSPSetComputeRHS()`, `DMKSPSetComputeInitialGuess()`
323 S*/
324 struct _p_DMKSP {
325   PETSCHEADER(struct _DMKSPOps);
326   void *operatorsctx;
327   void *rhsctx;
328   void *initialguessctx;
329   void *data;
330 
331   /* See developer note for `DMKSP` above */
332   DM originaldm;
333 
334   void (*fortran_func_pointers[3])(void); /* Store our own function pointers so they are associated with the DMKSP instead of the DM */
335 };
336 PETSC_EXTERN PetscErrorCode DMGetDMKSP(DM, DMKSP *);
337 PETSC_EXTERN PetscErrorCode DMGetDMKSPWrite(DM, DMKSP *);
338 PETSC_EXTERN PetscErrorCode DMCopyDMKSP(DM, DM);
339 
340 /*
341        These allow the various Krylov methods to apply to either the linear system or its transpose.
342 */
343 static inline PetscErrorCode KSP_RemoveNullSpace(KSP ksp, Vec y)
344 {
345   PetscFunctionBegin;
346   if (ksp->pc_side == PC_LEFT) {
347     Mat          A;
348     MatNullSpace nullsp;
349 
350     PetscCall(PCGetOperators(ksp->pc, &A, NULL));
351     PetscCall(MatGetNullSpace(A, &nullsp));
352     if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, y));
353   }
354   PetscFunctionReturn(PETSC_SUCCESS);
355 }
356 
357 static inline PetscErrorCode KSP_RemoveNullSpaceTranspose(KSP ksp, Vec y)
358 {
359   PetscFunctionBegin;
360   if (ksp->pc_side == PC_LEFT) {
361     Mat          A;
362     MatNullSpace nullsp;
363 
364     PetscCall(PCGetOperators(ksp->pc, &A, NULL));
365     PetscCall(MatGetTransposeNullSpace(A, &nullsp));
366     if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, y));
367   }
368   PetscFunctionReturn(PETSC_SUCCESS);
369 }
370 
371 static inline PetscErrorCode KSP_MatMult(KSP ksp, Mat A, Vec x, Vec y)
372 {
373   PetscFunctionBegin;
374   if (ksp->transpose_solve) PetscCall(MatMultTranspose(A, x, y));
375   else PetscCall(MatMult(A, x, y));
376   PetscFunctionReturn(PETSC_SUCCESS);
377 }
378 
379 static inline PetscErrorCode KSP_MatMultTranspose(KSP ksp, Mat A, Vec x, Vec y)
380 {
381   PetscFunctionBegin;
382   if (ksp->transpose_solve) PetscCall(MatMult(A, x, y));
383   else PetscCall(MatMultTranspose(A, x, y));
384   PetscFunctionReturn(PETSC_SUCCESS);
385 }
386 
387 static inline PetscErrorCode KSP_MatMultHermitianTranspose(KSP ksp, Mat A, Vec x, Vec y)
388 {
389   PetscFunctionBegin;
390   if (!ksp->transpose_solve) PetscCall(MatMultHermitianTranspose(A, x, y));
391   else {
392     Vec w;
393 
394     PetscCall(VecDuplicate(x, &w));
395     PetscCall(VecCopy(x, w));
396     PetscCall(VecConjugate(w));
397     PetscCall(MatMult(A, w, y));
398     PetscCall(VecDestroy(&w));
399     PetscCall(VecConjugate(y));
400   }
401   PetscFunctionReturn(PETSC_SUCCESS);
402 }
403 
404 static inline PetscErrorCode KSP_PCApply(KSP ksp, Vec x, Vec y)
405 {
406   PetscFunctionBegin;
407   if (ksp->transpose_solve) {
408     PetscCall(PCApplyTranspose(ksp->pc, x, y));
409     PetscCall(KSP_RemoveNullSpaceTranspose(ksp, y));
410   } else {
411     PetscCall(PCApply(ksp->pc, x, y));
412     PetscCall(KSP_RemoveNullSpace(ksp, y));
413   }
414   PetscFunctionReturn(PETSC_SUCCESS);
415 }
416 
417 static inline PetscErrorCode KSP_PCApplyTranspose(KSP ksp, Vec x, Vec y)
418 {
419   PetscFunctionBegin;
420   if (ksp->transpose_solve) {
421     PetscCall(PCApply(ksp->pc, x, y));
422     PetscCall(KSP_RemoveNullSpace(ksp, y));
423   } else {
424     PetscCall(PCApplyTranspose(ksp->pc, x, y));
425     PetscCall(KSP_RemoveNullSpaceTranspose(ksp, y));
426   }
427   PetscFunctionReturn(PETSC_SUCCESS);
428 }
429 
430 static inline PetscErrorCode KSP_PCApplyHermitianTranspose(KSP ksp, Vec x, Vec y)
431 {
432   PetscFunctionBegin;
433   PetscCall(VecConjugate(x));
434   PetscCall(KSP_PCApplyTranspose(ksp, x, y));
435   PetscCall(VecConjugate(x));
436   PetscCall(VecConjugate(y));
437   PetscFunctionReturn(PETSC_SUCCESS);
438 }
439 
440 static inline PetscErrorCode KSP_PCMatApply(KSP ksp, Mat X, Mat Y)
441 {
442   PetscFunctionBegin;
443   if (ksp->transpose_solve) {
444     PetscBool flg;
445     PetscCall(PetscObjectTypeCompareAny((PetscObject)ksp->pc, &flg, PCNONE, PCICC, PCCHOLESKY, ""));
446     PetscCheck(flg, PetscObjectComm((PetscObject)ksp), PETSC_ERR_SUP, "PCMatApplyTranspose() not yet implemented for nonsymmetric PC");
447   }
448   PetscCall(PCMatApply(ksp->pc, X, Y));
449   PetscFunctionReturn(PETSC_SUCCESS);
450 }
451 
452 static inline PetscErrorCode KSP_PCMatApplyTranspose(KSP ksp, Mat X, Mat Y)
453 {
454   PetscFunctionBegin;
455   if (!ksp->transpose_solve) {
456     PetscBool flg;
457     PetscCall(PetscObjectTypeCompareAny((PetscObject)ksp->pc, &flg, PCNONE, PCICC, PCCHOLESKY, ""));
458     PetscCheck(flg, PetscObjectComm((PetscObject)ksp), PETSC_ERR_SUP, "PCMatApplyTranspose() not yet implemented for nonsymmetric PC");
459   }
460   PetscCall(PCMatApply(ksp->pc, X, Y));
461   PetscFunctionReturn(PETSC_SUCCESS);
462 }
463 
464 static inline PetscErrorCode KSP_PCApplyBAorAB(KSP ksp, Vec x, Vec y, Vec w)
465 {
466   PetscFunctionBegin;
467   if (ksp->transpose_solve) {
468     PetscCall(PCApplyBAorABTranspose(ksp->pc, ksp->pc_side, x, y, w));
469     PetscCall(KSP_RemoveNullSpaceTranspose(ksp, y));
470   } else {
471     PetscCall(PCApplyBAorAB(ksp->pc, ksp->pc_side, x, y, w));
472     PetscCall(KSP_RemoveNullSpace(ksp, y));
473   }
474   PetscFunctionReturn(PETSC_SUCCESS);
475 }
476 
477 static inline PetscErrorCode KSP_PCApplyBAorABTranspose(KSP ksp, Vec x, Vec y, Vec w)
478 {
479   PetscFunctionBegin;
480   if (ksp->transpose_solve) PetscCall(PCApplyBAorAB(ksp->pc, ksp->pc_side, x, y, w));
481   else PetscCall(PCApplyBAorABTranspose(ksp->pc, ksp->pc_side, x, y, w));
482   PetscFunctionReturn(PETSC_SUCCESS);
483 }
484 
485 PETSC_EXTERN PetscLogEvent KSP_GMRESOrthogonalization;
486 PETSC_EXTERN PetscLogEvent KSP_SetUp;
487 PETSC_EXTERN PetscLogEvent KSP_Solve;
488 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_0;
489 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_1;
490 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_2;
491 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_3;
492 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_4;
493 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_S;
494 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_L;
495 PETSC_EXTERN PetscLogEvent KSP_Solve_FS_U;
496 PETSC_EXTERN PetscLogEvent KSP_SolveTranspose;
497 PETSC_EXTERN PetscLogEvent KSP_MatSolve;
498 PETSC_EXTERN PetscLogEvent KSP_MatSolveTranspose;
499 
500 PETSC_INTERN PetscErrorCode MatGetSchurComplement_Basic(Mat, IS, IS, IS, IS, MatReuse, Mat *, MatSchurComplementAinvType, MatReuse, Mat *);
501 PETSC_INTERN PetscErrorCode PCPreSolveChangeRHS(PC, PetscBool *);
502 
503 /*MC
504    KSPCheckDot - Checks if the result of a dot product used by the corresponding `KSP` contains Inf or NaN. These indicate that the previous
505       application of the preconditioner generated an error. Sets a `KSPConvergedReason` and returns if the `PC` set a `PCFailedReason`.
506 
507    Collective
508 
509    Input Parameter:
510 .  ksp - the linear solver `KSP` context.
511 
512    Output Parameter:
513 .  beta - the result of the inner product
514 
515    Level: developer
516 
517    Developer Notes:
518    Used to manage returning from `KSP` solvers collectively whose preconditioners have failed, possibly only a subset of MPI processes, in some way
519 
520    It uses the fact that `KSP` piggy-backs the collectivity of certain error conditions on the results of norms and inner products.
521 
522 .seealso: `PCFailedReason`, `KSPConvergedReason`, `PCGetFailedReasonRank()`, `KSP`, `KSPCreate()`, `KSPSetType()`, `KSP`, `KSPCheckNorm()`, `KSPCheckSolve()`,
523           `KSPSetErrorIfNotConverged()`
524 M*/
525 #define KSPCheckDot(ksp, beta) \
526   do { \
527     if (PetscIsInfOrNanScalar(beta)) { \
528       PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "KSPSolve has not converged due to Nan or Inf inner product"); \
529       { \
530         PCFailedReason pcreason; \
531         PetscCall(PCReduceFailedReason(ksp->pc)); \
532         PetscCall(PCGetFailedReasonRank(ksp->pc, &pcreason)); \
533         PetscCall(VecFlag(ksp->vec_sol, pcreason)); \
534         if (pcreason) { \
535           ksp->reason = KSP_DIVERGED_PC_FAILED; \
536         } else { \
537           ksp->reason = KSP_DIVERGED_NANORINF; \
538         } \
539         PetscFunctionReturn(PETSC_SUCCESS); \
540       } \
541     } \
542   } while (0)
543 
544 /*MC
545    KSPCheckNorm - Checks if the result of a norm used by the corresponding `KSP` contains `inf` or `NaN`. These indicate that the previous
546       application of the preconditioner generated an error. Sets a `KSPConvergedReason` and returns if the `PC` set a `PCFailedReason`.
547 
548    Collective
549 
550    Input Parameter:
551 .  ksp - the linear solver `KSP` context.
552 
553    Output Parameter:
554 .  beta - the result of the norm
555 
556    Level: developer
557 
558    Developer Notes:
559    Used to manage returning from `KSP` solvers collectively whose preconditioners have failed, possibly only a subset of MPI processes, in some way.
560 
561    It uses the fact that `KSP` piggy-backs the collectivity of certain error conditions on the results of norms and inner products.
562 
563 .seealso: `PCFailedReason`, `KSPConvergedReason`, `PCGetFailedReasonRank()`, `KSP`, `KSPCreate()`, `KSPSetType()`, `KSP`, `KSPCheckDot()`, `KSPCheckSolve()`,
564           `KSPSetErrorIfNotConverged()`
565 M*/
566 #define KSPCheckNorm(ksp, beta) \
567   do { \
568     if (PetscIsInfOrNanReal(beta)) { \
569       PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "KSPSolve has not converged due to Nan or Inf norm"); \
570       { \
571         PCFailedReason pcreason; \
572         PetscCall(PCReduceFailedReason(ksp->pc)); \
573         PetscCall(PCGetFailedReasonRank(ksp->pc, &pcreason)); \
574         PetscCall(VecFlag(ksp->vec_sol, pcreason)); \
575         if (pcreason) { \
576           ksp->reason = KSP_DIVERGED_PC_FAILED; \
577         } else { \
578           ksp->reason = KSP_DIVERGED_NANORINF; \
579         } \
580         ksp->rnorm = beta; \
581         PetscFunctionReturn(PETSC_SUCCESS); \
582       } \
583     } \
584   } while (0)
585 
586 PETSC_INTERN PetscErrorCode KSPMonitorMakeKey_Internal(const char[], PetscViewerType, PetscViewerFormat, char[]);
587 PETSC_INTERN PetscErrorCode KSPMonitorRange_Private(KSP, PetscInt, PetscReal *);
588