xref: /petsc/src/snes/impls/qn/qn.c (revision c1c75074e128c85b53ed5ce1f9b329b0e4d789b9)
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 */
188e231d97SPeter Brune   PetscScalar       *alpha, *beta;
198e231d97SPeter Brune   PetscScalar       *dXtdF, *dFtdX, *YtdX;
2018aa0c0cSPeter Brune   PetscBool         singlereduction;      /* Aggregated reduction implementation */
218e231d97SPeter Brune   PetscScalar       *dXdFmat;             /* A matrix of values for dX_i dot dF_j */
2244f7e39eSPeter Brune   PetscViewer       monitor;
236bf1b2e5SPeter Brune   PetscReal         powell_gamma;         /* Powell angle restart condition */
246bf1b2e5SPeter Brune   PetscReal         powell_downhill;      /* Powell descent restart condition */
25b21d5a53SPeter Brune   PetscReal         scaling;              /* scaling of H0 */
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   PetscInt           k,i,lits;
42b8840d6bSPeter Brune   PetscInt           m = qn->m;
43b8840d6bSPeter Brune   PetscScalar        gdot;
44b8840d6bSPeter Brune   PetscInt           l = m;
452150357eSBarry Smith 
46b8840d6bSPeter Brune   PetscFunctionBegin;
47b8840d6bSPeter Brune   if (it < m) l = it;
48b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
49d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,D,W);CHKERRQ(ierr);
50b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
51b8840d6bSPeter Brune     if (kspreason < 0) {
52b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
53b8840d6bSPeter 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);
54b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
55b8840d6bSPeter Brune         PetscFunctionReturn(0);
56b8840d6bSPeter Brune       }
57b8840d6bSPeter Brune     }
58b8840d6bSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
59b8840d6bSPeter Brune     snes->linear_its += lits;
60b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
61b8840d6bSPeter Brune   } else {
62b8840d6bSPeter Brune     ierr = VecCopy(D,Y);CHKERRQ(ierr);
63b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
64b8840d6bSPeter Brune   }
65b8840d6bSPeter Brune 
66b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
67b8840d6bSPeter Brune   if (it > 1) {
68b8840d6bSPeter Brune     for (i = 0; i < l-1; i++) {
69b8840d6bSPeter Brune       k    = (it+i-l)%l;
70b8840d6bSPeter Brune       ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
71b8840d6bSPeter Brune       ierr = VecAXPY(Y,gdot,V[k]);CHKERRQ(ierr);
72b8840d6bSPeter Brune       if (qn->monitor) {
73b8840d6bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
74b8840d6bSPeter Brune         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
75b8840d6bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
76b8840d6bSPeter Brune       }
77b8840d6bSPeter Brune     }
78b8840d6bSPeter Brune   }
79b8840d6bSPeter Brune   if (it < m) l = it;
80b8840d6bSPeter Brune 
81b8840d6bSPeter Brune   /* set W to be the last step, post-linesearch */
82b8840d6bSPeter Brune   ierr = VecCopy(Xold,W);CHKERRQ(ierr);
83b8840d6bSPeter Brune   ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr);
84b8840d6bSPeter Brune 
85b8840d6bSPeter Brune   if (l > 0) {
86b8840d6bSPeter Brune     k    = (it-1)%l;
87b8840d6bSPeter Brune     ierr = VecCopy(W,U[k]);CHKERRQ(ierr);
88b8840d6bSPeter Brune     ierr = VecAXPY(W,-1.0,Y);CHKERRQ(ierr);
89b8840d6bSPeter Brune     ierr = VecDot(U[k],W,&gdot);CHKERRQ(ierr);
90b8840d6bSPeter Brune     ierr = VecCopy(Y,V[k]);CHKERRQ(ierr);
91b8840d6bSPeter Brune     ierr = VecScale(V[k],1.0/gdot);CHKERRQ(ierr);
92b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
93b8840d6bSPeter Brune     ierr = VecAXPY(Y,gdot,V[k]);CHKERRQ(ierr);
94b8840d6bSPeter Brune     if (qn->monitor) {
95b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
96b8840d6bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "update: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
97b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
98b8840d6bSPeter Brune     }
99b8840d6bSPeter Brune   }
100b8840d6bSPeter Brune   PetscFunctionReturn(0);
101b8840d6bSPeter Brune }
102b8840d6bSPeter Brune 
103b8840d6bSPeter Brune #undef __FUNCT__
104b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_BadBroyden"
1050adebc6cSBarry Smith PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1060adebc6cSBarry Smith {
107b8840d6bSPeter Brune   PetscErrorCode ierr;
108b8840d6bSPeter Brune   SNES_QN        *qn = (SNES_QN*)snes->data;
109b8840d6bSPeter Brune   Vec            W   = snes->work[3];
110b8840d6bSPeter Brune   Vec            *U  = qn->U;
111b8840d6bSPeter Brune   Vec            *T  = qn->V;
112b8840d6bSPeter Brune 
113b8840d6bSPeter Brune   /* ksp thing for jacobian scaling */
114b8840d6bSPeter Brune   KSPConvergedReason kspreason;
115b8840d6bSPeter Brune   PetscInt           k, i, lits;
116b8840d6bSPeter Brune   PetscInt           m = qn->m;
117b8840d6bSPeter Brune   PetscScalar        gdot;
118b8840d6bSPeter Brune   PetscInt           l = m;
1190adebc6cSBarry Smith 
120b8840d6bSPeter Brune   PetscFunctionBegin;
121b8840d6bSPeter Brune   if (it < m) l = it;
122b8840d6bSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
123b8840d6bSPeter Brune   if (l > 0) {
124b8840d6bSPeter Brune     k    = (it-1)%l;
125b8840d6bSPeter Brune     ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr);
126b8840d6bSPeter Brune     ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr);
127b8840d6bSPeter Brune     ierr = VecDot(U[k],U[k],&gdot);CHKERRQ(ierr);
128b8840d6bSPeter Brune     ierr = VecCopy(D,T[k]);CHKERRQ(ierr);
129b8840d6bSPeter Brune     ierr = VecScale(T[k],1.0/gdot);CHKERRQ(ierr);
130b8840d6bSPeter Brune     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
131b8840d6bSPeter Brune     ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
132b8840d6bSPeter Brune     if (qn->monitor) {
133b8840d6bSPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
134b8840d6bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "update: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
135b8840d6bSPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
136b8840d6bSPeter Brune     }
137b8840d6bSPeter Brune   }
138b8840d6bSPeter Brune 
139b8840d6bSPeter Brune   /* inward recursion starting at the first update and working forward */
140b8840d6bSPeter Brune   if (it > 1) {
141b8840d6bSPeter Brune     for (i = 0; i < l-1; i++) {
142b8840d6bSPeter Brune       k    = (it+i-l)%l;
143b8840d6bSPeter Brune       ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
144b8840d6bSPeter Brune       ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
145b8840d6bSPeter Brune       if (qn->monitor) {
146b8840d6bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
147b8840d6bSPeter Brune         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
148b8840d6bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
149b8840d6bSPeter Brune       }
150b8840d6bSPeter Brune     }
151b8840d6bSPeter Brune   }
152b8840d6bSPeter Brune 
153b8840d6bSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
154d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
155b8840d6bSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
156b8840d6bSPeter Brune     if (kspreason < 0) {
157b8840d6bSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
158b8840d6bSPeter 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);
159b8840d6bSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
160b8840d6bSPeter Brune         PetscFunctionReturn(0);
161b8840d6bSPeter Brune       }
162b8840d6bSPeter Brune     }
163b8840d6bSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
164b8840d6bSPeter Brune     snes->linear_its += lits;
165b8840d6bSPeter Brune     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
166b8840d6bSPeter Brune   } else {
167b8840d6bSPeter Brune     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
168b8840d6bSPeter Brune   }
169b8840d6bSPeter Brune   PetscFunctionReturn(0);
170b8840d6bSPeter Brune }
171b8840d6bSPeter Brune 
172b8840d6bSPeter Brune #undef __FUNCT__
173b8840d6bSPeter Brune #define __FUNCT__ "SNESQNApply_LBFGS"
1740adebc6cSBarry Smith PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
1750adebc6cSBarry Smith {
176b8840d6bSPeter Brune   PetscErrorCode ierr;
177b8840d6bSPeter Brune   SNES_QN        *qn    = (SNES_QN*)snes->data;
178b8840d6bSPeter Brune   Vec            W      = snes->work[3];
179b8840d6bSPeter Brune   Vec            *dX    = qn->U;
180b8840d6bSPeter Brune   Vec            *dF    = qn->V;
181bd052dfeSPeter Brune   PetscScalar    *alpha = qn->alpha;
182bd052dfeSPeter Brune   PetscScalar    *beta  = qn->beta;
1838e231d97SPeter Brune   PetscScalar    *dXtdF = qn->dXtdF;
184b8840d6bSPeter Brune   PetscScalar    *dFtdX = qn->dFtdX;
1858e231d97SPeter Brune   PetscScalar    *YtdX  = qn->YtdX;
186bd052dfeSPeter Brune 
1870ecc9e1dSPeter Brune   /* ksp thing for jacobian scaling */
1880ecc9e1dSPeter Brune   KSPConvergedReason kspreason;
1898e231d97SPeter Brune   PetscInt           k,i,j,g,lits;
1904b11644fSPeter Brune   PetscInt           m = qn->m;
1914b11644fSPeter Brune   PetscScalar        t;
1924b11644fSPeter Brune   PetscInt           l = m;
1938e231d97SPeter Brune 
1944b11644fSPeter Brune   PetscFunctionBegin;
1955ba6227bSPeter Brune   if (it < m) l = it;
1961c6523dcSPeter Brune   ierr = VecCopy(D,Y);CHKERRQ(ierr);
197b8840d6bSPeter Brune   if (it > 0) {
198b8840d6bSPeter Brune     k    = (it - 1) % l;
199b8840d6bSPeter Brune     ierr = VecCopy(D,dF[k]);CHKERRQ(ierr);
200b8840d6bSPeter Brune     ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr);
201b8840d6bSPeter Brune     ierr = VecCopy(X, dX[k]);CHKERRQ(ierr);
202b8840d6bSPeter Brune     ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr);
20318aa0c0cSPeter Brune     if (qn->singlereduction) {
20423d44fbcSPeter Brune       PetscScalar dFtdF;
2051c6523dcSPeter Brune       ierr = VecMDotBegin(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
2061c6523dcSPeter Brune       ierr = VecMDotBegin(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
2071c6523dcSPeter Brune       ierr = VecMDotBegin(Y,l,dX,YtdX);CHKERRQ(ierr);
20823d44fbcSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {ierr = VecDotBegin(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);}
2091c6523dcSPeter Brune       ierr = VecMDotEnd(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
2101c6523dcSPeter Brune       ierr = VecMDotEnd(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
2111c6523dcSPeter Brune       ierr = VecMDotEnd(Y,l,dX,YtdX);CHKERRQ(ierr);
21223d44fbcSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {
21323d44fbcSPeter Brune         ierr = VecDotEnd(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);
21423d44fbcSPeter Brune         qn->scaling = PetscRealPart(dXtdF[k]) / PetscRealPart(dFtdF);
21523d44fbcSPeter Brune       }
216b8840d6bSPeter Brune       for (j = 0; j < l; j++) {
217b8840d6bSPeter Brune         H(k, j) = dFtdX[j];
218b8840d6bSPeter Brune         H(j, k) = dXtdF[j];
219b8840d6bSPeter Brune       }
220b8840d6bSPeter Brune       /* copy back over to make the computation of alpha and beta easier */
2211aa26658SKarl Rupp       for (j = 0; j < l; j++) dXtdF[j] = H(j, j);
222b8840d6bSPeter Brune     } else {
223b8840d6bSPeter Brune       ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr);
224b8840d6bSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_SHANNO) {
22567392de3SBarry Smith         PetscReal dFtdF;
22667392de3SBarry Smith         ierr        = VecDotRealPart(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);
22767392de3SBarry Smith         qn->scaling = PetscRealPart(dXtdF[k])/dFtdF;
22823d44fbcSPeter Brune       }
22923d44fbcSPeter Brune     }
23023d44fbcSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
231b8840d6bSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr);
232b8840d6bSPeter Brune     }
233b8840d6bSPeter Brune   }
234b8840d6bSPeter Brune 
2354b11644fSPeter Brune   /* outward recursion starting at iteration k's update and working back */
2364b11644fSPeter Brune   for (i=0; i<l; i++) {
237b21d5a53SPeter Brune     k = (it-i-1)%l;
23818aa0c0cSPeter Brune     if (qn->singlereduction) {
2398e231d97SPeter Brune       /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */
2408e231d97SPeter Brune       t = YtdX[k];
2418e231d97SPeter Brune       for (j=0; j<i; j++) {
2428e231d97SPeter Brune         g  = (it-j-1)%l;
243b3cfccb2SPeter Brune         t -= alpha[g]*H(k, g);
2448e231d97SPeter Brune       }
2458e231d97SPeter Brune       alpha[k] = t/H(k,k);
2468e231d97SPeter Brune     } else {
2473af51624SPeter Brune       ierr     = VecDot(dX[k],Y,&t);CHKERRQ(ierr);
2488e231d97SPeter Brune       alpha[k] = t/dXtdF[k];
2498e231d97SPeter Brune     }
25044f7e39eSPeter Brune     if (qn->monitor) {
2513af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
2525ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha:        %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr);
2533af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
25444f7e39eSPeter Brune     }
2556bf1b2e5SPeter Brune     ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr);
2564b11644fSPeter Brune   }
2574b11644fSPeter Brune 
2580c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
259d4211eb9SBarry Smith     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
2600ecc9e1dSPeter Brune     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
2610ecc9e1dSPeter Brune     if (kspreason < 0) {
2620ecc9e1dSPeter Brune       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
2630ecc9e1dSPeter 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);
2640ecc9e1dSPeter Brune         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
2650ecc9e1dSPeter Brune         PetscFunctionReturn(0);
2660ecc9e1dSPeter Brune       }
2670ecc9e1dSPeter Brune     }
2680ecc9e1dSPeter Brune     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
2690ecc9e1dSPeter Brune     snes->linear_its += lits;
270b8840d6bSPeter Brune     ierr              = VecCopy(W, Y);CHKERRQ(ierr);
2710ecc9e1dSPeter Brune   } else {
272b21d5a53SPeter Brune     ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr);
2730ecc9e1dSPeter Brune   }
27418aa0c0cSPeter Brune   if (qn->singlereduction) {
275b8840d6bSPeter Brune     ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr);
2768e231d97SPeter Brune   }
2774b11644fSPeter Brune   /* inward recursion starting at the first update and working forward */
278bd052dfeSPeter Brune   for (i = 0; i < l; i++) {
279b21d5a53SPeter Brune     k = (it + i - l) % l;
28018aa0c0cSPeter Brune     if (qn->singlereduction) {
2818e231d97SPeter Brune       t = YtdX[k];
2828e231d97SPeter Brune       for (j = 0; j < i; j++) {
2838e231d97SPeter Brune         g  = (it + j - l) % l;
284b3cfccb2SPeter Brune         t += (alpha[g] - beta[g])*H(g, k);
2858e231d97SPeter Brune       }
2868e231d97SPeter Brune       beta[k] = t / H(k, k);
2878e231d97SPeter Brune     } else {
2886bf1b2e5SPeter Brune       ierr    = VecDot(dF[k], Y, &t);CHKERRQ(ierr);
2898e231d97SPeter Brune       beta[k] = t / dXtdF[k];
2908e231d97SPeter Brune     }
29122d28d08SBarry Smith     ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr);
29244f7e39eSPeter Brune     if (qn->monitor) {
2933af51624SPeter Brune       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
2945ba6227bSPeter Brune       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr);
2953af51624SPeter Brune       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
29644f7e39eSPeter Brune     }
2974b11644fSPeter Brune   }
2984b11644fSPeter Brune   PetscFunctionReturn(0);
2994b11644fSPeter Brune }
3004b11644fSPeter Brune 
3014b11644fSPeter Brune #undef __FUNCT__
3024b11644fSPeter Brune #define __FUNCT__ "SNESSolve_QN"
3034b11644fSPeter Brune static PetscErrorCode SNESSolve_QN(SNES snes)
3044b11644fSPeter Brune {
3054b11644fSPeter Brune   PetscErrorCode      ierr;
3069f83bee8SJed Brown   SNES_QN             *qn = (SNES_QN*) snes->data;
30715f5eeeaSPeter Brune   Vec                 X,Xold;
30847f26062SPeter Brune   Vec                 F;
30947f26062SPeter Brune   Vec                 Y,D,Dold;
310b8840d6bSPeter Brune   PetscInt            i, i_r;
311335fb975SPeter Brune   PetscReal           fnorm,xnorm,ynorm,gnorm;
3120c777b0cSPeter Brune   PetscBool           lssucceed,powell,periodic;
3131c6523dcSPeter Brune   PetscScalar         DolddotD,DolddotDold;
3140ecc9e1dSPeter Brune   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
315b7281c8aSPeter Brune   SNESConvergedReason reason;
3160ecc9e1dSPeter Brune 
3174b11644fSPeter Brune   /* basically just a regular newton's method except for the application of the jacobian */
3184b11644fSPeter Brune 
3196e111a19SKarl Rupp   PetscFunctionBegin;
3209f3a0142SPeter Brune   F = snes->vec_func;                   /* residual vector */
3213af51624SPeter Brune   Y = snes->vec_sol_update;             /* search direction generated by J^-1D*/
322b8840d6bSPeter Brune 
323b8840d6bSPeter Brune   X    = snes->vec_sol;                 /* solution vector */
324335fb975SPeter Brune   Xold = snes->work[0];
3253af51624SPeter Brune 
3263af51624SPeter Brune   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
327335fb975SPeter Brune   D    = snes->work[1];
328335fb975SPeter Brune   Dold = snes->work[2];
3294b11644fSPeter Brune 
3304b11644fSPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
3314b11644fSPeter Brune 
332ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3334b11644fSPeter Brune   snes->iter = 0;
3344b11644fSPeter Brune   snes->norm = 0.;
335ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
33647f26062SPeter Brune 
337b28a06ddSPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
33847f26062SPeter Brune     ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr);
339b7281c8aSPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
340b7281c8aSPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
341b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
342b7281c8aSPeter Brune       PetscFunctionReturn(0);
343b7281c8aSPeter Brune     }
34447f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
34547f26062SPeter Brune   } else {
346e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
34715f5eeeaSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
3484b11644fSPeter Brune       if (snes->domainerror) {
3494b11644fSPeter Brune         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
3504b11644fSPeter Brune         PetscFunctionReturn(0);
3514b11644fSPeter Brune       }
3521aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
353*c1c75074SPeter Brune 
35447f26062SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
355189a9710SBarry Smith     if (PetscIsInfOrNanReal(fnorm)) {
356189a9710SBarry Smith       snes->reason = SNES_DIVERGED_FNORM_NAN;
357189a9710SBarry Smith       PetscFunctionReturn(0);
358189a9710SBarry Smith     }
35947f26062SPeter Brune   }
360b28a06ddSPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
36147f26062SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr);
362b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
363b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
364b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
365b7281c8aSPeter Brune         PetscFunctionReturn(0);
366b7281c8aSPeter Brune       }
36747f26062SPeter Brune   } else {
36847f26062SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
36947f26062SPeter Brune   }
370b28a06ddSPeter Brune 
371ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
3724b11644fSPeter Brune   snes->norm = fnorm;
373ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
374a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
3754b11644fSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
3764b11644fSPeter Brune 
3774b11644fSPeter Brune   /* set parameter for default relative tolerance convergence test */
3784b11644fSPeter Brune   snes->ttol = fnorm*snes->rtol;
3794b11644fSPeter Brune   /* test convergence */
3804b11644fSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
3814b11644fSPeter Brune   if (snes->reason) PetscFunctionReturn(0);
38270d3b23bSPeter Brune 
3833cf07b75SPeter Brune   if (snes->pc && snes->pcside == PC_RIGHT) {
3843cf07b75SPeter Brune     ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
3853cf07b75SPeter Brune     ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
3863cf07b75SPeter Brune     ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
387ddd40ce5SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
388ddd40ce5SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
389ddd40ce5SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
390ddd40ce5SPeter Brune       PetscFunctionReturn(0);
391ddd40ce5SPeter Brune     }
392ddd40ce5SPeter Brune     ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
3933cf07b75SPeter Brune     ierr = VecCopy(F,D);CHKERRQ(ierr);
3943cf07b75SPeter Brune   }
3953cf07b75SPeter Brune 
396f8e15203SPeter Brune   /* scale the initial update */
3970c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
3980ecc9e1dSPeter Brune     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
3998cba9625SJed Brown     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
4000ecc9e1dSPeter Brune   }
4010ecc9e1dSPeter Brune 
4025ba6227bSPeter Brune   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
403b8840d6bSPeter Brune     switch (qn->type) {
404b8840d6bSPeter Brune     case SNES_QN_BADBROYDEN:
405b8840d6bSPeter Brune       ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
406b8840d6bSPeter Brune       break;
407b8840d6bSPeter Brune     case SNES_QN_BROYDEN:
408b8840d6bSPeter Brune       ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
409b8840d6bSPeter Brune       break;
410b8840d6bSPeter Brune     case SNES_QN_LBFGS:
411b8840d6bSPeter Brune       SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
412b8840d6bSPeter Brune       break;
413b8840d6bSPeter Brune     }
41470d3b23bSPeter Brune     /* line search for lambda */
41570d3b23bSPeter Brune     ynorm = 1; gnorm = fnorm;
41688d374b2SPeter Brune     ierr  = VecCopy(D, Dold);CHKERRQ(ierr);
41715f5eeeaSPeter Brune     ierr  = VecCopy(X, Xold);CHKERRQ(ierr);
418f1c6b773SPeter Brune     ierr  = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr);
4199f3a0142SPeter Brune     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
4209f3a0142SPeter Brune     if (snes->domainerror) {
4219f3a0142SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
4229f3a0142SPeter Brune       PetscFunctionReturn(0);
4239f3a0142SPeter Brune     }
424f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
4259f3a0142SPeter Brune     if (!lssucceed) {
4269f3a0142SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
4279f3a0142SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
4289f3a0142SPeter Brune         break;
4299f3a0142SPeter Brune       }
4309f3a0142SPeter Brune     }
431f1c6b773SPeter Brune     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
4320c777b0cSPeter Brune     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
43305ee83feSPeter Brune       ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr);
4340ecc9e1dSPeter Brune     }
4353af51624SPeter Brune 
43688d374b2SPeter Brune     /* convergence monitoring */
437b21d5a53SPeter 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);
438b21d5a53SPeter Brune 
439b28a06ddSPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
440b28a06ddSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
441b28a06ddSPeter Brune       ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
442b28a06ddSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
443ddd40ce5SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
444ddd40ce5SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
445ddd40ce5SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
446ddd40ce5SPeter Brune         PetscFunctionReturn(0);
447ddd40ce5SPeter Brune       }
448ddd40ce5SPeter Brune       ierr = SNESGetPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
449b28a06ddSPeter Brune     }
450b28a06ddSPeter Brune 
451360c497dSPeter Brune     ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr);
452360c497dSPeter Brune     ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr);
453360c497dSPeter Brune 
454a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
4558409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
4564b11644fSPeter Brune     /* set parameter for default relative tolerance convergence test */
457d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
4584b11644fSPeter Brune     if (snes->reason) PetscFunctionReturn(0);
459b28a06ddSPeter Brune     if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
46047f26062SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,D);CHKERRQ(ierr);
461b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
462b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
463b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
464b7281c8aSPeter Brune         PetscFunctionReturn(0);
465b7281c8aSPeter Brune       }
46688d374b2SPeter Brune     } else {
46788d374b2SPeter Brune       ierr = VecCopy(F, D);CHKERRQ(ierr);
46888d374b2SPeter Brune     }
46988d374b2SPeter Brune 
4700c777b0cSPeter Brune     powell = PETSC_FALSE;
4710c777b0cSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_POWELL) {
4726bf1b2e5SPeter Brune       /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */
4738e231d97SPeter Brune       ierr = VecDotBegin(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
4748e231d97SPeter Brune       ierr = VecDotBegin(Dold, D, &DolddotD);CHKERRQ(ierr);
4758e231d97SPeter Brune       ierr = VecDotEnd(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
4768e231d97SPeter Brune       ierr = VecDotEnd(Dold, D, &DolddotD);CHKERRQ(ierr);
4770c777b0cSPeter Brune       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
4780c777b0cSPeter Brune     }
4790c777b0cSPeter Brune     periodic = PETSC_FALSE;
480b8840d6bSPeter Brune     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
481b8840d6bSPeter Brune       if (i_r>qn->m-1) periodic = PETSC_TRUE;
4820c777b0cSPeter Brune     }
4830c777b0cSPeter Brune     /* restart if either powell or periodic restart is satisfied. */
4840c777b0cSPeter Brune     if (powell || periodic) {
4855ba6227bSPeter Brune       if (qn->monitor) {
4865ba6227bSPeter Brune         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
487516fe3c3SPeter 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);
4885ba6227bSPeter Brune         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
4895ba6227bSPeter Brune       }
4905ba6227bSPeter Brune       i_r = -1;
4915ba6227bSPeter Brune       /* general purpose update */
4925ba6227bSPeter Brune       if (snes->ops->update) {
4935ba6227bSPeter Brune         ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
4945ba6227bSPeter Brune       }
4950c777b0cSPeter Brune       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
4960ecc9e1dSPeter Brune         ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
4978cba9625SJed Brown         ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
4980ecc9e1dSPeter Brune       }
4990ecc9e1dSPeter Brune     }
50070d3b23bSPeter Brune     /* general purpose update */
50170d3b23bSPeter Brune     if (snes->ops->update) {
50270d3b23bSPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
50370d3b23bSPeter Brune     }
5045ba6227bSPeter Brune   }
5054b11644fSPeter Brune   if (i == snes->max_its) {
5064b11644fSPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr);
5074b11644fSPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
5084b11644fSPeter Brune   }
5094b11644fSPeter Brune   PetscFunctionReturn(0);
5104b11644fSPeter Brune }
5114b11644fSPeter Brune 
5124b11644fSPeter Brune #undef __FUNCT__
5134b11644fSPeter Brune #define __FUNCT__ "SNESSetUp_QN"
5144b11644fSPeter Brune static PetscErrorCode SNESSetUp_QN(SNES snes)
5154b11644fSPeter Brune {
5169f83bee8SJed Brown   SNES_QN        *qn = (SNES_QN*)snes->data;
5174b11644fSPeter Brune   PetscErrorCode ierr;
518335fb975SPeter Brune 
5194b11644fSPeter Brune   PetscFunctionBegin;
520b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr);
521b8840d6bSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr);
5228e231d97SPeter Brune   ierr = PetscMalloc3(qn->m, PetscScalar, &qn->alpha,
5238e231d97SPeter Brune                       qn->m, PetscScalar, &qn->beta,
5248e231d97SPeter Brune                       qn->m, PetscScalar, &qn->dXtdF);CHKERRQ(ierr);
5258e231d97SPeter Brune 
52618aa0c0cSPeter Brune   if (qn->singlereduction) {
5278e231d97SPeter Brune     ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat,
5288e231d97SPeter Brune                         qn->m, PetscScalar, &qn->dFtdX,
5298e231d97SPeter Brune                         qn->m, PetscScalar, &qn->YtdX);CHKERRQ(ierr);
5308e231d97SPeter Brune   }
531fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr);
532335fb975SPeter Brune 
533335fb975SPeter Brune   /* set up the line search */
5340c777b0cSPeter Brune   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
5358e231d97SPeter Brune     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
5368e231d97SPeter Brune   }
5376c67d002SPeter Brune 
5386c67d002SPeter Brune   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;}
5396c67d002SPeter Brune 
5404b11644fSPeter Brune   PetscFunctionReturn(0);
5414b11644fSPeter Brune }
5424b11644fSPeter Brune 
5434b11644fSPeter Brune #undef __FUNCT__
5444b11644fSPeter Brune #define __FUNCT__ "SNESReset_QN"
5454b11644fSPeter Brune static PetscErrorCode SNESReset_QN(SNES snes)
5464b11644fSPeter Brune {
5474b11644fSPeter Brune   PetscErrorCode ierr;
5489f83bee8SJed Brown   SNES_QN        *qn;
5490adebc6cSBarry Smith 
5504b11644fSPeter Brune   PetscFunctionBegin;
5514b11644fSPeter Brune   if (snes->data) {
5529f83bee8SJed Brown     qn = (SNES_QN*)snes->data;
553b8840d6bSPeter Brune     if (qn->U) {
554b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr);
5554b11644fSPeter Brune     }
556b8840d6bSPeter Brune     if (qn->V) {
557b8840d6bSPeter Brune       ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr);
5584b11644fSPeter Brune     }
55918aa0c0cSPeter Brune     if (qn->singlereduction) {
5608e231d97SPeter Brune       ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr);
5618e231d97SPeter Brune     }
5628e231d97SPeter Brune     ierr = PetscFree3(qn->alpha, qn->beta, qn->dXtdF);CHKERRQ(ierr);
5634b11644fSPeter Brune   }
5644b11644fSPeter Brune   PetscFunctionReturn(0);
5654b11644fSPeter Brune }
5664b11644fSPeter Brune 
5674b11644fSPeter Brune #undef __FUNCT__
5684b11644fSPeter Brune #define __FUNCT__ "SNESDestroy_QN"
5694b11644fSPeter Brune static PetscErrorCode SNESDestroy_QN(SNES snes)
5704b11644fSPeter Brune {
5714b11644fSPeter Brune   PetscErrorCode ierr;
5726e111a19SKarl Rupp 
5734b11644fSPeter Brune   PetscFunctionBegin;
5744b11644fSPeter Brune   ierr = SNESReset_QN(snes);CHKERRQ(ierr);
5754b11644fSPeter Brune   ierr = PetscFree(snes->data);CHKERRQ(ierr);
576bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr);
5774b11644fSPeter Brune   PetscFunctionReturn(0);
5784b11644fSPeter Brune }
5794b11644fSPeter Brune 
5804b11644fSPeter Brune #undef __FUNCT__
5814b11644fSPeter Brune #define __FUNCT__ "SNESSetFromOptions_QN"
5824b11644fSPeter Brune static PetscErrorCode SNESSetFromOptions_QN(SNES snes)
5834b11644fSPeter Brune {
5844b11644fSPeter Brune 
5854b11644fSPeter Brune   PetscErrorCode    ierr;
5862150357eSBarry Smith   SNES_QN           *qn    = (SNES_QN*)snes->data;
58788f769c5SPeter Brune   PetscBool         monflg = PETSC_FALSE,flg;
588f1c6b773SPeter Brune   SNESLineSearch    linesearch;
5892150357eSBarry Smith   SNESQNRestartType rtype = qn->restart_type;
5902150357eSBarry Smith   SNESQNScaleType   stype = qn->scale_type;
5912150357eSBarry Smith 
5924b11644fSPeter Brune   PetscFunctionBegin;
5934b11644fSPeter Brune   ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr);
5940298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,NULL);CHKERRQ(ierr);
5950298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance",          "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL);CHKERRQ(ierr);
5960298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance",        "SNESQN", qn->powell_downhill, &qn->powell_downhill, NULL);CHKERRQ(ierr);
5970298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_monitor",         "Monitor for the QN methods",      "SNESQN", monflg, &monflg, NULL);CHKERRQ(ierr);
5980298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions",           "SNESQN", qn->singlereduction, &qn->singlereduction, NULL);CHKERRQ(ierr);
59988f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr);
60088f769c5SPeter Brune   if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr);
60188f769c5SPeter Brune 
60288f769c5SPeter Brune   ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr);
60388f769c5SPeter Brune   if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr);
60488f769c5SPeter Brune 
605b8840d6bSPeter Brune   ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes,
6060298fd71SBarry Smith                           (PetscEnum)qn->type,(PetscEnum*)&qn->type,NULL);CHKERRQ(ierr);
6074b11644fSPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
6089e764e56SPeter Brune   if (!snes->linesearch) {
6097601faf0SJed Brown     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
6101a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
6119e764e56SPeter Brune   }
61244f7e39eSPeter Brune   if (monflg) {
613ce94432eSBarry Smith     qn->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
61444f7e39eSPeter Brune   }
6154b11644fSPeter Brune   PetscFunctionReturn(0);
6164b11644fSPeter Brune }
6174b11644fSPeter Brune 
61892c02d66SPeter Brune 
6190c777b0cSPeter Brune #undef __FUNCT__
6200c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType"
6210c777b0cSPeter Brune /*@
6220c777b0cSPeter Brune     SNESQNSetRestartType - Sets the restart type for SNESQN.
6230c777b0cSPeter Brune 
6240c777b0cSPeter Brune     Logically Collective on SNES
6250c777b0cSPeter Brune 
6260c777b0cSPeter Brune     Input Parameters:
6270c777b0cSPeter Brune +   snes - the iterative context
6280c777b0cSPeter Brune -   rtype - restart type
6290c777b0cSPeter Brune 
6300c777b0cSPeter Brune     Options Database:
6310c777b0cSPeter Brune +   -snes_qn_restart_type<powell,periodic,none> - set the restart type
632b8840d6bSPeter Brune -   -snes_qn_restart[10] - sets the number of iterations before restart for periodic
6330c777b0cSPeter Brune 
6340c777b0cSPeter Brune     Level: intermediate
6350c777b0cSPeter Brune 
6360c777b0cSPeter Brune     SNESQNRestartTypes:
6370c777b0cSPeter Brune +   SNES_QN_RESTART_NONE - never restart
6380c777b0cSPeter Brune .   SNES_QN_RESTART_POWELL - restart based upon descent criteria
6390c777b0cSPeter Brune -   SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations
6400c777b0cSPeter Brune 
6410c777b0cSPeter Brune     Notes:
6420c777b0cSPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
6430c777b0cSPeter Brune 
6440c777b0cSPeter Brune .keywords: SNES, SNESQN, restart, type, set SNESLineSearch
6450c777b0cSPeter Brune @*/
6462150357eSBarry Smith PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
6472150357eSBarry Smith {
6480c777b0cSPeter Brune   PetscErrorCode ierr;
6496e111a19SKarl Rupp 
6500c777b0cSPeter Brune   PetscFunctionBegin;
6510c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
6520c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr);
6530c777b0cSPeter Brune   PetscFunctionReturn(0);
6540c777b0cSPeter Brune }
6550c777b0cSPeter Brune 
6560c777b0cSPeter Brune #undef __FUNCT__
6570c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType"
6580c777b0cSPeter Brune /*@
6590c777b0cSPeter Brune     SNESQNSetScaleType - Sets the scaling type for the inner inverse jacobian in SNESQN.
6600c777b0cSPeter Brune 
6610c777b0cSPeter Brune     Logically Collective on SNES
6620c777b0cSPeter Brune 
6630c777b0cSPeter Brune     Input Parameters:
6640c777b0cSPeter Brune +   snes - the iterative context
6650c777b0cSPeter Brune -   stype - scale type
6660c777b0cSPeter Brune 
6670c777b0cSPeter Brune     Options Database:
6680c777b0cSPeter Brune .   -snes_qn_scale_type<shanno,none,linesearch,jacobian>
6690c777b0cSPeter Brune 
6700c777b0cSPeter Brune     Level: intermediate
6710c777b0cSPeter Brune 
6720c777b0cSPeter Brune     SNESQNSelectTypes:
6730c777b0cSPeter Brune +   SNES_QN_SCALE_NONE - don't scale the problem
6740c777b0cSPeter Brune .   SNES_QN_SCALE_SHANNO - use shanno scaling
6750c777b0cSPeter Brune .   SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda
6760c777b0cSPeter Brune -   SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian.
6770c777b0cSPeter Brune 
6780c777b0cSPeter Brune .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch
6790c777b0cSPeter Brune @*/
6800c777b0cSPeter Brune 
6812150357eSBarry Smith PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
6822150357eSBarry Smith {
6830c777b0cSPeter Brune   PetscErrorCode ierr;
6846e111a19SKarl Rupp 
6850c777b0cSPeter Brune   PetscFunctionBegin;
6860c777b0cSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
6870c777b0cSPeter Brune   ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr);
6880c777b0cSPeter Brune   PetscFunctionReturn(0);
6890c777b0cSPeter Brune }
6900c777b0cSPeter Brune 
6910c777b0cSPeter Brune #undef __FUNCT__
6920c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetScaleType_QN"
6930adebc6cSBarry Smith PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
6940adebc6cSBarry Smith {
6950c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
6966e111a19SKarl Rupp 
6970c777b0cSPeter Brune   PetscFunctionBegin;
6980c777b0cSPeter Brune   qn->scale_type = stype;
6990c777b0cSPeter Brune   PetscFunctionReturn(0);
7000c777b0cSPeter Brune }
7010c777b0cSPeter Brune 
7020c777b0cSPeter Brune #undef __FUNCT__
7030c777b0cSPeter Brune #define __FUNCT__ "SNESQNSetRestartType_QN"
7040adebc6cSBarry Smith PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
7050adebc6cSBarry Smith {
7060c777b0cSPeter Brune   SNES_QN *qn = (SNES_QN*)snes->data;
7076e111a19SKarl Rupp 
7080c777b0cSPeter Brune   PetscFunctionBegin;
7090c777b0cSPeter Brune   qn->restart_type = rtype;
7100c777b0cSPeter Brune   PetscFunctionReturn(0);
7110c777b0cSPeter Brune }
7120c777b0cSPeter Brune 
7134b11644fSPeter Brune /* -------------------------------------------------------------------------- */
7144b11644fSPeter Brune /*MC
7154b11644fSPeter Brune       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
7164b11644fSPeter Brune 
7176cc8130cSPeter Brune       Options Database:
7186cc8130cSPeter Brune 
7196cc8130cSPeter Brune +     -snes_qn_m - Number of past states saved for the L-Broyden methods.
7201867fe5bSPeter Brune .     -snes_qn_powell_angle - Angle condition for restart.
7211867fe5bSPeter Brune .     -snes_qn_powell_descent - Descent condition for restart.
72272835e02SPeter Brune .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
72344f7e39eSPeter Brune -     -snes_qn_monitor - Monitors the quasi-newton jacobian.
7246cc8130cSPeter Brune 
725b8840d6bSPeter Brune       Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
726b8840d6bSPeter Brune       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
727b8840d6bSPeter Brune       updates.
7286cc8130cSPeter Brune 
7291867fe5bSPeter Brune       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
7301867fe5bSPeter Brune       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
7311867fe5bSPeter Brune       iteration as the current iteration's values when constructing the approximate jacobian.  The second, composed,
7321867fe5bSPeter Brune       perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
7331867fe5bSPeter Brune 
7346cc8130cSPeter Brune       References:
7356cc8130cSPeter Brune 
7366cc8130cSPeter Brune       L-Broyden Methods: a generalization of the L-BFGS method to the limited memory Broyden family, M. B. Reed,
7376cc8130cSPeter Brune       International Journal of Computer Mathematics, vol. 86, 2009.
7386cc8130cSPeter Brune 
739b8840d6bSPeter Brune       Experiments with Quasi-Newton Methods in Solving Stiff ODE Systems, Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker
740b8840d6bSPeter Brune       SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
741b8840d6bSPeter Brune 
7424b11644fSPeter Brune 
7434b11644fSPeter Brune       Level: beginner
7444b11644fSPeter Brune 
74504d7464bSBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR
7466cc8130cSPeter Brune 
7474b11644fSPeter Brune M*/
7484b11644fSPeter Brune #undef __FUNCT__
7494b11644fSPeter Brune #define __FUNCT__ "SNESCreate_QN"
7508cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes)
7514b11644fSPeter Brune {
7524b11644fSPeter Brune   PetscErrorCode ierr;
7539f83bee8SJed Brown   SNES_QN        *qn;
7544b11644fSPeter Brune 
7554b11644fSPeter Brune   PetscFunctionBegin;
7564b11644fSPeter Brune   snes->ops->setup          = SNESSetUp_QN;
7574b11644fSPeter Brune   snes->ops->solve          = SNESSolve_QN;
7584b11644fSPeter Brune   snes->ops->destroy        = SNESDestroy_QN;
7594b11644fSPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_QN;
7604b11644fSPeter Brune   snes->ops->view           = 0;
7614b11644fSPeter Brune   snes->ops->reset          = SNESReset_QN;
7624b11644fSPeter Brune 
76347f26062SPeter Brune   snes->pcside = PC_LEFT;
76447f26062SPeter Brune 
76542f4f86dSBarry Smith   snes->usespc  = PETSC_TRUE;
76642f4f86dSBarry Smith   snes->usesksp = PETSC_FALSE;
76742f4f86dSBarry Smith 
76888976e71SPeter Brune   if (!snes->tolerancesset) {
7690e444f03SPeter Brune     snes->max_funcs = 30000;
7700e444f03SPeter Brune     snes->max_its   = 10000;
77188976e71SPeter Brune   }
7720e444f03SPeter Brune 
7739f83bee8SJed Brown   ierr                = PetscNewLog(snes,SNES_QN,&qn);CHKERRQ(ierr);
7744b11644fSPeter Brune   snes->data          = (void*) qn;
7750ecc9e1dSPeter Brune   qn->m               = 10;
776b21d5a53SPeter Brune   qn->scaling         = 1.0;
7770298fd71SBarry Smith   qn->U               = NULL;
7780298fd71SBarry Smith   qn->V               = NULL;
7790298fd71SBarry Smith   qn->dXtdF           = NULL;
7800298fd71SBarry Smith   qn->dFtdX           = NULL;
7810298fd71SBarry Smith   qn->dXdFmat         = NULL;
7820298fd71SBarry Smith   qn->monitor         = NULL;
7831c6523dcSPeter Brune   qn->singlereduction = PETSC_TRUE;
784b8840d6bSPeter Brune   qn->powell_gamma    = 0.9999;
7850c777b0cSPeter Brune   qn->scale_type      = SNES_QN_SCALE_SHANNO;
7860c777b0cSPeter Brune   qn->restart_type    = SNES_QN_RESTART_POWELL;
787b8840d6bSPeter Brune   qn->type            = SNES_QN_LBFGS;
788ea630c6eSPeter Brune 
789bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetScaleType_C",SNESQNSetScaleType_QN);CHKERRQ(ierr);
790bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetRestartType_C",SNESQNSetRestartType_QN);CHKERRQ(ierr);
7914b11644fSPeter Brune   PetscFunctionReturn(0);
7924b11644fSPeter Brune }
793