xref: /petsc/src/snes/impls/ls/ls.c (revision 406556e62e20e5b64e64821a9e0a8a010c728d34)
15e76c431SBarry Smith #ifndef lint
2*406556e6SLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.89 1997/04/21 20:09:04 curfman Exp curfman $";
35e76c431SBarry Smith #endif
45e76c431SBarry Smith 
55e76c431SBarry Smith #include <math.h>
670f55243SBarry Smith #include "src/snes/impls/ls/ls.h"
7b16a3bb1SBarry Smith #include "pinclude/pviewer.h"
85e42470aSBarry Smith 
95e42470aSBarry Smith /*
105e42470aSBarry Smith      Implements a line search variant of Newton's Method
115e76c431SBarry Smith     for solving systems of nonlinear equations.
125e76c431SBarry Smith 
135e76c431SBarry Smith     Input parameters:
145e42470aSBarry Smith .   snes - nonlinear context obtained from SNESCreate()
155e76c431SBarry Smith 
165e42470aSBarry Smith     Output Parameters:
17a935fc98SLois Curfman McInnes .   outits  - Number of global iterations until termination.
185e76c431SBarry Smith 
195e76c431SBarry Smith     Notes:
205e76c431SBarry Smith     This implements essentially a truncated Newton method with a
215e76c431SBarry Smith     line search.  By default a cubic backtracking line search
225e76c431SBarry Smith     is employed, as described in the text "Numerical Methods for
235e76c431SBarry Smith     Unconstrained Optimization and Nonlinear Equations" by Dennis
24393d2d9aSLois Curfman McInnes     and Schnabel.
255e76c431SBarry Smith */
265e76c431SBarry Smith 
275615d1e5SSatish Balay #undef __FUNC__
285615d1e5SSatish Balay #define __FUNC__ "SNESSolve_EQ_LS"
29f63b844aSLois Curfman McInnes int SNESSolve_EQ_LS(SNES snes,int *outits)
305e76c431SBarry Smith {
315e42470aSBarry Smith   SNES_LS       *neP = (SNES_LS *) snes->data;
32761aaf1bSLois Curfman McInnes   int           maxits, i, history_len, ierr, lits, lsfail;
33112a2221SBarry Smith   MatStructure  flg = DIFFERENT_NONZERO_PATTERN;
346b5873e3SBarry Smith   double        fnorm, gnorm, xnorm, ynorm, *history;
355e42470aSBarry Smith   Vec           Y, X, F, G, W, TMP;
365e76c431SBarry Smith 
375e42470aSBarry Smith   history	= snes->conv_hist;	/* convergence history */
3851979daaSLois Curfman McInnes   history_len	= snes->conv_hist_size;	/* convergence history length */
395e42470aSBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
405e42470aSBarry Smith   X		= snes->vec_sol;	/* solution vector */
4139e2f89bSBarry Smith   F		= snes->vec_func;	/* residual vector */
425e42470aSBarry Smith   Y		= snes->work[0];	/* work vectors */
435e42470aSBarry Smith   G		= snes->work[1];
445e42470aSBarry Smith   W		= snes->work[2];
455e76c431SBarry Smith 
46cddf8d76SBarry Smith   ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);       /* xnorm = || X || */
4725ed9cd1SBarry Smith   snes->iter = 0;
485334005bSBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);  /*  F(X)      */
49cddf8d76SBarry Smith   ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr);	/* fnorm <- ||F||  */
505e42470aSBarry Smith   snes->norm = fnorm;
5151979daaSLois Curfman McInnes   if (history) history[0] = fnorm;
5294a424c1SBarry Smith   SNESMonitor(snes,0,fnorm);
535e76c431SBarry Smith 
5494a9d846SBarry Smith   if (fnorm == 0.0) {outits = 0; return 0;}
5594a9d846SBarry Smith 
56d034289bSBarry Smith   /* set parameter for default relative tolerance convergence test */
57d034289bSBarry Smith   snes->ttol = fnorm*snes->rtol;
58d034289bSBarry Smith 
595e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
605e42470aSBarry Smith     snes->iter = i+1;
615e76c431SBarry Smith 
62ea4d3ed3SLois Curfman McInnes     /* Solve J Y = F, where J is Jacobian matrix */
635334005bSBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr);
645334005bSBarry Smith     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
6578b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
667a00f4a9SLois Curfman McInnes     snes->linear_its += PetscAbsInt(lits);
67af1ccdebSLois Curfman McInnes     PLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
68ea4d3ed3SLois Curfman McInnes 
69ea4d3ed3SLois Curfman McInnes     /* Compute a (scaled) negative update in the line search routine:
70ea4d3ed3SLois Curfman McInnes          Y <- X - lambda*Y
71ea4d3ed3SLois Curfman McInnes        and evaluate G(Y) = function(Y))
72ea4d3ed3SLois Curfman McInnes     */
7381b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
74ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr);
75af1ccdebSLois Curfman McInnes     PLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
76761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
775e76c431SBarry Smith 
7839e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
7939e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
805e76c431SBarry Smith     fnorm = gnorm;
815e76c431SBarry Smith 
825e42470aSBarry Smith     snes->norm = fnorm;
835e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
84cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
8594a424c1SBarry Smith     SNESMonitor(snes,i+1,fnorm);
865e76c431SBarry Smith 
875e76c431SBarry Smith     /* Test for convergence */
88bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
8916c95cacSBarry Smith       break;
9016c95cacSBarry Smith     }
9116c95cacSBarry Smith   }
9239e2f89bSBarry Smith   if (X != snes->vec_sol) {
93393d2d9aSLois Curfman McInnes     ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
9439e2f89bSBarry Smith     snes->vec_sol_always  = snes->vec_sol;
9539e2f89bSBarry Smith     snes->vec_func_always = snes->vec_func;
9639e2f89bSBarry Smith   }
9752392280SLois Curfman McInnes   if (i == maxits) {
9894a424c1SBarry Smith     PLogInfo(snes,
99f63b844aSLois Curfman McInnes       "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
10052392280SLois Curfman McInnes     i--;
10152392280SLois Curfman McInnes   }
10251979daaSLois Curfman McInnes   if (history) snes->conv_act_size = (history_len < i+1) ? history_len : i+1;
1035e42470aSBarry Smith   *outits = i+1;
1045e42470aSBarry Smith   return 0;
1055e76c431SBarry Smith }
1065e76c431SBarry Smith /* ------------------------------------------------------------ */
1075615d1e5SSatish Balay #undef __FUNC__
1085615d1e5SSatish Balay #define __FUNC__ "SNESSetUp_EQ_LS"
109f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes )
1105e76c431SBarry Smith {
1115e42470aSBarry Smith   int ierr;
11281b6cf68SLois Curfman McInnes   snes->nwork = 4;
113d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
1145e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
11581b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1165e42470aSBarry Smith   return 0;
1175e76c431SBarry Smith }
1185e76c431SBarry Smith /* ------------------------------------------------------------ */
1195615d1e5SSatish Balay #undef __FUNC__
1205eea60f9SBarry Smith #define __FUNC__ "SNESDestroy_EQ_LS" /* ADIC Ignore */
121f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj)
1225e76c431SBarry Smith {
1235e42470aSBarry Smith   SNES snes = (SNES) obj;
124393d2d9aSLois Curfman McInnes   int  ierr;
1255baf8537SBarry Smith   if (snes->nwork) {
1264b0e389bSBarry Smith     ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
12721c89e3eSBarry Smith   }
1280452661fSBarry Smith   PetscFree(snes->data);
1295e42470aSBarry Smith   return 0;
1305e76c431SBarry Smith }
1315e76c431SBarry Smith /* ------------------------------------------------------------ */
1325615d1e5SSatish Balay #undef __FUNC__
1335615d1e5SSatish Balay #define __FUNC__ "SNESNoLineSearch"
1345e76c431SBarry Smith /*ARGSUSED*/
1354b828684SBarry Smith /*@C
1365e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1375e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1385e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1395e76c431SBarry Smith 
1405e76c431SBarry Smith    Input Parameters:
1415e42470aSBarry Smith .  snes - nonlinear context
1425e76c431SBarry Smith .  x - current iterate
1435e76c431SBarry Smith .  f - residual evaluated at x
1445e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1455e76c431SBarry Smith .  w - work vector
1465e76c431SBarry Smith .  fnorm - 2-norm of f
1475e76c431SBarry Smith 
148c4a48953SLois Curfman McInnes    Output Parameters:
1495e76c431SBarry Smith .  g - residual evaluated at new iterate y
1505e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1515e76c431SBarry Smith .  gnorm - 2-norm of g
1525e76c431SBarry Smith .  ynorm - 2-norm of search length
153761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1545e76c431SBarry Smith 
155c4a48953SLois Curfman McInnes    Options Database Key:
15609d61ba7SLois Curfman McInnes $  -snes_eq_ls basic
157c4a48953SLois Curfman McInnes 
15828ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
15928ae5a21SLois Curfman McInnes 
160f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
16177c4ece6SBarry Smith           SNESSetLineSearch()
1625e76c431SBarry Smith @*/
1635e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
164761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1655e76c431SBarry Smith {
1665e42470aSBarry Smith   int    ierr;
1675334005bSBarry Smith   Scalar mone = -1.0;
1685334005bSBarry Smith 
169761aaf1bSLois Curfman McInnes   *flag = 0;
1707857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
171cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);       /* ynorm = || y || */
172ea4d3ed3SLois Curfman McInnes   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);            /* y <- y - x      */
173ea4d3ed3SLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y)    */
174cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);       /* gnorm = || g || */
1757857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
176761aaf1bSLois Curfman McInnes   return 0;
1775e76c431SBarry Smith }
1785e76c431SBarry Smith /* ------------------------------------------------------------------ */
1795615d1e5SSatish Balay #undef __FUNC__
1805615d1e5SSatish Balay #define __FUNC__ "SNESCubicLineSearch"
1814b828684SBarry Smith /*@C
182f525115eSLois Curfman McInnes    SNESCubicLineSearch - Performs a cubic line search (default line search method).
1835e76c431SBarry Smith 
1845e76c431SBarry Smith    Input Parameters:
1855e42470aSBarry Smith .  snes - nonlinear context
1865e76c431SBarry Smith .  x - current iterate
1875e76c431SBarry Smith .  f - residual evaluated at x
1885e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1895e76c431SBarry Smith .  w - work vector
1905e76c431SBarry Smith .  fnorm - 2-norm of f
1915e76c431SBarry Smith 
192393d2d9aSLois Curfman McInnes    Output Parameters:
1935e76c431SBarry Smith .  g - residual evaluated at new iterate y
1945e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1955e76c431SBarry Smith .  gnorm - 2-norm of g
1965e76c431SBarry Smith .  ynorm - 2-norm of search length
197761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1985e76c431SBarry Smith 
199c4a48953SLois Curfman McInnes    Options Database Key:
20009d61ba7SLois Curfman McInnes $  -snes_eq_ls cubic
201c4a48953SLois Curfman McInnes 
2025e76c431SBarry Smith    Notes:
2035e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
2045e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
2055e76c431SBarry Smith 
20628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
20728ae5a21SLois Curfman McInnes 
20877c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
2095e76c431SBarry Smith @*/
2105e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w,
211761aaf1bSLois Curfman McInnes                         double fnorm,double *ynorm,double *gnorm,int *flag)
2125e76c431SBarry Smith {
213*406556e6SLois Curfman McInnes   /*
214*406556e6SLois Curfman McInnes      Note that for line search purposes we work with with the related
215*406556e6SLois Curfman McInnes      minimization problem:
216*406556e6SLois Curfman McInnes         min  z(x):  R^n -> R,
217*406556e6SLois Curfman McInnes      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
218*406556e6SLois Curfman McInnes    */
219*406556e6SLois Curfman McInnes 
220ddd12767SBarry Smith   double  steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2;
221ea4d3ed3SLois Curfman McInnes   double  maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg;
2226b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2235e42470aSBarry Smith   Scalar  cinitslope, clambda;
2246b5873e3SBarry Smith #endif
2255e42470aSBarry Smith   int     ierr, count;
2265e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2275334005bSBarry Smith   Scalar  mone = -1.0,scale;
2285e76c431SBarry Smith 
2297857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
230761aaf1bSLois Curfman McInnes   *flag   = 0;
2315e76c431SBarry Smith   alpha   = neP->alpha;
2325e76c431SBarry Smith   maxstep = neP->maxstep;
2335e76c431SBarry Smith   steptol = neP->steptol;
2345e76c431SBarry Smith 
235cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
23694a9d846SBarry Smith   if (*ynorm == 0.0) {
23794a9d846SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Search direction and size is 0\n");
238ad922ac9SBarry Smith     goto theend1;
23994a9d846SBarry Smith   }
2405e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2415e42470aSBarry Smith     scale = maxstep/(*ynorm);
2426b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
24394a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2446b5873e3SBarry Smith #else
24594a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2466b5873e3SBarry Smith #endif
247393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2485e76c431SBarry Smith     *ynorm = maxstep;
2495e76c431SBarry Smith   }
2505e76c431SBarry Smith   minlambda = steptol/(*ynorm);
251a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2525e42470aSBarry Smith #if defined(PETSC_COMPLEX)
253a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2545e42470aSBarry Smith   initslope = real(cinitslope);
2555e42470aSBarry Smith #else
256a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2575e42470aSBarry Smith #endif
2585e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2595e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2605e76c431SBarry Smith 
261393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2625334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
26378b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
264cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
265*406556e6SLois Curfman McInnes   if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* Sufficient reduction */
266393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
26794a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
268ad922ac9SBarry Smith     goto theend1;
2695e76c431SBarry Smith   }
2705e76c431SBarry Smith 
2715e76c431SBarry Smith   /* Fit points with quadratic */
2725e76c431SBarry Smith   lambda = 1.0; count = 0;
273a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2745e76c431SBarry Smith   lambdaprev = lambda;
2755e76c431SBarry Smith   gnormprev = *gnorm;
276ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
277ddd12767SBarry Smith   else lambda = lambdatemp;
278393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
279ea4d3ed3SLois Curfman McInnes   lambdaneg = -lambda;
2805e42470aSBarry Smith #if defined(PETSC_COMPLEX)
281ea4d3ed3SLois Curfman McInnes   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2825e42470aSBarry Smith #else
283ea4d3ed3SLois Curfman McInnes   ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
2845e42470aSBarry Smith #endif
28578b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
286cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
287*406556e6SLois Curfman McInnes   if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* sufficient reduction */
288393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
289ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda);
290ad922ac9SBarry Smith     goto theend1;
2915e76c431SBarry Smith   }
2925e76c431SBarry Smith 
2935e76c431SBarry Smith   /* Fit points with cubic */
2945e76c431SBarry Smith   count = 1;
2955e76c431SBarry Smith   while (1) {
2965e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
2972b022350SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count);
2982b022350SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
299ea4d3ed3SLois Curfman McInnes                fnorm,*gnorm,*ynorm,lambda,initslope);
300393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
301761aaf1bSLois Curfman McInnes       *flag = -1; break;
3025e76c431SBarry Smith     }
303*406556e6SLois Curfman McInnes     t1 = ((*gnorm)*(*gnorm) - fnorm*fnorm)*0.5 - lambda*initslope;
304*406556e6SLois Curfman McInnes     t2 = (gnormprev*gnormprev  - fnorm*fnorm)*0.5 - lambdaprev*initslope;
305ddd12767SBarry Smith     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3062b022350SLois Curfman McInnes     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3075e76c431SBarry Smith     d  = b*b - 3*a*initslope;
3085e76c431SBarry Smith     if (d < 0.0) d = 0.0;
3095e76c431SBarry Smith     if (a == 0.0) {
3105e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
3115e76c431SBarry Smith     } else {
3125e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
3135e76c431SBarry Smith     }
3145e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
3155e76c431SBarry Smith       lambdatemp = .5*lambda;
3165e76c431SBarry Smith     }
3175e76c431SBarry Smith     lambdaprev = lambda;
3185e76c431SBarry Smith     gnormprev = *gnorm;
3195e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
3205e76c431SBarry Smith       lambda = .1*lambda;
3215e76c431SBarry Smith     }
3225e76c431SBarry Smith     else lambda = lambdatemp;
323393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
324ea4d3ed3SLois Curfman McInnes     lambdaneg = -lambda;
3255e42470aSBarry Smith #if defined(PETSC_COMPLEX)
326ea4d3ed3SLois Curfman McInnes     clambda = lambdaneg;
327393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3285e42470aSBarry Smith #else
329ea4d3ed3SLois Curfman McInnes     ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
3305e42470aSBarry Smith #endif
33178b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
332cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
333*406556e6SLois Curfman McInnes     if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* is reduction enough? */
334393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
335ea4d3ed3SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
3362715565aSLois Curfman McInnes       goto theend1;
3372b022350SLois Curfman McInnes     } else {
3382b022350SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda,  lambda=%g\n",lambda);
3395e76c431SBarry Smith     }
3405e76c431SBarry Smith     count++;
3415e76c431SBarry Smith   }
342ad922ac9SBarry Smith   theend1:
3437857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3445e42470aSBarry Smith   return 0;
3455e76c431SBarry Smith }
34652392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3475615d1e5SSatish Balay #undef __FUNC__
3485615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch"
3494b828684SBarry Smith /*@C
350f525115eSLois Curfman McInnes    SNESQuadraticLineSearch - Performs a quadratic line search.
3515e76c431SBarry Smith 
3525e42470aSBarry Smith    Input Parameters:
353f59ffdedSLois Curfman McInnes .  snes - the SNES context
3545e42470aSBarry Smith .  x - current iterate
3555e42470aSBarry Smith .  f - residual evaluated at x
3565e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3575e42470aSBarry Smith .  w - work vector
3585e42470aSBarry Smith .  fnorm - 2-norm of f
3595e42470aSBarry Smith 
360c4a48953SLois Curfman McInnes    Output Parameters:
3615e42470aSBarry Smith .  g - residual evaluated at new iterate y
3625e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3635e42470aSBarry Smith .  gnorm - 2-norm of g
3645e42470aSBarry Smith .  ynorm - 2-norm of search length
365761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3665e42470aSBarry Smith 
367c4a48953SLois Curfman McInnes    Options Database Key:
36809d61ba7SLois Curfman McInnes $  -snes_eq_ls quadratic
369c4a48953SLois Curfman McInnes 
3705e42470aSBarry Smith    Notes:
37177c4ece6SBarry Smith    Use SNESSetLineSearch()
372f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3735e42470aSBarry Smith 
374f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
375f59ffdedSLois Curfman McInnes 
37677c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3775e42470aSBarry Smith @*/
3785e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
379761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3805e76c431SBarry Smith {
381*406556e6SLois Curfman McInnes   /*
382*406556e6SLois Curfman McInnes      Note that for line search purposes we work with with the related
383*406556e6SLois Curfman McInnes      minimization problem:
384*406556e6SLois Curfman McInnes         min  z(x):  R^n -> R,
385*406556e6SLois Curfman McInnes      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
386*406556e6SLois Curfman McInnes    */
387ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3886b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3895e42470aSBarry Smith   Scalar  cinitslope,clambda;
3906b5873e3SBarry Smith #endif
3915e42470aSBarry Smith   int     ierr,count;
3925e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3935334005bSBarry Smith   Scalar  mone = -1.0,scale;
3945e76c431SBarry Smith 
3957857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
396761aaf1bSLois Curfman McInnes   *flag = 0;
3975e42470aSBarry Smith   alpha   = neP->alpha;
3985e42470aSBarry Smith   maxstep = neP->maxstep;
3995e42470aSBarry Smith   steptol = neP->steptol;
4005e76c431SBarry Smith 
401cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
40294a9d846SBarry Smith   if (*ynorm == 0.0) {
40394a9d846SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n");
404ad922ac9SBarry Smith     goto theend2;
40594a9d846SBarry Smith   }
4065e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
4075e42470aSBarry Smith     scale = maxstep/(*ynorm);
408393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
4095e42470aSBarry Smith     *ynorm = maxstep;
4105e76c431SBarry Smith   }
4115e42470aSBarry Smith   minlambda = steptol/(*ynorm);
412a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
4135e42470aSBarry Smith #if defined(PETSC_COMPLEX)
414a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
4155e42470aSBarry Smith   initslope = real(cinitslope);
4165e42470aSBarry Smith #else
417a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
4185e42470aSBarry Smith #endif
4195e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
4205e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
4215e42470aSBarry Smith 
422393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
4235334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
42478b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
425cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
426*406556e6SLois Curfman McInnes   if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* Sufficient reduction */
427393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
42894a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
429ad922ac9SBarry Smith     goto theend2;
4305e42470aSBarry Smith   }
4315e42470aSBarry Smith 
4325e42470aSBarry Smith   /* Fit points with quadratic */
4335e42470aSBarry Smith   lambda = 1.0; count = 0;
4345e42470aSBarry Smith   count = 1;
4355e42470aSBarry Smith   while (1) {
4365e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
43794a424c1SBarry Smith       PLogInfo(snes,
4384b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
43994a424c1SBarry Smith       PLogInfo(snes,
440ea4d3ed3SLois Curfman McInnes       "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
441ea4d3ed3SLois Curfman McInnes           fnorm,*gnorm,*ynorm,lambda,initslope);
442393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
443761aaf1bSLois Curfman McInnes       *flag = -1; break;
4445e42470aSBarry Smith     }
445a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4465e42470aSBarry Smith     lambdaprev = lambda;
4475e42470aSBarry Smith     gnormprev = *gnorm;
4485e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4495e42470aSBarry Smith       lambda = .1*lambda;
4505e42470aSBarry Smith     } else lambda = lambdatemp;
451393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4525334005bSBarry Smith     lambda = -lambda;
4535e42470aSBarry Smith #if defined(PETSC_COMPLEX)
454393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4555e42470aSBarry Smith #else
456393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4575e42470aSBarry Smith #endif
45878b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
459cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
460*406556e6SLois Curfman McInnes     if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* sufficient reduction */
461393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
46294a424c1SBarry Smith       PLogInfo(snes,
463ea4d3ed3SLois Curfman McInnes         "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
46406259719SBarry Smith       break;
4655e42470aSBarry Smith     }
4665e42470aSBarry Smith     count++;
4675e42470aSBarry Smith   }
468ad922ac9SBarry Smith   theend2:
4697857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4705e42470aSBarry Smith   return 0;
4715e76c431SBarry Smith }
4725e76c431SBarry Smith /* ------------------------------------------------------------ */
4735615d1e5SSatish Balay #undef __FUNC__
4745eea60f9SBarry Smith #define __FUNC__ "SNESSetLineSearch" /* ADIC Ignore */
475c9e6a524SLois Curfman McInnes /*@C
47677c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
477f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4785e76c431SBarry Smith 
4795e76c431SBarry Smith    Input Parameters:
480eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4815e76c431SBarry Smith .  func - pointer to int function
4825e76c431SBarry Smith 
483c4a48953SLois Curfman McInnes    Available Routines:
484f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
485f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
486f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4875e76c431SBarry Smith 
488c4a48953SLois Curfman McInnes     Options Database Keys:
48909d61ba7SLois Curfman McInnes $   -snes_eq_ls [basic,quadratic,cubic]
490912ebf9aSLois Curfman McInnes $   -snes_eq_ls_alpha <alpha>
491912ebf9aSLois Curfman McInnes $   -snes_eq_ls_maxstep <max>
492912ebf9aSLois Curfman McInnes $   -snes_eq_ls_steptol <steptol>
493c4a48953SLois Curfman McInnes 
4945e76c431SBarry Smith    Calling sequence of func:
495f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
496761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
497761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4985e76c431SBarry Smith 
4995e76c431SBarry Smith     Input parameters for func:
5005e42470aSBarry Smith .   snes - nonlinear context
5015e76c431SBarry Smith .   x - current iterate
5025e76c431SBarry Smith .   f - residual evaluated at x
5035e76c431SBarry Smith .   y - search direction (contains new iterate on output)
5045e76c431SBarry Smith .   w - work vector
5055e76c431SBarry Smith .   fnorm - 2-norm of f
5065e76c431SBarry Smith 
5075e76c431SBarry Smith     Output parameters for func:
5085e76c431SBarry Smith .   g - residual evaluated at new iterate y
5095e76c431SBarry Smith .   y - new iterate (contains search direction on input)
5105e76c431SBarry Smith .   gnorm - 2-norm of g
5115e76c431SBarry Smith .   ynorm - 2-norm of search length
512761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
513761aaf1bSLois Curfman McInnes            on failure.
514f59ffdedSLois Curfman McInnes 
515f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
516f59ffdedSLois Curfman McInnes 
517f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
5185e76c431SBarry Smith @*/
51977c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
520761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
5215e76c431SBarry Smith {
522f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
5235e42470aSBarry Smith   return 0;
5245e76c431SBarry Smith }
52552392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5265615d1e5SSatish Balay #undef __FUNC__
5275eea60f9SBarry Smith #define __FUNC__ "SNESPrintHelp_EQ_LS" /* ADIC Ignore */
528f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
5295e42470aSBarry Smith {
5305e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5316daaf66cSBarry Smith 
532f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
53309d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls [basic,quadratic,cubic]\n",p);
53409d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
53509d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
53609d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol);
5376b5873e3SBarry Smith   return 0;
5385e42470aSBarry Smith }
53952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5405615d1e5SSatish Balay #undef __FUNC__
5415eea60f9SBarry Smith #define __FUNC__ "SNESView_EQ_LS" /* ADIC Ignore */
542f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
543a935fc98SLois Curfman McInnes {
544a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
545a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
546d636dbe3SBarry Smith   FILE       *fd;
54719bcc07fSBarry Smith   char       *cstr;
54851695f54SLois Curfman McInnes   int        ierr;
54919bcc07fSBarry Smith   ViewerType vtype;
550a935fc98SLois Curfman McInnes 
55119bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
55219bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
55390ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
55419bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
55519bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
55619bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
55719bcc07fSBarry Smith     else cstr = "unknown";
55877c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
55977c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
560a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
56119bcc07fSBarry Smith   }
562a935fc98SLois Curfman McInnes   return 0;
563a935fc98SLois Curfman McInnes }
56452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5655615d1e5SSatish Balay #undef __FUNC__
5665615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS"
567f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5685e42470aSBarry Smith {
5695e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5705e42470aSBarry Smith   char    ver[16];
5715e42470aSBarry Smith   double  tmp;
57225cdf11fSBarry Smith   int     ierr,flg;
5735e42470aSBarry Smith 
57409d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr);
57525cdf11fSBarry Smith   if (flg) {
5765e42470aSBarry Smith     ls->alpha = tmp;
5775e42470aSBarry Smith   }
57809d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr);
57925cdf11fSBarry Smith   if (flg) {
5805e42470aSBarry Smith     ls->maxstep = tmp;
5815e42470aSBarry Smith   }
58209d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr);
58325cdf11fSBarry Smith   if (flg) {
5845e42470aSBarry Smith     ls->steptol = tmp;
5855e42470aSBarry Smith   }
58609d61ba7SLois Curfman McInnes   ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr);
58725cdf11fSBarry Smith   if (flg) {
58848d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
58977c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5905e42470aSBarry Smith     }
59148d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
59277c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5935e42470aSBarry Smith     }
59448d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
59577c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5965e42470aSBarry Smith     }
597e3372554SBarry Smith     else {SETERRQ(1,0,"Unknown line search");}
5985e42470aSBarry Smith   }
5995e42470aSBarry Smith   return 0;
6005e42470aSBarry Smith }
6015e42470aSBarry Smith /* ------------------------------------------------------------ */
6025615d1e5SSatish Balay #undef __FUNC__
6035615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS"
604f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
6055e42470aSBarry Smith {
6065e42470aSBarry Smith   SNES_LS *neP;
6075e42470aSBarry Smith 
608ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
609e3372554SBarry Smith     SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only");
610f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
611f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
612f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
613f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
614f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
615f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
616f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
617f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
6185baf8537SBarry Smith   snes->nwork           = 0;
6195e42470aSBarry Smith 
6200452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
621ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
6225e42470aSBarry Smith   snes->data    	= (void *) neP;
6235e42470aSBarry Smith   neP->alpha		= 1.e-4;
6245e42470aSBarry Smith   neP->maxstep		= 1.e8;
6255e42470aSBarry Smith   neP->steptol		= 1.e-12;
6265e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
6275e42470aSBarry Smith   return 0;
6285e42470aSBarry Smith }
6295e42470aSBarry Smith 
630