xref: /petsc/src/snes/impls/qn/qn.c (revision 6e111a19f6677190c8cb13236301fcb65e0e3d3b)
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,
11b8840d6bSPeter Brune               SNES_QN_BADBROYDEN = 2} SNESQNType;
126bf1b2e5SPeter Brune 
134b11644fSPeter Brune typedef struct {
14b8840d6bSPeter Brune   Vec                   *U;               /* Stored past states (vary from method to method) */
15b8840d6bSPeter Brune   Vec                   *V;               /* Stored past states (vary from method to method) */
168e231d97SPeter Brune   PetscInt              m;                /* The number of kept previous steps */
178e231d97SPeter Brune   PetscScalar           *alpha, *beta;
188e231d97SPeter Brune   PetscScalar           *dXtdF, *dFtdX, *YtdX;
1918aa0c0cSPeter Brune   PetscBool             singlereduction;  /* Aggregated reduction implementation */
208e231d97SPeter Brune   PetscScalar           *dXdFmat;         /* A matrix of values for dX_i dot dF_j */
2144f7e39eSPeter Brune   PetscViewer           monitor;
226bf1b2e5SPeter Brune   PetscReal             powell_gamma;     /* Powell angle restart condition */
236bf1b2e5SPeter Brune   PetscReal             powell_downhill;  /* Powell descent restart condition */
24b21d5a53SPeter Brune   PetscReal             scaling;          /* scaling of H0 */
2588d374b2SPeter Brune 
26b8840d6bSPeter Brune   SNESQNType            type;             /* the type of quasi-newton method used */
2788f769c5SPeter Brune   SNESQNScaleType       scale_type;       /* the type of scaling used */
280c777b0cSPeter Brune   SNESQNRestartType     restart_type;     /* determine the frequency and type of restart conditions */
299f83bee8SJed Brown } SNES_QN;
304b11644fSPeter Brune 
314b11644fSPeter Brune #undef __FUNCT__
32b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_Broyden"
332150357eSBarry Smith PetscErrorCode SNESQNApply_Broyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold, Vec D, Vec Dold)
342150357eSBarry Smith {
354b11644fSPeter Brune   PetscErrorCode     ierr;
369f83bee8SJed Brown   SNES_QN            *qn = (SNES_QN*)snes->data;
37b8840d6bSPeter Brune   Vec                W = snes->work[3];
38b8840d6bSPeter Brune   Vec                *U = qn->U;
39b8840d6bSPeter Brune   Vec                *V = qn->V;
40b8840d6bSPeter Brune   KSPConvergedReason kspreason;
41b8840d6bSPeter Brune   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
42b8840d6bSPeter Brune   PetscInt           k,i,lits;
43b8840d6bSPeter Brune   PetscInt           m = qn->m;
44b8840d6bSPeter Brune   PetscScalar        gdot;
45b8840d6bSPeter Brune   PetscInt           l = m;
46b8840d6bSPeter Brune   Mat                jac,jac_pre;
472150357eSBarry Smith 
48b8840d6bSPeter Brune   PetscFunctionBegin;
49b8840d6bSPeter Brune   if (it < m) l = it;
50b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
51b8840d6bSPeter Brune     ierr = SNESGetJacobian(snes,&jac,&jac_pre,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
52b8840d6bSPeter Brune     ierr = KSPSetOperators(snes->ksp,jac,jac_pre,flg);CHKERRQ(ierr);
53b8840d6bSPeter Brune     ierr = SNES_KSPSolve(snes,snes->ksp,D,W);CHKERRQ(ierr);
54b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
55b8840d6bSPeter Brune     if (kspreason < 0) {
56b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
57b8840d6bSPeter 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);
58b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
59b8840d6bSPeter Brune         PetscFunctionReturn(0);
60b8840d6bSPeter Brune       }
61b8840d6bSPeter Brune     }
62b8840d6bSPeter Brune     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
63b8840d6bSPeter Brune     snes->linear_its += lits;
64b8840d6bSPeter Brune     ierr = VecCopy(W,Y);CHKERRQ(ierr);
65b8840d6bSPeter Brune   } else {
66b8840d6bSPeter Brune     ierr = VecCopy(D,Y);CHKERRQ(ierr);
67b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
68b8840d6bSPeter Brune   }
69b8840d6bSPeter Brune 
70b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
71b8840d6bSPeter Brune   if (it > 1) {
72b8840d6bSPeter Brune     for (i = 0; i < l-1; i++) {
73b8840d6bSPeter Brune       k = (it+i-l)%l;
74b8840d6bSPeter Brune       ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
75b8840d6bSPeter Brune       ierr = VecAXPY(Y,gdot,V[k]);CHKERRQ(ierr);
76b8840d6bSPeter Brune       if (qn->monitor) {
77b8840d6bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
78b8840d6bSPeter Brune         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
79b8840d6bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
80b8840d6bSPeter Brune       }
81b8840d6bSPeter Brune     }
82b8840d6bSPeter Brune   }
83b8840d6bSPeter Brune   if (it < m) l = it;
84b8840d6bSPeter Brune 
85b8840d6bSPeter Brune   /* set W to be the last step, post-linesearch */
86b8840d6bSPeter Brune   ierr = VecCopy(Xold,W);CHKERRQ(ierr);
87b8840d6bSPeter Brune   ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr);
88b8840d6bSPeter Brune 
89b8840d6bSPeter Brune   if (l > 0) {
90b8840d6bSPeter Brune     k = (it-1)%l;
91b8840d6bSPeter Brune     ierr = VecCopy(W,U[k]);CHKERRQ(ierr);
92b8840d6bSPeter Brune     ierr = VecAXPY(W,-1.0,Y);CHKERRQ(ierr);
93b8840d6bSPeter Brune     ierr = VecDot(U[k],W,&gdot);CHKERRQ(ierr);
94b8840d6bSPeter Brune     ierr = VecCopy(Y,V[k]);CHKERRQ(ierr);
95b8840d6bSPeter Brune     ierr = VecScale(V[k],1.0/gdot);CHKERRQ(ierr);
96b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
97b8840d6bSPeter Brune     ierr = VecAXPY(Y,gdot,V[k]);CHKERRQ(ierr);
98b8840d6bSPeter Brune     if (qn->monitor) {
99b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
100b8840d6bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "update: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
101b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
102b8840d6bSPeter Brune     }
103b8840d6bSPeter Brune   }
104b8840d6bSPeter Brune   PetscFunctionReturn(0);
105b8840d6bSPeter Brune }
106b8840d6bSPeter Brune 
107b8840d6bSPeter Brune #undef __FUNCT__
108b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_BadBroyden"
1090adebc6cSBarry Smith PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1100adebc6cSBarry Smith {
111b8840d6bSPeter Brune   PetscErrorCode     ierr;
112b8840d6bSPeter Brune   SNES_QN            *qn = (SNES_QN*)snes->data;
113b8840d6bSPeter Brune   Vec                W = snes->work[3];
114b8840d6bSPeter Brune   Vec                *U = qn->U;
115b8840d6bSPeter Brune   Vec                *T = qn->V;
116b8840d6bSPeter Brune 
117b8840d6bSPeter Brune   /* ksp thing for jacobian scaling */
118b8840d6bSPeter Brune   KSPConvergedReason kspreason;
119b8840d6bSPeter Brune   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
120b8840d6bSPeter Brune   PetscInt           k, i, lits;
121b8840d6bSPeter Brune   PetscInt           m = qn->m;
122b8840d6bSPeter Brune   PetscScalar        gdot;
123b8840d6bSPeter Brune   PetscInt           l = m;
124b8840d6bSPeter Brune   Mat                jac, jac_pre;
1250adebc6cSBarry Smith 
126b8840d6bSPeter Brune   PetscFunctionBegin;
127b8840d6bSPeter Brune   if (it < m) l = it;
128b8840d6bSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
129b8840d6bSPeter Brune   if (l > 0) {
130b8840d6bSPeter Brune     k = (it-1)%l;
131b8840d6bSPeter Brune     ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr);
132b8840d6bSPeter Brune     ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr);
133b8840d6bSPeter Brune     ierr = VecDot(U[k],U[k],&gdot);CHKERRQ(ierr);
134b8840d6bSPeter Brune     ierr = VecCopy(D,T[k]);CHKERRQ(ierr);
135b8840d6bSPeter Brune     ierr = VecScale(T[k],1.0/gdot);CHKERRQ(ierr);
136b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
137b8840d6bSPeter Brune     ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
138b8840d6bSPeter Brune     if (qn->monitor) {
139b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
140b8840d6bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "update: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
141b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
142b8840d6bSPeter Brune     }
143b8840d6bSPeter Brune   }
144b8840d6bSPeter Brune 
145b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
146b8840d6bSPeter Brune   if (it > 1) {
147b8840d6bSPeter Brune     for (i = 0; i < l-1; i++) {
148b8840d6bSPeter Brune       k = (it+i-l)%l;
149b8840d6bSPeter Brune       ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
150b8840d6bSPeter Brune       ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
151b8840d6bSPeter Brune       if (qn->monitor) {
152b8840d6bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
153b8840d6bSPeter Brune         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
154b8840d6bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
155b8840d6bSPeter Brune       }
156b8840d6bSPeter Brune     }
157b8840d6bSPeter Brune   }
158b8840d6bSPeter Brune 
159b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
160b8840d6bSPeter Brune     ierr = SNESGetJacobian(snes, &jac, &jac_pre, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
161b8840d6bSPeter Brune     ierr = KSPSetOperators(snes->ksp,jac,jac_pre,flg);CHKERRQ(ierr);
162b8840d6bSPeter Brune     ierr = SNES_KSPSolve(snes,snes->ksp,Y,W);CHKERRQ(ierr);
163b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
164b8840d6bSPeter Brune     if (kspreason < 0) {
165b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
166b8840d6bSPeter 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);
167b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
168b8840d6bSPeter Brune         PetscFunctionReturn(0);
169b8840d6bSPeter Brune       }
170b8840d6bSPeter Brune     }
171b8840d6bSPeter Brune     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
172b8840d6bSPeter Brune     snes->linear_its += lits;
173b8840d6bSPeter Brune     ierr = VecCopy(W,Y);CHKERRQ(ierr);
174b8840d6bSPeter Brune   }  else {
175b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
176b8840d6bSPeter Brune   }
177b8840d6bSPeter Brune   PetscFunctionReturn(0);
178b8840d6bSPeter Brune }
179b8840d6bSPeter Brune 
180b8840d6bSPeter Brune #undef __FUNCT__
181b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_LBFGS"
1820adebc6cSBarry Smith PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1830adebc6cSBarry Smith {
184b8840d6bSPeter Brune   PetscErrorCode     ierr;
185b8840d6bSPeter Brune   SNES_QN            *qn = (SNES_QN*)snes->data;
186b8840d6bSPeter Brune   Vec                W = snes->work[3];
187b8840d6bSPeter Brune   Vec                *dX = qn->U;
188b8840d6bSPeter Brune   Vec                *dF = qn->V;
189bd052dfeSPeter Brune   PetscScalar        *alpha    = qn->alpha;
190bd052dfeSPeter Brune   PetscScalar        *beta     = qn->beta;
1918e231d97SPeter Brune   PetscScalar        *dXtdF    = qn->dXtdF;
192b8840d6bSPeter Brune   PetscScalar        *dFtdX    = qn->dFtdX;
1938e231d97SPeter Brune   PetscScalar        *YtdX     = qn->YtdX;
194bd052dfeSPeter Brune 
1950ecc9e1dSPeter Brune   /* ksp thing for jacobian scaling */
1960ecc9e1dSPeter Brune   KSPConvergedReason kspreason;
1970ecc9e1dSPeter Brune   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
1988e231d97SPeter Brune   PetscInt           k,i,j,g,lits;
1994b11644fSPeter Brune   PetscInt           m = qn->m;
2004b11644fSPeter Brune   PetscScalar        t;
2014b11644fSPeter Brune   PetscInt           l = m;
2028e231d97SPeter Brune   Mat                jac,jac_pre;
2038e231d97SPeter Brune 
2044b11644fSPeter Brune   PetscFunctionBegin;
2055ba6227bSPeter Brune   if (it < m) l = it;
206b8840d6bSPeter Brune   if (it > 0) {
207b8840d6bSPeter Brune     k = (it - 1) % l;
208b8840d6bSPeter Brune     ierr = VecCopy(D, dF[k]);CHKERRQ(ierr);
209b8840d6bSPeter Brune     ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr);
210b8840d6bSPeter Brune     ierr = VecCopy(X, dX[k]);CHKERRQ(ierr);
211b8840d6bSPeter Brune     ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr);
21218aa0c0cSPeter Brune     if (qn->singlereduction) {
213b8840d6bSPeter Brune       ierr = VecMDot(dF[k], l, dX, dXtdF);CHKERRQ(ierr);
214b8840d6bSPeter Brune       ierr = VecMDot(dX[k], l, dF, dFtdX);CHKERRQ(ierr);
215b8840d6bSPeter Brune       for (j = 0; j < l; j++) {
216b8840d6bSPeter Brune         H(k, j) = dFtdX[j];
217b8840d6bSPeter Brune         H(j, k) = dXtdF[j];
218b8840d6bSPeter Brune       }
219b8840d6bSPeter Brune       /* copy back over to make the computation of alpha and beta easier */
220b8840d6bSPeter Brune       for (j = 0; j < l; j++) {
221b8840d6bSPeter Brune         dXtdF[j] = H(j, j);
222b8840d6bSPeter Brune       }
223b8840d6bSPeter Brune     } else {
224b8840d6bSPeter Brune       ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr);
225b8840d6bSPeter Brune     }
226b8840d6bSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_SHANNO) {
22767392de3SBarry Smith       PetscReal dFtdF;
22867392de3SBarry Smith       ierr = VecDotRealPart(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);
22967392de3SBarry Smith       qn->scaling = PetscRealPart(dXtdF[k])/dFtdF;
230b8840d6bSPeter Brune     } else if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
231b8840d6bSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr);
232b8840d6bSPeter Brune     }
233b8840d6bSPeter Brune   }
234b8840d6bSPeter Brune 
235b8840d6bSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
236b8840d6bSPeter Brune 
237b8840d6bSPeter Brune   if (qn->singlereduction) {
238b8840d6bSPeter Brune     ierr = VecMDot(Y,l,dX,YtdX);CHKERRQ(ierr);
2398e231d97SPeter Brune   }
2404b11644fSPeter Brune   /* outward recursion starting at iteration k's update and working back */
2414b11644fSPeter Brune   for (i=0;i<l;i++) {
242b21d5a53SPeter Brune     k = (it-i-1)%l;
24318aa0c0cSPeter Brune     if (qn->singlereduction) {
2448e231d97SPeter Brune       /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */
2458e231d97SPeter Brune       t = YtdX[k];
2468e231d97SPeter Brune       for (j=0;j<i;j++) {
2478e231d97SPeter Brune         g = (it-j-1)%l;
2488e231d97SPeter Brune         t += -alpha[g]*H(g, k);
2498e231d97SPeter Brune       }
2508e231d97SPeter Brune       alpha[k] = t/H(k,k);
2518e231d97SPeter Brune     } else {
2523af51624SPeter Brune       ierr = VecDot(dX[k],Y,&t);CHKERRQ(ierr);
2538e231d97SPeter Brune       alpha[k] = t/dXtdF[k];
2548e231d97SPeter Brune     }
25544f7e39eSPeter Brune     if (qn->monitor) {
2563af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
2575ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha:        %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr);
2583af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
25944f7e39eSPeter Brune     }
2606bf1b2e5SPeter Brune     ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr);
2614b11644fSPeter Brune   }
2624b11644fSPeter Brune 
2630c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
2648e231d97SPeter Brune     ierr = SNESGetJacobian(snes, &jac, &jac_pre, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
2658e231d97SPeter Brune     ierr = KSPSetOperators(snes->ksp,jac,jac_pre,flg);CHKERRQ(ierr);
266b8840d6bSPeter Brune     ierr = SNES_KSPSolve(snes,snes->ksp,Y,W);CHKERRQ(ierr);
2670ecc9e1dSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
2680ecc9e1dSPeter Brune     if (kspreason < 0) {
2690ecc9e1dSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
2700ecc9e1dSPeter 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);
2710ecc9e1dSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
2720ecc9e1dSPeter Brune         PetscFunctionReturn(0);
2730ecc9e1dSPeter Brune       }
2740ecc9e1dSPeter Brune     }
2750ecc9e1dSPeter Brune     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
2760ecc9e1dSPeter Brune     snes->linear_its += lits;
277b8840d6bSPeter Brune     ierr = VecCopy(W, Y);CHKERRQ(ierr);
2780ecc9e1dSPeter Brune   } else {
279b21d5a53SPeter Brune     ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr);
2800ecc9e1dSPeter Brune   }
28118aa0c0cSPeter Brune   if (qn->singlereduction) {
282b8840d6bSPeter Brune     ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr);
2838e231d97SPeter Brune   }
2844b11644fSPeter Brune   /* inward recursion starting at the first update and working forward */
285bd052dfeSPeter Brune   for (i = 0; i < l; i++) {
286b21d5a53SPeter Brune     k = (it + i - l) % l;
28718aa0c0cSPeter Brune     if (qn->singlereduction) {
2888e231d97SPeter Brune       t = YtdX[k];
2898e231d97SPeter Brune       for (j = 0; j < i; j++) {
2908e231d97SPeter Brune         g = (it + j - l) % l;
2918e231d97SPeter Brune         t += (alpha[g] - beta[g])*H(k, g);
2928e231d97SPeter Brune       }
2938e231d97SPeter Brune       beta[k] = t / H(k, k);
2948e231d97SPeter Brune     } else {
2956bf1b2e5SPeter Brune       ierr = VecDot(dF[k], Y, &t);CHKERRQ(ierr);
2968e231d97SPeter Brune       beta[k] = t / dXtdF[k];
2978e231d97SPeter Brune     }
29822d28d08SBarry Smith     ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr);
29944f7e39eSPeter Brune     if (qn->monitor) {
3003af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
3015ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr);
3023af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
30344f7e39eSPeter Brune     }
3044b11644fSPeter Brune   }
3054b11644fSPeter Brune   PetscFunctionReturn(0);
3064b11644fSPeter Brune }
3074b11644fSPeter Brune 
3084b11644fSPeter Brune #undef __FUNCT__
3094b11644fSPeter Brune #define __FUNCT__ "SNESSolve_QN"
3104b11644fSPeter Brune static PetscErrorCode SNESSolve_QN(SNES snes)
3114b11644fSPeter Brune {
3124b11644fSPeter Brune   PetscErrorCode      ierr;
3139f83bee8SJed Brown   SNES_QN             *qn = (SNES_QN*) snes->data;
31415f5eeeaSPeter Brune   Vec                 X,Xold;
315335fb975SPeter Brune   Vec                 F,B;
316335fb975SPeter Brune   Vec                 Y,FPC,D,Dold;
3173af51624SPeter Brune   SNESConvergedReason reason;
318b8840d6bSPeter Brune   PetscInt            i, i_r;
319335fb975SPeter Brune   PetscReal           fnorm,xnorm,ynorm,gnorm;
3200c777b0cSPeter Brune   PetscBool           lssucceed,powell,periodic;
321b8840d6bSPeter Brune   PetscScalar         DolddotD,DolddotDold,DdotD,YdotD;
3220ecc9e1dSPeter Brune   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
3230ecc9e1dSPeter Brune 
3244b11644fSPeter Brune   /* basically just a regular newton's method except for the application of the jacobian */
3254b11644fSPeter Brune 
326*6e111a19SKarl Rupp   PetscFunctionBegin;
3279f3a0142SPeter Brune   F             = snes->vec_func;       /* residual vector */
3283af51624SPeter Brune   Y             = snes->vec_sol_update; /* search direction generated by J^-1D*/
3293af51624SPeter Brune   B             = snes->vec_rhs;
330b8840d6bSPeter Brune 
331b8840d6bSPeter Brune   X             = snes->vec_sol;        /* solution vector */
332335fb975SPeter Brune   Xold          = snes->work[0];
3333af51624SPeter Brune 
3343af51624SPeter Brune   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
335335fb975SPeter Brune   D             = snes->work[1];
336335fb975SPeter Brune   Dold          = snes->work[2];
3374b11644fSPeter Brune 
3384b11644fSPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
3394b11644fSPeter Brune 
3404b11644fSPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
3414b11644fSPeter Brune   snes->iter = 0;
3424b11644fSPeter Brune   snes->norm = 0.;
3434b11644fSPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
344e4ed7901SPeter Brune   if (!snes->vec_func_init_set) {
34515f5eeeaSPeter Brune     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
3464b11644fSPeter Brune     if (snes->domainerror) {
3474b11644fSPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
3484b11644fSPeter Brune       PetscFunctionReturn(0);
3494b11644fSPeter Brune     }
350e4ed7901SPeter Brune   } else {
351e4ed7901SPeter Brune     snes->vec_func_init_set = PETSC_FALSE;
352e4ed7901SPeter Brune   }
353e4ed7901SPeter Brune 
354e4ed7901SPeter Brune   if (!snes->norm_init_set) {
35515f5eeeaSPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
3564b11644fSPeter Brune     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
357e4ed7901SPeter Brune   } else {
358e4ed7901SPeter Brune     fnorm = snes->norm_init;
359e4ed7901SPeter Brune     snes->norm_init_set = PETSC_FALSE;
360e4ed7901SPeter Brune   }
361e4ed7901SPeter Brune 
3624b11644fSPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
3634b11644fSPeter Brune   snes->norm = fnorm;
3644b11644fSPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
3654b11644fSPeter Brune   SNESLogConvHistory(snes,fnorm,0);
3664b11644fSPeter Brune   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
3674b11644fSPeter Brune 
3684b11644fSPeter Brune   /* set parameter for default relative tolerance convergence test */
3694b11644fSPeter Brune    snes->ttol = fnorm*snes->rtol;
3704b11644fSPeter Brune   /* test convergence */
3714b11644fSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
3724b11644fSPeter Brune   if (snes->reason) PetscFunctionReturn(0);
37370d3b23bSPeter Brune 
37488f769c5SPeter Brune   /* composed solve */
375c40d0f55SPeter Brune   if (snes->pc && snes->pcside == PC_RIGHT) {
376217b9c2eSPeter Brune     ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr);
377217b9c2eSPeter Brune     ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr);
37888d374b2SPeter Brune     ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
37988d374b2SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
38088d374b2SPeter Brune     if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) {
38188d374b2SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
38288d374b2SPeter Brune       PetscFunctionReturn(0);
38388d374b2SPeter Brune     }
38488d374b2SPeter Brune     ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
38588d374b2SPeter Brune     ierr = VecCopy(FPC, F);CHKERRQ(ierr);
38688d374b2SPeter Brune     ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr);
3876bf1b2e5SPeter Brune     ierr = VecCopy(F, Y);CHKERRQ(ierr);
38888d374b2SPeter Brune   } else {
38988d374b2SPeter Brune     ierr = VecCopy(F, Y);CHKERRQ(ierr);
39088d374b2SPeter Brune   }
39188d374b2SPeter Brune   ierr = VecCopy(Y, D);CHKERRQ(ierr);
3923af51624SPeter Brune 
393f8e15203SPeter Brune   /* scale the initial update */
3940c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
3950ecc9e1dSPeter Brune     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
3960ecc9e1dSPeter Brune   }
3970ecc9e1dSPeter Brune 
3985ba6227bSPeter Brune   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
399b8840d6bSPeter Brune     switch (qn->type) {
400b8840d6bSPeter Brune     case SNES_QN_BADBROYDEN:
401b8840d6bSPeter Brune       ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
402b8840d6bSPeter Brune       break;
403b8840d6bSPeter Brune     case SNES_QN_BROYDEN:
404b8840d6bSPeter Brune       ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
405b8840d6bSPeter Brune       break;
406b8840d6bSPeter Brune     case SNES_QN_LBFGS:
407b8840d6bSPeter Brune       SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
408b8840d6bSPeter Brune       break;
409b8840d6bSPeter Brune     }
41070d3b23bSPeter Brune     /* line search for lambda */
41170d3b23bSPeter Brune     ynorm = 1; gnorm = fnorm;
41288d374b2SPeter Brune     ierr = VecCopy(D, Dold);CHKERRQ(ierr);
41315f5eeeaSPeter Brune     ierr = VecCopy(X, Xold);CHKERRQ(ierr);
414f1c6b773SPeter Brune     ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr);
4159f3a0142SPeter Brune     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
4169f3a0142SPeter Brune     if (snes->domainerror) {
4179f3a0142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
4189f3a0142SPeter Brune       PetscFunctionReturn(0);
4199f3a0142SPeter Brune       }
420f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
4219f3a0142SPeter Brune     if (!lssucceed) {
4229f3a0142SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
4239f3a0142SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
4249f3a0142SPeter Brune         break;
4259f3a0142SPeter Brune       }
4269f3a0142SPeter Brune     }
427f1c6b773SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
4280c777b0cSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
42905ee83feSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr);
4300ecc9e1dSPeter Brune     }
4313af51624SPeter Brune 
43288d374b2SPeter Brune     /* convergence monitoring */
433b21d5a53SPeter 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);
434b21d5a53SPeter Brune 
435360c497dSPeter Brune     ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr);
436360c497dSPeter Brune     ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr);
437360c497dSPeter Brune 
4388409ca45SMatthew G Knepley     SNESLogConvHistory(snes,snes->norm,snes->iter);
4398409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
4404b11644fSPeter Brune     /* set parameter for default relative tolerance convergence test */
441d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
4424b11644fSPeter Brune     if (snes->reason) PetscFunctionReturn(0);
4434b11644fSPeter Brune 
444c40d0f55SPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
445217b9c2eSPeter Brune       ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr);
446217b9c2eSPeter Brune       ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr);
44788d374b2SPeter Brune       ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
44888d374b2SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
44988d374b2SPeter Brune       if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) {
45088d374b2SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
45188d374b2SPeter Brune         PetscFunctionReturn(0);
45288d374b2SPeter Brune       }
45388d374b2SPeter Brune       ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
45488d374b2SPeter Brune       ierr = VecCopy(FPC, F);CHKERRQ(ierr);
45588d374b2SPeter Brune       ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr);
45688d374b2SPeter Brune       ierr = VecCopy(F, D);CHKERRQ(ierr);
45788d374b2SPeter Brune     } else {
45888d374b2SPeter Brune       ierr = VecCopy(F, D);CHKERRQ(ierr);
45988d374b2SPeter Brune     }
46088d374b2SPeter Brune 
4610c777b0cSPeter Brune     powell = PETSC_FALSE;
4620c777b0cSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_POWELL) {
4636bf1b2e5SPeter Brune       /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */
4648e231d97SPeter Brune       ierr = VecDotBegin(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
4658e231d97SPeter Brune       ierr = VecDotBegin(Dold, D, &DolddotD);CHKERRQ(ierr);
4668e231d97SPeter Brune       ierr = VecDotBegin(D, D, &DdotD);CHKERRQ(ierr);
4678e231d97SPeter Brune       ierr = VecDotBegin(Y, D, &YdotD);CHKERRQ(ierr);
4688e231d97SPeter Brune       ierr = VecDotEnd(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
4698e231d97SPeter Brune       ierr = VecDotEnd(Dold, D, &DolddotD);CHKERRQ(ierr);
4708e231d97SPeter Brune       ierr = VecDotEnd(D, D, &DdotD);CHKERRQ(ierr);
4718e231d97SPeter Brune       ierr = VecDotEnd(Y, D, &YdotD);CHKERRQ(ierr);
4720c777b0cSPeter Brune       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
4730c777b0cSPeter Brune     }
4740c777b0cSPeter Brune     periodic = PETSC_FALSE;
475b8840d6bSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
476b8840d6bSPeter Brune       if (i_r>qn->m-1) periodic = PETSC_TRUE;
4770c777b0cSPeter Brune     }
4780c777b0cSPeter Brune     /* restart if either powell or periodic restart is satisfied. */
4790c777b0cSPeter Brune     if (powell || periodic) {
4805ba6227bSPeter Brune       if (qn->monitor) {
4815ba6227bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
482516fe3c3SPeter 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);
4835ba6227bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
4845ba6227bSPeter Brune       }
4855ba6227bSPeter Brune       i_r = -1;
4865ba6227bSPeter Brune       /* general purpose update */
4875ba6227bSPeter Brune       if (snes->ops->update) {
4885ba6227bSPeter Brune         ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
4895ba6227bSPeter Brune       }
4900c777b0cSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
4910ecc9e1dSPeter Brune         ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
4920ecc9e1dSPeter Brune       }
4930ecc9e1dSPeter Brune     }
49470d3b23bSPeter Brune     /* general purpose update */
49570d3b23bSPeter Brune     if (snes->ops->update) {
49670d3b23bSPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
49770d3b23bSPeter Brune     }
4985ba6227bSPeter Brune   }
4994b11644fSPeter Brune   if (i == snes->max_its) {
5004b11644fSPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr);
5014b11644fSPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
5024b11644fSPeter Brune   }
5034b11644fSPeter Brune   PetscFunctionReturn(0);
5044b11644fSPeter Brune }
5054b11644fSPeter Brune 
5064b11644fSPeter Brune #undef __FUNCT__
5074b11644fSPeter Brune #define __FUNCT__ "SNESSetUp_QN"
5084b11644fSPeter Brune static PetscErrorCode SNESSetUp_QN(SNES snes)
5094b11644fSPeter Brune {
5109f83bee8SJed Brown   SNES_QN        *qn = (SNES_QN*)snes->data;
5114b11644fSPeter Brune   PetscErrorCode ierr;
512335fb975SPeter Brune 
5134b11644fSPeter Brune   PetscFunctionBegin;
514b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr);
515b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr);
5168e231d97SPeter Brune   ierr = PetscMalloc3(qn->m, PetscScalar, &qn->alpha,
5178e231d97SPeter Brune                       qn->m, PetscScalar, &qn->beta,
5188e231d97SPeter Brune                       qn->m, PetscScalar, &qn->dXtdF);CHKERRQ(ierr);
5198e231d97SPeter Brune 
52018aa0c0cSPeter Brune   if (qn->singlereduction) {
5218e231d97SPeter Brune     ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat,
5228e231d97SPeter Brune                         qn->m, PetscScalar, &qn->dFtdX,
5238e231d97SPeter Brune                         qn->m, PetscScalar, &qn->YtdX);CHKERRQ(ierr);
5248e231d97SPeter Brune   }
525335fb975SPeter Brune   ierr = SNESDefaultGetWork(snes,4);CHKERRQ(ierr);
526335fb975SPeter Brune 
527335fb975SPeter Brune   /* set up the line search */
5280c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5298e231d97SPeter Brune     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
5308e231d97SPeter Brune   }
5314b11644fSPeter Brune   PetscFunctionReturn(0);
5324b11644fSPeter Brune }
5334b11644fSPeter Brune 
5344b11644fSPeter Brune #undef __FUNCT__
5354b11644fSPeter Brune #define __FUNCT__ "SNESReset_QN"
5364b11644fSPeter Brune static PetscErrorCode SNESReset_QN(SNES snes)
5374b11644fSPeter Brune {
5384b11644fSPeter Brune   PetscErrorCode ierr;
5399f83bee8SJed Brown   SNES_QN        *qn;
5400adebc6cSBarry Smith 
5414b11644fSPeter Brune   PetscFunctionBegin;
5424b11644fSPeter Brune   if (snes->data) {
5439f83bee8SJed Brown     qn = (SNES_QN*)snes->data;
544b8840d6bSPeter Brune     if (qn->U) {
545b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr);
5464b11644fSPeter Brune     }
547b8840d6bSPeter Brune     if (qn->V) {
548b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr);
5494b11644fSPeter Brune     }
55018aa0c0cSPeter Brune     if (qn->singlereduction) {
5518e231d97SPeter Brune       ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr);
5528e231d97SPeter Brune     }
5538e231d97SPeter Brune     ierr = PetscFree3(qn->alpha, qn->beta, qn->dXtdF);CHKERRQ(ierr);
5544b11644fSPeter Brune   }
5554b11644fSPeter Brune   PetscFunctionReturn(0);
5564b11644fSPeter Brune }
5574b11644fSPeter Brune 
5584b11644fSPeter Brune #undef __FUNCT__
5594b11644fSPeter Brune #define __FUNCT__ "SNESDestroy_QN"
5604b11644fSPeter Brune static PetscErrorCode SNESDestroy_QN(SNES snes)
5614b11644fSPeter Brune {
5624b11644fSPeter Brune   PetscErrorCode ierr;
563*6e111a19SKarl Rupp 
5644b11644fSPeter Brune   PetscFunctionBegin;
5654b11644fSPeter Brune   ierr = SNESReset_QN(snes);CHKERRQ(ierr);
5664b11644fSPeter Brune   ierr = PetscFree(snes->data);CHKERRQ(ierr);
5679c05af5eSJed Brown   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"","",PETSC_NULL);CHKERRQ(ierr);
5684b11644fSPeter Brune   PetscFunctionReturn(0);
5694b11644fSPeter Brune }
5704b11644fSPeter Brune 
5714b11644fSPeter Brune #undef __FUNCT__
5724b11644fSPeter Brune #define __FUNCT__ "SNESSetFromOptions_QN"
5734b11644fSPeter Brune static PetscErrorCode SNESSetFromOptions_QN(SNES snes)
5744b11644fSPeter Brune {
5754b11644fSPeter Brune 
5764b11644fSPeter Brune   PetscErrorCode    ierr;
5772150357eSBarry Smith   SNES_QN           *qn = (SNES_QN*)snes->data;
57888f769c5SPeter Brune   PetscBool         monflg = PETSC_FALSE,flg;
579f1c6b773SPeter Brune   SNESLineSearch    linesearch;
5802150357eSBarry Smith   SNESQNRestartType rtype = qn->restart_type;
5812150357eSBarry Smith   SNESQNScaleType   stype = qn->scale_type;
5822150357eSBarry Smith 
5834b11644fSPeter Brune   PetscFunctionBegin;
5844b11644fSPeter Brune   ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr);
5855b4627e8SPeter Brune   ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,PETSC_NULL);CHKERRQ(ierr);
5865b4627e8SPeter Brune   ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance",          "SNESQN", qn->powell_gamma, &qn->powell_gamma, PETSC_NULL);CHKERRQ(ierr);
5875b4627e8SPeter Brune   ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance",        "SNESQN", qn->powell_downhill, &qn->powell_downhill, PETSC_NULL);CHKERRQ(ierr);
5885b4627e8SPeter Brune   ierr = PetscOptionsBool("-snes_qn_monitor",         "Monitor for the QN methods",      "SNESQN", monflg, &monflg, PETSC_NULL);CHKERRQ(ierr);
5894d116c7dSPeter Brune   ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions",           "SNESQN", qn->singlereduction, &qn->singlereduction, PETSC_NULL);CHKERRQ(ierr);
59088f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr);
59188f769c5SPeter Brune   if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr);
59288f769c5SPeter Brune 
59388f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr);
59488f769c5SPeter Brune   if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr);
59588f769c5SPeter Brune 
596b8840d6bSPeter Brune   ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes,
597b8840d6bSPeter Brune                           (PetscEnum)qn->type,(PetscEnum*)&qn->type,PETSC_NULL);CHKERRQ(ierr);
5984b11644fSPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
5999e764e56SPeter Brune   if (!snes->linesearch) {
600f1c6b773SPeter Brune     ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
6011a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
6029e764e56SPeter Brune   }
60344f7e39eSPeter Brune   if (monflg) {
60444f7e39eSPeter Brune     qn->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
60544f7e39eSPeter Brune   }
6064b11644fSPeter Brune   PetscFunctionReturn(0);
6074b11644fSPeter Brune }
6084b11644fSPeter Brune 
60992c02d66SPeter Brune 
6100c777b0cSPeter Brune #undef __FUNCT__
6110c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType"
6120c777b0cSPeter Brune /*@
6130c777b0cSPeter Brune     SNESQNSetRestartType - Sets the restart type for SNESQN.
6140c777b0cSPeter Brune 
6150c777b0cSPeter Brune     Logically Collective on SNES
6160c777b0cSPeter Brune 
6170c777b0cSPeter Brune     Input Parameters:
6180c777b0cSPeter Brune +   snes - the iterative context
6190c777b0cSPeter Brune -   rtype - restart type
6200c777b0cSPeter Brune 
6210c777b0cSPeter Brune     Options Database:
6220c777b0cSPeter Brune +   -snes_qn_restart_type<powell,periodic,none> - set the restart type
623b8840d6bSPeter Brune -   -snes_qn_restart[10] - sets the number of iterations before restart for periodic
6240c777b0cSPeter Brune 
6250c777b0cSPeter Brune     Level: intermediate
6260c777b0cSPeter Brune 
6270c777b0cSPeter Brune     SNESQNRestartTypes:
6280c777b0cSPeter Brune +   SNES_QN_RESTART_NONE - never restart
6290c777b0cSPeter Brune .   SNES_QN_RESTART_POWELL - restart based upon descent criteria
6300c777b0cSPeter Brune -   SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations
6310c777b0cSPeter Brune 
6320c777b0cSPeter Brune     Notes:
6330c777b0cSPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
6340c777b0cSPeter Brune 
6350c777b0cSPeter Brune .keywords: SNES, SNESQN, restart, type, set SNESLineSearch
6360c777b0cSPeter Brune @*/
6372150357eSBarry Smith PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
6382150357eSBarry Smith {
6390c777b0cSPeter Brune   PetscErrorCode ierr;
640*6e111a19SKarl Rupp 
6410c777b0cSPeter Brune   PetscFunctionBegin;
6420c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
6430c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr);
6440c777b0cSPeter Brune   PetscFunctionReturn(0);
6450c777b0cSPeter Brune }
6460c777b0cSPeter Brune 
6470c777b0cSPeter Brune #undef __FUNCT__
6480c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType"
6490c777b0cSPeter Brune /*@
6500c777b0cSPeter Brune     SNESQNSetScaleType - Sets the scaling type for the inner inverse jacobian in SNESQN.
6510c777b0cSPeter Brune 
6520c777b0cSPeter Brune     Logically Collective on SNES
6530c777b0cSPeter Brune 
6540c777b0cSPeter Brune     Input Parameters:
6550c777b0cSPeter Brune +   snes - the iterative context
6560c777b0cSPeter Brune -   stype - scale type
6570c777b0cSPeter Brune 
6580c777b0cSPeter Brune     Options Database:
6590c777b0cSPeter Brune .   -snes_qn_scale_type<shanno,none,linesearch,jacobian>
6600c777b0cSPeter Brune 
6610c777b0cSPeter Brune     Level: intermediate
6620c777b0cSPeter Brune 
6630c777b0cSPeter Brune     SNESQNSelectTypes:
6640c777b0cSPeter Brune +   SNES_QN_SCALE_NONE - don't scale the problem
6650c777b0cSPeter Brune .   SNES_QN_SCALE_SHANNO - use shanno scaling
6660c777b0cSPeter Brune .   SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda
6670c777b0cSPeter Brune -   SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian.
6680c777b0cSPeter Brune 
6690c777b0cSPeter Brune .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch
6700c777b0cSPeter Brune @*/
6710c777b0cSPeter Brune 
6722150357eSBarry Smith PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
6732150357eSBarry Smith {
6740c777b0cSPeter Brune   PetscErrorCode ierr;
675*6e111a19SKarl Rupp 
6760c777b0cSPeter Brune   PetscFunctionBegin;
6770c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
6780c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr);
6790c777b0cSPeter Brune   PetscFunctionReturn(0);
6800c777b0cSPeter Brune }
6810c777b0cSPeter Brune 
6820c777b0cSPeter Brune EXTERN_C_BEGIN
6830c777b0cSPeter Brune #undef __FUNCT__
6840c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType_QN"
6850adebc6cSBarry Smith PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
6860adebc6cSBarry Smith {
6870c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN *)snes->data;
688*6e111a19SKarl Rupp 
6890c777b0cSPeter Brune   PetscFunctionBegin;
6900c777b0cSPeter Brune   qn->scale_type = stype;
6910c777b0cSPeter Brune   PetscFunctionReturn(0);
6920c777b0cSPeter Brune }
6930c777b0cSPeter Brune 
6940c777b0cSPeter Brune #undef __FUNCT__
6950c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType_QN"
6960adebc6cSBarry Smith PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
6970adebc6cSBarry Smith {
6980c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN *)snes->data;
699*6e111a19SKarl Rupp 
7000c777b0cSPeter Brune   PetscFunctionBegin;
7010c777b0cSPeter Brune   qn->restart_type = rtype;
7020c777b0cSPeter Brune   PetscFunctionReturn(0);
7030c777b0cSPeter Brune }
7040c777b0cSPeter Brune EXTERN_C_END
7050c777b0cSPeter Brune 
7064b11644fSPeter Brune /* -------------------------------------------------------------------------- */
7074b11644fSPeter Brune /*MC
7084b11644fSPeter Brune       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
7094b11644fSPeter Brune 
7106cc8130cSPeter Brune       Options Database:
7116cc8130cSPeter Brune 
7126cc8130cSPeter Brune +     -snes_qn_m - Number of past states saved for the L-Broyden methods.
7131867fe5bSPeter Brune .     -snes_qn_powell_angle - Angle condition for restart.
7141867fe5bSPeter Brune .     -snes_qn_powell_descent - Descent condition for restart.
71572835e02SPeter Brune .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
71644f7e39eSPeter Brune -     -snes_qn_monitor - Monitors the quasi-newton jacobian.
7176cc8130cSPeter Brune 
718b8840d6bSPeter Brune       Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
719b8840d6bSPeter Brune       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
720b8840d6bSPeter Brune       updates.
7216cc8130cSPeter Brune 
7221867fe5bSPeter Brune       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
7231867fe5bSPeter Brune       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
7241867fe5bSPeter Brune       iteration as the current iteration's values when constructing the approximate jacobian.  The second, composed,
7251867fe5bSPeter Brune       perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
7261867fe5bSPeter Brune 
7276cc8130cSPeter Brune       References:
7286cc8130cSPeter Brune 
7296cc8130cSPeter Brune       L-Broyden Methods: a generalization of the L-BFGS method to the limited memory Broyden family, M. B. Reed,
7306cc8130cSPeter Brune       International Journal of Computer Mathematics, vol. 86, 2009.
7316cc8130cSPeter Brune 
732b8840d6bSPeter Brune       Experiments with Quasi-Newton Methods in Solving Stiff ODE Systems, Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker
733b8840d6bSPeter Brune       SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
734b8840d6bSPeter Brune 
7354b11644fSPeter Brune 
7364b11644fSPeter Brune       Level: beginner
7374b11644fSPeter Brune 
73804d7464bSBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR
7396cc8130cSPeter Brune 
7404b11644fSPeter Brune M*/
7414b11644fSPeter Brune EXTERN_C_BEGIN
7424b11644fSPeter Brune #undef __FUNCT__
7434b11644fSPeter Brune #define __FUNCT__ "SNESCreate_QN"
7444b11644fSPeter Brune PetscErrorCode  SNESCreate_QN(SNES snes)
7454b11644fSPeter Brune {
7464b11644fSPeter Brune   PetscErrorCode ierr;
7479f83bee8SJed Brown   SNES_QN        *qn;
7484b11644fSPeter Brune 
7494b11644fSPeter Brune   PetscFunctionBegin;
7504b11644fSPeter Brune   snes->ops->setup           = SNESSetUp_QN;
7514b11644fSPeter Brune   snes->ops->solve           = SNESSolve_QN;
7524b11644fSPeter Brune   snes->ops->destroy         = SNESDestroy_QN;
7534b11644fSPeter Brune   snes->ops->setfromoptions  = SNESSetFromOptions_QN;
7544b11644fSPeter Brune   snes->ops->view            = 0;
7554b11644fSPeter Brune   snes->ops->reset           = SNESReset_QN;
7564b11644fSPeter Brune 
75742f4f86dSBarry Smith   snes->usespc          = PETSC_TRUE;
75842f4f86dSBarry Smith   snes->usesksp         = PETSC_FALSE;
75942f4f86dSBarry Smith 
76088976e71SPeter Brune   if (!snes->tolerancesset) {
7610e444f03SPeter Brune     snes->max_funcs = 30000;
7620e444f03SPeter Brune     snes->max_its   = 10000;
76388976e71SPeter Brune   }
7640e444f03SPeter Brune 
7659f83bee8SJed Brown   ierr = PetscNewLog(snes,SNES_QN,&qn);CHKERRQ(ierr);
7664b11644fSPeter Brune   snes->data = (void *) qn;
7670ecc9e1dSPeter Brune   qn->m               = 10;
768b21d5a53SPeter Brune   qn->scaling         = 1.0;
769b8840d6bSPeter Brune   qn->U               = PETSC_NULL;
770b8840d6bSPeter Brune   qn->V               = PETSC_NULL;
7718e231d97SPeter Brune   qn->dXtdF           = PETSC_NULL;
7728e231d97SPeter Brune   qn->dFtdX           = PETSC_NULL;
7738e231d97SPeter Brune   qn->dXdFmat         = PETSC_NULL;
77444f7e39eSPeter Brune   qn->monitor         = PETSC_NULL;
77518aa0c0cSPeter Brune   qn->singlereduction = PETSC_FALSE;
776b8840d6bSPeter Brune   qn->powell_gamma    = 0.9999;
7770c777b0cSPeter Brune   qn->scale_type      = SNES_QN_SCALE_SHANNO;
7780c777b0cSPeter Brune   qn->restart_type    = SNES_QN_RESTART_POWELL;
779b8840d6bSPeter Brune   qn->type            = SNES_QN_LBFGS;
780ea630c6eSPeter Brune 
78188f769c5SPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESQNSetScaleType_C","SNESQNSetScaleType_QN",SNESQNSetScaleType_QN);CHKERRQ(ierr);
78288f769c5SPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESQNSetRestartType_C","SNESQNSetRestartType_QN",SNESQNSetRestartType_QN);CHKERRQ(ierr);
7834b11644fSPeter Brune   PetscFunctionReturn(0);
7844b11644fSPeter Brune }
7858e231d97SPeter Brune 
7864b11644fSPeter Brune EXTERN_C_END
787