138774f0aSPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/
238774f0aSPeter Brune #include <petscblaslapack.h>
338774f0aSPeter Brune
SNESNGMRESGetAdditiveLineSearch_Private(SNES snes,SNESLineSearch * linesearch)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));
14a99ef635SJonas Heinzmann PetscCall(SNESLineSearchSetType(ngmres->additive_linesearch, SNESLINESEARCHSECANT));
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
SNESNGMRESUpdateSubspace_Private(SNES snes,PetscInt ivec,PetscInt l,Vec F,PetscReal fnorm,Vec X)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
SNESNGMRESFormCombinedSolution_Private(SNES snes,PetscInt ivec,PetscInt l,Vec XM,Vec FM,PetscReal fMnorm,Vec X,Vec XA,Vec FA)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
54dd8e379bSPierre 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
97647c55fdSStefano Zampini PetscCall(VecAXPBY(XA, 1.0 - alph_total, 0.0, XM));
989566063dSJacob Faibussowitsch PetscCall(VecMAXPY(XA, l, beta, Xdot));
9938774f0aSPeter Brune /* check the validity of the step */
100647c55fdSStefano Zampini PetscCall(VecWAXPY(Y, -1.0, X, XA));
1019566063dSJacob Faibussowitsch PetscCall(SNESLineSearchPostCheck(snes->linesearch, X, Y, XA, &changed_y, &changed_w));
10246159c86SPeter Brune if (!ngmres->approxfunc) {
103efd4aadfSBarry Smith if (snes->npc && snes->npcside == PC_LEFT) {
1049566063dSJacob Faibussowitsch PetscCall(SNESApplyNPC(snes, XA, NULL, FA));
10546159c86SPeter Brune } else {
1069566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, XA, FA));
10746159c86SPeter Brune }
10835f895b4SBarry Smith } else {
109647c55fdSStefano Zampini PetscCall(VecAXPBY(FA, 1.0 - alph_total, 0.0, FM));
1109566063dSJacob Faibussowitsch PetscCall(VecMAXPY(FA, l, beta, Fdot));
111077c4231SPeter Brune }
1123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
11338774f0aSPeter Brune }
11438774f0aSPeter Brune
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)115d71ae5a4SJacob 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)
116d71ae5a4SJacob Faibussowitsch {
11738774f0aSPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
118b3c6a99cSPeter Brune PetscReal dcurnorm, dmin = -1.0;
11938774f0aSPeter Brune Vec *Xdot = ngmres->Xdot;
12038774f0aSPeter Brune PetscInt i;
12138774f0aSPeter Brune
12238774f0aSPeter Brune PetscFunctionBegin;
1231baa6e33SBarry Smith if (xMnorm) PetscCall(VecNormBegin(XM, NORM_2, xMnorm));
1241baa6e33SBarry Smith if (fMnorm) PetscCall(VecNormBegin(FM, NORM_2, fMnorm));
125b3c6a99cSPeter Brune if (yMnorm) {
126647c55fdSStefano Zampini PetscCall(VecWAXPY(D, -1.0, XM, X));
1279566063dSJacob Faibussowitsch PetscCall(VecNormBegin(D, NORM_2, yMnorm));
128b3c6a99cSPeter Brune }
1291baa6e33SBarry Smith if (xAnorm) PetscCall(VecNormBegin(XA, NORM_2, xAnorm));
1301baa6e33SBarry Smith if (fAnorm) PetscCall(VecNormBegin(FA, NORM_2, fAnorm));
131b3c6a99cSPeter Brune if (yAnorm) {
132647c55fdSStefano Zampini PetscCall(VecWAXPY(D, -1.0, XA, X));
1339566063dSJacob Faibussowitsch PetscCall(VecNormBegin(D, NORM_2, yAnorm));
134b3c6a99cSPeter Brune }
13538774f0aSPeter Brune if (dnorm) {
136647c55fdSStefano Zampini PetscCall(VecWAXPY(D, -1.0, XM, XA));
1379566063dSJacob Faibussowitsch PetscCall(VecNormBegin(D, NORM_2, dnorm));
13838774f0aSPeter Brune }
13938774f0aSPeter Brune if (dminnorm) {
14038774f0aSPeter Brune for (i = 0; i < l; i++) {
141647c55fdSStefano Zampini PetscCall(VecWAXPY(D, -1.0, XA, Xdot[i]));
1429566063dSJacob Faibussowitsch PetscCall(VecNormBegin(D, NORM_2, &ngmres->xnorms[i]));
14338774f0aSPeter Brune }
14438774f0aSPeter Brune }
1459566063dSJacob Faibussowitsch if (xMnorm) PetscCall(VecNormEnd(XM, NORM_2, xMnorm));
1469566063dSJacob Faibussowitsch if (fMnorm) PetscCall(VecNormEnd(FM, NORM_2, fMnorm));
1479566063dSJacob Faibussowitsch if (yMnorm) PetscCall(VecNormEnd(D, NORM_2, yMnorm));
1489566063dSJacob Faibussowitsch if (xAnorm) PetscCall(VecNormEnd(XA, NORM_2, xAnorm));
1499566063dSJacob Faibussowitsch if (fAnorm) PetscCall(VecNormEnd(FA, NORM_2, fAnorm));
1509566063dSJacob Faibussowitsch if (yAnorm) PetscCall(VecNormEnd(D, NORM_2, yAnorm));
1519566063dSJacob Faibussowitsch if (dnorm) PetscCall(VecNormEnd(D, NORM_2, dnorm));
15238774f0aSPeter Brune if (dminnorm) {
15338774f0aSPeter Brune for (i = 0; i < l; i++) {
1549566063dSJacob Faibussowitsch PetscCall(VecNormEnd(D, NORM_2, &ngmres->xnorms[i]));
15538774f0aSPeter Brune dcurnorm = ngmres->xnorms[i];
156b3c6a99cSPeter Brune if ((dcurnorm < dmin) || (dmin < 0.0)) dmin = dcurnorm;
15738774f0aSPeter Brune }
158b3c6a99cSPeter Brune *dminnorm = dmin;
15938774f0aSPeter Brune }
1603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
16138774f0aSPeter Brune }
16238774f0aSPeter Brune
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)1634936d809SStefano 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)
164d71ae5a4SJacob Faibussowitsch {
16538774f0aSPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
166*76c63389SBarry Smith SNESLineSearchReason lsreason;
167422a814eSBarry Smith PetscBool selectA;
16838774f0aSPeter Brune
16938774f0aSPeter Brune PetscFunctionBegin;
17038774f0aSPeter Brune if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
17138774f0aSPeter Brune /* X = X + \lambda(XA - X) */
1724936d809SStefano 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));
1734936d809SStefano Zampini /* Test if is XA - XM is a descent direction: we want < F(XM), XA - XM > not positive
1744936d809SStefano Zampini If positive, GMRES will be restarted see https://epubs.siam.org/doi/pdf/10.1137/110835530 */
1759566063dSJacob Faibussowitsch PetscCall(VecCopy(FM, F));
1769566063dSJacob Faibussowitsch PetscCall(VecCopy(XM, X));
1774936d809SStefano Zampini PetscCall(VecWAXPY(Y, -1.0, XA, X)); /* minus sign since linesearch expects to find Xnew = X - lambda * Y */
1784936d809SStefano Zampini PetscCall(VecDotRealPart(FM, Y, &ngmres->descent_ls_test)); /* this is actually < F(XM), XM - XA > */
17938774f0aSPeter Brune *fnorm = fMnorm;
1804936d809SStefano Zampini if (ngmres->descent_ls_test < 0) { /* XA - XM is not a descent direction, select XM */
1814936d809SStefano Zampini *xnorm = xMnorm;
1824936d809SStefano Zampini *fnorm = fMnorm;
1834936d809SStefano Zampini *ynorm = yMnorm;
1844936d809SStefano Zampini PetscCall(VecWAXPY(Y, -1.0, X, XM));
1854936d809SStefano Zampini PetscCall(VecCopy(FM, F));
1864936d809SStefano Zampini PetscCall(VecCopy(XM, X));
1874936d809SStefano Zampini } else {
1884936d809SStefano Zampini PetscCall(SNESNGMRESGetAdditiveLineSearch_Private(snes, &ngmres->additive_linesearch));
1899566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(ngmres->additive_linesearch, X, F, fnorm, Y));
190*76c63389SBarry Smith PetscCall(SNESLineSearchGetReason(ngmres->additive_linesearch, &lsreason));
191*76c63389SBarry Smith if (lsreason == SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN) {
192*76c63389SBarry Smith PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNES solver has not converged");
193*76c63389SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
194*76c63389SBarry Smith PetscFunctionReturn(PETSC_SUCCESS);
195*76c63389SBarry Smith }
196*76c63389SBarry Smith if (lsreason == SNES_LINESEARCH_FAILED_NANORINF) {
197*76c63389SBarry Smith PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNES solver has not converged");
198*76c63389SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_NANORINF;
199*76c63389SBarry Smith PetscFunctionReturn(PETSC_SUCCESS);
200*76c63389SBarry Smith }
201*76c63389SBarry Smith if (lsreason && ++snes->numFailures >= snes->maxFailures) {
202*76c63389SBarry Smith PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNES solver has not converged");
20338774f0aSPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH;
2043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
20538774f0aSPeter Brune }
206*76c63389SBarry Smith PetscCall(SNESLineSearchGetNorms(ngmres->additive_linesearch, xnorm, fnorm, ynorm));
2074936d809SStefano Zampini }
2084936d809SStefano Zampini if (ngmres->monitor) {
2094936d809SStefano Zampini PetscReal objT = *fnorm;
2106b72add0SBarry Smith SNESObjectiveFn *objective;
2111aa26658SKarl Rupp
2124936d809SStefano Zampini PetscCall(SNESGetObjective(snes, &objective, NULL));
2134936d809SStefano Zampini if (objective) PetscCall(SNESComputeObjective(snes, X, &objT));
2144936d809SStefano Zampini PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: objective = %e\n", (double)objT));
2154936d809SStefano Zampini }
2164936d809SStefano Zampini } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
2174936d809SStefano Zampini /* Conditions for choosing the accelerated answer:
2184936d809SStefano Zampini Criterion A -- the objective function isn't increased above the minimum by too much
2194936d809SStefano Zampini Criterion B -- the choice of x^A isn't too close to some other choice
2204936d809SStefano Zampini */
2214936d809SStefano Zampini selectA = (PetscBool)(/* A */ (objA < ngmres->gammaA * objmin) && /* B */ (ngmres->epsilonB * dnorm < dminnorm || objA < ngmres->deltaB * objmin));
2221aa26658SKarl Rupp
22338774f0aSPeter Brune if (selectA) {
2244936d809SStefano 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));
22538774f0aSPeter Brune /* copy it over */
226b3c6a99cSPeter Brune *xnorm = xAnorm;
22738774f0aSPeter Brune *fnorm = fAnorm;
228b3c6a99cSPeter Brune *ynorm = yAnorm;
2299566063dSJacob Faibussowitsch PetscCall(VecCopy(FA, F));
2309566063dSJacob Faibussowitsch PetscCall(VecCopy(XA, X));
23138774f0aSPeter Brune } else {
2324936d809SStefano 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));
233b3c6a99cSPeter Brune *xnorm = xMnorm;
23438774f0aSPeter Brune *fnorm = fMnorm;
235b3c6a99cSPeter Brune *ynorm = yMnorm;
2364936d809SStefano Zampini PetscCall(VecWAXPY(Y, -1.0, X, XM));
2379566063dSJacob Faibussowitsch PetscCall(VecCopy(FM, F));
2389566063dSJacob Faibussowitsch PetscCall(VecCopy(XM, X));
23938774f0aSPeter Brune }
24038774f0aSPeter Brune } else { /* none */
241b3c6a99cSPeter Brune *xnorm = xAnorm;
24238774f0aSPeter Brune *fnorm = fAnorm;
243b3c6a99cSPeter Brune *ynorm = yAnorm;
2449566063dSJacob Faibussowitsch PetscCall(VecCopy(FA, F));
2459566063dSJacob Faibussowitsch PetscCall(VecCopy(XA, X));
24638774f0aSPeter Brune }
2473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
24838774f0aSPeter Brune }
24938774f0aSPeter Brune
SNESNGMRESSelectRestart_Private(SNES snes,PetscInt l,PetscReal obj,PetscReal objM,PetscReal objA,PetscReal dnorm,PetscReal objmin,PetscReal dminnorm,PetscBool * selectRestart)2504936d809SStefano Zampini PetscErrorCode SNESNGMRESSelectRestart_Private(SNES snes, PetscInt l, PetscReal obj, PetscReal objM, PetscReal objA, PetscReal dnorm, PetscReal objmin, PetscReal dminnorm, PetscBool *selectRestart)
251d71ae5a4SJacob Faibussowitsch {
25238774f0aSPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
25338774f0aSPeter Brune
25438774f0aSPeter Brune PetscFunctionBegin;
25538774f0aSPeter Brune *selectRestart = PETSC_FALSE;
2564936d809SStefano Zampini if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
2574936d809SStefano Zampini if (ngmres->descent_ls_test < 0) { /* XA - XM is not a descent direction */
2584936d809SStefano Zampini if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "ascent restart: %e > 0\n", (double)-ngmres->descent_ls_test));
2594936d809SStefano Zampini *selectRestart = PETSC_TRUE;
2604936d809SStefano Zampini }
2614936d809SStefano Zampini } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
26238774f0aSPeter Brune /* difference stagnation restart */
2634936d809SStefano Zampini if (ngmres->epsilonB * dnorm > dminnorm && objA > ngmres->deltaB * objmin && l > 0) {
26448a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", (double)(ngmres->epsilonB * dnorm), (double)dminnorm));
26538774f0aSPeter Brune *selectRestart = PETSC_TRUE;
26638774f0aSPeter Brune }
26738774f0aSPeter Brune /* residual stagnation restart */
2684936d809SStefano Zampini if (objA > ngmres->gammaC * objmin) {
2694936d809SStefano Zampini if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", (double)objA, (double)(ngmres->gammaC * objmin)));
27038774f0aSPeter Brune *selectRestart = PETSC_TRUE;
27138774f0aSPeter Brune }
27223b3e82cSAsbjørn Nilsen Riseth
27323b3e82cSAsbjørn Nilsen Riseth /* F_M stagnation restart */
2744936d809SStefano Zampini if (ngmres->restart_fm_rise && objM > obj) {
2754936d809SStefano Zampini if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "F_M rise restart: %e > %e\n", (double)objM, (double)obj));
27623b3e82cSAsbjørn Nilsen Riseth *selectRestart = PETSC_TRUE;
27723b3e82cSAsbjørn Nilsen Riseth }
2784936d809SStefano Zampini }
2793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
28038774f0aSPeter Brune }
281