xref: /petsc/src/snes/impls/ls/ls.c (revision f08646a875d6c8bb0dc8fb3d7c6d74e67952873a)
1 
2 #include <../src/snes/impls/ls/lsimpl.h>
3 
4 /*
5      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
6     || F(u) ||_2 but not a zero, F(u) = 0. In the case when one cannot compute J^T F we use the fact that
7     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
8     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
9 */
10 #undef __FUNCT__
11 #define __FUNCT__ "SNESLSCheckLocalMin_Private"
12 PetscErrorCode SNESLSCheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool  *ismin)
13 {
14   PetscReal      a1;
15   PetscErrorCode ierr;
16   PetscBool      hastranspose;
17 
18   PetscFunctionBegin;
19   *ismin = PETSC_FALSE;
20   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
21   if (hastranspose) {
22     /* Compute || J^T F|| */
23     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
24     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
25     ierr = PetscInfo1(snes,"|| J^T F|| %14.12e near zero implies found a local minimum\n",(double)(a1/fnorm));CHKERRQ(ierr);
26     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
27   } else {
28     Vec         work;
29     PetscScalar result;
30     PetscReal   wnorm;
31 
32     ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr);
33     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
34     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
35     ierr = MatMult(A,W,work);CHKERRQ(ierr);
36     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
37     ierr = VecDestroy(&work);CHKERRQ(ierr);
38     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
39     ierr = PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %14.12e near zero implies found a local minimum\n",(double)a1);CHKERRQ(ierr);
40     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
41   }
42   PetscFunctionReturn(0);
43 }
44 
45 /*
46      Checks if J^T(F - J*X) = 0
47 */
48 #undef __FUNCT__
49 #define __FUNCT__ "SNESLSCheckResidual_Private"
50 PetscErrorCode SNESLSCheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
51 {
52   PetscReal      a1,a2;
53   PetscErrorCode ierr;
54   PetscBool      hastranspose;
55 
56   PetscFunctionBegin;
57   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
58   if (hastranspose) {
59     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
60     ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr);
61 
62     /* Compute || J^T W|| */
63     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
64     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
65     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
66     if (a1 != 0.0) {
67       ierr = PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %14.12e near zero implies inconsistent rhs\n",(double)(a2/a1));CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "SNESLineSearchCubic_LS"
75 /*@C
76    SNESLineSearchCubic - Performs a cubic line search (default line search method).
77 
78    Collective on SNES
79 
80    Input Parameters:
81 +  snes - nonlinear context
82 .  lsctx - optional context for line search (not used here)
83 .  x - current iterate
84 .  f - residual evaluated at x
85 .  y - search direction
86 .  fnorm - 2-norm of f
87 -  xnorm - norm of x if known, otherwise 0
88 
89    Output Parameters:
90 +  g - residual evaluated at new iterate y
91 .  w - new iterate
92 .  gnorm - 2-norm of g
93 .  ynorm - 2-norm of search length
94 -  flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.
95 
96    Options Database Key:
97 +  -snes_ls cubic - Activates SNESLineSearchCubic()
98 .   -snes_ls_alpha <alpha> - Sets alpha
99 .   -snes_ls_maxstep <maxstep> - Sets the maximum stepsize the line search will use (if the 2-norm(y) > maxstep then scale y to be y = (maxstep/2-norm(y)) *y)
100 -   -snes_ls_minlambda <minlambda> - Sets the minimum lambda the line search will use minlambda/ max_i ( y[i]/x[i] )
101 
102 
103    Notes:
104    This line search is taken from "Numerical Methods for Unconstrained
105    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
106 
107    Level: advanced
108 
109 .keywords: SNES, nonlinear, line search, cubic
110 
111 .seealso: SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
112 @*/
113 PetscErrorCode  SNESLineSearchCubic_LS(SNES snes,void *lsctx,Vec x,Vec f,Vec y,PetscReal fnorm,PetscReal xnorm,Vec g,Vec w,PetscReal *ynorm,PetscReal *gnorm,PetscBool  *flag)
114 {
115   /*
116      Note that for line search purposes we work with with the related
117      minimization problem:
118         min  z(x):  R^n -> R,
119      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
120    */
121 
122   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
123   PetscReal      minlambda,lambda,lambdatemp;
124 #if defined(PETSC_USE_COMPLEX)
125   PetscScalar    cinitslope;
126 #endif
127   PetscErrorCode ierr;
128   PetscInt       count;
129   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
130   MPI_Comm       comm;
131 
132   PetscFunctionBegin;
133   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
134   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
135   *flag   = PETSC_TRUE;
136 
137   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
138   if (*ynorm == 0.0) {
139     if (snes->ls_monitor) {
140       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
141       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
142       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
143     }
144     *gnorm = fnorm;
145     ierr   = VecCopy(x,w);CHKERRQ(ierr);
146     ierr   = VecCopy(f,g);CHKERRQ(ierr);
147     *flag  = PETSC_FALSE;
148     goto theend1;
149   }
150   if (*ynorm > snes->maxstep) {	/* Step too big, so scale back */
151     if (snes->ls_monitor) {
152       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
153       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Scaling step by %14.12e old ynorm %14.12e\n",(double)(snes->maxstep/(*ynorm)),(double)(*ynorm));CHKERRQ(ierr);
154       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
155     }
156     ierr = VecScale(y,snes->maxstep/(*ynorm));CHKERRQ(ierr);
157     *ynorm = snes->maxstep;
158   }
159   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
160   minlambda = snes->steptol/rellength;
161   ierr      = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
162 #if defined(PETSC_USE_COMPLEX)
163   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
164   initslope = PetscRealPart(cinitslope);
165 #else
166   ierr      = VecDot(f,w,&initslope);CHKERRQ(ierr);
167 #endif
168   if (initslope > 0.0)  initslope = -initslope;
169   if (initslope == 0.0) initslope = -1.0;
170 
171   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
172   if (snes->nfuncs >= snes->max_funcs) {
173     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
174     *flag = PETSC_FALSE;
175     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
176     goto theend1;
177   }
178   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
179   if (snes->domainerror) {
180     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
181     PetscFunctionReturn(0);
182   }
183   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
184   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
185   ierr = PetscInfo2(snes,"Initial fnorm %14.12e gnorm %14.12e\n",(double)fnorm,(double)*gnorm);CHKERRQ(ierr);
186   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + snes->ls_alpha*initslope) { /* Sufficient reduction */
187     if (snes->ls_monitor) {
188       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
189       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Using full step: fnorm %14.12e gnorm %14.12e\n",(double)fnorm,(double)*gnorm);CHKERRQ(ierr);
190       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
191     }
192     goto theend1;
193   }
194 
195   /* Fit points with quadratic */
196   lambda     = 1.0;
197   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
198   lambdaprev = lambda;
199   gnormprev  = *gnorm;
200   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
201   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
202   else                         lambda = lambdatemp;
203 
204   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
205   if (snes->nfuncs >= snes->max_funcs) {
206     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
207     *flag = PETSC_FALSE;
208     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
209     goto theend1;
210   }
211   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
212   if (snes->domainerror) {
213     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
214     PetscFunctionReturn(0);
215   }
216   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
217   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
218   if (snes->ls_monitor) {
219     ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
220     ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: gnorm after quadratic fit %14.12e\n",(double)(*gnorm));CHKERRQ(ierr);
221     ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
222   }
223   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*snes->ls_alpha*initslope) { /* sufficient reduction */
224     if (snes->ls_monitor) {
225       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
226       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",(double)lambda);CHKERRQ(ierr);
227       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
228     }
229     goto theend1;
230   }
231 
232   /* Fit points with cubic */
233   count = 1;
234   while (PETSC_TRUE) {
235     if (lambda <= minlambda) {
236       if (snes->ls_monitor) {
237         ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
238 	ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
239 	ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",(double)fnorm,(double)(*gnorm),(double)(*ynorm),(double)minlambda,(double)lambda,(double)initslope);CHKERRQ(ierr);
240         ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
241       }
242       *flag = PETSC_FALSE;
243       break;
244     }
245     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
246     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
247     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
248     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
249     d  = b*b - 3*a*initslope;
250     if (d < 0.0) d = 0.0;
251     if (a == 0.0) {
252       lambdatemp = -initslope/(2.0*b);
253     } else {
254       lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a);
255     }
256     lambdaprev = lambda;
257     gnormprev  = *gnorm;
258     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
259     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
260     else                         lambda     = lambdatemp;
261     ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
262     if (snes->nfuncs >= snes->max_funcs) {
263       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
264       ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",(double)fnorm,(double)(*gnorm),(double)(*ynorm),(double)lambda,(double)initslope);CHKERRQ(ierr);
265       *flag = PETSC_FALSE;
266       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
267       break;
268     }
269     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
270     if (snes->domainerror) {
271       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
272       PetscFunctionReturn(0);
273     }
274     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
275     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
276     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*snes->ls_alpha*initslope) { /* is reduction enough? */
277       if (snes->ls_monitor) {
278 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)(*gnorm),(double)lambda);CHKERRQ(ierr);
279       }
280       break;
281     } else {
282       if (snes->ls_monitor) {
283         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",(double)(*gnorm),(double)lambda);CHKERRQ(ierr);
284       }
285     }
286     count++;
287   }
288   theend1:
289   /* Optional user-defined check for line search step validity */
290   if (snes->ops->postcheckstep && *flag) {
291     ierr = (*snes->ops->postcheckstep)(snes,x,y,w,snes->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
292     if (changed_y) {
293       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
294     }
295     if (changed_y || changed_w) { /* recompute the function if the step has changed */
296       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
297       if (snes->domainerror) {
298         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
299         PetscFunctionReturn(0);
300       }
301       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
302       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
303       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
304       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
305       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
306     }
307   }
308   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
309   PetscFunctionReturn(0);
310 }
311 /* -------------------------------------------------------------------------- */
312 
313 #undef __FUNCT__
314 #define __FUNCT__ "SNESLineSearchQuadratic_LS"
315 /*@C
316    SNESLineSearchQuadratic_LS - Performs a quadratic line search.
317 
318    Collective on SNES and Vec
319 
320    Input Parameters:
321 +  snes - the SNES context
322 .  lsctx - optional context for line search (not used here)
323 .  x - current iterate
324 .  f - residual evaluated at x
325 .  y - search direction
326 .  fnorm - 2-norm of f
327 -  xnorm - norm of x if known, otherwise 0
328 
329    Output Parameters:
330 +  g - residual evaluated at new iterate w
331 .  w - new iterate (x + lambda*y)
332 .  gnorm - 2-norm of g
333 .  ynorm - 2-norm of search length
334 -  flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.
335 
336    Options Database Keys:
337 +  -snes_ls quadratic - Activates SNESLineSearchQuadratic()
338 .   -snes_ls_alpha <alpha> - Sets alpha
339 .   -snes_ls_maxstep <maxstep> - Sets the maximum stepsize the line search will use (if the 2-norm(y) > maxstep then scale y to be y = (maxstep/2-norm(y)) *y)
340 -   -snes_ls_minlambda <minlambda> - Sets the minimum lambda the line search will use minlambda/ max_i ( y[i]/x[i] )
341 
342    Notes:
343    Use SNESLineSearchSet() to set this routine within the SNESLS method.
344 
345    Level: advanced
346 
347 .keywords: SNES, nonlinear, quadratic, line search
348 
349 .seealso: SNESLineSearchCubic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
350 @*/
351 PetscErrorCode  SNESLineSearchQuadratic_LS(SNES snes,void *lsctx,Vec x,Vec f,Vec y,PetscReal fnorm,PetscReal xnorm,Vec g,Vec w,PetscReal *ynorm,PetscReal *gnorm,PetscBool  *flag)
352 {
353   /*
354      Note that for line search purposes we work with with the related
355      minimization problem:
356         min  z(x):  R^n -> R,
357      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
358    */
359   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
360 #if defined(PETSC_USE_COMPLEX)
361   PetscScalar    cinitslope;
362 #endif
363   PetscErrorCode ierr;
364   PetscInt       count;
365   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
366 
367   PetscFunctionBegin;
368   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
369   *flag   = PETSC_TRUE;
370 
371   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
372   if (*ynorm == 0.0) {
373     if (snes->ls_monitor) {
374       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
375       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
376       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
377     }
378     *gnorm = fnorm;
379     ierr   = VecCopy(x,w);CHKERRQ(ierr);
380     ierr   = VecCopy(f,g);CHKERRQ(ierr);
381     *flag  = PETSC_FALSE;
382     goto theend2;
383   }
384   if (*ynorm > snes->maxstep) {	/* Step too big, so scale back */
385     ierr   = VecScale(y,snes->maxstep/(*ynorm));CHKERRQ(ierr);
386     *ynorm = snes->maxstep;
387   }
388   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
389   minlambda = snes->steptol/rellength;
390   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
391 #if defined(PETSC_USE_COMPLEX)
392   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
393   initslope = PetscRealPart(cinitslope);
394 #else
395   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
396 #endif
397   if (initslope > 0.0)  initslope = -initslope;
398   if (initslope == 0.0) initslope = -1.0;
399   ierr = PetscInfo1(snes,"Initslope %14.12e \n",(double)initslope);CHKERRQ(ierr);
400 
401   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
402   if (snes->nfuncs >= snes->max_funcs) {
403     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
404     *flag = PETSC_FALSE;
405     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
406     goto theend2;
407   }
408   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
409   if (snes->domainerror) {
410     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
411     PetscFunctionReturn(0);
412   }
413   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
414   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
415   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + snes->ls_alpha*initslope) { /* Sufficient reduction */
416     if (snes->ls_monitor) {
417       ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
418       ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line Search: Using full step\n");CHKERRQ(ierr);
419       ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
420     }
421     goto theend2;
422   }
423 
424   /* Fit points with quadratic */
425   lambda = 1.0;
426   count = 1;
427   while (PETSC_TRUE) {
428     if (lambda <= minlambda) { /* bad luck; use full step */
429       if (snes->ls_monitor) {
430         ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
431         ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
432         ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"Line search: fnorm=%14.12e, gnorm=%14.12e, ynorm=%14.12e, lambda=%14.12e, initial slope=%14.12e\n",(double)fnorm,(double)(*gnorm),(double)(*ynorm),(double)lambda,(double)initslope);CHKERRQ(ierr);
433         ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
434       }
435       ierr = VecCopy(x,w);CHKERRQ(ierr);
436       *flag = PETSC_FALSE;
437       break;
438     }
439     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
440     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
441     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
442     else                         lambda     = lambdatemp;
443 
444     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
445     if (snes->nfuncs >= snes->max_funcs) {
446       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
447       ierr  = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",(double)fnorm,(double)*gnorm,(double)*ynorm,(double)lambda,(double)initslope);CHKERRQ(ierr);
448       *flag = PETSC_FALSE;
449       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
450       break;
451     }
452     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
453     if (snes->domainerror) {
454       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
455       PetscFunctionReturn(0);
456     }
457     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
458     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
459     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*snes->ls_alpha*initslope) { /* sufficient reduction */
460       if (snes->ls_monitor) {
461         ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
462         ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line Search: Quadratically determined step, lambda=%14.12e\n",(double)lambda);CHKERRQ(ierr);
463         ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
464       }
465       break;
466     }
467     count++;
468   }
469   theend2:
470   /* Optional user-defined check for line search step validity */
471   if (snes->ops->postcheckstep) {
472     ierr = (*snes->ops->postcheckstep)(snes,x,y,w,snes->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
473     if (changed_y) {
474       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
475     }
476     if (changed_y || changed_w) { /* recompute the function if the step has changed */
477       ierr = SNESComputeFunction(snes,w,g);
478       if (snes->domainerror) {
479         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
480         PetscFunctionReturn(0);
481       }
482       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
483       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
484       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
485       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
486       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
487     }
488   }
489   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
490   PetscFunctionReturn(0);
491 }
492 
493 
494 EXTERN_C_BEGIN
495 #undef __FUNCT__
496 #define __FUNCT__ "SNESLineSearchSetType_LS"
497 PetscErrorCode  SNESLineSearchSetType_LS(SNES snes, SNESLineSearchType type)
498 {
499   PetscErrorCode ierr;
500   PetscFunctionBegin;
501 
502   switch (type) {
503   case SNES_LS_BASIC:
504     ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr);
505     break;
506   case SNES_LS_BASIC_NONORMS:
507     ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
508     break;
509   case SNES_LS_QUADRATIC:
510     ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_LS,PETSC_NULL);CHKERRQ(ierr);
511     break;
512   case SNES_LS_CUBIC:
513     ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_LS,PETSC_NULL);CHKERRQ(ierr);
514     break;
515   default:
516     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type.");
517     break;
518   }
519   snes->ls_type = type;
520   PetscFunctionReturn(0);
521 }
522 EXTERN_C_END
523 
524 
525 /*  --------------------------------------------------------------------
526 
527      This file implements a truncated Newton method with a line search,
528      for solving a system of nonlinear equations, using the KSP, Vec,
529      and Mat interfaces for linear solvers, vectors, and matrices,
530      respectively.
531 
532      The following basic routines are required for each nonlinear solver:
533           SNESCreate_XXX()          - Creates a nonlinear solver context
534           SNESSetFromOptions_XXX()  - Sets runtime options
535           SNESSolve_XXX()           - Solves the nonlinear system
536           SNESDestroy_XXX()         - Destroys the nonlinear solver context
537      The suffix "_XXX" denotes a particular implementation, in this case
538      we use _LS (e.g., SNESCreate_LS, SNESSolve_LS) for solving
539      systems of nonlinear equations with a line search (LS) method.
540      These routines are actually called via the common user interface
541      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
542      SNESDestroy(), so the application code interface remains identical
543      for all nonlinear solvers.
544 
545      Another key routine is:
546           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
547      by setting data structures and options.   The interface routine SNESSetUp()
548      is not usually called directly by the user, but instead is called by
549      SNESSolve() if necessary.
550 
551      Additional basic routines are:
552           SNESView_XXX()            - Prints details of runtime options that
553                                       have actually been used.
554      These are called by application codes via the interface routines
555      SNESView().
556 
557      The various types of solvers (preconditioners, Krylov subspace methods,
558      nonlinear solvers, timesteppers) are all organized similarly, so the
559      above description applies to these categories also.
560 
561     -------------------------------------------------------------------- */
562 /*
563    SNESSolve_LS - Solves a nonlinear system with a truncated Newton
564    method with a line search.
565 
566    Input Parameters:
567 .  snes - the SNES context
568 
569    Output Parameter:
570 .  outits - number of iterations until termination
571 
572    Application Interface Routine: SNESSolve()
573 
574    Notes:
575    This implements essentially a truncated Newton method with a
576    line search.  By default a cubic backtracking line search
577    is employed, as described in the text "Numerical Methods for
578    Unconstrained Optimization and Nonlinear Equations" by Dennis
579    and Schnabel.
580 */
581 #undef __FUNCT__
582 #define __FUNCT__ "SNESSolve_LS"
583 PetscErrorCode SNESSolve_LS(SNES snes)
584 {
585   PetscErrorCode     ierr;
586   PetscInt           maxits,i,lits;
587   PetscBool          lssucceed;
588   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
589   PetscReal          fnorm,gnorm,xnorm=0,ynorm;
590   Vec                Y,X,F,G,W;
591   KSPConvergedReason kspreason;
592 
593   PetscFunctionBegin;
594   snes->numFailures            = 0;
595   snes->numLinearSolveFailures = 0;
596   snes->reason                 = SNES_CONVERGED_ITERATING;
597 
598   maxits	= snes->max_its;	/* maximum number of iterations */
599   X		= snes->vec_sol;	/* solution vector */
600   F		= snes->vec_func;	/* residual vector */
601   Y		= snes->work[0];	/* work vectors */
602   G		= snes->work[1];
603   W		= snes->work[2];
604 
605   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
606   snes->iter = 0;
607   snes->norm = 0.0;
608   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
609   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
610   if (snes->domainerror) {
611     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
612     PetscFunctionReturn(0);
613   }
614   ierr = VecNormBegin(F,NORM_2,&fnorm);CHKERRQ(ierr);	/* fnorm <- ||F||  */
615   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
616   ierr = VecNormEnd(F,NORM_2,&fnorm);CHKERRQ(ierr);
617   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
618   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
619   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
620   snes->norm = fnorm;
621   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
622   SNESLogConvHistory(snes,fnorm,0);
623   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
624 
625   /* set parameter for default relative tolerance convergence test */
626   snes->ttol = fnorm*snes->rtol;
627   /* test convergence */
628   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
629   if (snes->reason) PetscFunctionReturn(0);
630 
631   for (i=0; i<maxits; i++) {
632 
633     /* Call general purpose update function */
634     if (snes->ops->update) {
635       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
636     }
637 
638     /* Solve J Y = F, where J is Jacobian matrix */
639     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
640     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
641     ierr = SNES_KSPSolve(snes,snes->ksp,F,Y);CHKERRQ(ierr);
642     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
643     if (kspreason < 0) {
644       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
645         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
646         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
647         break;
648       }
649     }
650     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
651     snes->linear_its += lits;
652     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
653 
654     if (snes->ops->precheckstep) {
655       PetscBool  changed_y = PETSC_FALSE;
656       ierr = (*snes->ops->precheckstep)(snes,X,Y,snes->precheck,&changed_y);CHKERRQ(ierr);
657     }
658 
659     if (PetscLogPrintInfo){
660       ierr = SNESLSCheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
661     }
662 
663     /* Compute a (scaled) negative update in the line search routine:
664          Y <- X - lambda*Y
665        and evaluate G = function(Y) (depends on the line search).
666     */
667     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
668     ynorm = 1; gnorm = fnorm;
669     ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Y,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
670     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);
671     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
672     if (snes->domainerror) {
673       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
674       PetscFunctionReturn(0);
675     }
676     if (!lssucceed) {
677       if (++snes->numFailures >= snes->maxFailures) {
678 	PetscBool  ismin;
679         snes->reason = SNES_DIVERGED_LINE_SEARCH;
680         ierr = SNESLSCheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
681         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
682         break;
683       }
684     }
685     /* Update function and solution vectors */
686     fnorm = gnorm;
687     ierr = VecCopy(G,F);CHKERRQ(ierr);
688     ierr = VecCopy(W,X);CHKERRQ(ierr);
689     /* Monitor convergence */
690     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
691     snes->iter = i+1;
692     snes->norm = fnorm;
693     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
694     SNESLogConvHistory(snes,snes->norm,lits);
695     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
696     /* Test for convergence, xnorm = || X || */
697     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
698     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
699     if (snes->reason) break;
700   }
701   if (i == maxits) {
702     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
703     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
704   }
705   PetscFunctionReturn(0);
706 }
707 /* -------------------------------------------------------------------------- */
708 /*
709    SNESSetUp_LS - Sets up the internal data structures for the later use
710    of the SNESLS nonlinear solver.
711 
712    Input Parameter:
713 .  snes - the SNES context
714 .  x - the solution vector
715 
716    Application Interface Routine: SNESSetUp()
717 
718    Notes:
719    For basic use of the SNES solvers, the user need not explicitly call
720    SNESSetUp(), since these actions will automatically occur during
721    the call to SNESSolve().
722  */
723 #undef __FUNCT__
724 #define __FUNCT__ "SNESSetUp_LS"
725 PetscErrorCode SNESSetUp_LS(SNES snes)
726 {
727   PetscErrorCode ierr;
728 
729   PetscFunctionBegin;
730   ierr = SNESDefaultGetWork(snes,3);CHKERRQ(ierr);
731   PetscFunctionReturn(0);
732 }
733 /* -------------------------------------------------------------------------- */
734 
735 #undef __FUNCT__
736 #define __FUNCT__ "SNESReset_LS"
737 PetscErrorCode SNESReset_LS(SNES snes)
738 {
739   PetscErrorCode ierr;
740 
741   PetscFunctionBegin;
742   if (snes->work) {ierr = VecDestroyVecs(snes->nwork,&snes->work);CHKERRQ(ierr);}
743   PetscFunctionReturn(0);
744 }
745 
746 /*
747    SNESDestroy_LS - Destroys the private SNES_LS context that was created
748    with SNESCreate_LS().
749 
750    Input Parameter:
751 .  snes - the SNES context
752 
753    Application Interface Routine: SNESDestroy()
754  */
755 #undef __FUNCT__
756 #define __FUNCT__ "SNESDestroy_LS"
757 PetscErrorCode SNESDestroy_LS(SNES snes)
758 {
759   PetscErrorCode ierr;
760 
761   PetscFunctionBegin;
762   ierr = SNESReset_LS(snes);CHKERRQ(ierr);
763   ierr = PetscFree(snes->data);CHKERRQ(ierr);
764 
765   PetscFunctionReturn(0);
766 }
767 /* -------------------------------------------------------------------------- */
768 
769 /*
770    SNESView_LS - Prints info from the SNESLS data structure.
771 
772    Input Parameters:
773 .  SNES - the SNES context
774 .  viewer - visualization context
775 
776    Application Interface Routine: SNESView()
777 */
778 #undef __FUNCT__
779 #define __FUNCT__ "SNESView_LS"
780 static PetscErrorCode SNESView_LS(SNES snes,PetscViewer viewer)
781 {
782   const char     *cstr;
783   PetscErrorCode ierr;
784   PetscBool      iascii;
785 
786   PetscFunctionBegin;
787   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
788   if (iascii) {
789     cstr = SNESLineSearchTypeName(snes->ls_type);
790     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
791     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%14.12e, maxstep=%14.12e, minlambda=%14.12e\n",(double)snes->ls_alpha,(double)snes->maxstep,(double)snes->steptol);CHKERRQ(ierr);
792     ierr = PetscViewerASCIIPrintf(viewer,"  damping factor=%14.12e\n",(double)snes->damping);CHKERRQ(ierr);
793   }
794   PetscFunctionReturn(0);
795 }
796 
797 /* -------------------------------------------------------------------------- */
798 /*
799    SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.
800 
801    Input Parameter:
802 .  snes - the SNES context
803 
804    Application Interface Routine: SNESSetFromOptions()
805 */
806 #undef __FUNCT__
807 #define __FUNCT__ "SNESSetFromOptions_LS"
808 static PetscErrorCode SNESSetFromOptions_LS(SNES snes)
809 {
810   PetscErrorCode ierr;
811 
812   PetscFunctionBegin;
813   ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr);
814   ierr = PetscOptionsTail();CHKERRQ(ierr);
815   PetscFunctionReturn(0);
816 }
817 
818 /* -------------------------------------------------------------------------- */
819 /*MC
820       SNESLS - Newton based nonlinear solver that uses a line search
821 
822    Options Database:
823 +   -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
824 .   -snes_ls_alpha <alpha> - Sets alpha used in determining if reduction in function norm is sufficient
825 .   -snes_ls_maxstep <maxstep> - Sets the maximum stepsize the line search will use (if the 2-norm(y) > maxstep then scale y to be y = (maxstep/2-norm(y)) *y)
826 .   -snes_ls_minlambda <minlambda>  - Sets the minimum lambda the line search will use  minlambda / max_i ( y[i]/x[i] )
827 .   -snes_ls_monitor - print information about progress of line searches
828 -   -snes_ls_damping - damping factor used if -snes_ls is basic or basicnonorms
829 
830 
831     Notes: This is the default nonlinear solver in SNES
832 
833    Level: beginner
834 
835 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
836            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
837           SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
838 
839 M*/
840 EXTERN_C_BEGIN
841 #undef __FUNCT__
842 #define __FUNCT__ "SNESCreate_LS"
843 PetscErrorCode  SNESCreate_LS(SNES snes)
844 {
845   PetscErrorCode ierr;
846   SNES_LS        *neP;
847 
848   PetscFunctionBegin;
849   snes->ops->setup           = SNESSetUp_LS;
850   snes->ops->solve           = SNESSolve_LS;
851   snes->ops->destroy         = SNESDestroy_LS;
852   snes->ops->setfromoptions  = SNESSetFromOptions_LS;
853   snes->ops->view            = SNESView_LS;
854   snes->ops->reset           = SNESReset_LS;
855 
856   snes->usesksp                      = PETSC_TRUE;
857   snes->usespc                       = PETSC_FALSE;
858   ierr                               = PetscNewLog(snes,SNES_LS,&neP);CHKERRQ(ierr);
859   snes->data                         = (void*)neP;
860   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_LS",SNESLineSearchSetType_LS);CHKERRQ(ierr);
861   ierr = SNESLineSearchSetType(snes, SNES_LS_CUBIC);CHKERRQ(ierr);
862   PetscFunctionReturn(0);
863 }
864 EXTERN_C_END
865