xref: /petsc/src/snes/impls/ls/ls.c (revision 614e12f882facc7034cea413fc32dd1973cefaef)
15e76c431SBarry Smith #ifndef lint
2*614e12f8SBarry Smith static char vcid[] = "$Id: ls.c,v 1.20 1995/05/30 22:52:06 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;
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 
465e42470aSBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr);  /* X <- X_0 */
475e42470aSBarry Smith   VecNorm( X, &xnorm );		       /* xnorm = || X || */
48a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERR(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,
59df60cc22SBarry Smith                                 &flg,snes->jacP); CHKERR(ierr);
6023242f5aSBarry Smith        ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg);
615e42470aSBarry Smith        ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERR(ierr);
625e42470aSBarry Smith        ierr = (*neP->LineSearch)(snes, X, F, G, Y, W, fnorm, &ynorm, &gnorm );
6323242f5aSBarry Smith        CHKERR(ierr);
645e76c431SBarry Smith 
6539e2f89bSBarry Smith        TMP = F; F = G; snes->vec_func_always = F; G = TMP;
6639e2f89bSBarry Smith        TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
675e76c431SBarry Smith        fnorm = gnorm;
685e76c431SBarry Smith 
695e42470aSBarry Smith        snes->norm = fnorm;
705e76c431SBarry Smith        if (history && history_len > i+1) history[i+1] = fnorm;
715e42470aSBarry Smith        VecNorm( X, &xnorm );		/* xnorm = || X || */
72eafb4bcbSBarry Smith        if (snes->Monitor) (*snes->Monitor)(snes,i+1,fnorm,snes->monP);
735e76c431SBarry Smith 
745e76c431SBarry Smith        /* Test for convergence */
755e42470aSBarry Smith        if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) {
7639e2f89bSBarry Smith            if (X != snes->vec_sol) {
7739e2f89bSBarry Smith              VecCopy( X, snes->vec_sol );
7839e2f89bSBarry Smith              snes->vec_sol_always = snes->vec_sol;
7939e2f89bSBarry Smith              snes->vec_func_always = snes->vec_func;
8039e2f89bSBarry Smith            }
815e76c431SBarry Smith            break;
825e76c431SBarry Smith        }
835e76c431SBarry Smith   }
845e76c431SBarry Smith   if (i == maxits) i--;
855e42470aSBarry Smith   *outits = i+1;
865e42470aSBarry Smith   return 0;
875e76c431SBarry Smith }
885e76c431SBarry Smith /* ------------------------------------------------------------ */
895e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
905e76c431SBarry Smith {
915e42470aSBarry Smith   int ierr;
925e42470aSBarry Smith   snes->nwork = 3;
935e42470aSBarry Smith   ierr = VecGetVecs( snes->vec_sol, snes->nwork,&snes->work ); CHKERR(ierr);
945e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work );
955e42470aSBarry Smith   return 0;
965e76c431SBarry Smith }
975e76c431SBarry Smith /* ------------------------------------------------------------ */
985e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
995e76c431SBarry Smith {
1005e42470aSBarry Smith   SNES snes = (SNES) obj;
1015e42470aSBarry Smith   VecFreeVecs(snes->work, snes->nwork );
102df60cc22SBarry Smith   FREE(snes->data);
1035e42470aSBarry Smith   return 0;
1045e76c431SBarry Smith }
1055e42470aSBarry Smith /*@
1060de89847SLois Curfman McInnes    SNESDefaultMonitor - Default SNES monitoring routine.  Prints the
1075e42470aSBarry Smith    residual norm at each iteration.
1085e42470aSBarry Smith 
1095e42470aSBarry Smith    Input Parameters:
1100de89847SLois Curfman McInnes .  snes - the SNES context
1110de89847SLois Curfman McInnes .  its - iteration number
1120de89847SLois Curfman McInnes .  fnorm - 2-norm residual value (may be estimated)
1130de89847SLois Curfman McInnes .  dummy - unused context
1145e42470aSBarry Smith 
1155e42470aSBarry Smith    Notes:
1165e42470aSBarry Smith    f is either the residual or its negative, depending on the user's
117a9581db2SBarry Smith    preference, as set with SNESSetFunction().
118a67c8522SLois Curfman McInnes 
119a67c8522SLois Curfman McInnes .keywords: SNES, nonlinear, default, monitor, residual, norm
120a67c8522SLois Curfman McInnes 
121a67c8522SLois Curfman McInnes .seealso: SNESSetMonitor()
1225e42470aSBarry Smith @*/
123eafb4bcbSBarry Smith int SNESDefaultMonitor(SNES snes,int its, double fnorm,void *dummy)
1245e42470aSBarry Smith {
125*614e12f8SBarry Smith   MPIU_printf(snes->comm, "iter = %d, Function norm %g \n",its,fnorm);
126*614e12f8SBarry Smith   return 0;
127*614e12f8SBarry Smith }
128*614e12f8SBarry Smith 
129*614e12f8SBarry Smith int SNESDefaultSMonitor(SNES snes,int its, double fnorm,void *dummy)
130*614e12f8SBarry Smith {
131*614e12f8SBarry Smith   if (fnorm > 1.e-9 || fnorm == 0.0) {
1327f813858SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm %g \n",its,fnorm);
13369e4de80SBarry Smith   }
134*614e12f8SBarry Smith   else if (fnorm > 1.e-11){
13569e4de80SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm %5.3e \n",its,fnorm);
13669e4de80SBarry Smith   }
137*614e12f8SBarry Smith   else {
138*614e12f8SBarry Smith     MPIU_printf(snes->comm, "iter = %d, Function norm < 1.e-11\n",its);
139*614e12f8SBarry Smith   }
1405e42470aSBarry Smith   return 0;
1415e42470aSBarry Smith }
1425e42470aSBarry Smith 
1435e42470aSBarry Smith /*@
1445e42470aSBarry Smith    SNESDefaultConverged - Default test for monitoring the convergence
1450de89847SLois Curfman McInnes    of the SNES solvers.
1465e42470aSBarry Smith 
1475e42470aSBarry Smith    Input Parameters:
1480de89847SLois Curfman McInnes .  snes - the SNES context
1495e42470aSBarry Smith .  xnorm - 2-norm of current iterate
1505e42470aSBarry Smith .  pnorm - 2-norm of current step
1515e42470aSBarry Smith .  fnorm - 2-norm of residual
1520de89847SLois Curfman McInnes .  dummy - unused context
1535e42470aSBarry Smith 
1545e42470aSBarry Smith    Returns:
1555e42470aSBarry Smith $  2  if  ( fnorm < atol ),
1565e42470aSBarry Smith $  3  if  ( pnorm < xtol*xnorm ),
1575e42470aSBarry Smith $ -2  if  ( nres > max_res ),
1585e42470aSBarry Smith $  0  otherwise,
1595e42470aSBarry Smith 
1605e42470aSBarry Smith    where
1615e42470aSBarry Smith $    atol    - absolute residual norm tolerance,
1620de89847SLois Curfman McInnes $              set with SNESSetAbsoluteTolerance()
1635e42470aSBarry Smith $    max_res - maximum number of residual evaluations,
1640de89847SLois Curfman McInnes $              set with SNESSetMaxResidualEvaluations()
1655e42470aSBarry Smith $    nres    - number of residual evaluations
1665e42470aSBarry Smith $    xtol    - relative residual norm tolerance,
1670de89847SLois Curfman McInnes $              set with SNESSetRelativeTolerance()
1685e42470aSBarry Smith 
1690de89847SLois Curfman McInnes .keywords: SNES, nonlinear, default, converged, convergence
1705e42470aSBarry Smith 
1710de89847SLois Curfman McInnes .seealso: SNESSetConvergenceTest()
1725e42470aSBarry Smith @*/
1735e42470aSBarry Smith int SNESDefaultConverged(SNES snes,double xnorm,double pnorm,double fnorm,
1745e42470aSBarry Smith                          void *dummy)
1755e42470aSBarry Smith {
1765e42470aSBarry Smith   if (fnorm < snes->atol) {
177a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
178a67c8522SLois Curfman McInnes       "Converged due to absolute residual norm %g < %g\n",fnorm,snes->atol);
1795e42470aSBarry Smith     return 2;
1805e42470aSBarry Smith   }
1815e42470aSBarry Smith   if (pnorm < snes->xtol*(xnorm)) {
182a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
183a67c8522SLois Curfman McInnes       "Converged due to small update length  %g < %g*%g\n",
1845e42470aSBarry Smith        pnorm,snes->xtol,xnorm);
1855e42470aSBarry Smith     return 3;
1865e42470aSBarry Smith   }
18749e3953dSBarry Smith   if (snes->nfuncs > snes->max_funcs) {
188a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
189a67c8522SLois Curfman McInnes       "Exceeded maximum number of residual evaluations: %d > %d\n",
19049e3953dSBarry Smith        snes->nfuncs, snes->max_funcs );
191a67c8522SLois Curfman McInnes     return -2;
192a67c8522SLois Curfman McInnes   }
1935e42470aSBarry Smith   return 0;
1945e42470aSBarry Smith }
1955e42470aSBarry Smith 
1965e76c431SBarry Smith /* ------------------------------------------------------------ */
1975e76c431SBarry Smith /*ARGSUSED*/
1985e76c431SBarry Smith /*@
1995e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
2005e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
2015e76c431SBarry Smith    to serve as a template and is not recommended for general use.
2025e76c431SBarry Smith 
2035e76c431SBarry Smith    Input Parameters:
2045e42470aSBarry Smith .  snes - nonlinear context
2055e76c431SBarry Smith .  x - current iterate
2065e76c431SBarry Smith .  f - residual evaluated at x
2075e76c431SBarry Smith .  y - search direction (contains new iterate on output)
2085e76c431SBarry Smith .  w - work vector
2095e76c431SBarry Smith .  fnorm - 2-norm of f
2105e76c431SBarry Smith 
211c4a48953SLois Curfman McInnes    Output Parameters:
2125e76c431SBarry Smith .  g - residual evaluated at new iterate y
2135e76c431SBarry Smith .  y - new iterate (contains search direction on input)
2145e76c431SBarry Smith .  gnorm - 2-norm of g
2155e76c431SBarry Smith .  ynorm - 2-norm of search length
2165e76c431SBarry Smith 
217c4a48953SLois Curfman McInnes    Options Database Key:
218c4a48953SLois Curfman McInnes $  -snes_line_search basic
219c4a48953SLois Curfman McInnes 
2205e76c431SBarry Smith    Returns:
2215e76c431SBarry Smith    1, indicating success of the step.
2225e76c431SBarry Smith 
22328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
22428ae5a21SLois Curfman McInnes 
225f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
226f59ffdedSLois Curfman McInnes .seealso: SNESSetLineSearchRoutine()
2275e76c431SBarry Smith @*/
2285e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
2295e42470aSBarry Smith                              double fnorm, double *ynorm, double *gnorm )
2305e76c431SBarry Smith {
2315e42470aSBarry Smith   int    ierr;
2325e42470aSBarry Smith   Scalar one = 1.0;
2337857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
2345e42470aSBarry Smith   VecNorm(y, ynorm );	/* ynorm = || y ||    */
2355e42470aSBarry Smith   VecAXPY(&one, x, y );	/* y <- x + y         */
236a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,y,g); CHKERR(ierr);
2375e42470aSBarry Smith   VecNorm( g, gnorm ); 	/* gnorm = || g ||    */
2387857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
2395e76c431SBarry Smith   return 1;
2405e76c431SBarry Smith }
2415e76c431SBarry Smith /* ------------------------------------------------------------------ */
2425e76c431SBarry Smith /*@
243f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
244f59ffdedSLois Curfman McInnes    is the default line search method.
2455e76c431SBarry Smith 
2465e76c431SBarry Smith    Input Parameters:
2475e42470aSBarry Smith .  snes - nonlinear context
2485e76c431SBarry Smith .  x - current iterate
2495e76c431SBarry Smith .  f - residual evaluated at x
2505e76c431SBarry Smith .  y - search direction (contains new iterate on output)
2515e76c431SBarry Smith .  w - work vector
2525e76c431SBarry Smith .  fnorm - 2-norm of f
2535e76c431SBarry Smith 
2545e76c431SBarry Smith    Output parameters:
2555e76c431SBarry Smith .  g - residual evaluated at new iterate y
2565e76c431SBarry Smith .  y - new iterate (contains search direction on input)
2575e76c431SBarry Smith .  gnorm - 2-norm of g
2585e76c431SBarry Smith .  ynorm - 2-norm of search length
2595e76c431SBarry Smith 
2605e76c431SBarry Smith    Returns:
2615e76c431SBarry Smith    1 if the line search succeeds; 0 if the line search fails.
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,
2755e42470aSBarry Smith                               double fnorm, double *ynorm, double *gnorm )
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);
2895e76c431SBarry Smith   alpha   = neP->alpha;
2905e76c431SBarry Smith   maxstep = neP->maxstep;
2915e76c431SBarry Smith   steptol = neP->steptol;
2925e76c431SBarry Smith 
2935e42470aSBarry Smith   VecNorm(y, ynorm );
2945e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2955e42470aSBarry Smith     scale = maxstep/(*ynorm);
2966b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2976b5873e3SBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",real(scale));
2986b5873e3SBarry Smith #else
2995e42470aSBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",scale);
3006b5873e3SBarry Smith #endif
3015e42470aSBarry Smith     VecScale(&scale, y );
3025e76c431SBarry Smith     *ynorm = maxstep;
3035e76c431SBarry Smith   }
3045e76c431SBarry Smith   minlambda = steptol/(*ynorm);
3055e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3065e42470aSBarry Smith   VecDot(f, y, &cinitslope );
3075e42470aSBarry Smith   initslope = real(cinitslope);
3085e42470aSBarry Smith #else
3095e42470aSBarry Smith   VecDot(f, y, &initslope );
3105e42470aSBarry Smith #endif
3115e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
3125e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
3135e76c431SBarry Smith 
3145e42470aSBarry Smith   VecCopy(y, w );
3155e42470aSBarry Smith   VecAXPY(&one, x, w );
316a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERR(ierr);
3175e42470aSBarry Smith   VecNorm(g, gnorm );
3185e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
3195e42470aSBarry Smith       VecCopy(w, y );
3205e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Using full step\n");
3217857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3225e42470aSBarry Smith       return 0;
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
339a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERR(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);
3447857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
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 );
3567857610eSBarry Smith            PLogEventEnd(SNES_LineSearch,snes,x,f,g);
35723242f5aSBarry Smith            return -1;
3585e76c431SBarry Smith       }
3595e76c431SBarry Smith       t1 = *gnorm - fnorm - lambda*initslope;
3605e76c431SBarry Smith       t2 = gnormprev  - fnorm - lambdaprev*initslope;
3615e76c431SBarry Smith       a = (t1/(lambda*lambda) -
3625e76c431SBarry Smith                 t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3635e76c431SBarry Smith       b = (-lambdaprev*t1/(lambda*lambda) +
3645e76c431SBarry Smith                 lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3655e76c431SBarry Smith       d = b*b - 3*a*initslope;
3665e76c431SBarry Smith       if (d < 0.0) d = 0.0;
3675e76c431SBarry Smith       if (a == 0.0) {
3685e76c431SBarry Smith          lambdatemp = -initslope/(2.0*b);
3695e76c431SBarry Smith       } else {
3705e76c431SBarry Smith          lambdatemp = (-b + sqrt(d))/(3.0*a);
3715e76c431SBarry Smith       }
3725e76c431SBarry Smith       if (lambdatemp > .5*lambda) {
3735e76c431SBarry Smith          lambdatemp = .5*lambda;
3745e76c431SBarry Smith       }
3755e76c431SBarry Smith       lambdaprev = lambda;
3765e76c431SBarry Smith       gnormprev = *gnorm;
3775e76c431SBarry Smith       if (lambdatemp <= .1*lambda) {
3785e76c431SBarry Smith          lambda = .1*lambda;
3795e76c431SBarry Smith       }
3805e76c431SBarry Smith       else lambda = lambdatemp;
3815e42470aSBarry Smith       VecCopy( x, w );
3825e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3835e42470aSBarry Smith       VecAXPY(&clambda, y, w );
3845e42470aSBarry Smith #else
3855e42470aSBarry Smith       VecAXPY(&lambda, y, w );
3865e42470aSBarry Smith #endif
387a9581db2SBarry Smith       ierr = SNESComputeFunction(snes,w,g); CHKERR(ierr);
3885e42470aSBarry Smith       VecNorm(g, gnorm );
3895e76c431SBarry Smith       if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
3905e42470aSBarry Smith          VecCopy(w, y );
3915e42470aSBarry Smith          PLogInfo((PetscObject)snes,"Cubically determined step, lambda %g\n",lambda);
3927857610eSBarry Smith          PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3935e42470aSBarry Smith          return 0;
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 );
467a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERR(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 );
4857857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4865e42470aSBarry Smith       return 0;
4875e42470aSBarry Smith     }
4885e42470aSBarry Smith     lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
4895e42470aSBarry Smith     lambdaprev = lambda;
4905e42470aSBarry Smith     gnormprev = *gnorm;
4915e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4925e42470aSBarry Smith       lambda = .1*lambda;
4935e42470aSBarry Smith     } else lambda = lambdatemp;
4945e42470aSBarry Smith     VecCopy(x, w );
4955e42470aSBarry Smith #if defined(PETSC_COMPLEX)
4965e42470aSBarry Smith     clambda = lambda; VecAXPY(&clambda, y, w );
4975e42470aSBarry Smith #else
4985e42470aSBarry Smith     VecAXPY(&lambda, y, w );
4995e42470aSBarry Smith #endif
500a9581db2SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERR(ierr);
5015e42470aSBarry Smith     VecNorm(g, gnorm );
5025e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
5035e42470aSBarry Smith       VecCopy(w, y );
5045e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
5057857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
5065e42470aSBarry Smith       return 0;
5075e42470aSBarry Smith     }
5085e42470aSBarry Smith     count++;
5095e42470aSBarry Smith   }
5105e42470aSBarry Smith 
5117857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
5125e42470aSBarry Smith   return 0;
5135e76c431SBarry Smith }
5145e76c431SBarry Smith /* ------------------------------------------------------------ */
5155e76c431SBarry Smith /*@C
5165e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
517fbe28522SBarry Smith    by the method SNES_LS.
5185e76c431SBarry Smith 
5195e76c431SBarry Smith    Input Parameters:
520eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
5215e76c431SBarry Smith .  func - pointer to int function
5225e76c431SBarry Smith 
523c4a48953SLois Curfman McInnes    Available Routines:
524f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
525f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
526f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
5275e76c431SBarry Smith 
528c4a48953SLois Curfman McInnes     Options Database Keys:
529c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
530c4a48953SLois Curfman McInnes 
5315e76c431SBarry Smith    Calling sequence of func:
532f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
5335e42470aSBarry Smith          Vec w, double fnorm, double *ynorm, double *gnorm)
5345e76c431SBarry Smith 
5355e76c431SBarry Smith     Input parameters for func:
5365e42470aSBarry Smith .   snes - nonlinear context
5375e76c431SBarry Smith .   x - current iterate
5385e76c431SBarry Smith .   f - residual evaluated at x
5395e76c431SBarry Smith .   y - search direction (contains new iterate on output)
5405e76c431SBarry Smith .   w - work vector
5415e76c431SBarry Smith .   fnorm - 2-norm of f
5425e76c431SBarry Smith 
5435e76c431SBarry Smith     Output parameters for func:
5445e76c431SBarry Smith .   g - residual evaluated at new iterate y
5455e76c431SBarry Smith .   y - new iterate (contains search direction on input)
5465e76c431SBarry Smith .   gnorm - 2-norm of g
5475e76c431SBarry Smith .   ynorm - 2-norm of search length
5485e76c431SBarry Smith 
5495e76c431SBarry Smith     Returned by func:
5505e76c431SBarry Smith     1 if the line search succeeds; 0 if the line search fails.
551f59ffdedSLois Curfman McInnes 
552f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
553f59ffdedSLois Curfman McInnes 
554f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
5555e76c431SBarry Smith @*/
5565e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
5575e42470aSBarry Smith                              double,double *,double*) )
5585e76c431SBarry Smith {
559fbe28522SBarry Smith   if ((snes)->type == SNES_NLS)
5605e42470aSBarry Smith     ((SNES_LS *)(snes->data))->LineSearch = func;
5615e42470aSBarry Smith   return 0;
5625e76c431SBarry Smith }
5635e42470aSBarry Smith 
5645e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes)
5655e42470aSBarry Smith {
5665e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5675e42470aSBarry Smith   fprintf(stderr,"-snes_line_search [basic,quadratic,cubic]\n");
5685e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_alpha alpha (default %g)\n",ls->alpha);
5695e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_maxstep max (default %g)\n",ls->maxstep);
5705e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_steptol tol (default %g)\n",ls->steptol);
5716b5873e3SBarry Smith   return 0;
5725e42470aSBarry Smith }
5735e42470aSBarry Smith 
5745e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5755e42470aSBarry Smith {
5765e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5775e42470aSBarry Smith   char    ver[16];
5785e42470aSBarry Smith   double  tmp;
5795e42470aSBarry Smith 
580df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) {
5815e42470aSBarry Smith     ls->alpha = tmp;
5825e42470aSBarry Smith   }
583df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) {
5845e42470aSBarry Smith     ls->maxstep = tmp;
5855e42470aSBarry Smith   }
586df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) {
5875e42470aSBarry Smith     ls->steptol = tmp;
5885e42470aSBarry Smith   }
589df60cc22SBarry Smith   if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) {
5905e42470aSBarry Smith     if (!strcmp(ver,"basic")) {
5915e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5925e42470aSBarry Smith     }
5935e42470aSBarry Smith     else if (!strcmp(ver,"quadratic")) {
5945e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5955e42470aSBarry Smith     }
5965e42470aSBarry Smith     else if (!strcmp(ver,"cubic")) {
5975e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5985e42470aSBarry Smith     }
5995e42470aSBarry Smith     else {SETERR(1,"Unknown line search?");}
6005e42470aSBarry Smith   }
6015e42470aSBarry Smith   return 0;
6025e42470aSBarry Smith }
6035e42470aSBarry Smith 
6045e42470aSBarry Smith /* ------------------------------------------------------------ */
6055e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
6065e42470aSBarry Smith {
6075e42470aSBarry Smith   SNES_LS *neP;
6085e42470aSBarry Smith 
609fbe28522SBarry Smith   snes->type		= SNES_NLS;
61049e3953dSBarry Smith   snes->setup		= SNESSetUp_LS;
61149e3953dSBarry Smith   snes->solve		= SNESSolve_LS;
6125e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
6135e42470aSBarry Smith   snes->Converged	= SNESDefaultConverged;
61449e3953dSBarry Smith   snes->printhelp       = SNESPrintHelp_LS;
61549e3953dSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_LS;
6165e42470aSBarry Smith 
6175e42470aSBarry Smith   neP			= NEW(SNES_LS);   CHKPTR(neP);
6185e42470aSBarry Smith   snes->data    	= (void *) neP;
6195e42470aSBarry Smith   neP->alpha		= 1.e-4;
6205e42470aSBarry Smith   neP->maxstep		= 1.e8;
6215e42470aSBarry Smith   neP->steptol		= 1.e-12;
6225e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
6235e42470aSBarry Smith   return 0;
6245e42470aSBarry Smith }
6255e42470aSBarry Smith 
6265e42470aSBarry Smith 
6275e42470aSBarry Smith 
6285e42470aSBarry Smith 
629