xref: /petsc/src/snes/impls/qn/qn.c (revision 01fe78ea94fd6c6bd79fc98c41e4c7bdd1273430)
1af0996ceSBarry Smith #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/
2fced5a79SAsbjørn Nilsen Riseth #include <petscdm.h>
34b11644fSPeter Brune 
48e231d97SPeter Brune #define H(i,j)  qn->dXdFmat[i*qn->m + j]
58e231d97SPeter Brune 
61efc8c45SPeter Brune const char *const SNESQNScaleTypes[] =        {"DEFAULT","NONE","SHANNO","LINESEARCH","JACOBIAN","SNESQNScaleType","SNES_QN_SCALING_",0};
71efc8c45SPeter Brune const char *const SNESQNRestartTypes[] =      {"DEFAULT","NONE","POWELL","PERIODIC","SNESQNRestartType","SNES_QN_RESTART_",0};
860c08b40SPeter Brune const char *const SNESQNTypes[] =             {"LBFGS","BROYDEN","BADBROYDEN","SNESQNType","SNES_QN_",0};
9b8840d6bSPeter Brune 
104b11644fSPeter Brune typedef struct {
11b8840d6bSPeter Brune   Vec               *U;                   /* Stored past states (vary from method to method) */
12b8840d6bSPeter Brune   Vec               *V;                   /* Stored past states (vary from method to method) */
138e231d97SPeter Brune   PetscInt          m;                    /* The number of kept previous steps */
145c7a0a03SPeter Brune   PetscReal         *lambda;              /* The line search history of the method */
155c7a0a03SPeter Brune   PetscReal         *norm;                /* norms of the steps */
168e231d97SPeter Brune   PetscScalar       *alpha, *beta;
178e231d97SPeter Brune   PetscScalar       *dXtdF, *dFtdX, *YtdX;
1818aa0c0cSPeter Brune   PetscBool         singlereduction;      /* Aggregated reduction implementation */
198e231d97SPeter Brune   PetscScalar       *dXdFmat;             /* A matrix of values for dX_i dot dF_j */
2044f7e39eSPeter Brune   PetscViewer       monitor;
216bf1b2e5SPeter Brune   PetscReal         powell_gamma;         /* Powell angle restart condition */
22b21d5a53SPeter Brune   PetscReal         scaling;              /* scaling of H0 */
23b8840d6bSPeter Brune   SNESQNType        type;                 /* the type of quasi-newton method used */
2488f769c5SPeter Brune   SNESQNScaleType   scale_type;           /* the type of scaling used */
250c777b0cSPeter Brune   SNESQNRestartType restart_type;         /* determine the frequency and type of restart conditions */
269f83bee8SJed Brown } SNES_QN;
274b11644fSPeter Brune 
285051edb1SPeter Brune PetscErrorCode SNESQNApply_Broyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D)
292150357eSBarry Smith {
304b11644fSPeter Brune   PetscErrorCode     ierr;
319f83bee8SJed Brown   SNES_QN            *qn = (SNES_QN*)snes->data;
32b8840d6bSPeter Brune   Vec                W   = snes->work[3];
33b8840d6bSPeter Brune   Vec                *U  = qn->U;
34b8840d6bSPeter Brune   PetscInt           m = qn->m;
357f41f16fSJed Brown   PetscInt           k,i,j,l = m;
365c7a0a03SPeter Brune   PetscReal          unorm,a,b;
375c7a0a03SPeter Brune   PetscReal          *lambda=qn->lambda;
38b8840d6bSPeter Brune   PetscScalar        gdot;
3959e7931aSPeter Brune   PetscReal          udot;
402150357eSBarry Smith 
41b8840d6bSPeter Brune   PetscFunctionBegin;
42b8840d6bSPeter Brune   if (it < m) l = it;
435c7a0a03SPeter Brune   if (it > 0) {
445c7a0a03SPeter Brune     k = (it-1)%l;
455c7a0a03SPeter Brune     ierr = SNESLineSearchGetLambda(snes->linesearch,&lambda[k]);CHKERRQ(ierr);
46a49fa0d8SPeter Brune     ierr = VecCopy(Xold,U[k]);CHKERRQ(ierr);
475051edb1SPeter Brune     ierr = VecAXPY(U[k],-1.0,X);CHKERRQ(ierr);
485c7a0a03SPeter Brune     if (qn->monitor) {
495c7a0a03SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
506bdcc836SBarry Smith       ierr = PetscViewerASCIIPrintf(qn->monitor, "scaling vector %D of %D by lambda: %14.12e \n",k,l,(double)lambda[k]);CHKERRQ(ierr);
515c7a0a03SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
525c7a0a03SPeter Brune     }
535c7a0a03SPeter Brune   }
54b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
55d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,D,W);CHKERRQ(ierr);
56422a814eSBarry Smith     SNESCheckKSPSolve(snes);
57b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
58b8840d6bSPeter Brune   } else {
59b8840d6bSPeter Brune     ierr = VecCopy(D,Y);CHKERRQ(ierr);
60b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
61b8840d6bSPeter Brune   }
62b8840d6bSPeter Brune 
63b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
64b8840d6bSPeter Brune   for (i = 0; i < l-1; i++) {
655c7a0a03SPeter Brune     j = (it+i-l)%l;
665c7a0a03SPeter Brune     k = (it+i-l+1)%l;
675c7a0a03SPeter Brune     ierr = VecNorm(U[j],NORM_2,&unorm);CHKERRQ(ierr);
685c7a0a03SPeter Brune     ierr = VecDot(U[j],Y,&gdot);CHKERRQ(ierr);
6959e7931aSPeter Brune     unorm *= unorm;
7059e7931aSPeter Brune     udot = PetscRealPart(gdot);
715c7a0a03SPeter Brune     a = (lambda[j]/lambda[k]);
725c7a0a03SPeter Brune     b = -(1.-lambda[j]);
7359e7931aSPeter Brune     a *= udot/unorm;
7459e7931aSPeter Brune     b *= udot/unorm;
755c7a0a03SPeter Brune     ierr = VecAXPBYPCZ(Y,a,b,1.,U[k],U[j]);CHKERRQ(ierr);
765c7a0a03SPeter Brune 
77b8840d6bSPeter Brune     if (qn->monitor) {
78b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
796bdcc836SBarry Smith       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %D and %D, gdot: %14.12e\n",k,j,(double)PetscRealPart(gdot));CHKERRQ(ierr);
80b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
81b8840d6bSPeter Brune     }
82b8840d6bSPeter Brune   }
83b8840d6bSPeter Brune   if (l > 0) {
84b8840d6bSPeter Brune     k = (it-1)%l;
85b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
865c7a0a03SPeter Brune     ierr = VecNorm(U[k],NORM_2,&unorm);CHKERRQ(ierr);
8759e7931aSPeter Brune     unorm *= unorm;
8859e7931aSPeter Brune     udot = PetscRealPart(gdot);
8959e7931aSPeter Brune     a = unorm/(unorm-lambda[k]*udot);
9059e7931aSPeter Brune     b = -(1.-lambda[k])*udot/(unorm-lambda[k]*udot);
91b8840d6bSPeter Brune     if (qn->monitor) {
92b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
936bdcc836SBarry Smith       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %D: a: %14.12e b: %14.12e \n",k,(double)a,(double)b);CHKERRQ(ierr);
94b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
95b8840d6bSPeter Brune     }
965c7a0a03SPeter Brune     ierr = VecAXPBY(Y,b,a,U[k]);CHKERRQ(ierr);
97b8840d6bSPeter Brune   }
985c7a0a03SPeter Brune   l = m;
995c7a0a03SPeter Brune   if (it+1<m)l=it+1;
1005c7a0a03SPeter Brune   k = it%l;
1015c7a0a03SPeter Brune   if (qn->monitor) {
1025c7a0a03SPeter Brune     ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1036bdcc836SBarry Smith     ierr = PetscViewerASCIIPrintf(qn->monitor, "setting vector %D of %D\n",k,l);CHKERRQ(ierr);
1045c7a0a03SPeter Brune     ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1055c7a0a03SPeter Brune   }
106b8840d6bSPeter Brune   PetscFunctionReturn(0);
107b8840d6bSPeter Brune }
108b8840d6bSPeter Brune 
1090adebc6cSBarry Smith PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1100adebc6cSBarry Smith {
111b8840d6bSPeter Brune   PetscErrorCode ierr;
112b8840d6bSPeter Brune   SNES_QN        *qn = (SNES_QN*)snes->data;
113b8840d6bSPeter Brune   Vec            W   = snes->work[3];
114b8840d6bSPeter Brune   Vec            *U  = qn->U;
115b8840d6bSPeter Brune   Vec            *T  = qn->V;
116b8840d6bSPeter Brune 
11784c577daSBarry Smith   /* ksp thing for Jacobian scaling */
1187f41f16fSJed Brown   PetscInt           h,k,j,i;
119b8840d6bSPeter Brune   PetscInt           m = qn->m;
1205051edb1SPeter Brune   PetscScalar        gdot,udot;
121b8840d6bSPeter Brune   PetscInt           l = m;
1220adebc6cSBarry Smith 
123b8840d6bSPeter Brune   PetscFunctionBegin;
124b8840d6bSPeter Brune   if (it < m) l = it;
125b8840d6bSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
126b8840d6bSPeter Brune   if (l > 0) {
127b8840d6bSPeter Brune     k    = (it-1)%l;
128c9e59058SPeter Brune     ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->lambda[k]);CHKERRQ(ierr);
129b8840d6bSPeter Brune     ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr);
130b8840d6bSPeter Brune     ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr);
1315051edb1SPeter Brune     ierr = VecCopy(Xold,T[k]);CHKERRQ(ierr);
1325051edb1SPeter Brune     ierr = VecAXPY(T[k],-1.0,X);CHKERRQ(ierr);
133b8840d6bSPeter Brune   }
134b8840d6bSPeter Brune 
135b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
136d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
137422a814eSBarry Smith     SNESCheckKSPSolve(snes);
138b8840d6bSPeter Brune     ierr = VecCopy(W,Y);CHKERRQ(ierr);
139b8840d6bSPeter Brune   } else {
140b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
141b8840d6bSPeter Brune   }
1425051edb1SPeter Brune 
1435051edb1SPeter Brune   /* inward recursion starting at the first update and working forward */
1445051edb1SPeter Brune   if (l > 0) {
1455051edb1SPeter Brune     for (i = 0; i < l-1; i++) {
146c9e59058SPeter Brune       j    = (it+i-l)%l;
147c9e59058SPeter Brune       k    = (it+i-l+1)%l;
148c9e59058SPeter Brune       h    = (it-1)%l;
149c9e59058SPeter Brune       ierr = VecDotBegin(U[j],U[h],&gdot);CHKERRQ(ierr);
150c9e59058SPeter Brune       ierr = VecDotBegin(U[j],U[j],&udot);CHKERRQ(ierr);
151c9e59058SPeter Brune       ierr = VecDotEnd(U[j],U[h],&gdot);CHKERRQ(ierr);
152c9e59058SPeter Brune       ierr = VecDotEnd(U[j],U[j],&udot);CHKERRQ(ierr);
1535051edb1SPeter Brune       ierr = VecAXPY(Y,PetscRealPart(gdot)/PetscRealPart(udot),T[k]);CHKERRQ(ierr);
154c9e59058SPeter Brune       ierr = VecAXPY(Y,-(1.-qn->lambda[k])*PetscRealPart(gdot)/PetscRealPart(udot),T[j]);CHKERRQ(ierr);
1555051edb1SPeter Brune       if (qn->monitor) {
1565051edb1SPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1576bdcc836SBarry Smith         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %D k: %D gdot: %14.12e\n", it, k, (double)PetscRealPart(gdot));CHKERRQ(ierr);
1585051edb1SPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1595051edb1SPeter Brune       }
1605051edb1SPeter Brune     }
1615051edb1SPeter Brune   }
162b8840d6bSPeter Brune   PetscFunctionReturn(0);
163b8840d6bSPeter Brune }
164b8840d6bSPeter Brune 
1650adebc6cSBarry Smith PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1660adebc6cSBarry Smith {
167b8840d6bSPeter Brune   PetscErrorCode ierr;
168b8840d6bSPeter Brune   SNES_QN        *qn    = (SNES_QN*)snes->data;
169b8840d6bSPeter Brune   Vec            W      = snes->work[3];
170b8840d6bSPeter Brune   Vec            *dX    = qn->U;
171b8840d6bSPeter Brune   Vec            *dF    = qn->V;
172bd052dfeSPeter Brune   PetscScalar    *alpha = qn->alpha;
173bd052dfeSPeter Brune   PetscScalar    *beta  = qn->beta;
1748e231d97SPeter Brune   PetscScalar    *dXtdF = qn->dXtdF;
175b8840d6bSPeter Brune   PetscScalar    *dFtdX = qn->dFtdX;
1768e231d97SPeter Brune   PetscScalar    *YtdX  = qn->YtdX;
177bd052dfeSPeter Brune 
17884c577daSBarry Smith   /* ksp thing for Jacobian scaling */
1797f41f16fSJed Brown   PetscInt           k,i,j,g;
1804b11644fSPeter Brune   PetscInt           m = qn->m;
1814b11644fSPeter Brune   PetscScalar        t;
1824b11644fSPeter Brune   PetscInt           l = m;
1838e231d97SPeter Brune 
1844b11644fSPeter Brune   PetscFunctionBegin;
1855ba6227bSPeter Brune   if (it < m) l = it;
1861c6523dcSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
187b8840d6bSPeter Brune   if (it > 0) {
188b8840d6bSPeter Brune     k    = (it - 1) % l;
189b8840d6bSPeter Brune     ierr = VecCopy(D,dF[k]);CHKERRQ(ierr);
190b8840d6bSPeter Brune     ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr);
191b8840d6bSPeter Brune     ierr = VecCopy(X, dX[k]);CHKERRQ(ierr);
192b8840d6bSPeter Brune     ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr);
19318aa0c0cSPeter Brune     if (qn->singlereduction) {
1941c6523dcSPeter Brune       ierr = VecMDotBegin(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
1951c6523dcSPeter Brune       ierr = VecMDotBegin(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
1961c6523dcSPeter Brune       ierr = VecMDotBegin(Y,l,dX,YtdX);CHKERRQ(ierr);
1971c6523dcSPeter Brune       ierr = VecMDotEnd(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
1981c6523dcSPeter Brune       ierr = VecMDotEnd(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
1991c6523dcSPeter Brune       ierr = VecMDotEnd(Y,l,dX,YtdX);CHKERRQ(ierr);
200b8840d6bSPeter Brune       for (j = 0; j < l; j++) {
201b8840d6bSPeter Brune         H(k, j) = dFtdX[j];
202b8840d6bSPeter Brune         H(j, k) = dXtdF[j];
203b8840d6bSPeter Brune       }
204b8840d6bSPeter Brune       /* copy back over to make the computation of alpha and beta easier */
2051aa26658SKarl Rupp       for (j = 0; j < l; j++) dXtdF[j] = H(j, j);
206b8840d6bSPeter Brune     } else {
207b8840d6bSPeter Brune       ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr);
20823d44fbcSPeter Brune     }
20923d44fbcSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
210b8840d6bSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr);
211b8840d6bSPeter Brune     }
212b8840d6bSPeter Brune   }
213b8840d6bSPeter Brune 
2144b11644fSPeter Brune   /* outward recursion starting at iteration k's update and working back */
2154b11644fSPeter Brune   for (i=0; i<l; i++) {
216b21d5a53SPeter Brune     k = (it-i-1)%l;
21718aa0c0cSPeter Brune     if (qn->singlereduction) {
2188e231d97SPeter Brune       /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */
2198e231d97SPeter Brune       t = YtdX[k];
2208e231d97SPeter Brune       for (j=0; j<i; j++) {
2218e231d97SPeter Brune         g  = (it-j-1)%l;
222b3cfccb2SPeter Brune         t -= alpha[g]*H(k, g);
2238e231d97SPeter Brune       }
2248e231d97SPeter Brune       alpha[k] = t/H(k,k);
2258e231d97SPeter Brune     } else {
2263af51624SPeter Brune       ierr     = VecDot(dX[k],Y,&t);CHKERRQ(ierr);
2278e231d97SPeter Brune       alpha[k] = t/dXtdF[k];
2288e231d97SPeter Brune     }
22944f7e39eSPeter Brune     if (qn->monitor) {
2303af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
2316bdcc836SBarry Smith       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %D k: %D alpha:        %14.12e\n", it, k, (double)PetscRealPart(alpha[k]));CHKERRQ(ierr);
2323af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
23344f7e39eSPeter Brune     }
2346bf1b2e5SPeter Brune     ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr);
2354b11644fSPeter Brune   }
2364b11644fSPeter Brune 
2370c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
238d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
239422a814eSBarry Smith     SNESCheckKSPSolve(snes);
240b8840d6bSPeter Brune     ierr              = VecCopy(W, Y);CHKERRQ(ierr);
2410ecc9e1dSPeter Brune   } else {
242b21d5a53SPeter Brune     ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr);
2430ecc9e1dSPeter Brune   }
24418aa0c0cSPeter Brune   if (qn->singlereduction) {
245b8840d6bSPeter Brune     ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr);
2468e231d97SPeter Brune   }
2474b11644fSPeter Brune   /* inward recursion starting at the first update and working forward */
248bd052dfeSPeter Brune   for (i = 0; i < l; i++) {
249b21d5a53SPeter Brune     k = (it + i - l) % l;
25018aa0c0cSPeter Brune     if (qn->singlereduction) {
2518e231d97SPeter Brune       t = YtdX[k];
2528e231d97SPeter Brune       for (j = 0; j < i; j++) {
2538e231d97SPeter Brune         g  = (it + j - l) % l;
254b3cfccb2SPeter Brune         t += (alpha[g] - beta[g])*H(g, k);
2558e231d97SPeter Brune       }
2568e231d97SPeter Brune       beta[k] = t / H(k, k);
2578e231d97SPeter Brune     } else {
2586bf1b2e5SPeter Brune       ierr    = VecDot(dF[k], Y, &t);CHKERRQ(ierr);
2598e231d97SPeter Brune       beta[k] = t / dXtdF[k];
2608e231d97SPeter Brune     }
26122d28d08SBarry Smith     ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr);
26244f7e39eSPeter Brune     if (qn->monitor) {
2633af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
2646bdcc836SBarry Smith       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %D k: %D alpha - beta: %14.12e\n", it, k, (double)PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr);
2653af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
26644f7e39eSPeter Brune     }
2674b11644fSPeter Brune   }
2684b11644fSPeter Brune   PetscFunctionReturn(0);
2694b11644fSPeter Brune }
2704b11644fSPeter Brune 
2714b11644fSPeter Brune static PetscErrorCode SNESSolve_QN(SNES snes)
2724b11644fSPeter Brune {
2734b11644fSPeter Brune   PetscErrorCode       ierr;
2749f83bee8SJed Brown   SNES_QN              *qn = (SNES_QN*) snes->data;
27515f5eeeaSPeter Brune   Vec                  X,Xold;
2760a3905e1SPeter Brune   Vec                  F,W;
27747f26062SPeter Brune   Vec                  Y,D,Dold;
278b8840d6bSPeter Brune   PetscInt             i, i_r;
279335fb975SPeter Brune   PetscReal            fnorm,xnorm,ynorm,gnorm;
280422a814eSBarry Smith   SNESLineSearchReason lssucceed;
281422a814eSBarry Smith   PetscBool            powell,periodic;
2821c6523dcSPeter Brune   PetscScalar          DolddotD,DolddotDold;
283b7281c8aSPeter Brune   SNESConvergedReason  reason;
2840ecc9e1dSPeter Brune 
28584c577daSBarry Smith   /* basically just a regular newton's method except for the application of the Jacobian */
2864b11644fSPeter Brune 
2876e111a19SKarl Rupp   PetscFunctionBegin;
2886c4ed002SBarry Smith   if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
289c579b300SPatrick Farrell 
290fffbeea8SBarry Smith   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
2919f3a0142SPeter Brune   F    = snes->vec_func;                /* residual vector */
2923af51624SPeter Brune   Y    = snes->vec_sol_update;          /* search direction generated by J^-1D*/
2930a3905e1SPeter Brune   W    = snes->work[3];
294b8840d6bSPeter Brune   X    = snes->vec_sol;                 /* solution vector */
295335fb975SPeter Brune   Xold = snes->work[0];
2963af51624SPeter Brune 
2973af51624SPeter Brune   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
298335fb975SPeter Brune   D    = snes->work[1];
299335fb975SPeter Brune   Dold = snes->work[2];
3004b11644fSPeter Brune 
3014b11644fSPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
3024b11644fSPeter Brune 
303e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3044b11644fSPeter Brune   snes->iter = 0;
3054b11644fSPeter Brune   snes->norm = 0.;
306e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
30747f26062SPeter Brune 
308efd4aadfSBarry Smith   if (snes->npc && snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
309be95d8f1SBarry Smith     ierr = SNESApplyNPC(snes,X,NULL,F);CHKERRQ(ierr);
310efd4aadfSBarry Smith     ierr = SNESGetConvergedReason(snes->npc,&reason);CHKERRQ(ierr);
311b7281c8aSPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
312b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
313b7281c8aSPeter Brune       PetscFunctionReturn(0);
314b7281c8aSPeter Brune     }
31547f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
31647f26062SPeter Brune   } else {
317e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
31815f5eeeaSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
3191aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
320c1c75074SPeter Brune 
32147f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
322422a814eSBarry Smith     SNESCheckFunctionNorm(snes,fnorm);
32347f26062SPeter Brune   }
324efd4aadfSBarry Smith   if (snes->npc && snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
325be95d8f1SBarry Smith       ierr = SNESApplyNPC(snes,X,F,D);CHKERRQ(ierr);
326efd4aadfSBarry Smith       ierr = SNESGetConvergedReason(snes->npc,&reason);CHKERRQ(ierr);
327b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
328b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
329b7281c8aSPeter Brune         PetscFunctionReturn(0);
330b7281c8aSPeter Brune       }
33147f26062SPeter Brune   } else {
33247f26062SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
33347f26062SPeter Brune   }
334b28a06ddSPeter Brune 
335e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3364b11644fSPeter Brune   snes->norm = fnorm;
337e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
338a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
3394b11644fSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
3404b11644fSPeter Brune 
3414b11644fSPeter Brune   /* test convergence */
3424b11644fSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
3434b11644fSPeter Brune   if (snes->reason) PetscFunctionReturn(0);
34470d3b23bSPeter Brune 
345efd4aadfSBarry Smith   if (snes->npc && snes->npcside== PC_RIGHT) {
346efd4aadfSBarry Smith     ierr = PetscLogEventBegin(SNES_NPCSolve,snes->npc,X,0,0);CHKERRQ(ierr);
347efd4aadfSBarry Smith     ierr = SNESSolve(snes->npc,snes->vec_rhs,X);CHKERRQ(ierr);
348efd4aadfSBarry Smith     ierr = PetscLogEventEnd(SNES_NPCSolve,snes->npc,X,0,0);CHKERRQ(ierr);
349efd4aadfSBarry Smith     ierr = SNESGetConvergedReason(snes->npc,&reason);CHKERRQ(ierr);
350ddd40ce5SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
351ddd40ce5SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
352ddd40ce5SPeter Brune       PetscFunctionReturn(0);
353ddd40ce5SPeter Brune     }
354be95d8f1SBarry Smith     ierr = SNESGetNPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
3553cf07b75SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
3563cf07b75SPeter Brune   }
3573cf07b75SPeter Brune 
358*01fe78eaSStefano Zampini   /* general purpose update */
359*01fe78eaSStefano Zampini   if (snes->ops->update) {
360*01fe78eaSStefano Zampini     ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
361*01fe78eaSStefano Zampini   }
362*01fe78eaSStefano Zampini 
363f8e15203SPeter Brune   /* scale the initial update */
3640c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
365d1e9a80fSBarry Smith     ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
36607b62357SFande Kong     SNESCheckJacobianDomainerror(snes);
367aeb49b86SAsbjørn Nilsen Riseth     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
3680ecc9e1dSPeter Brune   }
3690ecc9e1dSPeter Brune 
3705ba6227bSPeter Brune   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
3710a3905e1SPeter Brune     if (qn->scale_type == SNES_QN_SCALE_SHANNO && i_r > 0) {
3720a3905e1SPeter Brune       PetscScalar ff,xf;
3730a3905e1SPeter Brune       ierr = VecCopy(Dold,Y);CHKERRQ(ierr);
3740a3905e1SPeter Brune       ierr = VecCopy(Xold,W);CHKERRQ(ierr);
3750a3905e1SPeter Brune       ierr = VecAXPY(Y,-1.0,D);CHKERRQ(ierr);
3760a3905e1SPeter Brune       ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr);
3770a3905e1SPeter Brune       ierr = VecDotBegin(Y,Y,&ff);CHKERRQ(ierr);
3780a3905e1SPeter Brune       ierr = VecDotBegin(W,Y,&xf);CHKERRQ(ierr);
3790a3905e1SPeter Brune       ierr = VecDotEnd(Y,Y,&ff);CHKERRQ(ierr);
3800a3905e1SPeter Brune       ierr = VecDotEnd(W,Y,&xf);CHKERRQ(ierr);
3810a3905e1SPeter Brune       qn->scaling = PetscRealPart(xf)/PetscRealPart(ff);
3826bdcc836SBarry Smith       if (qn->monitor) {
3836bdcc836SBarry Smith         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
3846bdcc836SBarry Smith         ierr = PetscViewerASCIIPrintf(qn->monitor, "Shanno scaling %D %g\n", i,(double)qn->scaling);CHKERRQ(ierr);
3856bdcc836SBarry Smith         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
3866bdcc836SBarry Smith       }
3870a3905e1SPeter Brune     }
388b8840d6bSPeter Brune     switch (qn->type) {
389b8840d6bSPeter Brune     case SNES_QN_BADBROYDEN:
390b8840d6bSPeter Brune       ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
391b8840d6bSPeter Brune       break;
392b8840d6bSPeter Brune     case SNES_QN_BROYDEN:
3935051edb1SPeter Brune       ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D);CHKERRQ(ierr);
394b8840d6bSPeter Brune       break;
395b8840d6bSPeter Brune     case SNES_QN_LBFGS:
396*01fe78eaSStefano Zampini       ierr = SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
397b8840d6bSPeter Brune       break;
398b8840d6bSPeter Brune     }
39970d3b23bSPeter Brune     /* line search for lambda */
40070d3b23bSPeter Brune     ynorm = 1; gnorm = fnorm;
4010a3905e1SPeter Brune     ierr  = VecCopy(D, Dold);CHKERRQ(ierr);
40215f5eeeaSPeter Brune     ierr  = VecCopy(X, Xold);CHKERRQ(ierr);
403f1c6b773SPeter Brune     ierr  = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr);
4049f3a0142SPeter Brune     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
405422a814eSBarry Smith     ierr = SNESLineSearchGetReason(snes->linesearch, &lssucceed);CHKERRQ(ierr);
406422a814eSBarry Smith     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
407422a814eSBarry Smith     if (lssucceed) {
4089f3a0142SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
4099f3a0142SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
4109f3a0142SPeter Brune         break;
4119f3a0142SPeter Brune       }
4129f3a0142SPeter Brune     }
4130c777b0cSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
41405ee83feSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr);
4150ecc9e1dSPeter Brune     }
4163af51624SPeter Brune 
41788d374b2SPeter Brune     /* convergence monitoring */
418b21d5a53SPeter Brune     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)fnorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr);
419b21d5a53SPeter Brune 
420efd4aadfSBarry Smith     if (snes->npc && snes->npcside== PC_RIGHT) {
421efd4aadfSBarry Smith       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->npc,X,0,0);CHKERRQ(ierr);
422efd4aadfSBarry Smith       ierr = SNESSolve(snes->npc,snes->vec_rhs,X);CHKERRQ(ierr);
423efd4aadfSBarry Smith       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->npc,X,0,0);CHKERRQ(ierr);
424efd4aadfSBarry Smith       ierr = SNESGetConvergedReason(snes->npc,&reason);CHKERRQ(ierr);
425ddd40ce5SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
426ddd40ce5SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
427ddd40ce5SPeter Brune         PetscFunctionReturn(0);
428ddd40ce5SPeter Brune       }
429be95d8f1SBarry Smith       ierr = SNESGetNPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
430b28a06ddSPeter Brune     }
431b28a06ddSPeter Brune 
432360c497dSPeter Brune     ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr);
43371dbe336SPeter Brune     snes->norm = fnorm;
434c1e67a49SFande Kong     snes->xnorm = xnorm;
435c1e67a49SFande Kong     snes->ynorm = ynorm;
436360c497dSPeter Brune 
437a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
4388409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
4394b11644fSPeter Brune     /* set parameter for default relative tolerance convergence test */
440d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
4414b11644fSPeter Brune     if (snes->reason) PetscFunctionReturn(0);
442efd4aadfSBarry Smith     if (snes->npc && snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
443be95d8f1SBarry Smith       ierr = SNESApplyNPC(snes,X,F,D);CHKERRQ(ierr);
444efd4aadfSBarry Smith       ierr = SNESGetConvergedReason(snes->npc,&reason);CHKERRQ(ierr);
445b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
446b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
447b7281c8aSPeter Brune         PetscFunctionReturn(0);
448b7281c8aSPeter Brune       }
44988d374b2SPeter Brune     } else {
45088d374b2SPeter Brune       ierr = VecCopy(F, D);CHKERRQ(ierr);
45188d374b2SPeter Brune     }
452*01fe78eaSStefano Zampini 
453*01fe78eaSStefano Zampini     /* general purpose update */
454*01fe78eaSStefano Zampini     if (snes->ops->update) {
455*01fe78eaSStefano Zampini       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
456*01fe78eaSStefano Zampini     }
457*01fe78eaSStefano Zampini 
4580c777b0cSPeter Brune     powell = PETSC_FALSE;
4596bdcc836SBarry Smith     if (qn->restart_type == SNES_QN_RESTART_POWELL && i_r > 1) {
4606bdcc836SBarry Smith       /* check restart by Powell's Criterion: |F^T H_0 Fold| > powell_gamma * |Fold^T H_0 Fold| */
46123c918e7SPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
46223c918e7SPeter Brune         ierr = MatMult(snes->jacobian_pre,Dold,W);CHKERRQ(ierr);
46323c918e7SPeter Brune       } else {
46423c918e7SPeter Brune         ierr = VecCopy(Dold,W);CHKERRQ(ierr);
46523c918e7SPeter Brune       }
46623c918e7SPeter Brune       ierr = VecDotBegin(W, Dold, &DolddotDold);CHKERRQ(ierr);
46723c918e7SPeter Brune       ierr = VecDotBegin(W, D, &DolddotD);CHKERRQ(ierr);
46823c918e7SPeter Brune       ierr = VecDotEnd(W, Dold, &DolddotDold);CHKERRQ(ierr);
46923c918e7SPeter Brune       ierr = VecDotEnd(W, D, &DolddotD);CHKERRQ(ierr);
4700c777b0cSPeter Brune       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
4710c777b0cSPeter Brune     }
4720c777b0cSPeter Brune     periodic = PETSC_FALSE;
473b8840d6bSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
474b8840d6bSPeter Brune       if (i_r>qn->m-1) periodic = PETSC_TRUE;
4750c777b0cSPeter Brune     }
4760c777b0cSPeter Brune     /* restart if either powell or periodic restart is satisfied. */
4770c777b0cSPeter Brune     if (powell || periodic) {
4785ba6227bSPeter Brune       if (qn->monitor) {
4795ba6227bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
4806bdcc836SBarry Smith         if (powell) {
4816bdcc836SBarry Smith           ierr = PetscViewerASCIIPrintf(qn->monitor, "Powell restart! |%14.12e| > %6.4f*|%14.12e| i_r = %D\n", (double)PetscRealPart(DolddotD), (double)qn->powell_gamma, (double)PetscRealPart(DolddotDold),i_r);CHKERRQ(ierr);
4826bdcc836SBarry Smith         } else {
4836bdcc836SBarry Smith           ierr = PetscViewerASCIIPrintf(qn->monitor, "Periodic restart! i_r = %D\n", i_r);CHKERRQ(ierr);
4846bdcc836SBarry Smith         }
4855ba6227bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
4865ba6227bSPeter Brune       }
4875ba6227bSPeter Brune       i_r = -1;
4880c777b0cSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
489d1e9a80fSBarry Smith         ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
49007b62357SFande Kong         SNESCheckJacobianDomainerror(snes);
4910ecc9e1dSPeter Brune       }
4920ecc9e1dSPeter Brune     }
4935ba6227bSPeter Brune   }
4944b11644fSPeter Brune   if (i == snes->max_its) {
4954b11644fSPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr);
4964b11644fSPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
4974b11644fSPeter Brune   }
4984b11644fSPeter Brune   PetscFunctionReturn(0);
4994b11644fSPeter Brune }
5004b11644fSPeter Brune 
5014b11644fSPeter Brune static PetscErrorCode SNESSetUp_QN(SNES snes)
5024b11644fSPeter Brune {
5039f83bee8SJed Brown   SNES_QN        *qn = (SNES_QN*)snes->data;
5044b11644fSPeter Brune   PetscErrorCode ierr;
505fced5a79SAsbjørn Nilsen Riseth   DM             dm;
506335fb975SPeter Brune 
5074b11644fSPeter Brune   PetscFunctionBegin;
508fced5a79SAsbjørn Nilsen Riseth 
509fced5a79SAsbjørn Nilsen Riseth   if (!snes->vec_sol) {
510fced5a79SAsbjørn Nilsen Riseth     ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
511fced5a79SAsbjørn Nilsen Riseth     ierr = DMCreateGlobalVector(dm,&snes->vec_sol);CHKERRQ(ierr);
512fced5a79SAsbjørn Nilsen Riseth   }
513fced5a79SAsbjørn Nilsen Riseth 
514b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr);
51559e7931aSPeter Brune   if (qn->type != SNES_QN_BROYDEN) ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr);
516dcca6d9dSJed Brown   ierr = PetscMalloc4(qn->m,&qn->alpha,qn->m,&qn->beta,qn->m,&qn->dXtdF,qn->m,&qn->lambda);CHKERRQ(ierr);
5178e231d97SPeter Brune 
51818aa0c0cSPeter Brune   if (qn->singlereduction) {
519dcca6d9dSJed Brown     ierr = PetscMalloc3(qn->m*qn->m,&qn->dXdFmat,qn->m,&qn->dFtdX,qn->m,&qn->YtdX);CHKERRQ(ierr);
5208e231d97SPeter Brune   }
521fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr);
52260c08b40SPeter Brune   /* set method defaults */
5231efc8c45SPeter Brune   if (qn->scale_type == SNES_QN_SCALE_DEFAULT) {
52460c08b40SPeter Brune     if (qn->type == SNES_QN_BADBROYDEN) {
52560c08b40SPeter Brune       qn->scale_type = SNES_QN_SCALE_NONE;
52660c08b40SPeter Brune     } else {
52760c08b40SPeter Brune       qn->scale_type = SNES_QN_SCALE_SHANNO;
52860c08b40SPeter Brune     }
52960c08b40SPeter Brune   }
5301efc8c45SPeter Brune   if (qn->restart_type == SNES_QN_RESTART_DEFAULT) {
53160c08b40SPeter Brune     if (qn->type == SNES_QN_LBFGS) {
53260c08b40SPeter Brune       qn->restart_type = SNES_QN_RESTART_POWELL;
53360c08b40SPeter Brune     } else {
53460c08b40SPeter Brune       qn->restart_type = SNES_QN_RESTART_PERIODIC;
53560c08b40SPeter Brune     }
53660c08b40SPeter Brune   }
53760c08b40SPeter Brune 
5380c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5398e231d97SPeter Brune     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
5408e231d97SPeter Brune   }
541efd4aadfSBarry Smith   if (snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;}
5424b11644fSPeter Brune   PetscFunctionReturn(0);
5434b11644fSPeter Brune }
5444b11644fSPeter Brune 
5454b11644fSPeter Brune static PetscErrorCode SNESReset_QN(SNES snes)
5464b11644fSPeter Brune {
5474b11644fSPeter Brune   PetscErrorCode ierr;
5489f83bee8SJed Brown   SNES_QN        *qn;
5490adebc6cSBarry Smith 
5504b11644fSPeter Brune   PetscFunctionBegin;
5514b11644fSPeter Brune   if (snes->data) {
5529f83bee8SJed Brown     qn = (SNES_QN*)snes->data;
553b8840d6bSPeter Brune     if (qn->U) {
554b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr);
5554b11644fSPeter Brune     }
556b8840d6bSPeter Brune     if (qn->V) {
557b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr);
5584b11644fSPeter Brune     }
55918aa0c0cSPeter Brune     if (qn->singlereduction) {
5608e231d97SPeter Brune       ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr);
5618e231d97SPeter Brune     }
5625c7a0a03SPeter Brune     ierr = PetscFree4(qn->alpha,qn->beta,qn->dXtdF,qn->lambda);CHKERRQ(ierr);
5634b11644fSPeter Brune   }
5644b11644fSPeter Brune   PetscFunctionReturn(0);
5654b11644fSPeter Brune }
5664b11644fSPeter Brune 
5674b11644fSPeter Brune static PetscErrorCode SNESDestroy_QN(SNES snes)
5684b11644fSPeter Brune {
5694b11644fSPeter Brune   PetscErrorCode ierr;
5706e111a19SKarl Rupp 
5714b11644fSPeter Brune   PetscFunctionBegin;
5724b11644fSPeter Brune   ierr = SNESReset_QN(snes);CHKERRQ(ierr);
5734b11644fSPeter Brune   ierr = PetscFree(snes->data);CHKERRQ(ierr);
574bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr);
5754b11644fSPeter Brune   PetscFunctionReturn(0);
5764b11644fSPeter Brune }
5774b11644fSPeter Brune 
5784416b707SBarry Smith static PetscErrorCode SNESSetFromOptions_QN(PetscOptionItems *PetscOptionsObject,SNES snes)
5794b11644fSPeter Brune {
5804b11644fSPeter Brune 
5814b11644fSPeter Brune   PetscErrorCode    ierr;
5822150357eSBarry Smith   SNES_QN           *qn    = (SNES_QN*)snes->data;
58388f769c5SPeter Brune   PetscBool         monflg = PETSC_FALSE,flg;
584f1c6b773SPeter Brune   SNESLineSearch    linesearch;
5852150357eSBarry Smith   SNESQNRestartType rtype = qn->restart_type;
5862150357eSBarry Smith   SNESQNScaleType   stype = qn->scale_type;
5871efc8c45SPeter Brune   SNESQNType        qtype = qn->type;
5882150357eSBarry Smith 
5894b11644fSPeter Brune   PetscFunctionBegin;
590e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"SNES QN options");CHKERRQ(ierr);
5910298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,NULL);CHKERRQ(ierr);
5920298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance",          "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL);CHKERRQ(ierr);
5930298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_monitor",         "Monitor for the QN methods",      "SNESQN", monflg, &monflg, NULL);CHKERRQ(ierr);
5940298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions",           "SNESQN", qn->singlereduction, &qn->singlereduction, NULL);CHKERRQ(ierr);
59588f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr);
59688f769c5SPeter Brune   if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr);
59788f769c5SPeter Brune 
59888f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr);
59988f769c5SPeter Brune   if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr);
60088f769c5SPeter Brune 
6010fdccdaeSBarry Smith   ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes,(PetscEnum)qtype,(PetscEnum*)&qtype,&flg);CHKERRQ(ierr);
6021efc8c45SPeter Brune   if (flg) {ierr = SNESQNSetType(snes,qtype);CHKERRQ(ierr);}
6034b11644fSPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
6049e764e56SPeter Brune   if (!snes->linesearch) {
6057601faf0SJed Brown     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
60660c08b40SPeter Brune     if (qn->type == SNES_QN_LBFGS) {
6071a4f838cSPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
60860c08b40SPeter Brune     } else if (qn->type == SNES_QN_BROYDEN) {
60960c08b40SPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC);CHKERRQ(ierr);
61060c08b40SPeter Brune     } else {
61160c08b40SPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
61260c08b40SPeter Brune     }
6139e764e56SPeter Brune   }
61444f7e39eSPeter Brune   if (monflg) {
615ce94432eSBarry Smith     qn->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
61644f7e39eSPeter Brune   }
6174b11644fSPeter Brune   PetscFunctionReturn(0);
6184b11644fSPeter Brune }
6194b11644fSPeter Brune 
6205cd83419SPeter Brune static PetscErrorCode SNESView_QN(SNES snes, PetscViewer viewer)
6215cd83419SPeter Brune {
6225cd83419SPeter Brune   SNES_QN        *qn    = (SNES_QN*)snes->data;
6235cd83419SPeter Brune   PetscBool      iascii;
6245cd83419SPeter Brune   PetscErrorCode ierr;
6255cd83419SPeter Brune 
6265cd83419SPeter Brune   PetscFunctionBegin;
6275cd83419SPeter Brune   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
6285cd83419SPeter Brune   if (iascii) {
629efd4aadfSBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  type is %s, restart type is %s, scale type is %s\n",SNESQNTypes[qn->type],SNESQNRestartTypes[qn->restart_type],SNESQNScaleTypes[qn->scale_type]);CHKERRQ(ierr);
6306bdcc836SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  Stored subspace size: %D\n", qn->m);CHKERRQ(ierr);
6315cd83419SPeter Brune     if (qn->singlereduction) {
6325cd83419SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer,"  Using the single reduction variant.\n");CHKERRQ(ierr);
6335cd83419SPeter Brune     }
6345cd83419SPeter Brune   }
6355cd83419SPeter Brune   PetscFunctionReturn(0);
6365cd83419SPeter Brune }
63792c02d66SPeter Brune 
6380c777b0cSPeter Brune /*@
6390c777b0cSPeter Brune     SNESQNSetRestartType - Sets the restart type for SNESQN.
6400c777b0cSPeter Brune 
6410c777b0cSPeter Brune     Logically Collective on SNES
6420c777b0cSPeter Brune 
6430c777b0cSPeter Brune     Input Parameters:
6440c777b0cSPeter Brune +   snes - the iterative context
6450c777b0cSPeter Brune -   rtype - restart type
6460c777b0cSPeter Brune 
6470c777b0cSPeter Brune     Options Database:
6480c777b0cSPeter Brune +   -snes_qn_restart_type <powell,periodic,none> - set the restart type
64984c577daSBarry Smith -   -snes_qn_m <m> - sets the number of stored updates and the restart period for periodic
6500c777b0cSPeter Brune 
6510c777b0cSPeter Brune     Level: intermediate
6520c777b0cSPeter Brune 
6530c777b0cSPeter Brune     SNESQNRestartTypes:
6540c777b0cSPeter Brune +   SNES_QN_RESTART_NONE - never restart
6550c777b0cSPeter Brune .   SNES_QN_RESTART_POWELL - restart based upon descent criteria
6560c777b0cSPeter Brune -   SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations
6570c777b0cSPeter Brune 
65884c577daSBarry Smith .keywords: SNES, SNESQN, restart, type, set SNESLineSearch, SNESQNRestartType
6590c777b0cSPeter Brune @*/
6602150357eSBarry Smith PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
6612150357eSBarry Smith {
6620c777b0cSPeter Brune   PetscErrorCode ierr;
6636e111a19SKarl Rupp 
6640c777b0cSPeter Brune   PetscFunctionBegin;
6650c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
6660c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr);
6670c777b0cSPeter Brune   PetscFunctionReturn(0);
6680c777b0cSPeter Brune }
6690c777b0cSPeter Brune 
6700c777b0cSPeter Brune /*@
67184c577daSBarry Smith     SNESQNSetScaleType - Sets the scaling type for the inner inverse Jacobian in SNESQN.
6720c777b0cSPeter Brune 
6730c777b0cSPeter Brune     Logically Collective on SNES
6740c777b0cSPeter Brune 
6750c777b0cSPeter Brune     Input Parameters:
6760c777b0cSPeter Brune +   snes - the iterative context
6770c777b0cSPeter Brune -   stype - scale type
6780c777b0cSPeter Brune 
6790c777b0cSPeter Brune     Options Database:
6800c777b0cSPeter Brune .   -snes_qn_scale_type <shanno,none,linesearch,jacobian>
6810c777b0cSPeter Brune 
6820c777b0cSPeter Brune     Level: intermediate
6830c777b0cSPeter Brune 
68484c577daSBarry Smith     SNESQNScaleTypes:
6850c777b0cSPeter Brune +   SNES_QN_SCALE_NONE - don't scale the problem
6860c777b0cSPeter Brune .   SNES_QN_SCALE_SHANNO - use shanno scaling
6870c777b0cSPeter Brune .   SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda
688a01a0525SBarry Smith -   SNES_QN_SCALE_JACOBIAN - scale by solving a linear system coming from the Jacobian you provided with SNESSetJacobian() computed at the first iteration
689a01a0525SBarry Smith                              of QN and at ever restart.
6900c777b0cSPeter Brune 
691a01a0525SBarry Smith .keywords: scaling type
692a01a0525SBarry Smith 
693a01a0525SBarry Smith .seealso: SNES, SNESQN, SNESLineSearch, SNESQNScaleType, SNESetJacobian()
6940c777b0cSPeter Brune @*/
6950c777b0cSPeter Brune 
6962150357eSBarry Smith PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
6972150357eSBarry Smith {
6980c777b0cSPeter Brune   PetscErrorCode ierr;
6996e111a19SKarl Rupp 
7000c777b0cSPeter Brune   PetscFunctionBegin;
7010c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
7020c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr);
7030c777b0cSPeter Brune   PetscFunctionReturn(0);
7040c777b0cSPeter Brune }
7050c777b0cSPeter Brune 
7060adebc6cSBarry Smith PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
7070adebc6cSBarry Smith {
7080c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7096e111a19SKarl Rupp 
7100c777b0cSPeter Brune   PetscFunctionBegin;
7110c777b0cSPeter Brune   qn->scale_type = stype;
7120c777b0cSPeter Brune   PetscFunctionReturn(0);
7130c777b0cSPeter Brune }
7140c777b0cSPeter Brune 
7150adebc6cSBarry Smith PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
7160adebc6cSBarry Smith {
7170c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7186e111a19SKarl Rupp 
7190c777b0cSPeter Brune   PetscFunctionBegin;
7200c777b0cSPeter Brune   qn->restart_type = rtype;
7210c777b0cSPeter Brune   PetscFunctionReturn(0);
7220c777b0cSPeter Brune }
7230c777b0cSPeter Brune 
7241efc8c45SPeter Brune /*@
7251efc8c45SPeter Brune     SNESQNSetType - Sets the quasi-Newton variant to be used in SNESQN.
7261efc8c45SPeter Brune 
7271efc8c45SPeter Brune     Logically Collective on SNES
7281efc8c45SPeter Brune 
7291efc8c45SPeter Brune     Input Parameters:
7301efc8c45SPeter Brune +   snes - the iterative context
7311efc8c45SPeter Brune -   qtype - variant type
7321efc8c45SPeter Brune 
7331efc8c45SPeter Brune     Options Database:
73484c577daSBarry Smith .   -snes_qn_type <lbfgs,broyden,badbroyden>
7351efc8c45SPeter Brune 
7361efc8c45SPeter Brune     Level: beginner
7371efc8c45SPeter Brune 
7381efc8c45SPeter Brune     SNESQNTypes:
7391efc8c45SPeter Brune +   SNES_QN_LBFGS - LBFGS variant
7401efc8c45SPeter Brune .   SNES_QN_BROYDEN - Broyden variant
7411efc8c45SPeter Brune -   SNES_QN_BADBROYDEN - Bad Broyden variant
7421efc8c45SPeter Brune 
74384c577daSBarry Smith .keywords: SNES, SNESQN, type, set, SNESQNType
7441efc8c45SPeter Brune @*/
7451efc8c45SPeter Brune 
7461efc8c45SPeter Brune PetscErrorCode SNESQNSetType(SNES snes, SNESQNType qtype)
7471efc8c45SPeter Brune {
7481efc8c45SPeter Brune   PetscErrorCode ierr;
7491efc8c45SPeter Brune 
7501efc8c45SPeter Brune   PetscFunctionBegin;
7511efc8c45SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
7521efc8c45SPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetType_C",(SNES,SNESQNType),(snes,qtype));CHKERRQ(ierr);
7531efc8c45SPeter Brune   PetscFunctionReturn(0);
7541efc8c45SPeter Brune }
7551efc8c45SPeter Brune 
7561efc8c45SPeter Brune PetscErrorCode SNESQNSetType_QN(SNES snes, SNESQNType qtype)
7571efc8c45SPeter Brune {
7581efc8c45SPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7591efc8c45SPeter Brune 
7601efc8c45SPeter Brune   PetscFunctionBegin;
7611efc8c45SPeter Brune   qn->type = qtype;
7621efc8c45SPeter Brune   PetscFunctionReturn(0);
7631efc8c45SPeter Brune }
7641efc8c45SPeter Brune 
7654b11644fSPeter Brune /* -------------------------------------------------------------------------- */
7664b11644fSPeter Brune /*MC
7674b11644fSPeter Brune       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
7684b11644fSPeter Brune 
7696cc8130cSPeter Brune       Options Database:
7706cc8130cSPeter Brune 
77184c577daSBarry Smith +     -snes_qn_m <m> - Number of past states saved for the L-Broyden methods.
77284c577daSBarry Smith +     -snes_qn_restart_type <powell,periodic,none> - set the restart type
7736bdcc836SBarry Smith .     -snes_qn_powell_gamma - Angle condition for restart.
7741867fe5bSPeter Brune .     -snes_qn_powell_descent - Descent condition for restart.
77584c577daSBarry Smith .     -snes_qn_type <lbfgs,broyden,badbroyden> - QN type
77684c577daSBarry Smith .     -snes_qn_scale_type <shanno,none,linesearch,jacobian> - scaling performed on inner Jacobian
77772835e02SPeter Brune .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
77884c577daSBarry Smith -     -snes_qn_monitor - Monitors the quasi-newton Jacobian.
7796cc8130cSPeter Brune 
78095452b02SPatrick Sanan       Notes:
78195452b02SPatrick Sanan     This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
782b8840d6bSPeter Brune       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
783b8840d6bSPeter Brune       updates.
7846cc8130cSPeter Brune 
7851867fe5bSPeter Brune       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
7861867fe5bSPeter Brune       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
78784c577daSBarry Smith       iteration as the current iteration's values when constructing the approximate Jacobian.  The second, composed,
78884c577daSBarry Smith       perturbs the problem the Jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
7891867fe5bSPeter Brune 
7902d547940SBarry Smith       Uses left nonlinear preconditioning by default.
7912d547940SBarry Smith 
7926cc8130cSPeter Brune       References:
79396a0c994SBarry Smith +   1. -   Kelley, C.T., Iterative Methods for Linear and Nonlinear Equations, Chapter 8, SIAM, 1995.
79496a0c994SBarry Smith .   2. -   R. Byrd, J. Nocedal, R. Schnabel, Representations of Quasi Newton Matrices and their use in Limited Memory Methods,
7950a8e8854SPeter Brune       Technical Report, Northwestern University, June 1992.
79696a0c994SBarry Smith .   3. -   Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker, Experiments with Quasi-Newton Methods in Solving Stiff ODE
7970a8e8854SPeter Brune       Systems, SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
79896a0c994SBarry Smith -   4. -   Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers",
7994f02bc6aSBarry Smith        SIAM Review, 57(4), 2015
8004b11644fSPeter Brune 
8014b11644fSPeter Brune       Level: beginner
8024b11644fSPeter Brune 
80304d7464bSBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR
8046cc8130cSPeter Brune 
8054b11644fSPeter Brune M*/
8068cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes)
8074b11644fSPeter Brune {
8084b11644fSPeter Brune   PetscErrorCode ierr;
8099f83bee8SJed Brown   SNES_QN        *qn;
8104b11644fSPeter Brune 
8114b11644fSPeter Brune   PetscFunctionBegin;
8124b11644fSPeter Brune   snes->ops->setup          = SNESSetUp_QN;
8134b11644fSPeter Brune   snes->ops->solve          = SNESSolve_QN;
8144b11644fSPeter Brune   snes->ops->destroy        = SNESDestroy_QN;
8154b11644fSPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_QN;
8165cd83419SPeter Brune   snes->ops->view           = SNESView_QN;
8174b11644fSPeter Brune   snes->ops->reset          = SNESReset_QN;
8184b11644fSPeter Brune 
819efd4aadfSBarry Smith   snes->npcside= PC_LEFT;
82047f26062SPeter Brune 
821efd4aadfSBarry Smith   snes->usesnpc = PETSC_TRUE;
82242f4f86dSBarry Smith   snes->usesksp = PETSC_FALSE;
82342f4f86dSBarry Smith 
8244fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
8254fc747eaSLawrence Mitchell 
82688976e71SPeter Brune   if (!snes->tolerancesset) {
8270e444f03SPeter Brune     snes->max_funcs = 30000;
8280e444f03SPeter Brune     snes->max_its   = 10000;
82988976e71SPeter Brune   }
8300e444f03SPeter Brune 
831b00a9115SJed Brown   ierr                = PetscNewLog(snes,&qn);CHKERRQ(ierr);
8324b11644fSPeter Brune   snes->data          = (void*) qn;
8330ecc9e1dSPeter Brune   qn->m               = 10;
834b21d5a53SPeter Brune   qn->scaling         = 1.0;
8350298fd71SBarry Smith   qn->U               = NULL;
8360298fd71SBarry Smith   qn->V               = NULL;
8370298fd71SBarry Smith   qn->dXtdF           = NULL;
8380298fd71SBarry Smith   qn->dFtdX           = NULL;
8390298fd71SBarry Smith   qn->dXdFmat         = NULL;
8400298fd71SBarry Smith   qn->monitor         = NULL;
8411c6523dcSPeter Brune   qn->singlereduction = PETSC_TRUE;
842b8840d6bSPeter Brune   qn->powell_gamma    = 0.9999;
84360c08b40SPeter Brune   qn->scale_type      = SNES_QN_SCALE_DEFAULT;
84460c08b40SPeter Brune   qn->restart_type    = SNES_QN_RESTART_DEFAULT;
845b8840d6bSPeter Brune   qn->type            = SNES_QN_LBFGS;
846ea630c6eSPeter Brune 
847bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetScaleType_C",SNESQNSetScaleType_QN);CHKERRQ(ierr);
848bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetRestartType_C",SNESQNSetRestartType_QN);CHKERRQ(ierr);
8491efc8c45SPeter Brune   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetType_C",SNESQNSetType_QN);CHKERRQ(ierr);
8504b11644fSPeter Brune   PetscFunctionReturn(0);
8514b11644fSPeter Brune }
852