xref: /petsc/src/snes/impls/ls/ls.c (revision 16c95cac94409547d4f262edea7ff32ae7f72d5b)
15e76c431SBarry Smith #ifndef lint
2*16c95cacSBarry Smith static char vcid[] = "$Id: ls.c,v 1.81 1997/01/14 22:58:01 curfman 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 
275615d1e5SSatish Balay #undef __FUNC__
285615d1e5SSatish Balay #define __FUNC__ "SNESSolve_EQ_LS"
29f63b844aSLois Curfman McInnes int SNESSolve_EQ_LS(SNES snes,int *outits)
305e76c431SBarry Smith {
315e42470aSBarry Smith   SNES_LS       *neP = (SNES_LS *) snes->data;
32761aaf1bSLois Curfman McInnes   int           maxits, i, history_len, ierr, lits, lsfail;
33112a2221SBarry Smith   MatStructure  flg = DIFFERENT_NONZERO_PATTERN;
346b5873e3SBarry Smith   double        fnorm, gnorm, xnorm, ynorm, *history;
355e42470aSBarry Smith   Vec           Y, X, F, G, W, TMP;
365e76c431SBarry Smith 
375e42470aSBarry Smith   history	= snes->conv_hist;	/* convergence history */
385e42470aSBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
395e42470aSBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
405e42470aSBarry Smith   X		= snes->vec_sol;	/* solution vector */
4139e2f89bSBarry Smith   F		= snes->vec_func;	/* residual vector */
425e42470aSBarry Smith   Y		= snes->work[0];	/* work vectors */
435e42470aSBarry Smith   G		= snes->work[1];
445e42470aSBarry Smith   W		= snes->work[2];
455e76c431SBarry Smith 
46cddf8d76SBarry Smith   ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);       /* xnorm = || X || */
4725ed9cd1SBarry Smith   snes->iter = 0;
485334005bSBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);  /*  F(X)      */
49cddf8d76SBarry Smith   ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr);	/* fnorm <- ||F||  */
505e42470aSBarry Smith   snes->norm = fnorm;
515e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
5294a424c1SBarry Smith   SNESMonitor(snes,0,fnorm);
535e76c431SBarry Smith 
54d034289bSBarry Smith   /* set parameter for default relative tolerance convergence test */
55d034289bSBarry Smith   snes->ttol = fnorm*snes->rtol;
56d034289bSBarry Smith 
575e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
585e42470aSBarry Smith     snes->iter = i+1;
595e76c431SBarry Smith 
60ea4d3ed3SLois Curfman McInnes     /* Solve J Y = F, where J is Jacobian matrix */
615334005bSBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr);
625334005bSBarry Smith     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
6378b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
647a00f4a9SLois Curfman McInnes     snes->linear_its += PetscAbsInt(lits);
65af1ccdebSLois Curfman McInnes     PLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
66ea4d3ed3SLois Curfman McInnes 
67ea4d3ed3SLois Curfman McInnes     /* Compute a (scaled) negative update in the line search routine:
68ea4d3ed3SLois Curfman McInnes          Y <- X - lambda*Y
69ea4d3ed3SLois Curfman McInnes        and evaluate G(Y) = function(Y))
70ea4d3ed3SLois Curfman McInnes     */
7181b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
72ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr);
73af1ccdebSLois Curfman McInnes     PLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
74761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
755e76c431SBarry Smith 
7639e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
7739e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
785e76c431SBarry Smith     fnorm = gnorm;
795e76c431SBarry Smith 
805e42470aSBarry Smith     snes->norm = fnorm;
815e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
82cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
8394a424c1SBarry Smith     SNESMonitor(snes,i+1,fnorm);
845e76c431SBarry Smith 
855e76c431SBarry Smith     /* Test for convergence */
86bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
87*16c95cacSBarry Smith       break;
88*16c95cacSBarry Smith     }
89*16c95cacSBarry Smith   }
9039e2f89bSBarry Smith   if (X != snes->vec_sol) {
91393d2d9aSLois Curfman McInnes     ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
9239e2f89bSBarry Smith     snes->vec_sol_always  = snes->vec_sol;
9339e2f89bSBarry Smith     snes->vec_func_always = snes->vec_func;
9439e2f89bSBarry Smith   }
9552392280SLois Curfman McInnes   if (i == maxits) {
9694a424c1SBarry Smith     PLogInfo(snes,
97f63b844aSLois Curfman McInnes       "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
9852392280SLois Curfman McInnes     i--;
9952392280SLois Curfman McInnes   }
1005e42470aSBarry Smith   *outits = i+1;
1015e42470aSBarry Smith   return 0;
1025e76c431SBarry Smith }
1035e76c431SBarry Smith /* ------------------------------------------------------------ */
1045615d1e5SSatish Balay #undef __FUNC__
1055615d1e5SSatish Balay #define __FUNC__ "SNESSetUp_EQ_LS"
106f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes )
1075e76c431SBarry Smith {
1085e42470aSBarry Smith   int ierr;
10981b6cf68SLois Curfman McInnes   snes->nwork = 4;
110d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
1115e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
11281b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1135e42470aSBarry Smith   return 0;
1145e76c431SBarry Smith }
1155e76c431SBarry Smith /* ------------------------------------------------------------ */
1165615d1e5SSatish Balay #undef __FUNC__
1175615d1e5SSatish Balay #define __FUNC__ "SNESDestroy_EQ_LS"
118f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj)
1195e76c431SBarry Smith {
1205e42470aSBarry Smith   SNES snes = (SNES) obj;
121393d2d9aSLois Curfman McInnes   int  ierr;
1225baf8537SBarry Smith   if (snes->nwork) {
1234b0e389bSBarry Smith     ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
12421c89e3eSBarry Smith   }
1250452661fSBarry Smith   PetscFree(snes->data);
1265e42470aSBarry Smith   return 0;
1275e76c431SBarry Smith }
1285e76c431SBarry Smith /* ------------------------------------------------------------ */
1295615d1e5SSatish Balay #undef __FUNC__
1305615d1e5SSatish Balay #define __FUNC__ "SNESNoLineSearch"
1315e76c431SBarry Smith /*ARGSUSED*/
1324b828684SBarry Smith /*@C
1335e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1345e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1355e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1365e76c431SBarry Smith 
1375e76c431SBarry Smith    Input Parameters:
1385e42470aSBarry Smith .  snes - nonlinear context
1395e76c431SBarry Smith .  x - current iterate
1405e76c431SBarry Smith .  f - residual evaluated at x
1415e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1425e76c431SBarry Smith .  w - work vector
1435e76c431SBarry Smith .  fnorm - 2-norm of f
1445e76c431SBarry Smith 
145c4a48953SLois Curfman McInnes    Output Parameters:
1465e76c431SBarry Smith .  g - residual evaluated at new iterate y
1475e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1485e76c431SBarry Smith .  gnorm - 2-norm of g
1495e76c431SBarry Smith .  ynorm - 2-norm of search length
150761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1515e76c431SBarry Smith 
152c4a48953SLois Curfman McInnes    Options Database Key:
15309d61ba7SLois Curfman McInnes $  -snes_eq_ls basic
154c4a48953SLois Curfman McInnes 
15528ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
15628ae5a21SLois Curfman McInnes 
157f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
15877c4ece6SBarry Smith           SNESSetLineSearch()
1595e76c431SBarry Smith @*/
1605e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
161761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1625e76c431SBarry Smith {
1635e42470aSBarry Smith   int    ierr;
1645334005bSBarry Smith   Scalar mone = -1.0;
1655334005bSBarry Smith 
166761aaf1bSLois Curfman McInnes   *flag = 0;
1677857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
168cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);       /* ynorm = || y || */
169ea4d3ed3SLois Curfman McInnes   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);            /* y <- y - x      */
170ea4d3ed3SLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y)    */
171cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);       /* gnorm = || g || */
1727857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
173761aaf1bSLois Curfman McInnes   return 0;
1745e76c431SBarry Smith }
1755e76c431SBarry Smith /* ------------------------------------------------------------------ */
1765615d1e5SSatish Balay #undef __FUNC__
1775615d1e5SSatish Balay #define __FUNC__ "SNESCubicLineSearch"
1784b828684SBarry Smith /*@C
179f525115eSLois Curfman McInnes    SNESCubicLineSearch - Performs a cubic line search (default line search method).
1805e76c431SBarry Smith 
1815e76c431SBarry Smith    Input Parameters:
1825e42470aSBarry Smith .  snes - nonlinear context
1835e76c431SBarry Smith .  x - current iterate
1845e76c431SBarry Smith .  f - residual evaluated at x
1855e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1865e76c431SBarry Smith .  w - work vector
1875e76c431SBarry Smith .  fnorm - 2-norm of f
1885e76c431SBarry Smith 
189393d2d9aSLois Curfman McInnes    Output Parameters:
1905e76c431SBarry Smith .  g - residual evaluated at new iterate y
1915e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1925e76c431SBarry Smith .  gnorm - 2-norm of g
1935e76c431SBarry Smith .  ynorm - 2-norm of search length
194761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1955e76c431SBarry Smith 
196c4a48953SLois Curfman McInnes    Options Database Key:
19709d61ba7SLois Curfman McInnes $  -snes_eq_ls cubic
198c4a48953SLois Curfman McInnes 
1995e76c431SBarry Smith    Notes:
2005e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
2015e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
2025e76c431SBarry Smith 
20328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
20428ae5a21SLois Curfman McInnes 
20577c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
2065e76c431SBarry Smith @*/
2075e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w,
208761aaf1bSLois Curfman McInnes                         double fnorm,double *ynorm,double *gnorm,int *flag)
2095e76c431SBarry Smith {
210ddd12767SBarry Smith   double  steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2;
211ea4d3ed3SLois Curfman McInnes   double  maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg;
2126b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2135e42470aSBarry Smith   Scalar  cinitslope, clambda;
2146b5873e3SBarry Smith #endif
2155e42470aSBarry Smith   int     ierr, count;
2165e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2175334005bSBarry Smith   Scalar  mone = -1.0,scale;
2185e76c431SBarry Smith 
2197857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
220761aaf1bSLois Curfman McInnes   *flag   = 0;
2215e76c431SBarry Smith   alpha   = neP->alpha;
2225e76c431SBarry Smith   maxstep = neP->maxstep;
2235e76c431SBarry Smith   steptol = neP->steptol;
2245e76c431SBarry Smith 
225cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
2265e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2275e42470aSBarry Smith     scale = maxstep/(*ynorm);
2286b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
22994a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2306b5873e3SBarry Smith #else
23194a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2326b5873e3SBarry Smith #endif
233393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2345e76c431SBarry Smith     *ynorm = maxstep;
2355e76c431SBarry Smith   }
2365e76c431SBarry Smith   minlambda = steptol/(*ynorm);
237a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2385e42470aSBarry Smith #if defined(PETSC_COMPLEX)
239a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2405e42470aSBarry Smith   initslope = real(cinitslope);
2415e42470aSBarry Smith #else
242a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2435e42470aSBarry Smith #endif
2445e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2455e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2465e76c431SBarry Smith 
247393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2485334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
24978b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
250cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2515e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
252393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
25394a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
254d93a2b8dSBarry Smith     goto theend;
2555e76c431SBarry Smith   }
2565e76c431SBarry Smith 
2575e76c431SBarry Smith   /* Fit points with quadratic */
2585e76c431SBarry Smith   lambda = 1.0; count = 0;
259a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2605e76c431SBarry Smith   lambdaprev = lambda;
2615e76c431SBarry Smith   gnormprev = *gnorm;
262ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
263ddd12767SBarry Smith   else lambda = lambdatemp;
264393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
265ea4d3ed3SLois Curfman McInnes   lambdaneg = -lambda;
2665e42470aSBarry Smith #if defined(PETSC_COMPLEX)
267ea4d3ed3SLois Curfman McInnes   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2685e42470aSBarry Smith #else
269ea4d3ed3SLois Curfman McInnes   ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
2705e42470aSBarry Smith #endif
27178b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
272cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2735e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
274393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
275ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda);
276d93a2b8dSBarry Smith     goto theend;
2775e76c431SBarry Smith   }
2785e76c431SBarry Smith 
2795e76c431SBarry Smith   /* Fit points with cubic */
2805e76c431SBarry Smith   count = 1;
2815e76c431SBarry Smith   while (1) {
2825e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
28394a424c1SBarry Smith       PLogInfo(snes,
2844b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
28594a424c1SBarry Smith       PLogInfo(snes,
286ea4d3ed3SLois Curfman McInnes          "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
287ea4d3ed3SLois Curfman McInnes              fnorm,*gnorm,*ynorm,lambda,initslope);
288393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
289761aaf1bSLois Curfman McInnes       *flag = -1; break;
2905e76c431SBarry Smith     }
2915e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2925e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
293ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2945e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2955e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2965e76c431SBarry Smith     d = b*b - 3*a*initslope;
2975e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2985e76c431SBarry Smith     if (a == 0.0) {
2995e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
3005e76c431SBarry Smith     } else {
3015e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
3025e76c431SBarry Smith     }
3035e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
3045e76c431SBarry Smith       lambdatemp = .5*lambda;
3055e76c431SBarry Smith     }
3065e76c431SBarry Smith     lambdaprev = lambda;
3075e76c431SBarry Smith     gnormprev = *gnorm;
3085e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
3095e76c431SBarry Smith       lambda = .1*lambda;
3105e76c431SBarry Smith     }
3115e76c431SBarry Smith     else lambda = lambdatemp;
312393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
313ea4d3ed3SLois Curfman McInnes     lambdaneg = -lambda;
3145e42470aSBarry Smith #if defined(PETSC_COMPLEX)
315ea4d3ed3SLois Curfman McInnes     clambda = lambdaneg;
316393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3175e42470aSBarry Smith #else
318ea4d3ed3SLois Curfman McInnes     ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
3195e42470aSBarry Smith #endif
32078b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
321cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3225e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
323393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
324ea4d3ed3SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
325761aaf1bSLois Curfman McInnes       *flag = -1; break;
3265e76c431SBarry Smith     }
3275e76c431SBarry Smith     count++;
3285e76c431SBarry Smith   }
329d93a2b8dSBarry Smith   theend:
3307857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3315e42470aSBarry Smith   return 0;
3325e76c431SBarry Smith }
33352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3345615d1e5SSatish Balay #undef __FUNC__
3355615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch"
3364b828684SBarry Smith /*@C
337f525115eSLois Curfman McInnes    SNESQuadraticLineSearch - Performs a quadratic line search.
3385e76c431SBarry Smith 
3395e42470aSBarry Smith    Input Parameters:
340f59ffdedSLois Curfman McInnes .  snes - the SNES context
3415e42470aSBarry Smith .  x - current iterate
3425e42470aSBarry Smith .  f - residual evaluated at x
3435e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3445e42470aSBarry Smith .  w - work vector
3455e42470aSBarry Smith .  fnorm - 2-norm of f
3465e42470aSBarry Smith 
347c4a48953SLois Curfman McInnes    Output Parameters:
3485e42470aSBarry Smith .  g - residual evaluated at new iterate y
3495e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3505e42470aSBarry Smith .  gnorm - 2-norm of g
3515e42470aSBarry Smith .  ynorm - 2-norm of search length
352761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3535e42470aSBarry Smith 
354c4a48953SLois Curfman McInnes    Options Database Key:
35509d61ba7SLois Curfman McInnes $  -snes_eq_ls quadratic
356c4a48953SLois Curfman McInnes 
3575e42470aSBarry Smith    Notes:
35877c4ece6SBarry Smith    Use SNESSetLineSearch()
359f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3605e42470aSBarry Smith 
361f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
362f59ffdedSLois Curfman McInnes 
36377c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3645e42470aSBarry Smith @*/
3655e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
366761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3675e76c431SBarry Smith {
368ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3696b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3705e42470aSBarry Smith   Scalar  cinitslope,clambda;
3716b5873e3SBarry Smith #endif
3725e42470aSBarry Smith   int     ierr,count;
3735e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3745334005bSBarry Smith   Scalar  mone = -1.0,scale;
3755e76c431SBarry Smith 
3767857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
377761aaf1bSLois Curfman McInnes   *flag = 0;
3785e42470aSBarry Smith   alpha   = neP->alpha;
3795e42470aSBarry Smith   maxstep = neP->maxstep;
3805e42470aSBarry Smith   steptol = neP->steptol;
3815e76c431SBarry Smith 
382cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
3835e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3845e42470aSBarry Smith     scale = maxstep/(*ynorm);
385393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3865e42470aSBarry Smith     *ynorm = maxstep;
3875e76c431SBarry Smith   }
3885e42470aSBarry Smith   minlambda = steptol/(*ynorm);
389a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
3905e42470aSBarry Smith #if defined(PETSC_COMPLEX)
391a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
3925e42470aSBarry Smith   initslope = real(cinitslope);
3935e42470aSBarry Smith #else
394a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
3955e42470aSBarry Smith #endif
3965e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3975e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3985e42470aSBarry Smith 
399393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
4005334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
40178b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
402cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4035e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
404393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
40594a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
406d93a2b8dSBarry Smith     goto theend;
4075e42470aSBarry Smith   }
4085e42470aSBarry Smith 
4095e42470aSBarry Smith   /* Fit points with quadratic */
4105e42470aSBarry Smith   lambda = 1.0; count = 0;
4115e42470aSBarry Smith   count = 1;
4125e42470aSBarry Smith   while (1) {
4135e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
41494a424c1SBarry Smith       PLogInfo(snes,
4154b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
41694a424c1SBarry Smith       PLogInfo(snes,
417ea4d3ed3SLois Curfman McInnes       "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
418ea4d3ed3SLois Curfman McInnes           fnorm,*gnorm,*ynorm,lambda,initslope);
419393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
420761aaf1bSLois Curfman McInnes       *flag = -1; break;
4215e42470aSBarry Smith     }
422a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4235e42470aSBarry Smith     lambdaprev = lambda;
4245e42470aSBarry Smith     gnormprev = *gnorm;
4255e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4265e42470aSBarry Smith       lambda = .1*lambda;
4275e42470aSBarry Smith     } else lambda = lambdatemp;
428393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4295334005bSBarry Smith     lambda = -lambda;
4305e42470aSBarry Smith #if defined(PETSC_COMPLEX)
431393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4325e42470aSBarry Smith #else
433393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4345e42470aSBarry Smith #endif
43578b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
436cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4375e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
438393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
43994a424c1SBarry Smith       PLogInfo(snes,
440ea4d3ed3SLois Curfman McInnes         "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
44106259719SBarry Smith       break;
4425e42470aSBarry Smith     }
4435e42470aSBarry Smith     count++;
4445e42470aSBarry Smith   }
445d93a2b8dSBarry Smith   theend:
4467857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4475e42470aSBarry Smith   return 0;
4485e76c431SBarry Smith }
4495e76c431SBarry Smith /* ------------------------------------------------------------ */
4505615d1e5SSatish Balay #undef __FUNC__
4515615d1e5SSatish Balay #define __FUNC__ "SNESSetLineSearch"
452c9e6a524SLois Curfman McInnes /*@C
45377c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
454f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4555e76c431SBarry Smith 
4565e76c431SBarry Smith    Input Parameters:
457eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4585e76c431SBarry Smith .  func - pointer to int function
4595e76c431SBarry Smith 
460c4a48953SLois Curfman McInnes    Available Routines:
461f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
462f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
463f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4645e76c431SBarry Smith 
465c4a48953SLois Curfman McInnes     Options Database Keys:
46609d61ba7SLois Curfman McInnes $   -snes_eq_ls [basic,quadratic,cubic]
467c4a48953SLois Curfman McInnes 
4685e76c431SBarry Smith    Calling sequence of func:
469f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
470761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
471761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4725e76c431SBarry Smith 
4735e76c431SBarry Smith     Input parameters for func:
4745e42470aSBarry Smith .   snes - nonlinear context
4755e76c431SBarry Smith .   x - current iterate
4765e76c431SBarry Smith .   f - residual evaluated at x
4775e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4785e76c431SBarry Smith .   w - work vector
4795e76c431SBarry Smith .   fnorm - 2-norm of f
4805e76c431SBarry Smith 
4815e76c431SBarry Smith     Output parameters for func:
4825e76c431SBarry Smith .   g - residual evaluated at new iterate y
4835e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4845e76c431SBarry Smith .   gnorm - 2-norm of g
4855e76c431SBarry Smith .   ynorm - 2-norm of search length
486761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
487761aaf1bSLois Curfman McInnes            on failure.
488f59ffdedSLois Curfman McInnes 
489f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
490f59ffdedSLois Curfman McInnes 
491f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4925e76c431SBarry Smith @*/
49377c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
494761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
4955e76c431SBarry Smith {
496f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
4975e42470aSBarry Smith   return 0;
4985e76c431SBarry Smith }
49952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5005615d1e5SSatish Balay #undef __FUNC__
5015615d1e5SSatish Balay #define __FUNC__ "SNESPrintHelp_EQ_LS"
502f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
5035e42470aSBarry Smith {
5045e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5056daaf66cSBarry Smith 
506f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
50709d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls [basic,quadratic,cubic]\n",p);
50809d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
50909d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
51009d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol);
5116b5873e3SBarry Smith   return 0;
5125e42470aSBarry Smith }
51352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5145615d1e5SSatish Balay #undef __FUNC__
5155615d1e5SSatish Balay #define __FUNC__ "SNESView_EQ_LS"
516f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
517a935fc98SLois Curfman McInnes {
518a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
519a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
520d636dbe3SBarry Smith   FILE       *fd;
52119bcc07fSBarry Smith   char       *cstr;
52251695f54SLois Curfman McInnes   int        ierr;
52319bcc07fSBarry Smith   ViewerType vtype;
524a935fc98SLois Curfman McInnes 
52519bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
52619bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
52790ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
52819bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
52919bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
53019bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
53119bcc07fSBarry Smith     else cstr = "unknown";
53277c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
53377c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
534a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
53519bcc07fSBarry Smith   }
536a935fc98SLois Curfman McInnes   return 0;
537a935fc98SLois Curfman McInnes }
53852392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5395615d1e5SSatish Balay #undef __FUNC__
5405615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS"
541f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5425e42470aSBarry Smith {
5435e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5445e42470aSBarry Smith   char    ver[16];
5455e42470aSBarry Smith   double  tmp;
54625cdf11fSBarry Smith   int     ierr,flg;
5475e42470aSBarry Smith 
54809d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr);
54925cdf11fSBarry Smith   if (flg) {
5505e42470aSBarry Smith     ls->alpha = tmp;
5515e42470aSBarry Smith   }
55209d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr);
55325cdf11fSBarry Smith   if (flg) {
5545e42470aSBarry Smith     ls->maxstep = tmp;
5555e42470aSBarry Smith   }
55609d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr);
55725cdf11fSBarry Smith   if (flg) {
5585e42470aSBarry Smith     ls->steptol = tmp;
5595e42470aSBarry Smith   }
56009d61ba7SLois Curfman McInnes   ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr);
56125cdf11fSBarry Smith   if (flg) {
56248d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
56377c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5645e42470aSBarry Smith     }
56548d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
56677c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5675e42470aSBarry Smith     }
56848d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
56977c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5705e42470aSBarry Smith     }
571e3372554SBarry Smith     else {SETERRQ(1,0,"Unknown line search");}
5725e42470aSBarry Smith   }
5735e42470aSBarry Smith   return 0;
5745e42470aSBarry Smith }
5755e42470aSBarry Smith /* ------------------------------------------------------------ */
5765615d1e5SSatish Balay #undef __FUNC__
5775615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS"
578f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
5795e42470aSBarry Smith {
5805e42470aSBarry Smith   SNES_LS *neP;
5815e42470aSBarry Smith 
582ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
583e3372554SBarry Smith     SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only");
584f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
585f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
586f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
587f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
588f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
589f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
590f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
591f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
5925baf8537SBarry Smith   snes->nwork           = 0;
5935e42470aSBarry Smith 
5940452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
595ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5965e42470aSBarry Smith   snes->data    	= (void *) neP;
5975e42470aSBarry Smith   neP->alpha		= 1.e-4;
5985e42470aSBarry Smith   neP->maxstep		= 1.e8;
5995e42470aSBarry Smith   neP->steptol		= 1.e-12;
6005e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
6015e42470aSBarry Smith   return 0;
6025e42470aSBarry Smith }
6035e42470aSBarry Smith 
604