xref: /petsc/src/snes/impls/ls/ls.c (revision 23242f5a347c7ec34b2cd4c88fec47fa748e5b8b)
15e76c431SBarry Smith #ifndef lint
2*23242f5aSBarry Smith static char vcid[] = "$Id: ls.c,v 1.11 1995/04/25 16:24:36 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;
32*23242f5aSBarry Smith   int     maxits, i, history_len,ierr,lits,flg;
336b5873e3SBarry Smith   double  fnorm, gnorm, xnorm, ynorm, *history;
345e42470aSBarry Smith   Vec     Y, X, F, G, W, TMP;
355e76c431SBarry Smith 
365e42470aSBarry Smith   history	= snes->conv_hist;	/* convergence history */
375e42470aSBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
385e42470aSBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
395e42470aSBarry Smith   X		= snes->vec_sol;		/* solution vector */
405e42470aSBarry Smith   F		= snes->vec_res;		/* residual vector */
415e42470aSBarry Smith   Y		= snes->work[0];		/* work vectors */
425e42470aSBarry Smith   G		= snes->work[1];
435e42470aSBarry Smith   W		= snes->work[2];
445e76c431SBarry Smith 
455e42470aSBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr);  /* X <- X_0 */
465e42470aSBarry Smith   VecNorm( X, &xnorm );		       /* xnorm = || X || */
47a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */
485e42470aSBarry Smith   VecNorm(F, &fnorm );	        	/* fnorm <- || F || */
495e42470aSBarry Smith   snes->norm = fnorm;
505e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
51eafb4bcbSBarry Smith   if (snes->Monitor) (*snes->Monitor)(snes,0,fnorm,snes->monP);
525e76c431SBarry Smith 
535e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
545e42470aSBarry Smith        snes->iter = i+1;
555e76c431SBarry Smith 
565e76c431SBarry Smith        /* Solve J Y = -F, where J is Jacobian matrix */
57*23242f5aSBarry Smith        (*snes->ComputeJacobian)(snes,X,&snes->jacobian,&snes->jacobian_pre,
58*23242f5aSBarry Smith                                 &flg,snes->jacP);
59*23242f5aSBarry Smith        ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg);
605e42470aSBarry Smith        ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERR(ierr);
615e42470aSBarry Smith        ierr = (*neP->LineSearch)(snes, X, F, G, Y, W, fnorm, &ynorm, &gnorm );
62*23242f5aSBarry Smith        CHKERR(ierr);
635e76c431SBarry Smith 
645e76c431SBarry Smith        TMP = F; F = G; G = TMP;
655e76c431SBarry Smith        TMP = X; X = Y; Y = TMP;
665e76c431SBarry Smith        fnorm = gnorm;
675e76c431SBarry Smith 
685e42470aSBarry Smith        snes->norm = fnorm;
695e76c431SBarry Smith        if (history && history_len > i+1) history[i+1] = fnorm;
705e42470aSBarry Smith        VecNorm( X, &xnorm );		/* xnorm = || X || */
71eafb4bcbSBarry Smith        if (snes->Monitor) (*snes->Monitor)(snes,i+1,fnorm,snes->monP);
725e76c431SBarry Smith 
735e76c431SBarry Smith        /* Test for convergence */
745e42470aSBarry Smith        if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) {
755e42470aSBarry Smith            if (X != snes->vec_sol) VecCopy( X, snes->vec_sol );
765e76c431SBarry Smith            break;
775e76c431SBarry Smith        }
785e76c431SBarry Smith   }
795e76c431SBarry Smith   if (i == maxits) i--;
805e42470aSBarry Smith   *outits = i+1;
815e42470aSBarry Smith   return 0;
825e76c431SBarry Smith }
835e76c431SBarry Smith /* ------------------------------------------------------------ */
845e76c431SBarry Smith /*ARGSUSED*/
855e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
865e76c431SBarry Smith {
875e42470aSBarry Smith   int ierr;
885e42470aSBarry Smith   snes->nwork = 3;
895e42470aSBarry Smith   ierr = VecGetVecs( snes->vec_sol, snes->nwork,&snes->work ); CHKERR(ierr);
905e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work );
915e42470aSBarry Smith   return 0;
925e76c431SBarry Smith }
935e76c431SBarry Smith /* ------------------------------------------------------------ */
945e76c431SBarry Smith /*ARGSUSED*/
955e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
965e76c431SBarry Smith {
975e42470aSBarry Smith   SNES snes = (SNES) obj;
985e42470aSBarry Smith   SLESDestroy(snes->sles);
995e42470aSBarry Smith   VecFreeVecs(snes->work, snes->nwork );
1005e42470aSBarry Smith   PLogObjectDestroy(obj);
1015e42470aSBarry Smith   PETSCHEADERDESTROY(obj);
1025e42470aSBarry Smith   return 0;
1035e76c431SBarry Smith }
1045e42470aSBarry Smith /*@
1050de89847SLois Curfman McInnes    SNESDefaultMonitor - Default SNES monitoring routine.  Prints the
1065e42470aSBarry Smith    residual norm at each iteration.
1075e42470aSBarry Smith 
1085e42470aSBarry Smith    Input Parameters:
1090de89847SLois Curfman McInnes .  snes - the SNES context
1100de89847SLois Curfman McInnes .  its - iteration number
1110de89847SLois Curfman McInnes .  fnorm - 2-norm residual value (may be estimated)
1120de89847SLois Curfman McInnes .  dummy - unused context
1135e42470aSBarry Smith 
1145e42470aSBarry Smith    Notes:
1155e42470aSBarry Smith    f is either the residual or its negative, depending on the user's
116a9581db2SBarry Smith    preference, as set with SNESSetFunction().
117a67c8522SLois Curfman McInnes 
118a67c8522SLois Curfman McInnes .keywords: SNES, nonlinear, default, monitor, residual, norm
119a67c8522SLois Curfman McInnes 
120a67c8522SLois Curfman McInnes .seealso: SNESSetMonitor()
1215e42470aSBarry Smith @*/
122eafb4bcbSBarry Smith int SNESDefaultMonitor(SNES snes,int its, double fnorm,void *dummy)
1235e42470aSBarry Smith {
1245e42470aSBarry Smith   fprintf( stdout, "iter = %d, residual norm %g \n",its,fnorm);
1255e42470aSBarry Smith   return 0;
1265e42470aSBarry Smith }
1275e42470aSBarry Smith 
1285e42470aSBarry Smith /*@
1295e42470aSBarry Smith    SNESDefaultConverged - Default test for monitoring the convergence
1300de89847SLois Curfman McInnes    of the SNES solvers.
1315e42470aSBarry Smith 
1325e42470aSBarry Smith    Input Parameters:
1330de89847SLois Curfman McInnes .  snes - the SNES context
1345e42470aSBarry Smith .  xnorm - 2-norm of current iterate
1355e42470aSBarry Smith .  pnorm - 2-norm of current step
1365e42470aSBarry Smith .  fnorm - 2-norm of residual
1370de89847SLois Curfman McInnes .  dummy - unused context
1385e42470aSBarry Smith 
1395e42470aSBarry Smith    Returns:
1405e42470aSBarry Smith $  2  if  ( fnorm < atol ),
1415e42470aSBarry Smith $  3  if  ( pnorm < xtol*xnorm ),
1425e42470aSBarry Smith $ -2  if  ( nres > max_res ),
1435e42470aSBarry Smith $  0  otherwise,
1445e42470aSBarry Smith 
1455e42470aSBarry Smith    where
1465e42470aSBarry Smith $    atol    - absolute residual norm tolerance,
1470de89847SLois Curfman McInnes $              set with SNESSetAbsoluteTolerance()
1485e42470aSBarry Smith $    max_res - maximum number of residual evaluations,
1490de89847SLois Curfman McInnes $              set with SNESSetMaxResidualEvaluations()
1505e42470aSBarry Smith $    nres    - number of residual evaluations
1515e42470aSBarry Smith $    xtol    - relative residual norm tolerance,
1520de89847SLois Curfman McInnes $              set with SNESSetRelativeTolerance()
1535e42470aSBarry Smith 
1540de89847SLois Curfman McInnes .keywords: SNES, nonlinear, default, converged, convergence
1555e42470aSBarry Smith 
1560de89847SLois Curfman McInnes .seealso: SNESSetConvergenceTest()
1575e42470aSBarry Smith @*/
1585e42470aSBarry Smith int SNESDefaultConverged(SNES snes,double xnorm,double pnorm,double fnorm,
1595e42470aSBarry Smith                          void *dummy)
1605e42470aSBarry Smith {
1615e42470aSBarry Smith   if (fnorm < snes->atol) {
162a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
163a67c8522SLois Curfman McInnes       "Converged due to absolute residual norm %g < %g\n",fnorm,snes->atol);
1645e42470aSBarry Smith     return 2;
1655e42470aSBarry Smith   }
1665e42470aSBarry Smith   if (pnorm < snes->xtol*(xnorm)) {
167a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
168a67c8522SLois Curfman McInnes       "Converged due to small update length  %g < %g*%g\n",
1695e42470aSBarry Smith        pnorm,snes->xtol,xnorm);
1705e42470aSBarry Smith     return 3;
1715e42470aSBarry Smith   }
172a67c8522SLois Curfman McInnes   if (snes->nresids > snes->max_resids) {
173a67c8522SLois Curfman McInnes     PLogInfo((PetscObject)snes,
174a67c8522SLois Curfman McInnes       "Exceeded maximum number of residual evaluations: %d > %d\n",
175a67c8522SLois Curfman McInnes        snes->nresids, snes->max_resids );
176a67c8522SLois Curfman McInnes     return -2;
177a67c8522SLois Curfman McInnes   }
1785e42470aSBarry Smith   return 0;
1795e42470aSBarry Smith }
1805e42470aSBarry Smith 
1815e76c431SBarry Smith /* ------------------------------------------------------------ */
1825e76c431SBarry Smith /*ARGSUSED*/
1835e76c431SBarry Smith /*@
1845e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1855e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1865e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1875e76c431SBarry Smith 
1885e76c431SBarry Smith    Input Parameters:
1895e42470aSBarry Smith .  snes - nonlinear context
1905e76c431SBarry Smith .  x - current iterate
1915e76c431SBarry Smith .  f - residual evaluated at x
1925e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1935e76c431SBarry Smith .  w - work vector
1945e76c431SBarry Smith .  fnorm - 2-norm of f
1955e76c431SBarry Smith 
1965e76c431SBarry Smith    Output parameters:
1975e76c431SBarry Smith .  g - residual evaluated at new iterate y
1985e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1995e76c431SBarry Smith .  gnorm - 2-norm of g
2005e76c431SBarry Smith .  ynorm - 2-norm of search length
2015e76c431SBarry Smith 
2025e76c431SBarry Smith    Returns:
2035e76c431SBarry Smith    1, indicating success of the step.
2045e76c431SBarry Smith 
20528ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
20628ae5a21SLois Curfman McInnes 
207f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
208f59ffdedSLois Curfman McInnes .seealso: SNESSetLineSearchRoutine()
2095e76c431SBarry Smith @*/
2105e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
2115e42470aSBarry Smith                              double fnorm, double *ynorm, double *gnorm )
2125e76c431SBarry Smith {
2135e42470aSBarry Smith   int    ierr;
2145e42470aSBarry Smith   Scalar one = 1.0;
2157857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
2165e42470aSBarry Smith   VecNorm(y, ynorm );	/* ynorm = || y ||    */
2175e42470aSBarry Smith   VecAXPY(&one, x, y );	/* y <- x + y         */
218a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,y,g); CHKERR(ierr);
2195e42470aSBarry Smith   VecNorm( g, gnorm ); 	/* gnorm = || g ||    */
2207857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
2215e76c431SBarry Smith   return 1;
2225e76c431SBarry Smith }
2235e76c431SBarry Smith /* ------------------------------------------------------------------ */
2245e76c431SBarry Smith /*@
225f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
226f59ffdedSLois Curfman McInnes    is the default line search method.
2275e76c431SBarry Smith 
2285e76c431SBarry Smith    Input Parameters:
2295e42470aSBarry Smith .  snes - nonlinear context
2305e76c431SBarry Smith .  x - current iterate
2315e76c431SBarry Smith .  f - residual evaluated at x
2325e76c431SBarry Smith .  y - search direction (contains new iterate on output)
2335e76c431SBarry Smith .  w - work vector
2345e76c431SBarry Smith .  fnorm - 2-norm of f
2355e76c431SBarry Smith 
2365e76c431SBarry Smith    Output parameters:
2375e76c431SBarry Smith .  g - residual evaluated at new iterate y
2385e76c431SBarry Smith .  y - new iterate (contains search direction on input)
2395e76c431SBarry Smith .  gnorm - 2-norm of g
2405e76c431SBarry Smith .  ynorm - 2-norm of search length
2415e76c431SBarry Smith 
2425e76c431SBarry Smith    Returns:
2435e76c431SBarry Smith    1 if the line search succeeds; 0 if the line search fails.
2445e76c431SBarry Smith 
2455e76c431SBarry Smith    Notes:
2465e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
2475e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
2485e76c431SBarry Smith 
24928ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
25028ae5a21SLois Curfman McInnes 
251f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
2525e76c431SBarry Smith @*/
2535e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
2545e42470aSBarry Smith                               double fnorm, double *ynorm, double *gnorm )
2555e76c431SBarry Smith {
2565e42470aSBarry Smith   double  steptol, initslope;
2575e42470aSBarry Smith   double  lambdaprev, gnormprev;
2585e76c431SBarry Smith   double  a, b, d, t1, t2;
2596b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2605e42470aSBarry Smith   Scalar  cinitslope,clambda;
2616b5873e3SBarry Smith #endif
2625e42470aSBarry Smith   int     ierr,count;
2635e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2645e42470aSBarry Smith   Scalar  one = 1.0,scale;
2655e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
2665e76c431SBarry Smith 
2677857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
2685e76c431SBarry Smith   alpha   = neP->alpha;
2695e76c431SBarry Smith   maxstep = neP->maxstep;
2705e76c431SBarry Smith   steptol = neP->steptol;
2715e76c431SBarry Smith 
2725e42470aSBarry Smith   VecNorm(y, ynorm );
2735e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2745e42470aSBarry Smith     scale = maxstep/(*ynorm);
2756b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2766b5873e3SBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",real(scale));
2776b5873e3SBarry Smith #else
2785e42470aSBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",scale);
2796b5873e3SBarry Smith #endif
2805e42470aSBarry Smith     VecScale(&scale, y );
2815e76c431SBarry Smith     *ynorm = maxstep;
2825e76c431SBarry Smith   }
2835e76c431SBarry Smith   minlambda = steptol/(*ynorm);
2845e42470aSBarry Smith #if defined(PETSC_COMPLEX)
2855e42470aSBarry Smith   VecDot(f, y, &cinitslope );
2865e42470aSBarry Smith   initslope = real(cinitslope);
2875e42470aSBarry Smith #else
2885e42470aSBarry Smith   VecDot(f, y, &initslope );
2895e42470aSBarry Smith #endif
2905e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2915e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2925e76c431SBarry Smith 
2935e42470aSBarry Smith   VecCopy(y, w );
2945e42470aSBarry Smith   VecAXPY(&one, x, w );
295a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERR(ierr);
2965e42470aSBarry Smith   VecNorm(g, gnorm );
2975e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
2985e42470aSBarry Smith       VecCopy(w, y );
2995e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Using full step\n");
3007857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3015e42470aSBarry Smith       return 0;
3025e76c431SBarry Smith   }
3035e76c431SBarry Smith 
3045e76c431SBarry Smith   /* Fit points with quadratic */
3055e76c431SBarry Smith   lambda = 1.0; count = 0;
3065e76c431SBarry Smith   lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
3075e76c431SBarry Smith   lambdaprev = lambda;
3085e76c431SBarry Smith   gnormprev = *gnorm;
3095e76c431SBarry Smith   if (lambdatemp <= .1*lambda) {
3105e76c431SBarry Smith       lambda = .1*lambda;
3115e76c431SBarry Smith   } else lambda = lambdatemp;
3125e42470aSBarry Smith   VecCopy(x, w );
3135e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3145e42470aSBarry Smith   clambda = lambda; VecAXPY(&clambda, y, w );
3155e42470aSBarry Smith #else
3165e42470aSBarry Smith   VecAXPY(&lambda, y, w );
3175e42470aSBarry Smith #endif
318a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERR(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,"Quadratically determined step, lambda %g\n",lambda);
3237857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3245e42470aSBarry Smith       return 0;
3255e76c431SBarry Smith   }
3265e76c431SBarry Smith 
3275e76c431SBarry Smith   /* Fit points with cubic */
3285e76c431SBarry Smith   count = 1;
3295e76c431SBarry Smith   while (1) {
3305e76c431SBarry Smith       if (lambda <= minlambda) { /* bad luck; use full step */
3315e42470aSBarry Smith            PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
3325e42470aSBarry Smith            PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
3335e76c431SBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
3345e42470aSBarry Smith            VecCopy(w, y );
3357857610eSBarry Smith            PLogEventEnd(SNES_LineSearch,snes,x,f,g);
336*23242f5aSBarry Smith            return -1;
3375e76c431SBarry Smith       }
3385e76c431SBarry Smith       t1 = *gnorm - fnorm - lambda*initslope;
3395e76c431SBarry Smith       t2 = gnormprev  - fnorm - lambdaprev*initslope;
3405e76c431SBarry Smith       a = (t1/(lambda*lambda) -
3415e76c431SBarry Smith                 t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3425e76c431SBarry Smith       b = (-lambdaprev*t1/(lambda*lambda) +
3435e76c431SBarry Smith                 lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3445e76c431SBarry Smith       d = b*b - 3*a*initslope;
3455e76c431SBarry Smith       if (d < 0.0) d = 0.0;
3465e76c431SBarry Smith       if (a == 0.0) {
3475e76c431SBarry Smith          lambdatemp = -initslope/(2.0*b);
3485e76c431SBarry Smith       } else {
3495e76c431SBarry Smith          lambdatemp = (-b + sqrt(d))/(3.0*a);
3505e76c431SBarry Smith       }
3515e76c431SBarry Smith       if (lambdatemp > .5*lambda) {
3525e76c431SBarry Smith          lambdatemp = .5*lambda;
3535e76c431SBarry Smith       }
3545e76c431SBarry Smith       lambdaprev = lambda;
3555e76c431SBarry Smith       gnormprev = *gnorm;
3565e76c431SBarry Smith       if (lambdatemp <= .1*lambda) {
3575e76c431SBarry Smith          lambda = .1*lambda;
3585e76c431SBarry Smith       }
3595e76c431SBarry Smith       else lambda = lambdatemp;
3605e42470aSBarry Smith       VecCopy( x, w );
3615e42470aSBarry Smith #if defined(PETSC_COMPLEX)
3625e42470aSBarry Smith       VecAXPY(&clambda, y, w );
3635e42470aSBarry Smith #else
3645e42470aSBarry Smith       VecAXPY(&lambda, y, w );
3655e42470aSBarry Smith #endif
366a9581db2SBarry Smith       ierr = SNESComputeFunction(snes,w,g); CHKERR(ierr);
3675e42470aSBarry Smith       VecNorm(g, gnorm );
3685e76c431SBarry Smith       if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
3695e42470aSBarry Smith          VecCopy(w, y );
3705e42470aSBarry Smith          PLogInfo((PetscObject)snes,"Cubically determined step, lambda %g\n",lambda);
3717857610eSBarry Smith          PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3725e42470aSBarry Smith          return 0;
3735e76c431SBarry Smith       }
3745e76c431SBarry Smith       count++;
3755e76c431SBarry Smith    }
3767857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3775e42470aSBarry Smith   return 0;
3785e76c431SBarry Smith }
3795e42470aSBarry Smith /*@
3805e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3815e76c431SBarry Smith 
3825e42470aSBarry Smith    Input Parameters:
383f59ffdedSLois Curfman McInnes .  snes - the SNES context
3845e42470aSBarry Smith .  x - current iterate
3855e42470aSBarry Smith .  f - residual evaluated at x
3865e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3875e42470aSBarry Smith .  w - work vector
3885e42470aSBarry Smith .  fnorm - 2-norm of f
3895e42470aSBarry Smith 
3905e42470aSBarry Smith    Output parameters:
3915e42470aSBarry Smith .  g - residual evaluated at new iterate y
3925e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3935e42470aSBarry Smith .  gnorm - 2-norm of g
3945e42470aSBarry Smith .  ynorm - 2-norm of search length
3955e42470aSBarry Smith 
3965e42470aSBarry Smith    Returns:
3975e42470aSBarry Smith    1 if the line search succeeds; 0 if the line search fails.
3985e42470aSBarry Smith 
3995e42470aSBarry Smith    Notes:
400f59ffdedSLois Curfman McInnes    Use SNESSetLineSearchRoutine()
401f59ffdedSLois Curfman McInnes    to set this routine within the SNES_NLS method.
4025e42470aSBarry Smith 
403f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
404f59ffdedSLois Curfman McInnes 
405f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
4065e42470aSBarry Smith @*/
4075e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
4085e42470aSBarry Smith                               double fnorm, double *ynorm, double *gnorm )
4095e76c431SBarry Smith {
4105e42470aSBarry Smith   double  steptol, initslope;
4115e42470aSBarry Smith   double  lambdaprev, gnormprev;
4126b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
4135e42470aSBarry Smith   Scalar  cinitslope,clambda;
4146b5873e3SBarry Smith #endif
4155e42470aSBarry Smith   int     ierr,count;
4165e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
4175e42470aSBarry Smith   Scalar  one = 1.0,scale;
4185e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
4195e76c431SBarry Smith 
4207857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
4215e42470aSBarry Smith   alpha   = neP->alpha;
4225e42470aSBarry Smith   maxstep = neP->maxstep;
4235e42470aSBarry Smith   steptol = neP->steptol;
4245e76c431SBarry Smith 
4255e42470aSBarry Smith   VecNorm(y, ynorm );
4265e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
4275e42470aSBarry Smith     scale = maxstep/(*ynorm);
4285e42470aSBarry Smith     VecScale(&scale, y );
4295e42470aSBarry Smith     *ynorm = maxstep;
4305e76c431SBarry Smith   }
4315e42470aSBarry Smith   minlambda = steptol/(*ynorm);
4325e42470aSBarry Smith #if defined(PETSC_COMPLEX)
4335e42470aSBarry Smith   VecDot(f, y, &cinitslope );
4345e42470aSBarry Smith   initslope = real(cinitslope);
4355e42470aSBarry Smith #else
4365e42470aSBarry Smith   VecDot(f, y, &initslope );
4375e42470aSBarry Smith #endif
4385e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
4395e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
4405e42470aSBarry Smith 
4415e42470aSBarry Smith   VecCopy(y, w );
4425e42470aSBarry Smith   VecAXPY(&one, x, w );
443a9581db2SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERR(ierr);
4445e42470aSBarry Smith   VecNorm(g, gnorm );
4455e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
4465e42470aSBarry Smith       VecCopy(w, y );
4475e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Using full step\n");
4487857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4495e42470aSBarry Smith       return 0;
4505e42470aSBarry Smith   }
4515e42470aSBarry Smith 
4525e42470aSBarry Smith   /* Fit points with quadratic */
4535e42470aSBarry Smith   lambda = 1.0; count = 0;
4545e42470aSBarry Smith   count = 1;
4555e42470aSBarry Smith   while (1) {
4565e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
4575e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
4585e42470aSBarry Smith       PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
4595e42470aSBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
4605e42470aSBarry Smith       VecCopy(w, y );
4617857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4625e42470aSBarry Smith       return 0;
4635e42470aSBarry Smith     }
4645e42470aSBarry Smith     lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
4655e42470aSBarry Smith     lambdaprev = lambda;
4665e42470aSBarry Smith     gnormprev = *gnorm;
4675e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4685e42470aSBarry Smith       lambda = .1*lambda;
4695e42470aSBarry Smith     } else lambda = lambdatemp;
4705e42470aSBarry Smith     VecCopy(x, w );
4715e42470aSBarry Smith #if defined(PETSC_COMPLEX)
4725e42470aSBarry Smith     clambda = lambda; VecAXPY(&clambda, y, w );
4735e42470aSBarry Smith #else
4745e42470aSBarry Smith     VecAXPY(&lambda, y, w );
4755e42470aSBarry Smith #endif
476a9581db2SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERR(ierr);
4775e42470aSBarry Smith     VecNorm(g, gnorm );
4785e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
4795e42470aSBarry Smith       VecCopy(w, y );
4805e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
4817857610eSBarry Smith       PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4825e42470aSBarry Smith       return 0;
4835e42470aSBarry Smith     }
4845e42470aSBarry Smith     count++;
4855e42470aSBarry Smith   }
4865e42470aSBarry Smith 
4877857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4885e42470aSBarry Smith   return 0;
4895e76c431SBarry Smith }
4905e76c431SBarry Smith /* ------------------------------------------------------------ */
4915e76c431SBarry Smith /*@C
4925e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
493fbe28522SBarry Smith    by the method SNES_LS.
4945e76c431SBarry Smith 
4955e76c431SBarry Smith    Input Parameters:
496eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4975e76c431SBarry Smith .  func - pointer to int function
4985e76c431SBarry Smith 
4995e76c431SBarry Smith    Possible routines:
500f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
501f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
502f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
5035e76c431SBarry Smith 
5045e76c431SBarry Smith    Calling sequence of func:
505f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
5065e42470aSBarry Smith          Vec w, double fnorm, double *ynorm, double *gnorm)
5075e76c431SBarry Smith 
5085e76c431SBarry Smith     Input parameters for func:
5095e42470aSBarry Smith .   snes - nonlinear context
5105e76c431SBarry Smith .   x - current iterate
5115e76c431SBarry Smith .   f - residual evaluated at x
5125e76c431SBarry Smith .   y - search direction (contains new iterate on output)
5135e76c431SBarry Smith .   w - work vector
5145e76c431SBarry Smith .   fnorm - 2-norm of f
5155e76c431SBarry Smith 
5165e76c431SBarry Smith     Output parameters for func:
5175e76c431SBarry Smith .   g - residual evaluated at new iterate y
5185e76c431SBarry Smith .   y - new iterate (contains search direction on input)
5195e76c431SBarry Smith .   gnorm - 2-norm of g
5205e76c431SBarry Smith .   ynorm - 2-norm of search length
5215e76c431SBarry Smith 
5225e76c431SBarry Smith     Returned by func:
5235e76c431SBarry Smith     1 if the line search succeeds; 0 if the line search fails.
524f59ffdedSLois Curfman McInnes 
525f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
526f59ffdedSLois Curfman McInnes 
527f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
5285e76c431SBarry Smith @*/
5295e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
5305e42470aSBarry Smith                              double,double *,double*) )
5315e76c431SBarry Smith {
532fbe28522SBarry Smith   if ((snes)->type == SNES_NLS)
5335e42470aSBarry Smith     ((SNES_LS *)(snes->data))->LineSearch = func;
5345e42470aSBarry Smith   return 0;
5355e76c431SBarry Smith }
5365e42470aSBarry Smith 
5375e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes)
5385e42470aSBarry Smith {
5395e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5405e42470aSBarry Smith   fprintf(stderr,"-snes_line_search [basic,quadratic,cubic]\n");
5415e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_alpha alpha (default %g)\n",ls->alpha);
5425e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_maxstep max (default %g)\n",ls->maxstep);
5435e42470aSBarry Smith   fprintf(stderr,"-snes_line_search_steptol tol (default %g)\n",ls->steptol);
5446b5873e3SBarry Smith   return 0;
5455e42470aSBarry Smith }
5465e42470aSBarry Smith 
5476b5873e3SBarry Smith #include "options.h"
5485e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5495e42470aSBarry Smith {
5505e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5515e42470aSBarry Smith   char    ver[16];
5525e42470aSBarry Smith   double  tmp;
5535e42470aSBarry Smith 
5545e42470aSBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_alpa",&tmp)) {
5555e42470aSBarry Smith     ls->alpha = tmp;
5565e42470aSBarry Smith   }
5575e42470aSBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_maxstep",&tmp)) {
5585e42470aSBarry Smith     ls->maxstep = tmp;
5595e42470aSBarry Smith   }
5605e42470aSBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_steptol",&tmp)) {
5615e42470aSBarry Smith     ls->steptol = tmp;
5625e42470aSBarry Smith   }
5635e42470aSBarry Smith   if (OptionsGetString(0,snes->prefix,"-snes_line_search",ver,16)) {
5645e42470aSBarry Smith     if (!strcmp(ver,"basic")) {
5655e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5665e42470aSBarry Smith     }
5675e42470aSBarry Smith     else if (!strcmp(ver,"quadratic")) {
5685e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5695e42470aSBarry Smith     }
5705e42470aSBarry Smith     else if (!strcmp(ver,"cubic")) {
5715e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5725e42470aSBarry Smith     }
5735e42470aSBarry Smith     else {SETERR(1,"Unknown line search?");}
5745e42470aSBarry Smith   }
5755e42470aSBarry Smith   return 0;
5765e42470aSBarry Smith }
5775e42470aSBarry Smith 
5785e42470aSBarry Smith /* ------------------------------------------------------------ */
5795e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
5805e42470aSBarry Smith {
5815e42470aSBarry Smith   SNES_LS *neP;
5825e42470aSBarry Smith 
583fbe28522SBarry Smith   snes->type		= SNES_NLS;
5845e42470aSBarry Smith   snes->Setup		= SNESSetUp_LS;
5855e42470aSBarry Smith   snes->Solver		= SNESSolve_LS;
5865e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
5875e42470aSBarry Smith   snes->Converged	= SNESDefaultConverged;
5885e42470aSBarry Smith   snes->PrintHelp       = SNESPrintHelp_LS;
5895e42470aSBarry Smith   snes->SetFromOptions  = SNESSetFromOptions_LS;
5905e42470aSBarry Smith 
5915e42470aSBarry Smith   neP			= NEW(SNES_LS);   CHKPTR(neP);
5925e42470aSBarry Smith   snes->data    	= (void *) neP;
5935e42470aSBarry Smith   neP->alpha		= 1.e-4;
5945e42470aSBarry Smith   neP->maxstep		= 1.e8;
5955e42470aSBarry Smith   neP->steptol		= 1.e-12;
5965e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5975e42470aSBarry Smith   return 0;
5985e42470aSBarry Smith }
5995e42470aSBarry Smith 
6005e42470aSBarry Smith 
6015e42470aSBarry Smith 
6025e42470aSBarry Smith 
603