xref: /petsc/src/snes/impls/ls/ls.c (revision d93a2b8d0462e3d094dea4dad545188cef485173)
15e76c431SBarry Smith #ifndef lint
2*d93a2b8dSBarry Smith static char vcid[] = "$Id: ls.c,v 1.27 1995/06/29 23:54:19 bsmith Exp bsmith $";
35e76c431SBarry Smith #endif
45e76c431SBarry Smith 
55e76c431SBarry Smith #include <math.h>
6fbe28522SBarry Smith #include "ls.h"
75e42470aSBarry Smith 
85e42470aSBarry Smith /*
95e42470aSBarry Smith      Implements a line search variant of Newton's Method
105e76c431SBarry Smith     for solving systems of nonlinear equations.
115e76c431SBarry Smith 
125e76c431SBarry Smith     Input parameters:
135e42470aSBarry Smith .   snes - nonlinear context obtained from SNESCreate()
145e76c431SBarry Smith 
155e42470aSBarry Smith     Output Parameters:
165e42470aSBarry Smith .   its  - Number of global iterations until termination.
175e76c431SBarry Smith 
185e76c431SBarry Smith     Notes:
195e42470aSBarry Smith     See SNESCreate() and SNESSetUp() for information on the definition and
205e76c431SBarry Smith     initialization of the nonlinear solver context.
215e76c431SBarry Smith 
225e76c431SBarry Smith     This implements essentially a truncated Newton method with a
235e76c431SBarry Smith     line search.  By default a cubic backtracking line search
245e76c431SBarry Smith     is employed, as described in the text "Numerical Methods for
255e76c431SBarry Smith     Unconstrained Optimization and Nonlinear Equations" by Dennis
265e42470aSBarry Smith     and Schnabel.  See the examples in src/snes/examples.
275e76c431SBarry Smith */
285e76c431SBarry Smith 
295e42470aSBarry Smith int SNESSolve_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;
33df60cc22SBarry Smith   MatStructure flg = ALLMAT_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 */
385e42470aSBarry Smith   history_len	= snes->conv_hist_len;	/* 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 
4678b31e54SBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr);  /* X <- X_0 */
475e42470aSBarry Smith   VecNorm( X, &xnorm );		       /* xnorm = || X || */
4878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* (+/-) F(X) */
495e42470aSBarry Smith   VecNorm(F, &fnorm );	        	/* fnorm <- || F || */
505e42470aSBarry Smith   snes->norm = fnorm;
515e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
52eafb4bcbSBarry Smith   if (snes->Monitor) (*snes->Monitor)(snes,0,fnorm,snes->monP);
535e76c431SBarry Smith 
545e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
555e42470aSBarry Smith        snes->iter = i+1;
565e76c431SBarry Smith 
575e76c431SBarry Smith        /* Solve J Y = -F, where J is Jacobian matrix */
58df60cc22SBarry Smith        ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,
5978b31e54SBarry Smith                                 &flg,snes->jacP); CHKERRQ(ierr);
6023242f5aSBarry Smith        ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg);
6178b31e54SBarry Smith        ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
6281b6cf68SLois Curfman McInnes        ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
63761aaf1bSLois Curfman McInnes        ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);
64761aaf1bSLois Curfman McInnes        if (lsfail) snes->nfailures++;
6578b31e54SBarry Smith        CHKERRQ(ierr);
665e76c431SBarry Smith 
6739e2f89bSBarry Smith        TMP = F; F = G; snes->vec_func_always = F; G = TMP;
6839e2f89bSBarry Smith        TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
695e76c431SBarry Smith        fnorm = gnorm;
705e76c431SBarry Smith 
715e42470aSBarry Smith        snes->norm = fnorm;
725e76c431SBarry Smith        if (history && history_len > i+1) history[i+1] = fnorm;
735e42470aSBarry Smith        VecNorm( X, &xnorm );		/* xnorm = || X || */
74eafb4bcbSBarry Smith        if (snes->Monitor) (*snes->Monitor)(snes,i+1,fnorm,snes->monP);
755e76c431SBarry Smith 
765e76c431SBarry Smith        /* Test for convergence */
775e42470aSBarry Smith        if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) {
7839e2f89bSBarry Smith            if (X != snes->vec_sol) {
7939e2f89bSBarry Smith              VecCopy( X, snes->vec_sol );
8039e2f89bSBarry Smith              snes->vec_sol_always = snes->vec_sol;
8139e2f89bSBarry Smith              snes->vec_func_always = snes->vec_func;
8239e2f89bSBarry Smith            }
835e76c431SBarry Smith            break;
845e76c431SBarry Smith        }
855e76c431SBarry Smith   }
865e76c431SBarry Smith   if (i == maxits) i--;
875e42470aSBarry Smith   *outits = i+1;
885e42470aSBarry Smith   return 0;
895e76c431SBarry Smith }
905e76c431SBarry Smith /* ------------------------------------------------------------ */
915e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
925e76c431SBarry Smith {
935e42470aSBarry Smith   int ierr;
9481b6cf68SLois Curfman McInnes   snes->nwork = 4;
9578b31e54SBarry Smith   ierr = VecGetVecs( snes->vec_sol, snes->nwork,&snes->work ); CHKERRQ(ierr);
965e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work );
9781b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
985e42470aSBarry Smith   return 0;
995e76c431SBarry Smith }
1005e76c431SBarry Smith /* ------------------------------------------------------------ */
1015e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
1025e76c431SBarry Smith {
1035e42470aSBarry Smith   SNES snes = (SNES) obj;
1045e42470aSBarry Smith   VecFreeVecs(snes->work, snes->nwork );
10578b31e54SBarry Smith   PETSCFREE(snes->data);
1065e42470aSBarry Smith   return 0;
1075e76c431SBarry Smith }
1085e42470aSBarry Smith /*@
1090de89847SLois Curfman McInnes    SNESDefaultMonitor - Default SNES monitoring routine.  Prints the
1105e42470aSBarry Smith    residual norm at each iteration.
1115e42470aSBarry Smith 
1125e42470aSBarry Smith    Input Parameters:
1130de89847SLois Curfman McInnes .  snes - the SNES context
1140de89847SLois Curfman McInnes .  its - iteration number
1150de89847SLois Curfman McInnes .  fnorm - 2-norm residual value (may be estimated)
1160de89847SLois Curfman McInnes .  dummy - unused context
1175e42470aSBarry Smith 
1185e42470aSBarry Smith    Notes:
1195e42470aSBarry Smith    f is either the residual or its negative, depending on the user's
120a9581db2SBarry Smith    preference, as set with SNESSetFunction().
121a67c8522SLois Curfman McInnes 
122a67c8522SLois Curfman McInnes .keywords: SNES, nonlinear, default, monitor, residual, norm
123a67c8522SLois Curfman McInnes 
124a67c8522SLois Curfman McInnes .seealso: SNESSetMonitor()
1255e42470aSBarry Smith @*/
126eafb4bcbSBarry Smith int SNESDefaultMonitor(SNES snes,int its, double fnorm,void *dummy)
1275e42470aSBarry Smith {
128614e12f8SBarry Smith   MPIU_printf(snes->comm, "iter = %d, Function norm %g \n",its,fnorm);
129614e12f8SBarry Smith   return 0;
130614e12f8SBarry Smith }
131614e12f8SBarry Smith 
132614e12f8SBarry Smith int SNESDefaultSMonitor(SNES snes,int its, double fnorm,void *dummy)
133614e12f8SBarry Smith {
134614e12f8SBarry Smith   if (fnorm > 1.e-9 || fnorm == 0.0) {
1357f813858SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm %g \n",its,fnorm);
13669e4de80SBarry Smith   }
137614e12f8SBarry Smith   else if (fnorm > 1.e-11){
13869e4de80SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm %5.3e \n",its,fnorm);
13969e4de80SBarry Smith   }
140614e12f8SBarry Smith   else {
141614e12f8SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm < 1.e-11\n",its);
142614e12f8SBarry Smith   }
1435e42470aSBarry Smith   return 0;
1445e42470aSBarry Smith }
1455e42470aSBarry Smith 
1465e42470aSBarry Smith /*@
1475e42470aSBarry Smith    SNESDefaultConverged - Default test for monitoring the convergence
1480de89847SLois Curfman McInnes    of the SNES solvers.
1495e42470aSBarry Smith 
1505e42470aSBarry Smith    Input Parameters:
1510de89847SLois Curfman McInnes .  snes - the SNES context
1525e42470aSBarry Smith .  xnorm - 2-norm of current iterate
1535e42470aSBarry Smith .  pnorm - 2-norm of current step
1545e42470aSBarry Smith .  fnorm - 2-norm of residual
1550de89847SLois Curfman McInnes .  dummy - unused context
1565e42470aSBarry Smith 
1575e42470aSBarry Smith    Returns:
1585e42470aSBarry Smith $  2  if  ( fnorm < atol ),
1595e42470aSBarry Smith $  3  if  ( pnorm < xtol*xnorm ),
1605e42470aSBarry Smith $ -2  if  ( nres > max_res ),
1615e42470aSBarry Smith $  0  otherwise,
1625e42470aSBarry Smith 
1635e42470aSBarry Smith    where
1645e42470aSBarry Smith $    atol    - absolute residual norm tolerance,
1650de89847SLois Curfman McInnes $              set with SNESSetAbsoluteTolerance()
1665e42470aSBarry Smith $    max_res - maximum number of residual evaluations,
1670de89847SLois Curfman McInnes $              set with SNESSetMaxResidualEvaluations()
1685e42470aSBarry Smith $    nres    - number of residual evaluations
1695e42470aSBarry Smith $    xtol    - relative residual norm tolerance,
1700de89847SLois Curfman McInnes $              set with SNESSetRelativeTolerance()
1715e42470aSBarry Smith 
1720de89847SLois Curfman McInnes .keywords: SNES, nonlinear, default, converged, convergence
1735e42470aSBarry Smith 
1740de89847SLois Curfman McInnes .seealso: SNESSetConvergenceTest()
1755e42470aSBarry Smith @*/
1765e42470aSBarry Smith int SNESDefaultConverged(SNES snes,double xnorm,double pnorm,double fnorm,
1775e42470aSBarry Smith                          void *dummy)
1785e42470aSBarry Smith {
1795e42470aSBarry Smith   if (fnorm < snes->atol) {
180a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
181a67c8522SLois Curfman McInnes       "Converged due to absolute residual norm %g < %g\n",fnorm,snes->atol);
1825e42470aSBarry Smith     return 2;
1835e42470aSBarry Smith   }
1845e42470aSBarry Smith   if (pnorm < snes->xtol*(xnorm)) {
185a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
186a67c8522SLois Curfman McInnes       "Converged due to small update length  %g < %g*%g\n",
1875e42470aSBarry Smith        pnorm,snes->xtol,xnorm);
1885e42470aSBarry Smith     return 3;
1895e42470aSBarry Smith   }
19049e3953dSBarry Smith   if (snes->nfuncs > snes->max_funcs) {
191a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
192a67c8522SLois Curfman McInnes       "Exceeded maximum number of residual evaluations: %d > %d\n",
19349e3953dSBarry Smith        snes->nfuncs, snes->max_funcs );
194a67c8522SLois Curfman McInnes     return -2;
195a67c8522SLois Curfman McInnes   }
1965e42470aSBarry Smith   return 0;
1975e42470aSBarry Smith }
1985e42470aSBarry Smith 
1995e76c431SBarry Smith /* ------------------------------------------------------------ */
2005e76c431SBarry Smith /*ARGSUSED*/
2015e76c431SBarry Smith /*@
2025e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
2035e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
2045e76c431SBarry Smith    to serve as a template and is not recommended for general use.
2055e76c431SBarry Smith 
2065e76c431SBarry Smith    Input Parameters:
2075e42470aSBarry Smith .  snes - nonlinear context
2085e76c431SBarry Smith .  x - current iterate
2095e76c431SBarry Smith .  f - residual evaluated at x
2105e76c431SBarry Smith .  y - search direction (contains new iterate on output)
2115e76c431SBarry Smith .  w - work vector
2125e76c431SBarry Smith .  fnorm - 2-norm of f
2135e76c431SBarry Smith 
214c4a48953SLois Curfman McInnes    Output Parameters:
2155e76c431SBarry Smith .  g - residual evaluated at new iterate y
2165e76c431SBarry Smith .  y - new iterate (contains search direction on input)
2175e76c431SBarry Smith .  gnorm - 2-norm of g
2185e76c431SBarry Smith .  ynorm - 2-norm of search length
219761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
2205e76c431SBarry Smith 
221c4a48953SLois Curfman McInnes    Options Database Key:
222c4a48953SLois Curfman McInnes $  -snes_line_search basic
223c4a48953SLois Curfman McInnes 
22428ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
22528ae5a21SLois Curfman McInnes 
226f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
227f59ffdedSLois Curfman McInnes .seealso: SNESSetLineSearchRoutine()
2285e76c431SBarry Smith @*/
2295e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
230761aaf1bSLois Curfman McInnes               double fnorm, double *ynorm, double *gnorm,int *flag )
2315e76c431SBarry Smith {
2325e42470aSBarry Smith   int    ierr;
2335e42470aSBarry Smith   Scalar one = 1.0;
234761aaf1bSLois Curfman McInnes   *flag = 0;
2357857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
2365e42470aSBarry Smith   VecNorm(y, ynorm );	/* ynorm = || y ||    */
2375e42470aSBarry Smith   VecAXPY(&one, x, y );	/* y <- x + y         */
23878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr);
2395e42470aSBarry Smith   VecNorm( g, gnorm ); 	/* gnorm = || g ||    */
2407857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
241761aaf1bSLois Curfman McInnes   return 0;
2425e76c431SBarry Smith }
2435e76c431SBarry Smith /* ------------------------------------------------------------------ */
2445e76c431SBarry Smith /*@
245f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
246f59ffdedSLois Curfman McInnes    is the default line search method.
2475e76c431SBarry Smith 
2485e76c431SBarry Smith    Input Parameters:
2495e42470aSBarry Smith .  snes - nonlinear context
2505e76c431SBarry Smith .  x - current iterate
2515e76c431SBarry Smith .  f - residual evaluated at x
2525e76c431SBarry Smith .  y - search direction (contains new iterate on output)
2535e76c431SBarry Smith .  w - work vector
2545e76c431SBarry Smith .  fnorm - 2-norm of f
2555e76c431SBarry Smith 
2565e76c431SBarry Smith    Output parameters:
2575e76c431SBarry Smith .  g - residual evaluated at new iterate y
2585e76c431SBarry Smith .  y - new iterate (contains search direction on input)
2595e76c431SBarry Smith .  gnorm - 2-norm of g
2605e76c431SBarry Smith .  ynorm - 2-norm of search length
261761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
2625e76c431SBarry Smith 
263c4a48953SLois Curfman McInnes    Options Database Key:
264c4a48953SLois Curfman McInnes $  -snes_line_search cubic
265c4a48953SLois Curfman McInnes 
2665e76c431SBarry Smith    Notes:
2675e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
2685e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
2695e76c431SBarry Smith 
27028ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
27128ae5a21SLois Curfman McInnes 
272f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
2735e76c431SBarry Smith @*/
2745e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
275761aaf1bSLois Curfman McInnes                 double fnorm, double *ynorm, double *gnorm,int *flag)
2765e76c431SBarry Smith {
2775e42470aSBarry Smith   double  steptol, initslope;
2785e42470aSBarry Smith   double  lambdaprev, gnormprev;
2795e76c431SBarry Smith   double  a, b, d, t1, t2;
2806b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2815e42470aSBarry Smith   Scalar  cinitslope,clambda;
2826b5873e3SBarry Smith #endif
2835e42470aSBarry Smith   int     ierr,count;
2845e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2855e42470aSBarry Smith   Scalar  one = 1.0,scale;
2865e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
2875e76c431SBarry Smith 
2887857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
289761aaf1bSLois Curfman McInnes   *flag = 0;
2905e76c431SBarry Smith   alpha   = neP->alpha;
2915e76c431SBarry Smith   maxstep = neP->maxstep;
2925e76c431SBarry Smith   steptol = neP->steptol;
2935e76c431SBarry Smith 
2945e42470aSBarry Smith   VecNorm(y, ynorm );
2955e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2965e42470aSBarry Smith     scale = maxstep/(*ynorm);
2976b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2986b5873e3SBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",real(scale));
2996b5873e3SBarry Smith #else
3005e42470aSBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",scale);
3016b5873e3SBarry Smith #endif
3025e42470aSBarry Smith     VecScale(&scale, y );
3035e76c431SBarry Smith     *ynorm = maxstep;
3045e76c431SBarry Smith   }
3055e76c431SBarry Smith   minlambda = steptol/(*ynorm);
3065e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3075e42470aSBarry Smith   VecDot(f, y, &cinitslope );
3085e42470aSBarry Smith   initslope = real(cinitslope);
3095e42470aSBarry Smith #else
3105e42470aSBarry Smith   VecDot(f, y, &initslope );
3115e42470aSBarry Smith #endif
3125e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
3135e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
3145e76c431SBarry Smith 
3155e42470aSBarry Smith   VecCopy(y, w );
3165e42470aSBarry Smith   VecAXPY(&one, x, w );
31778b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
3185e42470aSBarry Smith   VecNorm(g, gnorm );
3195e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
3205e42470aSBarry Smith       VecCopy(w, y );
3215e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Using full step\n");
322*d93a2b8dSBarry Smith       goto theend;
3235e76c431SBarry Smith   }
3245e76c431SBarry Smith 
3255e76c431SBarry Smith   /* Fit points with quadratic */
3265e76c431SBarry Smith   lambda = 1.0; count = 0;
3275e76c431SBarry Smith   lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
3285e76c431SBarry Smith   lambdaprev = lambda;
3295e76c431SBarry Smith   gnormprev = *gnorm;
3305e76c431SBarry Smith   if (lambdatemp <= .1*lambda) {
3315e76c431SBarry Smith       lambda = .1*lambda;
3325e76c431SBarry Smith   } else lambda = lambdatemp;
3335e42470aSBarry Smith   VecCopy(x, w );
3345e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3355e42470aSBarry Smith   clambda = lambda; VecAXPY(&clambda, y, w );
3365e42470aSBarry Smith #else
3375e42470aSBarry Smith   VecAXPY(&lambda, y, w );
3385e42470aSBarry Smith #endif
33978b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
3405e42470aSBarry Smith   VecNorm(g, gnorm );
3415e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
3425e42470aSBarry Smith       VecCopy(w, y );
3435e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
344*d93a2b8dSBarry Smith       goto theend;
3455e42470aSBarry Smith       return 0;
3465e76c431SBarry Smith   }
3475e76c431SBarry Smith 
3485e76c431SBarry Smith   /* Fit points with cubic */
3495e76c431SBarry Smith   count = 1;
3505e76c431SBarry Smith   while (1) {
3515e76c431SBarry Smith       if (lambda <= minlambda) { /* bad luck; use full step */
3525e42470aSBarry Smith            PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
3535e42470aSBarry Smith            PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
3545e76c431SBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
3555e42470aSBarry Smith            VecCopy(w, y );
356761aaf1bSLois Curfman McInnes            *flag = -1; break;
3575e76c431SBarry Smith       }
3585e76c431SBarry Smith       t1 = *gnorm - fnorm - lambda*initslope;
3595e76c431SBarry Smith       t2 = gnormprev  - fnorm - lambdaprev*initslope;
3605e76c431SBarry Smith       a = (t1/(lambda*lambda) -
3615e76c431SBarry Smith                 t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3625e76c431SBarry Smith       b = (-lambdaprev*t1/(lambda*lambda) +
3635e76c431SBarry Smith                 lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3645e76c431SBarry Smith       d = b*b - 3*a*initslope;
3655e76c431SBarry Smith       if (d < 0.0) d = 0.0;
3665e76c431SBarry Smith       if (a == 0.0) {
3675e76c431SBarry Smith          lambdatemp = -initslope/(2.0*b);
3685e76c431SBarry Smith       } else {
3695e76c431SBarry Smith          lambdatemp = (-b + sqrt(d))/(3.0*a);
3705e76c431SBarry Smith       }
3715e76c431SBarry Smith       if (lambdatemp > .5*lambda) {
3725e76c431SBarry Smith          lambdatemp = .5*lambda;
3735e76c431SBarry Smith       }
3745e76c431SBarry Smith       lambdaprev = lambda;
3755e76c431SBarry Smith       gnormprev = *gnorm;
3765e76c431SBarry Smith       if (lambdatemp <= .1*lambda) {
3775e76c431SBarry Smith          lambda = .1*lambda;
3785e76c431SBarry Smith       }
3795e76c431SBarry Smith       else lambda = lambdatemp;
3805e42470aSBarry Smith       VecCopy( x, w );
3815e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3825e42470aSBarry Smith       VecAXPY(&clambda, y, w );
3835e42470aSBarry Smith #else
3845e42470aSBarry Smith       VecAXPY(&lambda, y, w );
3855e42470aSBarry Smith #endif
38678b31e54SBarry Smith       ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
3875e42470aSBarry Smith       VecNorm(g, gnorm );
3885e76c431SBarry Smith       if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
3895e42470aSBarry Smith          VecCopy(w, y );
3905e42470aSBarry Smith          PLogInfo((PetscObject)snes,"Cubically determined step, lambda %g\n",lambda);
391761aaf1bSLois Curfman McInnes          *flag = -1; break;
3925e76c431SBarry Smith       }
3935e76c431SBarry Smith       count++;
3945e76c431SBarry Smith    }
395*d93a2b8dSBarry Smith   theend:
3967857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3975e42470aSBarry Smith   return 0;
3985e76c431SBarry Smith }
3995e42470aSBarry Smith /*@
4005e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
4015e76c431SBarry Smith 
4025e42470aSBarry Smith    Input Parameters:
403f59ffdedSLois Curfman McInnes .  snes - the SNES context
4045e42470aSBarry Smith .  x - current iterate
4055e42470aSBarry Smith .  f - residual evaluated at x
4065e42470aSBarry Smith .  y - search direction (contains new iterate on output)
4075e42470aSBarry Smith .  w - work vector
4085e42470aSBarry Smith .  fnorm - 2-norm of f
4095e42470aSBarry Smith 
410c4a48953SLois Curfman McInnes    Output Parameters:
4115e42470aSBarry Smith .  g - residual evaluated at new iterate y
4125e42470aSBarry Smith .  y - new iterate (contains search direction on input)
4135e42470aSBarry Smith .  gnorm - 2-norm of g
4145e42470aSBarry Smith .  ynorm - 2-norm of search length
415761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
4165e42470aSBarry Smith 
417c4a48953SLois Curfman McInnes    Options Database Key:
418c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
419c4a48953SLois Curfman McInnes 
4205e42470aSBarry Smith    Notes:
421f59ffdedSLois Curfman McInnes    Use SNESSetLineSearchRoutine()
422f59ffdedSLois Curfman McInnes    to set this routine within the SNES_NLS method.
4235e42470aSBarry Smith 
424f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
425f59ffdedSLois Curfman McInnes 
426f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
4275e42470aSBarry Smith @*/
4285e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
429761aaf1bSLois Curfman McInnes                     double fnorm, double *ynorm, double *gnorm,int *flag)
4305e76c431SBarry Smith {
4315e42470aSBarry Smith   double  steptol, initslope;
4325e42470aSBarry Smith   double  lambdaprev, gnormprev;
4336b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
4345e42470aSBarry Smith   Scalar  cinitslope,clambda;
4356b5873e3SBarry Smith #endif
4365e42470aSBarry Smith   int     ierr,count;
4375e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
4385e42470aSBarry Smith   Scalar  one = 1.0,scale;
4395e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
4405e76c431SBarry Smith 
4417857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
442761aaf1bSLois Curfman McInnes   *flag = 0;
4435e42470aSBarry Smith   alpha   = neP->alpha;
4445e42470aSBarry Smith   maxstep = neP->maxstep;
4455e42470aSBarry Smith   steptol = neP->steptol;
4465e76c431SBarry Smith 
4475e42470aSBarry Smith   VecNorm(y, ynorm );
4485e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
4495e42470aSBarry Smith     scale = maxstep/(*ynorm);
4505e42470aSBarry Smith     VecScale(&scale, y );
4515e42470aSBarry Smith     *ynorm = maxstep;
4525e76c431SBarry Smith   }
4535e42470aSBarry Smith   minlambda = steptol/(*ynorm);
4545e42470aSBarry Smith #if defined(PETSC_COMPLEX)
4555e42470aSBarry Smith   VecDot(f, y, &cinitslope );
4565e42470aSBarry Smith   initslope = real(cinitslope);
4575e42470aSBarry Smith #else
4585e42470aSBarry Smith   VecDot(f, y, &initslope );
4595e42470aSBarry Smith #endif
4605e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
4615e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
4625e42470aSBarry Smith 
4635e42470aSBarry Smith   VecCopy(y, w );
4645e42470aSBarry Smith   VecAXPY(&one, x, w );
46578b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
4665e42470aSBarry Smith   VecNorm(g, gnorm );
4675e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
4685e42470aSBarry Smith       VecCopy(w, y );
4695e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Using full step\n");
470*d93a2b8dSBarry Smith       goto theend;
4715e42470aSBarry Smith   }
4725e42470aSBarry Smith 
4735e42470aSBarry Smith   /* Fit points with quadratic */
4745e42470aSBarry Smith   lambda = 1.0; count = 0;
4755e42470aSBarry Smith   count = 1;
4765e42470aSBarry Smith   while (1) {
4775e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
4785e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
4795e42470aSBarry Smith       PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
4805e42470aSBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
4815e42470aSBarry Smith       VecCopy(w, y );
482761aaf1bSLois Curfman McInnes       *flag = -1; break;
4835e42470aSBarry Smith     }
4845e42470aSBarry Smith     lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
4855e42470aSBarry Smith     lambdaprev = lambda;
4865e42470aSBarry Smith     gnormprev = *gnorm;
4875e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4885e42470aSBarry Smith       lambda = .1*lambda;
4895e42470aSBarry Smith     } else lambda = lambdatemp;
4905e42470aSBarry Smith     VecCopy(x, w );
4915e42470aSBarry Smith #if defined(PETSC_COMPLEX)
4925e42470aSBarry Smith     clambda = lambda; VecAXPY(&clambda, y, w );
4935e42470aSBarry Smith #else
4945e42470aSBarry Smith     VecAXPY(&lambda, y, w );
4955e42470aSBarry Smith #endif
49678b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
4975e42470aSBarry Smith     VecNorm(g, gnorm );
4985e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
4995e42470aSBarry Smith       VecCopy(w, y );
5005e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
50106259719SBarry Smith       break;
5025e42470aSBarry Smith     }
5035e42470aSBarry Smith     count++;
5045e42470aSBarry Smith   }
505*d93a2b8dSBarry Smith   theend:
5067857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
5075e42470aSBarry Smith   return 0;
5085e76c431SBarry Smith }
5095e76c431SBarry Smith /* ------------------------------------------------------------ */
510b1f0a012SBarry Smith /*@
5115e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
512fbe28522SBarry Smith    by the method SNES_LS.
5135e76c431SBarry Smith 
5145e76c431SBarry Smith    Input Parameters:
515eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
5165e76c431SBarry Smith .  func - pointer to int function
5175e76c431SBarry Smith 
518c4a48953SLois Curfman McInnes    Available Routines:
519f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
520f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
521f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
5225e76c431SBarry Smith 
523c4a48953SLois Curfman McInnes     Options Database Keys:
524c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
525c4a48953SLois Curfman McInnes 
5265e76c431SBarry Smith    Calling sequence of func:
527f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
528761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
529761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
5305e76c431SBarry Smith 
5315e76c431SBarry Smith     Input parameters for func:
5325e42470aSBarry Smith .   snes - nonlinear context
5335e76c431SBarry Smith .   x - current iterate
5345e76c431SBarry Smith .   f - residual evaluated at x
5355e76c431SBarry Smith .   y - search direction (contains new iterate on output)
5365e76c431SBarry Smith .   w - work vector
5375e76c431SBarry Smith .   fnorm - 2-norm of f
5385e76c431SBarry Smith 
5395e76c431SBarry Smith     Output parameters for func:
5405e76c431SBarry Smith .   g - residual evaluated at new iterate y
5415e76c431SBarry Smith .   y - new iterate (contains search direction on input)
5425e76c431SBarry Smith .   gnorm - 2-norm of g
5435e76c431SBarry Smith .   ynorm - 2-norm of search length
544761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
545761aaf1bSLois Curfman McInnes            on failure.
546f59ffdedSLois Curfman McInnes 
547f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
548f59ffdedSLois Curfman McInnes 
549f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
5505e76c431SBarry Smith @*/
5515e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
552761aaf1bSLois Curfman McInnes                              double,double *,double*,int*) )
5535e76c431SBarry Smith {
554fbe28522SBarry Smith   if ((snes)->type == SNES_NLS)
5555e42470aSBarry Smith     ((SNES_LS *)(snes->data))->LineSearch = func;
5565e42470aSBarry Smith   return 0;
5575e76c431SBarry Smith }
5585e42470aSBarry Smith 
5595e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes)
5605e42470aSBarry Smith {
5615e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5625e42470aSBarry Smith   fprintf(stderr,"-snes_line_search [basic,quadratic,cubic]\n");
5635e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_alpha alpha (default %g)\n",ls->alpha);
5645e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_maxstep max (default %g)\n",ls->maxstep);
5655e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_steptol tol (default %g)\n",ls->steptol);
5666b5873e3SBarry Smith   return 0;
5675e42470aSBarry Smith }
5685e42470aSBarry Smith 
5695e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5705e42470aSBarry Smith {
5715e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5725e42470aSBarry Smith   char    ver[16];
5735e42470aSBarry Smith   double  tmp;
5745e42470aSBarry Smith 
575df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) {
5765e42470aSBarry Smith     ls->alpha = tmp;
5775e42470aSBarry Smith   }
578df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) {
5795e42470aSBarry Smith     ls->maxstep = tmp;
5805e42470aSBarry Smith   }
581df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) {
5825e42470aSBarry Smith     ls->steptol = tmp;
5835e42470aSBarry Smith   }
584df60cc22SBarry Smith   if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) {
5855e42470aSBarry Smith     if (!strcmp(ver,"basic")) {
5865e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5875e42470aSBarry Smith     }
5885e42470aSBarry Smith     else if (!strcmp(ver,"quadratic")) {
5895e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5905e42470aSBarry Smith     }
5915e42470aSBarry Smith     else if (!strcmp(ver,"cubic")) {
5925e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5935e42470aSBarry Smith     }
5948c48e012SBarry Smith     else {SETERRQ(1,"SNESSetFromOptions_LS: Unknown line search");}
5955e42470aSBarry Smith   }
5965e42470aSBarry Smith   return 0;
5975e42470aSBarry Smith }
5985e42470aSBarry Smith 
5995e42470aSBarry Smith /* ------------------------------------------------------------ */
6005e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
6015e42470aSBarry Smith {
6025e42470aSBarry Smith   SNES_LS *neP;
6035e42470aSBarry Smith 
604fbe28522SBarry Smith   snes->type		= SNES_NLS;
60549e3953dSBarry Smith   snes->setup		= SNESSetUp_LS;
60649e3953dSBarry Smith   snes->solve		= SNESSolve_LS;
6075e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
6085e42470aSBarry Smith   snes->Converged	= SNESDefaultConverged;
60949e3953dSBarry Smith   snes->printhelp       = SNESPrintHelp_LS;
61049e3953dSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_LS;
6115e42470aSBarry Smith 
61278b31e54SBarry Smith   neP			= PETSCNEW(SNES_LS);   CHKPTRQ(neP);
6135e42470aSBarry Smith   snes->data    	= (void *) neP;
6145e42470aSBarry Smith   neP->alpha		= 1.e-4;
6155e42470aSBarry Smith   neP->maxstep		= 1.e8;
6165e42470aSBarry Smith   neP->steptol		= 1.e-12;
6175e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
6185e42470aSBarry Smith   return 0;
6195e42470aSBarry Smith }
6205e42470aSBarry Smith 
6215e42470aSBarry Smith 
6225e42470aSBarry Smith 
6235e42470aSBarry Smith 
624