xref: /petsc/src/snes/impls/ls/ls.c (revision ea4d3ed3ef29c6048dff471500c966e5b191a8b9)
15e76c431SBarry Smith #ifndef lint
2*ea4d3ed3SLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.72 1996/09/17 20:04:51 curfman Exp $";
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 || */
4525ed9cd1SBarry 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 
58*ea4d3ed3SLois Curfman McInnes     /* 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);
62*ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNES: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
63*ea4d3ed3SLois Curfman McInnes 
64*ea4d3ed3SLois Curfman McInnes     /* Compute a (scaled) negative update in the line search routine:
65*ea4d3ed3SLois Curfman McInnes          Y <- X - lambda*Y
66*ea4d3ed3SLois Curfman McInnes        and evaluate G(Y) = function(Y))
67*ea4d3ed3SLois Curfman McInnes     */
6881b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
69ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr);
70*ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNES: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
71761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
725e76c431SBarry Smith 
7339e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
7439e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
755e76c431SBarry Smith     fnorm = gnorm;
765e76c431SBarry Smith 
775e42470aSBarry Smith     snes->norm = fnorm;
785e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
79cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
8094a424c1SBarry Smith     SNESMonitor(snes,i+1,fnorm);
815e76c431SBarry Smith 
825e76c431SBarry Smith     /* Test for convergence */
83bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
8439e2f89bSBarry Smith       if (X != snes->vec_sol) {
85393d2d9aSLois Curfman McInnes         ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
8639e2f89bSBarry Smith         snes->vec_sol_always = snes->vec_sol;
8739e2f89bSBarry Smith         snes->vec_func_always = snes->vec_func;
8839e2f89bSBarry Smith       }
895e76c431SBarry Smith       break;
905e76c431SBarry Smith     }
915e76c431SBarry Smith   }
9252392280SLois Curfman McInnes   if (i == maxits) {
9394a424c1SBarry Smith     PLogInfo(snes,
94f63b844aSLois Curfman McInnes       "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
9552392280SLois Curfman McInnes     i--;
9652392280SLois Curfman McInnes   }
975e42470aSBarry Smith   *outits = i+1;
985e42470aSBarry Smith   return 0;
995e76c431SBarry Smith }
1005e76c431SBarry Smith /* ------------------------------------------------------------ */
101f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes )
1025e76c431SBarry Smith {
1035e42470aSBarry Smith   int ierr;
10481b6cf68SLois Curfman McInnes   snes->nwork = 4;
105d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
1065e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
10781b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1085e42470aSBarry Smith   return 0;
1095e76c431SBarry Smith }
1105e76c431SBarry Smith /* ------------------------------------------------------------ */
111f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj)
1125e76c431SBarry Smith {
1135e42470aSBarry Smith   SNES snes = (SNES) obj;
114393d2d9aSLois Curfman McInnes   int  ierr;
1155baf8537SBarry Smith   if (snes->nwork) {
1164b0e389bSBarry Smith     ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
11721c89e3eSBarry Smith   }
1180452661fSBarry Smith   PetscFree(snes->data);
1195e42470aSBarry Smith   return 0;
1205e76c431SBarry Smith }
1215e76c431SBarry Smith /* ------------------------------------------------------------ */
1225e76c431SBarry Smith /*ARGSUSED*/
1234b828684SBarry Smith /*@C
1245e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1255e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1265e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1275e76c431SBarry Smith 
1285e76c431SBarry Smith    Input Parameters:
1295e42470aSBarry Smith .  snes - nonlinear context
1305e76c431SBarry Smith .  x - current iterate
1315e76c431SBarry Smith .  f - residual evaluated at x
1325e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1335e76c431SBarry Smith .  w - work vector
1345e76c431SBarry Smith .  fnorm - 2-norm of f
1355e76c431SBarry Smith 
136c4a48953SLois Curfman McInnes    Output Parameters:
1375e76c431SBarry Smith .  g - residual evaluated at new iterate y
1385e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1395e76c431SBarry Smith .  gnorm - 2-norm of g
1405e76c431SBarry Smith .  ynorm - 2-norm of search length
141761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1425e76c431SBarry Smith 
143c4a48953SLois Curfman McInnes    Options Database Key:
144c4a48953SLois Curfman McInnes $  -snes_line_search basic
145c4a48953SLois Curfman McInnes 
14628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
14728ae5a21SLois Curfman McInnes 
148f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
14977c4ece6SBarry Smith           SNESSetLineSearch()
1505e76c431SBarry Smith @*/
1515e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
152761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1535e76c431SBarry Smith {
1545e42470aSBarry Smith   int    ierr;
1555334005bSBarry Smith   Scalar mone = -1.0;
1565334005bSBarry Smith 
157761aaf1bSLois Curfman McInnes   *flag = 0;
1587857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
159cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);       /* ynorm = || y || */
160*ea4d3ed3SLois Curfman McInnes   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);            /* y <- y - x      */
161*ea4d3ed3SLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y)    */
162cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);       /* gnorm = || g || */
1637857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
164761aaf1bSLois Curfman McInnes   return 0;
1655e76c431SBarry Smith }
1665e76c431SBarry Smith /* ------------------------------------------------------------------ */
1674b828684SBarry Smith /*@C
168f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
169f59ffdedSLois Curfman McInnes    is the default line search method.
1705e76c431SBarry Smith 
1715e76c431SBarry Smith    Input Parameters:
1725e42470aSBarry Smith .  snes - nonlinear context
1735e76c431SBarry Smith .  x - current iterate
1745e76c431SBarry Smith .  f - residual evaluated at x
1755e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1765e76c431SBarry Smith .  w - work vector
1775e76c431SBarry Smith .  fnorm - 2-norm of f
1785e76c431SBarry Smith 
179393d2d9aSLois Curfman McInnes    Output Parameters:
1805e76c431SBarry Smith .  g - residual evaluated at new iterate y
1815e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1825e76c431SBarry Smith .  gnorm - 2-norm of g
1835e76c431SBarry Smith .  ynorm - 2-norm of search length
184761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1855e76c431SBarry Smith 
186c4a48953SLois Curfman McInnes    Options Database Key:
187c4a48953SLois Curfman McInnes $  -snes_line_search cubic
188c4a48953SLois Curfman McInnes 
1895e76c431SBarry Smith    Notes:
1905e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1915e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1925e76c431SBarry Smith 
19328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
19428ae5a21SLois Curfman McInnes 
19577c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
1965e76c431SBarry Smith @*/
1975e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w,
198761aaf1bSLois Curfman McInnes                         double fnorm,double *ynorm,double *gnorm,int *flag)
1995e76c431SBarry Smith {
200ddd12767SBarry Smith   double  steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2;
201*ea4d3ed3SLois Curfman McInnes   double  maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg;
2026b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2035e42470aSBarry Smith   Scalar  cinitslope, clambda;
2046b5873e3SBarry Smith #endif
2055e42470aSBarry Smith   int     ierr, count;
2065e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2075334005bSBarry Smith   Scalar  mone = -1.0,scale;
2085e76c431SBarry Smith 
2097857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
210761aaf1bSLois Curfman McInnes   *flag   = 0;
2115e76c431SBarry Smith   alpha   = neP->alpha;
2125e76c431SBarry Smith   maxstep = neP->maxstep;
2135e76c431SBarry Smith   steptol = neP->steptol;
2145e76c431SBarry Smith 
215cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
2165e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2175e42470aSBarry Smith     scale = maxstep/(*ynorm);
2186b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
21994a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2206b5873e3SBarry Smith #else
22194a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2226b5873e3SBarry Smith #endif
223393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2245e76c431SBarry Smith     *ynorm = maxstep;
2255e76c431SBarry Smith   }
2265e76c431SBarry Smith   minlambda = steptol/(*ynorm);
227a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2285e42470aSBarry Smith #if defined(PETSC_COMPLEX)
229a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2305e42470aSBarry Smith   initslope = real(cinitslope);
2315e42470aSBarry Smith #else
232a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2335e42470aSBarry Smith #endif
2345e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2355e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2365e76c431SBarry Smith 
237393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2385334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
23978b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
240cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2415e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
242393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
24394a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
244d93a2b8dSBarry Smith     goto theend;
2455e76c431SBarry Smith   }
2465e76c431SBarry Smith 
2475e76c431SBarry Smith   /* Fit points with quadratic */
2485e76c431SBarry Smith   lambda = 1.0; count = 0;
249a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2505e76c431SBarry Smith   lambdaprev = lambda;
2515e76c431SBarry Smith   gnormprev = *gnorm;
252ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
253ddd12767SBarry Smith   else lambda = lambdatemp;
254393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
255*ea4d3ed3SLois Curfman McInnes   lambdaneg = -lambda;
2565e42470aSBarry Smith #if defined(PETSC_COMPLEX)
257*ea4d3ed3SLois Curfman McInnes   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2585e42470aSBarry Smith #else
259*ea4d3ed3SLois Curfman McInnes   ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
2605e42470aSBarry Smith #endif
26178b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
262cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2635e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
264393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
265*ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda);
266d93a2b8dSBarry Smith     goto theend;
2675e76c431SBarry Smith   }
2685e76c431SBarry Smith 
2695e76c431SBarry Smith   /* Fit points with cubic */
2705e76c431SBarry Smith   count = 1;
2715e76c431SBarry Smith   while (1) {
2725e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
27394a424c1SBarry Smith       PLogInfo(snes,
2744b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
27594a424c1SBarry Smith       PLogInfo(snes,
276*ea4d3ed3SLois Curfman McInnes          "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
277*ea4d3ed3SLois Curfman McInnes              fnorm,*gnorm,*ynorm,lambda,initslope);
278393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
279761aaf1bSLois Curfman McInnes       *flag = -1; break;
2805e76c431SBarry Smith     }
2815e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2825e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
283ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2845e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2855e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2865e76c431SBarry Smith     d = b*b - 3*a*initslope;
2875e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2885e76c431SBarry Smith     if (a == 0.0) {
2895e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2905e76c431SBarry Smith     } else {
2915e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
2925e76c431SBarry Smith     }
2935e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
2945e76c431SBarry Smith       lambdatemp = .5*lambda;
2955e76c431SBarry Smith     }
2965e76c431SBarry Smith     lambdaprev = lambda;
2975e76c431SBarry Smith     gnormprev = *gnorm;
2985e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
2995e76c431SBarry Smith       lambda = .1*lambda;
3005e76c431SBarry Smith     }
3015e76c431SBarry Smith     else lambda = lambdatemp;
302393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
303*ea4d3ed3SLois Curfman McInnes     lambdaneg = -lambda;
3045e42470aSBarry Smith #if defined(PETSC_COMPLEX)
305*ea4d3ed3SLois Curfman McInnes     clambda = lambdaneg;
306393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3075e42470aSBarry Smith #else
308*ea4d3ed3SLois Curfman McInnes     ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
3095e42470aSBarry Smith #endif
31078b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
311cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3125e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
313393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
314*ea4d3ed3SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
315761aaf1bSLois Curfman McInnes       *flag = -1; break;
3165e76c431SBarry Smith     }
3175e76c431SBarry Smith     count++;
3185e76c431SBarry Smith   }
319d93a2b8dSBarry Smith   theend:
3207857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3215e42470aSBarry Smith   return 0;
3225e76c431SBarry Smith }
32352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3244b828684SBarry Smith /*@C
3255e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3265e76c431SBarry Smith 
3275e42470aSBarry Smith    Input Parameters:
328f59ffdedSLois Curfman McInnes .  snes - the SNES context
3295e42470aSBarry Smith .  x - current iterate
3305e42470aSBarry Smith .  f - residual evaluated at x
3315e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3325e42470aSBarry Smith .  w - work vector
3335e42470aSBarry Smith .  fnorm - 2-norm of f
3345e42470aSBarry Smith 
335c4a48953SLois Curfman McInnes    Output Parameters:
3365e42470aSBarry Smith .  g - residual evaluated at new iterate y
3375e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3385e42470aSBarry Smith .  gnorm - 2-norm of g
3395e42470aSBarry Smith .  ynorm - 2-norm of search length
340761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3415e42470aSBarry Smith 
342c4a48953SLois Curfman McInnes    Options Database Key:
343c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
344c4a48953SLois Curfman McInnes 
3455e42470aSBarry Smith    Notes:
34677c4ece6SBarry Smith    Use SNESSetLineSearch()
347f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3485e42470aSBarry Smith 
349f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
350f59ffdedSLois Curfman McInnes 
35177c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3525e42470aSBarry Smith @*/
3535e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
354761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3555e76c431SBarry Smith {
356ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3576b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3585e42470aSBarry Smith   Scalar  cinitslope,clambda;
3596b5873e3SBarry Smith #endif
3605e42470aSBarry Smith   int     ierr,count;
3615e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3625334005bSBarry Smith   Scalar  mone = -1.0,scale;
3635e76c431SBarry Smith 
3647857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
365761aaf1bSLois Curfman McInnes   *flag = 0;
3665e42470aSBarry Smith   alpha   = neP->alpha;
3675e42470aSBarry Smith   maxstep = neP->maxstep;
3685e42470aSBarry Smith   steptol = neP->steptol;
3695e76c431SBarry Smith 
370cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
3715e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3725e42470aSBarry Smith     scale = maxstep/(*ynorm);
373393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3745e42470aSBarry Smith     *ynorm = maxstep;
3755e76c431SBarry Smith   }
3765e42470aSBarry Smith   minlambda = steptol/(*ynorm);
377a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
3785e42470aSBarry Smith #if defined(PETSC_COMPLEX)
379a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
3805e42470aSBarry Smith   initslope = real(cinitslope);
3815e42470aSBarry Smith #else
382a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
3835e42470aSBarry Smith #endif
3845e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3855e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3865e42470aSBarry Smith 
387393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
3885334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
38978b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
390cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3915e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
392393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
39394a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
394d93a2b8dSBarry Smith     goto theend;
3955e42470aSBarry Smith   }
3965e42470aSBarry Smith 
3975e42470aSBarry Smith   /* Fit points with quadratic */
3985e42470aSBarry Smith   lambda = 1.0; count = 0;
3995e42470aSBarry Smith   count = 1;
4005e42470aSBarry Smith   while (1) {
4015e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
40294a424c1SBarry Smith       PLogInfo(snes,
4034b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
40494a424c1SBarry Smith       PLogInfo(snes,
405*ea4d3ed3SLois Curfman McInnes       "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
406*ea4d3ed3SLois Curfman McInnes           fnorm,*gnorm,*ynorm,lambda,initslope);
407393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
408761aaf1bSLois Curfman McInnes       *flag = -1; break;
4095e42470aSBarry Smith     }
410a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4115e42470aSBarry Smith     lambdaprev = lambda;
4125e42470aSBarry Smith     gnormprev = *gnorm;
4135e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4145e42470aSBarry Smith       lambda = .1*lambda;
4155e42470aSBarry Smith     } else lambda = lambdatemp;
416393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4175334005bSBarry Smith     lambda = -lambda;
4185e42470aSBarry Smith #if defined(PETSC_COMPLEX)
419393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4205e42470aSBarry Smith #else
421393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4225e42470aSBarry Smith #endif
42378b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
424cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4255e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
426393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
42794a424c1SBarry Smith       PLogInfo(snes,
428*ea4d3ed3SLois Curfman McInnes         "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
42906259719SBarry Smith       break;
4305e42470aSBarry Smith     }
4315e42470aSBarry Smith     count++;
4325e42470aSBarry Smith   }
433d93a2b8dSBarry Smith   theend:
4347857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4355e42470aSBarry Smith   return 0;
4365e76c431SBarry Smith }
4375e76c431SBarry Smith /* ------------------------------------------------------------ */
438c9e6a524SLois Curfman McInnes /*@C
43977c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
440f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4415e76c431SBarry Smith 
4425e76c431SBarry Smith    Input Parameters:
443eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4445e76c431SBarry Smith .  func - pointer to int function
4455e76c431SBarry Smith 
446c4a48953SLois Curfman McInnes    Available Routines:
447f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
448f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
449f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4505e76c431SBarry Smith 
451c4a48953SLois Curfman McInnes     Options Database Keys:
452c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
453c4a48953SLois Curfman McInnes 
4545e76c431SBarry Smith    Calling sequence of func:
455f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
456761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
457761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4585e76c431SBarry Smith 
4595e76c431SBarry Smith     Input parameters for func:
4605e42470aSBarry Smith .   snes - nonlinear context
4615e76c431SBarry Smith .   x - current iterate
4625e76c431SBarry Smith .   f - residual evaluated at x
4635e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4645e76c431SBarry Smith .   w - work vector
4655e76c431SBarry Smith .   fnorm - 2-norm of f
4665e76c431SBarry Smith 
4675e76c431SBarry Smith     Output parameters for func:
4685e76c431SBarry Smith .   g - residual evaluated at new iterate y
4695e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4705e76c431SBarry Smith .   gnorm - 2-norm of g
4715e76c431SBarry Smith .   ynorm - 2-norm of search length
472761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
473761aaf1bSLois Curfman McInnes            on failure.
474f59ffdedSLois Curfman McInnes 
475f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
476f59ffdedSLois Curfman McInnes 
477f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4785e76c431SBarry Smith @*/
47977c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
480761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
4815e76c431SBarry Smith {
482f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
4835e42470aSBarry Smith   return 0;
4845e76c431SBarry Smith }
48552392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
486f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
4875e42470aSBarry Smith {
4885e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
4896daaf66cSBarry Smith 
490f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
49177c4ece6SBarry Smith   PetscPrintf(snes->comm,"   %ssnes_line_search [basic,quadratic,cubic]\n",p);
4929aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_alpha <alpha> (default %g)\n",p,ls->alpha);
4939aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_maxstep <max> (default %g)\n",p,ls->maxstep);
4949aca352dSLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_line_search_steptol <tol> (default %g)\n",p,ls->steptol);
4956b5873e3SBarry Smith   return 0;
4965e42470aSBarry Smith }
49752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
498f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
499a935fc98SLois Curfman McInnes {
500a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
501a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
502d636dbe3SBarry Smith   FILE       *fd;
50319bcc07fSBarry Smith   char       *cstr;
50451695f54SLois Curfman McInnes   int        ierr;
50519bcc07fSBarry Smith   ViewerType vtype;
506a935fc98SLois Curfman McInnes 
50719bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
50819bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
50990ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
51019bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
51119bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
51219bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
51319bcc07fSBarry Smith     else cstr = "unknown";
51477c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
51577c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
516a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
51719bcc07fSBarry Smith   }
518a935fc98SLois Curfman McInnes   return 0;
519a935fc98SLois Curfman McInnes }
52052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
521f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5225e42470aSBarry Smith {
5235e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5245e42470aSBarry Smith   char    ver[16];
5255e42470aSBarry Smith   double  tmp;
52625cdf11fSBarry Smith   int     ierr,flg;
5275e42470aSBarry Smith 
528fb262c43SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_alpha",&tmp, &flg);CHKERRQ(ierr);
52925cdf11fSBarry Smith   if (flg) {
5305e42470aSBarry Smith     ls->alpha = tmp;
5315e42470aSBarry Smith   }
532ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp, &flg);CHKERRQ(ierr);
53325cdf11fSBarry Smith   if (flg) {
5345e42470aSBarry Smith     ls->maxstep = tmp;
5355e42470aSBarry Smith   }
536ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp, &flg);CHKERRQ(ierr);
53725cdf11fSBarry Smith   if (flg) {
5385e42470aSBarry Smith     ls->steptol = tmp;
5395e42470aSBarry Smith   }
540ee8b94d1SSatish Balay   ierr = OptionsGetString(snes->prefix,"-snes_line_search",ver,16, &flg); CHKERRQ(ierr);
54125cdf11fSBarry Smith   if (flg) {
54248d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
54377c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5445e42470aSBarry Smith     }
54548d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
54677c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5475e42470aSBarry Smith     }
54848d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
54977c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5505e42470aSBarry Smith     }
551f63b844aSLois Curfman McInnes     else {SETERRQ(1,"SNESSetFromOptions_EQ_LS:Unknown line search");}
5525e42470aSBarry Smith   }
5535e42470aSBarry Smith   return 0;
5545e42470aSBarry Smith }
5555e42470aSBarry Smith /* ------------------------------------------------------------ */
556f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
5575e42470aSBarry Smith {
5585e42470aSBarry Smith   SNES_LS *neP;
5595e42470aSBarry Smith 
560ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
561f63b844aSLois Curfman McInnes     SETERRQ(1,"SNESCreate_EQ_LS:For SNES_NONLINEAR_EQUATIONS only");
562f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
563f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
564f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
565f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
566f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
567f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
568f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
569f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
5705baf8537SBarry Smith   snes->nwork           = 0;
5715e42470aSBarry Smith 
5720452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
573ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5745e42470aSBarry Smith   snes->data    	= (void *) neP;
5755e42470aSBarry Smith   neP->alpha		= 1.e-4;
5765e42470aSBarry Smith   neP->maxstep		= 1.e8;
5775e42470aSBarry Smith   neP->steptol		= 1.e-12;
5785e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5795e42470aSBarry Smith   return 0;
5805e42470aSBarry Smith }
5815e42470aSBarry Smith 
5825e42470aSBarry Smith 
5835e42470aSBarry Smith 
5845e42470aSBarry Smith 
585