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