xref: /petsc/src/snes/impls/ls/ls.c (revision 25cdf11f00656cd6142ccc252ca9e2f99af554b2)
15e76c431SBarry Smith #ifndef lint
2*25cdf11fSBarry Smith static char vcid[] = "$Id: ls.c,v 1.54 1996/01/12 03:55:48 bsmith Exp bsmith $";
35e76c431SBarry Smith #endif
45e76c431SBarry Smith 
55e76c431SBarry Smith #include <math.h>
6fbe28522SBarry Smith #include "ls.h"
7b16a3bb1SBarry Smith #include "pinclude/pviewer.h"
85e42470aSBarry Smith 
95e42470aSBarry Smith /*
105e42470aSBarry Smith      Implements a line search variant of Newton's Method
115e76c431SBarry Smith     for solving systems of nonlinear equations.
125e76c431SBarry Smith 
135e76c431SBarry Smith     Input parameters:
145e42470aSBarry Smith .   snes - nonlinear context obtained from SNESCreate()
155e76c431SBarry Smith 
165e42470aSBarry Smith     Output Parameters:
17a935fc98SLois Curfman McInnes .   outits  - Number of global iterations until termination.
185e76c431SBarry Smith 
195e76c431SBarry Smith     Notes:
205e76c431SBarry Smith     This implements essentially a truncated Newton method with a
215e76c431SBarry Smith     line search.  By default a cubic backtracking line search
225e76c431SBarry Smith     is employed, as described in the text "Numerical Methods for
235e76c431SBarry Smith     Unconstrained Optimization and Nonlinear Equations" by Dennis
24393d2d9aSLois Curfman McInnes     and Schnabel.
255e76c431SBarry Smith */
265e76c431SBarry Smith 
275e42470aSBarry Smith int SNESSolve_LS(SNES snes,int *outits)
285e76c431SBarry Smith {
295e42470aSBarry Smith   SNES_LS      *neP = (SNES_LS *) snes->data;
30761aaf1bSLois Curfman McInnes   int          maxits, i, history_len, ierr, lits, lsfail;
31df60cc22SBarry Smith   MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN;
326b5873e3SBarry Smith   double       fnorm, gnorm, xnorm, ynorm, *history;
335e42470aSBarry Smith   Vec          Y, X, F, G, W, TMP;
345e76c431SBarry Smith 
355e42470aSBarry Smith   history	= snes->conv_hist;	/* convergence history */
365e42470aSBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
375e42470aSBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
385e42470aSBarry Smith   X		= snes->vec_sol;	/* solution vector */
3939e2f89bSBarry Smith   F		= snes->vec_func;	/* residual vector */
405e42470aSBarry Smith   Y		= snes->work[0];	/* work vectors */
415e42470aSBarry Smith   G		= snes->work[1];
425e42470aSBarry Smith   W		= snes->work[2];
435e76c431SBarry Smith 
4478b31e54SBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr);        /* X <- X_0        */
45cddf8d76SBarry Smith   ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);               /* xnorm = || X || */
465334005bSBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);          /*  F(X)      */
47cddf8d76SBarry Smith   ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr);	        /* fnorm <- ||F||  */
485e42470aSBarry Smith   snes->norm = fnorm;
495e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
50ddd12767SBarry Smith   if (snes->monitor) {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);}
515e76c431SBarry Smith 
525e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
535e42470aSBarry Smith     snes->iter = i+1;
545e76c431SBarry Smith 
555e76c431SBarry Smith     /* Solve J Y = -F, where J is Jacobian matrix */
565334005bSBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
575334005bSBarry Smith     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
5878b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
5981b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
60ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr);
61761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
625e76c431SBarry Smith 
6339e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
6439e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
655e76c431SBarry Smith     fnorm = gnorm;
665e76c431SBarry Smith 
675e42470aSBarry Smith     snes->norm = fnorm;
685e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
69cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
70ddd12767SBarry Smith     if (snes->monitor) {ierr = (*snes->monitor)(snes,i+1,fnorm,snes->monP);CHKERRQ(ierr);}
715e76c431SBarry Smith 
725e76c431SBarry Smith     /* Test for convergence */
73bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
7439e2f89bSBarry Smith       if (X != snes->vec_sol) {
75393d2d9aSLois Curfman McInnes         ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
7639e2f89bSBarry Smith         snes->vec_sol_always = snes->vec_sol;
7739e2f89bSBarry Smith         snes->vec_func_always = snes->vec_func;
7839e2f89bSBarry Smith       }
795e76c431SBarry Smith       break;
805e76c431SBarry Smith     }
815e76c431SBarry Smith   }
8252392280SLois Curfman McInnes   if (i == maxits) {
8352392280SLois Curfman McInnes     PLogInfo((PetscObject)snes,
84ddd12767SBarry Smith       "SNESSolve_LS: Maximum number of iterations has been reached: %d\n",maxits);
8552392280SLois Curfman McInnes     i--;
8652392280SLois Curfman McInnes   }
875e42470aSBarry Smith   *outits = i+1;
885e42470aSBarry Smith   return 0;
895e76c431SBarry Smith }
905e76c431SBarry Smith /* ------------------------------------------------------------ */
915e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
925e76c431SBarry Smith {
935e42470aSBarry Smith   int ierr;
9481b6cf68SLois Curfman McInnes   snes->nwork = 4;
95d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr);
965e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
9781b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
985e42470aSBarry Smith   return 0;
995e76c431SBarry Smith }
1005e76c431SBarry Smith /* ------------------------------------------------------------ */
1015e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
1025e76c431SBarry Smith {
1035e42470aSBarry Smith   SNES snes = (SNES) obj;
104393d2d9aSLois Curfman McInnes   int  ierr;
1054b0e389bSBarry Smith   ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
1060452661fSBarry Smith   PetscFree(snes->data);
1075e42470aSBarry Smith   return 0;
1085e76c431SBarry Smith }
1095e76c431SBarry Smith /* ------------------------------------------------------------ */
1105e76c431SBarry Smith /*ARGSUSED*/
1114b828684SBarry Smith /*@C
1125e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1135e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1145e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1155e76c431SBarry Smith 
1165e76c431SBarry Smith    Input Parameters:
1175e42470aSBarry Smith .  snes - nonlinear context
1185e76c431SBarry Smith .  x - current iterate
1195e76c431SBarry Smith .  f - residual evaluated at x
1205e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1215e76c431SBarry Smith .  w - work vector
1225e76c431SBarry Smith .  fnorm - 2-norm of f
1235e76c431SBarry Smith 
124c4a48953SLois Curfman McInnes    Output Parameters:
1255e76c431SBarry Smith .  g - residual evaluated at new iterate y
1265e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1275e76c431SBarry Smith .  gnorm - 2-norm of g
1285e76c431SBarry Smith .  ynorm - 2-norm of search length
129761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1305e76c431SBarry Smith 
131c4a48953SLois Curfman McInnes    Options Database Key:
132c4a48953SLois Curfman McInnes $  -snes_line_search basic
133c4a48953SLois Curfman McInnes 
13428ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
13528ae5a21SLois Curfman McInnes 
136f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
137a935fc98SLois Curfman McInnes           SNESSetLineSearchRoutine()
1385e76c431SBarry Smith @*/
1395e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
140761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1415e76c431SBarry Smith {
1425e42470aSBarry Smith   int    ierr;
1435334005bSBarry Smith   Scalar mone = -1.0;
1445334005bSBarry Smith 
145761aaf1bSLois Curfman McInnes   *flag = 0;
1467857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
147cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);              /* ynorm = || y || */
1485334005bSBarry Smith   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);                   /* y <- x + y      */
1495334005bSBarry Smith   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr);        /*  F(y)      */
150cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);              /* gnorm = || g || */
1517857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
152761aaf1bSLois Curfman McInnes   return 0;
1535e76c431SBarry Smith }
1545e76c431SBarry Smith /* ------------------------------------------------------------------ */
1554b828684SBarry Smith /*@C
156f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
157f59ffdedSLois Curfman McInnes    is the default line search method.
1585e76c431SBarry Smith 
1595e76c431SBarry Smith    Input Parameters:
1605e42470aSBarry Smith .  snes - nonlinear context
1615e76c431SBarry Smith .  x - current iterate
1625e76c431SBarry Smith .  f - residual evaluated at x
1635e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1645e76c431SBarry Smith .  w - work vector
1655e76c431SBarry Smith .  fnorm - 2-norm of f
1665e76c431SBarry Smith 
167393d2d9aSLois Curfman McInnes    Output Parameters:
1685e76c431SBarry Smith .  g - residual evaluated at new iterate y
1695e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1705e76c431SBarry Smith .  gnorm - 2-norm of g
1715e76c431SBarry Smith .  ynorm - 2-norm of search length
172761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1735e76c431SBarry Smith 
174c4a48953SLois Curfman McInnes    Options Database Key:
175c4a48953SLois Curfman McInnes $  -snes_line_search cubic
176c4a48953SLois Curfman McInnes 
1775e76c431SBarry Smith    Notes:
1785e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1795e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1805e76c431SBarry Smith 
18128ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
18228ae5a21SLois Curfman McInnes 
183f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
1845e76c431SBarry Smith @*/
1855e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
186761aaf1bSLois Curfman McInnes                         double fnorm, double *ynorm, double *gnorm,int *flag)
1875e76c431SBarry Smith {
188ddd12767SBarry Smith   double  steptol, initslope,lambdaprev, gnormprev,a, b, d, t1, t2;
189ddd12767SBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
1906b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
1915e42470aSBarry Smith   Scalar  cinitslope,clambda;
1926b5873e3SBarry Smith #endif
1935e42470aSBarry Smith   int     ierr, count;
1945e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
1955334005bSBarry Smith   Scalar  mone = -1.0,scale;
1965e76c431SBarry Smith 
1977857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
198761aaf1bSLois Curfman McInnes   *flag   = 0;
1995e76c431SBarry Smith   alpha   = neP->alpha;
2005e76c431SBarry Smith   maxstep = neP->maxstep;
2015e76c431SBarry Smith   steptol = neP->steptol;
2025e76c431SBarry Smith 
203cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
2045e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2055e42470aSBarry Smith     scale = maxstep/(*ynorm);
2066b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
207ddd12767SBarry Smith     PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2086b5873e3SBarry Smith #else
209ddd12767SBarry Smith     PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2106b5873e3SBarry Smith #endif
211393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2125e76c431SBarry Smith     *ynorm = maxstep;
2135e76c431SBarry Smith   }
2145e76c431SBarry Smith   minlambda = steptol/(*ynorm);
215a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2165e42470aSBarry Smith #if defined(PETSC_COMPLEX)
217a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2185e42470aSBarry Smith   initslope = real(cinitslope);
2195e42470aSBarry Smith #else
220a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2215e42470aSBarry Smith #endif
2225e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2235e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2245e76c431SBarry Smith 
225393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2265334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
22778b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
228cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2295e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
230393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2314b828684SBarry Smith     PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Using full step\n");
232d93a2b8dSBarry Smith     goto theend;
2335e76c431SBarry Smith   }
2345e76c431SBarry Smith 
2355e76c431SBarry Smith   /* Fit points with quadratic */
2365e76c431SBarry Smith   lambda = 1.0; count = 0;
237a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2385e76c431SBarry Smith   lambdaprev = lambda;
2395e76c431SBarry Smith   gnormprev = *gnorm;
240ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
241ddd12767SBarry Smith   else lambda = lambdatemp;
242393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
2435334005bSBarry Smith   lambda = -lambda;
2445e42470aSBarry Smith #if defined(PETSC_COMPLEX)
245393d2d9aSLois Curfman McInnes   clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2465e42470aSBarry Smith #else
247393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2485e42470aSBarry Smith #endif
24978b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
250cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2515e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
252393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2534b828684SBarry Smith     PLogInfo((PetscObject)snes,
2544b828684SBarry Smith              "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda);
255d93a2b8dSBarry Smith     goto theend;
2565e76c431SBarry Smith   }
2575e76c431SBarry Smith 
2585e76c431SBarry Smith   /* Fit points with cubic */
2595e76c431SBarry Smith   count = 1;
2605e76c431SBarry Smith   while (1) {
2615e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
2624b828684SBarry Smith       PLogInfo((PetscObject)snes,
2634b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
2644b828684SBarry Smith       PLogInfo((PetscObject)snes,
265ddd12767SBarry Smith          "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda);
266393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
267761aaf1bSLois Curfman McInnes       *flag = -1; break;
2685e76c431SBarry Smith     }
2695e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2705e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
271ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2725e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2735e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2745e76c431SBarry Smith     d = b*b - 3*a*initslope;
2755e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2765e76c431SBarry Smith     if (a == 0.0) {
2775e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2785e76c431SBarry Smith     } else {
2795e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
2805e76c431SBarry Smith     }
2815e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
2825e76c431SBarry Smith       lambdatemp = .5*lambda;
2835e76c431SBarry Smith     }
2845e76c431SBarry Smith     lambdaprev = lambda;
2855e76c431SBarry Smith     gnormprev = *gnorm;
2865e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
2875e76c431SBarry Smith       lambda = .1*lambda;
2885e76c431SBarry Smith     }
2895e76c431SBarry Smith     else lambda = lambdatemp;
290393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
2915334005bSBarry Smith     lambda = -lambda;
2925e42470aSBarry Smith #if defined(PETSC_COMPLEX)
2935334005bSBarry Smith     clambda = lambda;
294393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2955e42470aSBarry Smith #else
296393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2975e42470aSBarry Smith #endif
29878b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
299cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3005e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
301393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
3024b828684SBarry Smith       PLogInfo((PetscObject)snes,
3034b828684SBarry Smith                 "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda);
304761aaf1bSLois Curfman McInnes       *flag = -1; break;
3055e76c431SBarry Smith     }
3065e76c431SBarry Smith     count++;
3075e76c431SBarry Smith   }
308d93a2b8dSBarry Smith   theend:
3097857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3105e42470aSBarry Smith   return 0;
3115e76c431SBarry Smith }
31252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3134b828684SBarry Smith /*@C
3145e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3155e76c431SBarry Smith 
3165e42470aSBarry Smith    Input Parameters:
317f59ffdedSLois Curfman McInnes .  snes - the SNES context
3185e42470aSBarry Smith .  x - current iterate
3195e42470aSBarry Smith .  f - residual evaluated at x
3205e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3215e42470aSBarry Smith .  w - work vector
3225e42470aSBarry Smith .  fnorm - 2-norm of f
3235e42470aSBarry Smith 
324c4a48953SLois Curfman McInnes    Output Parameters:
3255e42470aSBarry Smith .  g - residual evaluated at new iterate y
3265e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3275e42470aSBarry Smith .  gnorm - 2-norm of g
3285e42470aSBarry Smith .  ynorm - 2-norm of search length
329761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3305e42470aSBarry Smith 
331c4a48953SLois Curfman McInnes    Options Database Key:
332c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
333c4a48953SLois Curfman McInnes 
3345e42470aSBarry Smith    Notes:
335f59ffdedSLois Curfman McInnes    Use SNESSetLineSearchRoutine()
336ddd12767SBarry Smith    to set this routine within the SNES_EQ_NLS method.
3375e42470aSBarry Smith 
338f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
339f59ffdedSLois Curfman McInnes 
340f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
3415e42470aSBarry Smith @*/
3425e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
343761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3445e76c431SBarry Smith {
345ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3466b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3475e42470aSBarry Smith   Scalar  cinitslope,clambda;
3486b5873e3SBarry Smith #endif
3495e42470aSBarry Smith   int     ierr,count;
3505e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3515334005bSBarry Smith   Scalar  mone = -1.0,scale;
3525e76c431SBarry Smith 
3537857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
354761aaf1bSLois Curfman McInnes   *flag = 0;
3555e42470aSBarry Smith   alpha   = neP->alpha;
3565e42470aSBarry Smith   maxstep = neP->maxstep;
3575e42470aSBarry Smith   steptol = neP->steptol;
3585e76c431SBarry Smith 
359cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
3605e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3615e42470aSBarry Smith     scale = maxstep/(*ynorm);
362393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3635e42470aSBarry Smith     *ynorm = maxstep;
3645e76c431SBarry Smith   }
3655e42470aSBarry Smith   minlambda = steptol/(*ynorm);
366a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
3675e42470aSBarry Smith #if defined(PETSC_COMPLEX)
368a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
3695e42470aSBarry Smith   initslope = real(cinitslope);
3705e42470aSBarry Smith #else
371a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
3725e42470aSBarry Smith #endif
3735e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3745e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3755e42470aSBarry Smith 
376393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
3775334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
37878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
379cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3805e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
381393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
3824b828684SBarry Smith     PLogInfo((PetscObject)snes,"SNESQuadraticLineSearch: Using full step\n");
383d93a2b8dSBarry Smith     goto theend;
3845e42470aSBarry Smith   }
3855e42470aSBarry Smith 
3865e42470aSBarry Smith   /* Fit points with quadratic */
3875e42470aSBarry Smith   lambda = 1.0; count = 0;
3885e42470aSBarry Smith   count = 1;
3895e42470aSBarry Smith   while (1) {
3905e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
3914b828684SBarry Smith       PLogInfo((PetscObject)snes,
3924b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
3934b828684SBarry Smith       PLogInfo((PetscObject)snes,
394ddd12767SBarry Smith       "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda);
395393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
396761aaf1bSLois Curfman McInnes       *flag = -1; break;
3975e42470aSBarry Smith     }
398a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
3995e42470aSBarry Smith     lambdaprev = lambda;
4005e42470aSBarry Smith     gnormprev = *gnorm;
4015e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4025e42470aSBarry Smith       lambda = .1*lambda;
4035e42470aSBarry Smith     } else lambda = lambdatemp;
404393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4055334005bSBarry Smith     lambda = -lambda;
4065e42470aSBarry Smith #if defined(PETSC_COMPLEX)
407393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4085e42470aSBarry Smith #else
409393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4105e42470aSBarry Smith #endif
41178b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
412cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4135e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
414393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
4154b828684SBarry Smith       PLogInfo((PetscObject)snes,
416ddd12767SBarry Smith         "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n",lambda);
41706259719SBarry Smith       break;
4185e42470aSBarry Smith     }
4195e42470aSBarry Smith     count++;
4205e42470aSBarry Smith   }
421d93a2b8dSBarry Smith   theend:
4227857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4235e42470aSBarry Smith   return 0;
4245e76c431SBarry Smith }
4255e76c431SBarry Smith /* ------------------------------------------------------------ */
426c9e6a524SLois Curfman McInnes /*@C
4275e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
428fbe28522SBarry Smith    by the method SNES_LS.
4295e76c431SBarry Smith 
4305e76c431SBarry Smith    Input Parameters:
431eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4325e76c431SBarry Smith .  func - pointer to int function
4335e76c431SBarry Smith 
434c4a48953SLois Curfman McInnes    Available Routines:
435f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
436f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
437f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4385e76c431SBarry Smith 
439c4a48953SLois Curfman McInnes     Options Database Keys:
440c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
441c4a48953SLois Curfman McInnes 
4425e76c431SBarry Smith    Calling sequence of func:
443f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
444761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
445761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4465e76c431SBarry Smith 
4475e76c431SBarry Smith     Input parameters for func:
4485e42470aSBarry Smith .   snes - nonlinear context
4495e76c431SBarry Smith .   x - current iterate
4505e76c431SBarry Smith .   f - residual evaluated at x
4515e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4525e76c431SBarry Smith .   w - work vector
4535e76c431SBarry Smith .   fnorm - 2-norm of f
4545e76c431SBarry Smith 
4555e76c431SBarry Smith     Output parameters for func:
4565e76c431SBarry Smith .   g - residual evaluated at new iterate y
4575e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4585e76c431SBarry Smith .   gnorm - 2-norm of g
4595e76c431SBarry Smith .   ynorm - 2-norm of search length
460761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
461761aaf1bSLois Curfman McInnes            on failure.
462f59ffdedSLois Curfman McInnes 
463f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
464f59ffdedSLois Curfman McInnes 
465f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4665e76c431SBarry Smith @*/
4675e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
468761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
4695e76c431SBarry Smith {
4705334005bSBarry Smith   if ((snes)->type == SNES_EQ_NLS) ((SNES_LS *)(snes->data))->LineSearch = func;
4715e42470aSBarry Smith   return 0;
4725e76c431SBarry Smith }
47352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
4746daaf66cSBarry Smith static int SNESPrintHelp_LS(SNES snes,char *p)
4755e42470aSBarry Smith {
4765e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
4776daaf66cSBarry Smith 
47852392280SLois Curfman McInnes   MPIU_printf(snes->comm," method ls (system of nonlinear equations):\n");
47952392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search [basic,quadratic,cubic]\n",p);
48052392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_alpha alpha (default %g)\n",p,ls->alpha);
48152392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_maxstep max (default %g)\n",p,ls->maxstep);
48252392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_steptol tol (default %g)\n",p,ls->steptol);
4836b5873e3SBarry Smith   return 0;
4845e42470aSBarry Smith }
48552392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
486a935fc98SLois Curfman McInnes static int SNESView_LS(PetscObject obj,Viewer viewer)
487a935fc98SLois Curfman McInnes {
488a935fc98SLois Curfman McInnes   SNES    snes = (SNES)obj;
489a935fc98SLois Curfman McInnes   SNES_LS *ls = (SNES_LS *)snes->data;
490d636dbe3SBarry Smith   FILE    *fd;
491a935fc98SLois Curfman McInnes   char    *cstring;
49251695f54SLois Curfman McInnes   int     ierr;
493a935fc98SLois Curfman McInnes 
494a447f0b5SLois Curfman McInnes   ierr = ViewerFileGetPointer_Private(viewer,&fd); CHKERRQ(ierr);
495ddd12767SBarry Smith   if (ls->LineSearch == SNESNoLineSearch) cstring = "SNESNoLineSearch";
496ddd12767SBarry Smith   else if (ls->LineSearch == SNESQuadraticLineSearch) cstring = "SNESQuadraticLineSearch";
497ddd12767SBarry Smith   else if (ls->LineSearch == SNESCubicLineSearch) cstring = "SNESCubicLineSearch";
498ddd12767SBarry Smith   else cstring = "unknown";
499a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    line search variant: %s\n",cstring);
500a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
501a935fc98SLois Curfman McInnes                ls->alpha,ls->maxstep,ls->steptol);
502a935fc98SLois Curfman McInnes   return 0;
503a935fc98SLois Curfman McInnes }
50452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5055e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5065e42470aSBarry Smith {
5075e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5085e42470aSBarry Smith   char    ver[16];
5095e42470aSBarry Smith   double  tmp;
510*25cdf11fSBarry Smith   int     ierr,flg;
5115e42470aSBarry Smith 
512*25cdf11fSBarry Smith   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp);CHKERRQ(ierr);
513*25cdf11fSBarry Smith   if (flg) {
5145e42470aSBarry Smith     ls->alpha = tmp;
5155e42470aSBarry Smith   }
516*25cdf11fSBarry Smith   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp);CHKERRQ(ierr);
517*25cdf11fSBarry Smith   if (flg) {
5185e42470aSBarry Smith     ls->maxstep = tmp;
5195e42470aSBarry Smith   }
520*25cdf11fSBarry Smith   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp);CHKERRQ(ierr);
521*25cdf11fSBarry Smith   if (flg) {
5225e42470aSBarry Smith     ls->steptol = tmp;
5235e42470aSBarry Smith   }
524*25cdf11fSBarry Smith   ierr = OptionsGetString(snes->prefix,"-snes_line_search",ver,16);CHKERRQ(ierr);
525*25cdf11fSBarry Smith   if (flg) {
52648d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
5275e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5285e42470aSBarry Smith     }
52948d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
5305e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5315e42470aSBarry Smith     }
53248d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
5335e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5345e42470aSBarry Smith     }
5358c48e012SBarry Smith     else {SETERRQ(1,"SNESSetFromOptions_LS:Unknown line search");}
5365e42470aSBarry Smith   }
5375e42470aSBarry Smith   return 0;
5385e42470aSBarry Smith }
5395e42470aSBarry Smith /* ------------------------------------------------------------ */
5405e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
5415e42470aSBarry Smith {
5425e42470aSBarry Smith   SNES_LS *neP;
5435e42470aSBarry Smith 
544ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
545ddd12767SBarry Smith     SETERRQ(1,"SNESCreate_LS:For SNES_NONLINEAR_EQUATIONS only");
54625c7317fSLois Curfman McInnes   snes->type		= SNES_EQ_NLS;
54749e3953dSBarry Smith   snes->setup		= SNESSetUp_LS;
54849e3953dSBarry Smith   snes->solve		= SNESSolve_LS;
5495e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
550bbb6d6a8SBarry Smith   snes->converged	= SNESDefaultConverged;
55149e3953dSBarry Smith   snes->printhelp       = SNESPrintHelp_LS;
55249e3953dSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_LS;
553a935fc98SLois Curfman McInnes   snes->view            = SNESView_LS;
5545e42470aSBarry Smith 
5550452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
556ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5575e42470aSBarry Smith   snes->data    	= (void *) neP;
5585e42470aSBarry Smith   neP->alpha		= 1.e-4;
5595e42470aSBarry Smith   neP->maxstep		= 1.e8;
5605e42470aSBarry Smith   neP->steptol		= 1.e-12;
5615e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5625e42470aSBarry Smith   return 0;
5635e42470aSBarry Smith }
5645e42470aSBarry Smith 
5655e42470aSBarry Smith 
5665e42470aSBarry Smith 
5675e42470aSBarry Smith 
568