xref: /petsc/src/snes/impls/qn/qn.c (revision 59e7931a999feb88589b78c0a68353855379e9a9)
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 */
185c7a0a03SPeter Brune   PetscReal         *lambda;              /* The line search history of the method */
195c7a0a03SPeter 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;
435c7a0a03SPeter Brune   PetscInt           k,i,j,lits,l = m;
445c7a0a03SPeter Brune   PetscReal          unorm,a,b;
455c7a0a03SPeter Brune   PetscReal          *lambda=qn->lambda;
46b8840d6bSPeter Brune   PetscScalar        gdot;
47*59e7931aSPeter Brune   PetscReal          udot;
482150357eSBarry Smith 
49b8840d6bSPeter Brune   PetscFunctionBegin;
50b8840d6bSPeter Brune   if (it < m) l = it;
515c7a0a03SPeter Brune   if (it > 0) {
525c7a0a03SPeter Brune     k = (it-1)%l;
535c7a0a03SPeter Brune     ierr = SNESLineSearchGetLambda(snes->linesearch,&lambda[k]);CHKERRQ(ierr);
545c7a0a03SPeter Brune     ierr = VecScale(U[k],lambda[k]);CHKERRQ(ierr);
555c7a0a03SPeter Brune     if (qn->monitor) {
565c7a0a03SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
575c7a0a03SPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "scaling vector %d of %d by lambda: %14.12e \n",k,l,lambda[k]);CHKERRQ(ierr);
585c7a0a03SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
595c7a0a03SPeter Brune     }
605c7a0a03SPeter Brune   }
61b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
62d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,D,W);CHKERRQ(ierr);
63b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
64b8840d6bSPeter Brune     if (kspreason < 0) {
65b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
66b8840d6bSPeter 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);
67b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
68b8840d6bSPeter Brune         PetscFunctionReturn(0);
69b8840d6bSPeter Brune       }
70b8840d6bSPeter Brune     }
71b8840d6bSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
72b8840d6bSPeter Brune     snes->linear_its += lits;
73b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
74b8840d6bSPeter Brune   } else {
75b8840d6bSPeter Brune     ierr = VecCopy(D,Y);CHKERRQ(ierr);
76b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
77b8840d6bSPeter Brune   }
78b8840d6bSPeter Brune 
79b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
80b8840d6bSPeter Brune   for (i = 0; i < l-1; i++) {
815c7a0a03SPeter Brune     j = (it+i-l)%l;
825c7a0a03SPeter Brune     k = (it+i-l+1)%l;
835c7a0a03SPeter Brune 
845c7a0a03SPeter Brune     ierr = VecNorm(U[j],NORM_2,&unorm);CHKERRQ(ierr);
855c7a0a03SPeter Brune     ierr = VecDot(U[j],Y,&gdot);CHKERRQ(ierr);
86*59e7931aSPeter Brune     unorm *= unorm;
87*59e7931aSPeter Brune     udot = PetscRealPart(gdot);
885c7a0a03SPeter Brune     a = (lambda[j]/lambda[k]);
895c7a0a03SPeter Brune     b = -(1.-lambda[j]);
90*59e7931aSPeter Brune     a *= udot/unorm;
91*59e7931aSPeter Brune     b *= udot/unorm;
925c7a0a03SPeter Brune     ierr = VecAXPBYPCZ(Y,a,b,1.,U[k],U[j]);CHKERRQ(ierr);
935c7a0a03SPeter Brune 
94b8840d6bSPeter Brune     if (qn->monitor) {
95b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
965c7a0a03SPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d and %d, gdot: %14.12e\n",k,j,gdot);CHKERRQ(ierr);
97b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
98b8840d6bSPeter Brune     }
99b8840d6bSPeter Brune   }
100b8840d6bSPeter Brune   if (l > 0) {
101b8840d6bSPeter Brune     k = (it-1)%l;
102b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
1035c7a0a03SPeter Brune     ierr = VecNorm(U[k],NORM_2,&unorm);CHKERRQ(ierr);
104*59e7931aSPeter Brune     unorm *= unorm;
105*59e7931aSPeter Brune     udot = PetscRealPart(gdot);
106*59e7931aSPeter Brune     a = unorm/(unorm-lambda[k]*udot);
107*59e7931aSPeter Brune     b = -(1.-lambda[k])*udot/(unorm-lambda[k]*udot);
108b8840d6bSPeter Brune     if (qn->monitor) {
109b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
110*59e7931aSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d: a: %14.12e b: %14.12e \n",k,a,b);CHKERRQ(ierr);
111b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
112b8840d6bSPeter Brune     }
1135c7a0a03SPeter Brune     ierr = VecAXPBY(Y,b,a,U[k]);CHKERRQ(ierr);
114b8840d6bSPeter Brune   }
1155c7a0a03SPeter Brune   l = m;
1165c7a0a03SPeter Brune   if (it+1<m)l=it+1;
1175c7a0a03SPeter Brune   k = it%l;
1185c7a0a03SPeter Brune   if (qn->monitor) {
1195c7a0a03SPeter Brune     ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1205c7a0a03SPeter Brune     ierr = PetscViewerASCIIPrintf(qn->monitor, "setting vector %d of %d\n",k,l);CHKERRQ(ierr);
1215c7a0a03SPeter Brune     ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1225c7a0a03SPeter Brune   }
1235c7a0a03SPeter Brune   ierr = VecCopy(Y,U[k]);CHKERRQ(ierr);
124b8840d6bSPeter Brune  PetscFunctionReturn(0);
125b8840d6bSPeter Brune }
126b8840d6bSPeter Brune 
127b8840d6bSPeter Brune #undef __FUNCT__
128b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_BadBroyden"
1290adebc6cSBarry Smith PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1300adebc6cSBarry Smith {
131b8840d6bSPeter Brune   PetscErrorCode ierr;
132b8840d6bSPeter Brune   SNES_QN        *qn = (SNES_QN*)snes->data;
133b8840d6bSPeter Brune   Vec            W   = snes->work[3];
134b8840d6bSPeter Brune   Vec            *U  = qn->U;
135b8840d6bSPeter Brune   Vec            *T  = qn->V;
136b8840d6bSPeter Brune 
137b8840d6bSPeter Brune   /* ksp thing for jacobian scaling */
138b8840d6bSPeter Brune   KSPConvergedReason kspreason;
139b8840d6bSPeter Brune   PetscInt           k, i, lits;
140b8840d6bSPeter Brune   PetscInt           m = qn->m;
141b8840d6bSPeter Brune   PetscScalar        gdot;
142b8840d6bSPeter Brune   PetscInt           l = m;
1430adebc6cSBarry Smith 
144b8840d6bSPeter Brune   PetscFunctionBegin;
145b8840d6bSPeter Brune   if (it < m) l = it;
146b8840d6bSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
147b8840d6bSPeter Brune   if (l > 0) {
148b8840d6bSPeter Brune     k    = (it-1)%l;
149b8840d6bSPeter Brune     ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr);
150b8840d6bSPeter Brune     ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr);
151b8840d6bSPeter Brune     ierr = VecDot(U[k],U[k],&gdot);CHKERRQ(ierr);
152b8840d6bSPeter Brune     ierr = VecCopy(D,T[k]);CHKERRQ(ierr);
153b8840d6bSPeter Brune     ierr = VecScale(T[k],1.0/gdot);CHKERRQ(ierr);
154b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
155b8840d6bSPeter Brune     ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
156b8840d6bSPeter Brune     if (qn->monitor) {
157b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
158b8840d6bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "update: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
159b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
160b8840d6bSPeter Brune     }
161b8840d6bSPeter Brune   }
162b8840d6bSPeter Brune 
163b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
164b8840d6bSPeter Brune   if (it > 1) {
165b8840d6bSPeter Brune     for (i = 0; i < l-1; i++) {
166b8840d6bSPeter Brune       k    = (it+i-l)%l;
167b8840d6bSPeter Brune       ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
168b8840d6bSPeter Brune       ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
169b8840d6bSPeter Brune       if (qn->monitor) {
170b8840d6bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
171b8840d6bSPeter Brune         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
172b8840d6bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
173b8840d6bSPeter Brune       }
174b8840d6bSPeter Brune     }
175b8840d6bSPeter Brune   }
176b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
177d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
178b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
179b8840d6bSPeter Brune     if (kspreason < 0) {
180b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
181b8840d6bSPeter 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);
182b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
183b8840d6bSPeter Brune         PetscFunctionReturn(0);
184b8840d6bSPeter Brune       }
185b8840d6bSPeter Brune     }
186b8840d6bSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
187b8840d6bSPeter Brune     snes->linear_its += lits;
188b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
189b8840d6bSPeter Brune   } else {
190b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
191b8840d6bSPeter Brune   }
192b8840d6bSPeter Brune   PetscFunctionReturn(0);
193b8840d6bSPeter Brune }
194b8840d6bSPeter Brune 
195b8840d6bSPeter Brune #undef __FUNCT__
196b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_LBFGS"
1970adebc6cSBarry Smith PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1980adebc6cSBarry Smith {
199b8840d6bSPeter Brune   PetscErrorCode ierr;
200b8840d6bSPeter Brune   SNES_QN        *qn    = (SNES_QN*)snes->data;
201b8840d6bSPeter Brune   Vec            W      = snes->work[3];
202b8840d6bSPeter Brune   Vec            *dX    = qn->U;
203b8840d6bSPeter Brune   Vec            *dF    = qn->V;
204bd052dfeSPeter Brune   PetscScalar    *alpha = qn->alpha;
205bd052dfeSPeter Brune   PetscScalar    *beta  = qn->beta;
2068e231d97SPeter Brune   PetscScalar    *dXtdF = qn->dXtdF;
207b8840d6bSPeter Brune   PetscScalar    *dFtdX = qn->dFtdX;
2088e231d97SPeter Brune   PetscScalar    *YtdX  = qn->YtdX;
209bd052dfeSPeter Brune 
2100ecc9e1dSPeter Brune   /* ksp thing for jacobian scaling */
2110ecc9e1dSPeter Brune   KSPConvergedReason kspreason;
2128e231d97SPeter Brune   PetscInt           k,i,j,g,lits;
2134b11644fSPeter Brune   PetscInt           m = qn->m;
2144b11644fSPeter Brune   PetscScalar        t;
2154b11644fSPeter Brune   PetscInt           l = m;
2168e231d97SPeter Brune 
2174b11644fSPeter Brune   PetscFunctionBegin;
2185ba6227bSPeter Brune   if (it < m) l = it;
2191c6523dcSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
220b8840d6bSPeter Brune   if (it > 0) {
221b8840d6bSPeter Brune     k    = (it - 1) % l;
222b8840d6bSPeter Brune     ierr = VecCopy(D,dF[k]);CHKERRQ(ierr);
223b8840d6bSPeter Brune     ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr);
224b8840d6bSPeter Brune     ierr = VecCopy(X, dX[k]);CHKERRQ(ierr);
225b8840d6bSPeter Brune     ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr);
22618aa0c0cSPeter Brune     if (qn->singlereduction) {
22723d44fbcSPeter Brune       PetscScalar dFtdF;
2281c6523dcSPeter Brune       ierr = VecMDotBegin(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
2291c6523dcSPeter Brune       ierr = VecMDotBegin(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
2301c6523dcSPeter Brune       ierr = VecMDotBegin(Y,l,dX,YtdX);CHKERRQ(ierr);
23123d44fbcSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {ierr = VecDotBegin(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);}
2321c6523dcSPeter Brune       ierr = VecMDotEnd(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
2331c6523dcSPeter Brune       ierr = VecMDotEnd(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
2341c6523dcSPeter Brune       ierr = VecMDotEnd(Y,l,dX,YtdX);CHKERRQ(ierr);
23523d44fbcSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {
23623d44fbcSPeter Brune         ierr = VecDotEnd(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);
23723d44fbcSPeter Brune         qn->scaling = PetscRealPart(dXtdF[k]) / PetscRealPart(dFtdF);
23823d44fbcSPeter Brune       }
239b8840d6bSPeter Brune       for (j = 0; j < l; j++) {
240b8840d6bSPeter Brune         H(k, j) = dFtdX[j];
241b8840d6bSPeter Brune         H(j, k) = dXtdF[j];
242b8840d6bSPeter Brune       }
243b8840d6bSPeter Brune       /* copy back over to make the computation of alpha and beta easier */
2441aa26658SKarl Rupp       for (j = 0; j < l; j++) dXtdF[j] = H(j, j);
245b8840d6bSPeter Brune     } else {
246b8840d6bSPeter Brune       ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr);
247b8840d6bSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {
24867392de3SBarry Smith         PetscReal dFtdF;
24967392de3SBarry Smith         ierr        = VecDotRealPart(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);
25067392de3SBarry Smith         qn->scaling = PetscRealPart(dXtdF[k])/dFtdF;
25123d44fbcSPeter Brune       }
25223d44fbcSPeter Brune     }
25323d44fbcSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
254b8840d6bSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr);
255b8840d6bSPeter Brune     }
256b8840d6bSPeter Brune   }
257b8840d6bSPeter Brune 
2584b11644fSPeter Brune   /* outward recursion starting at iteration k's update and working back */
2594b11644fSPeter Brune   for (i=0; i<l; i++) {
260b21d5a53SPeter Brune     k = (it-i-1)%l;
26118aa0c0cSPeter Brune     if (qn->singlereduction) {
2628e231d97SPeter Brune       /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */
2638e231d97SPeter Brune       t = YtdX[k];
2648e231d97SPeter Brune       for (j=0; j<i; j++) {
2658e231d97SPeter Brune         g  = (it-j-1)%l;
266b3cfccb2SPeter Brune         t -= alpha[g]*H(k, g);
2678e231d97SPeter Brune       }
2688e231d97SPeter Brune       alpha[k] = t/H(k,k);
2698e231d97SPeter Brune     } else {
2703af51624SPeter Brune       ierr     = VecDot(dX[k],Y,&t);CHKERRQ(ierr);
2718e231d97SPeter Brune       alpha[k] = t/dXtdF[k];
2728e231d97SPeter Brune     }
27344f7e39eSPeter Brune     if (qn->monitor) {
2743af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
2755ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha:        %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr);
2763af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
27744f7e39eSPeter Brune     }
2786bf1b2e5SPeter Brune     ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr);
2794b11644fSPeter Brune   }
2804b11644fSPeter Brune 
2810c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
282d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
2830ecc9e1dSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
2840ecc9e1dSPeter Brune     if (kspreason < 0) {
2850ecc9e1dSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
2860ecc9e1dSPeter 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);
2870ecc9e1dSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
2880ecc9e1dSPeter Brune         PetscFunctionReturn(0);
2890ecc9e1dSPeter Brune       }
2900ecc9e1dSPeter Brune     }
2910ecc9e1dSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
2920ecc9e1dSPeter Brune     snes->linear_its += lits;
293b8840d6bSPeter Brune     ierr              = VecCopy(W, Y);CHKERRQ(ierr);
2940ecc9e1dSPeter Brune   } else {
295b21d5a53SPeter Brune     ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr);
2960ecc9e1dSPeter Brune   }
29718aa0c0cSPeter Brune   if (qn->singlereduction) {
298b8840d6bSPeter Brune     ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr);
2998e231d97SPeter Brune   }
3004b11644fSPeter Brune   /* inward recursion starting at the first update and working forward */
301bd052dfeSPeter Brune   for (i = 0; i < l; i++) {
302b21d5a53SPeter Brune     k = (it + i - l) % l;
30318aa0c0cSPeter Brune     if (qn->singlereduction) {
3048e231d97SPeter Brune       t = YtdX[k];
3058e231d97SPeter Brune       for (j = 0; j < i; j++) {
3068e231d97SPeter Brune         g  = (it + j - l) % l;
307b3cfccb2SPeter Brune         t += (alpha[g] - beta[g])*H(g, k);
3088e231d97SPeter Brune       }
3098e231d97SPeter Brune       beta[k] = t / H(k, k);
3108e231d97SPeter Brune     } else {
3116bf1b2e5SPeter Brune       ierr    = VecDot(dF[k], Y, &t);CHKERRQ(ierr);
3128e231d97SPeter Brune       beta[k] = t / dXtdF[k];
3138e231d97SPeter Brune     }
31422d28d08SBarry Smith     ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr);
31544f7e39eSPeter Brune     if (qn->monitor) {
3163af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
3175ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr);
3183af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
31944f7e39eSPeter Brune     }
3204b11644fSPeter Brune   }
3214b11644fSPeter Brune   PetscFunctionReturn(0);
3224b11644fSPeter Brune }
3234b11644fSPeter Brune 
3244b11644fSPeter Brune #undef __FUNCT__
3254b11644fSPeter Brune #define __FUNCT__ "SNESSolve_QN"
3264b11644fSPeter Brune static PetscErrorCode SNESSolve_QN(SNES snes)
3274b11644fSPeter Brune {
3284b11644fSPeter Brune   PetscErrorCode      ierr;
3299f83bee8SJed Brown   SNES_QN             *qn = (SNES_QN*) snes->data;
33015f5eeeaSPeter Brune   Vec                 X,Xold;
33147f26062SPeter Brune   Vec                 F;
33247f26062SPeter Brune   Vec                 Y,D,Dold;
333b8840d6bSPeter Brune   PetscInt            i, i_r;
334335fb975SPeter Brune   PetscReal           fnorm,xnorm,ynorm,gnorm;
3350c777b0cSPeter Brune   PetscBool           lssucceed,powell,periodic;
3361c6523dcSPeter Brune   PetscScalar         DolddotD,DolddotDold;
3370ecc9e1dSPeter Brune   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
338b7281c8aSPeter Brune   SNESConvergedReason reason;
3390ecc9e1dSPeter Brune 
3404b11644fSPeter Brune   /* basically just a regular newton's method except for the application of the jacobian */
3414b11644fSPeter Brune 
3426e111a19SKarl Rupp   PetscFunctionBegin;
3439f3a0142SPeter Brune   F = snes->vec_func;                   /* residual vector */
3443af51624SPeter Brune   Y = snes->vec_sol_update;             /* search direction generated by J^-1D*/
345b8840d6bSPeter Brune 
346b8840d6bSPeter Brune   X    = snes->vec_sol;                 /* solution vector */
347335fb975SPeter Brune   Xold = snes->work[0];
3483af51624SPeter Brune 
3493af51624SPeter Brune   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
350335fb975SPeter Brune   D    = snes->work[1];
351335fb975SPeter Brune   Dold = snes->work[2];
3524b11644fSPeter Brune 
3534b11644fSPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
3544b11644fSPeter Brune 
355ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3564b11644fSPeter Brune   snes->iter = 0;
3574b11644fSPeter Brune   snes->norm = 0.;
358ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
35947f26062SPeter Brune 
360b28a06ddSPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
36147f26062SPeter Brune     ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr);
362b7281c8aSPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
363b7281c8aSPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
364b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
365b7281c8aSPeter Brune       PetscFunctionReturn(0);
366b7281c8aSPeter Brune     }
36747f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
36847f26062SPeter Brune   } else {
369e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
37015f5eeeaSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
3714b11644fSPeter Brune       if (snes->domainerror) {
3724b11644fSPeter Brune         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
3734b11644fSPeter Brune         PetscFunctionReturn(0);
3744b11644fSPeter Brune       }
3751aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
376c1c75074SPeter Brune 
37747f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
378189a9710SBarry Smith     if (PetscIsInfOrNanReal(fnorm)) {
379189a9710SBarry Smith       snes->reason = SNES_DIVERGED_FNORM_NAN;
380189a9710SBarry Smith       PetscFunctionReturn(0);
381189a9710SBarry Smith     }
38247f26062SPeter Brune   }
383b28a06ddSPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
38447f26062SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr);
385b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
386b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
387b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
388b7281c8aSPeter Brune         PetscFunctionReturn(0);
389b7281c8aSPeter Brune       }
39047f26062SPeter Brune   } else {
39147f26062SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
39247f26062SPeter Brune   }
393b28a06ddSPeter Brune 
394ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3954b11644fSPeter Brune   snes->norm = fnorm;
396ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
397a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
3984b11644fSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
3994b11644fSPeter Brune 
4004b11644fSPeter Brune   /* test convergence */
4014b11644fSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
4024b11644fSPeter Brune   if (snes->reason) PetscFunctionReturn(0);
40370d3b23bSPeter Brune 
4043cf07b75SPeter Brune   if (snes->pc && snes->pcside == PC_RIGHT) {
4053cf07b75SPeter Brune     ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
4063cf07b75SPeter Brune     ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
4073cf07b75SPeter Brune     ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
408ddd40ce5SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
409ddd40ce5SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
410ddd40ce5SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
411ddd40ce5SPeter Brune       PetscFunctionReturn(0);
412ddd40ce5SPeter Brune     }
413ddd40ce5SPeter Brune     ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
4143cf07b75SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
4153cf07b75SPeter Brune   }
4163cf07b75SPeter Brune 
417f8e15203SPeter Brune   /* scale the initial update */
4180c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
4190ecc9e1dSPeter Brune     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
4208cba9625SJed Brown     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
4210ecc9e1dSPeter Brune   }
4220ecc9e1dSPeter Brune 
4235ba6227bSPeter Brune   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
424b8840d6bSPeter Brune     switch (qn->type) {
425b8840d6bSPeter Brune     case SNES_QN_BADBROYDEN:
426b8840d6bSPeter Brune       ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
427b8840d6bSPeter Brune       break;
428b8840d6bSPeter Brune     case SNES_QN_BROYDEN:
429b8840d6bSPeter Brune       ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
430b8840d6bSPeter Brune       break;
431b8840d6bSPeter Brune     case SNES_QN_LBFGS:
432b8840d6bSPeter Brune       SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
433b8840d6bSPeter Brune       break;
434b8840d6bSPeter Brune     }
43570d3b23bSPeter Brune     /* line search for lambda */
43670d3b23bSPeter Brune     ynorm = 1; gnorm = fnorm;
43788d374b2SPeter Brune     ierr  = VecCopy(D, Dold);CHKERRQ(ierr);
43815f5eeeaSPeter Brune     ierr  = VecCopy(X, Xold);CHKERRQ(ierr);
439f1c6b773SPeter Brune     ierr  = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr);
4409f3a0142SPeter Brune     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
4419f3a0142SPeter Brune     if (snes->domainerror) {
4429f3a0142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
4439f3a0142SPeter Brune       PetscFunctionReturn(0);
4449f3a0142SPeter Brune     }
445f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
4469f3a0142SPeter Brune     if (!lssucceed) {
4479f3a0142SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
4489f3a0142SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
4499f3a0142SPeter Brune         break;
4509f3a0142SPeter Brune       }
4519f3a0142SPeter Brune     }
452f1c6b773SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
4530c777b0cSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
45405ee83feSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr);
4550ecc9e1dSPeter Brune     }
4563af51624SPeter Brune 
45788d374b2SPeter Brune     /* convergence monitoring */
458b21d5a53SPeter 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);
459b21d5a53SPeter Brune 
460b28a06ddSPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
461b28a06ddSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
462b28a06ddSPeter Brune       ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
463b28a06ddSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
464ddd40ce5SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
465ddd40ce5SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
466ddd40ce5SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
467ddd40ce5SPeter Brune         PetscFunctionReturn(0);
468ddd40ce5SPeter Brune       }
469ddd40ce5SPeter Brune       ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
470b28a06ddSPeter Brune     }
471b28a06ddSPeter Brune 
472360c497dSPeter Brune     ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr);
473360c497dSPeter Brune     ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr);
474360c497dSPeter Brune 
475a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
4768409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
4774b11644fSPeter Brune     /* set parameter for default relative tolerance convergence test */
478d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
4794b11644fSPeter Brune     if (snes->reason) PetscFunctionReturn(0);
480b28a06ddSPeter Brune     if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
48147f26062SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr);
482b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
483b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
484b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
485b7281c8aSPeter Brune         PetscFunctionReturn(0);
486b7281c8aSPeter Brune       }
48788d374b2SPeter Brune     } else {
48888d374b2SPeter Brune       ierr = VecCopy(F, D);CHKERRQ(ierr);
48988d374b2SPeter Brune     }
49088d374b2SPeter Brune 
4910c777b0cSPeter Brune     powell = PETSC_FALSE;
4920c777b0cSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_POWELL) {
4936bf1b2e5SPeter Brune       /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */
4948e231d97SPeter Brune       ierr = VecDotBegin(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
4958e231d97SPeter Brune       ierr = VecDotBegin(Dold, D, &DolddotD);CHKERRQ(ierr);
4968e231d97SPeter Brune       ierr = VecDotEnd(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
4978e231d97SPeter Brune       ierr = VecDotEnd(Dold, D, &DolddotD);CHKERRQ(ierr);
4980c777b0cSPeter Brune       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
4990c777b0cSPeter Brune     }
5000c777b0cSPeter Brune     periodic = PETSC_FALSE;
501b8840d6bSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
502b8840d6bSPeter Brune       if (i_r>qn->m-1) periodic = PETSC_TRUE;
5030c777b0cSPeter Brune     }
5040c777b0cSPeter Brune     /* restart if either powell or periodic restart is satisfied. */
5050c777b0cSPeter Brune     if (powell || periodic) {
5065ba6227bSPeter Brune       if (qn->monitor) {
5075ba6227bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
508516fe3c3SPeter 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);
5095ba6227bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
5105ba6227bSPeter Brune       }
5115ba6227bSPeter Brune       i_r = -1;
5125ba6227bSPeter Brune       /* general purpose update */
5135ba6227bSPeter Brune       if (snes->ops->update) {
5145ba6227bSPeter Brune         ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
5155ba6227bSPeter Brune       }
5160c777b0cSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5170ecc9e1dSPeter Brune         ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
5188cba9625SJed Brown         ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
5190ecc9e1dSPeter Brune       }
5200ecc9e1dSPeter Brune     }
52170d3b23bSPeter Brune     /* general purpose update */
52270d3b23bSPeter Brune     if (snes->ops->update) {
52370d3b23bSPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
52470d3b23bSPeter Brune     }
5255ba6227bSPeter Brune   }
5264b11644fSPeter Brune   if (i == snes->max_its) {
5274b11644fSPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr);
5284b11644fSPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
5294b11644fSPeter Brune   }
5304b11644fSPeter Brune   PetscFunctionReturn(0);
5314b11644fSPeter Brune }
5324b11644fSPeter Brune 
5334b11644fSPeter Brune #undef __FUNCT__
5344b11644fSPeter Brune #define __FUNCT__ "SNESSetUp_QN"
5354b11644fSPeter Brune static PetscErrorCode SNESSetUp_QN(SNES snes)
5364b11644fSPeter Brune {
5379f83bee8SJed Brown   SNES_QN        *qn = (SNES_QN*)snes->data;
5384b11644fSPeter Brune   PetscErrorCode ierr;
539335fb975SPeter Brune 
5404b11644fSPeter Brune   PetscFunctionBegin;
541b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr);
542*59e7931aSPeter Brune   if (qn->type != SNES_QN_BROYDEN) ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr);
5435c7a0a03SPeter Brune   ierr = PetscMalloc4(qn->m, PetscScalar, &qn->alpha,
5448e231d97SPeter Brune                       qn->m, PetscScalar, &qn->beta,
5455c7a0a03SPeter Brune                       qn->m, PetscScalar, &qn->dXtdF,
5465c7a0a03SPeter Brune                       qn->m, PetscReal, &qn->lambda);CHKERRQ(ierr);
5478e231d97SPeter Brune 
54818aa0c0cSPeter Brune   if (qn->singlereduction) {
5498e231d97SPeter Brune     ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat,
5508e231d97SPeter Brune                         qn->m, PetscScalar, &qn->dFtdX,
5518e231d97SPeter Brune                         qn->m, PetscScalar, &qn->YtdX);CHKERRQ(ierr);
5528e231d97SPeter Brune   }
553fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr);
554335fb975SPeter Brune 
555335fb975SPeter Brune   /* set up the line search */
5560c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5578e231d97SPeter Brune     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
5588e231d97SPeter Brune   }
5596c67d002SPeter Brune 
5606c67d002SPeter Brune   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;}
5616c67d002SPeter Brune 
5624b11644fSPeter Brune   PetscFunctionReturn(0);
5634b11644fSPeter Brune }
5644b11644fSPeter Brune 
5654b11644fSPeter Brune #undef __FUNCT__
5664b11644fSPeter Brune #define __FUNCT__ "SNESReset_QN"
5674b11644fSPeter Brune static PetscErrorCode SNESReset_QN(SNES snes)
5684b11644fSPeter Brune {
5694b11644fSPeter Brune   PetscErrorCode ierr;
5709f83bee8SJed Brown   SNES_QN        *qn;
5710adebc6cSBarry Smith 
5724b11644fSPeter Brune   PetscFunctionBegin;
5734b11644fSPeter Brune   if (snes->data) {
5749f83bee8SJed Brown     qn = (SNES_QN*)snes->data;
575b8840d6bSPeter Brune     if (qn->U) {
576b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr);
5774b11644fSPeter Brune     }
578b8840d6bSPeter Brune     if (qn->V) {
579b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr);
5804b11644fSPeter Brune     }
58118aa0c0cSPeter Brune     if (qn->singlereduction) {
5828e231d97SPeter Brune       ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr);
5838e231d97SPeter Brune     }
5845c7a0a03SPeter Brune     ierr = PetscFree4(qn->alpha,qn->beta,qn->dXtdF,qn->lambda);CHKERRQ(ierr);
5854b11644fSPeter Brune   }
5864b11644fSPeter Brune   PetscFunctionReturn(0);
5874b11644fSPeter Brune }
5884b11644fSPeter Brune 
5894b11644fSPeter Brune #undef __FUNCT__
5904b11644fSPeter Brune #define __FUNCT__ "SNESDestroy_QN"
5914b11644fSPeter Brune static PetscErrorCode SNESDestroy_QN(SNES snes)
5924b11644fSPeter Brune {
5934b11644fSPeter Brune   PetscErrorCode ierr;
5946e111a19SKarl Rupp 
5954b11644fSPeter Brune   PetscFunctionBegin;
5964b11644fSPeter Brune   ierr = SNESReset_QN(snes);CHKERRQ(ierr);
5974b11644fSPeter Brune   ierr = PetscFree(snes->data);CHKERRQ(ierr);
598bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr);
5994b11644fSPeter Brune   PetscFunctionReturn(0);
6004b11644fSPeter Brune }
6014b11644fSPeter Brune 
6024b11644fSPeter Brune #undef __FUNCT__
6034b11644fSPeter Brune #define __FUNCT__ "SNESSetFromOptions_QN"
6044b11644fSPeter Brune static PetscErrorCode SNESSetFromOptions_QN(SNES snes)
6054b11644fSPeter Brune {
6064b11644fSPeter Brune 
6074b11644fSPeter Brune   PetscErrorCode    ierr;
6082150357eSBarry Smith   SNES_QN           *qn    = (SNES_QN*)snes->data;
60988f769c5SPeter Brune   PetscBool         monflg = PETSC_FALSE,flg;
610f1c6b773SPeter Brune   SNESLineSearch    linesearch;
6112150357eSBarry Smith   SNESQNRestartType rtype = qn->restart_type;
6122150357eSBarry Smith   SNESQNScaleType   stype = qn->scale_type;
6132150357eSBarry Smith 
6144b11644fSPeter Brune   PetscFunctionBegin;
6154b11644fSPeter Brune   ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr);
6160298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,NULL);CHKERRQ(ierr);
6170298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance",          "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL);CHKERRQ(ierr);
6180298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance",        "SNESQN", qn->powell_downhill, &qn->powell_downhill, NULL);CHKERRQ(ierr);
6190298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_monitor",         "Monitor for the QN methods",      "SNESQN", monflg, &monflg, NULL);CHKERRQ(ierr);
6200298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions",           "SNESQN", qn->singlereduction, &qn->singlereduction, NULL);CHKERRQ(ierr);
62188f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr);
62288f769c5SPeter Brune   if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr);
62388f769c5SPeter Brune 
62488f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr);
62588f769c5SPeter Brune   if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr);
62688f769c5SPeter Brune 
627b8840d6bSPeter Brune   ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes,
6280298fd71SBarry Smith                           (PetscEnum)qn->type,(PetscEnum*)&qn->type,NULL);CHKERRQ(ierr);
6294b11644fSPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
6309e764e56SPeter Brune   if (!snes->linesearch) {
6317601faf0SJed Brown     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
6321a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
6339e764e56SPeter Brune   }
63444f7e39eSPeter Brune   if (monflg) {
635ce94432eSBarry Smith     qn->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
63644f7e39eSPeter Brune   }
6374b11644fSPeter Brune   PetscFunctionReturn(0);
6384b11644fSPeter Brune }
6394b11644fSPeter Brune 
64092c02d66SPeter Brune 
6410c777b0cSPeter Brune #undef __FUNCT__
6420c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType"
6430c777b0cSPeter Brune /*@
6440c777b0cSPeter Brune     SNESQNSetRestartType - Sets the restart type for SNESQN.
6450c777b0cSPeter Brune 
6460c777b0cSPeter Brune     Logically Collective on SNES
6470c777b0cSPeter Brune 
6480c777b0cSPeter Brune     Input Parameters:
6490c777b0cSPeter Brune +   snes - the iterative context
6500c777b0cSPeter Brune -   rtype - restart type
6510c777b0cSPeter Brune 
6520c777b0cSPeter Brune     Options Database:
6530c777b0cSPeter Brune +   -snes_qn_restart_type<powell,periodic,none> - set the restart type
654b8840d6bSPeter Brune -   -snes_qn_restart[10] - sets the number of iterations before restart for periodic
6550c777b0cSPeter Brune 
6560c777b0cSPeter Brune     Level: intermediate
6570c777b0cSPeter Brune 
6580c777b0cSPeter Brune     SNESQNRestartTypes:
6590c777b0cSPeter Brune +   SNES_QN_RESTART_NONE - never restart
6600c777b0cSPeter Brune .   SNES_QN_RESTART_POWELL - restart based upon descent criteria
6610c777b0cSPeter Brune -   SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations
6620c777b0cSPeter Brune 
6630c777b0cSPeter Brune     Notes:
6640c777b0cSPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
6650c777b0cSPeter Brune 
6660c777b0cSPeter Brune .keywords: SNES, SNESQN, restart, type, set SNESLineSearch
6670c777b0cSPeter Brune @*/
6682150357eSBarry Smith PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
6692150357eSBarry Smith {
6700c777b0cSPeter Brune   PetscErrorCode ierr;
6716e111a19SKarl Rupp 
6720c777b0cSPeter Brune   PetscFunctionBegin;
6730c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
6740c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr);
6750c777b0cSPeter Brune   PetscFunctionReturn(0);
6760c777b0cSPeter Brune }
6770c777b0cSPeter Brune 
6780c777b0cSPeter Brune #undef __FUNCT__
6790c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType"
6800c777b0cSPeter Brune /*@
6810c777b0cSPeter Brune     SNESQNSetScaleType - Sets the scaling type for the inner inverse jacobian in SNESQN.
6820c777b0cSPeter Brune 
6830c777b0cSPeter Brune     Logically Collective on SNES
6840c777b0cSPeter Brune 
6850c777b0cSPeter Brune     Input Parameters:
6860c777b0cSPeter Brune +   snes - the iterative context
6870c777b0cSPeter Brune -   stype - scale type
6880c777b0cSPeter Brune 
6890c777b0cSPeter Brune     Options Database:
6900c777b0cSPeter Brune .   -snes_qn_scale_type<shanno,none,linesearch,jacobian>
6910c777b0cSPeter Brune 
6920c777b0cSPeter Brune     Level: intermediate
6930c777b0cSPeter Brune 
6940c777b0cSPeter Brune     SNESQNSelectTypes:
6950c777b0cSPeter Brune +   SNES_QN_SCALE_NONE - don't scale the problem
6960c777b0cSPeter Brune .   SNES_QN_SCALE_SHANNO - use shanno scaling
6970c777b0cSPeter Brune .   SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda
6980c777b0cSPeter Brune -   SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian.
6990c777b0cSPeter Brune 
7000c777b0cSPeter Brune .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch
7010c777b0cSPeter Brune @*/
7020c777b0cSPeter Brune 
7032150357eSBarry Smith PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
7042150357eSBarry Smith {
7050c777b0cSPeter Brune   PetscErrorCode ierr;
7066e111a19SKarl Rupp 
7070c777b0cSPeter Brune   PetscFunctionBegin;
7080c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
7090c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr);
7100c777b0cSPeter Brune   PetscFunctionReturn(0);
7110c777b0cSPeter Brune }
7120c777b0cSPeter Brune 
7130c777b0cSPeter Brune #undef __FUNCT__
7140c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType_QN"
7150adebc6cSBarry Smith PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
7160adebc6cSBarry Smith {
7170c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7186e111a19SKarl Rupp 
7190c777b0cSPeter Brune   PetscFunctionBegin;
7200c777b0cSPeter Brune   qn->scale_type = stype;
7210c777b0cSPeter Brune   PetscFunctionReturn(0);
7220c777b0cSPeter Brune }
7230c777b0cSPeter Brune 
7240c777b0cSPeter Brune #undef __FUNCT__
7250c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType_QN"
7260adebc6cSBarry Smith PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
7270adebc6cSBarry Smith {
7280c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7296e111a19SKarl Rupp 
7300c777b0cSPeter Brune   PetscFunctionBegin;
7310c777b0cSPeter Brune   qn->restart_type = rtype;
7320c777b0cSPeter Brune   PetscFunctionReturn(0);
7330c777b0cSPeter Brune }
7340c777b0cSPeter Brune 
7354b11644fSPeter Brune /* -------------------------------------------------------------------------- */
7364b11644fSPeter Brune /*MC
7374b11644fSPeter Brune       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
7384b11644fSPeter Brune 
7396cc8130cSPeter Brune       Options Database:
7406cc8130cSPeter Brune 
7416cc8130cSPeter Brune +     -snes_qn_m - Number of past states saved for the L-Broyden methods.
7421867fe5bSPeter Brune .     -snes_qn_powell_angle - Angle condition for restart.
7431867fe5bSPeter Brune .     -snes_qn_powell_descent - Descent condition for restart.
74472835e02SPeter Brune .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
74544f7e39eSPeter Brune -     -snes_qn_monitor - Monitors the quasi-newton jacobian.
7466cc8130cSPeter Brune 
747b8840d6bSPeter Brune       Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
748b8840d6bSPeter Brune       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
749b8840d6bSPeter Brune       updates.
7506cc8130cSPeter Brune 
7511867fe5bSPeter Brune       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
7521867fe5bSPeter Brune       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
7531867fe5bSPeter Brune       iteration as the current iteration's values when constructing the approximate jacobian.  The second, composed,
7541867fe5bSPeter Brune       perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
7551867fe5bSPeter Brune 
7566cc8130cSPeter Brune       References:
7576cc8130cSPeter Brune 
7580a8e8854SPeter Brune       Kelley, C.T., Iterative Methods for Linear and Nonlinear Equations, Chapter 8, SIAM, 1995.
7596cc8130cSPeter Brune 
7600a8e8854SPeter Brune       R. Byrd, J. Nocedal, R. Schnabel, Representations of Quasi-Newton Matrices and their use in Limited Memory Methods,
7610a8e8854SPeter Brune       Technical Report, Northwestern University, June 1992.
7620a8e8854SPeter Brune 
7630a8e8854SPeter Brune       Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker, Experiments with Quasi-Newton Methods in Solving Stiff ODE
7640a8e8854SPeter Brune       Systems, SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
765b8840d6bSPeter Brune 
7664b11644fSPeter Brune 
7674b11644fSPeter Brune       Level: beginner
7684b11644fSPeter Brune 
76904d7464bSBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR
7706cc8130cSPeter Brune 
7714b11644fSPeter Brune M*/
7724b11644fSPeter Brune #undef __FUNCT__
7734b11644fSPeter Brune #define __FUNCT__ "SNESCreate_QN"
7748cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes)
7754b11644fSPeter Brune {
7764b11644fSPeter Brune   PetscErrorCode ierr;
7779f83bee8SJed Brown   SNES_QN        *qn;
7784b11644fSPeter Brune 
7794b11644fSPeter Brune   PetscFunctionBegin;
7804b11644fSPeter Brune   snes->ops->setup          = SNESSetUp_QN;
7814b11644fSPeter Brune   snes->ops->solve          = SNESSolve_QN;
7824b11644fSPeter Brune   snes->ops->destroy        = SNESDestroy_QN;
7834b11644fSPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_QN;
7844b11644fSPeter Brune   snes->ops->view           = 0;
7854b11644fSPeter Brune   snes->ops->reset          = SNESReset_QN;
7864b11644fSPeter Brune 
78747f26062SPeter Brune   snes->pcside = PC_LEFT;
78847f26062SPeter Brune 
78942f4f86dSBarry Smith   snes->usespc  = PETSC_TRUE;
79042f4f86dSBarry Smith   snes->usesksp = PETSC_FALSE;
79142f4f86dSBarry Smith 
79288976e71SPeter Brune   if (!snes->tolerancesset) {
7930e444f03SPeter Brune     snes->max_funcs = 30000;
7940e444f03SPeter Brune     snes->max_its   = 10000;
79588976e71SPeter Brune   }
7960e444f03SPeter Brune 
7979f83bee8SJed Brown   ierr                = PetscNewLog(snes,SNES_QN,&qn);CHKERRQ(ierr);
7984b11644fSPeter Brune   snes->data          = (void*) qn;
7990ecc9e1dSPeter Brune   qn->m               = 10;
800b21d5a53SPeter Brune   qn->scaling         = 1.0;
8010298fd71SBarry Smith   qn->U               = NULL;
8020298fd71SBarry Smith   qn->V               = NULL;
8030298fd71SBarry Smith   qn->dXtdF           = NULL;
8040298fd71SBarry Smith   qn->dFtdX           = NULL;
8050298fd71SBarry Smith   qn->dXdFmat         = NULL;
8060298fd71SBarry Smith   qn->monitor         = NULL;
8071c6523dcSPeter Brune   qn->singlereduction = PETSC_TRUE;
808b8840d6bSPeter Brune   qn->powell_gamma    = 0.9999;
8090c777b0cSPeter Brune   qn->scale_type      = SNES_QN_SCALE_SHANNO;
8100c777b0cSPeter Brune   qn->restart_type    = SNES_QN_RESTART_POWELL;
811b8840d6bSPeter Brune   qn->type            = SNES_QN_LBFGS;
812ea630c6eSPeter Brune 
813bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetScaleType_C",SNESQNSetScaleType_QN);CHKERRQ(ierr);
814bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetRestartType_C",SNESQNSetRestartType_QN);CHKERRQ(ierr);
8154b11644fSPeter Brune   PetscFunctionReturn(0);
8164b11644fSPeter Brune }
817