xref: /petsc/src/snes/impls/ls/ls.c (revision f63b844a08011cbceb00a6ecbb68fd67c9b34e11)
15e76c431SBarry Smith #ifndef lint
2*f63b844aSLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.66 1996/03/24 16:05:52 curfman Exp curfman $";
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 
27*f63b844aSLois Curfman McInnes int SNESSolve_EQ_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;
31112a2221SBarry Smith   MatStructure  flg = 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 
44cddf8d76SBarry Smith   ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);               /* xnorm = || X || */
455334005bSBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);          /*  F(X)      */
46cddf8d76SBarry Smith   ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr);	        /* fnorm <- ||F||  */
475e42470aSBarry Smith   snes->norm = fnorm;
485e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
4994a424c1SBarry Smith   SNESMonitor(snes,0,fnorm);
505e76c431SBarry Smith 
51d034289bSBarry Smith   /* set parameter for default relative tolerance convergence test */
52d034289bSBarry Smith   snes->ttol = fnorm*snes->rtol;
53d034289bSBarry 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 */
585334005bSBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
595334005bSBarry Smith     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
6078b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
6181b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
62ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr);
63761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
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;
71cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
7294a424c1SBarry Smith     SNESMonitor(snes,i+1,fnorm);
735e76c431SBarry Smith 
745e76c431SBarry Smith     /* Test for convergence */
75bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
7639e2f89bSBarry Smith       if (X != snes->vec_sol) {
77393d2d9aSLois Curfman McInnes         ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
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   }
8452392280SLois Curfman McInnes   if (i == maxits) {
8594a424c1SBarry Smith     PLogInfo(snes,
86*f63b844aSLois Curfman McInnes       "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
8752392280SLois Curfman McInnes     i--;
8852392280SLois Curfman McInnes   }
895e42470aSBarry Smith   *outits = i+1;
905e42470aSBarry Smith   return 0;
915e76c431SBarry Smith }
925e76c431SBarry Smith /* ------------------------------------------------------------ */
93*f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes )
945e76c431SBarry Smith {
955e42470aSBarry Smith   int ierr;
9681b6cf68SLois Curfman McInnes   snes->nwork = 4;
97d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr);
985e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
9981b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1005e42470aSBarry Smith   return 0;
1015e76c431SBarry Smith }
1025e76c431SBarry Smith /* ------------------------------------------------------------ */
103*f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj)
1045e76c431SBarry Smith {
1055e42470aSBarry Smith   SNES snes = (SNES) obj;
106393d2d9aSLois Curfman McInnes   int  ierr;
1074b0e389bSBarry Smith   ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
1080452661fSBarry Smith   PetscFree(snes->data);
1095e42470aSBarry Smith   return 0;
1105e76c431SBarry Smith }
1115e76c431SBarry Smith /* ------------------------------------------------------------ */
1125e76c431SBarry Smith /*ARGSUSED*/
1134b828684SBarry Smith /*@C
1145e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1155e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1165e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1175e76c431SBarry Smith 
1185e76c431SBarry Smith    Input Parameters:
1195e42470aSBarry Smith .  snes - nonlinear context
1205e76c431SBarry Smith .  x - current iterate
1215e76c431SBarry Smith .  f - residual evaluated at x
1225e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1235e76c431SBarry Smith .  w - work vector
1245e76c431SBarry Smith .  fnorm - 2-norm of f
1255e76c431SBarry Smith 
126c4a48953SLois Curfman McInnes    Output Parameters:
1275e76c431SBarry Smith .  g - residual evaluated at new iterate y
1285e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1295e76c431SBarry Smith .  gnorm - 2-norm of g
1305e76c431SBarry Smith .  ynorm - 2-norm of search length
131761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1325e76c431SBarry Smith 
133c4a48953SLois Curfman McInnes    Options Database Key:
134c4a48953SLois Curfman McInnes $  -snes_line_search basic
135c4a48953SLois Curfman McInnes 
13628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
13728ae5a21SLois Curfman McInnes 
138f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
13977c4ece6SBarry Smith           SNESSetLineSearch()
1405e76c431SBarry Smith @*/
1415e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
142761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1435e76c431SBarry Smith {
1445e42470aSBarry Smith   int    ierr;
1455334005bSBarry Smith   Scalar mone = -1.0;
1465334005bSBarry Smith 
147761aaf1bSLois Curfman McInnes   *flag = 0;
1487857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
149cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);              /* ynorm = || y || */
1505334005bSBarry Smith   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);                   /* y <- x + y      */
1515334005bSBarry Smith   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr);        /*  F(y)      */
152cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);              /* gnorm = || g || */
1537857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
154761aaf1bSLois Curfman McInnes   return 0;
1555e76c431SBarry Smith }
1565e76c431SBarry Smith /* ------------------------------------------------------------------ */
1574b828684SBarry Smith /*@C
158f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
159f59ffdedSLois Curfman McInnes    is the default line search method.
1605e76c431SBarry Smith 
1615e76c431SBarry Smith    Input Parameters:
1625e42470aSBarry Smith .  snes - nonlinear context
1635e76c431SBarry Smith .  x - current iterate
1645e76c431SBarry Smith .  f - residual evaluated at x
1655e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1665e76c431SBarry Smith .  w - work vector
1675e76c431SBarry Smith .  fnorm - 2-norm of f
1685e76c431SBarry Smith 
169393d2d9aSLois Curfman McInnes    Output Parameters:
1705e76c431SBarry Smith .  g - residual evaluated at new iterate y
1715e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1725e76c431SBarry Smith .  gnorm - 2-norm of g
1735e76c431SBarry Smith .  ynorm - 2-norm of search length
174761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1755e76c431SBarry Smith 
176c4a48953SLois Curfman McInnes    Options Database Key:
177c4a48953SLois Curfman McInnes $  -snes_line_search cubic
178c4a48953SLois Curfman McInnes 
1795e76c431SBarry Smith    Notes:
1805e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1815e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1825e76c431SBarry Smith 
18328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
18428ae5a21SLois Curfman McInnes 
18577c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
1865e76c431SBarry Smith @*/
1875e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
188761aaf1bSLois Curfman McInnes                         double fnorm, double *ynorm, double *gnorm,int *flag)
1895e76c431SBarry Smith {
190ddd12767SBarry Smith   double  steptol, initslope,lambdaprev, gnormprev,a, b, d, t1, t2;
191ddd12767SBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
1926b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
1935e42470aSBarry Smith   Scalar  cinitslope,clambda;
1946b5873e3SBarry Smith #endif
1955e42470aSBarry Smith   int     ierr, count;
1965e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
1975334005bSBarry Smith   Scalar  mone = -1.0,scale;
1985e76c431SBarry Smith 
1997857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
200761aaf1bSLois Curfman McInnes   *flag   = 0;
2015e76c431SBarry Smith   alpha   = neP->alpha;
2025e76c431SBarry Smith   maxstep = neP->maxstep;
2035e76c431SBarry Smith   steptol = neP->steptol;
2045e76c431SBarry Smith 
205cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
2065e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2075e42470aSBarry Smith     scale = maxstep/(*ynorm);
2086b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
20994a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2106b5873e3SBarry Smith #else
21194a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2126b5873e3SBarry Smith #endif
213393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2145e76c431SBarry Smith     *ynorm = maxstep;
2155e76c431SBarry Smith   }
2165e76c431SBarry Smith   minlambda = steptol/(*ynorm);
217a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2185e42470aSBarry Smith #if defined(PETSC_COMPLEX)
219a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2205e42470aSBarry Smith   initslope = real(cinitslope);
2215e42470aSBarry Smith #else
222a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2235e42470aSBarry Smith #endif
2245e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2255e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2265e76c431SBarry Smith 
227393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2285334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
22978b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
230cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2315e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
232393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
23394a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
234d93a2b8dSBarry Smith     goto theend;
2355e76c431SBarry Smith   }
2365e76c431SBarry Smith 
2375e76c431SBarry Smith   /* Fit points with quadratic */
2385e76c431SBarry Smith   lambda = 1.0; count = 0;
239a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2405e76c431SBarry Smith   lambdaprev = lambda;
2415e76c431SBarry Smith   gnormprev = *gnorm;
242ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
243ddd12767SBarry Smith   else lambda = lambdatemp;
244393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
2455334005bSBarry Smith   lambda = -lambda;
2465e42470aSBarry Smith #if defined(PETSC_COMPLEX)
247393d2d9aSLois Curfman McInnes   clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2485e42470aSBarry Smith #else
249393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2505e42470aSBarry Smith #endif
25178b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
252cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2535e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
254393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
25594a424c1SBarry Smith     PLogInfo(snes,
2564b828684SBarry Smith              "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda);
257d93a2b8dSBarry Smith     goto theend;
2585e76c431SBarry Smith   }
2595e76c431SBarry Smith 
2605e76c431SBarry Smith   /* Fit points with cubic */
2615e76c431SBarry Smith   count = 1;
2625e76c431SBarry Smith   while (1) {
2635e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
26494a424c1SBarry Smith       PLogInfo(snes,
2654b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
26694a424c1SBarry Smith       PLogInfo(snes,
267052efed2SBarry Smith          "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g initial slope %g\n",fnorm,*gnorm,*ynorm,lambda,initslope);
268393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
269761aaf1bSLois Curfman McInnes       *flag = -1; break;
2705e76c431SBarry Smith     }
2715e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2725e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
273ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2745e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2755e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2765e76c431SBarry Smith     d = b*b - 3*a*initslope;
2775e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2785e76c431SBarry Smith     if (a == 0.0) {
2795e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2805e76c431SBarry Smith     } else {
2815e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
2825e76c431SBarry Smith     }
2835e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
2845e76c431SBarry Smith       lambdatemp = .5*lambda;
2855e76c431SBarry Smith     }
2865e76c431SBarry Smith     lambdaprev = lambda;
2875e76c431SBarry Smith     gnormprev = *gnorm;
2885e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
2895e76c431SBarry Smith       lambda = .1*lambda;
2905e76c431SBarry Smith     }
2915e76c431SBarry Smith     else lambda = lambdatemp;
292393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
2935334005bSBarry Smith     lambda = -lambda;
2945e42470aSBarry Smith #if defined(PETSC_COMPLEX)
2955334005bSBarry Smith     clambda = lambda;
296393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2975e42470aSBarry Smith #else
298393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2995e42470aSBarry Smith #endif
30078b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
301cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3025e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
303393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
30494a424c1SBarry Smith       PLogInfo(snes,
3054b828684SBarry Smith                 "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda);
306761aaf1bSLois Curfman McInnes       *flag = -1; break;
3075e76c431SBarry Smith     }
3085e76c431SBarry Smith     count++;
3095e76c431SBarry Smith   }
310d93a2b8dSBarry Smith   theend:
3117857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3125e42470aSBarry Smith   return 0;
3135e76c431SBarry Smith }
31452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3154b828684SBarry Smith /*@C
3165e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3175e76c431SBarry Smith 
3185e42470aSBarry Smith    Input Parameters:
319f59ffdedSLois Curfman McInnes .  snes - the SNES context
3205e42470aSBarry Smith .  x - current iterate
3215e42470aSBarry Smith .  f - residual evaluated at x
3225e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3235e42470aSBarry Smith .  w - work vector
3245e42470aSBarry Smith .  fnorm - 2-norm of f
3255e42470aSBarry Smith 
326c4a48953SLois Curfman McInnes    Output Parameters:
3275e42470aSBarry Smith .  g - residual evaluated at new iterate y
3285e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3295e42470aSBarry Smith .  gnorm - 2-norm of g
3305e42470aSBarry Smith .  ynorm - 2-norm of search length
331761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3325e42470aSBarry Smith 
333c4a48953SLois Curfman McInnes    Options Database Key:
334c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
335c4a48953SLois Curfman McInnes 
3365e42470aSBarry Smith    Notes:
33777c4ece6SBarry Smith    Use SNESSetLineSearch()
338*f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3395e42470aSBarry Smith 
340f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
341f59ffdedSLois Curfman McInnes 
34277c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3435e42470aSBarry Smith @*/
3445e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
345761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3465e76c431SBarry Smith {
347ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3486b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3495e42470aSBarry Smith   Scalar  cinitslope,clambda;
3506b5873e3SBarry Smith #endif
3515e42470aSBarry Smith   int     ierr,count;
3525e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3535334005bSBarry Smith   Scalar  mone = -1.0,scale;
3545e76c431SBarry Smith 
3557857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
356761aaf1bSLois Curfman McInnes   *flag = 0;
3575e42470aSBarry Smith   alpha   = neP->alpha;
3585e42470aSBarry Smith   maxstep = neP->maxstep;
3595e42470aSBarry Smith   steptol = neP->steptol;
3605e76c431SBarry Smith 
361cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
3625e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3635e42470aSBarry Smith     scale = maxstep/(*ynorm);
364393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3655e42470aSBarry Smith     *ynorm = maxstep;
3665e76c431SBarry Smith   }
3675e42470aSBarry Smith   minlambda = steptol/(*ynorm);
368a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
3695e42470aSBarry Smith #if defined(PETSC_COMPLEX)
370a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
3715e42470aSBarry Smith   initslope = real(cinitslope);
3725e42470aSBarry Smith #else
373a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
3745e42470aSBarry Smith #endif
3755e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3765e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3775e42470aSBarry Smith 
378393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
3795334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
38078b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
381cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3825e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
383393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
38494a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
385d93a2b8dSBarry Smith     goto theend;
3865e42470aSBarry Smith   }
3875e42470aSBarry Smith 
3885e42470aSBarry Smith   /* Fit points with quadratic */
3895e42470aSBarry Smith   lambda = 1.0; count = 0;
3905e42470aSBarry Smith   count = 1;
3915e42470aSBarry Smith   while (1) {
3925e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
39394a424c1SBarry Smith       PLogInfo(snes,
3944b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
39594a424c1SBarry Smith       PLogInfo(snes,
396ddd12767SBarry Smith       "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda);
397393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
398761aaf1bSLois Curfman McInnes       *flag = -1; break;
3995e42470aSBarry Smith     }
400a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4015e42470aSBarry Smith     lambdaprev = lambda;
4025e42470aSBarry Smith     gnormprev = *gnorm;
4035e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4045e42470aSBarry Smith       lambda = .1*lambda;
4055e42470aSBarry Smith     } else lambda = lambdatemp;
406393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4075334005bSBarry Smith     lambda = -lambda;
4085e42470aSBarry Smith #if defined(PETSC_COMPLEX)
409393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4105e42470aSBarry Smith #else
411393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4125e42470aSBarry Smith #endif
41378b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
414cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4155e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
416393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
41794a424c1SBarry Smith       PLogInfo(snes,
418ddd12767SBarry Smith         "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n",lambda);
41906259719SBarry Smith       break;
4205e42470aSBarry Smith     }
4215e42470aSBarry Smith     count++;
4225e42470aSBarry Smith   }
423d93a2b8dSBarry Smith   theend:
4247857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4255e42470aSBarry Smith   return 0;
4265e76c431SBarry Smith }
4275e76c431SBarry Smith /* ------------------------------------------------------------ */
428c9e6a524SLois Curfman McInnes /*@C
42977c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
430*f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4315e76c431SBarry Smith 
4325e76c431SBarry Smith    Input Parameters:
433eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4345e76c431SBarry Smith .  func - pointer to int function
4355e76c431SBarry Smith 
436c4a48953SLois Curfman McInnes    Available Routines:
437f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
438f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
439f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4405e76c431SBarry Smith 
441c4a48953SLois Curfman McInnes     Options Database Keys:
442c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
443c4a48953SLois Curfman McInnes 
4445e76c431SBarry Smith    Calling sequence of func:
445f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
446761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
447761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4485e76c431SBarry Smith 
4495e76c431SBarry Smith     Input parameters for func:
4505e42470aSBarry Smith .   snes - nonlinear context
4515e76c431SBarry Smith .   x - current iterate
4525e76c431SBarry Smith .   f - residual evaluated at x
4535e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4545e76c431SBarry Smith .   w - work vector
4555e76c431SBarry Smith .   fnorm - 2-norm of f
4565e76c431SBarry Smith 
4575e76c431SBarry Smith     Output parameters for func:
4585e76c431SBarry Smith .   g - residual evaluated at new iterate y
4595e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4605e76c431SBarry Smith .   gnorm - 2-norm of g
4615e76c431SBarry Smith .   ynorm - 2-norm of search length
462761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
463761aaf1bSLois Curfman McInnes            on failure.
464f59ffdedSLois Curfman McInnes 
465f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
466f59ffdedSLois Curfman McInnes 
467f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4685e76c431SBarry Smith @*/
46977c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
470761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
4715e76c431SBarry Smith {
472*f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
4735e42470aSBarry Smith   return 0;
4745e76c431SBarry Smith }
47552392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
476*f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
4775e42470aSBarry Smith {
4785e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
4796daaf66cSBarry Smith 
480*f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
48177c4ece6SBarry Smith   PetscPrintf(snes->comm,"   %ssnes_line_search [basic,quadratic,cubic]\n",p);
4829aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_alpha <alpha> (default %g)\n",p,ls->alpha);
4839aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_maxstep <max> (default %g)\n",p,ls->maxstep);
4849aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_steptol <tol> (default %g)\n",p,ls->steptol);
4856b5873e3SBarry Smith   return 0;
4865e42470aSBarry Smith }
48752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
488*f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
489a935fc98SLois Curfman McInnes {
490a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
491a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
492d636dbe3SBarry Smith   FILE       *fd;
49319bcc07fSBarry Smith   char       *cstr;
49451695f54SLois Curfman McInnes   int        ierr;
49519bcc07fSBarry Smith   ViewerType vtype;
496a935fc98SLois Curfman McInnes 
49719bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
49819bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
49990ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
50019bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
50119bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
50219bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
50319bcc07fSBarry Smith     else cstr = "unknown";
50477c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
50577c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
506a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
50719bcc07fSBarry Smith   }
508a935fc98SLois Curfman McInnes   return 0;
509a935fc98SLois Curfman McInnes }
51052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
511*f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5125e42470aSBarry Smith {
5135e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5145e42470aSBarry Smith   char    ver[16];
5155e42470aSBarry Smith   double  tmp;
51625cdf11fSBarry Smith   int     ierr,flg;
5175e42470aSBarry Smith 
518ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp, &flg);CHKERRQ(ierr);
51925cdf11fSBarry Smith   if (flg) {
5205e42470aSBarry Smith     ls->alpha = tmp;
5215e42470aSBarry Smith   }
522ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp, &flg);CHKERRQ(ierr);
52325cdf11fSBarry Smith   if (flg) {
5245e42470aSBarry Smith     ls->maxstep = tmp;
5255e42470aSBarry Smith   }
526ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp, &flg);CHKERRQ(ierr);
52725cdf11fSBarry Smith   if (flg) {
5285e42470aSBarry Smith     ls->steptol = tmp;
5295e42470aSBarry Smith   }
530ee8b94d1SSatish Balay   ierr = OptionsGetString(snes->prefix,"-snes_line_search",ver,16, &flg); CHKERRQ(ierr);
53125cdf11fSBarry Smith   if (flg) {
53248d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
53377c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5345e42470aSBarry Smith     }
53548d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
53677c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5375e42470aSBarry Smith     }
53848d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
53977c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5405e42470aSBarry Smith     }
541*f63b844aSLois Curfman McInnes     else {SETERRQ(1,"SNESSetFromOptions_EQ_LS:Unknown line search");}
5425e42470aSBarry Smith   }
5435e42470aSBarry Smith   return 0;
5445e42470aSBarry Smith }
5455e42470aSBarry Smith /* ------------------------------------------------------------ */
546*f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
5475e42470aSBarry Smith {
5485e42470aSBarry Smith   SNES_LS *neP;
5495e42470aSBarry Smith 
550ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
551*f63b844aSLois Curfman McInnes     SETERRQ(1,"SNESCreate_EQ_LS:For SNES_NONLINEAR_EQUATIONS only");
552*f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
553*f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
554*f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
555*f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
556*f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
557*f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
558*f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
559*f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
5605e42470aSBarry Smith 
5610452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
562ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5635e42470aSBarry Smith   snes->data    	= (void *) neP;
5645e42470aSBarry Smith   neP->alpha		= 1.e-4;
5655e42470aSBarry Smith   neP->maxstep		= 1.e8;
5665e42470aSBarry Smith   neP->steptol		= 1.e-12;
5675e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5685e42470aSBarry Smith   return 0;
5695e42470aSBarry Smith }
5705e42470aSBarry Smith 
5715e42470aSBarry Smith 
5725e42470aSBarry Smith 
5735e42470aSBarry Smith 
574