xref: /petsc/src/snes/impls/ngmres/ngmresfunc.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
138774f0aSPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/
238774f0aSPeter Brune #include <petscblaslapack.h>
338774f0aSPeter Brune 
49371c9d4SSatish Balay PetscErrorCode SNESNGMRESUpdateSubspace_Private(SNES snes, PetscInt ivec, PetscInt l, Vec F, PetscReal fnorm, Vec X) {
538774f0aSPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
638774f0aSPeter Brune   Vec         *Fdot   = ngmres->Fdot;
738774f0aSPeter Brune   Vec         *Xdot   = ngmres->Xdot;
838774f0aSPeter Brune 
938774f0aSPeter Brune   PetscFunctionBegin;
1063a3b9bcSJacob Faibussowitsch   PetscCheck(ivec <= l, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Cannot update vector %" PetscInt_FMT " with space size %" PetscInt_FMT "!", ivec, l);
119566063dSJacob Faibussowitsch   PetscCall(VecCopy(F, Fdot[ivec]));
129566063dSJacob Faibussowitsch   PetscCall(VecCopy(X, Xdot[ivec]));
131aa26658SKarl Rupp 
1438774f0aSPeter Brune   ngmres->fnorms[ivec] = fnorm;
1538774f0aSPeter Brune   PetscFunctionReturn(0);
1638774f0aSPeter Brune }
1738774f0aSPeter Brune 
189371c9d4SSatish Balay PetscErrorCode SNESNGMRESFormCombinedSolution_Private(SNES snes, PetscInt ivec, PetscInt l, Vec XM, Vec FM, PetscReal fMnorm, Vec X, Vec XA, Vec FA) {
1938774f0aSPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
2038774f0aSPeter Brune   PetscInt     i, j;
2138774f0aSPeter Brune   Vec         *Fdot       = ngmres->Fdot;
2238774f0aSPeter Brune   Vec         *Xdot       = ngmres->Xdot;
2338774f0aSPeter Brune   PetscScalar *beta       = ngmres->beta;
2438774f0aSPeter Brune   PetscScalar *xi         = ngmres->xi;
2538774f0aSPeter Brune   PetscScalar  alph_total = 0.;
2638774f0aSPeter Brune   PetscReal    nu;
2738774f0aSPeter Brune   Vec          Y = snes->work[2];
2838774f0aSPeter Brune   PetscBool    changed_y, changed_w;
2938774f0aSPeter Brune 
3038774f0aSPeter Brune   PetscFunctionBegin;
3138774f0aSPeter Brune   nu = fMnorm * fMnorm;
3238774f0aSPeter Brune 
3338774f0aSPeter Brune   /* construct the right hand side and xi factors */
34b3c6a99cSPeter Brune   if (l > 0) {
359566063dSJacob Faibussowitsch     PetscCall(VecMDotBegin(FM, l, Fdot, xi));
369566063dSJacob Faibussowitsch     PetscCall(VecMDotBegin(Fdot[ivec], l, Fdot, beta));
379566063dSJacob Faibussowitsch     PetscCall(VecMDotEnd(FM, l, Fdot, xi));
389566063dSJacob Faibussowitsch     PetscCall(VecMDotEnd(Fdot[ivec], l, Fdot, beta));
39b3c6a99cSPeter Brune     for (i = 0; i < l; i++) {
40b3c6a99cSPeter Brune       Q(i, ivec) = beta[i];
41b3c6a99cSPeter Brune       Q(ivec, i) = beta[i];
42b3c6a99cSPeter Brune     }
43b3c6a99cSPeter Brune   } else {
44b3c6a99cSPeter Brune     Q(0, 0) = ngmres->fnorms[ivec] * ngmres->fnorms[ivec];
45b3c6a99cSPeter Brune   }
46b3c6a99cSPeter Brune 
471aa26658SKarl Rupp   for (i = 0; i < l; i++) beta[i] = nu - xi[i];
481aa26658SKarl Rupp 
4938774f0aSPeter Brune   /* construct h */
5038774f0aSPeter Brune   for (j = 0; j < l; j++) {
519371c9d4SSatish Balay     for (i = 0; i < l; i++) { H(i, j) = Q(i, j) - xi[i] - xi[j] + nu; }
5238774f0aSPeter Brune   }
5338774f0aSPeter Brune   if (l == 1) {
5438774f0aSPeter Brune     /* simply set alpha[0] = beta[0] / H[0, 0] */
551aa26658SKarl Rupp     if (H(0, 0) != 0.) beta[0] = beta[0] / H(0, 0);
561aa26658SKarl Rupp     else beta[0] = 0.;
5738774f0aSPeter Brune   } else {
589566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(l, &ngmres->m));
599566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(l, &ngmres->n));
6038774f0aSPeter Brune     ngmres->info  = 0;
6138774f0aSPeter Brune     ngmres->rcond = -1.;
629566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
6338774f0aSPeter Brune #if defined(PETSC_USE_COMPLEX)
64792fecdfSBarry 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));
6538774f0aSPeter Brune #else
66792fecdfSBarry 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));
6738774f0aSPeter Brune #endif
689566063dSJacob Faibussowitsch     PetscCall(PetscFPTrapPop());
6908401ef6SPierre Jolivet     PetscCheck(ngmres->info >= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "Bad argument to GELSS");
7008401ef6SPierre Jolivet     PetscCheck(ngmres->info <= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "SVD failed to converge");
7138774f0aSPeter Brune   }
729371c9d4SSatish Balay   for (i = 0; i < l; i++) { PetscCheck(!PetscIsInfOrNanScalar(beta[i]), PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "SVD generated inconsistent output"); }
7338774f0aSPeter Brune   alph_total = 0.;
741aa26658SKarl Rupp   for (i = 0; i < l; i++) alph_total += beta[i];
751aa26658SKarl Rupp 
769566063dSJacob Faibussowitsch   PetscCall(VecCopy(XM, XA));
779566063dSJacob Faibussowitsch   PetscCall(VecScale(XA, 1. - alph_total));
789566063dSJacob Faibussowitsch   PetscCall(VecMAXPY(XA, l, beta, Xdot));
7938774f0aSPeter Brune   /* check the validity of the step */
809566063dSJacob Faibussowitsch   PetscCall(VecCopy(XA, Y));
819566063dSJacob Faibussowitsch   PetscCall(VecAXPY(Y, -1.0, X));
829566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchPostCheck(snes->linesearch, X, Y, XA, &changed_y, &changed_w));
8346159c86SPeter Brune   if (!ngmres->approxfunc) {
84efd4aadfSBarry Smith     if (snes->npc && snes->npcside == PC_LEFT) {
859566063dSJacob Faibussowitsch       PetscCall(SNESApplyNPC(snes, XA, NULL, FA));
8646159c86SPeter Brune     } else {
879566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, XA, FA));
8846159c86SPeter Brune     }
8935f895b4SBarry Smith   } else {
909566063dSJacob Faibussowitsch     PetscCall(VecCopy(FM, FA));
919566063dSJacob Faibussowitsch     PetscCall(VecScale(FA, 1. - alph_total));
929566063dSJacob Faibussowitsch     PetscCall(VecMAXPY(FA, l, beta, Fdot));
93077c4231SPeter Brune   }
9438774f0aSPeter Brune   PetscFunctionReturn(0);
9538774f0aSPeter Brune }
9638774f0aSPeter Brune 
979371c9d4SSatish Balay 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) {
9838774f0aSPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
99b3c6a99cSPeter Brune   PetscReal    dcurnorm, dmin = -1.0;
10038774f0aSPeter Brune   Vec         *Xdot = ngmres->Xdot;
10138774f0aSPeter Brune   PetscInt     i;
10238774f0aSPeter Brune 
10338774f0aSPeter Brune   PetscFunctionBegin;
1041baa6e33SBarry Smith   if (xMnorm) PetscCall(VecNormBegin(XM, NORM_2, xMnorm));
1051baa6e33SBarry Smith   if (fMnorm) PetscCall(VecNormBegin(FM, NORM_2, fMnorm));
106b3c6a99cSPeter Brune   if (yMnorm) {
1079566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, D));
1089566063dSJacob Faibussowitsch     PetscCall(VecAXPY(D, -1.0, XM));
1099566063dSJacob Faibussowitsch     PetscCall(VecNormBegin(D, NORM_2, yMnorm));
110b3c6a99cSPeter Brune   }
1111baa6e33SBarry Smith   if (xAnorm) PetscCall(VecNormBegin(XA, NORM_2, xAnorm));
1121baa6e33SBarry Smith   if (fAnorm) PetscCall(VecNormBegin(FA, NORM_2, fAnorm));
113b3c6a99cSPeter Brune   if (yAnorm) {
1149566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, D));
1159566063dSJacob Faibussowitsch     PetscCall(VecAXPY(D, -1.0, XA));
1169566063dSJacob Faibussowitsch     PetscCall(VecNormBegin(D, NORM_2, yAnorm));
117b3c6a99cSPeter Brune   }
11838774f0aSPeter Brune   if (dnorm) {
1199566063dSJacob Faibussowitsch     PetscCall(VecCopy(XA, D));
1209566063dSJacob Faibussowitsch     PetscCall(VecAXPY(D, -1.0, XM));
1219566063dSJacob Faibussowitsch     PetscCall(VecNormBegin(D, NORM_2, dnorm));
12238774f0aSPeter Brune   }
12338774f0aSPeter Brune   if (dminnorm) {
12438774f0aSPeter Brune     for (i = 0; i < l; i++) {
1259566063dSJacob Faibussowitsch       PetscCall(VecCopy(Xdot[i], D));
1269566063dSJacob Faibussowitsch       PetscCall(VecAXPY(D, -1.0, XA));
1279566063dSJacob Faibussowitsch       PetscCall(VecNormBegin(D, NORM_2, &ngmres->xnorms[i]));
12838774f0aSPeter Brune     }
12938774f0aSPeter Brune   }
1309566063dSJacob Faibussowitsch   if (xMnorm) PetscCall(VecNormEnd(XM, NORM_2, xMnorm));
1319566063dSJacob Faibussowitsch   if (fMnorm) PetscCall(VecNormEnd(FM, NORM_2, fMnorm));
1329566063dSJacob Faibussowitsch   if (yMnorm) PetscCall(VecNormEnd(D, NORM_2, yMnorm));
1339566063dSJacob Faibussowitsch   if (xAnorm) PetscCall(VecNormEnd(XA, NORM_2, xAnorm));
1349566063dSJacob Faibussowitsch   if (fAnorm) PetscCall(VecNormEnd(FA, NORM_2, fAnorm));
1359566063dSJacob Faibussowitsch   if (yAnorm) PetscCall(VecNormEnd(D, NORM_2, yAnorm));
1369566063dSJacob Faibussowitsch   if (dnorm) PetscCall(VecNormEnd(D, NORM_2, dnorm));
13738774f0aSPeter Brune   if (dminnorm) {
13838774f0aSPeter Brune     for (i = 0; i < l; i++) {
1399566063dSJacob Faibussowitsch       PetscCall(VecNormEnd(D, NORM_2, &ngmres->xnorms[i]));
14038774f0aSPeter Brune       dcurnorm = ngmres->xnorms[i];
141b3c6a99cSPeter Brune       if ((dcurnorm < dmin) || (dmin < 0.0)) dmin = dcurnorm;
14238774f0aSPeter Brune     }
143b3c6a99cSPeter Brune     *dminnorm = dmin;
14438774f0aSPeter Brune   }
14538774f0aSPeter Brune   PetscFunctionReturn(0);
14638774f0aSPeter Brune }
14738774f0aSPeter Brune 
1489371c9d4SSatish Balay PetscErrorCode SNESNGMRESSelect_Private(SNES snes, PetscInt k_restart, Vec XM, Vec FM, PetscReal xMnorm, PetscReal fMnorm, PetscReal yMnorm, Vec XA, Vec FA, PetscReal xAnorm, PetscReal fAnorm, PetscReal yAnorm, PetscReal dnorm, PetscReal fminnorm, PetscReal dminnorm, Vec X, Vec F, Vec Y, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm) {
14938774f0aSPeter Brune   SNES_NGMRES         *ngmres = (SNES_NGMRES *)snes->data;
150422a814eSBarry Smith   SNESLineSearchReason lssucceed;
151422a814eSBarry Smith   PetscBool            selectA;
15238774f0aSPeter Brune 
15338774f0aSPeter Brune   PetscFunctionBegin;
15438774f0aSPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
15538774f0aSPeter Brune     /* X = X + \lambda(XA - X) */
156*48a46eb9SPierre Jolivet     if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "||F_A||_2 = %e, ||F_M||_2 = %e\n", (double)fAnorm, (double)fMnorm));
1579566063dSJacob Faibussowitsch     PetscCall(VecCopy(FM, F));
1589566063dSJacob Faibussowitsch     PetscCall(VecCopy(XM, X));
1599566063dSJacob Faibussowitsch     PetscCall(VecCopy(XA, Y));
1609566063dSJacob Faibussowitsch     PetscCall(VecAYPX(Y, -1.0, X));
16138774f0aSPeter Brune     *fnorm = fMnorm;
1629566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchApply(ngmres->additive_linesearch, X, F, fnorm, Y));
1639566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchGetReason(ngmres->additive_linesearch, &lssucceed));
1649566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchGetNorms(ngmres->additive_linesearch, xnorm, fnorm, ynorm));
165422a814eSBarry Smith     if (lssucceed) {
16638774f0aSPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
16738774f0aSPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
16838774f0aSPeter Brune         PetscFunctionReturn(0);
16938774f0aSPeter Brune       }
17038774f0aSPeter Brune     }
171*48a46eb9SPierre Jolivet     if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: ||F||_2 = %e\n", (double)*fnorm));
17238774f0aSPeter Brune   } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
17338774f0aSPeter Brune     selectA = PETSC_TRUE;
17438774f0aSPeter Brune     /* Conditions for choosing the accelerated answer */
17538774f0aSPeter Brune     /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
1761aa26658SKarl Rupp     if (fAnorm >= ngmres->gammaA * fminnorm) selectA = PETSC_FALSE;
1771aa26658SKarl Rupp 
17838774f0aSPeter Brune     /* Criterion B -- the choice of x^A isn't too close to some other choice */
17938774f0aSPeter Brune     if (ngmres->epsilonB * dnorm < dminnorm || PetscSqrtReal(*fnorm) < ngmres->deltaB * PetscSqrtReal(fminnorm)) {
1801aa26658SKarl Rupp     } else selectA = PETSC_FALSE;
1811aa26658SKarl Rupp 
18238774f0aSPeter Brune     if (selectA) {
183*48a46eb9SPierre Jolivet       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", (double)fAnorm, (double)fMnorm));
18438774f0aSPeter Brune       /* copy it over */
185b3c6a99cSPeter Brune       *xnorm = xAnorm;
18638774f0aSPeter Brune       *fnorm = fAnorm;
187b3c6a99cSPeter Brune       *ynorm = yAnorm;
1889566063dSJacob Faibussowitsch       PetscCall(VecCopy(FA, F));
1899566063dSJacob Faibussowitsch       PetscCall(VecCopy(XA, X));
19038774f0aSPeter Brune     } else {
191*48a46eb9SPierre Jolivet       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n", (double)fAnorm, (double)fMnorm));
192b3c6a99cSPeter Brune       *xnorm = xMnorm;
19338774f0aSPeter Brune       *fnorm = fMnorm;
194b3c6a99cSPeter Brune       *ynorm = yMnorm;
1959566063dSJacob Faibussowitsch       PetscCall(VecCopy(XM, Y));
1969566063dSJacob Faibussowitsch       PetscCall(VecAXPY(Y, -1.0, X));
1979566063dSJacob Faibussowitsch       PetscCall(VecCopy(FM, F));
1989566063dSJacob Faibussowitsch       PetscCall(VecCopy(XM, X));
19938774f0aSPeter Brune     }
20038774f0aSPeter Brune   } else { /* none */
201b3c6a99cSPeter Brune     *xnorm = xAnorm;
20238774f0aSPeter Brune     *fnorm = fAnorm;
203b3c6a99cSPeter Brune     *ynorm = yAnorm;
2049566063dSJacob Faibussowitsch     PetscCall(VecCopy(FA, F));
2059566063dSJacob Faibussowitsch     PetscCall(VecCopy(XA, X));
20638774f0aSPeter Brune   }
20738774f0aSPeter Brune   PetscFunctionReturn(0);
20838774f0aSPeter Brune }
20938774f0aSPeter Brune 
2109371c9d4SSatish Balay PetscErrorCode SNESNGMRESSelectRestart_Private(SNES snes, PetscInt l, PetscReal fMnorm, PetscReal fAnorm, PetscReal dnorm, PetscReal fminnorm, PetscReal dminnorm, PetscBool *selectRestart) {
21138774f0aSPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
21238774f0aSPeter Brune 
21338774f0aSPeter Brune   PetscFunctionBegin;
21438774f0aSPeter Brune   *selectRestart = PETSC_FALSE;
21538774f0aSPeter Brune   /* difference stagnation restart */
21621687c63SPeter Brune   if ((ngmres->epsilonB * dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB * PetscSqrtReal(fminnorm)) && l > 0) {
217*48a46eb9SPierre Jolivet     if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", (double)(ngmres->epsilonB * dnorm), (double)dminnorm));
21838774f0aSPeter Brune     *selectRestart = PETSC_TRUE;
21938774f0aSPeter Brune   }
22038774f0aSPeter Brune   /* residual stagnation restart */
22138774f0aSPeter Brune   if (PetscSqrtReal(fAnorm) > ngmres->gammaC * PetscSqrtReal(fminnorm)) {
222*48a46eb9SPierre Jolivet     if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", (double)PetscSqrtReal(fAnorm), (double)(ngmres->gammaC * PetscSqrtReal(fminnorm))));
22338774f0aSPeter Brune     *selectRestart = PETSC_TRUE;
22438774f0aSPeter Brune   }
22523b3e82cSAsbjørn Nilsen Riseth 
22623b3e82cSAsbjørn Nilsen Riseth   /* F_M stagnation restart */
22723b3e82cSAsbjørn Nilsen Riseth   if (ngmres->restart_fm_rise && fMnorm > snes->norm) {
228*48a46eb9SPierre Jolivet     if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "F_M rise restart: %e > %e\n", (double)fMnorm, (double)snes->norm));
22923b3e82cSAsbjørn Nilsen Riseth     *selectRestart = PETSC_TRUE;
23023b3e82cSAsbjørn Nilsen Riseth   }
23123b3e82cSAsbjørn Nilsen Riseth 
23238774f0aSPeter Brune   PetscFunctionReturn(0);
23338774f0aSPeter Brune }
234