xref: /petsc/src/snes/impls/qn/qn.c (revision 5c7a0a030075ba112928715984eedf01346bbd47)
10c777b0cSPeter Brune #include <petsc-private/snesimpl.h> /*I "petscsnes.h" I*/
24b11644fSPeter Brune 
38e231d97SPeter Brune #define H(i,j)  qn->dXdFmat[i*qn->m + j]
48e231d97SPeter Brune 
56a6fc655SJed Brown const char *const SNESQNScaleTypes[] =        {"NONE","SHANNO","LINESEARCH","JACOBIAN","SNESQNScaleType","SNES_QN_SCALING_",0};
66a6fc655SJed Brown const char *const SNESQNRestartTypes[] =      {"NONE","POWELL","PERIODIC","SNESQNRestartType","SNES_QN_RESTART_",0};
7b8840d6bSPeter Brune const char *const SNESQNTypes[] =             {"LBFGS","BROYDEN","BADBROYDEN","SNESQNType","SNES_QN_RESTART_",0};
8b8840d6bSPeter Brune 
9b8840d6bSPeter Brune typedef enum {SNES_QN_LBFGS      = 0,
10b8840d6bSPeter Brune               SNES_QN_BROYDEN    = 1,
110ad7597dSKarl Rupp               SNES_QN_BADBROYDEN = 2
120ad7597dSKarl Rupp              } SNESQNType;
136bf1b2e5SPeter Brune 
144b11644fSPeter Brune typedef struct {
15b8840d6bSPeter Brune   Vec               *U;                   /* Stored past states (vary from method to method) */
16b8840d6bSPeter Brune   Vec               *V;                   /* Stored past states (vary from method to method) */
178e231d97SPeter Brune   PetscInt          m;                    /* The number of kept previous steps */
18*5c7a0a03SPeter Brune   PetscReal         *lambda;              /* The line search history of the method */
19*5c7a0a03SPeter Brune   PetscReal         *norm;                /* norms of the steps */
208e231d97SPeter Brune   PetscScalar       *alpha, *beta;
218e231d97SPeter Brune   PetscScalar       *dXtdF, *dFtdX, *YtdX;
2218aa0c0cSPeter Brune   PetscBool         singlereduction;      /* Aggregated reduction implementation */
238e231d97SPeter Brune   PetscScalar       *dXdFmat;             /* A matrix of values for dX_i dot dF_j */
2444f7e39eSPeter Brune   PetscViewer       monitor;
256bf1b2e5SPeter Brune   PetscReal         powell_gamma;         /* Powell angle restart condition */
266bf1b2e5SPeter Brune   PetscReal         powell_downhill;      /* Powell descent restart condition */
27b21d5a53SPeter Brune   PetscReal         scaling;              /* scaling of H0 */
28b8840d6bSPeter Brune   SNESQNType        type;                 /* the type of quasi-newton method used */
2988f769c5SPeter Brune   SNESQNScaleType   scale_type;           /* the type of scaling used */
300c777b0cSPeter Brune   SNESQNRestartType restart_type;         /* determine the frequency and type of restart conditions */
319f83bee8SJed Brown } SNES_QN;
324b11644fSPeter Brune 
334b11644fSPeter Brune #undef __FUNCT__
34b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_Broyden"
352150357eSBarry Smith PetscErrorCode SNESQNApply_Broyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold, Vec D, Vec Dold)
362150357eSBarry Smith {
374b11644fSPeter Brune   PetscErrorCode     ierr;
389f83bee8SJed Brown   SNES_QN            *qn = (SNES_QN*)snes->data;
39b8840d6bSPeter Brune   Vec                W   = snes->work[3];
40b8840d6bSPeter Brune   Vec                *U  = qn->U;
41b8840d6bSPeter Brune   KSPConvergedReason kspreason;
42b8840d6bSPeter Brune   PetscInt           m = qn->m;
43*5c7a0a03SPeter Brune   PetscInt           k,i,j,lits,l = m;
44*5c7a0a03SPeter Brune   PetscReal          unorm,a,b;
45*5c7a0a03SPeter Brune   PetscReal          *lambda=qn->lambda;
46b8840d6bSPeter Brune   PetscScalar        gdot;
472150357eSBarry Smith 
48b8840d6bSPeter Brune   PetscFunctionBegin;
49b8840d6bSPeter Brune   if (it < m) l = it;
50*5c7a0a03SPeter Brune   if (it > 0) {
51*5c7a0a03SPeter Brune     k = (it-1)%l;
52*5c7a0a03SPeter Brune     ierr = SNESLineSearchGetLambda(snes->linesearch,&lambda[k]);CHKERRQ(ierr);
53*5c7a0a03SPeter Brune     ierr = VecScale(U[k],lambda[k]);CHKERRQ(ierr);
54*5c7a0a03SPeter Brune     if (qn->monitor) {
55*5c7a0a03SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
56*5c7a0a03SPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "scaling vector %d of %d by lambda: %14.12e \n",k,l,lambda[k]);CHKERRQ(ierr);
57*5c7a0a03SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
58*5c7a0a03SPeter Brune     }
59*5c7a0a03SPeter Brune   }
60b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
61d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,D,W);CHKERRQ(ierr);
62b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
63b8840d6bSPeter Brune     if (kspreason < 0) {
64b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
65b8840d6bSPeter Brune         ierr         = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
66b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
67b8840d6bSPeter Brune         PetscFunctionReturn(0);
68b8840d6bSPeter Brune       }
69b8840d6bSPeter Brune     }
70b8840d6bSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
71b8840d6bSPeter Brune     snes->linear_its += lits;
72b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
73b8840d6bSPeter Brune   } else {
74b8840d6bSPeter Brune     ierr = VecCopy(D,Y);CHKERRQ(ierr);
75b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
76b8840d6bSPeter Brune   }
77b8840d6bSPeter Brune 
78b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
79b8840d6bSPeter Brune   for (i = 0; i < l-1; i++) {
80*5c7a0a03SPeter Brune     j = (it+i-l)%l;
81*5c7a0a03SPeter Brune     k = (it+i-l+1)%l;
82*5c7a0a03SPeter Brune 
83*5c7a0a03SPeter Brune     ierr = VecNorm(U[j],NORM_2,&unorm);CHKERRQ(ierr);
84*5c7a0a03SPeter Brune     ierr = VecDot(U[j],Y,&gdot);CHKERRQ(ierr);
85*5c7a0a03SPeter Brune 
86*5c7a0a03SPeter Brune     /* ierr = VecAXPY(Y,gdot/PetscSqr(unorm),U[k]);CHKERRQ(ierr); */
87*5c7a0a03SPeter Brune     a = (lambda[j]/lambda[k]);
88*5c7a0a03SPeter Brune     b = -(1.-lambda[j]);
89*5c7a0a03SPeter Brune     a *= gdot/PetscSqr(unorm);
90*5c7a0a03SPeter Brune     b *= gdot/PetscSqr(unorm);
91*5c7a0a03SPeter Brune     ierr = VecAXPBYPCZ(Y,a,b,1.,U[k],U[j]);CHKERRQ(ierr);
92*5c7a0a03SPeter Brune 
93b8840d6bSPeter Brune     if (qn->monitor) {
94b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
95*5c7a0a03SPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d and %d, gdot: %14.12e\n",k,j,gdot);CHKERRQ(ierr);
96b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
97b8840d6bSPeter Brune     }
98b8840d6bSPeter Brune   }
99b8840d6bSPeter Brune   if (l > 0) {
100b8840d6bSPeter Brune     k = (it-1)%l;
101b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
102*5c7a0a03SPeter Brune     ierr = VecNorm(U[k],NORM_2,&unorm);CHKERRQ(ierr);
103b8840d6bSPeter Brune     if (qn->monitor) {
104b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
105*5c7a0a03SPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d: norm: %14.12e dot: %14.12e lambda: %14.12e scaling: %14.12e \n",k,gdot,unorm,lambda[k],1. - gdot/PetscSqr(unorm));CHKERRQ(ierr);
106b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
107b8840d6bSPeter Brune     }
108*5c7a0a03SPeter Brune     /* ierr = VecScale(Y,1./(1.-gdot/PetscSqr(unorm)));CHKERRQ(ierr); */
109*5c7a0a03SPeter Brune     a = PetscSqr(unorm)/(PetscSqr(unorm)-lambda[k]*gdot);
110*5c7a0a03SPeter Brune     b = -(1.-lambda[k])*gdot/(PetscSqr(unorm)-lambda[k]*gdot);
111*5c7a0a03SPeter Brune     ierr = VecAXPBY(Y,b,a,U[k]);CHKERRQ(ierr);
112b8840d6bSPeter Brune   }
113*5c7a0a03SPeter Brune   l = m;
114*5c7a0a03SPeter Brune   if (it+1<m)l=it+1;
115*5c7a0a03SPeter Brune   k = it%l;
116*5c7a0a03SPeter Brune   if (qn->monitor) {
117*5c7a0a03SPeter Brune     ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
118*5c7a0a03SPeter Brune     ierr = PetscViewerASCIIPrintf(qn->monitor, "setting vector %d of %d\n",k,l);CHKERRQ(ierr);
119*5c7a0a03SPeter Brune     ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
120*5c7a0a03SPeter Brune   }
121*5c7a0a03SPeter Brune   ierr = VecCopy(Y,U[k]);CHKERRQ(ierr);
122b8840d6bSPeter Brune  PetscFunctionReturn(0);
123b8840d6bSPeter Brune }
124b8840d6bSPeter Brune 
125b8840d6bSPeter Brune #undef __FUNCT__
126b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_BadBroyden"
1270adebc6cSBarry Smith PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1280adebc6cSBarry Smith {
129b8840d6bSPeter Brune   PetscErrorCode ierr;
130b8840d6bSPeter Brune   SNES_QN        *qn = (SNES_QN*)snes->data;
131b8840d6bSPeter Brune   Vec            W   = snes->work[3];
132b8840d6bSPeter Brune   Vec            *U  = qn->U;
133b8840d6bSPeter Brune   Vec            *T  = qn->V;
134b8840d6bSPeter Brune 
135b8840d6bSPeter Brune   /* ksp thing for jacobian scaling */
136b8840d6bSPeter Brune   KSPConvergedReason kspreason;
137b8840d6bSPeter Brune   PetscInt           k, i, lits;
138b8840d6bSPeter Brune   PetscInt           m = qn->m;
139b8840d6bSPeter Brune   PetscScalar        gdot;
140b8840d6bSPeter Brune   PetscInt           l = m;
1410adebc6cSBarry Smith 
142b8840d6bSPeter Brune   PetscFunctionBegin;
143b8840d6bSPeter Brune   if (it < m) l = it;
144b8840d6bSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
145b8840d6bSPeter Brune   if (l > 0) {
146b8840d6bSPeter Brune     k    = (it-1)%l;
147b8840d6bSPeter Brune     ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr);
148b8840d6bSPeter Brune     ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr);
149b8840d6bSPeter Brune     ierr = VecDot(U[k],U[k],&gdot);CHKERRQ(ierr);
150b8840d6bSPeter Brune     ierr = VecCopy(D,T[k]);CHKERRQ(ierr);
151b8840d6bSPeter Brune     ierr = VecScale(T[k],1.0/gdot);CHKERRQ(ierr);
152b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
153b8840d6bSPeter Brune     ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
154b8840d6bSPeter Brune     if (qn->monitor) {
155b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
156b8840d6bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "update: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
157b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
158b8840d6bSPeter Brune     }
159b8840d6bSPeter Brune   }
160b8840d6bSPeter Brune 
161b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
162b8840d6bSPeter Brune   if (it > 1) {
163b8840d6bSPeter Brune     for (i = 0; i < l-1; i++) {
164b8840d6bSPeter Brune       k    = (it+i-l)%l;
165b8840d6bSPeter Brune       ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
166b8840d6bSPeter Brune       ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
167b8840d6bSPeter Brune       if (qn->monitor) {
168b8840d6bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
169b8840d6bSPeter Brune         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
170b8840d6bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
171b8840d6bSPeter Brune       }
172b8840d6bSPeter Brune     }
173b8840d6bSPeter Brune   }
174b8840d6bSPeter Brune 
175b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
176d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
177b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
178b8840d6bSPeter Brune     if (kspreason < 0) {
179b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
180b8840d6bSPeter Brune         ierr         = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
181b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
182b8840d6bSPeter Brune         PetscFunctionReturn(0);
183b8840d6bSPeter Brune       }
184b8840d6bSPeter Brune     }
185b8840d6bSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
186b8840d6bSPeter Brune     snes->linear_its += lits;
187b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
188b8840d6bSPeter Brune   } else {
189b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
190b8840d6bSPeter Brune   }
191b8840d6bSPeter Brune   PetscFunctionReturn(0);
192b8840d6bSPeter Brune }
193b8840d6bSPeter Brune 
194b8840d6bSPeter Brune #undef __FUNCT__
195b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_LBFGS"
1960adebc6cSBarry Smith PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1970adebc6cSBarry Smith {
198b8840d6bSPeter Brune   PetscErrorCode ierr;
199b8840d6bSPeter Brune   SNES_QN        *qn    = (SNES_QN*)snes->data;
200b8840d6bSPeter Brune   Vec            W      = snes->work[3];
201b8840d6bSPeter Brune   Vec            *dX    = qn->U;
202b8840d6bSPeter Brune   Vec            *dF    = qn->V;
203bd052dfeSPeter Brune   PetscScalar    *alpha = qn->alpha;
204bd052dfeSPeter Brune   PetscScalar    *beta  = qn->beta;
2058e231d97SPeter Brune   PetscScalar    *dXtdF = qn->dXtdF;
206b8840d6bSPeter Brune   PetscScalar    *dFtdX = qn->dFtdX;
2078e231d97SPeter Brune   PetscScalar    *YtdX  = qn->YtdX;
208bd052dfeSPeter Brune 
2090ecc9e1dSPeter Brune   /* ksp thing for jacobian scaling */
2100ecc9e1dSPeter Brune   KSPConvergedReason kspreason;
2118e231d97SPeter Brune   PetscInt           k,i,j,g,lits;
2124b11644fSPeter Brune   PetscInt           m = qn->m;
2134b11644fSPeter Brune   PetscScalar        t;
2144b11644fSPeter Brune   PetscInt           l = m;
2158e231d97SPeter Brune 
2164b11644fSPeter Brune   PetscFunctionBegin;
2175ba6227bSPeter Brune   if (it < m) l = it;
2181c6523dcSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
219b8840d6bSPeter Brune   if (it > 0) {
220b8840d6bSPeter Brune     k    = (it - 1) % l;
221b8840d6bSPeter Brune     ierr = VecCopy(D,dF[k]);CHKERRQ(ierr);
222b8840d6bSPeter Brune     ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr);
223b8840d6bSPeter Brune     ierr = VecCopy(X, dX[k]);CHKERRQ(ierr);
224b8840d6bSPeter Brune     ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr);
22518aa0c0cSPeter Brune     if (qn->singlereduction) {
22623d44fbcSPeter Brune       PetscScalar dFtdF;
2271c6523dcSPeter Brune       ierr = VecMDotBegin(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
2281c6523dcSPeter Brune       ierr = VecMDotBegin(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
2291c6523dcSPeter Brune       ierr = VecMDotBegin(Y,l,dX,YtdX);CHKERRQ(ierr);
23023d44fbcSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {ierr = VecDotBegin(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);}
2311c6523dcSPeter Brune       ierr = VecMDotEnd(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
2321c6523dcSPeter Brune       ierr = VecMDotEnd(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
2331c6523dcSPeter Brune       ierr = VecMDotEnd(Y,l,dX,YtdX);CHKERRQ(ierr);
23423d44fbcSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {
23523d44fbcSPeter Brune         ierr = VecDotEnd(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);
23623d44fbcSPeter Brune         qn->scaling = PetscRealPart(dXtdF[k]) / PetscRealPart(dFtdF);
23723d44fbcSPeter Brune       }
238b8840d6bSPeter Brune       for (j = 0; j < l; j++) {
239b8840d6bSPeter Brune         H(k, j) = dFtdX[j];
240b8840d6bSPeter Brune         H(j, k) = dXtdF[j];
241b8840d6bSPeter Brune       }
242b8840d6bSPeter Brune       /* copy back over to make the computation of alpha and beta easier */
2431aa26658SKarl Rupp       for (j = 0; j < l; j++) dXtdF[j] = H(j, j);
244b8840d6bSPeter Brune     } else {
245b8840d6bSPeter Brune       ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr);
246b8840d6bSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {
24767392de3SBarry Smith         PetscReal dFtdF;
24867392de3SBarry Smith         ierr        = VecDotRealPart(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);
24967392de3SBarry Smith         qn->scaling = PetscRealPart(dXtdF[k])/dFtdF;
25023d44fbcSPeter Brune       }
25123d44fbcSPeter Brune     }
25223d44fbcSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
253b8840d6bSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr);
254b8840d6bSPeter Brune     }
255b8840d6bSPeter Brune   }
256b8840d6bSPeter Brune 
2574b11644fSPeter Brune   /* outward recursion starting at iteration k's update and working back */
2584b11644fSPeter Brune   for (i=0; i<l; i++) {
259b21d5a53SPeter Brune     k = (it-i-1)%l;
26018aa0c0cSPeter Brune     if (qn->singlereduction) {
2618e231d97SPeter Brune       /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */
2628e231d97SPeter Brune       t = YtdX[k];
2638e231d97SPeter Brune       for (j=0; j<i; j++) {
2648e231d97SPeter Brune         g  = (it-j-1)%l;
265b3cfccb2SPeter Brune         t -= alpha[g]*H(k, g);
2668e231d97SPeter Brune       }
2678e231d97SPeter Brune       alpha[k] = t/H(k,k);
2688e231d97SPeter Brune     } else {
2693af51624SPeter Brune       ierr     = VecDot(dX[k],Y,&t);CHKERRQ(ierr);
2708e231d97SPeter Brune       alpha[k] = t/dXtdF[k];
2718e231d97SPeter Brune     }
27244f7e39eSPeter Brune     if (qn->monitor) {
2733af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
2745ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha:        %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr);
2753af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
27644f7e39eSPeter Brune     }
2776bf1b2e5SPeter Brune     ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr);
2784b11644fSPeter Brune   }
2794b11644fSPeter Brune 
2800c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
281d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
2820ecc9e1dSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
2830ecc9e1dSPeter Brune     if (kspreason < 0) {
2840ecc9e1dSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
2850ecc9e1dSPeter Brune         ierr         = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
2860ecc9e1dSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
2870ecc9e1dSPeter Brune         PetscFunctionReturn(0);
2880ecc9e1dSPeter Brune       }
2890ecc9e1dSPeter Brune     }
2900ecc9e1dSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
2910ecc9e1dSPeter Brune     snes->linear_its += lits;
292b8840d6bSPeter Brune     ierr              = VecCopy(W, Y);CHKERRQ(ierr);
2930ecc9e1dSPeter Brune   } else {
294b21d5a53SPeter Brune     ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr);
2950ecc9e1dSPeter Brune   }
29618aa0c0cSPeter Brune   if (qn->singlereduction) {
297b8840d6bSPeter Brune     ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr);
2988e231d97SPeter Brune   }
2994b11644fSPeter Brune   /* inward recursion starting at the first update and working forward */
300bd052dfeSPeter Brune   for (i = 0; i < l; i++) {
301b21d5a53SPeter Brune     k = (it + i - l) % l;
30218aa0c0cSPeter Brune     if (qn->singlereduction) {
3038e231d97SPeter Brune       t = YtdX[k];
3048e231d97SPeter Brune       for (j = 0; j < i; j++) {
3058e231d97SPeter Brune         g  = (it + j - l) % l;
306b3cfccb2SPeter Brune         t += (alpha[g] - beta[g])*H(g, k);
3078e231d97SPeter Brune       }
3088e231d97SPeter Brune       beta[k] = t / H(k, k);
3098e231d97SPeter Brune     } else {
3106bf1b2e5SPeter Brune       ierr    = VecDot(dF[k], Y, &t);CHKERRQ(ierr);
3118e231d97SPeter Brune       beta[k] = t / dXtdF[k];
3128e231d97SPeter Brune     }
31322d28d08SBarry Smith     ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr);
31444f7e39eSPeter Brune     if (qn->monitor) {
3153af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
3165ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr);
3173af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
31844f7e39eSPeter Brune     }
3194b11644fSPeter Brune   }
3204b11644fSPeter Brune   PetscFunctionReturn(0);
3214b11644fSPeter Brune }
3224b11644fSPeter Brune 
3234b11644fSPeter Brune #undef __FUNCT__
3244b11644fSPeter Brune #define __FUNCT__ "SNESSolve_QN"
3254b11644fSPeter Brune static PetscErrorCode SNESSolve_QN(SNES snes)
3264b11644fSPeter Brune {
3274b11644fSPeter Brune   PetscErrorCode      ierr;
3289f83bee8SJed Brown   SNES_QN             *qn = (SNES_QN*) snes->data;
32915f5eeeaSPeter Brune   Vec                 X,Xold;
33047f26062SPeter Brune   Vec                 F;
33147f26062SPeter Brune   Vec                 Y,D,Dold;
332b8840d6bSPeter Brune   PetscInt            i, i_r;
333335fb975SPeter Brune   PetscReal           fnorm,xnorm,ynorm,gnorm;
3340c777b0cSPeter Brune   PetscBool           lssucceed,powell,periodic;
3351c6523dcSPeter Brune   PetscScalar         DolddotD,DolddotDold;
3360ecc9e1dSPeter Brune   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
337b7281c8aSPeter Brune   SNESConvergedReason reason;
3380ecc9e1dSPeter Brune 
3394b11644fSPeter Brune   /* basically just a regular newton's method except for the application of the jacobian */
3404b11644fSPeter Brune 
3416e111a19SKarl Rupp   PetscFunctionBegin;
3429f3a0142SPeter Brune   F = snes->vec_func;                   /* residual vector */
3433af51624SPeter Brune   Y = snes->vec_sol_update;             /* search direction generated by J^-1D*/
344b8840d6bSPeter Brune 
345b8840d6bSPeter Brune   X    = snes->vec_sol;                 /* solution vector */
346335fb975SPeter Brune   Xold = snes->work[0];
3473af51624SPeter Brune 
3483af51624SPeter Brune   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
349335fb975SPeter Brune   D    = snes->work[1];
350335fb975SPeter Brune   Dold = snes->work[2];
3514b11644fSPeter Brune 
3524b11644fSPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
3534b11644fSPeter Brune 
354ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3554b11644fSPeter Brune   snes->iter = 0;
3564b11644fSPeter Brune   snes->norm = 0.;
357ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
35847f26062SPeter Brune 
359b28a06ddSPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
36047f26062SPeter Brune     ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr);
361b7281c8aSPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
362b7281c8aSPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
363b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
364b7281c8aSPeter Brune       PetscFunctionReturn(0);
365b7281c8aSPeter Brune     }
36647f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
36747f26062SPeter Brune   } else {
368e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
36915f5eeeaSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
3704b11644fSPeter Brune       if (snes->domainerror) {
3714b11644fSPeter Brune         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
3724b11644fSPeter Brune         PetscFunctionReturn(0);
3734b11644fSPeter Brune       }
3741aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
375c1c75074SPeter Brune 
37647f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
377189a9710SBarry Smith     if (PetscIsInfOrNanReal(fnorm)) {
378189a9710SBarry Smith       snes->reason = SNES_DIVERGED_FNORM_NAN;
379189a9710SBarry Smith       PetscFunctionReturn(0);
380189a9710SBarry Smith     }
38147f26062SPeter Brune   }
382b28a06ddSPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
38347f26062SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr);
384b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
385b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
386b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
387b7281c8aSPeter Brune         PetscFunctionReturn(0);
388b7281c8aSPeter Brune       }
38947f26062SPeter Brune   } else {
39047f26062SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
39147f26062SPeter Brune   }
392b28a06ddSPeter Brune 
393ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3944b11644fSPeter Brune   snes->norm = fnorm;
395ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
396a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
3974b11644fSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
3984b11644fSPeter Brune 
3994b11644fSPeter Brune   /* test convergence */
4004b11644fSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
4014b11644fSPeter Brune   if (snes->reason) PetscFunctionReturn(0);
40270d3b23bSPeter Brune 
4033cf07b75SPeter Brune   if (snes->pc && snes->pcside == PC_RIGHT) {
4043cf07b75SPeter Brune     ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
4053cf07b75SPeter Brune     ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
4063cf07b75SPeter Brune     ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
407ddd40ce5SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
408ddd40ce5SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
409ddd40ce5SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
410ddd40ce5SPeter Brune       PetscFunctionReturn(0);
411ddd40ce5SPeter Brune     }
412ddd40ce5SPeter Brune     ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
4133cf07b75SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
4143cf07b75SPeter Brune   }
4153cf07b75SPeter Brune 
416f8e15203SPeter Brune   /* scale the initial update */
4170c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
4180ecc9e1dSPeter Brune     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
4198cba9625SJed Brown     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
4200ecc9e1dSPeter Brune   }
4210ecc9e1dSPeter Brune 
4225ba6227bSPeter Brune   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
423b8840d6bSPeter Brune     switch (qn->type) {
424b8840d6bSPeter Brune     case SNES_QN_BADBROYDEN:
425b8840d6bSPeter Brune       ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
426b8840d6bSPeter Brune       break;
427b8840d6bSPeter Brune     case SNES_QN_BROYDEN:
428b8840d6bSPeter Brune       ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
429b8840d6bSPeter Brune       break;
430b8840d6bSPeter Brune     case SNES_QN_LBFGS:
431b8840d6bSPeter Brune       SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
432b8840d6bSPeter Brune       break;
433b8840d6bSPeter Brune     }
43470d3b23bSPeter Brune     /* line search for lambda */
43570d3b23bSPeter Brune     ynorm = 1; gnorm = fnorm;
43688d374b2SPeter Brune     ierr  = VecCopy(D, Dold);CHKERRQ(ierr);
43715f5eeeaSPeter Brune     ierr  = VecCopy(X, Xold);CHKERRQ(ierr);
438f1c6b773SPeter Brune     ierr  = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr);
4399f3a0142SPeter Brune     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
4409f3a0142SPeter Brune     if (snes->domainerror) {
4419f3a0142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
4429f3a0142SPeter Brune       PetscFunctionReturn(0);
4439f3a0142SPeter Brune     }
444f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
4459f3a0142SPeter Brune     if (!lssucceed) {
4469f3a0142SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
4479f3a0142SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
4489f3a0142SPeter Brune         break;
4499f3a0142SPeter Brune       }
4509f3a0142SPeter Brune     }
451f1c6b773SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
4520c777b0cSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
45305ee83feSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr);
4540ecc9e1dSPeter Brune     }
4553af51624SPeter Brune 
45688d374b2SPeter Brune     /* convergence monitoring */
457b21d5a53SPeter 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);
458b21d5a53SPeter Brune 
459b28a06ddSPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
460b28a06ddSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
461b28a06ddSPeter Brune       ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
462b28a06ddSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
463ddd40ce5SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
464ddd40ce5SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
465ddd40ce5SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
466ddd40ce5SPeter Brune         PetscFunctionReturn(0);
467ddd40ce5SPeter Brune       }
468ddd40ce5SPeter Brune       ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
469b28a06ddSPeter Brune     }
470b28a06ddSPeter Brune 
471360c497dSPeter Brune     ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr);
472360c497dSPeter Brune     ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr);
473360c497dSPeter Brune 
474a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
4758409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
4764b11644fSPeter Brune     /* set parameter for default relative tolerance convergence test */
477d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
4784b11644fSPeter Brune     if (snes->reason) PetscFunctionReturn(0);
479b28a06ddSPeter Brune     if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
48047f26062SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr);
481b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
482b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
483b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
484b7281c8aSPeter Brune         PetscFunctionReturn(0);
485b7281c8aSPeter Brune       }
48688d374b2SPeter Brune     } else {
48788d374b2SPeter Brune       ierr = VecCopy(F, D);CHKERRQ(ierr);
48888d374b2SPeter Brune     }
48988d374b2SPeter Brune 
4900c777b0cSPeter Brune     powell = PETSC_FALSE;
4910c777b0cSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_POWELL) {
4926bf1b2e5SPeter Brune       /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */
4938e231d97SPeter Brune       ierr = VecDotBegin(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
4948e231d97SPeter Brune       ierr = VecDotBegin(Dold, D, &DolddotD);CHKERRQ(ierr);
4958e231d97SPeter Brune       ierr = VecDotEnd(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
4968e231d97SPeter Brune       ierr = VecDotEnd(Dold, D, &DolddotD);CHKERRQ(ierr);
4970c777b0cSPeter Brune       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
4980c777b0cSPeter Brune     }
4990c777b0cSPeter Brune     periodic = PETSC_FALSE;
500b8840d6bSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
501b8840d6bSPeter Brune       if (i_r>qn->m-1) periodic = PETSC_TRUE;
5020c777b0cSPeter Brune     }
5030c777b0cSPeter Brune     /* restart if either powell or periodic restart is satisfied. */
5040c777b0cSPeter Brune     if (powell || periodic) {
5055ba6227bSPeter Brune       if (qn->monitor) {
5065ba6227bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
507516fe3c3SPeter Brune         ierr = PetscViewerASCIIPrintf(qn->monitor, "restart! |%14.12e| > %4.2f*|%14.12e| or i_r = %d\n", PetscRealPart(DolddotD), qn->powell_gamma, PetscRealPart(DolddotDold), i_r);CHKERRQ(ierr);
5085ba6227bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
5095ba6227bSPeter Brune       }
5105ba6227bSPeter Brune       i_r = -1;
5115ba6227bSPeter Brune       /* general purpose update */
5125ba6227bSPeter Brune       if (snes->ops->update) {
5135ba6227bSPeter Brune         ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
5145ba6227bSPeter Brune       }
5150c777b0cSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5160ecc9e1dSPeter Brune         ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
5178cba9625SJed Brown         ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
5180ecc9e1dSPeter Brune       }
5190ecc9e1dSPeter Brune     }
52070d3b23bSPeter Brune     /* general purpose update */
52170d3b23bSPeter Brune     if (snes->ops->update) {
52270d3b23bSPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
52370d3b23bSPeter Brune     }
5245ba6227bSPeter Brune   }
5254b11644fSPeter Brune   if (i == snes->max_its) {
5264b11644fSPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr);
5274b11644fSPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
5284b11644fSPeter Brune   }
5294b11644fSPeter Brune   PetscFunctionReturn(0);
5304b11644fSPeter Brune }
5314b11644fSPeter Brune 
5324b11644fSPeter Brune #undef __FUNCT__
5334b11644fSPeter Brune #define __FUNCT__ "SNESSetUp_QN"
5344b11644fSPeter Brune static PetscErrorCode SNESSetUp_QN(SNES snes)
5354b11644fSPeter Brune {
5369f83bee8SJed Brown   SNES_QN        *qn = (SNES_QN*)snes->data;
5374b11644fSPeter Brune   PetscErrorCode ierr;
538335fb975SPeter Brune 
5394b11644fSPeter Brune   PetscFunctionBegin;
540b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr);
541b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr);
542*5c7a0a03SPeter Brune   ierr = PetscMalloc4(qn->m, PetscScalar, &qn->alpha,
5438e231d97SPeter Brune                       qn->m, PetscScalar, &qn->beta,
544*5c7a0a03SPeter Brune                       qn->m, PetscScalar, &qn->dXtdF,
545*5c7a0a03SPeter Brune                       qn->m, PetscReal, &qn->lambda);CHKERRQ(ierr);
5468e231d97SPeter Brune 
54718aa0c0cSPeter Brune   if (qn->singlereduction) {
5488e231d97SPeter Brune     ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat,
5498e231d97SPeter Brune                         qn->m, PetscScalar, &qn->dFtdX,
5508e231d97SPeter Brune                         qn->m, PetscScalar, &qn->YtdX);CHKERRQ(ierr);
5518e231d97SPeter Brune   }
552fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr);
553335fb975SPeter Brune 
554335fb975SPeter Brune   /* set up the line search */
5550c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5568e231d97SPeter Brune     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
5578e231d97SPeter Brune   }
5586c67d002SPeter Brune 
5596c67d002SPeter Brune   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;}
5606c67d002SPeter Brune 
5614b11644fSPeter Brune   PetscFunctionReturn(0);
5624b11644fSPeter Brune }
5634b11644fSPeter Brune 
5644b11644fSPeter Brune #undef __FUNCT__
5654b11644fSPeter Brune #define __FUNCT__ "SNESReset_QN"
5664b11644fSPeter Brune static PetscErrorCode SNESReset_QN(SNES snes)
5674b11644fSPeter Brune {
5684b11644fSPeter Brune   PetscErrorCode ierr;
5699f83bee8SJed Brown   SNES_QN        *qn;
5700adebc6cSBarry Smith 
5714b11644fSPeter Brune   PetscFunctionBegin;
5724b11644fSPeter Brune   if (snes->data) {
5739f83bee8SJed Brown     qn = (SNES_QN*)snes->data;
574b8840d6bSPeter Brune     if (qn->U) {
575b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr);
5764b11644fSPeter Brune     }
577b8840d6bSPeter Brune     if (qn->V) {
578b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr);
5794b11644fSPeter Brune     }
58018aa0c0cSPeter Brune     if (qn->singlereduction) {
5818e231d97SPeter Brune       ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr);
5828e231d97SPeter Brune     }
583*5c7a0a03SPeter Brune     ierr = PetscFree4(qn->alpha,qn->beta,qn->dXtdF,qn->lambda);CHKERRQ(ierr);
5844b11644fSPeter Brune   }
5854b11644fSPeter Brune   PetscFunctionReturn(0);
5864b11644fSPeter Brune }
5874b11644fSPeter Brune 
5884b11644fSPeter Brune #undef __FUNCT__
5894b11644fSPeter Brune #define __FUNCT__ "SNESDestroy_QN"
5904b11644fSPeter Brune static PetscErrorCode SNESDestroy_QN(SNES snes)
5914b11644fSPeter Brune {
5924b11644fSPeter Brune   PetscErrorCode ierr;
5936e111a19SKarl Rupp 
5944b11644fSPeter Brune   PetscFunctionBegin;
5954b11644fSPeter Brune   ierr = SNESReset_QN(snes);CHKERRQ(ierr);
5964b11644fSPeter Brune   ierr = PetscFree(snes->data);CHKERRQ(ierr);
597bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr);
5984b11644fSPeter Brune   PetscFunctionReturn(0);
5994b11644fSPeter Brune }
6004b11644fSPeter Brune 
6014b11644fSPeter Brune #undef __FUNCT__
6024b11644fSPeter Brune #define __FUNCT__ "SNESSetFromOptions_QN"
6034b11644fSPeter Brune static PetscErrorCode SNESSetFromOptions_QN(SNES snes)
6044b11644fSPeter Brune {
6054b11644fSPeter Brune 
6064b11644fSPeter Brune   PetscErrorCode    ierr;
6072150357eSBarry Smith   SNES_QN           *qn    = (SNES_QN*)snes->data;
60888f769c5SPeter Brune   PetscBool         monflg = PETSC_FALSE,flg;
609f1c6b773SPeter Brune   SNESLineSearch    linesearch;
6102150357eSBarry Smith   SNESQNRestartType rtype = qn->restart_type;
6112150357eSBarry Smith   SNESQNScaleType   stype = qn->scale_type;
6122150357eSBarry Smith 
6134b11644fSPeter Brune   PetscFunctionBegin;
6144b11644fSPeter Brune   ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr);
6150298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,NULL);CHKERRQ(ierr);
6160298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance",          "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL);CHKERRQ(ierr);
6170298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance",        "SNESQN", qn->powell_downhill, &qn->powell_downhill, NULL);CHKERRQ(ierr);
6180298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_monitor",         "Monitor for the QN methods",      "SNESQN", monflg, &monflg, NULL);CHKERRQ(ierr);
6190298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions",           "SNESQN", qn->singlereduction, &qn->singlereduction, NULL);CHKERRQ(ierr);
62088f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr);
62188f769c5SPeter Brune   if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr);
62288f769c5SPeter Brune 
62388f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr);
62488f769c5SPeter Brune   if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr);
62588f769c5SPeter Brune 
626b8840d6bSPeter Brune   ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes,
6270298fd71SBarry Smith                           (PetscEnum)qn->type,(PetscEnum*)&qn->type,NULL);CHKERRQ(ierr);
6284b11644fSPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
6299e764e56SPeter Brune   if (!snes->linesearch) {
6307601faf0SJed Brown     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
6311a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
6329e764e56SPeter Brune   }
63344f7e39eSPeter Brune   if (monflg) {
634ce94432eSBarry Smith     qn->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
63544f7e39eSPeter Brune   }
6364b11644fSPeter Brune   PetscFunctionReturn(0);
6374b11644fSPeter Brune }
6384b11644fSPeter Brune 
63992c02d66SPeter Brune 
6400c777b0cSPeter Brune #undef __FUNCT__
6410c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType"
6420c777b0cSPeter Brune /*@
6430c777b0cSPeter Brune     SNESQNSetRestartType - Sets the restart type for SNESQN.
6440c777b0cSPeter Brune 
6450c777b0cSPeter Brune     Logically Collective on SNES
6460c777b0cSPeter Brune 
6470c777b0cSPeter Brune     Input Parameters:
6480c777b0cSPeter Brune +   snes - the iterative context
6490c777b0cSPeter Brune -   rtype - restart type
6500c777b0cSPeter Brune 
6510c777b0cSPeter Brune     Options Database:
6520c777b0cSPeter Brune +   -snes_qn_restart_type<powell,periodic,none> - set the restart type
653b8840d6bSPeter Brune -   -snes_qn_restart[10] - sets the number of iterations before restart for periodic
6540c777b0cSPeter Brune 
6550c777b0cSPeter Brune     Level: intermediate
6560c777b0cSPeter Brune 
6570c777b0cSPeter Brune     SNESQNRestartTypes:
6580c777b0cSPeter Brune +   SNES_QN_RESTART_NONE - never restart
6590c777b0cSPeter Brune .   SNES_QN_RESTART_POWELL - restart based upon descent criteria
6600c777b0cSPeter Brune -   SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations
6610c777b0cSPeter Brune 
6620c777b0cSPeter Brune     Notes:
6630c777b0cSPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
6640c777b0cSPeter Brune 
6650c777b0cSPeter Brune .keywords: SNES, SNESQN, restart, type, set SNESLineSearch
6660c777b0cSPeter Brune @*/
6672150357eSBarry Smith PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
6682150357eSBarry Smith {
6690c777b0cSPeter Brune   PetscErrorCode ierr;
6706e111a19SKarl Rupp 
6710c777b0cSPeter Brune   PetscFunctionBegin;
6720c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
6730c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr);
6740c777b0cSPeter Brune   PetscFunctionReturn(0);
6750c777b0cSPeter Brune }
6760c777b0cSPeter Brune 
6770c777b0cSPeter Brune #undef __FUNCT__
6780c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType"
6790c777b0cSPeter Brune /*@
6800c777b0cSPeter Brune     SNESQNSetScaleType - Sets the scaling type for the inner inverse jacobian in SNESQN.
6810c777b0cSPeter Brune 
6820c777b0cSPeter Brune     Logically Collective on SNES
6830c777b0cSPeter Brune 
6840c777b0cSPeter Brune     Input Parameters:
6850c777b0cSPeter Brune +   snes - the iterative context
6860c777b0cSPeter Brune -   stype - scale type
6870c777b0cSPeter Brune 
6880c777b0cSPeter Brune     Options Database:
6890c777b0cSPeter Brune .   -snes_qn_scale_type<shanno,none,linesearch,jacobian>
6900c777b0cSPeter Brune 
6910c777b0cSPeter Brune     Level: intermediate
6920c777b0cSPeter Brune 
6930c777b0cSPeter Brune     SNESQNSelectTypes:
6940c777b0cSPeter Brune +   SNES_QN_SCALE_NONE - don't scale the problem
6950c777b0cSPeter Brune .   SNES_QN_SCALE_SHANNO - use shanno scaling
6960c777b0cSPeter Brune .   SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda
6970c777b0cSPeter Brune -   SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian.
6980c777b0cSPeter Brune 
6990c777b0cSPeter Brune .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch
7000c777b0cSPeter Brune @*/
7010c777b0cSPeter Brune 
7022150357eSBarry Smith PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
7032150357eSBarry Smith {
7040c777b0cSPeter Brune   PetscErrorCode ierr;
7056e111a19SKarl Rupp 
7060c777b0cSPeter Brune   PetscFunctionBegin;
7070c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
7080c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr);
7090c777b0cSPeter Brune   PetscFunctionReturn(0);
7100c777b0cSPeter Brune }
7110c777b0cSPeter Brune 
7120c777b0cSPeter Brune #undef __FUNCT__
7130c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType_QN"
7140adebc6cSBarry Smith PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
7150adebc6cSBarry Smith {
7160c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7176e111a19SKarl Rupp 
7180c777b0cSPeter Brune   PetscFunctionBegin;
7190c777b0cSPeter Brune   qn->scale_type = stype;
7200c777b0cSPeter Brune   PetscFunctionReturn(0);
7210c777b0cSPeter Brune }
7220c777b0cSPeter Brune 
7230c777b0cSPeter Brune #undef __FUNCT__
7240c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType_QN"
7250adebc6cSBarry Smith PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
7260adebc6cSBarry Smith {
7270c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7286e111a19SKarl Rupp 
7290c777b0cSPeter Brune   PetscFunctionBegin;
7300c777b0cSPeter Brune   qn->restart_type = rtype;
7310c777b0cSPeter Brune   PetscFunctionReturn(0);
7320c777b0cSPeter Brune }
7330c777b0cSPeter Brune 
7344b11644fSPeter Brune /* -------------------------------------------------------------------------- */
7354b11644fSPeter Brune /*MC
7364b11644fSPeter Brune       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
7374b11644fSPeter Brune 
7386cc8130cSPeter Brune       Options Database:
7396cc8130cSPeter Brune 
7406cc8130cSPeter Brune +     -snes_qn_m - Number of past states saved for the L-Broyden methods.
7411867fe5bSPeter Brune .     -snes_qn_powell_angle - Angle condition for restart.
7421867fe5bSPeter Brune .     -snes_qn_powell_descent - Descent condition for restart.
74372835e02SPeter Brune .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
74444f7e39eSPeter Brune -     -snes_qn_monitor - Monitors the quasi-newton jacobian.
7456cc8130cSPeter Brune 
746b8840d6bSPeter Brune       Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
747b8840d6bSPeter Brune       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
748b8840d6bSPeter Brune       updates.
7496cc8130cSPeter Brune 
7501867fe5bSPeter Brune       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
7511867fe5bSPeter Brune       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
7521867fe5bSPeter Brune       iteration as the current iteration's values when constructing the approximate jacobian.  The second, composed,
7531867fe5bSPeter Brune       perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
7541867fe5bSPeter Brune 
7556cc8130cSPeter Brune       References:
7566cc8130cSPeter Brune 
7576cc8130cSPeter Brune       L-Broyden Methods: a generalization of the L-BFGS method to the limited memory Broyden family, M. B. Reed,
7586cc8130cSPeter Brune       International Journal of Computer Mathematics, vol. 86, 2009.
7596cc8130cSPeter Brune 
760b8840d6bSPeter Brune       Experiments with Quasi-Newton Methods in Solving Stiff ODE Systems, Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker
761b8840d6bSPeter Brune       SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
762b8840d6bSPeter Brune 
7634b11644fSPeter Brune 
7644b11644fSPeter Brune       Level: beginner
7654b11644fSPeter Brune 
76604d7464bSBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR
7676cc8130cSPeter Brune 
7684b11644fSPeter Brune M*/
7694b11644fSPeter Brune #undef __FUNCT__
7704b11644fSPeter Brune #define __FUNCT__ "SNESCreate_QN"
7718cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes)
7724b11644fSPeter Brune {
7734b11644fSPeter Brune   PetscErrorCode ierr;
7749f83bee8SJed Brown   SNES_QN        *qn;
7754b11644fSPeter Brune 
7764b11644fSPeter Brune   PetscFunctionBegin;
7774b11644fSPeter Brune   snes->ops->setup          = SNESSetUp_QN;
7784b11644fSPeter Brune   snes->ops->solve          = SNESSolve_QN;
7794b11644fSPeter Brune   snes->ops->destroy        = SNESDestroy_QN;
7804b11644fSPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_QN;
7814b11644fSPeter Brune   snes->ops->view           = 0;
7824b11644fSPeter Brune   snes->ops->reset          = SNESReset_QN;
7834b11644fSPeter Brune 
78447f26062SPeter Brune   snes->pcside = PC_LEFT;
78547f26062SPeter Brune 
78642f4f86dSBarry Smith   snes->usespc  = PETSC_TRUE;
78742f4f86dSBarry Smith   snes->usesksp = PETSC_FALSE;
78842f4f86dSBarry Smith 
78988976e71SPeter Brune   if (!snes->tolerancesset) {
7900e444f03SPeter Brune     snes->max_funcs = 30000;
7910e444f03SPeter Brune     snes->max_its   = 10000;
79288976e71SPeter Brune   }
7930e444f03SPeter Brune 
7949f83bee8SJed Brown   ierr                = PetscNewLog(snes,SNES_QN,&qn);CHKERRQ(ierr);
7954b11644fSPeter Brune   snes->data          = (void*) qn;
7960ecc9e1dSPeter Brune   qn->m               = 10;
797b21d5a53SPeter Brune   qn->scaling         = 1.0;
7980298fd71SBarry Smith   qn->U               = NULL;
7990298fd71SBarry Smith   qn->V               = NULL;
8000298fd71SBarry Smith   qn->dXtdF           = NULL;
8010298fd71SBarry Smith   qn->dFtdX           = NULL;
8020298fd71SBarry Smith   qn->dXdFmat         = NULL;
8030298fd71SBarry Smith   qn->monitor         = NULL;
8041c6523dcSPeter Brune   qn->singlereduction = PETSC_TRUE;
805b8840d6bSPeter Brune   qn->powell_gamma    = 0.9999;
8060c777b0cSPeter Brune   qn->scale_type      = SNES_QN_SCALE_SHANNO;
8070c777b0cSPeter Brune   qn->restart_type    = SNES_QN_RESTART_POWELL;
808b8840d6bSPeter Brune   qn->type            = SNES_QN_LBFGS;
809ea630c6eSPeter Brune 
810bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetScaleType_C",SNESQNSetScaleType_QN);CHKERRQ(ierr);
811bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetRestartType_C",SNESQNSetRestartType_QN);CHKERRQ(ierr);
8124b11644fSPeter Brune   PetscFunctionReturn(0);
8134b11644fSPeter Brune }
814