xref: /petsc/src/snes/impls/ngmres/ngmresfunc.c (revision dd8e379b23d2ef935d8131fb74f7eb73fef09263)
138774f0aSPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/
238774f0aSPeter Brune #include <petscblaslapack.h>
338774f0aSPeter Brune 
44936d809SStefano Zampini PetscErrorCode SNESNGMRESGetAdditiveLineSearch_Private(SNES snes, SNESLineSearch *linesearch)
54936d809SStefano Zampini {
64936d809SStefano Zampini   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
74936d809SStefano Zampini 
84936d809SStefano Zampini   PetscFunctionBegin;
94936d809SStefano Zampini   if (!ngmres->additive_linesearch) {
104936d809SStefano Zampini     const char *optionsprefix;
114936d809SStefano Zampini     PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
124936d809SStefano Zampini     PetscCall(SNESLineSearchCreate(PetscObjectComm((PetscObject)snes), &ngmres->additive_linesearch));
134936d809SStefano Zampini     PetscCall(SNESLineSearchSetSNES(ngmres->additive_linesearch, snes));
144936d809SStefano Zampini     PetscCall(SNESLineSearchSetType(ngmres->additive_linesearch, SNESLINESEARCHL2));
154936d809SStefano Zampini     PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, "snes_ngmres_additive_"));
164936d809SStefano Zampini     PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, optionsprefix));
174936d809SStefano Zampini     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ngmres->additive_linesearch, (PetscObject)snes, 1));
184936d809SStefano Zampini   }
194936d809SStefano Zampini   *linesearch = ngmres->additive_linesearch;
204936d809SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
214936d809SStefano Zampini }
224936d809SStefano Zampini 
23d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESUpdateSubspace_Private(SNES snes, PetscInt ivec, PetscInt l, Vec F, PetscReal fnorm, Vec X)
24d71ae5a4SJacob Faibussowitsch {
2538774f0aSPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
2638774f0aSPeter Brune   Vec         *Fdot   = ngmres->Fdot;
2738774f0aSPeter Brune   Vec         *Xdot   = ngmres->Xdot;
2838774f0aSPeter Brune 
2938774f0aSPeter Brune   PetscFunctionBegin;
3063a3b9bcSJacob Faibussowitsch   PetscCheck(ivec <= l, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Cannot update vector %" PetscInt_FMT " with space size %" PetscInt_FMT "!", ivec, l);
319566063dSJacob Faibussowitsch   PetscCall(VecCopy(F, Fdot[ivec]));
329566063dSJacob Faibussowitsch   PetscCall(VecCopy(X, Xdot[ivec]));
331aa26658SKarl Rupp 
3438774f0aSPeter Brune   ngmres->fnorms[ivec] = fnorm;
353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3638774f0aSPeter Brune }
3738774f0aSPeter Brune 
38d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESFormCombinedSolution_Private(SNES snes, PetscInt ivec, PetscInt l, Vec XM, Vec FM, PetscReal fMnorm, Vec X, Vec XA, Vec FA)
39d71ae5a4SJacob Faibussowitsch {
4038774f0aSPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
4138774f0aSPeter Brune   PetscInt     i, j;
4238774f0aSPeter Brune   Vec         *Fdot       = ngmres->Fdot;
4338774f0aSPeter Brune   Vec         *Xdot       = ngmres->Xdot;
4438774f0aSPeter Brune   PetscScalar *beta       = ngmres->beta;
4538774f0aSPeter Brune   PetscScalar *xi         = ngmres->xi;
4638774f0aSPeter Brune   PetscScalar  alph_total = 0.;
4738774f0aSPeter Brune   PetscReal    nu;
485ef867c2SRené Chenard   Vec          Y = snes->vec_sol_update;
4938774f0aSPeter Brune   PetscBool    changed_y, changed_w;
5038774f0aSPeter Brune 
5138774f0aSPeter Brune   PetscFunctionBegin;
5238774f0aSPeter Brune   nu = fMnorm * fMnorm;
5338774f0aSPeter Brune 
54*dd8e379bSPierre Jolivet   /* construct the right-hand side and xi factors */
55b3c6a99cSPeter Brune   if (l > 0) {
569566063dSJacob Faibussowitsch     PetscCall(VecMDotBegin(FM, l, Fdot, xi));
579566063dSJacob Faibussowitsch     PetscCall(VecMDotBegin(Fdot[ivec], l, Fdot, beta));
589566063dSJacob Faibussowitsch     PetscCall(VecMDotEnd(FM, l, Fdot, xi));
599566063dSJacob Faibussowitsch     PetscCall(VecMDotEnd(Fdot[ivec], l, Fdot, beta));
60b3c6a99cSPeter Brune     for (i = 0; i < l; i++) {
61b3c6a99cSPeter Brune       Q(i, ivec) = beta[i];
62b3c6a99cSPeter Brune       Q(ivec, i) = beta[i];
63b3c6a99cSPeter Brune     }
64b3c6a99cSPeter Brune   } else {
65b3c6a99cSPeter Brune     Q(0, 0) = ngmres->fnorms[ivec] * ngmres->fnorms[ivec];
66b3c6a99cSPeter Brune   }
67b3c6a99cSPeter Brune 
681aa26658SKarl Rupp   for (i = 0; i < l; i++) beta[i] = nu - xi[i];
691aa26658SKarl Rupp 
7038774f0aSPeter Brune   /* construct h */
7138774f0aSPeter Brune   for (j = 0; j < l; j++) {
72ad540459SPierre Jolivet     for (i = 0; i < l; i++) H(i, j) = Q(i, j) - xi[i] - xi[j] + nu;
7338774f0aSPeter Brune   }
7438774f0aSPeter Brune   if (l == 1) {
7538774f0aSPeter Brune     /* simply set alpha[0] = beta[0] / H[0, 0] */
761aa26658SKarl Rupp     if (H(0, 0) != 0.) beta[0] = beta[0] / H(0, 0);
771aa26658SKarl Rupp     else beta[0] = 0.;
7838774f0aSPeter Brune   } else {
799566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(l, &ngmres->m));
809566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(l, &ngmres->n));
8138774f0aSPeter Brune     ngmres->info  = 0;
8238774f0aSPeter Brune     ngmres->rcond = -1.;
839566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
8438774f0aSPeter Brune #if defined(PETSC_USE_COMPLEX)
85792fecdfSBarry Smith     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&ngmres->m, &ngmres->n, &ngmres->nrhs, ngmres->h, &ngmres->lda, ngmres->beta, &ngmres->ldb, ngmres->s, &ngmres->rcond, &ngmres->rank, ngmres->work, &ngmres->lwork, ngmres->rwork, &ngmres->info));
8638774f0aSPeter Brune #else
87792fecdfSBarry Smith     PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&ngmres->m, &ngmres->n, &ngmres->nrhs, ngmres->h, &ngmres->lda, ngmres->beta, &ngmres->ldb, ngmres->s, &ngmres->rcond, &ngmres->rank, ngmres->work, &ngmres->lwork, &ngmres->info));
8838774f0aSPeter Brune #endif
899566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPop());
9008401ef6SPierre Jolivet     PetscCheck(ngmres->info >= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "Bad argument to GELSS");
9108401ef6SPierre Jolivet     PetscCheck(ngmres->info <= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "SVD failed to converge");
9238774f0aSPeter Brune   }
93ad540459SPierre Jolivet   for (i = 0; i < l; i++) PetscCheck(!PetscIsInfOrNanScalar(beta[i]), PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "SVD generated inconsistent output");
9438774f0aSPeter Brune   alph_total = 0.;
951aa26658SKarl Rupp   for (i = 0; i < l; i++) alph_total += beta[i];
961aa26658SKarl Rupp 
979566063dSJacob Faibussowitsch   PetscCall(VecCopy(XM, XA));
989566063dSJacob Faibussowitsch   PetscCall(VecScale(XA, 1. - alph_total));
999566063dSJacob Faibussowitsch   PetscCall(VecMAXPY(XA, l, beta, Xdot));
10038774f0aSPeter Brune   /* check the validity of the step */
1019566063dSJacob Faibussowitsch   PetscCall(VecCopy(XA, Y));
1029566063dSJacob Faibussowitsch   PetscCall(VecAXPY(Y, -1.0, X));
1039566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchPostCheck(snes->linesearch, X, Y, XA, &changed_y, &changed_w));
10446159c86SPeter Brune   if (!ngmres->approxfunc) {
105efd4aadfSBarry Smith     if (snes->npc && snes->npcside == PC_LEFT) {
1069566063dSJacob Faibussowitsch       PetscCall(SNESApplyNPC(snes, XA, NULL, FA));
10746159c86SPeter Brune     } else {
1089566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, XA, FA));
10946159c86SPeter Brune     }
11035f895b4SBarry Smith   } else {
1119566063dSJacob Faibussowitsch     PetscCall(VecCopy(FM, FA));
1129566063dSJacob Faibussowitsch     PetscCall(VecScale(FA, 1. - alph_total));
1139566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(FA, l, beta, Fdot));
114077c4231SPeter Brune   }
1153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11638774f0aSPeter Brune }
11738774f0aSPeter Brune 
118d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESNorms_Private(SNES snes, PetscInt l, Vec X, Vec F, Vec XM, Vec FM, Vec XA, Vec FA, Vec D, PetscReal *dnorm, PetscReal *dminnorm, PetscReal *xMnorm, PetscReal *fMnorm, PetscReal *yMnorm, PetscReal *xAnorm, PetscReal *fAnorm, PetscReal *yAnorm)
119d71ae5a4SJacob Faibussowitsch {
12038774f0aSPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
121b3c6a99cSPeter Brune   PetscReal    dcurnorm, dmin = -1.0;
12238774f0aSPeter Brune   Vec         *Xdot = ngmres->Xdot;
12338774f0aSPeter Brune   PetscInt     i;
12438774f0aSPeter Brune 
12538774f0aSPeter Brune   PetscFunctionBegin;
1261baa6e33SBarry Smith   if (xMnorm) PetscCall(VecNormBegin(XM, NORM_2, xMnorm));
1271baa6e33SBarry Smith   if (fMnorm) PetscCall(VecNormBegin(FM, NORM_2, fMnorm));
128b3c6a99cSPeter Brune   if (yMnorm) {
1299566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, D));
1309566063dSJacob Faibussowitsch     PetscCall(VecAXPY(D, -1.0, XM));
1319566063dSJacob Faibussowitsch     PetscCall(VecNormBegin(D, NORM_2, yMnorm));
132b3c6a99cSPeter Brune   }
1331baa6e33SBarry Smith   if (xAnorm) PetscCall(VecNormBegin(XA, NORM_2, xAnorm));
1341baa6e33SBarry Smith   if (fAnorm) PetscCall(VecNormBegin(FA, NORM_2, fAnorm));
135b3c6a99cSPeter Brune   if (yAnorm) {
1369566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, D));
1379566063dSJacob Faibussowitsch     PetscCall(VecAXPY(D, -1.0, XA));
1389566063dSJacob Faibussowitsch     PetscCall(VecNormBegin(D, NORM_2, yAnorm));
139b3c6a99cSPeter Brune   }
14038774f0aSPeter Brune   if (dnorm) {
1419566063dSJacob Faibussowitsch     PetscCall(VecCopy(XA, D));
1429566063dSJacob Faibussowitsch     PetscCall(VecAXPY(D, -1.0, XM));
1439566063dSJacob Faibussowitsch     PetscCall(VecNormBegin(D, NORM_2, dnorm));
14438774f0aSPeter Brune   }
14538774f0aSPeter Brune   if (dminnorm) {
14638774f0aSPeter Brune     for (i = 0; i < l; i++) {
1479566063dSJacob Faibussowitsch       PetscCall(VecCopy(Xdot[i], D));
1489566063dSJacob Faibussowitsch       PetscCall(VecAXPY(D, -1.0, XA));
1499566063dSJacob Faibussowitsch       PetscCall(VecNormBegin(D, NORM_2, &ngmres->xnorms[i]));
15038774f0aSPeter Brune     }
15138774f0aSPeter Brune   }
1529566063dSJacob Faibussowitsch   if (xMnorm) PetscCall(VecNormEnd(XM, NORM_2, xMnorm));
1539566063dSJacob Faibussowitsch   if (fMnorm) PetscCall(VecNormEnd(FM, NORM_2, fMnorm));
1549566063dSJacob Faibussowitsch   if (yMnorm) PetscCall(VecNormEnd(D, NORM_2, yMnorm));
1559566063dSJacob Faibussowitsch   if (xAnorm) PetscCall(VecNormEnd(XA, NORM_2, xAnorm));
1569566063dSJacob Faibussowitsch   if (fAnorm) PetscCall(VecNormEnd(FA, NORM_2, fAnorm));
1579566063dSJacob Faibussowitsch   if (yAnorm) PetscCall(VecNormEnd(D, NORM_2, yAnorm));
1589566063dSJacob Faibussowitsch   if (dnorm) PetscCall(VecNormEnd(D, NORM_2, dnorm));
15938774f0aSPeter Brune   if (dminnorm) {
16038774f0aSPeter Brune     for (i = 0; i < l; i++) {
1619566063dSJacob Faibussowitsch       PetscCall(VecNormEnd(D, NORM_2, &ngmres->xnorms[i]));
16238774f0aSPeter Brune       dcurnorm = ngmres->xnorms[i];
163b3c6a99cSPeter Brune       if ((dcurnorm < dmin) || (dmin < 0.0)) dmin = dcurnorm;
16438774f0aSPeter Brune     }
165b3c6a99cSPeter Brune     *dminnorm = dmin;
16638774f0aSPeter Brune   }
1673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16838774f0aSPeter Brune }
16938774f0aSPeter Brune 
1704936d809SStefano Zampini PetscErrorCode SNESNGMRESSelect_Private(SNES snes, PetscInt k_restart, Vec XM, Vec FM, PetscReal xMnorm, PetscReal fMnorm, PetscReal yMnorm, PetscReal objM, Vec XA, Vec FA, PetscReal xAnorm, PetscReal fAnorm, PetscReal yAnorm, PetscReal objA, PetscReal dnorm, PetscReal objmin, PetscReal dminnorm, Vec X, Vec F, Vec Y, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm)
171d71ae5a4SJacob Faibussowitsch {
17238774f0aSPeter Brune   SNES_NGMRES         *ngmres = (SNES_NGMRES *)snes->data;
173422a814eSBarry Smith   SNESLineSearchReason lssucceed;
174422a814eSBarry Smith   PetscBool            selectA;
17538774f0aSPeter Brune 
17638774f0aSPeter Brune   PetscFunctionBegin;
17738774f0aSPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
17838774f0aSPeter Brune     /* X = X + \lambda(XA - X) */
1794936d809SStefano Zampini     if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "obj(X_A) = %e, ||F_A||_2 = %e, obj(X_M) = %e, ||F_M||_2 = %e\n", (double)objA, (double)fAnorm, (double)objM, (double)fMnorm));
1804936d809SStefano Zampini     /* Test if is XA - XM is a descent direction: we want < F(XM), XA - XM > not positive
1814936d809SStefano Zampini        If positive, GMRES will be restarted see https://epubs.siam.org/doi/pdf/10.1137/110835530 */
1829566063dSJacob Faibussowitsch     PetscCall(VecCopy(FM, F));
1839566063dSJacob Faibussowitsch     PetscCall(VecCopy(XM, X));
1844936d809SStefano Zampini     PetscCall(VecWAXPY(Y, -1.0, XA, X));                        /* minus sign since linesearch expects to find Xnew = X - lambda * Y */
1854936d809SStefano Zampini     PetscCall(VecDotRealPart(FM, Y, &ngmres->descent_ls_test)); /* this is actually < F(XM), XM - XA > */
18638774f0aSPeter Brune     *fnorm = fMnorm;
1874936d809SStefano Zampini     if (ngmres->descent_ls_test < 0) { /* XA - XM is not a descent direction, select XM */
1884936d809SStefano Zampini       *xnorm = xMnorm;
1894936d809SStefano Zampini       *fnorm = fMnorm;
1904936d809SStefano Zampini       *ynorm = yMnorm;
1914936d809SStefano Zampini       PetscCall(VecWAXPY(Y, -1.0, X, XM));
1924936d809SStefano Zampini       PetscCall(VecCopy(FM, F));
1934936d809SStefano Zampini       PetscCall(VecCopy(XM, X));
1944936d809SStefano Zampini     } else {
1954936d809SStefano Zampini       PetscCall(SNESNGMRESGetAdditiveLineSearch_Private(snes, &ngmres->additive_linesearch));
1969566063dSJacob Faibussowitsch       PetscCall(SNESLineSearchApply(ngmres->additive_linesearch, X, F, fnorm, Y));
1979566063dSJacob Faibussowitsch       PetscCall(SNESLineSearchGetReason(ngmres->additive_linesearch, &lssucceed));
1989566063dSJacob Faibussowitsch       PetscCall(SNESLineSearchGetNorms(ngmres->additive_linesearch, xnorm, fnorm, ynorm));
199422a814eSBarry Smith       if (lssucceed) {
20038774f0aSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
20138774f0aSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
2023ba16761SJacob Faibussowitsch           PetscFunctionReturn(PETSC_SUCCESS);
20338774f0aSPeter Brune         }
20438774f0aSPeter Brune       }
2054936d809SStefano Zampini     }
2064936d809SStefano Zampini     if (ngmres->monitor) {
2074936d809SStefano Zampini       PetscReal objT = *fnorm;
2084936d809SStefano Zampini       PetscErrorCode (*objective)(SNES, Vec, PetscReal *, void *);
2091aa26658SKarl Rupp 
2104936d809SStefano Zampini       PetscCall(SNESGetObjective(snes, &objective, NULL));
2114936d809SStefano Zampini       if (objective) PetscCall(SNESComputeObjective(snes, X, &objT));
2124936d809SStefano Zampini       PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: objective = %e\n", (double)objT));
2134936d809SStefano Zampini     }
2144936d809SStefano Zampini   } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
2154936d809SStefano Zampini     /* Conditions for choosing the accelerated answer:
2164936d809SStefano Zampini           Criterion A -- the objective function isn't increased above the minimum by too much
2174936d809SStefano Zampini           Criterion B -- the choice of x^A isn't too close to some other choice
2184936d809SStefano Zampini     */
2194936d809SStefano Zampini     selectA = (PetscBool)(/* A */ (objA < ngmres->gammaA * objmin) && /* B */ (ngmres->epsilonB * dnorm < dminnorm || objA < ngmres->deltaB * objmin));
2201aa26658SKarl Rupp 
22138774f0aSPeter Brune     if (selectA) {
2224936d809SStefano Zampini       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, obj(X_A) = %e, ||F_A||_2 = %e, obj(X_M) = %e, ||F_M||_2 = %e\n", (double)objA, (double)fAnorm, (double)objM, (double)fMnorm));
22338774f0aSPeter Brune       /* copy it over */
224b3c6a99cSPeter Brune       *xnorm = xAnorm;
22538774f0aSPeter Brune       *fnorm = fAnorm;
226b3c6a99cSPeter Brune       *ynorm = yAnorm;
2279566063dSJacob Faibussowitsch       PetscCall(VecCopy(FA, F));
2289566063dSJacob Faibussowitsch       PetscCall(VecCopy(XA, X));
22938774f0aSPeter Brune     } else {
2304936d809SStefano Zampini       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, obj(X_A) = %e, ||F_A||_2 = %e, obj(X_M) = %e, ||F_M||_2 = %e\n", (double)objA, (double)fAnorm, (double)objM, (double)fMnorm));
231b3c6a99cSPeter Brune       *xnorm = xMnorm;
23238774f0aSPeter Brune       *fnorm = fMnorm;
233b3c6a99cSPeter Brune       *ynorm = yMnorm;
2344936d809SStefano Zampini       PetscCall(VecWAXPY(Y, -1.0, X, XM));
2359566063dSJacob Faibussowitsch       PetscCall(VecCopy(FM, F));
2369566063dSJacob Faibussowitsch       PetscCall(VecCopy(XM, X));
23738774f0aSPeter Brune     }
23838774f0aSPeter Brune   } else { /* none */
239b3c6a99cSPeter Brune     *xnorm = xAnorm;
24038774f0aSPeter Brune     *fnorm = fAnorm;
241b3c6a99cSPeter Brune     *ynorm = yAnorm;
2429566063dSJacob Faibussowitsch     PetscCall(VecCopy(FA, F));
2439566063dSJacob Faibussowitsch     PetscCall(VecCopy(XA, X));
24438774f0aSPeter Brune   }
2453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24638774f0aSPeter Brune }
24738774f0aSPeter Brune 
2484936d809SStefano Zampini PetscErrorCode SNESNGMRESSelectRestart_Private(SNES snes, PetscInt l, PetscReal obj, PetscReal objM, PetscReal objA, PetscReal dnorm, PetscReal objmin, PetscReal dminnorm, PetscBool *selectRestart)
249d71ae5a4SJacob Faibussowitsch {
25038774f0aSPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
25138774f0aSPeter Brune 
25238774f0aSPeter Brune   PetscFunctionBegin;
25338774f0aSPeter Brune   *selectRestart = PETSC_FALSE;
2544936d809SStefano Zampini   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
2554936d809SStefano Zampini     if (ngmres->descent_ls_test < 0) { /* XA - XM is not a descent direction */
2564936d809SStefano Zampini       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "ascent restart: %e > 0\n", (double)-ngmres->descent_ls_test));
2574936d809SStefano Zampini       *selectRestart = PETSC_TRUE;
2584936d809SStefano Zampini     }
2594936d809SStefano Zampini   } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
26038774f0aSPeter Brune     /* difference stagnation restart */
2614936d809SStefano Zampini     if (ngmres->epsilonB * dnorm > dminnorm && objA > ngmres->deltaB * objmin && l > 0) {
26248a46eb9SPierre Jolivet       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", (double)(ngmres->epsilonB * dnorm), (double)dminnorm));
26338774f0aSPeter Brune       *selectRestart = PETSC_TRUE;
26438774f0aSPeter Brune     }
26538774f0aSPeter Brune     /* residual stagnation restart */
2664936d809SStefano Zampini     if (objA > ngmres->gammaC * objmin) {
2674936d809SStefano Zampini       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", (double)objA, (double)(ngmres->gammaC * objmin)));
26838774f0aSPeter Brune       *selectRestart = PETSC_TRUE;
26938774f0aSPeter Brune     }
27023b3e82cSAsbjørn Nilsen Riseth 
27123b3e82cSAsbjørn Nilsen Riseth     /* F_M stagnation restart */
2724936d809SStefano Zampini     if (ngmres->restart_fm_rise && objM > obj) {
2734936d809SStefano Zampini       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "F_M rise restart: %e > %e\n", (double)objM, (double)obj));
27423b3e82cSAsbjørn Nilsen Riseth       *selectRestart = PETSC_TRUE;
27523b3e82cSAsbjørn Nilsen Riseth     }
2764936d809SStefano Zampini   }
2773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27838774f0aSPeter Brune }
279