xref: /petsc/src/snes/impls/ls/ls.c (revision 2b02235001c7458008d2355e1a70ee2ae58756e9)
15e76c431SBarry Smith #ifndef lint
2*2b022350SLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.88 1997/04/02 16:38:35 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 */
3851979daaSLois Curfman McInnes   history_len	= snes->conv_hist_size;	/* 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;
5151979daaSLois Curfman McInnes   if (history) history[0] = fnorm;
5294a424c1SBarry Smith   SNESMonitor(snes,0,fnorm);
535e76c431SBarry Smith 
5494a9d846SBarry Smith   if (fnorm == 0.0) {outits = 0; return 0;}
5594a9d846SBarry Smith 
56d034289bSBarry Smith   /* set parameter for default relative tolerance convergence test */
57d034289bSBarry Smith   snes->ttol = fnorm*snes->rtol;
58d034289bSBarry Smith 
595e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
605e42470aSBarry Smith     snes->iter = i+1;
615e76c431SBarry Smith 
62ea4d3ed3SLois Curfman McInnes     /* Solve J Y = F, where J is Jacobian matrix */
635334005bSBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr);
645334005bSBarry Smith     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
6578b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
667a00f4a9SLois Curfman McInnes     snes->linear_its += PetscAbsInt(lits);
67af1ccdebSLois Curfman McInnes     PLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
68ea4d3ed3SLois Curfman McInnes 
69ea4d3ed3SLois Curfman McInnes     /* Compute a (scaled) negative update in the line search routine:
70ea4d3ed3SLois Curfman McInnes          Y <- X - lambda*Y
71ea4d3ed3SLois Curfman McInnes        and evaluate G(Y) = function(Y))
72ea4d3ed3SLois Curfman McInnes     */
7381b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
74ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr);
75af1ccdebSLois Curfman McInnes     PLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
76761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
775e76c431SBarry Smith 
7839e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
7939e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
805e76c431SBarry Smith     fnorm = gnorm;
815e76c431SBarry Smith 
825e42470aSBarry Smith     snes->norm = fnorm;
835e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
84cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
8594a424c1SBarry Smith     SNESMonitor(snes,i+1,fnorm);
865e76c431SBarry Smith 
875e76c431SBarry Smith     /* Test for convergence */
88bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
8916c95cacSBarry Smith       break;
9016c95cacSBarry Smith     }
9116c95cacSBarry Smith   }
9239e2f89bSBarry Smith   if (X != snes->vec_sol) {
93393d2d9aSLois Curfman McInnes     ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
9439e2f89bSBarry Smith     snes->vec_sol_always  = snes->vec_sol;
9539e2f89bSBarry Smith     snes->vec_func_always = snes->vec_func;
9639e2f89bSBarry Smith   }
9752392280SLois Curfman McInnes   if (i == maxits) {
9894a424c1SBarry Smith     PLogInfo(snes,
99f63b844aSLois Curfman McInnes       "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
10052392280SLois Curfman McInnes     i--;
10152392280SLois Curfman McInnes   }
10251979daaSLois Curfman McInnes   if (history) snes->conv_act_size = (history_len < i+1) ? history_len : i+1;
1035e42470aSBarry Smith   *outits = i+1;
1045e42470aSBarry Smith   return 0;
1055e76c431SBarry Smith }
1065e76c431SBarry Smith /* ------------------------------------------------------------ */
1075615d1e5SSatish Balay #undef __FUNC__
1085615d1e5SSatish Balay #define __FUNC__ "SNESSetUp_EQ_LS"
109f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes )
1105e76c431SBarry Smith {
1115e42470aSBarry Smith   int ierr;
11281b6cf68SLois Curfman McInnes   snes->nwork = 4;
113d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
1145e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
11581b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1165e42470aSBarry Smith   return 0;
1175e76c431SBarry Smith }
1185e76c431SBarry Smith /* ------------------------------------------------------------ */
1195615d1e5SSatish Balay #undef __FUNC__
1205eea60f9SBarry Smith #define __FUNC__ "SNESDestroy_EQ_LS" /* ADIC Ignore */
121f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj)
1225e76c431SBarry Smith {
1235e42470aSBarry Smith   SNES snes = (SNES) obj;
124393d2d9aSLois Curfman McInnes   int  ierr;
1255baf8537SBarry Smith   if (snes->nwork) {
1264b0e389bSBarry Smith     ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
12721c89e3eSBarry Smith   }
1280452661fSBarry Smith   PetscFree(snes->data);
1295e42470aSBarry Smith   return 0;
1305e76c431SBarry Smith }
1315e76c431SBarry Smith /* ------------------------------------------------------------ */
1325615d1e5SSatish Balay #undef __FUNC__
1335615d1e5SSatish Balay #define __FUNC__ "SNESNoLineSearch"
1345e76c431SBarry Smith /*ARGSUSED*/
1354b828684SBarry Smith /*@C
1365e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1375e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1385e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1395e76c431SBarry Smith 
1405e76c431SBarry Smith    Input Parameters:
1415e42470aSBarry Smith .  snes - nonlinear context
1425e76c431SBarry Smith .  x - current iterate
1435e76c431SBarry Smith .  f - residual evaluated at x
1445e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1455e76c431SBarry Smith .  w - work vector
1465e76c431SBarry Smith .  fnorm - 2-norm of f
1475e76c431SBarry Smith 
148c4a48953SLois Curfman McInnes    Output Parameters:
1495e76c431SBarry Smith .  g - residual evaluated at new iterate y
1505e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1515e76c431SBarry Smith .  gnorm - 2-norm of g
1525e76c431SBarry Smith .  ynorm - 2-norm of search length
153761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1545e76c431SBarry Smith 
155c4a48953SLois Curfman McInnes    Options Database Key:
15609d61ba7SLois Curfman McInnes $  -snes_eq_ls basic
157c4a48953SLois Curfman McInnes 
15828ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
15928ae5a21SLois Curfman McInnes 
160f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
16177c4ece6SBarry Smith           SNESSetLineSearch()
1625e76c431SBarry Smith @*/
1635e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
164761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1655e76c431SBarry Smith {
1665e42470aSBarry Smith   int    ierr;
1675334005bSBarry Smith   Scalar mone = -1.0;
1685334005bSBarry Smith 
169761aaf1bSLois Curfman McInnes   *flag = 0;
1707857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
171cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);       /* ynorm = || y || */
172ea4d3ed3SLois Curfman McInnes   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);            /* y <- y - x      */
173ea4d3ed3SLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y)    */
174cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);       /* gnorm = || g || */
1757857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
176761aaf1bSLois Curfman McInnes   return 0;
1775e76c431SBarry Smith }
1785e76c431SBarry Smith /* ------------------------------------------------------------------ */
1795615d1e5SSatish Balay #undef __FUNC__
1805615d1e5SSatish Balay #define __FUNC__ "SNESCubicLineSearch"
1814b828684SBarry Smith /*@C
182f525115eSLois Curfman McInnes    SNESCubicLineSearch - Performs a cubic line search (default line search method).
1835e76c431SBarry Smith 
1845e76c431SBarry Smith    Input Parameters:
1855e42470aSBarry Smith .  snes - nonlinear context
1865e76c431SBarry Smith .  x - current iterate
1875e76c431SBarry Smith .  f - residual evaluated at x
1885e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1895e76c431SBarry Smith .  w - work vector
1905e76c431SBarry Smith .  fnorm - 2-norm of f
1915e76c431SBarry Smith 
192393d2d9aSLois Curfman McInnes    Output Parameters:
1935e76c431SBarry Smith .  g - residual evaluated at new iterate y
1945e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1955e76c431SBarry Smith .  gnorm - 2-norm of g
1965e76c431SBarry Smith .  ynorm - 2-norm of search length
197761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1985e76c431SBarry Smith 
199c4a48953SLois Curfman McInnes    Options Database Key:
20009d61ba7SLois Curfman McInnes $  -snes_eq_ls cubic
201c4a48953SLois Curfman McInnes 
2025e76c431SBarry Smith    Notes:
2035e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
2045e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
2055e76c431SBarry Smith 
20628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
20728ae5a21SLois Curfman McInnes 
20877c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
2095e76c431SBarry Smith @*/
2105e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w,
211761aaf1bSLois Curfman McInnes                         double fnorm,double *ynorm,double *gnorm,int *flag)
2125e76c431SBarry Smith {
213ddd12767SBarry Smith   double  steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2;
214ea4d3ed3SLois Curfman McInnes   double  maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg;
2156b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2165e42470aSBarry Smith   Scalar  cinitslope, clambda;
2176b5873e3SBarry Smith #endif
2185e42470aSBarry Smith   int     ierr, count;
2195e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2205334005bSBarry Smith   Scalar  mone = -1.0,scale;
2215e76c431SBarry Smith 
2227857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
223761aaf1bSLois Curfman McInnes   *flag   = 0;
2245e76c431SBarry Smith   alpha   = neP->alpha;
2255e76c431SBarry Smith   maxstep = neP->maxstep;
2265e76c431SBarry Smith   steptol = neP->steptol;
2275e76c431SBarry Smith 
228cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
22994a9d846SBarry Smith   if (*ynorm == 0.0) {
23094a9d846SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Search direction and size is 0\n");
231ad922ac9SBarry Smith     goto theend1;
23294a9d846SBarry Smith   }
2335e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2345e42470aSBarry Smith     scale = maxstep/(*ynorm);
2356b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
23694a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2376b5873e3SBarry Smith #else
23894a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2396b5873e3SBarry Smith #endif
240393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2415e76c431SBarry Smith     *ynorm = maxstep;
2425e76c431SBarry Smith   }
2435e76c431SBarry Smith   minlambda = steptol/(*ynorm);
244a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2455e42470aSBarry Smith #if defined(PETSC_COMPLEX)
246a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2475e42470aSBarry Smith   initslope = real(cinitslope);
2485e42470aSBarry Smith #else
249a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2505e42470aSBarry Smith #endif
2515e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2525e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2535e76c431SBarry Smith 
254393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2555334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
25678b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
257cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2585e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
259393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
26094a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
261ad922ac9SBarry Smith     goto theend1;
2625e76c431SBarry Smith   }
2635e76c431SBarry Smith 
2645e76c431SBarry Smith   /* Fit points with quadratic */
2655e76c431SBarry Smith   lambda = 1.0; count = 0;
266a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2675e76c431SBarry Smith   lambdaprev = lambda;
2685e76c431SBarry Smith   gnormprev = *gnorm;
269ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
270ddd12767SBarry Smith   else lambda = lambdatemp;
271393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
272ea4d3ed3SLois Curfman McInnes   lambdaneg = -lambda;
2735e42470aSBarry Smith #if defined(PETSC_COMPLEX)
274ea4d3ed3SLois Curfman McInnes   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2755e42470aSBarry Smith #else
276ea4d3ed3SLois Curfman McInnes   ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
2775e42470aSBarry Smith #endif
27878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
279cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2805e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
281393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
282ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda);
283ad922ac9SBarry Smith     goto theend1;
2845e76c431SBarry Smith   }
2855e76c431SBarry Smith 
2865e76c431SBarry Smith   /* Fit points with cubic */
2875e76c431SBarry Smith   count = 1;
2885e76c431SBarry Smith   while (1) {
2895e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
290*2b022350SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count);
291*2b022350SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
292ea4d3ed3SLois Curfman McInnes                fnorm,*gnorm,*ynorm,lambda,initslope);
293393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
294761aaf1bSLois Curfman McInnes       *flag = -1; break;
2955e76c431SBarry Smith     }
2965e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2975e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
298ddd12767SBarry Smith     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
299*2b022350SLois Curfman McInnes     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3005e76c431SBarry Smith     d  = b*b - 3*a*initslope;
3015e76c431SBarry Smith     if (d < 0.0) d = 0.0;
3025e76c431SBarry Smith     if (a == 0.0) {
3035e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
3045e76c431SBarry Smith     } else {
3055e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
3065e76c431SBarry Smith     }
3075e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
3085e76c431SBarry Smith       lambdatemp = .5*lambda;
3095e76c431SBarry Smith     }
3105e76c431SBarry Smith     lambdaprev = lambda;
3115e76c431SBarry Smith     gnormprev = *gnorm;
3125e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
3135e76c431SBarry Smith       lambda = .1*lambda;
3145e76c431SBarry Smith     }
3155e76c431SBarry Smith     else lambda = lambdatemp;
316393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
317ea4d3ed3SLois Curfman McInnes     lambdaneg = -lambda;
3185e42470aSBarry Smith #if defined(PETSC_COMPLEX)
319ea4d3ed3SLois Curfman McInnes     clambda = lambdaneg;
320393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3215e42470aSBarry Smith #else
322ea4d3ed3SLois Curfman McInnes     ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
3235e42470aSBarry Smith #endif
32478b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
325cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
326*2b022350SLois Curfman McInnes     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough? */
327393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
328ea4d3ed3SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
3292715565aSLois Curfman McInnes       goto theend1;
330*2b022350SLois Curfman McInnes     } else {
331*2b022350SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda,  lambda=%g\n",lambda);
3325e76c431SBarry Smith     }
3335e76c431SBarry Smith     count++;
3345e76c431SBarry Smith   }
335ad922ac9SBarry Smith   theend1:
3367857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3375e42470aSBarry Smith   return 0;
3385e76c431SBarry Smith }
33952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3405615d1e5SSatish Balay #undef __FUNC__
3415615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch"
3424b828684SBarry Smith /*@C
343f525115eSLois Curfman McInnes    SNESQuadraticLineSearch - Performs a quadratic line search.
3445e76c431SBarry Smith 
3455e42470aSBarry Smith    Input Parameters:
346f59ffdedSLois Curfman McInnes .  snes - the SNES context
3475e42470aSBarry Smith .  x - current iterate
3485e42470aSBarry Smith .  f - residual evaluated at x
3495e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3505e42470aSBarry Smith .  w - work vector
3515e42470aSBarry Smith .  fnorm - 2-norm of f
3525e42470aSBarry Smith 
353c4a48953SLois Curfman McInnes    Output Parameters:
3545e42470aSBarry Smith .  g - residual evaluated at new iterate y
3555e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3565e42470aSBarry Smith .  gnorm - 2-norm of g
3575e42470aSBarry Smith .  ynorm - 2-norm of search length
358761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3595e42470aSBarry Smith 
360c4a48953SLois Curfman McInnes    Options Database Key:
36109d61ba7SLois Curfman McInnes $  -snes_eq_ls quadratic
362c4a48953SLois Curfman McInnes 
3635e42470aSBarry Smith    Notes:
36477c4ece6SBarry Smith    Use SNESSetLineSearch()
365f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3665e42470aSBarry Smith 
367f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
368f59ffdedSLois Curfman McInnes 
36977c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3705e42470aSBarry Smith @*/
3715e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
372761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3735e76c431SBarry Smith {
374ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3756b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3765e42470aSBarry Smith   Scalar  cinitslope,clambda;
3776b5873e3SBarry Smith #endif
3785e42470aSBarry Smith   int     ierr,count;
3795e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3805334005bSBarry Smith   Scalar  mone = -1.0,scale;
3815e76c431SBarry Smith 
3827857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
383761aaf1bSLois Curfman McInnes   *flag = 0;
3845e42470aSBarry Smith   alpha   = neP->alpha;
3855e42470aSBarry Smith   maxstep = neP->maxstep;
3865e42470aSBarry Smith   steptol = neP->steptol;
3875e76c431SBarry Smith 
388cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
38994a9d846SBarry Smith   if (*ynorm == 0.0) {
39094a9d846SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n");
391ad922ac9SBarry Smith     goto theend2;
39294a9d846SBarry Smith   }
3935e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3945e42470aSBarry Smith     scale = maxstep/(*ynorm);
395393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3965e42470aSBarry Smith     *ynorm = maxstep;
3975e76c431SBarry Smith   }
3985e42470aSBarry Smith   minlambda = steptol/(*ynorm);
399a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
4005e42470aSBarry Smith #if defined(PETSC_COMPLEX)
401a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
4025e42470aSBarry Smith   initslope = real(cinitslope);
4035e42470aSBarry Smith #else
404a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
4055e42470aSBarry Smith #endif
4065e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
4075e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
4085e42470aSBarry Smith 
409393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
4105334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
41178b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
412cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4135e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
414393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
41594a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
416ad922ac9SBarry Smith     goto theend2;
4175e42470aSBarry Smith   }
4185e42470aSBarry Smith 
4195e42470aSBarry Smith   /* Fit points with quadratic */
4205e42470aSBarry Smith   lambda = 1.0; count = 0;
4215e42470aSBarry Smith   count = 1;
4225e42470aSBarry Smith   while (1) {
4235e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
42494a424c1SBarry Smith       PLogInfo(snes,
4254b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
42694a424c1SBarry Smith       PLogInfo(snes,
427ea4d3ed3SLois Curfman McInnes       "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
428ea4d3ed3SLois Curfman McInnes           fnorm,*gnorm,*ynorm,lambda,initslope);
429393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
430761aaf1bSLois Curfman McInnes       *flag = -1; break;
4315e42470aSBarry Smith     }
432a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4335e42470aSBarry Smith     lambdaprev = lambda;
4345e42470aSBarry Smith     gnormprev = *gnorm;
4355e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4365e42470aSBarry Smith       lambda = .1*lambda;
4375e42470aSBarry Smith     } else lambda = lambdatemp;
438393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4395334005bSBarry Smith     lambda = -lambda;
4405e42470aSBarry Smith #if defined(PETSC_COMPLEX)
441393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4425e42470aSBarry Smith #else
443393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4445e42470aSBarry Smith #endif
44578b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
446cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4475e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
448393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
44994a424c1SBarry Smith       PLogInfo(snes,
450ea4d3ed3SLois Curfman McInnes         "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
45106259719SBarry Smith       break;
4525e42470aSBarry Smith     }
4535e42470aSBarry Smith     count++;
4545e42470aSBarry Smith   }
455ad922ac9SBarry Smith   theend2:
4567857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4575e42470aSBarry Smith   return 0;
4585e76c431SBarry Smith }
4595e76c431SBarry Smith /* ------------------------------------------------------------ */
4605615d1e5SSatish Balay #undef __FUNC__
4615eea60f9SBarry Smith #define __FUNC__ "SNESSetLineSearch" /* ADIC Ignore */
462c9e6a524SLois Curfman McInnes /*@C
46377c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
464f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4655e76c431SBarry Smith 
4665e76c431SBarry Smith    Input Parameters:
467eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4685e76c431SBarry Smith .  func - pointer to int function
4695e76c431SBarry Smith 
470c4a48953SLois Curfman McInnes    Available Routines:
471f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
472f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
473f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4745e76c431SBarry Smith 
475c4a48953SLois Curfman McInnes     Options Database Keys:
47609d61ba7SLois Curfman McInnes $   -snes_eq_ls [basic,quadratic,cubic]
477912ebf9aSLois Curfman McInnes $   -snes_eq_ls_alpha <alpha>
478912ebf9aSLois Curfman McInnes $   -snes_eq_ls_maxstep <max>
479912ebf9aSLois Curfman McInnes $   -snes_eq_ls_steptol <steptol>
480c4a48953SLois Curfman McInnes 
4815e76c431SBarry Smith    Calling sequence of func:
482f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
483761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
484761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4855e76c431SBarry Smith 
4865e76c431SBarry Smith     Input parameters for func:
4875e42470aSBarry Smith .   snes - nonlinear context
4885e76c431SBarry Smith .   x - current iterate
4895e76c431SBarry Smith .   f - residual evaluated at x
4905e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4915e76c431SBarry Smith .   w - work vector
4925e76c431SBarry Smith .   fnorm - 2-norm of f
4935e76c431SBarry Smith 
4945e76c431SBarry Smith     Output parameters for func:
4955e76c431SBarry Smith .   g - residual evaluated at new iterate y
4965e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4975e76c431SBarry Smith .   gnorm - 2-norm of g
4985e76c431SBarry Smith .   ynorm - 2-norm of search length
499761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
500761aaf1bSLois Curfman McInnes            on failure.
501f59ffdedSLois Curfman McInnes 
502f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
503f59ffdedSLois Curfman McInnes 
504f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
5055e76c431SBarry Smith @*/
50677c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
507761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
5085e76c431SBarry Smith {
509f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
5105e42470aSBarry Smith   return 0;
5115e76c431SBarry Smith }
51252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5135615d1e5SSatish Balay #undef __FUNC__
5145eea60f9SBarry Smith #define __FUNC__ "SNESPrintHelp_EQ_LS" /* ADIC Ignore */
515f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
5165e42470aSBarry Smith {
5175e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5186daaf66cSBarry Smith 
519f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
52009d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls [basic,quadratic,cubic]\n",p);
52109d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
52209d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
52309d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol);
5246b5873e3SBarry Smith   return 0;
5255e42470aSBarry Smith }
52652392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5275615d1e5SSatish Balay #undef __FUNC__
5285eea60f9SBarry Smith #define __FUNC__ "SNESView_EQ_LS" /* ADIC Ignore */
529f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
530a935fc98SLois Curfman McInnes {
531a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
532a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
533d636dbe3SBarry Smith   FILE       *fd;
53419bcc07fSBarry Smith   char       *cstr;
53551695f54SLois Curfman McInnes   int        ierr;
53619bcc07fSBarry Smith   ViewerType vtype;
537a935fc98SLois Curfman McInnes 
53819bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
53919bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
54090ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
54119bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
54219bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
54319bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
54419bcc07fSBarry Smith     else cstr = "unknown";
54577c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
54677c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
547a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
54819bcc07fSBarry Smith   }
549a935fc98SLois Curfman McInnes   return 0;
550a935fc98SLois Curfman McInnes }
55152392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5525615d1e5SSatish Balay #undef __FUNC__
5535615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS"
554f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5555e42470aSBarry Smith {
5565e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5575e42470aSBarry Smith   char    ver[16];
5585e42470aSBarry Smith   double  tmp;
55925cdf11fSBarry Smith   int     ierr,flg;
5605e42470aSBarry Smith 
56109d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr);
56225cdf11fSBarry Smith   if (flg) {
5635e42470aSBarry Smith     ls->alpha = tmp;
5645e42470aSBarry Smith   }
56509d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr);
56625cdf11fSBarry Smith   if (flg) {
5675e42470aSBarry Smith     ls->maxstep = tmp;
5685e42470aSBarry Smith   }
56909d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr);
57025cdf11fSBarry Smith   if (flg) {
5715e42470aSBarry Smith     ls->steptol = tmp;
5725e42470aSBarry Smith   }
57309d61ba7SLois Curfman McInnes   ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr);
57425cdf11fSBarry Smith   if (flg) {
57548d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
57677c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5775e42470aSBarry Smith     }
57848d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
57977c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5805e42470aSBarry Smith     }
58148d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
58277c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5835e42470aSBarry Smith     }
584e3372554SBarry Smith     else {SETERRQ(1,0,"Unknown line search");}
5855e42470aSBarry Smith   }
5865e42470aSBarry Smith   return 0;
5875e42470aSBarry Smith }
5885e42470aSBarry Smith /* ------------------------------------------------------------ */
5895615d1e5SSatish Balay #undef __FUNC__
5905615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS"
591f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
5925e42470aSBarry Smith {
5935e42470aSBarry Smith   SNES_LS *neP;
5945e42470aSBarry Smith 
595ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
596e3372554SBarry Smith     SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only");
597f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
598f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
599f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
600f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
601f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
602f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
603f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
604f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
6055baf8537SBarry Smith   snes->nwork           = 0;
6065e42470aSBarry Smith 
6070452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
608ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
6095e42470aSBarry Smith   snes->data    	= (void *) neP;
6105e42470aSBarry Smith   neP->alpha		= 1.e-4;
6115e42470aSBarry Smith   neP->maxstep		= 1.e8;
6125e42470aSBarry Smith   neP->steptol		= 1.e-12;
6135e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
6145e42470aSBarry Smith   return 0;
6155e42470aSBarry Smith }
6165e42470aSBarry Smith 
617