xref: /petsc/src/snes/impls/ls/ls.c (revision 81b6cf68443c1f78afefadd3582a5abc239776a6)
15e76c431SBarry Smith #ifndef lint
2*81b6cf68SLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.23 1995/06/13 01:18:08 bsmith Exp curfman $";
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;
32edd2f0e1SBarry Smith   int          maxits, i, history_len,ierr,lits;
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);
62*81b6cf68SLois Curfman McInnes        ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
635e42470aSBarry Smith        ierr = (*neP->LineSearch)(snes, X, F, G, Y, W, fnorm, &ynorm, &gnorm );
6478b31e54SBarry Smith        CHKERRQ(ierr);
655e76c431SBarry Smith 
6639e2f89bSBarry Smith        TMP = F; F = G; snes->vec_func_always = F; G = TMP;
6739e2f89bSBarry Smith        TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
685e76c431SBarry Smith        fnorm = gnorm;
695e76c431SBarry Smith 
705e42470aSBarry Smith        snes->norm = fnorm;
715e76c431SBarry Smith        if (history && history_len > i+1) history[i+1] = fnorm;
725e42470aSBarry Smith        VecNorm( X, &xnorm );		/* xnorm = || X || */
73eafb4bcbSBarry Smith        if (snes->Monitor) (*snes->Monitor)(snes,i+1,fnorm,snes->monP);
745e76c431SBarry Smith 
755e76c431SBarry Smith        /* Test for convergence */
765e42470aSBarry Smith        if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) {
7739e2f89bSBarry Smith            if (X != snes->vec_sol) {
7839e2f89bSBarry Smith              VecCopy( X, snes->vec_sol );
7939e2f89bSBarry Smith              snes->vec_sol_always = snes->vec_sol;
8039e2f89bSBarry Smith              snes->vec_func_always = snes->vec_func;
8139e2f89bSBarry Smith            }
825e76c431SBarry Smith            break;
835e76c431SBarry Smith        }
845e76c431SBarry Smith   }
855e76c431SBarry Smith   if (i == maxits) i--;
865e42470aSBarry Smith   *outits = i+1;
875e42470aSBarry Smith   return 0;
885e76c431SBarry Smith }
895e76c431SBarry Smith /* ------------------------------------------------------------ */
905e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
915e76c431SBarry Smith {
925e42470aSBarry Smith   int ierr;
93*81b6cf68SLois Curfman McInnes   snes->nwork = 4;
9478b31e54SBarry Smith   ierr = VecGetVecs( snes->vec_sol, snes->nwork,&snes->work ); CHKERRQ(ierr);
955e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work );
96*81b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
975e42470aSBarry Smith   return 0;
985e76c431SBarry Smith }
995e76c431SBarry Smith /* ------------------------------------------------------------ */
1005e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
1015e76c431SBarry Smith {
1025e42470aSBarry Smith   SNES snes = (SNES) obj;
1035e42470aSBarry Smith   VecFreeVecs(snes->work, snes->nwork );
10478b31e54SBarry Smith   PETSCFREE(snes->data);
1055e42470aSBarry Smith   return 0;
1065e76c431SBarry Smith }
1075e42470aSBarry Smith /*@
1080de89847SLois Curfman McInnes    SNESDefaultMonitor - Default SNES monitoring routine.  Prints the
1095e42470aSBarry Smith    residual norm at each iteration.
1105e42470aSBarry Smith 
1115e42470aSBarry Smith    Input Parameters:
1120de89847SLois Curfman McInnes .  snes - the SNES context
1130de89847SLois Curfman McInnes .  its - iteration number
1140de89847SLois Curfman McInnes .  fnorm - 2-norm residual value (may be estimated)
1150de89847SLois Curfman McInnes .  dummy - unused context
1165e42470aSBarry Smith 
1175e42470aSBarry Smith    Notes:
1185e42470aSBarry Smith    f is either the residual or its negative, depending on the user's
119a9581db2SBarry Smith    preference, as set with SNESSetFunction().
120a67c8522SLois Curfman McInnes 
121a67c8522SLois Curfman McInnes .keywords: SNES, nonlinear, default, monitor, residual, norm
122a67c8522SLois Curfman McInnes 
123a67c8522SLois Curfman McInnes .seealso: SNESSetMonitor()
1245e42470aSBarry Smith @*/
125eafb4bcbSBarry Smith int SNESDefaultMonitor(SNES snes,int its, double fnorm,void *dummy)
1265e42470aSBarry Smith {
127614e12f8SBarry Smith   MPIU_printf(snes->comm, "iter = %d, Function norm %g \n",its,fnorm);
128614e12f8SBarry Smith   return 0;
129614e12f8SBarry Smith }
130614e12f8SBarry Smith 
131614e12f8SBarry Smith int SNESDefaultSMonitor(SNES snes,int its, double fnorm,void *dummy)
132614e12f8SBarry Smith {
133614e12f8SBarry Smith   if (fnorm > 1.e-9 || fnorm == 0.0) {
1347f813858SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm %g \n",its,fnorm);
13569e4de80SBarry Smith   }
136614e12f8SBarry Smith   else if (fnorm > 1.e-11){
13769e4de80SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm %5.3e \n",its,fnorm);
13869e4de80SBarry Smith   }
139614e12f8SBarry Smith   else {
140614e12f8SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm < 1.e-11\n",its);
141614e12f8SBarry Smith   }
1425e42470aSBarry Smith   return 0;
1435e42470aSBarry Smith }
1445e42470aSBarry Smith 
1455e42470aSBarry Smith /*@
1465e42470aSBarry Smith    SNESDefaultConverged - Default test for monitoring the convergence
1470de89847SLois Curfman McInnes    of the SNES solvers.
1485e42470aSBarry Smith 
1495e42470aSBarry Smith    Input Parameters:
1500de89847SLois Curfman McInnes .  snes - the SNES context
1515e42470aSBarry Smith .  xnorm - 2-norm of current iterate
1525e42470aSBarry Smith .  pnorm - 2-norm of current step
1535e42470aSBarry Smith .  fnorm - 2-norm of residual
1540de89847SLois Curfman McInnes .  dummy - unused context
1555e42470aSBarry Smith 
1565e42470aSBarry Smith    Returns:
1575e42470aSBarry Smith $  2  if  ( fnorm < atol ),
1585e42470aSBarry Smith $  3  if  ( pnorm < xtol*xnorm ),
1595e42470aSBarry Smith $ -2  if  ( nres > max_res ),
1605e42470aSBarry Smith $  0  otherwise,
1615e42470aSBarry Smith 
1625e42470aSBarry Smith    where
1635e42470aSBarry Smith $    atol    - absolute residual norm tolerance,
1640de89847SLois Curfman McInnes $              set with SNESSetAbsoluteTolerance()
1655e42470aSBarry Smith $    max_res - maximum number of residual evaluations,
1660de89847SLois Curfman McInnes $              set with SNESSetMaxResidualEvaluations()
1675e42470aSBarry Smith $    nres    - number of residual evaluations
1685e42470aSBarry Smith $    xtol    - relative residual norm tolerance,
1690de89847SLois Curfman McInnes $              set with SNESSetRelativeTolerance()
1705e42470aSBarry Smith 
1710de89847SLois Curfman McInnes .keywords: SNES, nonlinear, default, converged, convergence
1725e42470aSBarry Smith 
1730de89847SLois Curfman McInnes .seealso: SNESSetConvergenceTest()
1745e42470aSBarry Smith @*/
1755e42470aSBarry Smith int SNESDefaultConverged(SNES snes,double xnorm,double pnorm,double fnorm,
1765e42470aSBarry Smith                          void *dummy)
1775e42470aSBarry Smith {
1785e42470aSBarry Smith   if (fnorm < snes->atol) {
179a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
180a67c8522SLois Curfman McInnes       "Converged due to absolute residual norm %g < %g\n",fnorm,snes->atol);
1815e42470aSBarry Smith     return 2;
1825e42470aSBarry Smith   }
1835e42470aSBarry Smith   if (pnorm < snes->xtol*(xnorm)) {
184a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
185a67c8522SLois Curfman McInnes       "Converged due to small update length  %g < %g*%g\n",
1865e42470aSBarry Smith        pnorm,snes->xtol,xnorm);
1875e42470aSBarry Smith     return 3;
1885e42470aSBarry Smith   }
18949e3953dSBarry Smith   if (snes->nfuncs > snes->max_funcs) {
190a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
191a67c8522SLois Curfman McInnes       "Exceeded maximum number of residual evaluations: %d > %d\n",
19249e3953dSBarry Smith        snes->nfuncs, snes->max_funcs );
193a67c8522SLois Curfman McInnes     return -2;
194a67c8522SLois Curfman McInnes   }
1955e42470aSBarry Smith   return 0;
1965e42470aSBarry Smith }
1975e42470aSBarry Smith 
1985e76c431SBarry Smith /* ------------------------------------------------------------ */
1995e76c431SBarry Smith /*ARGSUSED*/
2005e76c431SBarry Smith /*@
2015e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
2025e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
2035e76c431SBarry Smith    to serve as a template and is not recommended for general use.
2045e76c431SBarry Smith 
2055e76c431SBarry Smith    Input Parameters:
2065e42470aSBarry Smith .  snes - nonlinear context
2075e76c431SBarry Smith .  x - current iterate
2085e76c431SBarry Smith .  f - residual evaluated at x
2095e76c431SBarry Smith .  y - search direction (contains new iterate on output)
2105e76c431SBarry Smith .  w - work vector
2115e76c431SBarry Smith .  fnorm - 2-norm of f
2125e76c431SBarry Smith 
213c4a48953SLois Curfman McInnes    Output Parameters:
2145e76c431SBarry Smith .  g - residual evaluated at new iterate y
2155e76c431SBarry Smith .  y - new iterate (contains search direction on input)
2165e76c431SBarry Smith .  gnorm - 2-norm of g
2175e76c431SBarry Smith .  ynorm - 2-norm of search length
2185e76c431SBarry Smith 
219c4a48953SLois Curfman McInnes    Options Database Key:
220c4a48953SLois Curfman McInnes $  -snes_line_search basic
221c4a48953SLois Curfman McInnes 
2225e76c431SBarry Smith    Returns:
2235e76c431SBarry Smith    1, indicating success of the step.
2245e76c431SBarry Smith 
22528ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
22628ae5a21SLois Curfman McInnes 
227f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
228f59ffdedSLois Curfman McInnes .seealso: SNESSetLineSearchRoutine()
2295e76c431SBarry Smith @*/
2305e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
2315e42470aSBarry Smith                              double fnorm, double *ynorm, double *gnorm )
2325e76c431SBarry Smith {
2335e42470aSBarry Smith   int    ierr;
2345e42470aSBarry Smith   Scalar one = 1.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);
2415e76c431SBarry Smith   return 1;
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
2615e76c431SBarry Smith 
2625e76c431SBarry Smith    Returns:
2635e76c431SBarry Smith    1 if the line search succeeds; 0 if the line search fails.
2645e76c431SBarry Smith 
265c4a48953SLois Curfman McInnes    Options Database Key:
266c4a48953SLois Curfman McInnes $  -snes_line_search cubic
267c4a48953SLois Curfman McInnes 
2685e76c431SBarry Smith    Notes:
2695e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
2705e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
2715e76c431SBarry Smith 
27228ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
27328ae5a21SLois Curfman McInnes 
274f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
2755e76c431SBarry Smith @*/
2765e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
2775e42470aSBarry Smith                               double fnorm, double *ynorm, double *gnorm )
2785e76c431SBarry Smith {
2795e42470aSBarry Smith   double  steptol, initslope;
2805e42470aSBarry Smith   double  lambdaprev, gnormprev;
2815e76c431SBarry Smith   double  a, b, d, t1, t2;
2826b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2835e42470aSBarry Smith   Scalar  cinitslope,clambda;
2846b5873e3SBarry Smith #endif
2855e42470aSBarry Smith   int     ierr,count;
2865e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2875e42470aSBarry Smith   Scalar  one = 1.0,scale;
2885e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
2895e76c431SBarry Smith 
2907857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
2915e76c431SBarry Smith   alpha   = neP->alpha;
2925e76c431SBarry Smith   maxstep = neP->maxstep;
2935e76c431SBarry Smith   steptol = neP->steptol;
2945e76c431SBarry Smith 
2955e42470aSBarry Smith   VecNorm(y, ynorm );
2965e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2975e42470aSBarry Smith     scale = maxstep/(*ynorm);
2986b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2996b5873e3SBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",real(scale));
3006b5873e3SBarry Smith #else
3015e42470aSBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",scale);
3026b5873e3SBarry Smith #endif
3035e42470aSBarry Smith     VecScale(&scale, y );
3045e76c431SBarry Smith     *ynorm = maxstep;
3055e76c431SBarry Smith   }
3065e76c431SBarry Smith   minlambda = steptol/(*ynorm);
3075e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3085e42470aSBarry Smith   VecDot(f, y, &cinitslope );
3095e42470aSBarry Smith   initslope = real(cinitslope);
3105e42470aSBarry Smith #else
3115e42470aSBarry Smith   VecDot(f, y, &initslope );
3125e42470aSBarry Smith #endif
3135e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
3145e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
3155e76c431SBarry Smith 
3165e42470aSBarry Smith   VecCopy(y, w );
3175e42470aSBarry Smith   VecAXPY(&one, x, w );
31878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
3195e42470aSBarry Smith   VecNorm(g, gnorm );
3205e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
3215e42470aSBarry Smith       VecCopy(w, y );
3225e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Using full step\n");
3237857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3245e42470aSBarry Smith       return 0;
3255e76c431SBarry Smith   }
3265e76c431SBarry Smith 
3275e76c431SBarry Smith   /* Fit points with quadratic */
3285e76c431SBarry Smith   lambda = 1.0; count = 0;
3295e76c431SBarry Smith   lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
3305e76c431SBarry Smith   lambdaprev = lambda;
3315e76c431SBarry Smith   gnormprev = *gnorm;
3325e76c431SBarry Smith   if (lambdatemp <= .1*lambda) {
3335e76c431SBarry Smith       lambda = .1*lambda;
3345e76c431SBarry Smith   } else lambda = lambdatemp;
3355e42470aSBarry Smith   VecCopy(x, w );
3365e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3375e42470aSBarry Smith   clambda = lambda; VecAXPY(&clambda, y, w );
3385e42470aSBarry Smith #else
3395e42470aSBarry Smith   VecAXPY(&lambda, y, w );
3405e42470aSBarry Smith #endif
34178b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
3425e42470aSBarry Smith   VecNorm(g, gnorm );
3435e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
3445e42470aSBarry Smith       VecCopy(w, y );
3455e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
3467857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3475e42470aSBarry Smith       return 0;
3485e76c431SBarry Smith   }
3495e76c431SBarry Smith 
3505e76c431SBarry Smith   /* Fit points with cubic */
3515e76c431SBarry Smith   count = 1;
3525e76c431SBarry Smith   while (1) {
3535e76c431SBarry Smith       if (lambda <= minlambda) { /* bad luck; use full step */
3545e42470aSBarry Smith            PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
3555e42470aSBarry Smith            PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
3565e76c431SBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
3575e42470aSBarry Smith            VecCopy(w, y );
35806259719SBarry Smith            break;
3595e76c431SBarry Smith       }
3605e76c431SBarry Smith       t1 = *gnorm - fnorm - lambda*initslope;
3615e76c431SBarry Smith       t2 = gnormprev  - fnorm - lambdaprev*initslope;
3625e76c431SBarry Smith       a = (t1/(lambda*lambda) -
3635e76c431SBarry Smith                 t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3645e76c431SBarry Smith       b = (-lambdaprev*t1/(lambda*lambda) +
3655e76c431SBarry Smith                 lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3665e76c431SBarry Smith       d = b*b - 3*a*initslope;
3675e76c431SBarry Smith       if (d < 0.0) d = 0.0;
3685e76c431SBarry Smith       if (a == 0.0) {
3695e76c431SBarry Smith          lambdatemp = -initslope/(2.0*b);
3705e76c431SBarry Smith       } else {
3715e76c431SBarry Smith          lambdatemp = (-b + sqrt(d))/(3.0*a);
3725e76c431SBarry Smith       }
3735e76c431SBarry Smith       if (lambdatemp > .5*lambda) {
3745e76c431SBarry Smith          lambdatemp = .5*lambda;
3755e76c431SBarry Smith       }
3765e76c431SBarry Smith       lambdaprev = lambda;
3775e76c431SBarry Smith       gnormprev = *gnorm;
3785e76c431SBarry Smith       if (lambdatemp <= .1*lambda) {
3795e76c431SBarry Smith          lambda = .1*lambda;
3805e76c431SBarry Smith       }
3815e76c431SBarry Smith       else lambda = lambdatemp;
3825e42470aSBarry Smith       VecCopy( x, w );
3835e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3845e42470aSBarry Smith       VecAXPY(&clambda, y, w );
3855e42470aSBarry Smith #else
3865e42470aSBarry Smith       VecAXPY(&lambda, y, w );
3875e42470aSBarry Smith #endif
38878b31e54SBarry Smith       ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
3895e42470aSBarry Smith       VecNorm(g, gnorm );
3905e76c431SBarry Smith       if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
3915e42470aSBarry Smith          VecCopy(w, y );
3925e42470aSBarry Smith          PLogInfo((PetscObject)snes,"Cubically determined step, lambda %g\n",lambda);
39306259719SBarry Smith          break;
3945e76c431SBarry Smith       }
3955e76c431SBarry Smith       count++;
3965e76c431SBarry Smith    }
3977857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3985e42470aSBarry Smith   return 0;
3995e76c431SBarry Smith }
4005e42470aSBarry Smith /*@
4015e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
4025e76c431SBarry Smith 
4035e42470aSBarry Smith    Input Parameters:
404f59ffdedSLois Curfman McInnes .  snes - the SNES context
4055e42470aSBarry Smith .  x - current iterate
4065e42470aSBarry Smith .  f - residual evaluated at x
4075e42470aSBarry Smith .  y - search direction (contains new iterate on output)
4085e42470aSBarry Smith .  w - work vector
4095e42470aSBarry Smith .  fnorm - 2-norm of f
4105e42470aSBarry Smith 
411c4a48953SLois Curfman McInnes    Output Parameters:
4125e42470aSBarry Smith .  g - residual evaluated at new iterate y
4135e42470aSBarry Smith .  y - new iterate (contains search direction on input)
4145e42470aSBarry Smith .  gnorm - 2-norm of g
4155e42470aSBarry Smith .  ynorm - 2-norm of search length
4165e42470aSBarry Smith 
4175e42470aSBarry Smith    Returns:
4185e42470aSBarry Smith    1 if the line search succeeds; 0 if the line search fails.
4195e42470aSBarry Smith 
420c4a48953SLois Curfman McInnes    Options Database Key:
421c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
422c4a48953SLois Curfman McInnes 
4235e42470aSBarry Smith    Notes:
424f59ffdedSLois Curfman McInnes    Use SNESSetLineSearchRoutine()
425f59ffdedSLois Curfman McInnes    to set this routine within the SNES_NLS method.
4265e42470aSBarry Smith 
427f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
428f59ffdedSLois Curfman McInnes 
429f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
4305e42470aSBarry Smith @*/
4315e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
4325e42470aSBarry Smith                               double fnorm, double *ynorm, double *gnorm )
4335e76c431SBarry Smith {
4345e42470aSBarry Smith   double  steptol, initslope;
4355e42470aSBarry Smith   double  lambdaprev, gnormprev;
4366b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
4375e42470aSBarry Smith   Scalar  cinitslope,clambda;
4386b5873e3SBarry Smith #endif
4395e42470aSBarry Smith   int     ierr,count;
4405e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
4415e42470aSBarry Smith   Scalar  one = 1.0,scale;
4425e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
4435e76c431SBarry Smith 
4447857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
4455e42470aSBarry Smith   alpha   = neP->alpha;
4465e42470aSBarry Smith   maxstep = neP->maxstep;
4475e42470aSBarry Smith   steptol = neP->steptol;
4485e76c431SBarry Smith 
4495e42470aSBarry Smith   VecNorm(y, ynorm );
4505e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
4515e42470aSBarry Smith     scale = maxstep/(*ynorm);
4525e42470aSBarry Smith     VecScale(&scale, y );
4535e42470aSBarry Smith     *ynorm = maxstep;
4545e76c431SBarry Smith   }
4555e42470aSBarry Smith   minlambda = steptol/(*ynorm);
4565e42470aSBarry Smith #if defined(PETSC_COMPLEX)
4575e42470aSBarry Smith   VecDot(f, y, &cinitslope );
4585e42470aSBarry Smith   initslope = real(cinitslope);
4595e42470aSBarry Smith #else
4605e42470aSBarry Smith   VecDot(f, y, &initslope );
4615e42470aSBarry Smith #endif
4625e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
4635e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
4645e42470aSBarry Smith 
4655e42470aSBarry Smith   VecCopy(y, w );
4665e42470aSBarry Smith   VecAXPY(&one, x, w );
46778b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
4685e42470aSBarry Smith   VecNorm(g, gnorm );
4695e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
4705e42470aSBarry Smith       VecCopy(w, y );
4715e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Using full step\n");
4727857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4735e42470aSBarry Smith       return 0;
4745e42470aSBarry Smith   }
4755e42470aSBarry Smith 
4765e42470aSBarry Smith   /* Fit points with quadratic */
4775e42470aSBarry Smith   lambda = 1.0; count = 0;
4785e42470aSBarry Smith   count = 1;
4795e42470aSBarry Smith   while (1) {
4805e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
4815e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
4825e42470aSBarry Smith       PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
4835e42470aSBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
4845e42470aSBarry Smith       VecCopy(w, y );
48506259719SBarry Smith       break;
4865e42470aSBarry Smith     }
4875e42470aSBarry Smith     lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
4885e42470aSBarry Smith     lambdaprev = lambda;
4895e42470aSBarry Smith     gnormprev = *gnorm;
4905e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4915e42470aSBarry Smith       lambda = .1*lambda;
4925e42470aSBarry Smith     } else lambda = lambdatemp;
4935e42470aSBarry Smith     VecCopy(x, w );
4945e42470aSBarry Smith #if defined(PETSC_COMPLEX)
4955e42470aSBarry Smith     clambda = lambda; VecAXPY(&clambda, y, w );
4965e42470aSBarry Smith #else
4975e42470aSBarry Smith     VecAXPY(&lambda, y, w );
4985e42470aSBarry Smith #endif
49978b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
5005e42470aSBarry Smith     VecNorm(g, gnorm );
5015e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
5025e42470aSBarry Smith       VecCopy(w, y );
5035e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
50406259719SBarry Smith       break;
5055e42470aSBarry Smith     }
5065e42470aSBarry Smith     count++;
5075e42470aSBarry Smith   }
5085e42470aSBarry Smith 
5097857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
5105e42470aSBarry Smith   return 0;
5115e76c431SBarry Smith }
5125e76c431SBarry Smith /* ------------------------------------------------------------ */
5135e76c431SBarry Smith /*@C
5145e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
515fbe28522SBarry Smith    by the method SNES_LS.
5165e76c431SBarry Smith 
5175e76c431SBarry Smith    Input Parameters:
518eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
5195e76c431SBarry Smith .  func - pointer to int function
5205e76c431SBarry Smith 
521c4a48953SLois Curfman McInnes    Available Routines:
522f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
523f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
524f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
5255e76c431SBarry Smith 
526c4a48953SLois Curfman McInnes     Options Database Keys:
527c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
528c4a48953SLois Curfman McInnes 
5295e76c431SBarry Smith    Calling sequence of func:
530f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
5315e42470aSBarry Smith          Vec w, double fnorm, double *ynorm, double *gnorm)
5325e76c431SBarry Smith 
5335e76c431SBarry Smith     Input parameters for func:
5345e42470aSBarry Smith .   snes - nonlinear context
5355e76c431SBarry Smith .   x - current iterate
5365e76c431SBarry Smith .   f - residual evaluated at x
5375e76c431SBarry Smith .   y - search direction (contains new iterate on output)
5385e76c431SBarry Smith .   w - work vector
5395e76c431SBarry Smith .   fnorm - 2-norm of f
5405e76c431SBarry Smith 
5415e76c431SBarry Smith     Output parameters for func:
5425e76c431SBarry Smith .   g - residual evaluated at new iterate y
5435e76c431SBarry Smith .   y - new iterate (contains search direction on input)
5445e76c431SBarry Smith .   gnorm - 2-norm of g
5455e76c431SBarry Smith .   ynorm - 2-norm of search length
5465e76c431SBarry Smith 
5475e76c431SBarry Smith     Returned by func:
5485e76c431SBarry Smith     1 if the line search succeeds; 0 if the line search fails.
549f59ffdedSLois Curfman McInnes 
550f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
551f59ffdedSLois Curfman McInnes 
552f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
5535e76c431SBarry Smith @*/
5545e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
5555e42470aSBarry Smith                              double,double *,double*) )
5565e76c431SBarry Smith {
557fbe28522SBarry Smith   if ((snes)->type == SNES_NLS)
5585e42470aSBarry Smith     ((SNES_LS *)(snes->data))->LineSearch = func;
5595e42470aSBarry Smith   return 0;
5605e76c431SBarry Smith }
5615e42470aSBarry Smith 
5625e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes)
5635e42470aSBarry Smith {
5645e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5655e42470aSBarry Smith   fprintf(stderr,"-snes_line_search [basic,quadratic,cubic]\n");
5665e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_alpha alpha (default %g)\n",ls->alpha);
5675e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_maxstep max (default %g)\n",ls->maxstep);
5685e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_steptol tol (default %g)\n",ls->steptol);
5696b5873e3SBarry Smith   return 0;
5705e42470aSBarry Smith }
5715e42470aSBarry Smith 
5725e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5735e42470aSBarry Smith {
5745e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5755e42470aSBarry Smith   char    ver[16];
5765e42470aSBarry Smith   double  tmp;
5775e42470aSBarry Smith 
578df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) {
5795e42470aSBarry Smith     ls->alpha = tmp;
5805e42470aSBarry Smith   }
581df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) {
5825e42470aSBarry Smith     ls->maxstep = tmp;
5835e42470aSBarry Smith   }
584df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) {
5855e42470aSBarry Smith     ls->steptol = tmp;
5865e42470aSBarry Smith   }
587df60cc22SBarry Smith   if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) {
5885e42470aSBarry Smith     if (!strcmp(ver,"basic")) {
5895e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5905e42470aSBarry Smith     }
5915e42470aSBarry Smith     else if (!strcmp(ver,"quadratic")) {
5925e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5935e42470aSBarry Smith     }
5945e42470aSBarry Smith     else if (!strcmp(ver,"cubic")) {
5955e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5965e42470aSBarry Smith     }
59778b31e54SBarry Smith     else {SETERRQ(1,"Unknown line search?");}
5985e42470aSBarry Smith   }
5995e42470aSBarry Smith   return 0;
6005e42470aSBarry Smith }
6015e42470aSBarry Smith 
6025e42470aSBarry Smith /* ------------------------------------------------------------ */
6035e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
6045e42470aSBarry Smith {
6055e42470aSBarry Smith   SNES_LS *neP;
6065e42470aSBarry Smith 
607fbe28522SBarry Smith   snes->type		= SNES_NLS;
60849e3953dSBarry Smith   snes->setup		= SNESSetUp_LS;
60949e3953dSBarry Smith   snes->solve		= SNESSolve_LS;
6105e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
6115e42470aSBarry Smith   snes->Converged	= SNESDefaultConverged;
61249e3953dSBarry Smith   snes->printhelp       = SNESPrintHelp_LS;
61349e3953dSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_LS;
6145e42470aSBarry Smith 
61578b31e54SBarry Smith   neP			= PETSCNEW(SNES_LS);   CHKPTRQ(neP);
6165e42470aSBarry Smith   snes->data    	= (void *) neP;
6175e42470aSBarry Smith   neP->alpha		= 1.e-4;
6185e42470aSBarry Smith   neP->maxstep		= 1.e8;
6195e42470aSBarry Smith   neP->steptol		= 1.e-12;
6205e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
6215e42470aSBarry Smith   return 0;
6225e42470aSBarry Smith }
6235e42470aSBarry Smith 
6245e42470aSBarry Smith 
6255e42470aSBarry Smith 
6265e42470aSBarry Smith 
627