Date: 2025-03-28T21:10:52+00:00

Actual source code: gmres.c

      1: /*
      2:     This file implements GMRES (a Generalized Minimal Residual) method.
      3:     Reference:  Saad and Schultz, 1986.

      5:     Some comments on left vs. right preconditioning, and restarts.
      6:     Left and right preconditioning.
      7:     If right preconditioning is chosen, then the problem being solved
      8:     by GMRES is actually
      9:        My =  AB^-1 y = f
     10:     so the initial residual is
     11:           r = f - M y
     12:     Note that B^-1 y = x or y = B x, and if x is non-zero, the initial
     13:     residual is
     14:           r = f - A x
     15:     The final solution is then
     16:           x = B^-1 y

     18:     If left preconditioning is chosen, then the problem being solved is
     19:        My = B^-1 A x = B^-1 f,
     20:     and the initial residual is
     21:        r  = B^-1(f - Ax)

     23:     Restarts:  Restarts are basically solves with x0 not equal to zero.
     24:     Note that we can eliminate an extra application of B^-1 between
     25:     restarts as long as we don't require that the solution at the end
     26:     of an unsuccessful gmres iteration always be the solution x.
     27:  */

     29: #include <../src/ksp/ksp/impls/gmres/gmresimpl.h>
     30: #define GMRES_DELTA_DIRECTIONS 10
     31: #define GMRES_DEFAULT_MAXK     30
     32: static PetscErrorCode KSPGMRESUpdateHessenberg(KSP, PetscInt, PetscBool, PetscReal *);
     33: static PetscErrorCode KSPGMRESBuildSoln(PetscScalar *, Vec, Vec, KSP, PetscInt);

     35: PetscErrorCode KSPSetUp_GMRES(KSP ksp)
     36: {
     37:   PetscInt   hh, hes, rs, cc;
     38:   PetscInt   max_k, k;
     39:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;

     41:   PetscFunctionBegin;
     42:   max_k = gmres->max_k; /* restart size */
     43:   hh    = (max_k + 2) * (max_k + 1);
     44:   hes   = (max_k + 1) * (max_k + 1);
     45:   rs    = (max_k + 2);
     46:   cc    = (max_k + 1);

     48:   PetscCall(PetscCalloc5(hh, &gmres->hh_origin, hes, &gmres->hes_origin, rs, &gmres->rs_origin, cc, &gmres->cc_origin, cc, &gmres->ss_origin));

     50:   if (ksp->calc_sings) {
     51:     /* Allocate workspace to hold Hessenberg matrix needed by lapack */
     52:     PetscCall(PetscMalloc1((max_k + 3) * (max_k + 9), &gmres->Rsvd));
     53:     PetscCall(PetscMalloc1(6 * (max_k + 2), &gmres->Dsvd));
     54:   }

     56:   /* Allocate array to hold pointers to user vectors.  Note that we need
     57:    4 + max_k + 1 (since we need it+1 vectors, and it <= max_k) */
     58:   gmres->vecs_allocated = VEC_OFFSET + 2 + max_k + gmres->nextra_vecs;

     60:   PetscCall(PetscMalloc1(gmres->vecs_allocated, &gmres->vecs));
     61:   PetscCall(PetscMalloc1(VEC_OFFSET + 2 + max_k, &gmres->user_work));
     62:   PetscCall(PetscMalloc1(VEC_OFFSET + 2 + max_k, &gmres->mwork_alloc));

     64:   if (gmres->q_preallocate) {
     65:     gmres->vv_allocated = VEC_OFFSET + 2 + max_k;

     67:     PetscCall(KSPCreateVecs(ksp, gmres->vv_allocated, &gmres->user_work[0], 0, NULL));

     69:     gmres->mwork_alloc[0] = gmres->vv_allocated;
     70:     gmres->nwork_alloc    = 1;
     71:     for (k = 0; k < gmres->vv_allocated; k++) gmres->vecs[k] = gmres->user_work[0][k];
     72:   } else {
     73:     gmres->vv_allocated = 5;

     75:     PetscCall(KSPCreateVecs(ksp, 5, &gmres->user_work[0], 0, NULL));

     77:     gmres->mwork_alloc[0] = 5;
     78:     gmres->nwork_alloc    = 1;
     79:     for (k = 0; k < gmres->vv_allocated; k++) gmres->vecs[k] = gmres->user_work[0][k];
     80:   }
     81:   PetscFunctionReturn(PETSC_SUCCESS);
     82: }

     84: /*
     85:     Run gmres, possibly with restart.  Return residual history if requested.
     86:     input parameters:

     88: .        gmres  - structure containing parameters and work areas

     90:     output parameters:
     91: .        nres    - residuals (from preconditioned system) at each step.
     92:                   If restarting, consider passing nres+it.  If null,
     93:                   ignored
     94: .        itcount - number of iterations used.  nres[0] to nres[itcount]
     95:                   are defined.  If null, ignored.

     97:     Notes:
     98:     On entry, the value in vector VEC_VV(0) should be the initial residual
     99:     (this allows shortcuts where the initial preconditioned residual is 0).
    100:  */
    101: static PetscErrorCode KSPGMRESCycle(PetscInt *itcount, KSP ksp)
    102: {
    103:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
    104:   PetscReal  res, hapbnd, tt;
    105:   PetscInt   it = 0, max_k = gmres->max_k;
    106:   PetscBool  hapend = PETSC_FALSE;

    108:   PetscFunctionBegin;
    109:   if (itcount) *itcount = 0;
    110:   PetscCall(VecNormalize(VEC_VV(0), &res));
    111:   KSPCheckNorm(ksp, res);

    113:   /* the constant .1 is arbitrary, just some measure at how incorrect the residuals are */
    114:   if ((ksp->rnorm > 0.0) && (PetscAbsReal(res - ksp->rnorm) > gmres->breakdowntol * gmres->rnorm0)) {
    115:     PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_CONV_FAILED, "Residual norm computed by GMRES recursion formula %g is far from the computed residual norm %g at restart, residual norm at start of cycle %g",
    116:                (double)ksp->rnorm, (double)res, (double)gmres->rnorm0);
    117:     PetscCall(PetscInfo(ksp, "Residual norm computed by GMRES recursion formula %g is far from the computed residual norm %g at restart, residual norm at start of cycle %g\n", (double)ksp->rnorm, (double)res, (double)gmres->rnorm0));
    118:     ksp->reason = KSP_DIVERGED_BREAKDOWN;
    119:     PetscFunctionReturn(PETSC_SUCCESS);
    120:   }
    121:   *GRS(0) = gmres->rnorm0 = res;

    123:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
    124:   ksp->rnorm = res;
    125:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
    126:   gmres->it = (it - 1);
    127:   PetscCall(KSPLogResidualHistory(ksp, res));
    128:   PetscCall(KSPLogErrorHistory(ksp));
    129:   PetscCall(KSPMonitor(ksp, ksp->its, res));
    130:   if (!res) {
    131:     ksp->reason = KSP_CONVERGED_ATOL;
    132:     PetscCall(PetscInfo(ksp, "Converged due to zero residual norm on entry\n"));
    133:     PetscFunctionReturn(PETSC_SUCCESS);
    134:   }

    136:   /* check for the convergence */
    137:   PetscCall((*ksp->converged)(ksp, ksp->its, res, &ksp->reason, ksp->cnvP));
    138:   while (!ksp->reason && it < max_k && ksp->its < ksp->max_it) {
    139:     if (it) {
    140:       PetscCall(KSPLogResidualHistory(ksp, res));
    141:       PetscCall(KSPLogErrorHistory(ksp));
    142:       PetscCall(KSPMonitor(ksp, ksp->its, res));
    143:     }
    144:     gmres->it = (it - 1);
    145:     if (gmres->vv_allocated <= it + VEC_OFFSET + 1) PetscCall(KSPGMRESGetNewVectors(ksp, it + 1));
    146:     PetscCall(KSP_PCApplyBAorAB(ksp, VEC_VV(it), VEC_VV(1 + it), VEC_TEMP_MATOP));

    148:     /* update Hessenberg matrix and do Gram-Schmidt */
    149:     PetscCall((*gmres->orthog)(ksp, it));
    150:     if (ksp->reason) break;

    152:     /* vv(i+1) . vv(i+1) */
    153:     PetscCall(VecNormalize(VEC_VV(it + 1), &tt));
    154:     KSPCheckNorm(ksp, tt);

    156:     /* save the magnitude */
    157:     *HH(it + 1, it)  = tt;
    158:     *HES(it + 1, it) = tt;

    160:     /* check for the happy breakdown */
    161:     hapbnd = PetscAbsScalar(tt / *GRS(it));
    162:     if (hapbnd > gmres->haptol) hapbnd = gmres->haptol;
    163:     if (tt < hapbnd) {
    164:       PetscCall(PetscInfo(ksp, "Detected happy ending, current hapbnd = %14.12e tt = %14.12e\n", (double)hapbnd, (double)tt));
    165:       hapend = PETSC_TRUE;
    166:     }
    167:     PetscCall(KSPGMRESUpdateHessenberg(ksp, it, hapend, &res));

    169:     it++;
    170:     gmres->it = (it - 1); /* For converged */
    171:     ksp->its++;
    172:     ksp->rnorm = res;
    173:     if (ksp->reason) break;

    175:     PetscCall((*ksp->converged)(ksp, ksp->its, res, &ksp->reason, ksp->cnvP));

    177:     /* Catch error in happy breakdown and signal convergence and break from loop */
    178:     if (hapend) {
    179:       if (ksp->normtype == KSP_NORM_NONE) { /* convergence test was skipped in this case */
    180:         ksp->reason = KSP_CONVERGED_HAPPY_BREAKDOWN;
    181:       } else if (!ksp->reason) {
    182:         PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "Reached happy break down, but convergence was not indicated. Residual norm = %g", (double)res);
    183:         ksp->reason = KSP_DIVERGED_BREAKDOWN;
    184:         break;
    185:       }
    186:     }
    187:   }

    189:   if (itcount) *itcount = it;

    191:   /*
    192:     Down here we have to solve for the "best" coefficients of the Krylov
    193:     columns, add the solution values together, and possibly unwind the
    194:     preconditioning from the solution
    195:    */
    196:   /* Form the solution (or the solution so far) */
    197:   PetscCall(KSPGMRESBuildSoln(GRS(0), ksp->vec_sol, ksp->vec_sol, ksp, it - 1));

    199:   /* Monitor if we know that we will not return for a restart */
    200:   if (ksp->reason == KSP_CONVERGED_ITERATING && ksp->its >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
    201:   if (it && ksp->reason) {
    202:     PetscCall(KSPLogResidualHistory(ksp, res));
    203:     PetscCall(KSPLogErrorHistory(ksp));
    204:     PetscCall(KSPMonitor(ksp, ksp->its, res));
    205:   }
    206:   PetscFunctionReturn(PETSC_SUCCESS);
    207: }

    209: static PetscErrorCode KSPSolve_GMRES(KSP ksp)
    210: {
    211:   PetscInt   its, itcount, i;
    212:   KSP_GMRES *gmres      = (KSP_GMRES *)ksp->data;
    213:   PetscBool  guess_zero = ksp->guess_zero;
    214:   PetscInt   N          = gmres->max_k + 1;

    216:   PetscFunctionBegin;
    217:   PetscCheck(!ksp->calc_sings || gmres->Rsvd, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ORDER, "Must call KSPSetComputeSingularValues() before KSPSetUp() is called");

    219:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
    220:   ksp->its = 0;
    221:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));

    223:   itcount          = 0;
    224:   gmres->fullcycle = 0;
    225:   ksp->rnorm       = -1.0; /* special marker for KSPGMRESCycle() */
    226:   while (!ksp->reason || (ksp->rnorm == -1 && ksp->reason == KSP_DIVERGED_PC_FAILED)) {
    227:     PetscCall(KSPInitialResidual(ksp, ksp->vec_sol, VEC_TEMP, VEC_TEMP_MATOP, VEC_VV(0), ksp->vec_rhs));
    228:     PetscCall(KSPGMRESCycle(&its, ksp));
    229:     /* Store the Hessenberg matrix and the basis vectors of the Krylov subspace
    230:     if the cycle is complete for the computation of the Ritz pairs */
    231:     if (its == gmres->max_k) {
    232:       gmres->fullcycle++;
    233:       if (ksp->calc_ritz) {
    234:         if (!gmres->hes_ritz) {
    235:           PetscCall(PetscMalloc1(N * N, &gmres->hes_ritz));
    236:           PetscCall(VecDuplicateVecs(VEC_VV(0), N, &gmres->vecb));
    237:         }
    238:         PetscCall(PetscArraycpy(gmres->hes_ritz, gmres->hes_origin, N * N));
    239:         for (i = 0; i < gmres->max_k + 1; i++) PetscCall(VecCopy(VEC_VV(i), gmres->vecb[i]));
    240:       }
    241:     }
    242:     itcount += its;
    243:     if (itcount >= ksp->max_it) {
    244:       if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS;
    245:       break;
    246:     }
    247:     ksp->guess_zero = PETSC_FALSE; /* every future call to KSPInitialResidual() will have nonzero guess */
    248:   }
    249:   ksp->guess_zero = guess_zero; /* restore if user provided nonzero initial guess */
    250:   PetscFunctionReturn(PETSC_SUCCESS);
    251: }

    253: PetscErrorCode KSPReset_GMRES(KSP ksp)
    254: {
    255:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
    256:   PetscInt   i;

    258:   PetscFunctionBegin;
    259:   /* Free the Hessenberg matrices */
    260:   PetscCall(PetscFree5(gmres->hh_origin, gmres->hes_origin, gmres->rs_origin, gmres->cc_origin, gmres->ss_origin));
    261:   PetscCall(PetscFree(gmres->hes_ritz));

    263:   /* free work vectors */
    264:   PetscCall(PetscFree(gmres->vecs));
    265:   for (i = 0; i < gmres->nwork_alloc; i++) PetscCall(VecDestroyVecs(gmres->mwork_alloc[i], &gmres->user_work[i]));
    266:   gmres->nwork_alloc = 0;
    267:   if (gmres->vecb) PetscCall(VecDestroyVecs(gmres->max_k + 1, &gmres->vecb));

    269:   PetscCall(PetscFree(gmres->user_work));
    270:   PetscCall(PetscFree(gmres->mwork_alloc));
    271:   PetscCall(PetscFree(gmres->nrs));
    272:   PetscCall(VecDestroy(&gmres->sol_temp));
    273:   PetscCall(PetscFree(gmres->Rsvd));
    274:   PetscCall(PetscFree(gmres->Dsvd));
    275:   PetscCall(PetscFree(gmres->orthogwork));

    277:   gmres->vv_allocated   = 0;
    278:   gmres->vecs_allocated = 0;
    279:   gmres->sol_temp       = NULL;
    280:   PetscFunctionReturn(PETSC_SUCCESS);
    281: }

    283: PetscErrorCode KSPDestroy_GMRES(KSP ksp)
    284: {
    285:   PetscFunctionBegin;
    286:   PetscCall(KSPReset_GMRES(ksp));
    287:   PetscCall(PetscFree(ksp->data));
    288:   /* clear composed functions */
    289:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetPreAllocateVectors_C", NULL));
    290:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetOrthogonalization_C", NULL));
    291:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetOrthogonalization_C", NULL));
    292:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetRestart_C", NULL));
    293:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetRestart_C", NULL));
    294:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetHapTol_C", NULL));
    295:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetBreakdownTolerance_C", NULL));
    296:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetCGSRefinementType_C", NULL));
    297:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetCGSRefinementType_C", NULL));
    298:   PetscFunctionReturn(PETSC_SUCCESS);
    299: }
    300: /*
    301:     KSPGMRESBuildSoln - create the solution from the starting vector and the
    302:     current iterates.

    304:     Input parameters:
    305:         nrs - work area of size it + 1.
    306:         vs  - index of initial guess
    307:         vdest - index of result.  Note that vs may == vdest (replace
    308:                 guess with the solution).

    310:      This is an internal routine that knows about the GMRES internals.
    311:  */
    312: static PetscErrorCode KSPGMRESBuildSoln(PetscScalar *nrs, Vec vs, Vec vdest, KSP ksp, PetscInt it)
    313: {
    314:   PetscScalar tt;
    315:   PetscInt    ii, k, j;
    316:   KSP_GMRES  *gmres = (KSP_GMRES *)ksp->data;

    318:   PetscFunctionBegin;
    319:   /* Solve for solution vector that minimizes the residual */

    321:   /* If it is < 0, no gmres steps have been performed */
    322:   if (it < 0) {
    323:     PetscCall(VecCopy(vs, vdest)); /* VecCopy() is smart, exists immediately if vguess == vdest */
    324:     PetscFunctionReturn(PETSC_SUCCESS);
    325:   }
    326:   if (*HH(it, it) != 0.0) {
    327:     nrs[it] = *GRS(it) / *HH(it, it);
    328:   } else {
    329:     PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "You reached the break down in GMRES; HH(it,it) = 0");
    330:     ksp->reason = KSP_DIVERGED_BREAKDOWN;

    332:     PetscCall(PetscInfo(ksp, "Likely your matrix or preconditioner is singular. HH(it,it) is identically zero; it = %" PetscInt_FMT " GRS(it) = %g\n", it, (double)PetscAbsScalar(*GRS(it))));
    333:     PetscFunctionReturn(PETSC_SUCCESS);
    334:   }
    335:   for (ii = 1; ii <= it; ii++) {
    336:     k  = it - ii;
    337:     tt = *GRS(k);
    338:     for (j = k + 1; j <= it; j++) tt = tt - *HH(k, j) * nrs[j];
    339:     if (*HH(k, k) == 0.0) {
    340:       PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "Likely your matrix or preconditioner is singular. HH(k,k) is identically zero; k = %" PetscInt_FMT, k);
    341:       ksp->reason = KSP_DIVERGED_BREAKDOWN;
    342:       PetscCall(PetscInfo(ksp, "Likely your matrix or preconditioner is singular. HH(k,k) is identically zero; k = %" PetscInt_FMT "\n", k));
    343:       PetscFunctionReturn(PETSC_SUCCESS);
    344:     }
    345:     nrs[k] = tt / *HH(k, k);
    346:   }

    348:   /* Accumulate the correction to the solution of the preconditioned problem in TEMP */
    349:   PetscCall(VecMAXPBY(VEC_TEMP, it + 1, nrs, 0, &VEC_VV(0)));

    351:   PetscCall(KSPUnwindPreconditioner(ksp, VEC_TEMP, VEC_TEMP_MATOP));
    352:   /* add solution to previous solution */
    353:   if (vdest != vs) PetscCall(VecCopy(vs, vdest));
    354:   PetscCall(VecAXPY(vdest, 1.0, VEC_TEMP));
    355:   PetscFunctionReturn(PETSC_SUCCESS);
    356: }
    357: /*
    358:    Do the scalar work for the orthogonalization.  Return new residual norm.
    359:  */
    360: static PetscErrorCode KSPGMRESUpdateHessenberg(KSP ksp, PetscInt it, PetscBool hapend, PetscReal *res)
    361: {
    362:   PetscScalar *hh, *cc, *ss, tt;
    363:   PetscInt     j;
    364:   KSP_GMRES   *gmres = (KSP_GMRES *)ksp->data;

    366:   PetscFunctionBegin;
    367:   hh = HH(0, it);
    368:   cc = CC(0);
    369:   ss = SS(0);

    371:   /* Apply all the previously computed plane rotations to the new column
    372:      of the Hessenberg matrix */
    373:   for (j = 1; j <= it; j++) {
    374:     tt  = *hh;
    375:     *hh = PetscConj(*cc) * tt + *ss * *(hh + 1);
    376:     hh++;
    377:     *hh = *cc++ * *hh - (*ss++ * tt);
    378:   }

    380:   /*
    381:     compute the new plane rotation, and apply it to:
    382:      1) the right-hand side of the Hessenberg system
    383:      2) the new column of the Hessenberg matrix
    384:     thus obtaining the updated value of the residual
    385:   */
    386:   if (!hapend) {
    387:     tt = PetscSqrtScalar(PetscConj(*hh) * *hh + PetscConj(*(hh + 1)) * *(hh + 1));
    388:     if (tt == 0.0) {
    389:       PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "tt == 0.0");
    390:       ksp->reason = KSP_DIVERGED_NULL;
    391:       PetscFunctionReturn(PETSC_SUCCESS);
    392:     }
    393:     *cc          = *hh / tt;
    394:     *ss          = *(hh + 1) / tt;
    395:     *GRS(it + 1) = -(*ss * *GRS(it));
    396:     *GRS(it)     = PetscConj(*cc) * *GRS(it);
    397:     *hh          = PetscConj(*cc) * *hh + *ss * *(hh + 1);
    398:     *res         = PetscAbsScalar(*GRS(it + 1));
    399:   } else {
    400:     /* happy breakdown: HH(it+1, it) = 0, therefore we don't need to apply
    401:             another rotation matrix (so RH doesn't change).  The new residual is
    402:             always the new sine term times the residual from last time (GRS(it)),
    403:             but now the new sine rotation would be zero...so the residual should
    404:             be zero...so we will multiply "zero" by the last residual.  This might
    405:             not be exactly what we want to do here -could just return "zero". */

    407:     *res = 0.0;
    408:   }
    409:   PetscFunctionReturn(PETSC_SUCCESS);
    410: }
    411: /*
    412:    This routine allocates more work vectors, starting from VEC_VV(it).
    413:  */
    414: PetscErrorCode KSPGMRESGetNewVectors(KSP ksp, PetscInt it)
    415: {
    416:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
    417:   PetscInt   nwork = gmres->nwork_alloc, k, nalloc;

    419:   PetscFunctionBegin;
    420:   nalloc = PetscMin(ksp->max_it, gmres->delta_allocate);
    421:   /* Adjust the number to allocate to make sure that we don't exceed the
    422:     number of available slots */
    423:   if (it + VEC_OFFSET + nalloc >= gmres->vecs_allocated) nalloc = gmres->vecs_allocated - it - VEC_OFFSET;
    424:   if (!nalloc) PetscFunctionReturn(PETSC_SUCCESS);

    426:   gmres->vv_allocated += nalloc;

    428:   PetscCall(KSPCreateVecs(ksp, nalloc, &gmres->user_work[nwork], 0, NULL));

    430:   gmres->mwork_alloc[nwork] = nalloc;
    431:   for (k = 0; k < nalloc; k++) gmres->vecs[it + VEC_OFFSET + k] = gmres->user_work[nwork][k];
    432:   gmres->nwork_alloc++;
    433:   PetscFunctionReturn(PETSC_SUCCESS);
    434: }

    436: static PetscErrorCode KSPBuildSolution_GMRES(KSP ksp, Vec ptr, Vec *result)
    437: {
    438:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;

    440:   PetscFunctionBegin;
    441:   if (!ptr) {
    442:     if (!gmres->sol_temp) PetscCall(VecDuplicate(ksp->vec_sol, &gmres->sol_temp));
    443:     ptr = gmres->sol_temp;
    444:   }
    445:   if (!gmres->nrs) {
    446:     /* allocate the work area */
    447:     PetscCall(PetscMalloc1(gmres->max_k, &gmres->nrs));
    448:   }

    450:   PetscCall(KSPGMRESBuildSoln(gmres->nrs, ksp->vec_sol, ptr, ksp, gmres->it));
    451:   if (result) *result = ptr;
    452:   PetscFunctionReturn(PETSC_SUCCESS);
    453: }

    455: PetscErrorCode KSPView_GMRES(KSP ksp, PetscViewer viewer)
    456: {
    457:   KSP_GMRES  *gmres = (KSP_GMRES *)ksp->data;
    458:   const char *cstr;
    459:   PetscBool   iascii, isstring;

    461:   PetscFunctionBegin;
    462:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    463:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
    464:   if (gmres->orthog == KSPGMRESClassicalGramSchmidtOrthogonalization) {
    465:     switch (gmres->cgstype) {
    466:     case (KSP_GMRES_CGS_REFINE_NEVER):
    467:       cstr = "Classical (unmodified) Gram-Schmidt Orthogonalization with no iterative refinement";
    468:       break;
    469:     case (KSP_GMRES_CGS_REFINE_ALWAYS):
    470:       cstr = "Classical (unmodified) Gram-Schmidt Orthogonalization with one step of iterative refinement";
    471:       break;
    472:     case (KSP_GMRES_CGS_REFINE_IFNEEDED):
    473:       cstr = "Classical (unmodified) Gram-Schmidt Orthogonalization with one step of iterative refinement when needed";
    474:       break;
    475:     default:
    476:       SETERRQ(PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_OUTOFRANGE, "Unknown orthogonalization");
    477:     }
    478:   } else if (gmres->orthog == KSPGMRESModifiedGramSchmidtOrthogonalization) {
    479:     cstr = "Modified Gram-Schmidt Orthogonalization";
    480:   } else {
    481:     cstr = "unknown orthogonalization";
    482:   }
    483:   if (iascii) {
    484:     PetscCall(PetscViewerASCIIPrintf(viewer, "  restart=%" PetscInt_FMT ", using %s\n", gmres->max_k, cstr));
    485:     PetscCall(PetscViewerASCIIPrintf(viewer, "  happy breakdown tolerance %g\n", (double)gmres->haptol));
    486:   } else if (isstring) {
    487:     PetscCall(PetscViewerStringSPrintf(viewer, "%s restart %" PetscInt_FMT, cstr, gmres->max_k));
    488:   }
    489:   PetscFunctionReturn(PETSC_SUCCESS);
    490: }

    492: /*@C
    493:   KSPGMRESMonitorKrylov - Calls `VecView()` to monitor each new direction in the `KSPGMRES` accumulated Krylov space.

    495:   Collective

    497:   Input Parameters:
    498: + ksp    - the `KSP` context
    499: . its    - iteration number
    500: . fgnorm - 2-norm of residual (or gradient)
    501: - dummy  - a collection of viewers created with `PetscViewersCreate()`

    503:   Options Database Key:
    504: . -ksp_gmres_krylov_monitor <bool> - Plot the Krylov directions

    506:   Level: intermediate

    508:   Note:
    509:   A new `PETSCVIEWERDRAW` is created for each Krylov vector so they can all be simultaneously viewed

    511: .seealso: [](ch_ksp), `KSPGMRES`, `KSPMonitorSet()`, `KSPMonitorResidual()`, `VecView()`, `PetscViewersCreate()`, `PetscViewersDestroy()`
    512: @*/
    513: PetscErrorCode KSPGMRESMonitorKrylov(KSP ksp, PetscInt its, PetscReal fgnorm, void *dummy)
    514: {
    515:   PetscViewers viewers = (PetscViewers)dummy;
    516:   KSP_GMRES   *gmres   = (KSP_GMRES *)ksp->data;
    517:   Vec          x;
    518:   PetscViewer  viewer;
    519:   PetscBool    flg;

    521:   PetscFunctionBegin;
    522:   PetscCall(PetscViewersGetViewer(viewers, gmres->it + 1, &viewer));
    523:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &flg));
    524:   if (!flg) {
    525:     PetscCall(PetscViewerSetType(viewer, PETSCVIEWERDRAW));
    526:     PetscCall(PetscViewerDrawSetInfo(viewer, NULL, "Krylov GMRES Monitor", PETSC_DECIDE, PETSC_DECIDE, 300, 300));
    527:   }
    528:   x = VEC_VV(gmres->it + 1);
    529:   PetscCall(VecView(x, viewer));
    530:   PetscFunctionReturn(PETSC_SUCCESS);
    531: }

    533: PetscErrorCode KSPSetFromOptions_GMRES(KSP ksp, PetscOptionItems *PetscOptionsObject)
    534: {
    535:   PetscInt   restart;
    536:   PetscReal  haptol, breakdowntol;
    537:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
    538:   PetscBool  flg;

    540:   PetscFunctionBegin;
    541:   PetscOptionsHeadBegin(PetscOptionsObject, "KSP GMRES Options");
    542:   PetscCall(PetscOptionsInt("-ksp_gmres_restart", "Number of Krylov search directions", "KSPGMRESSetRestart", gmres->max_k, &restart, &flg));
    543:   if (flg) PetscCall(KSPGMRESSetRestart(ksp, restart));
    544:   PetscCall(PetscOptionsReal("-ksp_gmres_haptol", "Tolerance for exact convergence (happy ending)", "KSPGMRESSetHapTol", gmres->haptol, &haptol, &flg));
    545:   if (flg) PetscCall(KSPGMRESSetHapTol(ksp, haptol));
    546:   PetscCall(PetscOptionsReal("-ksp_gmres_breakdown_tolerance", "Divergence breakdown tolerance during GMRES restart", "KSPGMRESSetBreakdownTolerance", gmres->breakdowntol, &breakdowntol, &flg));
    547:   if (flg) PetscCall(KSPGMRESSetBreakdownTolerance(ksp, breakdowntol));
    548:   flg = PETSC_FALSE;
    549:   PetscCall(PetscOptionsBool("-ksp_gmres_preallocate", "Preallocate Krylov vectors", "KSPGMRESSetPreAllocateVectors", flg, &flg, NULL));
    550:   if (flg) PetscCall(KSPGMRESSetPreAllocateVectors(ksp));
    551:   PetscCall(PetscOptionsBoolGroupBegin("-ksp_gmres_classicalgramschmidt", "Classical (unmodified) Gram-Schmidt (fast)", "KSPGMRESSetOrthogonalization", &flg));
    552:   if (flg) PetscCall(KSPGMRESSetOrthogonalization(ksp, KSPGMRESClassicalGramSchmidtOrthogonalization));
    553:   PetscCall(PetscOptionsBoolGroupEnd("-ksp_gmres_modifiedgramschmidt", "Modified Gram-Schmidt (slow,more stable)", "KSPGMRESSetOrthogonalization", &flg));
    554:   if (flg) PetscCall(KSPGMRESSetOrthogonalization(ksp, KSPGMRESModifiedGramSchmidtOrthogonalization));
    555:   PetscCall(PetscOptionsEnum("-ksp_gmres_cgs_refinement_type", "Type of iterative refinement for classical (unmodified) Gram-Schmidt", "KSPGMRESSetCGSRefinementType", KSPGMRESCGSRefinementTypes, (PetscEnum)gmres->cgstype, (PetscEnum *)&gmres->cgstype, &flg));
    556:   flg = PETSC_FALSE;
    557:   PetscCall(PetscOptionsBool("-ksp_gmres_krylov_monitor", "Plot the Krylov directions", "KSPMonitorSet", flg, &flg, NULL));
    558:   if (flg) {
    559:     PetscViewers viewers;
    560:     PetscCall(PetscViewersCreate(PetscObjectComm((PetscObject)ksp), &viewers));
    561:     PetscCall(KSPMonitorSet(ksp, KSPGMRESMonitorKrylov, viewers, (PetscErrorCode (*)(void **))PetscViewersDestroy));
    562:   }
    563:   PetscOptionsHeadEnd();
    564:   PetscFunctionReturn(PETSC_SUCCESS);
    565: }

    567: PetscErrorCode KSPGMRESSetHapTol_GMRES(KSP ksp, PetscReal tol)
    568: {
    569:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;

    571:   PetscFunctionBegin;
    572:   PetscCheck(tol >= 0.0, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_OUTOFRANGE, "Tolerance must be non-negative");
    573:   gmres->haptol = tol;
    574:   PetscFunctionReturn(PETSC_SUCCESS);
    575: }

    577: static PetscErrorCode KSPGMRESSetBreakdownTolerance_GMRES(KSP ksp, PetscReal tol)
    578: {
    579:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;

    581:   PetscFunctionBegin;
    582:   if (tol == (PetscReal)PETSC_DEFAULT) {
    583:     gmres->breakdowntol = 0.1;
    584:     PetscFunctionReturn(PETSC_SUCCESS);
    585:   }
    586:   PetscCheck(tol >= 0.0, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_OUTOFRANGE, "Breakdown tolerance must be non-negative");
    587:   gmres->breakdowntol = tol;
    588:   PetscFunctionReturn(PETSC_SUCCESS);
    589: }

    591: PetscErrorCode KSPGMRESGetRestart_GMRES(KSP ksp, PetscInt *max_k)
    592: {
    593:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;

    595:   PetscFunctionBegin;
    596:   *max_k = gmres->max_k;
    597:   PetscFunctionReturn(PETSC_SUCCESS);
    598: }

    600: PetscErrorCode KSPGMRESSetRestart_GMRES(KSP ksp, PetscInt max_k)
    601: {
    602:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;

    604:   PetscFunctionBegin;
    605:   PetscCheck(max_k >= 1, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_OUTOFRANGE, "Restart must be positive");
    606:   if (!ksp->setupstage) {
    607:     gmres->max_k = max_k;
    608:   } else if (gmres->max_k != max_k) {
    609:     gmres->max_k    = max_k;
    610:     ksp->setupstage = KSP_SETUP_NEW;
    611:     /* free the data structures, then create them again */
    612:     PetscCall(KSPReset_GMRES(ksp));
    613:   }
    614:   PetscFunctionReturn(PETSC_SUCCESS);
    615: }

    617: PetscErrorCode KSPGMRESSetOrthogonalization_GMRES(KSP ksp, FCN fcn)
    618: {
    619:   PetscFunctionBegin;
    620:   ((KSP_GMRES *)ksp->data)->orthog = fcn;
    621:   PetscFunctionReturn(PETSC_SUCCESS);
    622: }

    624: PetscErrorCode KSPGMRESGetOrthogonalization_GMRES(KSP ksp, FCN *fcn)
    625: {
    626:   PetscFunctionBegin;
    627:   *fcn = ((KSP_GMRES *)ksp->data)->orthog;
    628:   PetscFunctionReturn(PETSC_SUCCESS);
    629: }

    631: PetscErrorCode KSPGMRESSetPreAllocateVectors_GMRES(KSP ksp)
    632: {
    633:   KSP_GMRES *gmres;

    635:   PetscFunctionBegin;
    636:   gmres                = (KSP_GMRES *)ksp->data;
    637:   gmres->q_preallocate = 1;
    638:   PetscFunctionReturn(PETSC_SUCCESS);
    639: }

    641: PetscErrorCode KSPGMRESSetCGSRefinementType_GMRES(KSP ksp, KSPGMRESCGSRefinementType type)
    642: {
    643:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;

    645:   PetscFunctionBegin;
    646:   gmres->cgstype = type;
    647:   PetscFunctionReturn(PETSC_SUCCESS);
    648: }

    650: PetscErrorCode KSPGMRESGetCGSRefinementType_GMRES(KSP ksp, KSPGMRESCGSRefinementType *type)
    651: {
    652:   KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;

    654:   PetscFunctionBegin;
    655:   *type = gmres->cgstype;
    656:   PetscFunctionReturn(PETSC_SUCCESS);
    657: }

    659: /*@
    660:   KSPGMRESSetCGSRefinementType - Sets the type of iterative refinement to use
    661:   in the classical Gram-Schmidt orthogonalization used by `KSPGMRES` and other PETSc GMRES implementations.

    663:   Logically Collective

    665:   Input Parameters:
    666: + ksp  - the Krylov space solver context
    667: - type - the type of refinement
    668: .vb
    669:   KSP_GMRES_CGS_REFINE_NEVER
    670:   KSP_GMRES_CGS_REFINE_IFNEEDED
    671:   KSP_GMRES_CGS_REFINE_ALWAYS
    672: .ve

    674:   Options Database Key:
    675: . -ksp_gmres_cgs_refinement_type <refine_never,refine_ifneeded,refine_always> - refinement type

    677:   Level: intermediate

    679:   Notes:
    680:   The default is `KSP_GMRES_CGS_REFINE_NEVER`

    682:   For a very small set of problems not using refinement, that is `KSP_GMRES_CGS_REFINE_NEVER` may be unstable, thus causing `KSPSolve()`
    683:   to not converge.

    685: .seealso: [](ch_ksp), `KSPGMRES`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESCGSRefinementType`, `KSPGMRESClassicalGramSchmidtOrthogonalization()`, `KSPGMRESGetCGSRefinementType()`,
    686:           `KSPGMRESGetOrthogonalization()`
    687: @*/
    688: PetscErrorCode KSPGMRESSetCGSRefinementType(KSP ksp, KSPGMRESCGSRefinementType type)
    689: {
    690:   PetscFunctionBegin;
    693:   PetscTryMethod(ksp, "KSPGMRESSetCGSRefinementType_C", (KSP, KSPGMRESCGSRefinementType), (ksp, type));
    694:   PetscFunctionReturn(PETSC_SUCCESS);
    695: }

    697: /*@
    698:   KSPGMRESGetCGSRefinementType - Gets the type of iterative refinement to use
    699:   in the classical Gram-Schmidt orthogonalization used by `KSPGMRES` and other PETSc GMRES implementations.

    701:   Not Collective

    703:   Input Parameter:
    704: . ksp - the Krylov space solver context

    706:   Output Parameter:
    707: . type - the type of refinement

    709:   Level: intermediate

    711: .seealso: [](ch_ksp), `KSPGMRES`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESCGSRefinementType`, `KSPGMRESClassicalGramSchmidtOrthogonalization()`, `KSPGMRESSetCGSRefinementType()`,
    712:           `KSPGMRESGetOrthogonalization()`
    713: @*/
    714: PetscErrorCode KSPGMRESGetCGSRefinementType(KSP ksp, KSPGMRESCGSRefinementType *type)
    715: {
    716:   PetscFunctionBegin;
    718:   PetscUseMethod(ksp, "KSPGMRESGetCGSRefinementType_C", (KSP, KSPGMRESCGSRefinementType *), (ksp, type));
    719:   PetscFunctionReturn(PETSC_SUCCESS);
    720: }

    722: /*@
    723:   KSPGMRESSetRestart - Sets number of iterations at which GMRES (`KSPGMRES`, `KSPFGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`,
    724:   and `KSPLGMRES`) restarts.

    726:   Logically Collective

    728:   Input Parameters:
    729: + ksp     - the Krylov space solver context
    730: - restart - integer restart value, this corresponds to the number of iterations of GMRES to perform before restarting

    732:   Options Database Key:
    733: . -ksp_gmres_restart <positive integer> - integer restart value

    735:   Level: intermediate

    737:   Notes:
    738:   The default value is 30.

    740:   GMRES builds a Krylov subspace of increasing size, where each new vector is orthogonalized against the previous ones using a Gram-Schmidt process.
    741:   As the size of the Krylov subspace grows, the computational cost and memory requirements increase. To mitigate this issue, GMRES methods
    742:   usually employ restart strategies, which involve periodically deleting the Krylov subspace and beginning to generate a new one. This can help reduce
    743:   the computational cost and memory usage while still maintaining convergence. The maximum size of the Krylov subspace, that is the maximum number
    744:   of vectors orthogonalized is called the `restart` parameter.

    746:   A larger restart parameter generally leads to faster convergence of GMRES but the memory usage is higher than with a smaller `restart` parameter,
    747:   as is the average time to perform each iteration. For more ill-conditioned problems a larger restart value may be necessary.

    749:   `KSPBCGS` has the advantage over `KSPGMRES` in that it does not explicitly store the Krylov space and thus does not require as much memory
    750:   as GMRES might need.

    752: .seealso: [](ch_ksp), `KSPGMRES`, `KSPSetTolerances()`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESSetPreAllocateVectors()`, `KSPGMRESGetRestart()`,
    753:           `KSPFGMRES`, `KSPLGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`
    754: @*/
    755: PetscErrorCode KSPGMRESSetRestart(KSP ksp, PetscInt restart)
    756: {
    757:   PetscFunctionBegin;

    760:   PetscTryMethod(ksp, "KSPGMRESSetRestart_C", (KSP, PetscInt), (ksp, restart));
    761:   PetscFunctionReturn(PETSC_SUCCESS);
    762: }

    764: /*@
    765:   KSPGMRESGetRestart - Gets number of iterations at which GMRES (`KSPGMRES`, `KSPFGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`,
    766:   and `KSPLGMRES`) restarts.

    768:   Not Collective

    770:   Input Parameter:
    771: . ksp - the Krylov space solver context

    773:   Output Parameter:
    774: . restart - integer restart value

    776:   Level: intermediate

    778: .seealso: [](ch_ksp), `KSPGMRES`, `KSPSetTolerances()`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESSetPreAllocateVectors()`, `KSPGMRESSetRestart()`,
    779:           `KSPFGMRES`, `KSPLGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`
    780: @*/
    781: PetscErrorCode KSPGMRESGetRestart(KSP ksp, PetscInt *restart)
    782: {
    783:   PetscFunctionBegin;
    784:   PetscUseMethod(ksp, "KSPGMRESGetRestart_C", (KSP, PetscInt *), (ksp, restart));
    785:   PetscFunctionReturn(PETSC_SUCCESS);
    786: }

    788: /*@
    789:   KSPGMRESSetHapTol - Sets the tolerance for detecting a happy ending in GMRES (`KSPGMRES`, `KSPFGMRES` and `KSPLGMRES` and others)

    791:   Logically Collective

    793:   Input Parameters:
    794: + ksp - the Krylov space solver context
    795: - tol - the tolerance for detecting a happy ending

    797:   Options Database Key:
    798: . -ksp_gmres_haptol <positive real value> - set tolerance for determining happy breakdown

    800:   Level: intermediate

    802:   Note:
    803:   Happy ending is the rare case in `KSPGMRES` where a very near zero matrix entry is generated in the upper Hessenberg matrix indicating
    804:   an 'exact' solution has been obtained. If you attempt more iterations after this point with GMRES unstable
    805:   things can happen.

    807:   The default tolerance value for detecting a happy ending with GMRES in PETSc is 1.0e-30.

    809: .seealso: [](ch_ksp), `KSPGMRES`, `KSPSetTolerances()`
    810: @*/
    811: PetscErrorCode KSPGMRESSetHapTol(KSP ksp, PetscReal tol)
    812: {
    813:   PetscFunctionBegin;
    815:   PetscTryMethod(ksp, "KSPGMRESSetHapTol_C", (KSP, PetscReal), (ksp, tol));
    816:   PetscFunctionReturn(PETSC_SUCCESS);
    817: }

    819: /*@
    820:   KSPGMRESSetBreakdownTolerance - Sets the tolerance for determining divergence breakdown in `KSPGMRES` at restart.

    822:   Logically Collective

    824:   Input Parameters:
    825: + ksp - the Krylov space solver context
    826: - tol - the tolerance

    828:   Options Database Key:
    829: . -ksp_gmres_breakdown_tolerance <positive real value> - set tolerance for determining divergence breakdown

    831:   Level: intermediate

    833:   Note:
    834:   Divergence breakdown occurs when the norm of the GMRES residual increases significantly at a restart.
    835:   This is defined to be $ | truenorm - gmresnorm | > tol * gmresnorm $ where $ gmresnorm $ is the norm computed
    836:   by the GMRES process at a restart iteration using the standard GMRES recursion formula and $ truenorm $ is computed after
    837:   the restart using the definition $ \| r \| = \| b - A x \|$.

    839:   Divergence breakdown stops the iterative solve with a `KSPConvergedReason` of `KSP_DIVERGED_BREAKDOWN` indicating the
    840:   GMRES solver has not converged.

    842:   Divergence breakdown can occur when there is an error (bug) in either the application of the matrix or the preconditioner,
    843:   or the preconditioner is extremely ill-conditioned.

    845:   The default is .1

    847: .seealso: [](ch_ksp), `KSPGMRES`, `KSPSetTolerances()`, `KSPGMRESSetHapTol()`, `KSPConvergedReason`
    848: @*/
    849: PetscErrorCode KSPGMRESSetBreakdownTolerance(KSP ksp, PetscReal tol)
    850: {
    851:   PetscFunctionBegin;
    853:   PetscTryMethod(ksp, "KSPGMRESSetBreakdownTolerance_C", (KSP, PetscReal), (ksp, tol));
    854:   PetscFunctionReturn(PETSC_SUCCESS);
    855: }

    857: /*MC
    858:      KSPGMRES - Implements the Generalized Minimal Residual method {cite}`saad.schultz:gmres` with restart for solving linear systems using `KSP`.

    860:    Options Database Keys:
    861: +   -ksp_gmres_restart <restart>                                                - the number of Krylov directions to orthogonalize against
    862: .   -ksp_gmres_haptol <tol>                                                     - sets the tolerance for happy ending (exact convergence) of GMRES `KSPGMRES`
    863: .   -ksp_gmres_preallocate                                                      - preallocate all the Krylov search directions initially (otherwise groups of
    864:                                                                                   vectors are allocated as needed)
    865: .   -ksp_gmres_classicalgramschmidt                                             - use classical (unmodified) Gram-Schmidt to orthogonalize against
    866:                                                                                   the Krylov space (fast) (the default)
    867: .   -ksp_gmres_modifiedgramschmidt                                              - use modified Gram-Schmidt in the orthogonalization (more stable, but slower)
    868: .   -ksp_gmres_cgs_refinement_type <refine_never,refine_ifneeded,refine_always> - determine if iterative refinement is used to increase the
    869:                                                                                   stability of the classical Gram-Schmidt  orthogonalization.
    870: -   -ksp_gmres_krylov_monitor                                                   - plot the Krylov space generated

    872:    Level: beginner

    874:    Note:
    875:    Left and right preconditioning are supported, but not symmetric preconditioning.

    877: .seealso: [](ch_ksp), `KSPCreate()`, `KSPSetType()`, `KSPType`, `KSP`, `KSPFGMRES`, `KSPLGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`,
    878:           `KSPGMRESSetRestart()`, `KSPGMRESSetHapTol()`, `KSPGMRESSetPreAllocateVectors()`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESGetOrthogonalization()`,
    879:           `KSPGMRESClassicalGramSchmidtOrthogonalization()`, `KSPGMRESModifiedGramSchmidtOrthogonalization()`,
    880:           `KSPGMRESCGSRefinementType`, `KSPGMRESSetCGSRefinementType()`, `KSPGMRESGetCGSRefinementType()`, `KSPGMRESMonitorKrylov()`, `KSPSetPCSide()`
    881: M*/

    883: PETSC_EXTERN PetscErrorCode KSPCreate_GMRES(KSP ksp)
    884: {
    885:   KSP_GMRES *gmres;

    887:   PetscFunctionBegin;
    888:   PetscCall(PetscNew(&gmres));
    889:   ksp->data = (void *)gmres;

    891:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_LEFT, 4));
    892:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_UNPRECONDITIONED, PC_RIGHT, 3));
    893:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_SYMMETRIC, 2));
    894:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_RIGHT, 1));
    895:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_LEFT, 1));

    897:   ksp->ops->buildsolution                = KSPBuildSolution_GMRES;
    898:   ksp->ops->setup                        = KSPSetUp_GMRES;
    899:   ksp->ops->solve                        = KSPSolve_GMRES;
    900:   ksp->ops->reset                        = KSPReset_GMRES;
    901:   ksp->ops->destroy                      = KSPDestroy_GMRES;
    902:   ksp->ops->view                         = KSPView_GMRES;
    903:   ksp->ops->setfromoptions               = KSPSetFromOptions_GMRES;
    904:   ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_GMRES;
    905:   ksp->ops->computeeigenvalues           = KSPComputeEigenvalues_GMRES;
    906:   ksp->ops->computeritz                  = KSPComputeRitz_GMRES;
    907:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetPreAllocateVectors_C", KSPGMRESSetPreAllocateVectors_GMRES));
    908:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetOrthogonalization_C", KSPGMRESSetOrthogonalization_GMRES));
    909:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetOrthogonalization_C", KSPGMRESGetOrthogonalization_GMRES));
    910:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetRestart_C", KSPGMRESSetRestart_GMRES));
    911:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetRestart_C", KSPGMRESGetRestart_GMRES));
    912:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetHapTol_C", KSPGMRESSetHapTol_GMRES));
    913:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetBreakdownTolerance_C", KSPGMRESSetBreakdownTolerance_GMRES));
    914:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetCGSRefinementType_C", KSPGMRESSetCGSRefinementType_GMRES));
    915:   PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetCGSRefinementType_C", KSPGMRESGetCGSRefinementType_GMRES));

    917:   gmres->haptol         = 1.0e-30;
    918:   gmres->breakdowntol   = 0.1;
    919:   gmres->q_preallocate  = 0;
    920:   gmres->delta_allocate = GMRES_DELTA_DIRECTIONS;
    921:   gmres->orthog         = KSPGMRESClassicalGramSchmidtOrthogonalization;
    922:   gmres->nrs            = NULL;
    923:   gmres->sol_temp       = NULL;
    924:   gmres->max_k          = GMRES_DEFAULT_MAXK;
    925:   gmres->Rsvd           = NULL;
    926:   gmres->cgstype        = KSP_GMRES_CGS_REFINE_NEVER;
    927:   gmres->orthogwork     = NULL;
    928:   PetscFunctionReturn(PETSC_SUCCESS);
    929: }