xref: /petsc/src/snes/impls/qn/qn.c (revision 6d12d9af432f3df10729dc77d50e4e6962ce0056)
1 #include <petsc-private/snesimpl.h> /*I "petscsnes.h" I*/
2 
3 #define H(i,j)  qn->dXdFmat[i*qn->m + j]
4 
5 const char *const SNESQNScaleTypes[] =        {"NONE","SHANNO","LINESEARCH","JACOBIAN","SNESQNScaleType","SNES_QN_SCALING_",0};
6 const char *const SNESQNRestartTypes[] =      {"NONE","POWELL","PERIODIC","SNESQNRestartType","SNES_QN_RESTART_",0};
7 const char *const SNESQNTypes[] =             {"LBFGS","BROYDEN","BADBROYDEN","SNESQNType","SNES_QN_RESTART_",0};
8 
9 typedef enum {SNES_QN_LBFGS      = 0,
10               SNES_QN_BROYDEN    = 1,
11               SNES_QN_BADBROYDEN = 2} SNESQNType;
12 
13 typedef struct {
14   Vec                   *U;               /* Stored past states (vary from method to method) */
15   Vec                   *V;               /* Stored past states (vary from method to method) */
16   PetscInt              m;                /* The number of kept previous steps */
17   PetscScalar           *alpha, *beta;
18   PetscScalar           *dXtdF, *dFtdX, *YtdX;
19   PetscBool             singlereduction;  /* Aggregated reduction implementation */
20   PetscScalar           *dXdFmat;         /* A matrix of values for dX_i dot dF_j */
21   PetscViewer           monitor;
22   PetscReal             powell_gamma;     /* Powell angle restart condition */
23   PetscReal             powell_downhill;  /* Powell descent restart condition */
24   PetscReal             scaling;          /* scaling of H0 */
25 
26   SNESQNType            type;             /* the type of quasi-newton method used */
27   SNESQNScaleType       scale_type;       /* the type of scaling used */
28   SNESQNRestartType     restart_type;     /* determine the frequency and type of restart conditions */
29 } SNES_QN;
30 
31 #undef __FUNCT__
32 #define __FUNCT__ "SNESQNApply_Broyden"
33 PetscErrorCode SNESQNApply_Broyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold, Vec D, Vec Dold)
34 {
35   PetscErrorCode     ierr;
36   SNES_QN            *qn = (SNES_QN*)snes->data;
37   Vec                W = snes->work[3];
38   Vec                *U = qn->U;
39   Vec                *V = qn->V;
40   KSPConvergedReason kspreason;
41   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
42   PetscInt           k,i,lits;
43   PetscInt           m = qn->m;
44   PetscScalar        gdot;
45   PetscInt           l = m;
46   Mat                jac,jac_pre;
47 
48   PetscFunctionBegin;
49   if (it < m) l = it;
50   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
51     ierr = SNESGetJacobian(snes,&jac,&jac_pre,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
52     ierr = KSPSetOperators(snes->ksp,jac,jac_pre,flg);CHKERRQ(ierr);
53     ierr = SNES_KSPSolve(snes,snes->ksp,D,W);CHKERRQ(ierr);
54     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
55     if (kspreason < 0) {
56       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
57         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
58         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
59         PetscFunctionReturn(0);
60       }
61     }
62     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
63     snes->linear_its += lits;
64     ierr = VecCopy(W,Y);CHKERRQ(ierr);
65   } else {
66     ierr = VecCopy(D,Y);CHKERRQ(ierr);
67     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
68   }
69 
70   /* inward recursion starting at the first update and working forward */
71   if (it > 1) {
72     for (i = 0; i < l-1; i++) {
73       k = (it+i-l)%l;
74       ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
75       ierr = VecAXPY(Y,gdot,V[k]);CHKERRQ(ierr);
76       if (qn->monitor) {
77         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
78         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
79         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
80       }
81     }
82   }
83   if (it < m) l = it;
84 
85   /* set W to be the last step, post-linesearch */
86   ierr = VecCopy(Xold,W);CHKERRQ(ierr);
87   ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr);
88 
89   if (l > 0) {
90     k = (it-1)%l;
91     ierr = VecCopy(W,U[k]);CHKERRQ(ierr);
92     ierr = VecAXPY(W,-1.0,Y);CHKERRQ(ierr);
93     ierr = VecDot(U[k],W,&gdot);CHKERRQ(ierr);
94     ierr = VecCopy(Y,V[k]);CHKERRQ(ierr);
95     ierr = VecScale(V[k],1.0/gdot);CHKERRQ(ierr);
96     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
97     ierr = VecAXPY(Y,gdot,V[k]);CHKERRQ(ierr);
98     if (qn->monitor) {
99       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
100       ierr = PetscViewerASCIIPrintf(qn->monitor, "update: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
101       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
102     }
103   }
104   PetscFunctionReturn(0);
105 }
106 
107 #undef __FUNCT__
108 #define __FUNCT__ "SNESQNApply_BadBroyden"
109 PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
110 {
111   PetscErrorCode     ierr;
112   SNES_QN            *qn = (SNES_QN*)snes->data;
113   Vec                W = snes->work[3];
114   Vec                *U = qn->U;
115   Vec                *T = qn->V;
116 
117   /* ksp thing for jacobian scaling */
118   KSPConvergedReason kspreason;
119   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
120   PetscInt           k, i, lits;
121   PetscInt           m = qn->m;
122   PetscScalar        gdot;
123   PetscInt           l = m;
124   Mat                jac, jac_pre;
125 
126   PetscFunctionBegin;
127   if (it < m) l = it;
128   ierr = VecCopy(D,Y);CHKERRQ(ierr);
129   if (l > 0) {
130     k = (it-1)%l;
131     ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr);
132     ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr);
133     ierr = VecDot(U[k],U[k],&gdot);CHKERRQ(ierr);
134     ierr = VecCopy(D,T[k]);CHKERRQ(ierr);
135     ierr = VecScale(T[k],1.0/gdot);CHKERRQ(ierr);
136     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
137     ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
138     if (qn->monitor) {
139       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
140       ierr = PetscViewerASCIIPrintf(qn->monitor, "update: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
141       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
142     }
143   }
144 
145   /* inward recursion starting at the first update and working forward */
146   if (it > 1) {
147     for (i = 0; i < l-1; i++) {
148       k = (it+i-l)%l;
149       ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
150       ierr = VecAXPY(Y,gdot,T[k]);CHKERRQ(ierr);
151       if (qn->monitor) {
152         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
153         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
154         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
155       }
156     }
157   }
158 
159   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
160     ierr = SNESGetJacobian(snes, &jac, &jac_pre, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
161     ierr = KSPSetOperators(snes->ksp,jac,jac_pre,flg);CHKERRQ(ierr);
162     ierr = SNES_KSPSolve(snes,snes->ksp,Y,W);CHKERRQ(ierr);
163     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
164     if (kspreason < 0) {
165       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
166         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
167         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
168         PetscFunctionReturn(0);
169       }
170     }
171     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
172     snes->linear_its += lits;
173     ierr = VecCopy(W,Y);CHKERRQ(ierr);
174   }  else {
175     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
176   }
177   PetscFunctionReturn(0);
178 }
179 
180 #undef __FUNCT__
181 #define __FUNCT__ "SNESQNApply_LBFGS"
182 PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
183 {
184   PetscErrorCode     ierr;
185   SNES_QN            *qn = (SNES_QN*)snes->data;
186   Vec                W = snes->work[3];
187   Vec                *dX = qn->U;
188   Vec                *dF = qn->V;
189   PetscScalar        *alpha    = qn->alpha;
190   PetscScalar        *beta     = qn->beta;
191   PetscScalar        *dXtdF    = qn->dXtdF;
192   PetscScalar        *dFtdX    = qn->dFtdX;
193   PetscScalar        *YtdX     = qn->YtdX;
194 
195   /* ksp thing for jacobian scaling */
196   KSPConvergedReason kspreason;
197   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
198   PetscInt           k,i,j,g,lits;
199   PetscInt           m = qn->m;
200   PetscScalar        t;
201   PetscInt           l = m;
202   Mat                jac,jac_pre;
203 
204   PetscFunctionBegin;
205   if (it < m) l = it;
206   if (it > 0) {
207     k = (it - 1) % l;
208     ierr = VecCopy(D, dF[k]);CHKERRQ(ierr);
209     ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr);
210     ierr = VecCopy(X, dX[k]);CHKERRQ(ierr);
211     ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr);
212     if (qn->singlereduction) {
213       ierr = VecMDot(dF[k], l, dX, dXtdF);CHKERRQ(ierr);
214       ierr = VecMDot(dX[k], l, dF, dFtdX);CHKERRQ(ierr);
215       for (j = 0; j < l; j++) {
216         H(k, j) = dFtdX[j];
217         H(j, k) = dXtdF[j];
218       }
219       /* copy back over to make the computation of alpha and beta easier */
220       for (j = 0; j < l; j++) {
221         dXtdF[j] = H(j, j);
222       }
223     } else {
224       ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr);
225     }
226     if (qn->scale_type == SNES_QN_SCALE_SHANNO) {
227       PetscReal dFtdF;
228       ierr = VecDotRealPart(dF[k],dF[k],&dFtdF);CHKERRQ(ierr);
229       qn->scaling = PetscRealPart(dXtdF[k])/dFtdF;
230     } else if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
231       ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr);
232     }
233   }
234 
235   ierr = VecCopy(D,Y);CHKERRQ(ierr);
236 
237   if (qn->singlereduction) {
238     ierr = VecMDot(Y,l,dX,YtdX);CHKERRQ(ierr);
239   }
240   /* outward recursion starting at iteration k's update and working back */
241   for (i=0;i<l;i++) {
242     k = (it-i-1)%l;
243     if (qn->singlereduction) {
244       /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */
245       t = YtdX[k];
246       for (j=0;j<i;j++) {
247         g = (it-j-1)%l;
248         t += -alpha[g]*H(g, k);
249       }
250       alpha[k] = t/H(k,k);
251     } else {
252       ierr = VecDot(dX[k],Y,&t);CHKERRQ(ierr);
253       alpha[k] = t/dXtdF[k];
254     }
255     if (qn->monitor) {
256       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
257       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha:        %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr);
258       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
259     }
260     ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr);
261   }
262 
263   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
264     ierr = SNESGetJacobian(snes, &jac, &jac_pre, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
265     ierr = KSPSetOperators(snes->ksp,jac,jac_pre,flg);CHKERRQ(ierr);
266     ierr = SNES_KSPSolve(snes,snes->ksp,Y,W);CHKERRQ(ierr);
267     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
268     if (kspreason < 0) {
269       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
270         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
271         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
272         PetscFunctionReturn(0);
273       }
274     }
275     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
276     snes->linear_its += lits;
277     ierr = VecCopy(W, Y);CHKERRQ(ierr);
278   } else {
279     ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr);
280   }
281   if (qn->singlereduction) {
282     ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr);
283   }
284   /* inward recursion starting at the first update and working forward */
285   for (i = 0; i < l; i++) {
286     k = (it + i - l) % l;
287     if (qn->singlereduction) {
288       t = YtdX[k];
289       for (j = 0; j < i; j++) {
290         g = (it + j - l) % l;
291         t += (alpha[g] - beta[g])*H(k, g);
292       }
293       beta[k] = t / H(k, k);
294     } else {
295       ierr = VecDot(dF[k], Y, &t);CHKERRQ(ierr);
296       beta[k] = t / dXtdF[k];
297     }
298     ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr);
299     if (qn->monitor) {
300       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
301       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr);
302       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
303     }
304   }
305   PetscFunctionReturn(0);
306 }
307 
308 #undef __FUNCT__
309 #define __FUNCT__ "SNESSolve_QN"
310 static PetscErrorCode SNESSolve_QN(SNES snes)
311 {
312   PetscErrorCode      ierr;
313   SNES_QN             *qn = (SNES_QN*) snes->data;
314   Vec                 X,Xold;
315   Vec                 F,B;
316   Vec                 Y,FPC,D,Dold;
317   SNESConvergedReason reason;
318   PetscInt            i, i_r;
319   PetscReal           fnorm,xnorm,ynorm,gnorm;
320   PetscBool           lssucceed,powell,periodic;
321   PetscScalar         DolddotD,DolddotDold,DdotD,YdotD;
322   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
323 
324   /* basically just a regular newton's method except for the application of the jacobian */
325 
326   PetscFunctionBegin;
327   F             = snes->vec_func;       /* residual vector */
328   Y             = snes->vec_sol_update; /* search direction generated by J^-1D*/
329   B             = snes->vec_rhs;
330 
331   X             = snes->vec_sol;        /* solution vector */
332   Xold          = snes->work[0];
333 
334   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
335   D             = snes->work[1];
336   Dold          = snes->work[2];
337 
338   snes->reason = SNES_CONVERGED_ITERATING;
339 
340   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
341   snes->iter = 0;
342   snes->norm = 0.;
343   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
344   if (!snes->vec_func_init_set) {
345     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
346     if (snes->domainerror) {
347       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
348       PetscFunctionReturn(0);
349     }
350   } else {
351     snes->vec_func_init_set = PETSC_FALSE;
352   }
353 
354   if (!snes->norm_init_set) {
355     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
356     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
357   } else {
358     fnorm = snes->norm_init;
359     snes->norm_init_set = PETSC_FALSE;
360   }
361 
362   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
363   snes->norm = fnorm;
364   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
365   SNESLogConvHistory(snes,fnorm,0);
366   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
367 
368   /* set parameter for default relative tolerance convergence test */
369    snes->ttol = fnorm*snes->rtol;
370   /* test convergence */
371   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
372   if (snes->reason) PetscFunctionReturn(0);
373 
374   /* composed solve */
375   if (snes->pc && snes->pcside == PC_RIGHT) {
376     ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr);
377     ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr);
378     ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
379     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
380     if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) {
381       snes->reason = SNES_DIVERGED_INNER;
382       PetscFunctionReturn(0);
383     }
384     ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
385     ierr = VecCopy(FPC, F);CHKERRQ(ierr);
386     ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr);
387     ierr = VecCopy(F, Y);CHKERRQ(ierr);
388   } else {
389     ierr = VecCopy(F, Y);CHKERRQ(ierr);
390   }
391   ierr = VecCopy(Y, D);CHKERRQ(ierr);
392 
393   /* scale the initial update */
394   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
395     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
396   }
397 
398   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
399     switch (qn->type) {
400     case SNES_QN_BADBROYDEN:
401       ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
402       break;
403     case SNES_QN_BROYDEN:
404       ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
405       break;
406     case SNES_QN_LBFGS:
407       SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
408       break;
409     }
410     /* line search for lambda */
411     ynorm = 1; gnorm = fnorm;
412     ierr = VecCopy(D, Dold);CHKERRQ(ierr);
413     ierr = VecCopy(X, Xold);CHKERRQ(ierr);
414     ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr);
415     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
416     if (snes->domainerror) {
417       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
418       PetscFunctionReturn(0);
419       }
420     ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
421     if (!lssucceed) {
422       if (++snes->numFailures >= snes->maxFailures) {
423         snes->reason = SNES_DIVERGED_LINE_SEARCH;
424         break;
425       }
426     }
427     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
428     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
429       ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr);
430     }
431 
432     /* convergence monitoring */
433     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);
434 
435     ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr);
436     ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr);
437 
438     SNESLogConvHistory(snes,snes->norm,snes->iter);
439     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
440     /* set parameter for default relative tolerance convergence test */
441     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
442     if (snes->reason) PetscFunctionReturn(0);
443 
444     if (snes->pc && snes->pcside == PC_RIGHT) {
445       ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr);
446       ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr);
447       ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
448       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
449       if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) {
450         snes->reason = SNES_DIVERGED_INNER;
451         PetscFunctionReturn(0);
452       }
453       ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
454       ierr = VecCopy(FPC, F);CHKERRQ(ierr);
455       ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr);
456       ierr = VecCopy(F, D);CHKERRQ(ierr);
457     } else {
458       ierr = VecCopy(F, D);CHKERRQ(ierr);
459     }
460 
461     powell = PETSC_FALSE;
462     if (qn->restart_type == SNES_QN_RESTART_POWELL) {
463       /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */
464       ierr = VecDotBegin(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
465       ierr = VecDotBegin(Dold, D, &DolddotD);CHKERRQ(ierr);
466       ierr = VecDotBegin(D, D, &DdotD);CHKERRQ(ierr);
467       ierr = VecDotBegin(Y, D, &YdotD);CHKERRQ(ierr);
468       ierr = VecDotEnd(Dold, Dold, &DolddotDold);CHKERRQ(ierr);
469       ierr = VecDotEnd(Dold, D, &DolddotD);CHKERRQ(ierr);
470       ierr = VecDotEnd(D, D, &DdotD);CHKERRQ(ierr);
471       ierr = VecDotEnd(Y, D, &YdotD);CHKERRQ(ierr);
472       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
473     }
474     periodic = PETSC_FALSE;
475     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
476       if (i_r>qn->m-1) periodic = PETSC_TRUE;
477     }
478     /* restart if either powell or periodic restart is satisfied. */
479     if (powell || periodic) {
480       if (qn->monitor) {
481         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
482         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);
483         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
484       }
485       i_r = -1;
486       /* general purpose update */
487       if (snes->ops->update) {
488         ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
489       }
490       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
491         ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
492       }
493     }
494     /* general purpose update */
495     if (snes->ops->update) {
496       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
497     }
498   }
499   if (i == snes->max_its) {
500     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr);
501     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
502   }
503   PetscFunctionReturn(0);
504 }
505 
506 #undef __FUNCT__
507 #define __FUNCT__ "SNESSetUp_QN"
508 static PetscErrorCode SNESSetUp_QN(SNES snes)
509 {
510   SNES_QN        *qn = (SNES_QN*)snes->data;
511   PetscErrorCode ierr;
512 
513   PetscFunctionBegin;
514   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr);
515   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr);
516   ierr = PetscMalloc3(qn->m, PetscScalar, &qn->alpha,
517                       qn->m, PetscScalar, &qn->beta,
518                       qn->m, PetscScalar, &qn->dXtdF);CHKERRQ(ierr);
519 
520   if (qn->singlereduction) {
521     ierr = PetscMalloc3(qn->m*qn->m, PetscScalar, &qn->dXdFmat,
522                         qn->m, PetscScalar, &qn->dFtdX,
523                         qn->m, PetscScalar, &qn->YtdX);CHKERRQ(ierr);
524   }
525   ierr = SNESDefaultGetWork(snes,4);CHKERRQ(ierr);
526 
527   /* set up the line search */
528   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
529     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
530   }
531   PetscFunctionReturn(0);
532 }
533 
534 #undef __FUNCT__
535 #define __FUNCT__ "SNESReset_QN"
536 static PetscErrorCode SNESReset_QN(SNES snes)
537 {
538   PetscErrorCode ierr;
539   SNES_QN        *qn;
540 
541   PetscFunctionBegin;
542   if (snes->data) {
543     qn = (SNES_QN*)snes->data;
544     if (qn->U) {
545       ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr);
546     }
547     if (qn->V) {
548       ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr);
549     }
550     if (qn->singlereduction) {
551       ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr);
552     }
553     ierr = PetscFree3(qn->alpha, qn->beta, qn->dXtdF);CHKERRQ(ierr);
554   }
555   PetscFunctionReturn(0);
556 }
557 
558 #undef __FUNCT__
559 #define __FUNCT__ "SNESDestroy_QN"
560 static PetscErrorCode SNESDestroy_QN(SNES snes)
561 {
562   PetscErrorCode ierr;
563 
564   PetscFunctionBegin;
565   ierr = SNESReset_QN(snes);CHKERRQ(ierr);
566   ierr = PetscFree(snes->data);CHKERRQ(ierr);
567   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"","",PETSC_NULL);CHKERRQ(ierr);
568   PetscFunctionReturn(0);
569 }
570 
571 #undef __FUNCT__
572 #define __FUNCT__ "SNESSetFromOptions_QN"
573 static PetscErrorCode SNESSetFromOptions_QN(SNES snes)
574 {
575 
576   PetscErrorCode    ierr;
577   SNES_QN           *qn = (SNES_QN*)snes->data;
578   PetscBool         monflg = PETSC_FALSE,flg;
579   SNESLineSearch    linesearch;
580   SNESQNRestartType rtype = qn->restart_type;
581   SNESQNScaleType   stype = qn->scale_type;
582 
583   PetscFunctionBegin;
584   ierr = PetscOptionsHead("SNES QN options");CHKERRQ(ierr);
585   ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,PETSC_NULL);CHKERRQ(ierr);
586   ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance",          "SNESQN", qn->powell_gamma, &qn->powell_gamma, PETSC_NULL);CHKERRQ(ierr);
587   ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance",        "SNESQN", qn->powell_downhill, &qn->powell_downhill, PETSC_NULL);CHKERRQ(ierr);
588   ierr = PetscOptionsBool("-snes_qn_monitor",         "Monitor for the QN methods",      "SNESQN", monflg, &monflg, PETSC_NULL);CHKERRQ(ierr);
589   ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions",           "SNESQN", qn->singlereduction, &qn->singlereduction, PETSC_NULL);CHKERRQ(ierr);
590   ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr);
591   if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr);
592 
593   ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr);
594   if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr);
595 
596   ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes,
597                           (PetscEnum)qn->type,(PetscEnum*)&qn->type,PETSC_NULL);CHKERRQ(ierr);
598   ierr = PetscOptionsTail();CHKERRQ(ierr);
599   if (!snes->linesearch) {
600     ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
601     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
602   }
603   if (monflg) {
604     qn->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
605   }
606   PetscFunctionReturn(0);
607 }
608 
609 
610 #undef __FUNCT__
611 #define __FUNCT__ "SNESQNSetRestartType"
612 /*@
613     SNESQNSetRestartType - Sets the restart type for SNESQN.
614 
615     Logically Collective on SNES
616 
617     Input Parameters:
618 +   snes - the iterative context
619 -   rtype - restart type
620 
621     Options Database:
622 +   -snes_qn_restart_type<powell,periodic,none> - set the restart type
623 -   -snes_qn_restart[10] - sets the number of iterations before restart for periodic
624 
625     Level: intermediate
626 
627     SNESQNRestartTypes:
628 +   SNES_QN_RESTART_NONE - never restart
629 .   SNES_QN_RESTART_POWELL - restart based upon descent criteria
630 -   SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations
631 
632     Notes:
633     The default line search used is the L2 line search and it requires two additional function evaluations.
634 
635 .keywords: SNES, SNESQN, restart, type, set SNESLineSearch
636 @*/
637 PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
638 {
639   PetscErrorCode ierr;
640 
641   PetscFunctionBegin;
642   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
643   ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr);
644   PetscFunctionReturn(0);
645 }
646 
647 #undef __FUNCT__
648 #define __FUNCT__ "SNESQNSetScaleType"
649 /*@
650     SNESQNSetScaleType - Sets the scaling type for the inner inverse jacobian in SNESQN.
651 
652     Logically Collective on SNES
653 
654     Input Parameters:
655 +   snes - the iterative context
656 -   stype - scale type
657 
658     Options Database:
659 .   -snes_qn_scale_type<shanno,none,linesearch,jacobian>
660 
661     Level: intermediate
662 
663     SNESQNSelectTypes:
664 +   SNES_QN_SCALE_NONE - don't scale the problem
665 .   SNES_QN_SCALE_SHANNO - use shanno scaling
666 .   SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda
667 -   SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian.
668 
669 .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch
670 @*/
671 
672 PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
673 {
674   PetscErrorCode ierr;
675 
676   PetscFunctionBegin;
677   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
678   ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr);
679   PetscFunctionReturn(0);
680 }
681 
682 EXTERN_C_BEGIN
683 #undef __FUNCT__
684 #define __FUNCT__ "SNESQNSetScaleType_QN"
685 PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
686 {
687   SNES_QN *qn = (SNES_QN *)snes->data;
688 
689   PetscFunctionBegin;
690   qn->scale_type = stype;
691   PetscFunctionReturn(0);
692 }
693 
694 #undef __FUNCT__
695 #define __FUNCT__ "SNESQNSetRestartType_QN"
696 PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
697 {
698   SNES_QN *qn = (SNES_QN *)snes->data;
699 
700   PetscFunctionBegin;
701   qn->restart_type = rtype;
702   PetscFunctionReturn(0);
703 }
704 EXTERN_C_END
705 
706 /* -------------------------------------------------------------------------- */
707 /*MC
708       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
709 
710       Options Database:
711 
712 +     -snes_qn_m - Number of past states saved for the L-Broyden methods.
713 .     -snes_qn_powell_angle - Angle condition for restart.
714 .     -snes_qn_powell_descent - Descent condition for restart.
715 .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
716 -     -snes_qn_monitor - Monitors the quasi-newton jacobian.
717 
718       Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
719       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
720       updates.
721 
722       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
723       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
724       iteration as the current iteration's values when constructing the approximate jacobian.  The second, composed,
725       perturbs the problem the jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
726 
727       References:
728 
729       L-Broyden Methods: a generalization of the L-BFGS method to the limited memory Broyden family, M. B. Reed,
730       International Journal of Computer Mathematics, vol. 86, 2009.
731 
732       Experiments with Quasi-Newton Methods in Solving Stiff ODE Systems, Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker
733       SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
734 
735 
736       Level: beginner
737 
738 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR
739 
740 M*/
741 EXTERN_C_BEGIN
742 #undef __FUNCT__
743 #define __FUNCT__ "SNESCreate_QN"
744 PetscErrorCode  SNESCreate_QN(SNES snes)
745 {
746   PetscErrorCode ierr;
747   SNES_QN        *qn;
748 
749   PetscFunctionBegin;
750   snes->ops->setup           = SNESSetUp_QN;
751   snes->ops->solve           = SNESSolve_QN;
752   snes->ops->destroy         = SNESDestroy_QN;
753   snes->ops->setfromoptions  = SNESSetFromOptions_QN;
754   snes->ops->view            = 0;
755   snes->ops->reset           = SNESReset_QN;
756 
757   snes->usespc          = PETSC_TRUE;
758   snes->usesksp         = PETSC_FALSE;
759 
760   if (!snes->tolerancesset) {
761     snes->max_funcs = 30000;
762     snes->max_its   = 10000;
763   }
764 
765   ierr = PetscNewLog(snes,SNES_QN,&qn);CHKERRQ(ierr);
766   snes->data = (void *) qn;
767   qn->m               = 10;
768   qn->scaling         = 1.0;
769   qn->U               = PETSC_NULL;
770   qn->V               = PETSC_NULL;
771   qn->dXtdF           = PETSC_NULL;
772   qn->dFtdX           = PETSC_NULL;
773   qn->dXdFmat         = PETSC_NULL;
774   qn->monitor         = PETSC_NULL;
775   qn->singlereduction = PETSC_FALSE;
776   qn->powell_gamma    = 0.9999;
777   qn->scale_type      = SNES_QN_SCALE_SHANNO;
778   qn->restart_type    = SNES_QN_RESTART_POWELL;
779   qn->type            = SNES_QN_LBFGS;
780 
781   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESQNSetScaleType_C","SNESQNSetScaleType_QN",SNESQNSetScaleType_QN);CHKERRQ(ierr);
782   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESQNSetRestartType_C","SNESQNSetRestartType_QN",SNESQNSetRestartType_QN);CHKERRQ(ierr);
783   PetscFunctionReturn(0);
784 }
785 
786 EXTERN_C_END
787