xref: /petsc/src/snes/impls/ls/ls.c (revision 09d61ba7b1e8a6e640de74b933df3a6ae6740587)
15e76c431SBarry Smith #ifndef lint
2*09d61ba7SLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.74 1996/09/28 16:24:44 curfman 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 
27f63b844aSLois Curfman McInnes int SNESSolve_EQ_LS(SNES snes,int *outits)
285e76c431SBarry Smith {
295e42470aSBarry Smith   SNES_LS       *neP = (SNES_LS *) snes->data;
30761aaf1bSLois Curfman McInnes   int           maxits, i, history_len, ierr, lits, lsfail;
31112a2221SBarry Smith   MatStructure  flg = DIFFERENT_NONZERO_PATTERN;
326b5873e3SBarry Smith   double        fnorm, gnorm, xnorm, ynorm, *history;
335e42470aSBarry Smith   Vec           Y, X, F, G, W, TMP;
345e76c431SBarry Smith 
355e42470aSBarry Smith   history	= snes->conv_hist;	/* convergence history */
365e42470aSBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
375e42470aSBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
385e42470aSBarry Smith   X		= snes->vec_sol;	/* solution vector */
3939e2f89bSBarry Smith   F		= snes->vec_func;	/* residual vector */
405e42470aSBarry Smith   Y		= snes->work[0];	/* work vectors */
415e42470aSBarry Smith   G		= snes->work[1];
425e42470aSBarry Smith   W		= snes->work[2];
435e76c431SBarry Smith 
44cddf8d76SBarry Smith   ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);       /* xnorm = || X || */
4525ed9cd1SBarry Smith   snes->iter = 0;
465334005bSBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);  /*  F(X)      */
47cddf8d76SBarry Smith   ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr);	/* fnorm <- ||F||  */
485e42470aSBarry Smith   snes->norm = fnorm;
495e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
5094a424c1SBarry Smith   SNESMonitor(snes,0,fnorm);
515e76c431SBarry Smith 
52d034289bSBarry Smith   /* set parameter for default relative tolerance convergence test */
53d034289bSBarry Smith   snes->ttol = fnorm*snes->rtol;
54d034289bSBarry Smith 
555e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
565e42470aSBarry Smith     snes->iter = i+1;
575e76c431SBarry Smith 
58ea4d3ed3SLois Curfman McInnes     /* Solve J Y = F, where J is Jacobian matrix */
595334005bSBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr);
605334005bSBarry Smith     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
6178b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
62ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNES: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
63ea4d3ed3SLois Curfman McInnes 
64ea4d3ed3SLois Curfman McInnes     /* Compute a (scaled) negative update in the line search routine:
65ea4d3ed3SLois Curfman McInnes          Y <- X - lambda*Y
66ea4d3ed3SLois Curfman McInnes        and evaluate G(Y) = function(Y))
67ea4d3ed3SLois Curfman McInnes     */
6881b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
69ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr);
70ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNES: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
71761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
725e76c431SBarry Smith 
7339e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
7439e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
755e76c431SBarry Smith     fnorm = gnorm;
765e76c431SBarry Smith 
775e42470aSBarry Smith     snes->norm = fnorm;
785e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
79cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
8094a424c1SBarry Smith     SNESMonitor(snes,i+1,fnorm);
815e76c431SBarry Smith 
825e76c431SBarry Smith     /* Test for convergence */
83bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
8439e2f89bSBarry Smith       if (X != snes->vec_sol) {
85393d2d9aSLois Curfman McInnes         ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
8639e2f89bSBarry Smith         snes->vec_sol_always = snes->vec_sol;
8739e2f89bSBarry Smith         snes->vec_func_always = snes->vec_func;
8839e2f89bSBarry Smith       }
895e76c431SBarry Smith       break;
905e76c431SBarry Smith     }
915e76c431SBarry Smith   }
9252392280SLois Curfman McInnes   if (i == maxits) {
9394a424c1SBarry Smith     PLogInfo(snes,
94f63b844aSLois Curfman McInnes       "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
9552392280SLois Curfman McInnes     i--;
9652392280SLois Curfman McInnes   }
975e42470aSBarry Smith   *outits = i+1;
985e42470aSBarry Smith   return 0;
995e76c431SBarry Smith }
1005e76c431SBarry Smith /* ------------------------------------------------------------ */
101f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes )
1025e76c431SBarry Smith {
1035e42470aSBarry Smith   int ierr;
10481b6cf68SLois Curfman McInnes   snes->nwork = 4;
105d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
1065e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
10781b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1085e42470aSBarry Smith   return 0;
1095e76c431SBarry Smith }
1105e76c431SBarry Smith /* ------------------------------------------------------------ */
111f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj)
1125e76c431SBarry Smith {
1135e42470aSBarry Smith   SNES snes = (SNES) obj;
114393d2d9aSLois Curfman McInnes   int  ierr;
1155baf8537SBarry Smith   if (snes->nwork) {
1164b0e389bSBarry Smith     ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
11721c89e3eSBarry Smith   }
1180452661fSBarry Smith   PetscFree(snes->data);
1195e42470aSBarry Smith   return 0;
1205e76c431SBarry Smith }
1215e76c431SBarry Smith /* ------------------------------------------------------------ */
1225e76c431SBarry Smith /*ARGSUSED*/
1234b828684SBarry Smith /*@C
1245e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1255e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1265e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1275e76c431SBarry Smith 
1285e76c431SBarry Smith    Input Parameters:
1295e42470aSBarry Smith .  snes - nonlinear context
1305e76c431SBarry Smith .  x - current iterate
1315e76c431SBarry Smith .  f - residual evaluated at x
1325e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1335e76c431SBarry Smith .  w - work vector
1345e76c431SBarry Smith .  fnorm - 2-norm of f
1355e76c431SBarry Smith 
136c4a48953SLois Curfman McInnes    Output Parameters:
1375e76c431SBarry Smith .  g - residual evaluated at new iterate y
1385e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1395e76c431SBarry Smith .  gnorm - 2-norm of g
1405e76c431SBarry Smith .  ynorm - 2-norm of search length
141761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1425e76c431SBarry Smith 
143c4a48953SLois Curfman McInnes    Options Database Key:
144*09d61ba7SLois Curfman McInnes $  -snes_eq_ls basic
145c4a48953SLois Curfman McInnes 
14628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
14728ae5a21SLois Curfman McInnes 
148f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
14977c4ece6SBarry Smith           SNESSetLineSearch()
1505e76c431SBarry Smith @*/
1515e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
152761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1535e76c431SBarry Smith {
1545e42470aSBarry Smith   int    ierr;
1555334005bSBarry Smith   Scalar mone = -1.0;
1565334005bSBarry Smith 
157761aaf1bSLois Curfman McInnes   *flag = 0;
1587857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
159cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);       /* ynorm = || y || */
160ea4d3ed3SLois Curfman McInnes   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);            /* y <- y - x      */
161ea4d3ed3SLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y)    */
162cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);       /* gnorm = || g || */
1637857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
164761aaf1bSLois Curfman McInnes   return 0;
1655e76c431SBarry Smith }
1665e76c431SBarry Smith /* ------------------------------------------------------------------ */
1674b828684SBarry Smith /*@C
168f525115eSLois Curfman McInnes    SNESCubicLineSearch - Performs a cubic line search (default line search method).
1695e76c431SBarry Smith 
1705e76c431SBarry Smith    Input Parameters:
1715e42470aSBarry Smith .  snes - nonlinear context
1725e76c431SBarry Smith .  x - current iterate
1735e76c431SBarry Smith .  f - residual evaluated at x
1745e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1755e76c431SBarry Smith .  w - work vector
1765e76c431SBarry Smith .  fnorm - 2-norm of f
1775e76c431SBarry Smith 
178393d2d9aSLois Curfman McInnes    Output Parameters:
1795e76c431SBarry Smith .  g - residual evaluated at new iterate y
1805e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1815e76c431SBarry Smith .  gnorm - 2-norm of g
1825e76c431SBarry Smith .  ynorm - 2-norm of search length
183761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1845e76c431SBarry Smith 
185c4a48953SLois Curfman McInnes    Options Database Key:
186*09d61ba7SLois Curfman McInnes $  -snes_eq_ls cubic
187c4a48953SLois Curfman McInnes 
1885e76c431SBarry Smith    Notes:
1895e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1905e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1915e76c431SBarry Smith 
19228ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
19328ae5a21SLois Curfman McInnes 
19477c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
1955e76c431SBarry Smith @*/
1965e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w,
197761aaf1bSLois Curfman McInnes                         double fnorm,double *ynorm,double *gnorm,int *flag)
1985e76c431SBarry Smith {
199ddd12767SBarry Smith   double  steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2;
200ea4d3ed3SLois Curfman McInnes   double  maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg;
2016b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2025e42470aSBarry Smith   Scalar  cinitslope, clambda;
2036b5873e3SBarry Smith #endif
2045e42470aSBarry Smith   int     ierr, count;
2055e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2065334005bSBarry Smith   Scalar  mone = -1.0,scale;
2075e76c431SBarry Smith 
2087857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
209761aaf1bSLois Curfman McInnes   *flag   = 0;
2105e76c431SBarry Smith   alpha   = neP->alpha;
2115e76c431SBarry Smith   maxstep = neP->maxstep;
2125e76c431SBarry Smith   steptol = neP->steptol;
2135e76c431SBarry Smith 
214cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
2155e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2165e42470aSBarry Smith     scale = maxstep/(*ynorm);
2176b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
21894a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2196b5873e3SBarry Smith #else
22094a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2216b5873e3SBarry Smith #endif
222393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2235e76c431SBarry Smith     *ynorm = maxstep;
2245e76c431SBarry Smith   }
2255e76c431SBarry Smith   minlambda = steptol/(*ynorm);
226a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2275e42470aSBarry Smith #if defined(PETSC_COMPLEX)
228a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2295e42470aSBarry Smith   initslope = real(cinitslope);
2305e42470aSBarry Smith #else
231a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2325e42470aSBarry Smith #endif
2335e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2345e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2355e76c431SBarry Smith 
236393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2375334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
23878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
239cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2405e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
241393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
24294a424c1SBarry Smith     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
243d93a2b8dSBarry Smith     goto theend;
2445e76c431SBarry Smith   }
2455e76c431SBarry Smith 
2465e76c431SBarry Smith   /* Fit points with quadratic */
2475e76c431SBarry Smith   lambda = 1.0; count = 0;
248a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2495e76c431SBarry Smith   lambdaprev = lambda;
2505e76c431SBarry Smith   gnormprev = *gnorm;
251ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
252ddd12767SBarry Smith   else lambda = lambdatemp;
253393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
254ea4d3ed3SLois Curfman McInnes   lambdaneg = -lambda;
2555e42470aSBarry Smith #if defined(PETSC_COMPLEX)
256ea4d3ed3SLois Curfman McInnes   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2575e42470aSBarry Smith #else
258ea4d3ed3SLois Curfman McInnes   ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
2595e42470aSBarry Smith #endif
26078b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
261cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2625e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
263393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
264ea4d3ed3SLois Curfman McInnes     PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda);
265d93a2b8dSBarry Smith     goto theend;
2665e76c431SBarry Smith   }
2675e76c431SBarry Smith 
2685e76c431SBarry Smith   /* Fit points with cubic */
2695e76c431SBarry Smith   count = 1;
2705e76c431SBarry Smith   while (1) {
2715e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
27294a424c1SBarry Smith       PLogInfo(snes,
2734b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
27494a424c1SBarry Smith       PLogInfo(snes,
275ea4d3ed3SLois Curfman McInnes          "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
276ea4d3ed3SLois Curfman McInnes              fnorm,*gnorm,*ynorm,lambda,initslope);
277393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
278761aaf1bSLois Curfman McInnes       *flag = -1; break;
2795e76c431SBarry Smith     }
2805e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2815e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
282ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2835e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2845e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2855e76c431SBarry Smith     d = b*b - 3*a*initslope;
2865e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2875e76c431SBarry Smith     if (a == 0.0) {
2885e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2895e76c431SBarry Smith     } else {
2905e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
2915e76c431SBarry Smith     }
2925e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
2935e76c431SBarry Smith       lambdatemp = .5*lambda;
2945e76c431SBarry Smith     }
2955e76c431SBarry Smith     lambdaprev = lambda;
2965e76c431SBarry Smith     gnormprev = *gnorm;
2975e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
2985e76c431SBarry Smith       lambda = .1*lambda;
2995e76c431SBarry Smith     }
3005e76c431SBarry Smith     else lambda = lambdatemp;
301393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
302ea4d3ed3SLois Curfman McInnes     lambdaneg = -lambda;
3035e42470aSBarry Smith #if defined(PETSC_COMPLEX)
304ea4d3ed3SLois Curfman McInnes     clambda = lambdaneg;
305393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3065e42470aSBarry Smith #else
307ea4d3ed3SLois Curfman McInnes     ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
3085e42470aSBarry Smith #endif
30978b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
310cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3115e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
312393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
313ea4d3ed3SLois Curfman McInnes       PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
314761aaf1bSLois Curfman McInnes       *flag = -1; break;
3155e76c431SBarry Smith     }
3165e76c431SBarry Smith     count++;
3175e76c431SBarry Smith   }
318d93a2b8dSBarry Smith   theend:
3197857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3205e42470aSBarry Smith   return 0;
3215e76c431SBarry Smith }
32252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3234b828684SBarry Smith /*@C
324f525115eSLois Curfman McInnes    SNESQuadraticLineSearch - Performs a quadratic line search.
3255e76c431SBarry Smith 
3265e42470aSBarry Smith    Input Parameters:
327f59ffdedSLois Curfman McInnes .  snes - the SNES context
3285e42470aSBarry Smith .  x - current iterate
3295e42470aSBarry Smith .  f - residual evaluated at x
3305e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3315e42470aSBarry Smith .  w - work vector
3325e42470aSBarry Smith .  fnorm - 2-norm of f
3335e42470aSBarry Smith 
334c4a48953SLois Curfman McInnes    Output Parameters:
3355e42470aSBarry Smith .  g - residual evaluated at new iterate y
3365e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3375e42470aSBarry Smith .  gnorm - 2-norm of g
3385e42470aSBarry Smith .  ynorm - 2-norm of search length
339761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3405e42470aSBarry Smith 
341c4a48953SLois Curfman McInnes    Options Database Key:
342*09d61ba7SLois Curfman McInnes $  -snes_eq_ls quadratic
343c4a48953SLois Curfman McInnes 
3445e42470aSBarry Smith    Notes:
34577c4ece6SBarry Smith    Use SNESSetLineSearch()
346f63b844aSLois Curfman McInnes    to set this routine within the SNES_EQ_LS method.
3475e42470aSBarry Smith 
348f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
349f59ffdedSLois Curfman McInnes 
35077c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch()
3515e42470aSBarry Smith @*/
3525e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
353761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3545e76c431SBarry Smith {
355ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3566b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3575e42470aSBarry Smith   Scalar  cinitslope,clambda;
3586b5873e3SBarry Smith #endif
3595e42470aSBarry Smith   int     ierr,count;
3605e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3615334005bSBarry Smith   Scalar  mone = -1.0,scale;
3625e76c431SBarry Smith 
3637857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
364761aaf1bSLois Curfman McInnes   *flag = 0;
3655e42470aSBarry Smith   alpha   = neP->alpha;
3665e42470aSBarry Smith   maxstep = neP->maxstep;
3675e42470aSBarry Smith   steptol = neP->steptol;
3685e76c431SBarry Smith 
369cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
3705e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3715e42470aSBarry Smith     scale = maxstep/(*ynorm);
372393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3735e42470aSBarry Smith     *ynorm = maxstep;
3745e76c431SBarry Smith   }
3755e42470aSBarry Smith   minlambda = steptol/(*ynorm);
376a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
3775e42470aSBarry Smith #if defined(PETSC_COMPLEX)
378a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
3795e42470aSBarry Smith   initslope = real(cinitslope);
3805e42470aSBarry Smith #else
381a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
3825e42470aSBarry Smith #endif
3835e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3845e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3855e42470aSBarry Smith 
386393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
3875334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
38878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
389cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3905e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
391393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
39294a424c1SBarry Smith     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
393d93a2b8dSBarry Smith     goto theend;
3945e42470aSBarry Smith   }
3955e42470aSBarry Smith 
3965e42470aSBarry Smith   /* Fit points with quadratic */
3975e42470aSBarry Smith   lambda = 1.0; count = 0;
3985e42470aSBarry Smith   count = 1;
3995e42470aSBarry Smith   while (1) {
4005e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
40194a424c1SBarry Smith       PLogInfo(snes,
4024b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
40394a424c1SBarry Smith       PLogInfo(snes,
404ea4d3ed3SLois Curfman McInnes       "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
405ea4d3ed3SLois Curfman McInnes           fnorm,*gnorm,*ynorm,lambda,initslope);
406393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
407761aaf1bSLois Curfman McInnes       *flag = -1; break;
4085e42470aSBarry Smith     }
409a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
4105e42470aSBarry Smith     lambdaprev = lambda;
4115e42470aSBarry Smith     gnormprev = *gnorm;
4125e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4135e42470aSBarry Smith       lambda = .1*lambda;
4145e42470aSBarry Smith     } else lambda = lambdatemp;
415393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4165334005bSBarry Smith     lambda = -lambda;
4175e42470aSBarry Smith #if defined(PETSC_COMPLEX)
418393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4195e42470aSBarry Smith #else
420393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4215e42470aSBarry Smith #endif
42278b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
423cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4245e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
425393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
42694a424c1SBarry Smith       PLogInfo(snes,
427ea4d3ed3SLois Curfman McInnes         "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
42806259719SBarry Smith       break;
4295e42470aSBarry Smith     }
4305e42470aSBarry Smith     count++;
4315e42470aSBarry Smith   }
432d93a2b8dSBarry Smith   theend:
4337857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4345e42470aSBarry Smith   return 0;
4355e76c431SBarry Smith }
4365e76c431SBarry Smith /* ------------------------------------------------------------ */
437c9e6a524SLois Curfman McInnes /*@C
43877c4ece6SBarry Smith    SNESSetLineSearch - Sets the line search routine to be used
439f63b844aSLois Curfman McInnes    by the method SNES_EQ_LS.
4405e76c431SBarry Smith 
4415e76c431SBarry Smith    Input Parameters:
442eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4435e76c431SBarry Smith .  func - pointer to int function
4445e76c431SBarry Smith 
445c4a48953SLois Curfman McInnes    Available Routines:
446f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
447f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
448f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4495e76c431SBarry Smith 
450c4a48953SLois Curfman McInnes     Options Database Keys:
451*09d61ba7SLois Curfman McInnes $   -snes_eq_ls [basic,quadratic,cubic]
452c4a48953SLois Curfman McInnes 
4535e76c431SBarry Smith    Calling sequence of func:
454f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
455761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
456761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4575e76c431SBarry Smith 
4585e76c431SBarry Smith     Input parameters for func:
4595e42470aSBarry Smith .   snes - nonlinear context
4605e76c431SBarry Smith .   x - current iterate
4615e76c431SBarry Smith .   f - residual evaluated at x
4625e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4635e76c431SBarry Smith .   w - work vector
4645e76c431SBarry Smith .   fnorm - 2-norm of f
4655e76c431SBarry Smith 
4665e76c431SBarry Smith     Output parameters for func:
4675e76c431SBarry Smith .   g - residual evaluated at new iterate y
4685e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4695e76c431SBarry Smith .   gnorm - 2-norm of g
4705e76c431SBarry Smith .   ynorm - 2-norm of search length
471761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
472761aaf1bSLois Curfman McInnes            on failure.
473f59ffdedSLois Curfman McInnes 
474f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
475f59ffdedSLois Curfman McInnes 
476f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4775e76c431SBarry Smith @*/
47877c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
479761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
4805e76c431SBarry Smith {
481f63b844aSLois Curfman McInnes   if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func;
4825e42470aSBarry Smith   return 0;
4835e76c431SBarry Smith }
48452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
485f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
4865e42470aSBarry Smith {
4875e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
4886daaf66cSBarry Smith 
489f63b844aSLois Curfman McInnes   PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
490*09d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls [basic,quadratic,cubic]\n",p);
491*09d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
492*09d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
493*09d61ba7SLois Curfman McInnes   PetscPrintf(snes->comm,"   %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol);
4946b5873e3SBarry Smith   return 0;
4955e42470aSBarry Smith }
49652392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
497f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer)
498a935fc98SLois Curfman McInnes {
499a935fc98SLois Curfman McInnes   SNES       snes = (SNES)obj;
500a935fc98SLois Curfman McInnes   SNES_LS    *ls = (SNES_LS *)snes->data;
501d636dbe3SBarry Smith   FILE       *fd;
50219bcc07fSBarry Smith   char       *cstr;
50351695f54SLois Curfman McInnes   int        ierr;
50419bcc07fSBarry Smith   ViewerType vtype;
505a935fc98SLois Curfman McInnes 
50619bcc07fSBarry Smith   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
50719bcc07fSBarry Smith   if (vtype  == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
50890ace30eSBarry Smith     ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
50919bcc07fSBarry Smith     if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch";
51019bcc07fSBarry Smith     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
51119bcc07fSBarry Smith     else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch";
51219bcc07fSBarry Smith     else cstr = "unknown";
51377c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    line search variant: %s\n",cstr);
51477c4ece6SBarry Smith     PetscFPrintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
515a935fc98SLois Curfman McInnes                  ls->alpha,ls->maxstep,ls->steptol);
51619bcc07fSBarry Smith   }
517a935fc98SLois Curfman McInnes   return 0;
518a935fc98SLois Curfman McInnes }
51952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
520f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes)
5215e42470aSBarry Smith {
5225e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5235e42470aSBarry Smith   char    ver[16];
5245e42470aSBarry Smith   double  tmp;
52525cdf11fSBarry Smith   int     ierr,flg;
5265e42470aSBarry Smith 
527*09d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr);
52825cdf11fSBarry Smith   if (flg) {
5295e42470aSBarry Smith     ls->alpha = tmp;
5305e42470aSBarry Smith   }
531*09d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr);
53225cdf11fSBarry Smith   if (flg) {
5335e42470aSBarry Smith     ls->maxstep = tmp;
5345e42470aSBarry Smith   }
535*09d61ba7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr);
53625cdf11fSBarry Smith   if (flg) {
5375e42470aSBarry Smith     ls->steptol = tmp;
5385e42470aSBarry Smith   }
539*09d61ba7SLois Curfman McInnes   ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr);
54025cdf11fSBarry Smith   if (flg) {
54148d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
54277c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESNoLineSearch);
5435e42470aSBarry Smith     }
54448d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
54577c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESQuadraticLineSearch);
5465e42470aSBarry Smith     }
54748d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
54877c4ece6SBarry Smith       SNESSetLineSearch(snes,SNESCubicLineSearch);
5495e42470aSBarry Smith     }
550f63b844aSLois Curfman McInnes     else {SETERRQ(1,"SNESSetFromOptions_EQ_LS:Unknown line search");}
5515e42470aSBarry Smith   }
5525e42470aSBarry Smith   return 0;
5535e42470aSBarry Smith }
5545e42470aSBarry Smith /* ------------------------------------------------------------ */
555f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES  snes )
5565e42470aSBarry Smith {
5575e42470aSBarry Smith   SNES_LS *neP;
5585e42470aSBarry Smith 
559ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
560f63b844aSLois Curfman McInnes     SETERRQ(1,"SNESCreate_EQ_LS:For SNES_NONLINEAR_EQUATIONS only");
561f63b844aSLois Curfman McInnes   snes->type		= SNES_EQ_LS;
562f63b844aSLois Curfman McInnes   snes->setup		= SNESSetUp_EQ_LS;
563f63b844aSLois Curfman McInnes   snes->solve		= SNESSolve_EQ_LS;
564f63b844aSLois Curfman McInnes   snes->destroy		= SNESDestroy_EQ_LS;
565f63b844aSLois Curfman McInnes   snes->converged	= SNESConverged_EQ_LS;
566f63b844aSLois Curfman McInnes   snes->printhelp       = SNESPrintHelp_EQ_LS;
567f63b844aSLois Curfman McInnes   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
568f63b844aSLois Curfman McInnes   snes->view            = SNESView_EQ_LS;
5695baf8537SBarry Smith   snes->nwork           = 0;
5705e42470aSBarry Smith 
5710452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
572ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5735e42470aSBarry Smith   snes->data    	= (void *) neP;
5745e42470aSBarry Smith   neP->alpha		= 1.e-4;
5755e42470aSBarry Smith   neP->maxstep		= 1.e8;
5765e42470aSBarry Smith   neP->steptol		= 1.e-12;
5775e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5785e42470aSBarry Smith   return 0;
5795e42470aSBarry Smith }
5805e42470aSBarry Smith 
5815e42470aSBarry Smith 
5825e42470aSBarry Smith 
5835e42470aSBarry Smith 
584