xref: /petsc/src/snes/impls/ls/ls.c (revision 912ebf9aa32cd6ffee33ffd0333e9b4fec2e8450)
15e76c431SBarry Smith #ifndef lint
2*912ebf9aSLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.86 1997/02/22 02:28:49 bsmith Exp curfman $";
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 */
29094a424c1SBarry Smith       PLogInfo(snes,
2914b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
29294a424c1SBarry Smith       PLogInfo(snes,
293ea4d3ed3SLois Curfman McInnes          "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
294ea4d3ed3SLois Curfman McInnes              fnorm,*gnorm,*ynorm,lambda,initslope);
295393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
296761aaf1bSLois Curfman McInnes       *flag = -1; break;
2975e76c431SBarry Smith     }
2985e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2995e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
300ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3015e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
3025e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
3035e76c431SBarry Smith     d = b*b - 3*a*initslope;
3045e76c431SBarry Smith     if (d < 0.0) d = 0.0;
3055e76c431SBarry Smith     if (a == 0.0) {
3065e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
3075e76c431SBarry Smith     } else {
3085e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
3095e76c431SBarry Smith     }
3105e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
3115e76c431SBarry Smith       lambdatemp = .5*lambda;
3125e76c431SBarry Smith     }
3135e76c431SBarry Smith     lambdaprev = lambda;
3145e76c431SBarry Smith     gnormprev = *gnorm;
3155e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
3165e76c431SBarry Smith       lambda = .1*lambda;
3175e76c431SBarry Smith     }
3185e76c431SBarry Smith     else lambda = lambdatemp;
319393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
320ea4d3ed3SLois Curfman McInnes     lambdaneg = -lambda;
3215e42470aSBarry Smith #if defined(PETSC_COMPLEX)
322ea4d3ed3SLois Curfman McInnes     clambda = lambdaneg;
323393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3245e42470aSBarry Smith #else
325ea4d3ed3SLois Curfman McInnes     ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
3265e42470aSBarry Smith #endif
32778b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
328cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3295e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
330393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
331ea4d3ed3SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
332761aaf1bSLois Curfman McInnes       *flag = -1; break;
3335e76c431SBarry Smith     }
3345e76c431SBarry Smith     count++;
3355e76c431SBarry Smith   }
336ad922ac9SBarry Smith   theend1:
3377857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3385e42470aSBarry Smith   return 0;
3395e76c431SBarry Smith }
34052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3415615d1e5SSatish Balay #undef __FUNC__
3425615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch"
3434b828684SBarry Smith /*@C
344f525115eSLois Curfman McInnes    SNESQuadraticLineSearch - Performs a quadratic line search.
3455e76c431SBarry Smith 
3465e42470aSBarry Smith    Input Parameters:
347f59ffdedSLois Curfman McInnes .  snes - the SNES context
3485e42470aSBarry Smith .  x - current iterate
3495e42470aSBarry Smith .  f - residual evaluated at x
3505e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3515e42470aSBarry Smith .  w - work vector
3525e42470aSBarry Smith .  fnorm - 2-norm of f
3535e42470aSBarry Smith 
354c4a48953SLois Curfman McInnes    Output Parameters:
3555e42470aSBarry Smith .  g - residual evaluated at new iterate y
3565e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3575e42470aSBarry Smith .  gnorm - 2-norm of g
3585e42470aSBarry Smith .  ynorm - 2-norm of search length
359761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3605e42470aSBarry Smith 
361c4a48953SLois Curfman McInnes    Options Database Key:
36209d61ba7SLois Curfman McInnes $  -snes_eq_ls quadratic
363c4a48953SLois Curfman McInnes 
3645e42470aSBarry Smith    Notes:
36577c4ece6SBarry Smith    Use SNESSetLineSearch()
366f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3675e42470aSBarry Smith 
368f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
369f59ffdedSLois Curfman McInnes 
37077c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3715e42470aSBarry Smith @*/
3725e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
373761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3745e76c431SBarry Smith {
375ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3766b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3775e42470aSBarry Smith   Scalar  cinitslope,clambda;
3786b5873e3SBarry Smith #endif
3795e42470aSBarry Smith   int     ierr,count;
3805e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3815334005bSBarry Smith   Scalar  mone = -1.0,scale;
3825e76c431SBarry Smith 
3837857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
384761aaf1bSLois Curfman McInnes   *flag = 0;
3855e42470aSBarry Smith   alpha   = neP->alpha;
3865e42470aSBarry Smith   maxstep = neP->maxstep;
3875e42470aSBarry Smith   steptol = neP->steptol;
3885e76c431SBarry Smith 
389cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
39094a9d846SBarry Smith   if (*ynorm == 0.0) {
39194a9d846SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n");
392ad922ac9SBarry Smith     goto theend2;
39394a9d846SBarry Smith   }
3945e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3955e42470aSBarry Smith     scale = maxstep/(*ynorm);
396393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3975e42470aSBarry Smith     *ynorm = maxstep;
3985e76c431SBarry Smith   }
3995e42470aSBarry Smith   minlambda = steptol/(*ynorm);
400a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
4015e42470aSBarry Smith #if defined(PETSC_COMPLEX)
402a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
4035e42470aSBarry Smith   initslope = real(cinitslope);
4045e42470aSBarry Smith #else
405a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
4065e42470aSBarry Smith #endif
4075e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
4085e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
4095e42470aSBarry Smith 
410393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
4115334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
41278b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
413cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4145e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
415393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
41694a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
417ad922ac9SBarry Smith     goto theend2;
4185e42470aSBarry Smith   }
4195e42470aSBarry Smith 
4205e42470aSBarry Smith   /* Fit points with quadratic */
4215e42470aSBarry Smith   lambda = 1.0; count = 0;
4225e42470aSBarry Smith   count = 1;
4235e42470aSBarry Smith   while (1) {
4245e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
42594a424c1SBarry Smith       PLogInfo(snes,
4264b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
42794a424c1SBarry Smith       PLogInfo(snes,
428ea4d3ed3SLois Curfman McInnes       "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
429ea4d3ed3SLois Curfman McInnes           fnorm,*gnorm,*ynorm,lambda,initslope);
430393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
431761aaf1bSLois Curfman McInnes       *flag = -1; break;
4325e42470aSBarry Smith     }
433a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4345e42470aSBarry Smith     lambdaprev = lambda;
4355e42470aSBarry Smith     gnormprev = *gnorm;
4365e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4375e42470aSBarry Smith       lambda = .1*lambda;
4385e42470aSBarry Smith     } else lambda = lambdatemp;
439393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4405334005bSBarry Smith     lambda = -lambda;
4415e42470aSBarry Smith #if defined(PETSC_COMPLEX)
442393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4435e42470aSBarry Smith #else
444393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4455e42470aSBarry Smith #endif
44678b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
447cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4485e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
449393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
45094a424c1SBarry Smith       PLogInfo(snes,
451ea4d3ed3SLois Curfman McInnes         "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
45206259719SBarry Smith       break;
4535e42470aSBarry Smith     }
4545e42470aSBarry Smith     count++;
4555e42470aSBarry Smith   }
456ad922ac9SBarry Smith   theend2:
4577857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4585e42470aSBarry Smith   return 0;
4595e76c431SBarry Smith }
4605e76c431SBarry Smith /* ------------------------------------------------------------ */
4615615d1e5SSatish Balay #undef __FUNC__
4625eea60f9SBarry Smith #define __FUNC__ "SNESSetLineSearch" /* ADIC Ignore */
463c9e6a524SLois Curfman McInnes /*@C
46477c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
465f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4665e76c431SBarry Smith 
4675e76c431SBarry Smith    Input Parameters:
468eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4695e76c431SBarry Smith .  func - pointer to int function
4705e76c431SBarry Smith 
471c4a48953SLois Curfman McInnes    Available Routines:
472f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
473f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
474f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4755e76c431SBarry Smith 
476c4a48953SLois Curfman McInnes     Options Database Keys:
47709d61ba7SLois Curfman McInnes $   -snes_eq_ls [basic,quadratic,cubic]
478*912ebf9aSLois Curfman McInnes $   -snes_eq_ls_alpha <alpha>
479*912ebf9aSLois Curfman McInnes $   -snes_eq_ls_maxstep <max>
480*912ebf9aSLois Curfman McInnes $   -snes_eq_ls_steptol <steptol>
481c4a48953SLois Curfman McInnes 
4825e76c431SBarry Smith    Calling sequence of func:
483f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
484761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
485761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4865e76c431SBarry Smith 
4875e76c431SBarry Smith     Input parameters for func:
4885e42470aSBarry Smith .   snes - nonlinear context
4895e76c431SBarry Smith .   x - current iterate
4905e76c431SBarry Smith .   f - residual evaluated at x
4915e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4925e76c431SBarry Smith .   w - work vector
4935e76c431SBarry Smith .   fnorm - 2-norm of f
4945e76c431SBarry Smith 
4955e76c431SBarry Smith     Output parameters for func:
4965e76c431SBarry Smith .   g - residual evaluated at new iterate y
4975e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4985e76c431SBarry Smith .   gnorm - 2-norm of g
4995e76c431SBarry Smith .   ynorm - 2-norm of search length
500761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
501761aaf1bSLois Curfman McInnes            on failure.
502f59ffdedSLois Curfman McInnes 
503f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
504f59ffdedSLois Curfman McInnes 
505f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
5065e76c431SBarry Smith @*/
50777c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
508761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
5095e76c431SBarry Smith {
510f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
5115e42470aSBarry Smith   return 0;
5125e76c431SBarry Smith }
51352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5145615d1e5SSatish Balay #undef __FUNC__
5155eea60f9SBarry Smith #define __FUNC__ "SNESPrintHelp_EQ_LS" /* ADIC Ignore */
516f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
5175e42470aSBarry Smith {
5185e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5196daaf66cSBarry Smith 
520f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
52109d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls [basic,quadratic,cubic]\n",p);
52209d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
52309d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
52409d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol);
5256b5873e3SBarry Smith   return 0;
5265e42470aSBarry Smith }
52752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5285615d1e5SSatish Balay #undef __FUNC__
5295eea60f9SBarry Smith #define __FUNC__ "SNESView_EQ_LS" /* ADIC Ignore */
530f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
531a935fc98SLois Curfman McInnes {
532a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
533a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
534d636dbe3SBarry Smith   FILE       *fd;
53519bcc07fSBarry Smith   char       *cstr;
53651695f54SLois Curfman McInnes   int        ierr;
53719bcc07fSBarry Smith   ViewerType vtype;
538a935fc98SLois Curfman McInnes 
53919bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
54019bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
54190ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
54219bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
54319bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
54419bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
54519bcc07fSBarry Smith     else cstr = "unknown";
54677c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
54777c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
548a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
54919bcc07fSBarry Smith   }
550a935fc98SLois Curfman McInnes   return 0;
551a935fc98SLois Curfman McInnes }
55252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5535615d1e5SSatish Balay #undef __FUNC__
5545615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS"
555f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5565e42470aSBarry Smith {
5575e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5585e42470aSBarry Smith   char    ver[16];
5595e42470aSBarry Smith   double  tmp;
56025cdf11fSBarry Smith   int     ierr,flg;
5615e42470aSBarry Smith 
56209d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr);
56325cdf11fSBarry Smith   if (flg) {
5645e42470aSBarry Smith     ls->alpha = tmp;
5655e42470aSBarry Smith   }
56609d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr);
56725cdf11fSBarry Smith   if (flg) {
5685e42470aSBarry Smith     ls->maxstep = tmp;
5695e42470aSBarry Smith   }
57009d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr);
57125cdf11fSBarry Smith   if (flg) {
5725e42470aSBarry Smith     ls->steptol = tmp;
5735e42470aSBarry Smith   }
57409d61ba7SLois Curfman McInnes   ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr);
57525cdf11fSBarry Smith   if (flg) {
57648d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
57777c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5785e42470aSBarry Smith     }
57948d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
58077c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5815e42470aSBarry Smith     }
58248d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
58377c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5845e42470aSBarry Smith     }
585e3372554SBarry Smith     else {SETERRQ(1,0,"Unknown line search");}
5865e42470aSBarry Smith   }
5875e42470aSBarry Smith   return 0;
5885e42470aSBarry Smith }
5895e42470aSBarry Smith /* ------------------------------------------------------------ */
5905615d1e5SSatish Balay #undef __FUNC__
5915615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS"
592f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
5935e42470aSBarry Smith {
5945e42470aSBarry Smith   SNES_LS *neP;
5955e42470aSBarry Smith 
596ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
597e3372554SBarry Smith     SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only");
598f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
599f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
600f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
601f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
602f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
603f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
604f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
605f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
6065baf8537SBarry Smith   snes->nwork           = 0;
6075e42470aSBarry Smith 
6080452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
609ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
6105e42470aSBarry Smith   snes->data    	= (void *) neP;
6115e42470aSBarry Smith   neP->alpha		= 1.e-4;
6125e42470aSBarry Smith   neP->maxstep		= 1.e8;
6135e42470aSBarry Smith   neP->steptol		= 1.e-12;
6145e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
6155e42470aSBarry Smith   return 0;
6165e42470aSBarry Smith }
6175e42470aSBarry Smith 
618