xref: /petsc/src/snes/impls/qn/qn.c (revision 23c918e704714d5beb8190c593494696b95a3d84)
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"
355051edb1SPeter Brune PetscErrorCode SNESQNApply_Broyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D)
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;
4759e7931aSPeter 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);
545051edb1SPeter Brune     ierr = VecCopy(U[k],Xold);CHKERRQ(ierr);
555051edb1SPeter Brune     ierr = VecAXPY(U[k],-1.0,X);CHKERRQ(ierr);
565c7a0a03SPeter Brune     if (qn->monitor) {
575c7a0a03SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
585c7a0a03SPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "scaling vector %d of %d by lambda: %14.12e \n",k,l,lambda[k]);CHKERRQ(ierr);
595c7a0a03SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
605c7a0a03SPeter Brune     }
615c7a0a03SPeter Brune   }
62b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
63d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,D,W);CHKERRQ(ierr);
64b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
65b8840d6bSPeter Brune     if (kspreason < 0) {
66b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
67b8840d6bSPeter 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);
68b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
69b8840d6bSPeter Brune         PetscFunctionReturn(0);
70b8840d6bSPeter Brune       }
71b8840d6bSPeter Brune     }
72b8840d6bSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
73b8840d6bSPeter Brune     snes->linear_its += lits;
74b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
75b8840d6bSPeter Brune   } else {
76b8840d6bSPeter Brune     ierr = VecCopy(D,Y);CHKERRQ(ierr);
77b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
78b8840d6bSPeter Brune   }
79b8840d6bSPeter Brune 
80b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
81b8840d6bSPeter Brune   for (i = 0; i < l-1; i++) {
825c7a0a03SPeter Brune     j = (it+i-l)%l;
835c7a0a03SPeter Brune     k = (it+i-l+1)%l;
845c7a0a03SPeter Brune 
855c7a0a03SPeter Brune     ierr = VecNorm(U[j],NORM_2,&unorm);CHKERRQ(ierr);
865c7a0a03SPeter Brune     ierr = VecDot(U[j],Y,&gdot);CHKERRQ(ierr);
8759e7931aSPeter Brune     unorm *= unorm;
8859e7931aSPeter Brune     udot = PetscRealPart(gdot);
895c7a0a03SPeter Brune     a = (lambda[j]/lambda[k]);
905c7a0a03SPeter Brune     b = -(1.-lambda[j]);
9159e7931aSPeter Brune     a *= udot/unorm;
9259e7931aSPeter Brune     b *= udot/unorm;
935c7a0a03SPeter Brune     ierr = VecAXPBYPCZ(Y,a,b,1.,U[k],U[j]);CHKERRQ(ierr);
945c7a0a03SPeter Brune 
95b8840d6bSPeter Brune     if (qn->monitor) {
96b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
975c7a0a03SPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d and %d, gdot: %14.12e\n",k,j,gdot);CHKERRQ(ierr);
98b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
99b8840d6bSPeter Brune     }
100b8840d6bSPeter Brune   }
101b8840d6bSPeter Brune   if (l > 0) {
102b8840d6bSPeter Brune     k = (it-1)%l;
103b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
1045c7a0a03SPeter Brune     ierr = VecNorm(U[k],NORM_2,&unorm);CHKERRQ(ierr);
10559e7931aSPeter Brune     unorm *= unorm;
10659e7931aSPeter Brune     udot = PetscRealPart(gdot);
10759e7931aSPeter Brune     a = unorm/(unorm-lambda[k]*udot);
10859e7931aSPeter Brune     b = -(1.-lambda[k])*udot/(unorm-lambda[k]*udot);
109b8840d6bSPeter Brune     if (qn->monitor) {
110b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
11159e7931aSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d: a: %14.12e b: %14.12e \n",k,a,b);CHKERRQ(ierr);
112b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
113b8840d6bSPeter Brune     }
1145c7a0a03SPeter Brune     ierr = VecAXPBY(Y,b,a,U[k]);CHKERRQ(ierr);
115b8840d6bSPeter Brune   }
1165c7a0a03SPeter Brune   l = m;
1175c7a0a03SPeter Brune   if (it+1<m)l=it+1;
1185c7a0a03SPeter Brune   k = it%l;
1195c7a0a03SPeter Brune   if (qn->monitor) {
1205c7a0a03SPeter Brune     ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1215c7a0a03SPeter Brune     ierr = PetscViewerASCIIPrintf(qn->monitor, "setting vector %d of %d\n",k,l);CHKERRQ(ierr);
1225c7a0a03SPeter Brune     ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1235c7a0a03SPeter Brune   }
1245c7a0a03SPeter Brune   ierr = VecCopy(Y,U[k]);CHKERRQ(ierr);
125b8840d6bSPeter Brune   PetscFunctionReturn(0);
126b8840d6bSPeter Brune }
127b8840d6bSPeter Brune 
128b8840d6bSPeter Brune #undef __FUNCT__
129b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_BadBroyden"
1300adebc6cSBarry Smith PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1310adebc6cSBarry Smith {
132b8840d6bSPeter Brune   PetscErrorCode ierr;
133b8840d6bSPeter Brune   SNES_QN        *qn = (SNES_QN*)snes->data;
134b8840d6bSPeter Brune   Vec            W   = snes->work[3];
135b8840d6bSPeter Brune   Vec            *U  = qn->U;
136b8840d6bSPeter Brune   Vec            *T  = qn->V;
137b8840d6bSPeter Brune 
138b8840d6bSPeter Brune   /* ksp thing for jacobian scaling */
139b8840d6bSPeter Brune   KSPConvergedReason kspreason;
140c9e59058SPeter Brune   PetscInt           h,k,j,i,lits;
141b8840d6bSPeter Brune   PetscInt           m = qn->m;
1425051edb1SPeter Brune   PetscScalar        gdot,udot;
143b8840d6bSPeter Brune   PetscInt           l = m;
1440adebc6cSBarry Smith 
145b8840d6bSPeter Brune   PetscFunctionBegin;
146b8840d6bSPeter Brune   if (it < m) l = it;
147b8840d6bSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
148b8840d6bSPeter Brune   if (l > 0) {
149b8840d6bSPeter Brune     k    = (it-1)%l;
150c9e59058SPeter Brune     ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->lambda[k]);CHKERRQ(ierr);
151b8840d6bSPeter Brune     ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr);
152b8840d6bSPeter Brune     ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr);
1535051edb1SPeter Brune     ierr = VecCopy(Xold,T[k]);CHKERRQ(ierr);
1545051edb1SPeter Brune     ierr = VecAXPY(T[k],-1.0,X);CHKERRQ(ierr);
155b8840d6bSPeter Brune   }
156b8840d6bSPeter Brune 
157b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
158d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
159b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
160b8840d6bSPeter Brune     if (kspreason < 0) {
161b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
162b8840d6bSPeter 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);
163b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
164b8840d6bSPeter Brune         PetscFunctionReturn(0);
165b8840d6bSPeter Brune       }
166b8840d6bSPeter Brune     }
167b8840d6bSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
168b8840d6bSPeter Brune     snes->linear_its += lits;
169b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
170b8840d6bSPeter Brune   } else {
171b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
172b8840d6bSPeter Brune   }
1735051edb1SPeter Brune 
1745051edb1SPeter Brune   /* inward recursion starting at the first update and working forward */
1755051edb1SPeter Brune   if (l > 0) {
1765051edb1SPeter Brune     for (i = 0; i < l-1; i++) {
177c9e59058SPeter Brune       j    = (it+i-l)%l;
178c9e59058SPeter Brune       k    = (it+i-l+1)%l;
179c9e59058SPeter Brune       h    = (it-1)%l;
180c9e59058SPeter Brune       ierr = VecDotBegin(U[j],U[h],&gdot);CHKERRQ(ierr);
181c9e59058SPeter Brune       ierr = VecDotBegin(U[j],U[j],&udot);CHKERRQ(ierr);
182c9e59058SPeter Brune       ierr = VecDotEnd(U[j],U[h],&gdot);CHKERRQ(ierr);
183c9e59058SPeter Brune       ierr = VecDotEnd(U[j],U[j],&udot);CHKERRQ(ierr);
1845051edb1SPeter Brune       ierr = VecAXPY(Y,PetscRealPart(gdot)/PetscRealPart(udot),T[k]);CHKERRQ(ierr);
185c9e59058SPeter Brune       ierr = VecAXPY(Y,-(1.-qn->lambda[k])*PetscRealPart(gdot)/PetscRealPart(udot),T[j]);CHKERRQ(ierr);
1865051edb1SPeter Brune       if (qn->monitor) {
1875051edb1SPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1885051edb1SPeter Brune         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
1895051edb1SPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
1905051edb1SPeter Brune       }
1915051edb1SPeter Brune     }
1925051edb1SPeter Brune   }
193b8840d6bSPeter Brune   PetscFunctionReturn(0);
194b8840d6bSPeter Brune }
195b8840d6bSPeter Brune 
196b8840d6bSPeter Brune #undef __FUNCT__
197b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_LBFGS"
1980adebc6cSBarry Smith PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1990adebc6cSBarry Smith {
200b8840d6bSPeter Brune   PetscErrorCode ierr;
201b8840d6bSPeter Brune   SNES_QN        *qn    = (SNES_QN*)snes->data;
202b8840d6bSPeter Brune   Vec            W      = snes->work[3];
203b8840d6bSPeter Brune   Vec            *dX    = qn->U;
204b8840d6bSPeter Brune   Vec            *dF    = qn->V;
205bd052dfeSPeter Brune   PetscScalar    *alpha = qn->alpha;
206bd052dfeSPeter Brune   PetscScalar    *beta  = qn->beta;
2078e231d97SPeter Brune   PetscScalar    *dXtdF = qn->dXtdF;
208b8840d6bSPeter Brune   PetscScalar    *dFtdX = qn->dFtdX;
2098e231d97SPeter Brune   PetscScalar    *YtdX  = qn->YtdX;
210bd052dfeSPeter Brune 
2110ecc9e1dSPeter Brune   /* ksp thing for jacobian scaling */
2120ecc9e1dSPeter Brune   KSPConvergedReason kspreason;
2138e231d97SPeter Brune   PetscInt           k,i,j,g,lits;
2144b11644fSPeter Brune   PetscInt           m = qn->m;
2154b11644fSPeter Brune   PetscScalar        t;
2164b11644fSPeter Brune   PetscInt           l = m;
2178e231d97SPeter Brune 
2184b11644fSPeter Brune   PetscFunctionBegin;
2195ba6227bSPeter Brune   if (it < m) l = it;
2201c6523dcSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
221b8840d6bSPeter Brune   if (it > 0) {
222b8840d6bSPeter Brune     k    = (it - 1) % l;
223b8840d6bSPeter Brune     ierr = VecCopy(D,dF[k]);CHKERRQ(ierr);
224b8840d6bSPeter Brune     ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr);
225b8840d6bSPeter Brune     ierr = VecCopy(X, dX[k]);CHKERRQ(ierr);
226b8840d6bSPeter Brune     ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr);
22718aa0c0cSPeter Brune     if (qn->singlereduction) {
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);
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);
234b8840d6bSPeter Brune       for (j = 0; j < l; j++) {
235b8840d6bSPeter Brune         H(k, j) = dFtdX[j];
236b8840d6bSPeter Brune         H(j, k) = dXtdF[j];
237b8840d6bSPeter Brune       }
238b8840d6bSPeter Brune       /* copy back over to make the computation of alpha and beta easier */
2391aa26658SKarl Rupp       for (j = 0; j < l; j++) dXtdF[j] = H(j, j);
240b8840d6bSPeter Brune     } else {
241b8840d6bSPeter Brune       ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr);
24223d44fbcSPeter Brune     }
24323d44fbcSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
244b8840d6bSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr);
245b8840d6bSPeter Brune     }
246b8840d6bSPeter Brune   }
247b8840d6bSPeter Brune 
2484b11644fSPeter Brune   /* outward recursion starting at iteration k's update and working back */
2494b11644fSPeter Brune   for (i=0; i<l; i++) {
250b21d5a53SPeter Brune     k = (it-i-1)%l;
25118aa0c0cSPeter Brune     if (qn->singlereduction) {
2528e231d97SPeter Brune       /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */
2538e231d97SPeter Brune       t = YtdX[k];
2548e231d97SPeter Brune       for (j=0; j<i; j++) {
2558e231d97SPeter Brune         g  = (it-j-1)%l;
256b3cfccb2SPeter Brune         t -= alpha[g]*H(k, g);
2578e231d97SPeter Brune       }
2588e231d97SPeter Brune       alpha[k] = t/H(k,k);
2598e231d97SPeter Brune     } else {
2603af51624SPeter Brune       ierr     = VecDot(dX[k],Y,&t);CHKERRQ(ierr);
2618e231d97SPeter Brune       alpha[k] = t/dXtdF[k];
2628e231d97SPeter Brune     }
26344f7e39eSPeter Brune     if (qn->monitor) {
2643af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
2655ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha:        %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr);
2663af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
26744f7e39eSPeter Brune     }
2686bf1b2e5SPeter Brune     ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr);
2694b11644fSPeter Brune   }
2704b11644fSPeter Brune 
2710c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
272d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
2730ecc9e1dSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
2740ecc9e1dSPeter Brune     if (kspreason < 0) {
2750ecc9e1dSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
2760ecc9e1dSPeter 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);
2770ecc9e1dSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
2780ecc9e1dSPeter Brune         PetscFunctionReturn(0);
2790ecc9e1dSPeter Brune       }
2800ecc9e1dSPeter Brune     }
2810ecc9e1dSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
2820ecc9e1dSPeter Brune     snes->linear_its += lits;
283b8840d6bSPeter Brune     ierr              = VecCopy(W, Y);CHKERRQ(ierr);
2840ecc9e1dSPeter Brune   } else {
285b21d5a53SPeter Brune     ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr);
2860ecc9e1dSPeter Brune   }
28718aa0c0cSPeter Brune   if (qn->singlereduction) {
288b8840d6bSPeter Brune     ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr);
2898e231d97SPeter Brune   }
2904b11644fSPeter Brune   /* inward recursion starting at the first update and working forward */
291bd052dfeSPeter Brune   for (i = 0; i < l; i++) {
292b21d5a53SPeter Brune     k = (it + i - l) % l;
29318aa0c0cSPeter Brune     if (qn->singlereduction) {
2948e231d97SPeter Brune       t = YtdX[k];
2958e231d97SPeter Brune       for (j = 0; j < i; j++) {
2968e231d97SPeter Brune         g  = (it + j - l) % l;
297b3cfccb2SPeter Brune         t += (alpha[g] - beta[g])*H(g, k);
2988e231d97SPeter Brune       }
2998e231d97SPeter Brune       beta[k] = t / H(k, k);
3008e231d97SPeter Brune     } else {
3016bf1b2e5SPeter Brune       ierr    = VecDot(dF[k], Y, &t);CHKERRQ(ierr);
3028e231d97SPeter Brune       beta[k] = t / dXtdF[k];
3038e231d97SPeter Brune     }
30422d28d08SBarry Smith     ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr);
30544f7e39eSPeter Brune     if (qn->monitor) {
3063af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
3075ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr);
3083af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
30944f7e39eSPeter Brune     }
3104b11644fSPeter Brune   }
3114b11644fSPeter Brune   PetscFunctionReturn(0);
3124b11644fSPeter Brune }
3134b11644fSPeter Brune 
3144b11644fSPeter Brune #undef __FUNCT__
3154b11644fSPeter Brune #define __FUNCT__ "SNESSolve_QN"
3164b11644fSPeter Brune static PetscErrorCode SNESSolve_QN(SNES snes)
3174b11644fSPeter Brune {
3184b11644fSPeter Brune   PetscErrorCode      ierr;
3199f83bee8SJed Brown   SNES_QN             *qn = (SNES_QN*) snes->data;
32015f5eeeaSPeter Brune   Vec                 X,Xold;
3210a3905e1SPeter Brune   Vec                 F,W;
32247f26062SPeter Brune   Vec                 Y,D,Dold;
323b8840d6bSPeter Brune   PetscInt            i, i_r;
324335fb975SPeter Brune   PetscReal           fnorm,xnorm,ynorm,gnorm;
3250c777b0cSPeter Brune   PetscBool           lssucceed,powell,periodic;
3261c6523dcSPeter Brune   PetscScalar         DolddotD,DolddotDold;
3270ecc9e1dSPeter Brune   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
328b7281c8aSPeter Brune   SNESConvergedReason reason;
3290ecc9e1dSPeter Brune 
3304b11644fSPeter Brune   /* basically just a regular newton's method except for the application of the jacobian */
3314b11644fSPeter Brune 
3326e111a19SKarl Rupp   PetscFunctionBegin;
3339f3a0142SPeter Brune   F    = snes->vec_func;                /* residual vector */
3343af51624SPeter Brune   Y    = snes->vec_sol_update;          /* search direction generated by J^-1D*/
3350a3905e1SPeter Brune   W    = snes->work[3];
336b8840d6bSPeter Brune   X    = snes->vec_sol;                 /* solution vector */
337335fb975SPeter Brune   Xold = snes->work[0];
3383af51624SPeter Brune 
3393af51624SPeter Brune   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
340335fb975SPeter Brune   D    = snes->work[1];
341335fb975SPeter Brune   Dold = snes->work[2];
3424b11644fSPeter Brune 
3434b11644fSPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
3444b11644fSPeter Brune 
345ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3464b11644fSPeter Brune   snes->iter = 0;
3474b11644fSPeter Brune   snes->norm = 0.;
348ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
34947f26062SPeter Brune 
350b28a06ddSPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
35147f26062SPeter Brune     ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr);
352b7281c8aSPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
353b7281c8aSPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
354b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
355b7281c8aSPeter Brune       PetscFunctionReturn(0);
356b7281c8aSPeter Brune     }
35747f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
35847f26062SPeter Brune   } else {
359e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
36015f5eeeaSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
3614b11644fSPeter Brune       if (snes->domainerror) {
3624b11644fSPeter Brune         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
3634b11644fSPeter Brune         PetscFunctionReturn(0);
3644b11644fSPeter Brune       }
3651aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
366c1c75074SPeter Brune 
36747f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
368189a9710SBarry Smith     if (PetscIsInfOrNanReal(fnorm)) {
369189a9710SBarry Smith       snes->reason = SNES_DIVERGED_FNORM_NAN;
370189a9710SBarry Smith       PetscFunctionReturn(0);
371189a9710SBarry Smith     }
37247f26062SPeter Brune   }
373b28a06ddSPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
37447f26062SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr);
375b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
376b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
377b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
378b7281c8aSPeter Brune         PetscFunctionReturn(0);
379b7281c8aSPeter Brune       }
38047f26062SPeter Brune   } else {
38147f26062SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
38247f26062SPeter Brune   }
383b28a06ddSPeter Brune 
384ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3854b11644fSPeter Brune   snes->norm = fnorm;
386ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
387a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
3884b11644fSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
3894b11644fSPeter Brune 
3904b11644fSPeter Brune   /* test convergence */
3914b11644fSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
3924b11644fSPeter Brune   if (snes->reason) PetscFunctionReturn(0);
39370d3b23bSPeter Brune 
3943cf07b75SPeter Brune   if (snes->pc && snes->pcside == PC_RIGHT) {
3953cf07b75SPeter Brune     ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
3963cf07b75SPeter Brune     ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
3973cf07b75SPeter Brune     ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
398ddd40ce5SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
399ddd40ce5SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
400ddd40ce5SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
401ddd40ce5SPeter Brune       PetscFunctionReturn(0);
402ddd40ce5SPeter Brune     }
403ddd40ce5SPeter Brune     ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
4043cf07b75SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
4053cf07b75SPeter Brune   }
4063cf07b75SPeter Brune 
407f8e15203SPeter Brune   /* scale the initial update */
4080c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
4090ecc9e1dSPeter Brune     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
4108cba9625SJed Brown     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
4110ecc9e1dSPeter Brune   }
4120ecc9e1dSPeter Brune 
4135ba6227bSPeter Brune   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
4140a3905e1SPeter Brune     if (qn->scale_type == SNES_QN_SCALE_SHANNO && i_r > 0) {
4150a3905e1SPeter Brune       PetscScalar ff,xf;
4160a3905e1SPeter Brune       ierr = VecCopy(Dold,Y);CHKERRQ(ierr);
4170a3905e1SPeter Brune       ierr = VecCopy(Xold,W);CHKERRQ(ierr);
4180a3905e1SPeter Brune       ierr = VecAXPY(Y,-1.0,D);CHKERRQ(ierr);
4190a3905e1SPeter Brune       ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr);
4200a3905e1SPeter Brune       ierr = VecDotBegin(Y,Y,&ff);CHKERRQ(ierr);
4210a3905e1SPeter Brune       ierr = VecDotBegin(W,Y,&xf);CHKERRQ(ierr);
4220a3905e1SPeter Brune       ierr = VecDotEnd(Y,Y,&ff);CHKERRQ(ierr);
4230a3905e1SPeter Brune       ierr = VecDotEnd(W,Y,&xf);CHKERRQ(ierr);
4240a3905e1SPeter Brune       qn->scaling = PetscRealPart(xf)/PetscRealPart(ff);
4250a3905e1SPeter Brune     }
426b8840d6bSPeter Brune     switch (qn->type) {
427b8840d6bSPeter Brune     case SNES_QN_BADBROYDEN:
428b8840d6bSPeter Brune       ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
429b8840d6bSPeter Brune       break;
430b8840d6bSPeter Brune     case SNES_QN_BROYDEN:
4315051edb1SPeter Brune       ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D);CHKERRQ(ierr);
432b8840d6bSPeter Brune       break;
433b8840d6bSPeter Brune     case SNES_QN_LBFGS:
434b8840d6bSPeter Brune       SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
435b8840d6bSPeter Brune       break;
436b8840d6bSPeter Brune     }
43770d3b23bSPeter Brune     /* line search for lambda */
43870d3b23bSPeter Brune     ynorm = 1; gnorm = fnorm;
4390a3905e1SPeter Brune     ierr  = VecCopy(D, Dold);CHKERRQ(ierr);
44015f5eeeaSPeter Brune     ierr  = VecCopy(X, Xold);CHKERRQ(ierr);
441f1c6b773SPeter Brune     ierr  = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr);
4429f3a0142SPeter Brune     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
4439f3a0142SPeter Brune     if (snes->domainerror) {
4449f3a0142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
4459f3a0142SPeter Brune       PetscFunctionReturn(0);
4469f3a0142SPeter Brune     }
447f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
4489f3a0142SPeter Brune     if (!lssucceed) {
4499f3a0142SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
4509f3a0142SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
4519f3a0142SPeter Brune         break;
4529f3a0142SPeter Brune       }
4539f3a0142SPeter Brune     }
454f1c6b773SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
4550c777b0cSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
45605ee83feSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr);
4570ecc9e1dSPeter Brune     }
4583af51624SPeter Brune 
45988d374b2SPeter Brune     /* convergence monitoring */
460b21d5a53SPeter 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);
461b21d5a53SPeter Brune 
462b28a06ddSPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
463b28a06ddSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
464b28a06ddSPeter Brune       ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
465b28a06ddSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
466ddd40ce5SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
467ddd40ce5SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
468ddd40ce5SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
469ddd40ce5SPeter Brune         PetscFunctionReturn(0);
470ddd40ce5SPeter Brune       }
471ddd40ce5SPeter Brune       ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
472b28a06ddSPeter Brune     }
473b28a06ddSPeter Brune 
474360c497dSPeter Brune     ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr);
475360c497dSPeter Brune     ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr);
476360c497dSPeter Brune 
477a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
4788409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
4794b11644fSPeter Brune     /* set parameter for default relative tolerance convergence test */
480d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
4814b11644fSPeter Brune     if (snes->reason) PetscFunctionReturn(0);
482b28a06ddSPeter Brune     if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
48347f26062SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr);
484b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
485b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
486b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
487b7281c8aSPeter Brune         PetscFunctionReturn(0);
488b7281c8aSPeter Brune       }
48988d374b2SPeter Brune     } else {
49088d374b2SPeter Brune       ierr = VecCopy(F, D);CHKERRQ(ierr);
49188d374b2SPeter Brune     }
4920c777b0cSPeter Brune     powell = PETSC_FALSE;
4930c777b0cSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_POWELL) {
4946bf1b2e5SPeter Brune       /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */
495*23c918e7SPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
496*23c918e7SPeter Brune         ierr = MatMult(snes->jacobian_pre,Dold,W);CHKERRQ(ierr);
497*23c918e7SPeter Brune       } else {
498*23c918e7SPeter Brune         ierr = VecCopy(Dold,W);CHKERRQ(ierr);
499*23c918e7SPeter Brune       }
500*23c918e7SPeter Brune       ierr = VecDotBegin(W, Dold, &DolddotDold);CHKERRQ(ierr);
501*23c918e7SPeter Brune       ierr = VecDotBegin(W, D, &DolddotD);CHKERRQ(ierr);
502*23c918e7SPeter Brune       ierr = VecDotEnd(W, Dold, &DolddotDold);CHKERRQ(ierr);
503*23c918e7SPeter Brune       ierr = VecDotEnd(W, D, &DolddotD);CHKERRQ(ierr);
5040c777b0cSPeter Brune       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
5050c777b0cSPeter Brune     }
5060c777b0cSPeter Brune     periodic = PETSC_FALSE;
507b8840d6bSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
508b8840d6bSPeter Brune       if (i_r>qn->m-1) periodic = PETSC_TRUE;
5090c777b0cSPeter Brune     }
5100c777b0cSPeter Brune     /* restart if either powell or periodic restart is satisfied. */
5110c777b0cSPeter Brune     if (powell || periodic) {
5125ba6227bSPeter Brune       if (qn->monitor) {
5135ba6227bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
514516fe3c3SPeter 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);
5155ba6227bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
5165ba6227bSPeter Brune       }
5175ba6227bSPeter Brune       i_r = -1;
5185ba6227bSPeter Brune       /* general purpose update */
5195ba6227bSPeter Brune       if (snes->ops->update) {
5205ba6227bSPeter Brune         ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
5215ba6227bSPeter Brune       }
5220c777b0cSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5230ecc9e1dSPeter Brune         ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
5248cba9625SJed Brown         ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
5250ecc9e1dSPeter Brune       }
5260ecc9e1dSPeter Brune     }
52770d3b23bSPeter Brune     /* general purpose update */
52870d3b23bSPeter Brune     if (snes->ops->update) {
52970d3b23bSPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
53070d3b23bSPeter Brune     }
5315ba6227bSPeter Brune   }
5324b11644fSPeter Brune   if (i == snes->max_its) {
5334b11644fSPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr);
5344b11644fSPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
5354b11644fSPeter Brune   }
5364b11644fSPeter Brune   PetscFunctionReturn(0);
5374b11644fSPeter Brune }
5384b11644fSPeter Brune 
5394b11644fSPeter Brune #undef __FUNCT__
5404b11644fSPeter Brune #define __FUNCT__ "SNESSetUp_QN"
5414b11644fSPeter Brune static PetscErrorCode SNESSetUp_QN(SNES snes)
5424b11644fSPeter Brune {
5439f83bee8SJed Brown   SNES_QN        *qn = (SNES_QN*)snes->data;
5444b11644fSPeter Brune   PetscErrorCode ierr;
545335fb975SPeter Brune 
5464b11644fSPeter Brune   PetscFunctionBegin;
547b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr);
54859e7931aSPeter Brune   if (qn->type != SNES_QN_BROYDEN) ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr);
5495c7a0a03SPeter Brune   ierr = PetscMalloc4(qn->m, PetscScalar, &qn->alpha,
5508e231d97SPeter Brune                       qn->m, PetscScalar, &qn->beta,
5515c7a0a03SPeter Brune                       qn->m, PetscScalar, &qn->dXtdF,
5525c7a0a03SPeter Brune                       qn->m, PetscReal, &qn->lambda);CHKERRQ(ierr);
5538e231d97SPeter Brune 
55418aa0c0cSPeter Brune   if (qn->singlereduction) {
5558e231d97SPeter Brune     ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat,
5568e231d97SPeter Brune                         qn->m, PetscScalar, &qn->dFtdX,
5578e231d97SPeter Brune                         qn->m, PetscScalar, &qn->YtdX);CHKERRQ(ierr);
5588e231d97SPeter Brune   }
559fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr);
560335fb975SPeter Brune   /* set up the line search */
5610c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5628e231d97SPeter Brune     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
5638e231d97SPeter Brune   }
5646c67d002SPeter Brune   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;}
5654b11644fSPeter Brune   PetscFunctionReturn(0);
5664b11644fSPeter Brune }
5674b11644fSPeter Brune 
5684b11644fSPeter Brune #undef __FUNCT__
5694b11644fSPeter Brune #define __FUNCT__ "SNESReset_QN"
5704b11644fSPeter Brune static PetscErrorCode SNESReset_QN(SNES snes)
5714b11644fSPeter Brune {
5724b11644fSPeter Brune   PetscErrorCode ierr;
5739f83bee8SJed Brown   SNES_QN        *qn;
5740adebc6cSBarry Smith 
5754b11644fSPeter Brune   PetscFunctionBegin;
5764b11644fSPeter Brune   if (snes->data) {
5779f83bee8SJed Brown     qn = (SNES_QN*)snes->data;
578b8840d6bSPeter Brune     if (qn->U) {
579b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr);
5804b11644fSPeter Brune     }
581b8840d6bSPeter Brune     if (qn->V) {
582b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr);
5834b11644fSPeter Brune     }
58418aa0c0cSPeter Brune     if (qn->singlereduction) {
5858e231d97SPeter Brune       ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr);
5868e231d97SPeter Brune     }
5875c7a0a03SPeter Brune     ierr = PetscFree4(qn->alpha,qn->beta,qn->dXtdF,qn->lambda);CHKERRQ(ierr);
5884b11644fSPeter Brune   }
5894b11644fSPeter Brune   PetscFunctionReturn(0);
5904b11644fSPeter Brune }
5914b11644fSPeter Brune 
5924b11644fSPeter Brune #undef __FUNCT__
5934b11644fSPeter Brune #define __FUNCT__ "SNESDestroy_QN"
5944b11644fSPeter Brune static PetscErrorCode SNESDestroy_QN(SNES snes)
5954b11644fSPeter Brune {
5964b11644fSPeter Brune   PetscErrorCode ierr;
5976e111a19SKarl Rupp 
5984b11644fSPeter Brune   PetscFunctionBegin;
5994b11644fSPeter Brune   ierr = SNESReset_QN(snes);CHKERRQ(ierr);
6004b11644fSPeter Brune   ierr = PetscFree(snes->data);CHKERRQ(ierr);
601bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr);
6024b11644fSPeter Brune   PetscFunctionReturn(0);
6034b11644fSPeter Brune }
6044b11644fSPeter Brune 
6054b11644fSPeter Brune #undef __FUNCT__
6064b11644fSPeter Brune #define __FUNCT__ "SNESSetFromOptions_QN"
6074b11644fSPeter Brune static PetscErrorCode SNESSetFromOptions_QN(SNES snes)
6084b11644fSPeter Brune {
6094b11644fSPeter Brune 
6104b11644fSPeter Brune   PetscErrorCode    ierr;
6112150357eSBarry Smith   SNES_QN           *qn    = (SNES_QN*)snes->data;
61288f769c5SPeter Brune   PetscBool         monflg = PETSC_FALSE,flg;
613f1c6b773SPeter Brune   SNESLineSearch    linesearch;
6142150357eSBarry Smith   SNESQNRestartType rtype = qn->restart_type;
6152150357eSBarry Smith   SNESQNScaleType   stype = qn->scale_type;
6162150357eSBarry Smith 
6174b11644fSPeter Brune   PetscFunctionBegin;
6184b11644fSPeter Brune   ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr);
6190298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,NULL);CHKERRQ(ierr);
6200298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance",          "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL);CHKERRQ(ierr);
6210298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance",        "SNESQN", qn->powell_downhill, &qn->powell_downhill, NULL);CHKERRQ(ierr);
6220298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_monitor",         "Monitor for the QN methods",      "SNESQN", monflg, &monflg, NULL);CHKERRQ(ierr);
6230298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions",           "SNESQN", qn->singlereduction, &qn->singlereduction, NULL);CHKERRQ(ierr);
62488f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr);
62588f769c5SPeter Brune   if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr);
62688f769c5SPeter Brune 
62788f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr);
62888f769c5SPeter Brune   if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr);
62988f769c5SPeter Brune 
630b8840d6bSPeter Brune   ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes,
6310298fd71SBarry Smith                           (PetscEnum)qn->type,(PetscEnum*)&qn->type,NULL);CHKERRQ(ierr);
6324b11644fSPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
6339e764e56SPeter Brune   if (!snes->linesearch) {
6347601faf0SJed Brown     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
6351a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
6369e764e56SPeter Brune   }
63744f7e39eSPeter Brune   if (monflg) {
638ce94432eSBarry Smith     qn->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
63944f7e39eSPeter Brune   }
6404b11644fSPeter Brune   PetscFunctionReturn(0);
6414b11644fSPeter Brune }
6424b11644fSPeter Brune 
64392c02d66SPeter Brune 
6440c777b0cSPeter Brune #undef __FUNCT__
6450c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType"
6460c777b0cSPeter Brune /*@
6470c777b0cSPeter Brune     SNESQNSetRestartType - Sets the restart type for SNESQN.
6480c777b0cSPeter Brune 
6490c777b0cSPeter Brune     Logically Collective on SNES
6500c777b0cSPeter Brune 
6510c777b0cSPeter Brune     Input Parameters:
6520c777b0cSPeter Brune +   snes - the iterative context
6530c777b0cSPeter Brune -   rtype - restart type
6540c777b0cSPeter Brune 
6550c777b0cSPeter Brune     Options Database:
6560c777b0cSPeter Brune +   -snes_qn_restart_type<powell,periodic,none> - set the restart type
657b8840d6bSPeter Brune -   -snes_qn_restart[10] - sets the number of iterations before restart for periodic
6580c777b0cSPeter Brune 
6590c777b0cSPeter Brune     Level: intermediate
6600c777b0cSPeter Brune 
6610c777b0cSPeter Brune     SNESQNRestartTypes:
6620c777b0cSPeter Brune +   SNES_QN_RESTART_NONE - never restart
6630c777b0cSPeter Brune .   SNES_QN_RESTART_POWELL - restart based upon descent criteria
6640c777b0cSPeter Brune -   SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations
6650c777b0cSPeter Brune 
6660c777b0cSPeter Brune     Notes:
6670c777b0cSPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
6680c777b0cSPeter Brune 
6690c777b0cSPeter Brune .keywords: SNES, SNESQN, restart, type, set SNESLineSearch
6700c777b0cSPeter Brune @*/
6712150357eSBarry Smith PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
6722150357eSBarry Smith {
6730c777b0cSPeter Brune   PetscErrorCode ierr;
6746e111a19SKarl Rupp 
6750c777b0cSPeter Brune   PetscFunctionBegin;
6760c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
6770c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr);
6780c777b0cSPeter Brune   PetscFunctionReturn(0);
6790c777b0cSPeter Brune }
6800c777b0cSPeter Brune 
6810c777b0cSPeter Brune #undef __FUNCT__
6820c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType"
6830c777b0cSPeter Brune /*@
6840c777b0cSPeter Brune     SNESQNSetScaleType - Sets the scaling type for the inner inverse jacobian in SNESQN.
6850c777b0cSPeter Brune 
6860c777b0cSPeter Brune     Logically Collective on SNES
6870c777b0cSPeter Brune 
6880c777b0cSPeter Brune     Input Parameters:
6890c777b0cSPeter Brune +   snes - the iterative context
6900c777b0cSPeter Brune -   stype - scale type
6910c777b0cSPeter Brune 
6920c777b0cSPeter Brune     Options Database:
6930c777b0cSPeter Brune .   -snes_qn_scale_type<shanno,none,linesearch,jacobian>
6940c777b0cSPeter Brune 
6950c777b0cSPeter Brune     Level: intermediate
6960c777b0cSPeter Brune 
6970c777b0cSPeter Brune     SNESQNSelectTypes:
6980c777b0cSPeter Brune +   SNES_QN_SCALE_NONE - don't scale the problem
6990c777b0cSPeter Brune .   SNES_QN_SCALE_SHANNO - use shanno scaling
7000c777b0cSPeter Brune .   SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda
7010c777b0cSPeter Brune -   SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian.
7020c777b0cSPeter Brune 
7030c777b0cSPeter Brune .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch
7040c777b0cSPeter Brune @*/
7050c777b0cSPeter Brune 
7062150357eSBarry Smith PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
7072150357eSBarry Smith {
7080c777b0cSPeter Brune   PetscErrorCode ierr;
7096e111a19SKarl Rupp 
7100c777b0cSPeter Brune   PetscFunctionBegin;
7110c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
7120c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr);
7130c777b0cSPeter Brune   PetscFunctionReturn(0);
7140c777b0cSPeter Brune }
7150c777b0cSPeter Brune 
7160c777b0cSPeter Brune #undef __FUNCT__
7170c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType_QN"
7180adebc6cSBarry Smith PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
7190adebc6cSBarry Smith {
7200c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7216e111a19SKarl Rupp 
7220c777b0cSPeter Brune   PetscFunctionBegin;
7230c777b0cSPeter Brune   qn->scale_type = stype;
7240c777b0cSPeter Brune   PetscFunctionReturn(0);
7250c777b0cSPeter Brune }
7260c777b0cSPeter Brune 
7270c777b0cSPeter Brune #undef __FUNCT__
7280c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType_QN"
7290adebc6cSBarry Smith PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
7300adebc6cSBarry Smith {
7310c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7326e111a19SKarl Rupp 
7330c777b0cSPeter Brune   PetscFunctionBegin;
7340c777b0cSPeter Brune   qn->restart_type = rtype;
7350c777b0cSPeter Brune   PetscFunctionReturn(0);
7360c777b0cSPeter Brune }
7370c777b0cSPeter Brune 
7384b11644fSPeter Brune /* -------------------------------------------------------------------------- */
7394b11644fSPeter Brune /*MC
7404b11644fSPeter Brune       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
7414b11644fSPeter Brune 
7426cc8130cSPeter Brune       Options Database:
7436cc8130cSPeter Brune 
7446cc8130cSPeter Brune +     -snes_qn_m - Number of past states saved for the L-Broyden methods.
7451867fe5bSPeter Brune .     -snes_qn_powell_angle - Angle condition for restart.
7461867fe5bSPeter Brune .     -snes_qn_powell_descent - Descent condition for restart.
74772835e02SPeter Brune .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
74844f7e39eSPeter Brune -     -snes_qn_monitor - Monitors the quasi-newton jacobian.
7496cc8130cSPeter Brune 
750b8840d6bSPeter Brune       Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
751b8840d6bSPeter Brune       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
752b8840d6bSPeter Brune       updates.
7536cc8130cSPeter Brune 
7541867fe5bSPeter Brune       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
7551867fe5bSPeter Brune       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
7561867fe5bSPeter Brune       iteration as the current iteration's values when constructing the approximate jacobian.  The second, composed,
7571867fe5bSPeter Brune       perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
7581867fe5bSPeter Brune 
7596cc8130cSPeter Brune       References:
7606cc8130cSPeter Brune 
7610a8e8854SPeter Brune       Kelley, C.T., Iterative Methods for Linear and Nonlinear Equations, Chapter 8, SIAM, 1995.
7626cc8130cSPeter Brune 
7630a8e8854SPeter Brune       R. Byrd, J. Nocedal, R. Schnabel, Representations of Quasi-Newton Matrices and their use in Limited Memory Methods,
7640a8e8854SPeter Brune       Technical Report, Northwestern University, June 1992.
7650a8e8854SPeter Brune 
7660a8e8854SPeter Brune       Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker, Experiments with Quasi-Newton Methods in Solving Stiff ODE
7670a8e8854SPeter Brune       Systems, SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
768b8840d6bSPeter Brune 
7694b11644fSPeter Brune 
7704b11644fSPeter Brune       Level: beginner
7714b11644fSPeter Brune 
77204d7464bSBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR
7736cc8130cSPeter Brune 
7744b11644fSPeter Brune M*/
7754b11644fSPeter Brune #undef __FUNCT__
7764b11644fSPeter Brune #define __FUNCT__ "SNESCreate_QN"
7778cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes)
7784b11644fSPeter Brune {
7794b11644fSPeter Brune   PetscErrorCode ierr;
7809f83bee8SJed Brown   SNES_QN        *qn;
7814b11644fSPeter Brune 
7824b11644fSPeter Brune   PetscFunctionBegin;
7834b11644fSPeter Brune   snes->ops->setup          = SNESSetUp_QN;
7844b11644fSPeter Brune   snes->ops->solve          = SNESSolve_QN;
7854b11644fSPeter Brune   snes->ops->destroy        = SNESDestroy_QN;
7864b11644fSPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_QN;
7874b11644fSPeter Brune   snes->ops->view           = 0;
7884b11644fSPeter Brune   snes->ops->reset          = SNESReset_QN;
7894b11644fSPeter Brune 
79047f26062SPeter Brune   snes->pcside = PC_LEFT;
79147f26062SPeter Brune 
79242f4f86dSBarry Smith   snes->usespc  = PETSC_TRUE;
79342f4f86dSBarry Smith   snes->usesksp = PETSC_FALSE;
79442f4f86dSBarry Smith 
79588976e71SPeter Brune   if (!snes->tolerancesset) {
7960e444f03SPeter Brune     snes->max_funcs = 30000;
7970e444f03SPeter Brune     snes->max_its   = 10000;
79888976e71SPeter Brune   }
7990e444f03SPeter Brune 
8009f83bee8SJed Brown   ierr                = PetscNewLog(snes,SNES_QN,&qn);CHKERRQ(ierr);
8014b11644fSPeter Brune   snes->data          = (void*) qn;
8020ecc9e1dSPeter Brune   qn->m               = 10;
803b21d5a53SPeter Brune   qn->scaling         = 1.0;
8040298fd71SBarry Smith   qn->U               = NULL;
8050298fd71SBarry Smith   qn->V               = NULL;
8060298fd71SBarry Smith   qn->dXtdF           = NULL;
8070298fd71SBarry Smith   qn->dFtdX           = NULL;
8080298fd71SBarry Smith   qn->dXdFmat         = NULL;
8090298fd71SBarry Smith   qn->monitor         = NULL;
8101c6523dcSPeter Brune   qn->singlereduction = PETSC_TRUE;
811b8840d6bSPeter Brune   qn->powell_gamma    = 0.9999;
8120c777b0cSPeter Brune   qn->scale_type      = SNES_QN_SCALE_SHANNO;
8130c777b0cSPeter Brune   qn->restart_type    = SNES_QN_RESTART_POWELL;
814b8840d6bSPeter Brune   qn->type            = SNES_QN_LBFGS;
815ea630c6eSPeter Brune 
816bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetScaleType_C",SNESQNSetScaleType_QN);CHKERRQ(ierr);
817bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetRestartType_C",SNESQNSetRestartType_QN);CHKERRQ(ierr);
8184b11644fSPeter Brune   PetscFunctionReturn(0);
8194b11644fSPeter Brune }
820