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