xref: /petsc/src/snes/impls/ls/ls.c (revision 48d914877651b9fa76f196ebaf17c108719d05c1)
15e76c431SBarry Smith #ifndef lint
2*48d91487SBarry Smith static char vcid[] = "$Id: ls.c,v 1.44 1995/09/30 19:31:14 bsmith Exp bsmith $";
35e76c431SBarry Smith #endif
45e76c431SBarry Smith 
55e76c431SBarry Smith #include <math.h>
6fbe28522SBarry Smith #include "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 
275e42470aSBarry Smith int SNESSolve_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;
31df60cc22SBarry Smith   MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN;
326b5873e3SBarry Smith   double       fnorm, gnorm, xnorm, ynorm, *history;
335e42470aSBarry Smith   Vec          Y, X, F, G, W, TMP;
34336446d4SLois Curfman McInnes   SLES         sles;
35336446d4SLois Curfman McInnes   KSP          ksp;
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 
4678b31e54SBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr); /* X <- X_0        */
47393d2d9aSLois Curfman McInnes   ierr = VecNorm(X,&xnorm); CHKERRQ(ierr);               /* xnorm = || X || */
4878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);   /* (+/-) F(X)      */
49393d2d9aSLois Curfman McInnes   ierr = VecNorm(F,&fnorm); CHKERRQ(ierr);	         /* fnorm <- ||F||  */
505e42470aSBarry Smith   snes->norm = fnorm;
515e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
52bbb6d6a8SBarry Smith   if (snes->monitor)
53bbb6d6a8SBarry Smith     {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);}
545e76c431SBarry Smith 
55393d2d9aSLois Curfman McInnes   /* Set the KSP stopping criterion to use the Eisenstat-Walker method */
56336446d4SLois Curfman McInnes   if (snes->ksp_ewconv) {
57336446d4SLois Curfman McInnes     ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr);
58336446d4SLois Curfman McInnes     ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr);
59336446d4SLois Curfman McInnes     ierr = KSPSetConvergenceTest(ksp,SNES_KSP_EW_Converged_Private,
60336446d4SLois Curfman McInnes            (void *)snes);  CHKERRQ(ierr);
61336446d4SLois Curfman McInnes   }
62336446d4SLois Curfman McInnes 
635e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
645e42470aSBarry Smith     snes->iter = i+1;
655e76c431SBarry Smith 
665e76c431SBarry Smith     /* Solve J Y = -F, where J is Jacobian matrix */
67df60cc22SBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,
68bbb6d6a8SBarry Smith                                &flg); CHKERRQ(ierr);
69a935fc98SLois Curfman McInnes     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,
70a935fc98SLois Curfman McInnes                                flg); CHKERRQ(ierr);
7178b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
7281b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
73761aaf1bSLois Curfman McInnes     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);
74761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
7578b31e54SBarry Smith     CHKERRQ(ierr);
765e76c431SBarry Smith 
7739e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
7839e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
795e76c431SBarry Smith     fnorm = gnorm;
805e76c431SBarry Smith 
815e42470aSBarry Smith     snes->norm = fnorm;
825e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
83393d2d9aSLois Curfman McInnes     ierr = VecNorm(X,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
84bbb6d6a8SBarry Smith     if (snes->monitor)
85393d2d9aSLois Curfman McInnes       {ierr = (*snes->monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);}
865e76c431SBarry Smith 
875e76c431SBarry Smith     /* Test for convergence */
88bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
8939e2f89bSBarry Smith       if (X != snes->vec_sol) {
90393d2d9aSLois Curfman McInnes         ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
9139e2f89bSBarry Smith         snes->vec_sol_always = snes->vec_sol;
9239e2f89bSBarry Smith         snes->vec_func_always = snes->vec_func;
9339e2f89bSBarry Smith       }
945e76c431SBarry Smith       break;
955e76c431SBarry Smith     }
965e76c431SBarry Smith   }
9752392280SLois Curfman McInnes   if (i == maxits) {
9852392280SLois Curfman McInnes     PLogInfo((PetscObject)snes,
994b828684SBarry Smith       "SNESSolve_LS: Maximum number of iterations has been reached: %d\n",
1004b828684SBarry Smith       maxits);
10152392280SLois Curfman McInnes     i--;
10252392280SLois Curfman McInnes   }
1035e42470aSBarry Smith   *outits = i+1;
1045e42470aSBarry Smith   return 0;
1055e76c431SBarry Smith }
1065e76c431SBarry Smith /* ------------------------------------------------------------ */
1075e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
1085e76c431SBarry Smith {
1095e42470aSBarry Smith   int ierr;
11081b6cf68SLois Curfman McInnes   snes->nwork = 4;
11178b31e54SBarry Smith   ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr);
1125e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
11381b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1145e42470aSBarry Smith   return 0;
1155e76c431SBarry Smith }
1165e76c431SBarry Smith /* ------------------------------------------------------------ */
1175e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
1185e76c431SBarry Smith {
1195e42470aSBarry Smith   SNES snes = (SNES) obj;
120393d2d9aSLois Curfman McInnes   int  ierr;
121393d2d9aSLois Curfman McInnes   ierr = VecFreeVecs(snes->work,snes->nwork); CHKERRQ(ierr);
12278b31e54SBarry Smith   PETSCFREE(snes->data);
1235e42470aSBarry Smith   return 0;
1245e76c431SBarry Smith }
1255e76c431SBarry Smith /* ------------------------------------------------------------ */
1265e76c431SBarry Smith /*ARGSUSED*/
1274b828684SBarry Smith /*@C
1285e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1295e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1305e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1315e76c431SBarry Smith 
1325e76c431SBarry Smith    Input Parameters:
1335e42470aSBarry Smith .  snes - nonlinear context
1345e76c431SBarry Smith .  x - current iterate
1355e76c431SBarry Smith .  f - residual evaluated at x
1365e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1375e76c431SBarry Smith .  w - work vector
1385e76c431SBarry Smith .  fnorm - 2-norm of f
1395e76c431SBarry Smith 
140c4a48953SLois Curfman McInnes    Output Parameters:
1415e76c431SBarry Smith .  g - residual evaluated at new iterate y
1425e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1435e76c431SBarry Smith .  gnorm - 2-norm of g
1445e76c431SBarry Smith .  ynorm - 2-norm of search length
145761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1465e76c431SBarry Smith 
147c4a48953SLois Curfman McInnes    Options Database Key:
148c4a48953SLois Curfman McInnes $  -snes_line_search basic
149c4a48953SLois Curfman McInnes 
15028ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
15128ae5a21SLois Curfman McInnes 
152f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
153a935fc98SLois Curfman McInnes           SNESSetLineSearchRoutine()
1545e76c431SBarry Smith @*/
1555e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
156761aaf1bSLois Curfman McInnes               double fnorm, double *ynorm, double *gnorm,int *flag )
1575e76c431SBarry Smith {
1585e42470aSBarry Smith   int    ierr;
1595e42470aSBarry Smith   Scalar one = 1.0;
160761aaf1bSLois Curfman McInnes   *flag = 0;
1617857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
162393d2d9aSLois Curfman McInnes   ierr = VecNorm(y,ynorm); CHKERRQ(ierr);              /* ynorm = || y || */
163393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,y); CHKERRQ(ierr);             /* y <- x + y      */
164393d2d9aSLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* (+/-) F(y)      */
165393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);              /* gnorm = || g || */
1667857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
167761aaf1bSLois Curfman McInnes   return 0;
1685e76c431SBarry Smith }
1695e76c431SBarry Smith /* ------------------------------------------------------------------ */
1704b828684SBarry Smith /*@C
171f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
172f59ffdedSLois Curfman McInnes    is the default line search method.
1735e76c431SBarry Smith 
1745e76c431SBarry Smith    Input Parameters:
1755e42470aSBarry Smith .  snes - nonlinear context
1765e76c431SBarry Smith .  x - current iterate
1775e76c431SBarry Smith .  f - residual evaluated at x
1785e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1795e76c431SBarry Smith .  w - work vector
1805e76c431SBarry Smith .  fnorm - 2-norm of f
1815e76c431SBarry Smith 
182393d2d9aSLois Curfman McInnes    Output Parameters:
1835e76c431SBarry Smith .  g - residual evaluated at new iterate y
1845e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1855e76c431SBarry Smith .  gnorm - 2-norm of g
1865e76c431SBarry Smith .  ynorm - 2-norm of search length
187761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1885e76c431SBarry Smith 
189c4a48953SLois Curfman McInnes    Options Database Key:
190c4a48953SLois Curfman McInnes $  -snes_line_search cubic
191c4a48953SLois Curfman McInnes 
1925e76c431SBarry Smith    Notes:
1935e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1945e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1955e76c431SBarry Smith 
19628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
19728ae5a21SLois Curfman McInnes 
198f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
1995e76c431SBarry Smith @*/
2005e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
201761aaf1bSLois Curfman McInnes                 double fnorm, double *ynorm, double *gnorm,int *flag)
2025e76c431SBarry Smith {
2035e42470aSBarry Smith   double  steptol, initslope;
2045e42470aSBarry Smith   double  lambdaprev, gnormprev;
2055e76c431SBarry Smith   double  a, b, d, t1, t2;
2066b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2075e42470aSBarry Smith   Scalar  cinitslope,clambda;
2086b5873e3SBarry Smith #endif
2095e42470aSBarry Smith   int     ierr, count;
2105e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2115e42470aSBarry Smith   Scalar  one = 1.0,scale;
2125e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
2135e76c431SBarry Smith 
2147857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
215761aaf1bSLois Curfman McInnes   *flag = 0;
2165e76c431SBarry Smith   alpha   = neP->alpha;
2175e76c431SBarry Smith   maxstep = neP->maxstep;
2185e76c431SBarry Smith   steptol = neP->steptol;
2195e76c431SBarry Smith 
220393d2d9aSLois Curfman McInnes   ierr = VecNorm(y,ynorm); CHKERRQ(ierr);
2215e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2225e42470aSBarry Smith     scale = maxstep/(*ynorm);
2236b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2244b828684SBarry Smith     PLogInfo((PetscObject)snes,
2254b828684SBarry Smith                     "SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2266b5873e3SBarry Smith #else
2274b828684SBarry Smith     PLogInfo((PetscObject)snes,
2284b828684SBarry Smith                     "SNESCubicLineSearch: Scaling step by %g\n",scale);
2296b5873e3SBarry Smith #endif
230393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2315e76c431SBarry Smith     *ynorm = maxstep;
2325e76c431SBarry Smith   }
2335e76c431SBarry Smith   minlambda = steptol/(*ynorm);
2345e42470aSBarry Smith #if defined(PETSC_COMPLEX)
235393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr);
2365e42470aSBarry Smith   initslope = real(cinitslope);
2375e42470aSBarry Smith #else
238393d2d9aSLois Curfman McInnes   VecDot(f,y,&initslope); CHKERRQ(ierr);
2395e42470aSBarry Smith #endif
2405e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2415e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2425e76c431SBarry Smith 
243393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
244393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,w); CHKERRQ(ierr);
24578b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
246393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm);
2475e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
248393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2494b828684SBarry Smith     PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Using full step\n");
250d93a2b8dSBarry Smith     goto theend;
2515e76c431SBarry Smith   }
2525e76c431SBarry Smith 
2535e76c431SBarry Smith   /* Fit points with quadratic */
2545e76c431SBarry Smith   lambda = 1.0; count = 0;
2555e76c431SBarry Smith   lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
2565e76c431SBarry Smith   lambdaprev = lambda;
2575e76c431SBarry Smith   gnormprev = *gnorm;
2585e76c431SBarry Smith   if (lambdatemp <= .1*lambda) {
2595e76c431SBarry Smith     lambda = .1*lambda;
2605e76c431SBarry Smith   } else lambda = lambdatemp;
261393d2d9aSLois Curfman McInnes   ierr = VecCopy(x,w); CHKERRQ(ierr);
2625e42470aSBarry Smith #if defined(PETSC_COMPLEX)
263393d2d9aSLois Curfman McInnes   clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2645e42470aSBarry Smith #else
265393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2665e42470aSBarry Smith #endif
26778b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
268393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
2695e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
270393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2714b828684SBarry Smith     PLogInfo((PetscObject)snes,
2724b828684SBarry Smith     "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda);
273d93a2b8dSBarry Smith     goto theend;
2745e76c431SBarry Smith   }
2755e76c431SBarry Smith 
2765e76c431SBarry Smith   /* Fit points with cubic */
2775e76c431SBarry Smith   count = 1;
2785e76c431SBarry Smith   while (1) {
2795e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
2804b828684SBarry Smith       PLogInfo((PetscObject)snes,
2814b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
2824b828684SBarry Smith       PLogInfo((PetscObject)snes,
2834b828684SBarry Smith          "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g \n",
2845e76c431SBarry Smith               fnorm,*gnorm, *ynorm,lambda);
285393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
286761aaf1bSLois Curfman McInnes       *flag = -1; break;
2875e76c431SBarry Smith     }
2885e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2895e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
2905e76c431SBarry Smith     a = (t1/(lambda*lambda) -
2915e76c431SBarry Smith               t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2925e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2935e76c431SBarry Smith               lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2945e76c431SBarry Smith     d = b*b - 3*a*initslope;
2955e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2965e76c431SBarry Smith     if (a == 0.0) {
2975e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2985e76c431SBarry Smith     } else {
2995e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
3005e76c431SBarry Smith     }
3015e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
3025e76c431SBarry Smith       lambdatemp = .5*lambda;
3035e76c431SBarry Smith     }
3045e76c431SBarry Smith     lambdaprev = lambda;
3055e76c431SBarry Smith     gnormprev = *gnorm;
3065e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
3075e76c431SBarry Smith       lambda = .1*lambda;
3085e76c431SBarry Smith     }
3095e76c431SBarry Smith     else lambda = lambdatemp;
310393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
3115e42470aSBarry Smith #if defined(PETSC_COMPLEX)
312393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3135e42470aSBarry Smith #else
314393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
3155e42470aSBarry Smith #endif
31678b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
317393d2d9aSLois Curfman McInnes     ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
3185e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
319393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
3204b828684SBarry Smith       PLogInfo((PetscObject)snes,
3214b828684SBarry Smith         "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda);
322761aaf1bSLois Curfman McInnes       *flag = -1; break;
3235e76c431SBarry Smith     }
3245e76c431SBarry Smith     count++;
3255e76c431SBarry Smith   }
326d93a2b8dSBarry Smith   theend:
3277857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3285e42470aSBarry Smith   return 0;
3295e76c431SBarry Smith }
33052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3314b828684SBarry Smith /*@C
3325e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3335e76c431SBarry Smith 
3345e42470aSBarry Smith    Input Parameters:
335f59ffdedSLois Curfman McInnes .  snes - the SNES context
3365e42470aSBarry Smith .  x - current iterate
3375e42470aSBarry Smith .  f - residual evaluated at x
3385e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3395e42470aSBarry Smith .  w - work vector
3405e42470aSBarry Smith .  fnorm - 2-norm of f
3415e42470aSBarry Smith 
342c4a48953SLois Curfman McInnes    Output Parameters:
3435e42470aSBarry Smith .  g - residual evaluated at new iterate y
3445e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3455e42470aSBarry Smith .  gnorm - 2-norm of g
3465e42470aSBarry Smith .  ynorm - 2-norm of search length
347761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3485e42470aSBarry Smith 
349c4a48953SLois Curfman McInnes    Options Database Key:
350c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
351c4a48953SLois Curfman McInnes 
3525e42470aSBarry Smith    Notes:
353f59ffdedSLois Curfman McInnes    Use SNESSetLineSearchRoutine()
354f59ffdedSLois Curfman McInnes    to set this routine within the SNES_NLS method.
3555e42470aSBarry Smith 
356f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
357f59ffdedSLois Curfman McInnes 
358f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
3595e42470aSBarry Smith @*/
3605e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
361761aaf1bSLois Curfman McInnes                     double fnorm, double *ynorm, double *gnorm,int *flag)
3625e76c431SBarry Smith {
3635e42470aSBarry Smith   double  steptol, initslope;
3645e42470aSBarry Smith   double  lambdaprev, gnormprev;
3656b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3665e42470aSBarry Smith   Scalar  cinitslope,clambda;
3676b5873e3SBarry Smith #endif
3685e42470aSBarry Smith   int     ierr,count;
3695e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3705e42470aSBarry Smith   Scalar  one = 1.0,scale;
3715e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
3725e76c431SBarry Smith 
3737857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
374761aaf1bSLois Curfman McInnes   *flag = 0;
3755e42470aSBarry Smith   alpha   = neP->alpha;
3765e42470aSBarry Smith   maxstep = neP->maxstep;
3775e42470aSBarry Smith   steptol = neP->steptol;
3785e76c431SBarry Smith 
3795e42470aSBarry Smith   VecNorm(y, ynorm );
3805e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3815e42470aSBarry Smith     scale = maxstep/(*ynorm);
382393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3835e42470aSBarry Smith     *ynorm = maxstep;
3845e76c431SBarry Smith   }
3855e42470aSBarry Smith   minlambda = steptol/(*ynorm);
3865e42470aSBarry Smith #if defined(PETSC_COMPLEX)
387393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr);
3885e42470aSBarry Smith   initslope = real(cinitslope);
3895e42470aSBarry Smith #else
390393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&initslope); CHKERRQ(ierr);
3915e42470aSBarry Smith #endif
3925e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3935e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3945e42470aSBarry Smith 
395393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
396393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,w); CHKERRQ(ierr);
39778b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
398393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
3995e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
400393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
4014b828684SBarry Smith     PLogInfo((PetscObject)snes,"SNESQuadraticLineSearch: Using full step\n");
402d93a2b8dSBarry Smith     goto theend;
4035e42470aSBarry Smith   }
4045e42470aSBarry Smith 
4055e42470aSBarry Smith   /* Fit points with quadratic */
4065e42470aSBarry Smith   lambda = 1.0; count = 0;
4075e42470aSBarry Smith   count = 1;
4085e42470aSBarry Smith   while (1) {
4095e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
4104b828684SBarry Smith       PLogInfo((PetscObject)snes,
4114b828684SBarry Smith        "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
4124b828684SBarry Smith       PLogInfo((PetscObject)snes,
4134b828684SBarry Smith         "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g \n",
4145e42470aSBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
415393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
416761aaf1bSLois Curfman McInnes       *flag = -1; break;
4175e42470aSBarry Smith     }
4185e42470aSBarry Smith     lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
4195e42470aSBarry Smith     lambdaprev = lambda;
4205e42470aSBarry Smith     gnormprev = *gnorm;
4215e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4225e42470aSBarry Smith       lambda = .1*lambda;
4235e42470aSBarry Smith     } else lambda = lambdatemp;
424393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4255e42470aSBarry Smith #if defined(PETSC_COMPLEX)
426393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4275e42470aSBarry Smith #else
428393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4295e42470aSBarry Smith #endif
43078b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
431393d2d9aSLois Curfman McInnes     ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
4325e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
433393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
4344b828684SBarry Smith       PLogInfo((PetscObject)snes,
4354b828684SBarry Smith         "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n",
4364b828684SBarry Smith         lambda);
43706259719SBarry Smith       break;
4385e42470aSBarry Smith     }
4395e42470aSBarry Smith     count++;
4405e42470aSBarry Smith   }
441d93a2b8dSBarry Smith   theend:
4427857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4435e42470aSBarry Smith   return 0;
4445e76c431SBarry Smith }
4455e76c431SBarry Smith /* ------------------------------------------------------------ */
446b1f0a012SBarry Smith /*@
4475e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
448fbe28522SBarry Smith    by the method SNES_LS.
4495e76c431SBarry Smith 
4505e76c431SBarry Smith    Input Parameters:
451eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4525e76c431SBarry Smith .  func - pointer to int function
4535e76c431SBarry Smith 
454c4a48953SLois Curfman McInnes    Available Routines:
455f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
456f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
457f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4585e76c431SBarry Smith 
459c4a48953SLois Curfman McInnes     Options Database Keys:
460c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
461c4a48953SLois Curfman McInnes 
4625e76c431SBarry Smith    Calling sequence of func:
463f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
464761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
465761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4665e76c431SBarry Smith 
4675e76c431SBarry Smith     Input parameters for func:
4685e42470aSBarry Smith .   snes - nonlinear context
4695e76c431SBarry Smith .   x - current iterate
4705e76c431SBarry Smith .   f - residual evaluated at x
4715e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4725e76c431SBarry Smith .   w - work vector
4735e76c431SBarry Smith .   fnorm - 2-norm of f
4745e76c431SBarry Smith 
4755e76c431SBarry Smith     Output parameters for func:
4765e76c431SBarry Smith .   g - residual evaluated at new iterate y
4775e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4785e76c431SBarry Smith .   gnorm - 2-norm of g
4795e76c431SBarry Smith .   ynorm - 2-norm of search length
480761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
481761aaf1bSLois Curfman McInnes            on failure.
482f59ffdedSLois Curfman McInnes 
483f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
484f59ffdedSLois Curfman McInnes 
485f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4865e76c431SBarry Smith @*/
4875e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
488761aaf1bSLois Curfman McInnes                              double,double *,double*,int*) )
4895e76c431SBarry Smith {
490fbe28522SBarry Smith   if ((snes)->type == SNES_NLS)
4915e42470aSBarry Smith     ((SNES_LS *)(snes->data))->LineSearch = func;
4925e42470aSBarry Smith   return 0;
4935e76c431SBarry Smith }
49452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
4955e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes)
4965e42470aSBarry Smith {
4975e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
49852392280SLois Curfman McInnes   char    *p;
49952392280SLois Curfman McInnes   if (snes->prefix) p = snes->prefix; else p = "-";
50052392280SLois Curfman McInnes   MPIU_printf(snes->comm," method ls (system of nonlinear equations):\n");
50152392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search [basic,quadratic,cubic]\n",p);
50252392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_alpha alpha (default %g)\n",p,ls->alpha);
50352392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_maxstep max (default %g)\n",p,ls->maxstep);
50452392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_steptol tol (default %g)\n",p,ls->steptol);
5056b5873e3SBarry Smith   return 0;
5065e42470aSBarry Smith }
50752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
508a935fc98SLois Curfman McInnes static int SNESView_LS(PetscObject obj,Viewer viewer)
509a935fc98SLois Curfman McInnes {
510a935fc98SLois Curfman McInnes   SNES    snes = (SNES)obj;
511a935fc98SLois Curfman McInnes   SNES_LS *ls = (SNES_LS *)snes->data;
512d636dbe3SBarry Smith   FILE    *fd;
513a935fc98SLois Curfman McInnes   char    *cstring;
51451695f54SLois Curfman McInnes   int     ierr;
515a935fc98SLois Curfman McInnes 
516a447f0b5SLois Curfman McInnes   ierr = ViewerFileGetPointer_Private(viewer,&fd); CHKERRQ(ierr);
517a935fc98SLois Curfman McInnes   if (ls->LineSearch == SNESNoLineSearch)
518a935fc98SLois Curfman McInnes     cstring = "SNESNoLineSearch";
519a935fc98SLois Curfman McInnes   else if (ls->LineSearch == SNESQuadraticLineSearch)
520a935fc98SLois Curfman McInnes     cstring = "SNESQuadraticLineSearch";
521a935fc98SLois Curfman McInnes   else if (ls->LineSearch == SNESCubicLineSearch)
522a935fc98SLois Curfman McInnes     cstring = "SNESCubicLineSearch";
523a935fc98SLois Curfman McInnes   else
524a935fc98SLois Curfman McInnes     cstring = "unknown";
525a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    line search variant: %s\n",cstring);
526a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
527a935fc98SLois Curfman McInnes      ls->alpha,ls->maxstep,ls->steptol);
528a935fc98SLois Curfman McInnes   return 0;
529a935fc98SLois Curfman McInnes }
53052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5315e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5325e42470aSBarry Smith {
5335e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5345e42470aSBarry Smith   char    ver[16];
5355e42470aSBarry Smith   double  tmp;
5365e42470aSBarry Smith 
537df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) {
5385e42470aSBarry Smith     ls->alpha = tmp;
5395e42470aSBarry Smith   }
540df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) {
5415e42470aSBarry Smith     ls->maxstep = tmp;
5425e42470aSBarry Smith   }
543df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) {
5445e42470aSBarry Smith     ls->steptol = tmp;
5455e42470aSBarry Smith   }
546df60cc22SBarry Smith   if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) {
547*48d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
5485e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5495e42470aSBarry Smith     }
550*48d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
5515e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5525e42470aSBarry Smith     }
553*48d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
5545e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5555e42470aSBarry Smith     }
5568c48e012SBarry Smith     else {SETERRQ(1,"SNESSetFromOptions_LS:Unknown line search");}
5575e42470aSBarry Smith   }
5585e42470aSBarry Smith   return 0;
5595e42470aSBarry Smith }
5605e42470aSBarry Smith /* ------------------------------------------------------------ */
5615e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
5625e42470aSBarry Smith {
5635e42470aSBarry Smith   SNES_LS *neP;
5645e42470aSBarry Smith 
5651a3481a4SLois Curfman McInnes   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1,
566*48d91487SBarry Smith     "SNESCreate_LS:For SNES_NONLINEAR_EQUATIONS only");
56725c7317fSLois Curfman McInnes   snes->type		= SNES_EQ_NLS;
56849e3953dSBarry Smith   snes->setup		= SNESSetUp_LS;
56949e3953dSBarry Smith   snes->solve		= SNESSolve_LS;
5705e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
571bbb6d6a8SBarry Smith   snes->converged	= SNESDefaultConverged;
57249e3953dSBarry Smith   snes->printhelp       = SNESPrintHelp_LS;
57349e3953dSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_LS;
574a935fc98SLois Curfman McInnes   snes->view            = SNESView_LS;
5755e42470aSBarry Smith 
57678b31e54SBarry Smith   neP			= PETSCNEW(SNES_LS);   CHKPTRQ(neP);
577ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5785e42470aSBarry Smith   snes->data    	= (void *) neP;
5795e42470aSBarry Smith   neP->alpha		= 1.e-4;
5805e42470aSBarry Smith   neP->maxstep		= 1.e8;
5815e42470aSBarry Smith   neP->steptol		= 1.e-12;
5825e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5835e42470aSBarry Smith   return 0;
5845e42470aSBarry Smith }
5855e42470aSBarry Smith 
5865e42470aSBarry Smith 
5875e42470aSBarry Smith 
5885e42470aSBarry Smith 
589