xref: /petsc/src/snes/impls/ngmres/ngmresfunc.c (revision efd4aadf157bf1ba2d80c2be092fcf4247860003)
138774f0aSPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/
238774f0aSPeter Brune #include <petscblaslapack.h>
338774f0aSPeter Brune 
438774f0aSPeter Brune PetscErrorCode SNESNGMRESUpdateSubspace_Private(SNES snes,PetscInt ivec,PetscInt l,Vec F,PetscReal fnorm,Vec X)
538774f0aSPeter Brune {
638774f0aSPeter Brune   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
738774f0aSPeter Brune   Vec            *Fdot   = ngmres->Fdot;
838774f0aSPeter Brune   Vec            *Xdot   = ngmres->Xdot;
938774f0aSPeter Brune   PetscErrorCode ierr;
1038774f0aSPeter Brune 
1138774f0aSPeter Brune   PetscFunctionBegin;
12ce94432eSBarry Smith   if (ivec > l) SETERRQ2(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Cannot update vector %d with space size %d!",ivec,l);
1338774f0aSPeter Brune   ierr = VecCopy(F,Fdot[ivec]);CHKERRQ(ierr);
1438774f0aSPeter Brune   ierr = VecCopy(X,Xdot[ivec]);CHKERRQ(ierr);
151aa26658SKarl Rupp 
1638774f0aSPeter Brune   ngmres->fnorms[ivec] = fnorm;
1738774f0aSPeter Brune   PetscFunctionReturn(0);
1838774f0aSPeter Brune }
1938774f0aSPeter Brune 
20b3c6a99cSPeter Brune PetscErrorCode SNESNGMRESFormCombinedSolution_Private(SNES snes,PetscInt ivec,PetscInt l,Vec XM,Vec FM,PetscReal fMnorm,Vec X,Vec XA,Vec FA)
2138774f0aSPeter Brune {
2238774f0aSPeter Brune   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
2338774f0aSPeter Brune   PetscInt       i,j;
2438774f0aSPeter Brune   Vec            *Fdot      = ngmres->Fdot;
2538774f0aSPeter Brune   Vec            *Xdot      = ngmres->Xdot;
2638774f0aSPeter Brune   PetscScalar    *beta      = ngmres->beta;
2738774f0aSPeter Brune   PetscScalar    *xi        = ngmres->xi;
2838774f0aSPeter Brune   PetscScalar    alph_total = 0.;
2938774f0aSPeter Brune   PetscErrorCode ierr;
3038774f0aSPeter Brune   PetscReal      nu;
3138774f0aSPeter Brune   Vec            Y = snes->work[2];
3238774f0aSPeter Brune   PetscBool      changed_y,changed_w;
3338774f0aSPeter Brune 
3438774f0aSPeter Brune   PetscFunctionBegin;
3538774f0aSPeter Brune   nu = fMnorm*fMnorm;
3638774f0aSPeter Brune 
3738774f0aSPeter Brune   /* construct the right hand side and xi factors */
38b3c6a99cSPeter Brune   if (l > 0) {
39b3c6a99cSPeter Brune     ierr = VecMDotBegin(FM,l,Fdot,xi);CHKERRQ(ierr);
40b3c6a99cSPeter Brune     ierr = VecMDotBegin(Fdot[ivec],l,Fdot,beta);CHKERRQ(ierr);
41b3c6a99cSPeter Brune     ierr = VecMDotEnd(FM,l,Fdot,xi);CHKERRQ(ierr);
42b3c6a99cSPeter Brune     ierr = VecMDotEnd(Fdot[ivec],l,Fdot,beta);CHKERRQ(ierr);
43b3c6a99cSPeter Brune     for (i = 0; i < l; i++) {
44b3c6a99cSPeter Brune       Q(i,ivec) = beta[i];
45b3c6a99cSPeter Brune       Q(ivec,i) = beta[i];
46b3c6a99cSPeter Brune     }
47b3c6a99cSPeter Brune   } else {
48b3c6a99cSPeter Brune     Q(0,0) = ngmres->fnorms[ivec]*ngmres->fnorms[ivec];
49b3c6a99cSPeter Brune   }
50b3c6a99cSPeter Brune 
511aa26658SKarl Rupp   for (i = 0; i < l; i++) beta[i] = nu - xi[i];
521aa26658SKarl Rupp 
5338774f0aSPeter Brune   /* construct h */
5438774f0aSPeter Brune   for (j = 0; j < l; j++) {
5538774f0aSPeter Brune     for (i = 0; i < l; i++) {
5638774f0aSPeter Brune       H(i,j) = Q(i,j)-xi[i]-xi[j]+nu;
5738774f0aSPeter Brune     }
5838774f0aSPeter Brune   }
5938774f0aSPeter Brune   if (l == 1) {
6038774f0aSPeter Brune     /* simply set alpha[0] = beta[0] / H[0, 0] */
611aa26658SKarl Rupp     if (H(0,0) != 0.) beta[0] = beta[0]/H(0,0);
621aa26658SKarl Rupp     else beta[0] = 0.;
6338774f0aSPeter Brune   } else {
6438774f0aSPeter Brune #if defined(PETSC_MISSING_LAPACK_GELSS)
65ce94432eSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"NGMRES with LS requires the LAPACK GELSS routine.");
6638774f0aSPeter Brune #else
6738774f0aSPeter Brune     ierr          = PetscBLASIntCast(l,&ngmres->m);CHKERRQ(ierr);
6838774f0aSPeter Brune     ierr          = PetscBLASIntCast(l,&ngmres->n);CHKERRQ(ierr);
6938774f0aSPeter Brune     ngmres->info  = 0;
7038774f0aSPeter Brune     ngmres->rcond = -1.;
7138774f0aSPeter Brune     ierr          = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
7238774f0aSPeter Brune #if defined(PETSC_USE_COMPLEX)
738b83055fSJed Brown     PetscStackCallBLAS("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));
7438774f0aSPeter Brune #else
758b83055fSJed Brown     PetscStackCallBLAS("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));
7638774f0aSPeter Brune #endif
7738774f0aSPeter Brune     ierr = PetscFPTrapPop();CHKERRQ(ierr);
78ce94432eSBarry Smith     if (ngmres->info < 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"Bad argument to GELSS");
79ce94432eSBarry Smith     if (ngmres->info > 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD failed to converge");
8038774f0aSPeter Brune #endif
8138774f0aSPeter Brune   }
8238774f0aSPeter Brune   for (i=0; i<l; i++) {
83ce94432eSBarry Smith     if (PetscIsInfOrNanScalar(beta[i])) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD generated inconsistent output");
8438774f0aSPeter Brune   }
8538774f0aSPeter Brune   alph_total = 0.;
861aa26658SKarl Rupp   for (i = 0; i < l; i++) alph_total += beta[i];
871aa26658SKarl Rupp 
8838774f0aSPeter Brune   ierr = VecCopy(XM,XA);CHKERRQ(ierr);
8938774f0aSPeter Brune   ierr = VecScale(XA,1.-alph_total);CHKERRQ(ierr);
9038774f0aSPeter Brune   ierr = VecMAXPY(XA,l,beta,Xdot);CHKERRQ(ierr);
9138774f0aSPeter Brune   /* check the validity of the step */
9238774f0aSPeter Brune   ierr = VecCopy(XA,Y);CHKERRQ(ierr);
9338774f0aSPeter Brune   ierr = VecAXPY(Y,-1.0,X);CHKERRQ(ierr);
9438774f0aSPeter Brune   ierr = SNESLineSearchPostCheck(snes->linesearch,X,Y,XA,&changed_y,&changed_w);CHKERRQ(ierr);
9546159c86SPeter Brune   if (!ngmres->approxfunc) {
96*efd4aadfSBarry Smith     if (snes->npc && snes->npcside== PC_LEFT) {
97be95d8f1SBarry Smith       ierr = SNESApplyNPC(snes,XA,NULL,FA);CHKERRQ(ierr);
9846159c86SPeter Brune     } else {
9946159c86SPeter Brune       ierr =SNESComputeFunction(snes,XA,FA);CHKERRQ(ierr);
10046159c86SPeter Brune     }
10135f895b4SBarry Smith   } else {
102077c4231SPeter Brune     ierr = VecCopy(FM,FA);CHKERRQ(ierr);
103077c4231SPeter Brune     ierr = VecScale(FA,1.-alph_total);CHKERRQ(ierr);
104077c4231SPeter Brune     ierr = VecMAXPY(FA,l,beta,Fdot);CHKERRQ(ierr);
105077c4231SPeter Brune   }
10638774f0aSPeter Brune   PetscFunctionReturn(0);
10738774f0aSPeter Brune }
10838774f0aSPeter Brune 
109b3c6a99cSPeter Brune 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)
11038774f0aSPeter Brune {
11138774f0aSPeter Brune   PetscErrorCode ierr;
11238774f0aSPeter Brune   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
113b3c6a99cSPeter Brune   PetscReal      dcurnorm,dmin = -1.0;
11438774f0aSPeter Brune   Vec            *Xdot = ngmres->Xdot;
11538774f0aSPeter Brune   PetscInt       i;
11638774f0aSPeter Brune 
11738774f0aSPeter Brune   PetscFunctionBegin;
118b3c6a99cSPeter Brune   if (xMnorm) {
119b3c6a99cSPeter Brune     ierr = VecNormBegin(XM,NORM_2,xMnorm);CHKERRQ(ierr);
120b3c6a99cSPeter Brune   }
121b3c6a99cSPeter Brune   if (fMnorm) {
122b3c6a99cSPeter Brune     ierr = VecNormBegin(FM,NORM_2,fMnorm);CHKERRQ(ierr);
123b3c6a99cSPeter Brune   }
124b3c6a99cSPeter Brune   if (yMnorm) {
125b3c6a99cSPeter Brune     ierr = VecCopy(X,D);CHKERRQ(ierr);
126b3c6a99cSPeter Brune     ierr = VecAXPY(D,-1.0,XM);CHKERRQ(ierr);
127b3c6a99cSPeter Brune     ierr = VecNormBegin(D,NORM_2,yMnorm);CHKERRQ(ierr);
128b3c6a99cSPeter Brune   }
129b3c6a99cSPeter Brune   if (xAnorm) {
130b3c6a99cSPeter Brune     ierr = VecNormBegin(XA,NORM_2,xAnorm);CHKERRQ(ierr);
131b3c6a99cSPeter Brune   }
13238774f0aSPeter Brune   if (fAnorm) {
13338774f0aSPeter Brune     ierr = VecNormBegin(FA,NORM_2,fAnorm);CHKERRQ(ierr);
13438774f0aSPeter Brune   }
135b3c6a99cSPeter Brune   if (yAnorm) {
136b3c6a99cSPeter Brune     ierr = VecCopy(X,D);CHKERRQ(ierr);
137b3c6a99cSPeter Brune     ierr = VecAXPY(D,-1.0,XA);CHKERRQ(ierr);
138b3c6a99cSPeter Brune     ierr = VecNormBegin(D,NORM_2,yAnorm);CHKERRQ(ierr);
139b3c6a99cSPeter Brune   }
14038774f0aSPeter Brune   if (dnorm) {
14138774f0aSPeter Brune     ierr = VecCopy(XA,D);CHKERRQ(ierr);
14238774f0aSPeter Brune     ierr = VecAXPY(D,-1.0,XM);CHKERRQ(ierr);
14338774f0aSPeter Brune     ierr = VecNormBegin(D,NORM_2,dnorm);CHKERRQ(ierr);
14438774f0aSPeter Brune   }
14538774f0aSPeter Brune   if (dminnorm) {
14638774f0aSPeter Brune     for (i=0; i<l; i++) {
147b3c6a99cSPeter Brune       ierr = VecCopy(Xdot[i],D);CHKERRQ(ierr);
148b3c6a99cSPeter Brune       ierr = VecAXPY(D,-1.0,XA);CHKERRQ(ierr);
149b3c6a99cSPeter Brune       ierr = VecNormBegin(D,NORM_2,&ngmres->xnorms[i]);CHKERRQ(ierr);
15038774f0aSPeter Brune     }
15138774f0aSPeter Brune   }
152b3c6a99cSPeter Brune   if (xMnorm) {ierr = VecNormEnd(XM,NORM_2,xMnorm);CHKERRQ(ierr);}
153b3c6a99cSPeter Brune   if (fMnorm) {ierr = VecNormEnd(FM,NORM_2,fMnorm);CHKERRQ(ierr);}
154b3c6a99cSPeter Brune   if (yMnorm) {ierr = VecNormEnd(D,NORM_2,yMnorm);CHKERRQ(ierr);}
155b3c6a99cSPeter Brune   if (xAnorm) {ierr = VecNormEnd(XA,NORM_2,xAnorm);CHKERRQ(ierr);}
15638774f0aSPeter Brune   if (fAnorm) {ierr = VecNormEnd(FA,NORM_2,fAnorm);CHKERRQ(ierr);}
157b3c6a99cSPeter Brune   if (yAnorm) {ierr = VecNormEnd(D,NORM_2,yAnorm);CHKERRQ(ierr);}
15838774f0aSPeter Brune   if (dnorm) {ierr = VecNormEnd(D,NORM_2,dnorm);CHKERRQ(ierr);}
15938774f0aSPeter Brune   if (dminnorm) {
16038774f0aSPeter Brune     for (i=0; i<l; i++) {
161b3c6a99cSPeter Brune       ierr = VecNormEnd(D,NORM_2,&ngmres->xnorms[i]);CHKERRQ(ierr);
16238774f0aSPeter Brune       dcurnorm = ngmres->xnorms[i];
163b3c6a99cSPeter Brune       if ((dcurnorm < dmin) || (dmin < 0.0)) dmin = dcurnorm;
16438774f0aSPeter Brune     }
165b3c6a99cSPeter Brune     *dminnorm = dmin;
16638774f0aSPeter Brune   }
16738774f0aSPeter Brune   PetscFunctionReturn(0);
16838774f0aSPeter Brune }
16938774f0aSPeter Brune 
170b3c6a99cSPeter Brune 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)
17138774f0aSPeter Brune {
17238774f0aSPeter Brune   SNES_NGMRES          *ngmres = (SNES_NGMRES*) snes->data;
17338774f0aSPeter Brune   PetscErrorCode       ierr;
174422a814eSBarry Smith   SNESLineSearchReason lssucceed;
175422a814eSBarry Smith   PetscBool            selectA;
17638774f0aSPeter Brune 
17738774f0aSPeter Brune   PetscFunctionBegin;
17838774f0aSPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
17938774f0aSPeter Brune     /* X = X + \lambda(XA - X) */
18038774f0aSPeter Brune     if (ngmres->monitor) {
18138774f0aSPeter Brune       ierr = PetscViewerASCIIPrintf(ngmres->monitor,"||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);CHKERRQ(ierr);
18238774f0aSPeter Brune     }
18338774f0aSPeter Brune     ierr   = VecCopy(FM,F);CHKERRQ(ierr);
18438774f0aSPeter Brune     ierr   = VecCopy(XM,X);CHKERRQ(ierr);
18538774f0aSPeter Brune     ierr   = VecCopy(XA,Y);CHKERRQ(ierr);
18638774f0aSPeter Brune     ierr   = VecAYPX(Y,-1.0,X);CHKERRQ(ierr);
18738774f0aSPeter Brune     *fnorm = fMnorm;
18838774f0aSPeter Brune     ierr   = SNESLineSearchApply(ngmres->additive_linesearch,X,F,fnorm,Y);CHKERRQ(ierr);
189422a814eSBarry Smith     ierr   = SNESLineSearchGetReason(ngmres->additive_linesearch,&lssucceed);CHKERRQ(ierr);
190422a814eSBarry Smith     ierr   = SNESLineSearchGetNorms(ngmres->additive_linesearch,xnorm,fnorm,ynorm);CHKERRQ(ierr);
191422a814eSBarry Smith     if (lssucceed) {
19238774f0aSPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
19338774f0aSPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
19438774f0aSPeter Brune         PetscFunctionReturn(0);
19538774f0aSPeter Brune       }
19638774f0aSPeter Brune     }
19738774f0aSPeter Brune     if (ngmres->monitor) {
19838774f0aSPeter Brune       ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Additive solution: ||F||_2 = %e\n",*fnorm);CHKERRQ(ierr);
19938774f0aSPeter Brune     }
20038774f0aSPeter Brune   } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
20138774f0aSPeter Brune     selectA = PETSC_TRUE;
20238774f0aSPeter Brune     /* Conditions for choosing the accelerated answer */
20338774f0aSPeter Brune     /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
2041aa26658SKarl Rupp     if (fAnorm >= ngmres->gammaA*fminnorm) selectA = PETSC_FALSE;
2051aa26658SKarl Rupp 
20638774f0aSPeter Brune     /* Criterion B -- the choice of x^A isn't too close to some other choice */
20738774f0aSPeter Brune     if (ngmres->epsilonB*dnorm<dminnorm || PetscSqrtReal(*fnorm)<ngmres->deltaB*PetscSqrtReal(fminnorm)) {
2081aa26658SKarl Rupp     } else selectA=PETSC_FALSE;
2091aa26658SKarl Rupp 
21038774f0aSPeter Brune     if (selectA) {
21138774f0aSPeter Brune       if (ngmres->monitor) {
21238774f0aSPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);CHKERRQ(ierr);
21338774f0aSPeter Brune       }
21438774f0aSPeter Brune       /* copy it over */
215b3c6a99cSPeter Brune       *xnorm = xAnorm;
21638774f0aSPeter Brune       *fnorm = fAnorm;
217b3c6a99cSPeter Brune       *ynorm = yAnorm;
21838774f0aSPeter Brune       ierr   = VecCopy(FA,F);CHKERRQ(ierr);
21938774f0aSPeter Brune       ierr   = VecCopy(XA,X);CHKERRQ(ierr);
22038774f0aSPeter Brune     } else {
22138774f0aSPeter Brune       if (ngmres->monitor) {
22238774f0aSPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);CHKERRQ(ierr);
22338774f0aSPeter Brune       }
224b3c6a99cSPeter Brune       *xnorm = xMnorm;
22538774f0aSPeter Brune       *fnorm = fMnorm;
226b3c6a99cSPeter Brune       *ynorm = yMnorm;
22738774f0aSPeter Brune       ierr   = VecCopy(XM,Y);CHKERRQ(ierr);
22838774f0aSPeter Brune       ierr   = VecAXPY(Y,-1.0,X);CHKERRQ(ierr);
22938774f0aSPeter Brune       ierr   = VecCopy(FM,F);CHKERRQ(ierr);
23038774f0aSPeter Brune       ierr   = VecCopy(XM,X);CHKERRQ(ierr);
23138774f0aSPeter Brune     }
23238774f0aSPeter Brune   } else { /* none */
233b3c6a99cSPeter Brune     *xnorm = xAnorm;
23438774f0aSPeter Brune     *fnorm = fAnorm;
235b3c6a99cSPeter Brune     *ynorm = yAnorm;
23638774f0aSPeter Brune     ierr   = VecCopy(FA,F);CHKERRQ(ierr);
23738774f0aSPeter Brune     ierr   = VecCopy(XA,X);CHKERRQ(ierr);
23838774f0aSPeter Brune   }
23938774f0aSPeter Brune   PetscFunctionReturn(0);
24038774f0aSPeter Brune }
24138774f0aSPeter Brune 
24223b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESSelectRestart_Private(SNES snes,PetscInt l,PetscReal fMnorm, PetscReal fAnorm,PetscReal dnorm,PetscReal fminnorm,PetscReal dminnorm,PetscBool *selectRestart)
24338774f0aSPeter Brune {
24438774f0aSPeter Brune   SNES_NGMRES    *ngmres = (SNES_NGMRES*)snes->data;
24538774f0aSPeter Brune   PetscErrorCode ierr;
24638774f0aSPeter Brune 
24738774f0aSPeter Brune   PetscFunctionBegin;
24838774f0aSPeter Brune   *selectRestart = PETSC_FALSE;
24938774f0aSPeter Brune   /* difference stagnation restart */
25021687c63SPeter Brune   if ((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm)) && l > 0) {
25138774f0aSPeter Brune     if (ngmres->monitor) {
25238774f0aSPeter Brune       ierr = PetscViewerASCIIPrintf(ngmres->monitor,"difference restart: %e > %e\n",ngmres->epsilonB*dnorm,dminnorm);CHKERRQ(ierr);
25338774f0aSPeter Brune     }
25438774f0aSPeter Brune     *selectRestart = PETSC_TRUE;
25538774f0aSPeter Brune   }
25638774f0aSPeter Brune   /* residual stagnation restart */
25738774f0aSPeter Brune   if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) {
25838774f0aSPeter Brune     if (ngmres->monitor) {
25938774f0aSPeter Brune       ierr = PetscViewerASCIIPrintf(ngmres->monitor,"residual restart: %e > %e\n",PetscSqrtReal(fAnorm),ngmres->gammaC*PetscSqrtReal(fminnorm));CHKERRQ(ierr);
26038774f0aSPeter Brune     }
26138774f0aSPeter Brune     *selectRestart = PETSC_TRUE;
26238774f0aSPeter Brune   }
26323b3e82cSAsbjørn Nilsen Riseth 
26423b3e82cSAsbjørn Nilsen Riseth   /* F_M stagnation restart */
26523b3e82cSAsbjørn Nilsen Riseth   if (ngmres->restart_fm_rise && fMnorm > snes->norm) {
26623b3e82cSAsbjørn Nilsen Riseth     if (ngmres->monitor) {
26723b3e82cSAsbjørn Nilsen Riseth       ierr = PetscViewerASCIIPrintf(ngmres->monitor,"F_M rise restart: %e > %e\n",fMnorm,snes->norm);CHKERRQ(ierr);
26823b3e82cSAsbjørn Nilsen Riseth     }
26923b3e82cSAsbjørn Nilsen Riseth     *selectRestart = PETSC_TRUE;
27023b3e82cSAsbjørn Nilsen Riseth   }
27123b3e82cSAsbjørn Nilsen Riseth 
27238774f0aSPeter Brune   PetscFunctionReturn(0);
27338774f0aSPeter Brune }
274