xref: /petsc/src/snes/impls/ls/ls.c (revision 5615d1e584023db9367fb782d85b1b4ebbb8df18)
15e76c431SBarry Smith #ifndef lint
2*5615d1e5SSatish Balay static char vcid[] = "$Id: ls.c,v 1.79 1997/01/01 03:40:57 bsmith Exp balay $";
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 
27*5615d1e5SSatish Balay #undef __FUNC__
28*5615d1e5SSatish 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);
64af1ccdebSLois Curfman McInnes     PLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
65ea4d3ed3SLois Curfman McInnes 
66ea4d3ed3SLois Curfman McInnes     /* Compute a (scaled) negative update in the line search routine:
67ea4d3ed3SLois Curfman McInnes          Y <- X - lambda*Y
68ea4d3ed3SLois Curfman McInnes        and evaluate G(Y) = function(Y))
69ea4d3ed3SLois Curfman McInnes     */
7081b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
71ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr);
72af1ccdebSLois Curfman McInnes     PLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
73761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
745e76c431SBarry Smith 
7539e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
7639e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
775e76c431SBarry Smith     fnorm = gnorm;
785e76c431SBarry Smith 
795e42470aSBarry Smith     snes->norm = fnorm;
805e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
81cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
8294a424c1SBarry Smith     SNESMonitor(snes,i+1,fnorm);
835e76c431SBarry Smith 
845e76c431SBarry Smith     /* Test for convergence */
85bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
8639e2f89bSBarry Smith       if (X != snes->vec_sol) {
87393d2d9aSLois Curfman McInnes         ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
8839e2f89bSBarry Smith         snes->vec_sol_always = snes->vec_sol;
8939e2f89bSBarry Smith         snes->vec_func_always = snes->vec_func;
9039e2f89bSBarry Smith       }
915e76c431SBarry Smith       break;
925e76c431SBarry Smith     }
935e76c431SBarry Smith   }
9452392280SLois Curfman McInnes   if (i == maxits) {
9594a424c1SBarry Smith     PLogInfo(snes,
96f63b844aSLois Curfman McInnes       "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
9752392280SLois Curfman McInnes     i--;
9852392280SLois Curfman McInnes   }
995e42470aSBarry Smith   *outits = i+1;
1005e42470aSBarry Smith   return 0;
1015e76c431SBarry Smith }
1025e76c431SBarry Smith /* ------------------------------------------------------------ */
103*5615d1e5SSatish Balay #undef __FUNC__
104*5615d1e5SSatish Balay #define __FUNC__ "SNESSetUp_EQ_LS"
105f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes )
1065e76c431SBarry Smith {
1075e42470aSBarry Smith   int ierr;
10881b6cf68SLois Curfman McInnes   snes->nwork = 4;
109d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
1105e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
11181b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1125e42470aSBarry Smith   return 0;
1135e76c431SBarry Smith }
1145e76c431SBarry Smith /* ------------------------------------------------------------ */
115*5615d1e5SSatish Balay #undef __FUNC__
116*5615d1e5SSatish Balay #define __FUNC__ "SNESDestroy_EQ_LS"
117f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj)
1185e76c431SBarry Smith {
1195e42470aSBarry Smith   SNES snes = (SNES) obj;
120393d2d9aSLois Curfman McInnes   int  ierr;
1215baf8537SBarry Smith   if (snes->nwork) {
1224b0e389bSBarry Smith     ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
12321c89e3eSBarry Smith   }
1240452661fSBarry Smith   PetscFree(snes->data);
1255e42470aSBarry Smith   return 0;
1265e76c431SBarry Smith }
1275e76c431SBarry Smith /* ------------------------------------------------------------ */
128*5615d1e5SSatish Balay #undef __FUNC__
129*5615d1e5SSatish Balay #define __FUNC__ "SNESNoLineSearch"
1305e76c431SBarry Smith /*ARGSUSED*/
1314b828684SBarry Smith /*@C
1325e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1335e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1345e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1355e76c431SBarry Smith 
1365e76c431SBarry Smith    Input Parameters:
1375e42470aSBarry Smith .  snes - nonlinear context
1385e76c431SBarry Smith .  x - current iterate
1395e76c431SBarry Smith .  f - residual evaluated at x
1405e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1415e76c431SBarry Smith .  w - work vector
1425e76c431SBarry Smith .  fnorm - 2-norm of f
1435e76c431SBarry Smith 
144c4a48953SLois Curfman McInnes    Output Parameters:
1455e76c431SBarry Smith .  g - residual evaluated at new iterate y
1465e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1475e76c431SBarry Smith .  gnorm - 2-norm of g
1485e76c431SBarry Smith .  ynorm - 2-norm of search length
149761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1505e76c431SBarry Smith 
151c4a48953SLois Curfman McInnes    Options Database Key:
15209d61ba7SLois Curfman McInnes $  -snes_eq_ls basic
153c4a48953SLois Curfman McInnes 
15428ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
15528ae5a21SLois Curfman McInnes 
156f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
15777c4ece6SBarry Smith           SNESSetLineSearch()
1585e76c431SBarry Smith @*/
1595e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
160761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1615e76c431SBarry Smith {
1625e42470aSBarry Smith   int    ierr;
1635334005bSBarry Smith   Scalar mone = -1.0;
1645334005bSBarry Smith 
165761aaf1bSLois Curfman McInnes   *flag = 0;
1667857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
167cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);       /* ynorm = || y || */
168ea4d3ed3SLois Curfman McInnes   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);            /* y <- y - x      */
169ea4d3ed3SLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y)    */
170cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);       /* gnorm = || g || */
1717857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
172761aaf1bSLois Curfman McInnes   return 0;
1735e76c431SBarry Smith }
1745e76c431SBarry Smith /* ------------------------------------------------------------------ */
175*5615d1e5SSatish Balay #undef __FUNC__
176*5615d1e5SSatish Balay #define __FUNC__ "SNESCubicLineSearch"
1774b828684SBarry Smith /*@C
178f525115eSLois Curfman McInnes    SNESCubicLineSearch - Performs a cubic line search (default line search method).
1795e76c431SBarry Smith 
1805e76c431SBarry Smith    Input Parameters:
1815e42470aSBarry Smith .  snes - nonlinear context
1825e76c431SBarry Smith .  x - current iterate
1835e76c431SBarry Smith .  f - residual evaluated at x
1845e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1855e76c431SBarry Smith .  w - work vector
1865e76c431SBarry Smith .  fnorm - 2-norm of f
1875e76c431SBarry Smith 
188393d2d9aSLois Curfman McInnes    Output Parameters:
1895e76c431SBarry Smith .  g - residual evaluated at new iterate y
1905e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1915e76c431SBarry Smith .  gnorm - 2-norm of g
1925e76c431SBarry Smith .  ynorm - 2-norm of search length
193761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1945e76c431SBarry Smith 
195c4a48953SLois Curfman McInnes    Options Database Key:
19609d61ba7SLois Curfman McInnes $  -snes_eq_ls cubic
197c4a48953SLois Curfman McInnes 
1985e76c431SBarry Smith    Notes:
1995e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
2005e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
2015e76c431SBarry Smith 
20228ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
20328ae5a21SLois Curfman McInnes 
20477c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
2055e76c431SBarry Smith @*/
2065e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w,
207761aaf1bSLois Curfman McInnes                         double fnorm,double *ynorm,double *gnorm,int *flag)
2085e76c431SBarry Smith {
209ddd12767SBarry Smith   double  steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2;
210ea4d3ed3SLois Curfman McInnes   double  maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg;
2116b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2125e42470aSBarry Smith   Scalar  cinitslope, clambda;
2136b5873e3SBarry Smith #endif
2145e42470aSBarry Smith   int     ierr, count;
2155e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2165334005bSBarry Smith   Scalar  mone = -1.0,scale;
2175e76c431SBarry Smith 
2187857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
219761aaf1bSLois Curfman McInnes   *flag   = 0;
2205e76c431SBarry Smith   alpha   = neP->alpha;
2215e76c431SBarry Smith   maxstep = neP->maxstep;
2225e76c431SBarry Smith   steptol = neP->steptol;
2235e76c431SBarry Smith 
224cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
2255e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2265e42470aSBarry Smith     scale = maxstep/(*ynorm);
2276b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
22894a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2296b5873e3SBarry Smith #else
23094a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2316b5873e3SBarry Smith #endif
232393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2335e76c431SBarry Smith     *ynorm = maxstep;
2345e76c431SBarry Smith   }
2355e76c431SBarry Smith   minlambda = steptol/(*ynorm);
236a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2375e42470aSBarry Smith #if defined(PETSC_COMPLEX)
238a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2395e42470aSBarry Smith   initslope = real(cinitslope);
2405e42470aSBarry Smith #else
241a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2425e42470aSBarry Smith #endif
2435e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2445e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2455e76c431SBarry Smith 
246393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2475334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
24878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
249cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2505e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
251393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
25294a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
253d93a2b8dSBarry Smith     goto theend;
2545e76c431SBarry Smith   }
2555e76c431SBarry Smith 
2565e76c431SBarry Smith   /* Fit points with quadratic */
2575e76c431SBarry Smith   lambda = 1.0; count = 0;
258a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2595e76c431SBarry Smith   lambdaprev = lambda;
2605e76c431SBarry Smith   gnormprev = *gnorm;
261ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
262ddd12767SBarry Smith   else lambda = lambdatemp;
263393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
264ea4d3ed3SLois Curfman McInnes   lambdaneg = -lambda;
2655e42470aSBarry Smith #if defined(PETSC_COMPLEX)
266ea4d3ed3SLois Curfman McInnes   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2675e42470aSBarry Smith #else
268ea4d3ed3SLois Curfman McInnes   ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
2695e42470aSBarry Smith #endif
27078b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
271cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2725e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
273393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
274ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda);
275d93a2b8dSBarry Smith     goto theend;
2765e76c431SBarry Smith   }
2775e76c431SBarry Smith 
2785e76c431SBarry Smith   /* Fit points with cubic */
2795e76c431SBarry Smith   count = 1;
2805e76c431SBarry Smith   while (1) {
2815e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
28294a424c1SBarry Smith       PLogInfo(snes,
2834b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
28494a424c1SBarry Smith       PLogInfo(snes,
285ea4d3ed3SLois Curfman McInnes          "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
286ea4d3ed3SLois Curfman McInnes              fnorm,*gnorm,*ynorm,lambda,initslope);
287393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
288761aaf1bSLois Curfman McInnes       *flag = -1; break;
2895e76c431SBarry Smith     }
2905e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2915e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
292ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2935e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2945e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2955e76c431SBarry Smith     d = b*b - 3*a*initslope;
2965e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2975e76c431SBarry Smith     if (a == 0.0) {
2985e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2995e76c431SBarry Smith     } else {
3005e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
3015e76c431SBarry Smith     }
3025e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
3035e76c431SBarry Smith       lambdatemp = .5*lambda;
3045e76c431SBarry Smith     }
3055e76c431SBarry Smith     lambdaprev = lambda;
3065e76c431SBarry Smith     gnormprev = *gnorm;
3075e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
3085e76c431SBarry Smith       lambda = .1*lambda;
3095e76c431SBarry Smith     }
3105e76c431SBarry Smith     else lambda = lambdatemp;
311393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
312ea4d3ed3SLois Curfman McInnes     lambdaneg = -lambda;
3135e42470aSBarry Smith #if defined(PETSC_COMPLEX)
314ea4d3ed3SLois Curfman McInnes     clambda = lambdaneg;
315393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3165e42470aSBarry Smith #else
317ea4d3ed3SLois Curfman McInnes     ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
3185e42470aSBarry Smith #endif
31978b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
320cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3215e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
322393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
323ea4d3ed3SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
324761aaf1bSLois Curfman McInnes       *flag = -1; break;
3255e76c431SBarry Smith     }
3265e76c431SBarry Smith     count++;
3275e76c431SBarry Smith   }
328d93a2b8dSBarry Smith   theend:
3297857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3305e42470aSBarry Smith   return 0;
3315e76c431SBarry Smith }
33252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
333*5615d1e5SSatish Balay #undef __FUNC__
334*5615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch"
3354b828684SBarry Smith /*@C
336f525115eSLois Curfman McInnes    SNESQuadraticLineSearch - Performs a quadratic line search.
3375e76c431SBarry Smith 
3385e42470aSBarry Smith    Input Parameters:
339f59ffdedSLois Curfman McInnes .  snes - the SNES context
3405e42470aSBarry Smith .  x - current iterate
3415e42470aSBarry Smith .  f - residual evaluated at x
3425e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3435e42470aSBarry Smith .  w - work vector
3445e42470aSBarry Smith .  fnorm - 2-norm of f
3455e42470aSBarry Smith 
346c4a48953SLois Curfman McInnes    Output Parameters:
3475e42470aSBarry Smith .  g - residual evaluated at new iterate y
3485e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3495e42470aSBarry Smith .  gnorm - 2-norm of g
3505e42470aSBarry Smith .  ynorm - 2-norm of search length
351761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3525e42470aSBarry Smith 
353c4a48953SLois Curfman McInnes    Options Database Key:
35409d61ba7SLois Curfman McInnes $  -snes_eq_ls quadratic
355c4a48953SLois Curfman McInnes 
3565e42470aSBarry Smith    Notes:
35777c4ece6SBarry Smith    Use SNESSetLineSearch()
358f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3595e42470aSBarry Smith 
360f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
361f59ffdedSLois Curfman McInnes 
36277c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3635e42470aSBarry Smith @*/
3645e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
365761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3665e76c431SBarry Smith {
367ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3686b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3695e42470aSBarry Smith   Scalar  cinitslope,clambda;
3706b5873e3SBarry Smith #endif
3715e42470aSBarry Smith   int     ierr,count;
3725e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3735334005bSBarry Smith   Scalar  mone = -1.0,scale;
3745e76c431SBarry Smith 
3757857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
376761aaf1bSLois Curfman McInnes   *flag = 0;
3775e42470aSBarry Smith   alpha   = neP->alpha;
3785e42470aSBarry Smith   maxstep = neP->maxstep;
3795e42470aSBarry Smith   steptol = neP->steptol;
3805e76c431SBarry Smith 
381cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
3825e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3835e42470aSBarry Smith     scale = maxstep/(*ynorm);
384393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3855e42470aSBarry Smith     *ynorm = maxstep;
3865e76c431SBarry Smith   }
3875e42470aSBarry Smith   minlambda = steptol/(*ynorm);
388a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
3895e42470aSBarry Smith #if defined(PETSC_COMPLEX)
390a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
3915e42470aSBarry Smith   initslope = real(cinitslope);
3925e42470aSBarry Smith #else
393a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
3945e42470aSBarry Smith #endif
3955e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3965e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3975e42470aSBarry Smith 
398393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
3995334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
40078b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
401cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4025e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
403393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
40494a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
405d93a2b8dSBarry Smith     goto theend;
4065e42470aSBarry Smith   }
4075e42470aSBarry Smith 
4085e42470aSBarry Smith   /* Fit points with quadratic */
4095e42470aSBarry Smith   lambda = 1.0; count = 0;
4105e42470aSBarry Smith   count = 1;
4115e42470aSBarry Smith   while (1) {
4125e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
41394a424c1SBarry Smith       PLogInfo(snes,
4144b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
41594a424c1SBarry Smith       PLogInfo(snes,
416ea4d3ed3SLois Curfman McInnes       "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
417ea4d3ed3SLois Curfman McInnes           fnorm,*gnorm,*ynorm,lambda,initslope);
418393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
419761aaf1bSLois Curfman McInnes       *flag = -1; break;
4205e42470aSBarry Smith     }
421a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4225e42470aSBarry Smith     lambdaprev = lambda;
4235e42470aSBarry Smith     gnormprev = *gnorm;
4245e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4255e42470aSBarry Smith       lambda = .1*lambda;
4265e42470aSBarry Smith     } else lambda = lambdatemp;
427393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4285334005bSBarry Smith     lambda = -lambda;
4295e42470aSBarry Smith #if defined(PETSC_COMPLEX)
430393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4315e42470aSBarry Smith #else
432393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4335e42470aSBarry Smith #endif
43478b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
435cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4365e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
437393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
43894a424c1SBarry Smith       PLogInfo(snes,
439ea4d3ed3SLois Curfman McInnes         "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
44006259719SBarry Smith       break;
4415e42470aSBarry Smith     }
4425e42470aSBarry Smith     count++;
4435e42470aSBarry Smith   }
444d93a2b8dSBarry Smith   theend:
4457857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4465e42470aSBarry Smith   return 0;
4475e76c431SBarry Smith }
4485e76c431SBarry Smith /* ------------------------------------------------------------ */
449*5615d1e5SSatish Balay #undef __FUNC__
450*5615d1e5SSatish Balay #define __FUNC__ "SNESSetLineSearch"
451c9e6a524SLois Curfman McInnes /*@C
45277c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
453f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4545e76c431SBarry Smith 
4555e76c431SBarry Smith    Input Parameters:
456eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4575e76c431SBarry Smith .  func - pointer to int function
4585e76c431SBarry Smith 
459c4a48953SLois Curfman McInnes    Available Routines:
460f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
461f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
462f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4635e76c431SBarry Smith 
464c4a48953SLois Curfman McInnes     Options Database Keys:
46509d61ba7SLois Curfman McInnes $   -snes_eq_ls [basic,quadratic,cubic]
466c4a48953SLois Curfman McInnes 
4675e76c431SBarry Smith    Calling sequence of func:
468f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
469761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
470761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4715e76c431SBarry Smith 
4725e76c431SBarry Smith     Input parameters for func:
4735e42470aSBarry Smith .   snes - nonlinear context
4745e76c431SBarry Smith .   x - current iterate
4755e76c431SBarry Smith .   f - residual evaluated at x
4765e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4775e76c431SBarry Smith .   w - work vector
4785e76c431SBarry Smith .   fnorm - 2-norm of f
4795e76c431SBarry Smith 
4805e76c431SBarry Smith     Output parameters for func:
4815e76c431SBarry Smith .   g - residual evaluated at new iterate y
4825e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4835e76c431SBarry Smith .   gnorm - 2-norm of g
4845e76c431SBarry Smith .   ynorm - 2-norm of search length
485761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
486761aaf1bSLois Curfman McInnes            on failure.
487f59ffdedSLois Curfman McInnes 
488f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
489f59ffdedSLois Curfman McInnes 
490f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4915e76c431SBarry Smith @*/
49277c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
493761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
4945e76c431SBarry Smith {
495f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
4965e42470aSBarry Smith   return 0;
4975e76c431SBarry Smith }
49852392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
499*5615d1e5SSatish Balay #undef __FUNC__
500*5615d1e5SSatish Balay #define __FUNC__ "SNESPrintHelp_EQ_LS"
501f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
5025e42470aSBarry Smith {
5035e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5046daaf66cSBarry Smith 
505f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
50609d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls [basic,quadratic,cubic]\n",p);
50709d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
50809d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
50909d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol);
5106b5873e3SBarry Smith   return 0;
5115e42470aSBarry Smith }
51252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
513*5615d1e5SSatish Balay #undef __FUNC__
514*5615d1e5SSatish Balay #define __FUNC__ "SNESView_EQ_LS"
515f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
516a935fc98SLois Curfman McInnes {
517a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
518a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
519d636dbe3SBarry Smith   FILE       *fd;
52019bcc07fSBarry Smith   char       *cstr;
52151695f54SLois Curfman McInnes   int        ierr;
52219bcc07fSBarry Smith   ViewerType vtype;
523a935fc98SLois Curfman McInnes 
52419bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
52519bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
52690ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
52719bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
52819bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
52919bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
53019bcc07fSBarry Smith     else cstr = "unknown";
53177c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
53277c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
533a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
53419bcc07fSBarry Smith   }
535a935fc98SLois Curfman McInnes   return 0;
536a935fc98SLois Curfman McInnes }
53752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
538*5615d1e5SSatish Balay #undef __FUNC__
539*5615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS"
540f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5415e42470aSBarry Smith {
5425e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5435e42470aSBarry Smith   char    ver[16];
5445e42470aSBarry Smith   double  tmp;
54525cdf11fSBarry Smith   int     ierr,flg;
5465e42470aSBarry Smith 
54709d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr);
54825cdf11fSBarry Smith   if (flg) {
5495e42470aSBarry Smith     ls->alpha = tmp;
5505e42470aSBarry Smith   }
55109d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr);
55225cdf11fSBarry Smith   if (flg) {
5535e42470aSBarry Smith     ls->maxstep = tmp;
5545e42470aSBarry Smith   }
55509d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr);
55625cdf11fSBarry Smith   if (flg) {
5575e42470aSBarry Smith     ls->steptol = tmp;
5585e42470aSBarry Smith   }
55909d61ba7SLois Curfman McInnes   ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr);
56025cdf11fSBarry Smith   if (flg) {
56148d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
56277c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5635e42470aSBarry Smith     }
56448d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
56577c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5665e42470aSBarry Smith     }
56748d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
56877c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5695e42470aSBarry Smith     }
570e3372554SBarry Smith     else {SETERRQ(1,0,"Unknown line search");}
5715e42470aSBarry Smith   }
5725e42470aSBarry Smith   return 0;
5735e42470aSBarry Smith }
5745e42470aSBarry Smith /* ------------------------------------------------------------ */
575*5615d1e5SSatish Balay #undef __FUNC__
576*5615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS"
577f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
5785e42470aSBarry Smith {
5795e42470aSBarry Smith   SNES_LS *neP;
5805e42470aSBarry Smith 
581ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
582e3372554SBarry Smith     SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only");
583f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
584f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
585f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
586f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
587f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
588f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
589f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
590f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
5915baf8537SBarry Smith   snes->nwork           = 0;
5925e42470aSBarry Smith 
5930452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
594ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5955e42470aSBarry Smith   snes->data    	= (void *) neP;
5965e42470aSBarry Smith   neP->alpha		= 1.e-4;
5975e42470aSBarry Smith   neP->maxstep		= 1.e8;
5985e42470aSBarry Smith   neP->steptol		= 1.e-12;
5995e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
6005e42470aSBarry Smith   return 0;
6015e42470aSBarry Smith }
6025e42470aSBarry Smith 
603