xref: /petsc/src/snes/impls/ls/ls.c (revision d636dbe3a9c413b447e52fc0f7f06f5e4018d190)
15e76c431SBarry Smith #ifndef lint
2*d636dbe3SBarry Smith static char vcid[] = "$Id: ls.c,v 1.40 1995/09/04 17:25:44 bsmith Exp bsmith $";
35e76c431SBarry Smith #endif
45e76c431SBarry Smith 
55e76c431SBarry Smith #include <math.h>
6fbe28522SBarry Smith #include "ls.h"
7b16a3bb1SBarry Smith #include "pinclude/pviewer.h"
8bbb6d6a8SBarry Smith #if defined(HAVE_STRING_H)
9bbb6d6a8SBarry Smith #include <string.h>
10bbb6d6a8SBarry Smith #endif
115e42470aSBarry Smith 
125e42470aSBarry Smith /*
135e42470aSBarry Smith      Implements a line search variant of Newton's Method
145e76c431SBarry Smith     for solving systems of nonlinear equations.
155e76c431SBarry Smith 
165e76c431SBarry Smith     Input parameters:
175e42470aSBarry Smith .   snes - nonlinear context obtained from SNESCreate()
185e76c431SBarry Smith 
195e42470aSBarry Smith     Output Parameters:
20a935fc98SLois Curfman McInnes .   outits  - Number of global iterations until termination.
215e76c431SBarry Smith 
225e76c431SBarry Smith     Notes:
235e76c431SBarry Smith     This implements essentially a truncated Newton method with a
245e76c431SBarry Smith     line search.  By default a cubic backtracking line search
255e76c431SBarry Smith     is employed, as described in the text "Numerical Methods for
265e76c431SBarry Smith     Unconstrained Optimization and Nonlinear Equations" by Dennis
27393d2d9aSLois Curfman McInnes     and Schnabel.
285e76c431SBarry Smith */
295e76c431SBarry Smith 
305e42470aSBarry Smith int SNESSolve_LS(SNES snes,int *outits)
315e76c431SBarry Smith {
325e42470aSBarry Smith   SNES_LS      *neP = (SNES_LS *) snes->data;
33761aaf1bSLois Curfman McInnes   int          maxits, i, history_len, ierr, lits, lsfail;
34df60cc22SBarry Smith   MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN;
356b5873e3SBarry Smith   double       fnorm, gnorm, xnorm, ynorm, *history;
365e42470aSBarry Smith   Vec          Y, X, F, G, W, TMP;
37336446d4SLois Curfman McInnes   SLES         sles;
38336446d4SLois Curfman McInnes   KSP          ksp;
395e76c431SBarry Smith 
405e42470aSBarry Smith   history	= snes->conv_hist;	/* convergence history */
415e42470aSBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
425e42470aSBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
435e42470aSBarry Smith   X		= snes->vec_sol;	/* solution vector */
4439e2f89bSBarry Smith   F		= snes->vec_func;	/* residual vector */
455e42470aSBarry Smith   Y		= snes->work[0];	/* work vectors */
465e42470aSBarry Smith   G		= snes->work[1];
475e42470aSBarry Smith   W		= snes->work[2];
485e76c431SBarry Smith 
4978b31e54SBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr); /* X <- X_0        */
50393d2d9aSLois Curfman McInnes   ierr = VecNorm(X,&xnorm); CHKERRQ(ierr);               /* xnorm = || X || */
5178b31e54SBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);   /* (+/-) F(X)      */
52393d2d9aSLois Curfman McInnes   ierr = VecNorm(F,&fnorm); CHKERRQ(ierr);	         /* fnorm <- ||F||  */
535e42470aSBarry Smith   snes->norm = fnorm;
545e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
55bbb6d6a8SBarry Smith   if (snes->monitor)
56bbb6d6a8SBarry Smith     {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);}
575e76c431SBarry Smith 
58393d2d9aSLois Curfman McInnes   /* Set the KSP stopping criterion to use the Eisenstat-Walker method */
59336446d4SLois Curfman McInnes   if (snes->ksp_ewconv) {
60336446d4SLois Curfman McInnes     ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr);
61336446d4SLois Curfman McInnes     ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr);
62336446d4SLois Curfman McInnes     ierr = KSPSetConvergenceTest(ksp,SNES_KSP_EW_Converged_Private,
63336446d4SLois Curfman McInnes            (void *)snes);  CHKERRQ(ierr);
64336446d4SLois Curfman McInnes   }
65336446d4SLois Curfman McInnes 
665e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
675e42470aSBarry Smith     snes->iter = i+1;
685e76c431SBarry Smith 
695e76c431SBarry Smith     /* Solve J Y = -F, where J is Jacobian matrix */
70df60cc22SBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,
71bbb6d6a8SBarry Smith                                &flg); CHKERRQ(ierr);
72a935fc98SLois Curfman McInnes     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,
73a935fc98SLois Curfman McInnes                                flg); CHKERRQ(ierr);
7478b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
7581b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
76761aaf1bSLois Curfman McInnes     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);
77761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
7878b31e54SBarry Smith     CHKERRQ(ierr);
795e76c431SBarry Smith 
8039e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
8139e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
825e76c431SBarry Smith     fnorm = gnorm;
835e76c431SBarry Smith 
845e42470aSBarry Smith     snes->norm = fnorm;
855e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
86393d2d9aSLois Curfman McInnes     ierr = VecNorm(X,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
87bbb6d6a8SBarry Smith     if (snes->monitor)
88393d2d9aSLois Curfman McInnes       {ierr = (*snes->monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);}
895e76c431SBarry Smith 
905e76c431SBarry Smith     /* Test for convergence */
91bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
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       }
975e76c431SBarry Smith       break;
985e76c431SBarry Smith     }
995e76c431SBarry Smith   }
10052392280SLois Curfman McInnes   if (i == maxits) {
10152392280SLois Curfman McInnes     PLogInfo((PetscObject)snes,
1024b828684SBarry Smith       "SNESSolve_LS: Maximum number of iterations has been reached: %d\n",
1034b828684SBarry Smith       maxits);
10452392280SLois Curfman McInnes     i--;
10552392280SLois Curfman McInnes   }
1065e42470aSBarry Smith   *outits = i+1;
1075e42470aSBarry Smith   return 0;
1085e76c431SBarry Smith }
1095e76c431SBarry Smith /* ------------------------------------------------------------ */
1105e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
1115e76c431SBarry Smith {
1125e42470aSBarry Smith   int ierr;
11381b6cf68SLois Curfman McInnes   snes->nwork = 4;
11478b31e54SBarry Smith   ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr);
1155e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
11681b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1175e42470aSBarry Smith   return 0;
1185e76c431SBarry Smith }
1195e76c431SBarry Smith /* ------------------------------------------------------------ */
1205e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
1215e76c431SBarry Smith {
1225e42470aSBarry Smith   SNES snes = (SNES) obj;
123393d2d9aSLois Curfman McInnes   int  ierr;
124393d2d9aSLois Curfman McInnes   ierr = VecFreeVecs(snes->work,snes->nwork); CHKERRQ(ierr);
12578b31e54SBarry Smith   PETSCFREE(snes->data);
1265e42470aSBarry Smith   return 0;
1275e76c431SBarry Smith }
1285e76c431SBarry Smith /* ------------------------------------------------------------ */
1295e76c431SBarry Smith /*ARGSUSED*/
1304b828684SBarry Smith /*@C
1315e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1325e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1335e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1345e76c431SBarry Smith 
1355e76c431SBarry Smith    Input Parameters:
1365e42470aSBarry Smith .  snes - nonlinear context
1375e76c431SBarry Smith .  x - current iterate
1385e76c431SBarry Smith .  f - residual evaluated at x
1395e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1405e76c431SBarry Smith .  w - work vector
1415e76c431SBarry Smith .  fnorm - 2-norm of f
1425e76c431SBarry Smith 
143c4a48953SLois Curfman McInnes    Output Parameters:
1445e76c431SBarry Smith .  g - residual evaluated at new iterate y
1455e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1465e76c431SBarry Smith .  gnorm - 2-norm of g
1475e76c431SBarry Smith .  ynorm - 2-norm of search length
148761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1495e76c431SBarry Smith 
150c4a48953SLois Curfman McInnes    Options Database Key:
151c4a48953SLois Curfman McInnes $  -snes_line_search basic
152c4a48953SLois Curfman McInnes 
15328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
15428ae5a21SLois Curfman McInnes 
155f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
156a935fc98SLois Curfman McInnes           SNESSetLineSearchRoutine()
1575e76c431SBarry Smith @*/
1585e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
159761aaf1bSLois Curfman McInnes               double fnorm, double *ynorm, double *gnorm,int *flag )
1605e76c431SBarry Smith {
1615e42470aSBarry Smith   int    ierr;
1625e42470aSBarry Smith   Scalar one = 1.0;
163761aaf1bSLois Curfman McInnes   *flag = 0;
1647857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
165393d2d9aSLois Curfman McInnes   ierr = VecNorm(y,ynorm); CHKERRQ(ierr);              /* ynorm = || y || */
166393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,y); CHKERRQ(ierr);             /* y <- x + y      */
167393d2d9aSLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* (+/-) F(y)      */
168393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);              /* gnorm = || g || */
1697857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
170761aaf1bSLois Curfman McInnes   return 0;
1715e76c431SBarry Smith }
1725e76c431SBarry Smith /* ------------------------------------------------------------------ */
1734b828684SBarry Smith /*@C
174f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
175f59ffdedSLois Curfman McInnes    is the default line search method.
1765e76c431SBarry Smith 
1775e76c431SBarry Smith    Input Parameters:
1785e42470aSBarry Smith .  snes - nonlinear context
1795e76c431SBarry Smith .  x - current iterate
1805e76c431SBarry Smith .  f - residual evaluated at x
1815e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1825e76c431SBarry Smith .  w - work vector
1835e76c431SBarry Smith .  fnorm - 2-norm of f
1845e76c431SBarry Smith 
185393d2d9aSLois Curfman McInnes    Output Parameters:
1865e76c431SBarry Smith .  g - residual evaluated at new iterate y
1875e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1885e76c431SBarry Smith .  gnorm - 2-norm of g
1895e76c431SBarry Smith .  ynorm - 2-norm of search length
190761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1915e76c431SBarry Smith 
192c4a48953SLois Curfman McInnes    Options Database Key:
193c4a48953SLois Curfman McInnes $  -snes_line_search cubic
194c4a48953SLois Curfman McInnes 
1955e76c431SBarry Smith    Notes:
1965e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1975e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1985e76c431SBarry Smith 
19928ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
20028ae5a21SLois Curfman McInnes 
201f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
2025e76c431SBarry Smith @*/
2035e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
204761aaf1bSLois Curfman McInnes                 double fnorm, double *ynorm, double *gnorm,int *flag)
2055e76c431SBarry Smith {
2065e42470aSBarry Smith   double  steptol, initslope;
2075e42470aSBarry Smith   double  lambdaprev, gnormprev;
2085e76c431SBarry Smith   double  a, b, d, t1, t2;
2096b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2105e42470aSBarry Smith   Scalar  cinitslope,clambda;
2116b5873e3SBarry Smith #endif
2125e42470aSBarry Smith   int     ierr, count;
2135e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2145e42470aSBarry Smith   Scalar  one = 1.0,scale;
2155e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
2165e76c431SBarry Smith 
2177857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
218761aaf1bSLois Curfman McInnes   *flag = 0;
2195e76c431SBarry Smith   alpha   = neP->alpha;
2205e76c431SBarry Smith   maxstep = neP->maxstep;
2215e76c431SBarry Smith   steptol = neP->steptol;
2225e76c431SBarry Smith 
223393d2d9aSLois Curfman McInnes   ierr = VecNorm(y,ynorm); CHKERRQ(ierr);
2245e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2255e42470aSBarry Smith     scale = maxstep/(*ynorm);
2266b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2274b828684SBarry Smith     PLogInfo((PetscObject)snes,
2284b828684SBarry Smith                     "SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2296b5873e3SBarry Smith #else
2304b828684SBarry Smith     PLogInfo((PetscObject)snes,
2314b828684SBarry Smith                     "SNESCubicLineSearch: Scaling step by %g\n",scale);
2326b5873e3SBarry Smith #endif
233393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2345e76c431SBarry Smith     *ynorm = maxstep;
2355e76c431SBarry Smith   }
2365e76c431SBarry Smith   minlambda = steptol/(*ynorm);
2375e42470aSBarry Smith #if defined(PETSC_COMPLEX)
238393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr);
2395e42470aSBarry Smith   initslope = real(cinitslope);
2405e42470aSBarry Smith #else
241393d2d9aSLois Curfman McInnes   VecDot(f,y,&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);
247393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,w); CHKERRQ(ierr);
24878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
249393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm);
2505e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
251393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2524b828684SBarry Smith     PLogInfo((PetscObject)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;
2585e76c431SBarry Smith   lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
2595e76c431SBarry Smith   lambdaprev = lambda;
2605e76c431SBarry Smith   gnormprev = *gnorm;
2615e76c431SBarry Smith   if (lambdatemp <= .1*lambda) {
2625e76c431SBarry Smith     lambda = .1*lambda;
2635e76c431SBarry Smith   } else lambda = lambdatemp;
264393d2d9aSLois Curfman McInnes   ierr = VecCopy(x,w); CHKERRQ(ierr);
2655e42470aSBarry Smith #if defined(PETSC_COMPLEX)
266393d2d9aSLois Curfman McInnes   clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2675e42470aSBarry Smith #else
268393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2695e42470aSBarry Smith #endif
27078b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
271393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
2725e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
273393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2744b828684SBarry Smith     PLogInfo((PetscObject)snes,
2754b828684SBarry Smith     "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda);
276d93a2b8dSBarry Smith     goto theend;
2775e76c431SBarry Smith   }
2785e76c431SBarry Smith 
2795e76c431SBarry Smith   /* Fit points with cubic */
2805e76c431SBarry Smith   count = 1;
2815e76c431SBarry Smith   while (1) {
2825e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
2834b828684SBarry Smith       PLogInfo((PetscObject)snes,
2844b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
2854b828684SBarry Smith       PLogInfo((PetscObject)snes,
2864b828684SBarry Smith          "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g \n",
2875e76c431SBarry Smith               fnorm,*gnorm, *ynorm,lambda);
288393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
289761aaf1bSLois Curfman McInnes       *flag = -1; break;
2905e76c431SBarry Smith     }
2915e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2925e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
2935e76c431SBarry Smith     a = (t1/(lambda*lambda) -
2945e76c431SBarry Smith               t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2955e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2965e76c431SBarry Smith               lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2975e76c431SBarry Smith     d = b*b - 3*a*initslope;
2985e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2995e76c431SBarry Smith     if (a == 0.0) {
3005e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
3015e76c431SBarry Smith     } else {
3025e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
3035e76c431SBarry Smith     }
3045e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
3055e76c431SBarry Smith       lambdatemp = .5*lambda;
3065e76c431SBarry Smith     }
3075e76c431SBarry Smith     lambdaprev = lambda;
3085e76c431SBarry Smith     gnormprev = *gnorm;
3095e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
3105e76c431SBarry Smith       lambda = .1*lambda;
3115e76c431SBarry Smith     }
3125e76c431SBarry Smith     else lambda = lambdatemp;
313393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
3145e42470aSBarry Smith #if defined(PETSC_COMPLEX)
315393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3165e42470aSBarry Smith #else
317393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
3185e42470aSBarry Smith #endif
31978b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
320393d2d9aSLois Curfman McInnes     ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
3215e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
322393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
3234b828684SBarry Smith       PLogInfo((PetscObject)snes,
3244b828684SBarry Smith         "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda);
325761aaf1bSLois Curfman McInnes       *flag = -1; break;
3265e76c431SBarry Smith     }
3275e76c431SBarry Smith     count++;
3285e76c431SBarry Smith   }
329d93a2b8dSBarry Smith   theend:
3307857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3315e42470aSBarry Smith   return 0;
3325e76c431SBarry Smith }
33352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3344b828684SBarry Smith /*@C
3355e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3365e76c431SBarry Smith 
3375e42470aSBarry Smith    Input Parameters:
338f59ffdedSLois Curfman McInnes .  snes - the SNES context
3395e42470aSBarry Smith .  x - current iterate
3405e42470aSBarry Smith .  f - residual evaluated at x
3415e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3425e42470aSBarry Smith .  w - work vector
3435e42470aSBarry Smith .  fnorm - 2-norm of f
3445e42470aSBarry Smith 
345c4a48953SLois Curfman McInnes    Output Parameters:
3465e42470aSBarry Smith .  g - residual evaluated at new iterate y
3475e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3485e42470aSBarry Smith .  gnorm - 2-norm of g
3495e42470aSBarry Smith .  ynorm - 2-norm of search length
350761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3515e42470aSBarry Smith 
352c4a48953SLois Curfman McInnes    Options Database Key:
353c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
354c4a48953SLois Curfman McInnes 
3555e42470aSBarry Smith    Notes:
356f59ffdedSLois Curfman McInnes    Use SNESSetLineSearchRoutine()
357f59ffdedSLois Curfman McInnes    to set this routine within the SNES_NLS method.
3585e42470aSBarry Smith 
359f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
360f59ffdedSLois Curfman McInnes 
361f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
3625e42470aSBarry Smith @*/
3635e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
364761aaf1bSLois Curfman McInnes                     double fnorm, double *ynorm, double *gnorm,int *flag)
3655e76c431SBarry Smith {
3665e42470aSBarry Smith   double  steptol, initslope;
3675e42470aSBarry Smith   double  lambdaprev, gnormprev;
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;
3735e42470aSBarry Smith   Scalar  one = 1.0,scale;
3745e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
3755e76c431SBarry Smith 
3767857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
377761aaf1bSLois Curfman McInnes   *flag = 0;
3785e42470aSBarry Smith   alpha   = neP->alpha;
3795e42470aSBarry Smith   maxstep = neP->maxstep;
3805e42470aSBarry Smith   steptol = neP->steptol;
3815e76c431SBarry Smith 
3825e42470aSBarry Smith   VecNorm(y, ynorm );
3835e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3845e42470aSBarry Smith     scale = maxstep/(*ynorm);
385393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3865e42470aSBarry Smith     *ynorm = maxstep;
3875e76c431SBarry Smith   }
3885e42470aSBarry Smith   minlambda = steptol/(*ynorm);
3895e42470aSBarry Smith #if defined(PETSC_COMPLEX)
390393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr);
3915e42470aSBarry Smith   initslope = real(cinitslope);
3925e42470aSBarry Smith #else
393393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&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);
399393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,w); CHKERRQ(ierr);
40078b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
401393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
4025e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
403393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
4044b828684SBarry Smith     PLogInfo((PetscObject)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 */
4134b828684SBarry Smith       PLogInfo((PetscObject)snes,
4144b828684SBarry Smith        "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
4154b828684SBarry Smith       PLogInfo((PetscObject)snes,
4164b828684SBarry Smith         "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g \n",
4175e42470aSBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
418393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
419761aaf1bSLois Curfman McInnes       *flag = -1; break;
4205e42470aSBarry Smith     }
4215e42470aSBarry Smith     lambdatemp = -initslope/(2.0*(*gnorm - fnorm - 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);
4285e42470aSBarry Smith #if defined(PETSC_COMPLEX)
429393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4305e42470aSBarry Smith #else
431393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4325e42470aSBarry Smith #endif
43378b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
434393d2d9aSLois Curfman McInnes     ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
4355e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
436393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
4374b828684SBarry Smith       PLogInfo((PetscObject)snes,
4384b828684SBarry Smith         "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n",
4394b828684SBarry Smith         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 /* ------------------------------------------------------------ */
449b1f0a012SBarry Smith /*@
4505e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
451fbe28522SBarry Smith    by the method SNES_LS.
4525e76c431SBarry Smith 
4535e76c431SBarry Smith    Input Parameters:
454eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4555e76c431SBarry Smith .  func - pointer to int function
4565e76c431SBarry Smith 
457c4a48953SLois Curfman McInnes    Available Routines:
458f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
459f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
460f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4615e76c431SBarry Smith 
462c4a48953SLois Curfman McInnes     Options Database Keys:
463c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
464c4a48953SLois Curfman McInnes 
4655e76c431SBarry Smith    Calling sequence of func:
466f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
467761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
468761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4695e76c431SBarry Smith 
4705e76c431SBarry Smith     Input parameters for func:
4715e42470aSBarry Smith .   snes - nonlinear context
4725e76c431SBarry Smith .   x - current iterate
4735e76c431SBarry Smith .   f - residual evaluated at x
4745e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4755e76c431SBarry Smith .   w - work vector
4765e76c431SBarry Smith .   fnorm - 2-norm of f
4775e76c431SBarry Smith 
4785e76c431SBarry Smith     Output parameters for func:
4795e76c431SBarry Smith .   g - residual evaluated at new iterate y
4805e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4815e76c431SBarry Smith .   gnorm - 2-norm of g
4825e76c431SBarry Smith .   ynorm - 2-norm of search length
483761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
484761aaf1bSLois Curfman McInnes            on failure.
485f59ffdedSLois Curfman McInnes 
486f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
487f59ffdedSLois Curfman McInnes 
488f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4895e76c431SBarry Smith @*/
4905e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
491761aaf1bSLois Curfman McInnes                              double,double *,double*,int*) )
4925e76c431SBarry Smith {
493fbe28522SBarry Smith   if ((snes)->type == SNES_NLS)
4945e42470aSBarry Smith     ((SNES_LS *)(snes->data))->LineSearch = func;
4955e42470aSBarry Smith   return 0;
4965e76c431SBarry Smith }
49752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
4985e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes)
4995e42470aSBarry Smith {
5005e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
50152392280SLois Curfman McInnes   char    *p;
50252392280SLois Curfman McInnes   if (snes->prefix) p = snes->prefix; else p = "-";
50352392280SLois Curfman McInnes   MPIU_printf(snes->comm," method ls (system of nonlinear equations):\n");
50452392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search [basic,quadratic,cubic]\n",p);
50552392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_alpha alpha (default %g)\n",p,ls->alpha);
50652392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_maxstep max (default %g)\n",p,ls->maxstep);
50752392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_steptol tol (default %g)\n",p,ls->steptol);
5086b5873e3SBarry Smith   return 0;
5095e42470aSBarry Smith }
51052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
511a935fc98SLois Curfman McInnes static int SNESView_LS(PetscObject obj,Viewer viewer)
512a935fc98SLois Curfman McInnes {
513a935fc98SLois Curfman McInnes   SNES    snes = (SNES)obj;
514a935fc98SLois Curfman McInnes   SNES_LS *ls = (SNES_LS *)snes->data;
515*d636dbe3SBarry Smith   FILE    *fd;
516a935fc98SLois Curfman McInnes   char    *cstring;
517a935fc98SLois Curfman McInnes 
518*d636dbe3SBarry Smith   ierr = ViewerFileGetPointer_Private(viewer,&fd); CHKERRQ(ierr):
519a935fc98SLois Curfman McInnes   if (ls->LineSearch == SNESNoLineSearch)
520a935fc98SLois Curfman McInnes     cstring = "SNESNoLineSearch";
521a935fc98SLois Curfman McInnes   else if (ls->LineSearch == SNESQuadraticLineSearch)
522a935fc98SLois Curfman McInnes     cstring = "SNESQuadraticLineSearch";
523a935fc98SLois Curfman McInnes   else if (ls->LineSearch == SNESCubicLineSearch)
524a935fc98SLois Curfman McInnes     cstring = "SNESCubicLineSearch";
525a935fc98SLois Curfman McInnes   else
526a935fc98SLois Curfman McInnes     cstring = "unknown";
527a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    line search variant: %s\n",cstring);
528a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
529a935fc98SLois Curfman McInnes      ls->alpha,ls->maxstep,ls->steptol);
530a935fc98SLois Curfman McInnes   return 0;
531a935fc98SLois Curfman McInnes }
53252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5335e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5345e42470aSBarry Smith {
5355e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5365e42470aSBarry Smith   char    ver[16];
5375e42470aSBarry Smith   double  tmp;
5385e42470aSBarry Smith 
539df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) {
5405e42470aSBarry Smith     ls->alpha = tmp;
5415e42470aSBarry Smith   }
542df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) {
5435e42470aSBarry Smith     ls->maxstep = tmp;
5445e42470aSBarry Smith   }
545df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) {
5465e42470aSBarry Smith     ls->steptol = tmp;
5475e42470aSBarry Smith   }
548df60cc22SBarry Smith   if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) {
5495e42470aSBarry Smith     if (!strcmp(ver,"basic")) {
5505e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5515e42470aSBarry Smith     }
5525e42470aSBarry Smith     else if (!strcmp(ver,"quadratic")) {
5535e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5545e42470aSBarry Smith     }
5555e42470aSBarry Smith     else if (!strcmp(ver,"cubic")) {
5565e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5575e42470aSBarry Smith     }
5588c48e012SBarry Smith     else {SETERRQ(1,"SNESSetFromOptions_LS: Unknown line search");}
5595e42470aSBarry Smith   }
5605e42470aSBarry Smith   return 0;
5615e42470aSBarry Smith }
5625e42470aSBarry Smith /* ------------------------------------------------------------ */
5635e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
5645e42470aSBarry Smith {
5655e42470aSBarry Smith   SNES_LS *neP;
5665e42470aSBarry Smith 
5671a3481a4SLois Curfman McInnes   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1,
5681a3481a4SLois Curfman McInnes     "SNESCreate_LS: Valid for SNES_NONLINEAR_EQUATIONS problems only");
56925c7317fSLois Curfman McInnes   snes->type		= SNES_EQ_NLS;
57049e3953dSBarry Smith   snes->setup		= SNESSetUp_LS;
57149e3953dSBarry Smith   snes->solve		= SNESSolve_LS;
5725e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
573bbb6d6a8SBarry Smith   snes->converged	= SNESDefaultConverged;
57449e3953dSBarry Smith   snes->printhelp       = SNESPrintHelp_LS;
57549e3953dSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_LS;
576a935fc98SLois Curfman McInnes   snes->view            = SNESView_LS;
5775e42470aSBarry Smith 
57878b31e54SBarry Smith   neP			= PETSCNEW(SNES_LS);   CHKPTRQ(neP);
579ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5805e42470aSBarry Smith   snes->data    	= (void *) neP;
5815e42470aSBarry Smith   neP->alpha		= 1.e-4;
5825e42470aSBarry Smith   neP->maxstep		= 1.e8;
5835e42470aSBarry Smith   neP->steptol		= 1.e-12;
5845e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5855e42470aSBarry Smith   return 0;
5865e42470aSBarry Smith }
5875e42470aSBarry Smith 
5885e42470aSBarry Smith 
5895e42470aSBarry Smith 
5905e42470aSBarry Smith 
591