xref: /petsc/src/snes/impls/ls/ls.c (revision 25ed9cd1e4b63bc4e77603ab4704181db3325795)
15e76c431SBarry Smith #ifndef lint
2*25ed9cd1SBarry Smith static char vcid[] = "$Id: ls.c,v 1.70 1996/08/12 03:42:59 bsmith Exp bsmith $";
35e76c431SBarry Smith #endif
45e76c431SBarry Smith 
55e76c431SBarry Smith #include <math.h>
670f55243SBarry Smith #include "src/snes/impls/ls/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 
27f63b844aSLois 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 || */
45*25ed9cd1SBarry Smith   snes->iter = 0;
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;
5094a424c1SBarry Smith   SNESMonitor(snes,0,fnorm);
515e76c431SBarry Smith 
52d034289bSBarry Smith   /* set parameter for default relative tolerance convergence test */
53d034289bSBarry Smith   snes->ttol = fnorm*snes->rtol;
54d034289bSBarry Smith 
555e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
565e42470aSBarry Smith     snes->iter = i+1;
575e76c431SBarry Smith 
585e76c431SBarry Smith     /* Solve J Y = -F, where J is Jacobian matrix */
595334005bSBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
605334005bSBarry Smith     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
6178b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
6281b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
63ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr);
64761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
655e76c431SBarry Smith 
6639e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
6739e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
685e76c431SBarry Smith     fnorm = gnorm;
695e76c431SBarry Smith 
705e42470aSBarry Smith     snes->norm = fnorm;
715e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
72cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
7394a424c1SBarry Smith     SNESMonitor(snes,i+1,fnorm);
745e76c431SBarry Smith 
755e76c431SBarry Smith     /* Test for convergence */
76bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
7739e2f89bSBarry Smith       if (X != snes->vec_sol) {
78393d2d9aSLois Curfman McInnes         ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
7939e2f89bSBarry Smith         snes->vec_sol_always = snes->vec_sol;
8039e2f89bSBarry Smith         snes->vec_func_always = snes->vec_func;
8139e2f89bSBarry Smith       }
825e76c431SBarry Smith       break;
835e76c431SBarry Smith     }
845e76c431SBarry Smith   }
8552392280SLois Curfman McInnes   if (i == maxits) {
8694a424c1SBarry Smith     PLogInfo(snes,
87f63b844aSLois Curfman McInnes       "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
8852392280SLois Curfman McInnes     i--;
8952392280SLois Curfman McInnes   }
905e42470aSBarry Smith   *outits = i+1;
915e42470aSBarry Smith   return 0;
925e76c431SBarry Smith }
935e76c431SBarry Smith /* ------------------------------------------------------------ */
94f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes )
955e76c431SBarry Smith {
965e42470aSBarry Smith   int ierr;
9781b6cf68SLois Curfman McInnes   snes->nwork = 4;
98d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
995e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
10081b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1015e42470aSBarry Smith   return 0;
1025e76c431SBarry Smith }
1035e76c431SBarry Smith /* ------------------------------------------------------------ */
104f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj)
1055e76c431SBarry Smith {
1065e42470aSBarry Smith   SNES snes = (SNES) obj;
107393d2d9aSLois Curfman McInnes   int  ierr;
1085baf8537SBarry Smith   if (snes->nwork) {
1094b0e389bSBarry Smith     ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
11021c89e3eSBarry Smith   }
1110452661fSBarry Smith   PetscFree(snes->data);
1125e42470aSBarry Smith   return 0;
1135e76c431SBarry Smith }
1145e76c431SBarry Smith /* ------------------------------------------------------------ */
1155e76c431SBarry Smith /*ARGSUSED*/
1164b828684SBarry Smith /*@C
1175e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1185e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1195e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1205e76c431SBarry Smith 
1215e76c431SBarry Smith    Input Parameters:
1225e42470aSBarry Smith .  snes - nonlinear context
1235e76c431SBarry Smith .  x - current iterate
1245e76c431SBarry Smith .  f - residual evaluated at x
1255e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1265e76c431SBarry Smith .  w - work vector
1275e76c431SBarry Smith .  fnorm - 2-norm of f
1285e76c431SBarry Smith 
129c4a48953SLois Curfman McInnes    Output Parameters:
1305e76c431SBarry Smith .  g - residual evaluated at new iterate y
1315e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1325e76c431SBarry Smith .  gnorm - 2-norm of g
1335e76c431SBarry Smith .  ynorm - 2-norm of search length
134761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1355e76c431SBarry Smith 
136c4a48953SLois Curfman McInnes    Options Database Key:
137c4a48953SLois Curfman McInnes $  -snes_line_search basic
138c4a48953SLois Curfman McInnes 
13928ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
14028ae5a21SLois Curfman McInnes 
141f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
14277c4ece6SBarry Smith           SNESSetLineSearch()
1435e76c431SBarry Smith @*/
1445e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
145761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1465e76c431SBarry Smith {
1475e42470aSBarry Smith   int    ierr;
1485334005bSBarry Smith   Scalar mone = -1.0;
1495334005bSBarry Smith 
150761aaf1bSLois Curfman McInnes   *flag = 0;
1517857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
152cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);              /* ynorm = || y || */
1535334005bSBarry Smith   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);                   /* y <- x + y      */
1545334005bSBarry Smith   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr);        /*  F(y)      */
155cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);              /* gnorm = || g || */
1567857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
157761aaf1bSLois Curfman McInnes   return 0;
1585e76c431SBarry Smith }
1595e76c431SBarry Smith /* ------------------------------------------------------------------ */
1604b828684SBarry Smith /*@C
161f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
162f59ffdedSLois Curfman McInnes    is the default line search method.
1635e76c431SBarry Smith 
1645e76c431SBarry Smith    Input Parameters:
1655e42470aSBarry Smith .  snes - nonlinear context
1665e76c431SBarry Smith .  x - current iterate
1675e76c431SBarry Smith .  f - residual evaluated at x
1685e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1695e76c431SBarry Smith .  w - work vector
1705e76c431SBarry Smith .  fnorm - 2-norm of f
1715e76c431SBarry Smith 
172393d2d9aSLois Curfman McInnes    Output Parameters:
1735e76c431SBarry Smith .  g - residual evaluated at new iterate y
1745e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1755e76c431SBarry Smith .  gnorm - 2-norm of g
1765e76c431SBarry Smith .  ynorm - 2-norm of search length
177761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1785e76c431SBarry Smith 
179c4a48953SLois Curfman McInnes    Options Database Key:
180c4a48953SLois Curfman McInnes $  -snes_line_search cubic
181c4a48953SLois Curfman McInnes 
1825e76c431SBarry Smith    Notes:
1835e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1845e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1855e76c431SBarry Smith 
18628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
18728ae5a21SLois Curfman McInnes 
18877c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
1895e76c431SBarry Smith @*/
1905e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
191761aaf1bSLois Curfman McInnes                         double fnorm, double *ynorm, double *gnorm,int *flag)
1925e76c431SBarry Smith {
193ddd12767SBarry Smith   double  steptol, initslope,lambdaprev, gnormprev,a, b, d, t1, t2;
194ddd12767SBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
1956b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
1965e42470aSBarry Smith   Scalar  cinitslope,clambda;
1976b5873e3SBarry Smith #endif
1985e42470aSBarry Smith   int     ierr, count;
1995e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2005334005bSBarry Smith   Scalar  mone = -1.0,scale;
2015e76c431SBarry Smith 
2027857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
203761aaf1bSLois Curfman McInnes   *flag   = 0;
2045e76c431SBarry Smith   alpha   = neP->alpha;
2055e76c431SBarry Smith   maxstep = neP->maxstep;
2065e76c431SBarry Smith   steptol = neP->steptol;
2075e76c431SBarry Smith 
208cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
2095e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2105e42470aSBarry Smith     scale = maxstep/(*ynorm);
2116b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
21294a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2136b5873e3SBarry Smith #else
21494a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2156b5873e3SBarry Smith #endif
216393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2175e76c431SBarry Smith     *ynorm = maxstep;
2185e76c431SBarry Smith   }
2195e76c431SBarry Smith   minlambda = steptol/(*ynorm);
220a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2215e42470aSBarry Smith #if defined(PETSC_COMPLEX)
222a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2235e42470aSBarry Smith   initslope = real(cinitslope);
2245e42470aSBarry Smith #else
225a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2265e42470aSBarry Smith #endif
2275e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2285e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2295e76c431SBarry Smith 
230393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2315334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
23278b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
233cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2345e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
235393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
23694a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
237d93a2b8dSBarry Smith     goto theend;
2385e76c431SBarry Smith   }
2395e76c431SBarry Smith 
2405e76c431SBarry Smith   /* Fit points with quadratic */
2415e76c431SBarry Smith   lambda = 1.0; count = 0;
242a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2435e76c431SBarry Smith   lambdaprev = lambda;
2445e76c431SBarry Smith   gnormprev = *gnorm;
245ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
246ddd12767SBarry Smith   else lambda = lambdatemp;
247393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
2485334005bSBarry Smith   lambda = -lambda;
2495e42470aSBarry Smith #if defined(PETSC_COMPLEX)
250393d2d9aSLois Curfman McInnes   clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2515e42470aSBarry Smith #else
252393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2535e42470aSBarry Smith #endif
25478b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
255cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2565e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
257393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
25894a424c1SBarry Smith     PLogInfo(snes,
2594b828684SBarry Smith              "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda);
260d93a2b8dSBarry Smith     goto theend;
2615e76c431SBarry Smith   }
2625e76c431SBarry Smith 
2635e76c431SBarry Smith   /* Fit points with cubic */
2645e76c431SBarry Smith   count = 1;
2655e76c431SBarry Smith   while (1) {
2665e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
26794a424c1SBarry Smith       PLogInfo(snes,
2684b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
26994a424c1SBarry Smith       PLogInfo(snes,
270052efed2SBarry Smith          "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g initial slope %g\n",fnorm,*gnorm,*ynorm,lambda,initslope);
271393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
272761aaf1bSLois Curfman McInnes       *flag = -1; break;
2735e76c431SBarry Smith     }
2745e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2755e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
276ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2775e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2785e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2795e76c431SBarry Smith     d = b*b - 3*a*initslope;
2805e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2815e76c431SBarry Smith     if (a == 0.0) {
2825e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2835e76c431SBarry Smith     } else {
2845e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
2855e76c431SBarry Smith     }
2865e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
2875e76c431SBarry Smith       lambdatemp = .5*lambda;
2885e76c431SBarry Smith     }
2895e76c431SBarry Smith     lambdaprev = lambda;
2905e76c431SBarry Smith     gnormprev = *gnorm;
2915e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
2925e76c431SBarry Smith       lambda = .1*lambda;
2935e76c431SBarry Smith     }
2945e76c431SBarry Smith     else lambda = lambdatemp;
295393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
2965334005bSBarry Smith     lambda = -lambda;
2975e42470aSBarry Smith #if defined(PETSC_COMPLEX)
2985334005bSBarry Smith     clambda = lambda;
299393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3005e42470aSBarry Smith #else
301393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
3025e42470aSBarry Smith #endif
30378b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
304cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3055e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
306393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
30794a424c1SBarry Smith       PLogInfo(snes,
3084b828684SBarry Smith                 "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda);
309761aaf1bSLois Curfman McInnes       *flag = -1; break;
3105e76c431SBarry Smith     }
3115e76c431SBarry Smith     count++;
3125e76c431SBarry Smith   }
313d93a2b8dSBarry Smith   theend:
3147857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3155e42470aSBarry Smith   return 0;
3165e76c431SBarry Smith }
31752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3184b828684SBarry Smith /*@C
3195e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3205e76c431SBarry Smith 
3215e42470aSBarry Smith    Input Parameters:
322f59ffdedSLois Curfman McInnes .  snes - the SNES context
3235e42470aSBarry Smith .  x - current iterate
3245e42470aSBarry Smith .  f - residual evaluated at x
3255e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3265e42470aSBarry Smith .  w - work vector
3275e42470aSBarry Smith .  fnorm - 2-norm of f
3285e42470aSBarry Smith 
329c4a48953SLois Curfman McInnes    Output Parameters:
3305e42470aSBarry Smith .  g - residual evaluated at new iterate y
3315e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3325e42470aSBarry Smith .  gnorm - 2-norm of g
3335e42470aSBarry Smith .  ynorm - 2-norm of search length
334761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3355e42470aSBarry Smith 
336c4a48953SLois Curfman McInnes    Options Database Key:
337c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
338c4a48953SLois Curfman McInnes 
3395e42470aSBarry Smith    Notes:
34077c4ece6SBarry Smith    Use SNESSetLineSearch()
341f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3425e42470aSBarry Smith 
343f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
344f59ffdedSLois Curfman McInnes 
34577c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3465e42470aSBarry Smith @*/
3475e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
348761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3495e76c431SBarry Smith {
350ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3516b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3525e42470aSBarry Smith   Scalar  cinitslope,clambda;
3536b5873e3SBarry Smith #endif
3545e42470aSBarry Smith   int     ierr,count;
3555e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3565334005bSBarry Smith   Scalar  mone = -1.0,scale;
3575e76c431SBarry Smith 
3587857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
359761aaf1bSLois Curfman McInnes   *flag = 0;
3605e42470aSBarry Smith   alpha   = neP->alpha;
3615e42470aSBarry Smith   maxstep = neP->maxstep;
3625e42470aSBarry Smith   steptol = neP->steptol;
3635e76c431SBarry Smith 
364cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
3655e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3665e42470aSBarry Smith     scale = maxstep/(*ynorm);
367393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3685e42470aSBarry Smith     *ynorm = maxstep;
3695e76c431SBarry Smith   }
3705e42470aSBarry Smith   minlambda = steptol/(*ynorm);
371a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
3725e42470aSBarry Smith #if defined(PETSC_COMPLEX)
373a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
3745e42470aSBarry Smith   initslope = real(cinitslope);
3755e42470aSBarry Smith #else
376a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
3775e42470aSBarry Smith #endif
3785e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3795e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3805e42470aSBarry Smith 
381393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
3825334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
38378b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
384cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3855e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
386393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
38794a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
388d93a2b8dSBarry Smith     goto theend;
3895e42470aSBarry Smith   }
3905e42470aSBarry Smith 
3915e42470aSBarry Smith   /* Fit points with quadratic */
3925e42470aSBarry Smith   lambda = 1.0; count = 0;
3935e42470aSBarry Smith   count = 1;
3945e42470aSBarry Smith   while (1) {
3955e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
39694a424c1SBarry Smith       PLogInfo(snes,
3974b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
39894a424c1SBarry Smith       PLogInfo(snes,
399ddd12767SBarry Smith       "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda);
400393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
401761aaf1bSLois Curfman McInnes       *flag = -1; break;
4025e42470aSBarry Smith     }
403a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4045e42470aSBarry Smith     lambdaprev = lambda;
4055e42470aSBarry Smith     gnormprev = *gnorm;
4065e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4075e42470aSBarry Smith       lambda = .1*lambda;
4085e42470aSBarry Smith     } else lambda = lambdatemp;
409393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4105334005bSBarry Smith     lambda = -lambda;
4115e42470aSBarry Smith #if defined(PETSC_COMPLEX)
412393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4135e42470aSBarry Smith #else
414393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4155e42470aSBarry Smith #endif
41678b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
417cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4185e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
419393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
42094a424c1SBarry Smith       PLogInfo(snes,
421ddd12767SBarry Smith         "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n",lambda);
42206259719SBarry Smith       break;
4235e42470aSBarry Smith     }
4245e42470aSBarry Smith     count++;
4255e42470aSBarry Smith   }
426d93a2b8dSBarry Smith   theend:
4277857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4285e42470aSBarry Smith   return 0;
4295e76c431SBarry Smith }
4305e76c431SBarry Smith /* ------------------------------------------------------------ */
431c9e6a524SLois Curfman McInnes /*@C
43277c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
433f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4345e76c431SBarry Smith 
4355e76c431SBarry Smith    Input Parameters:
436eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4375e76c431SBarry Smith .  func - pointer to int function
4385e76c431SBarry Smith 
439c4a48953SLois Curfman McInnes    Available Routines:
440f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
441f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
442f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4435e76c431SBarry Smith 
444c4a48953SLois Curfman McInnes     Options Database Keys:
445c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
446c4a48953SLois Curfman McInnes 
4475e76c431SBarry Smith    Calling sequence of func:
448f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
449761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
450761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4515e76c431SBarry Smith 
4525e76c431SBarry Smith     Input parameters for func:
4535e42470aSBarry Smith .   snes - nonlinear context
4545e76c431SBarry Smith .   x - current iterate
4555e76c431SBarry Smith .   f - residual evaluated at x
4565e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4575e76c431SBarry Smith .   w - work vector
4585e76c431SBarry Smith .   fnorm - 2-norm of f
4595e76c431SBarry Smith 
4605e76c431SBarry Smith     Output parameters for func:
4615e76c431SBarry Smith .   g - residual evaluated at new iterate y
4625e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4635e76c431SBarry Smith .   gnorm - 2-norm of g
4645e76c431SBarry Smith .   ynorm - 2-norm of search length
465761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
466761aaf1bSLois Curfman McInnes            on failure.
467f59ffdedSLois Curfman McInnes 
468f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
469f59ffdedSLois Curfman McInnes 
470f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4715e76c431SBarry Smith @*/
47277c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
473761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
4745e76c431SBarry Smith {
475f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
4765e42470aSBarry Smith   return 0;
4775e76c431SBarry Smith }
47852392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
479f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
4805e42470aSBarry Smith {
4815e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
4826daaf66cSBarry Smith 
483f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
48477c4ece6SBarry Smith   PetscPrintf(snes->comm,"   %ssnes_line_search [basic,quadratic,cubic]\n",p);
4859aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_alpha <alpha> (default %g)\n",p,ls->alpha);
4869aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_maxstep <max> (default %g)\n",p,ls->maxstep);
4879aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_steptol <tol> (default %g)\n",p,ls->steptol);
4886b5873e3SBarry Smith   return 0;
4895e42470aSBarry Smith }
49052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
491f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
492a935fc98SLois Curfman McInnes {
493a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
494a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
495d636dbe3SBarry Smith   FILE       *fd;
49619bcc07fSBarry Smith   char       *cstr;
49751695f54SLois Curfman McInnes   int        ierr;
49819bcc07fSBarry Smith   ViewerType vtype;
499a935fc98SLois Curfman McInnes 
50019bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
50119bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
50290ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
50319bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
50419bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
50519bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
50619bcc07fSBarry Smith     else cstr = "unknown";
50777c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
50877c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
509a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
51019bcc07fSBarry Smith   }
511a935fc98SLois Curfman McInnes   return 0;
512a935fc98SLois Curfman McInnes }
51352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
514f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5155e42470aSBarry Smith {
5165e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5175e42470aSBarry Smith   char    ver[16];
5185e42470aSBarry Smith   double  tmp;
51925cdf11fSBarry Smith   int     ierr,flg;
5205e42470aSBarry Smith 
521ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp, &flg);CHKERRQ(ierr);
52225cdf11fSBarry Smith   if (flg) {
5235e42470aSBarry Smith     ls->alpha = tmp;
5245e42470aSBarry Smith   }
525ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp, &flg);CHKERRQ(ierr);
52625cdf11fSBarry Smith   if (flg) {
5275e42470aSBarry Smith     ls->maxstep = tmp;
5285e42470aSBarry Smith   }
529ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp, &flg);CHKERRQ(ierr);
53025cdf11fSBarry Smith   if (flg) {
5315e42470aSBarry Smith     ls->steptol = tmp;
5325e42470aSBarry Smith   }
533ee8b94d1SSatish Balay   ierr = OptionsGetString(snes->prefix,"-snes_line_search",ver,16, &flg); CHKERRQ(ierr);
53425cdf11fSBarry Smith   if (flg) {
53548d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
53677c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5375e42470aSBarry Smith     }
53848d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
53977c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5405e42470aSBarry Smith     }
54148d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
54277c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5435e42470aSBarry Smith     }
544f63b844aSLois Curfman McInnes     else {SETERRQ(1,"SNESSetFromOptions_EQ_LS:Unknown line search");}
5455e42470aSBarry Smith   }
5465e42470aSBarry Smith   return 0;
5475e42470aSBarry Smith }
5485e42470aSBarry Smith /* ------------------------------------------------------------ */
549f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
5505e42470aSBarry Smith {
5515e42470aSBarry Smith   SNES_LS *neP;
5525e42470aSBarry Smith 
553ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
554f63b844aSLois Curfman McInnes     SETERRQ(1,"SNESCreate_EQ_LS:For SNES_NONLINEAR_EQUATIONS only");
555f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
556f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
557f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
558f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
559f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
560f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
561f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
562f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
5635baf8537SBarry Smith   snes->nwork           = 0;
5645e42470aSBarry Smith 
5650452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
566ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5675e42470aSBarry Smith   snes->data    	= (void *) neP;
5685e42470aSBarry Smith   neP->alpha		= 1.e-4;
5695e42470aSBarry Smith   neP->maxstep		= 1.e8;
5705e42470aSBarry Smith   neP->steptol		= 1.e-12;
5715e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5725e42470aSBarry Smith   return 0;
5735e42470aSBarry Smith }
5745e42470aSBarry Smith 
5755e42470aSBarry Smith 
5765e42470aSBarry Smith 
5775e42470aSBarry Smith 
578