xref: /petsc/src/snes/impls/ls/ls.c (revision 393d2d9aa70a88d301b604b657c8529b0d46deef)
15e76c431SBarry Smith #ifndef lint
2*393d2d9aSLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.36 1995/07/29 04:29:53 curfman Exp curfman $";
35e76c431SBarry Smith #endif
45e76c431SBarry Smith 
55e76c431SBarry Smith #include <math.h>
6fbe28522SBarry Smith #include "ls.h"
7a935fc98SLois Curfman McInnes #include "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
27*393d2d9aSLois 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        */
50*393d2d9aSLois Curfman McInnes   ierr = VecNorm(X,&xnorm); CHKERRQ(ierr);               /* xnorm = || X || */
5178b31e54SBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);   /* (+/-) F(X)      */
52*393d2d9aSLois 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 
58*393d2d9aSLois 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;
86*393d2d9aSLois Curfman McInnes     ierr = VecNorm(X,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
87bbb6d6a8SBarry Smith     if (snes->monitor)
88*393d2d9aSLois 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) {
93*393d2d9aSLois 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,
10252392280SLois Curfman McInnes       "Maximum number of iterations has been reached: %d\n",maxits);
10352392280SLois Curfman McInnes     i--;
10452392280SLois Curfman McInnes   }
1055e42470aSBarry Smith   *outits = i+1;
1065e42470aSBarry Smith   return 0;
1075e76c431SBarry Smith }
1085e76c431SBarry Smith /* ------------------------------------------------------------ */
1095e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
1105e76c431SBarry Smith {
1115e42470aSBarry Smith   int ierr;
11281b6cf68SLois Curfman McInnes   snes->nwork = 4;
11378b31e54SBarry Smith   ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr);
1145e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
11581b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
1165e42470aSBarry Smith   return 0;
1175e76c431SBarry Smith }
1185e76c431SBarry Smith /* ------------------------------------------------------------ */
1195e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
1205e76c431SBarry Smith {
1215e42470aSBarry Smith   SNES snes = (SNES) obj;
122*393d2d9aSLois Curfman McInnes   int  ierr;
123*393d2d9aSLois Curfman McInnes   ierr = VecFreeVecs(snes->work,snes->nwork); CHKERRQ(ierr);
12478b31e54SBarry Smith   PETSCFREE(snes->data);
1255e42470aSBarry Smith   return 0;
1265e76c431SBarry Smith }
1275e76c431SBarry Smith /* ------------------------------------------------------------ */
1285e76c431SBarry Smith /*ARGSUSED*/
1295e76c431SBarry Smith /*@
1305e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1315e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1325e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1335e76c431SBarry Smith 
1345e76c431SBarry Smith    Input Parameters:
1355e42470aSBarry Smith .  snes - nonlinear context
1365e76c431SBarry Smith .  x - current iterate
1375e76c431SBarry Smith .  f - residual evaluated at x
1385e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1395e76c431SBarry Smith .  w - work vector
1405e76c431SBarry Smith .  fnorm - 2-norm of f
1415e76c431SBarry Smith 
142c4a48953SLois Curfman McInnes    Output Parameters:
1435e76c431SBarry Smith .  g - residual evaluated at new iterate y
1445e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1455e76c431SBarry Smith .  gnorm - 2-norm of g
1465e76c431SBarry Smith .  ynorm - 2-norm of search length
147761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1485e76c431SBarry Smith 
149c4a48953SLois Curfman McInnes    Options Database Key:
150c4a48953SLois Curfman McInnes $  -snes_line_search basic
151c4a48953SLois Curfman McInnes 
15228ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
15328ae5a21SLois Curfman McInnes 
154f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
155a935fc98SLois Curfman McInnes           SNESSetLineSearchRoutine()
1565e76c431SBarry Smith @*/
1575e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
158761aaf1bSLois Curfman McInnes               double fnorm, double *ynorm, double *gnorm,int *flag )
1595e76c431SBarry Smith {
1605e42470aSBarry Smith   int    ierr;
1615e42470aSBarry Smith   Scalar one = 1.0;
162761aaf1bSLois Curfman McInnes   *flag = 0;
1637857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
164*393d2d9aSLois Curfman McInnes   ierr = VecNorm(y,ynorm); CHKERRQ(ierr);              /* ynorm = || y || */
165*393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,y); CHKERRQ(ierr);             /* y <- x + y      */
166*393d2d9aSLois Curfman McInnes   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* (+/-) F(y)      */
167*393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);              /* gnorm = || g || */
1687857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
169761aaf1bSLois Curfman McInnes   return 0;
1705e76c431SBarry Smith }
1715e76c431SBarry Smith /* ------------------------------------------------------------------ */
1725e76c431SBarry Smith /*@
173f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
174f59ffdedSLois Curfman McInnes    is the default line search method.
1755e76c431SBarry Smith 
1765e76c431SBarry Smith    Input Parameters:
1775e42470aSBarry Smith .  snes - nonlinear context
1785e76c431SBarry Smith .  x - current iterate
1795e76c431SBarry Smith .  f - residual evaluated at x
1805e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1815e76c431SBarry Smith .  w - work vector
1825e76c431SBarry Smith .  fnorm - 2-norm of f
1835e76c431SBarry Smith 
184*393d2d9aSLois Curfman McInnes    Output Parameters:
1855e76c431SBarry Smith .  g - residual evaluated at new iterate y
1865e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1875e76c431SBarry Smith .  gnorm - 2-norm of g
1885e76c431SBarry Smith .  ynorm - 2-norm of search length
189761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1905e76c431SBarry Smith 
191c4a48953SLois Curfman McInnes    Options Database Key:
192c4a48953SLois Curfman McInnes $  -snes_line_search cubic
193c4a48953SLois Curfman McInnes 
1945e76c431SBarry Smith    Notes:
1955e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1965e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1975e76c431SBarry Smith 
19828ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
19928ae5a21SLois Curfman McInnes 
200f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
2015e76c431SBarry Smith @*/
2025e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
203761aaf1bSLois Curfman McInnes                 double fnorm, double *ynorm, double *gnorm,int *flag)
2045e76c431SBarry Smith {
2055e42470aSBarry Smith   double  steptol, initslope;
2065e42470aSBarry Smith   double  lambdaprev, gnormprev;
2075e76c431SBarry Smith   double  a, b, d, t1, t2;
2086b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2095e42470aSBarry Smith   Scalar  cinitslope,clambda;
2106b5873e3SBarry Smith #endif
2115e42470aSBarry Smith   int     ierr, count;
2125e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
2135e42470aSBarry Smith   Scalar  one = 1.0,scale;
2145e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
2155e76c431SBarry Smith 
2167857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
217761aaf1bSLois Curfman McInnes   *flag = 0;
2185e76c431SBarry Smith   alpha   = neP->alpha;
2195e76c431SBarry Smith   maxstep = neP->maxstep;
2205e76c431SBarry Smith   steptol = neP->steptol;
2215e76c431SBarry Smith 
222*393d2d9aSLois Curfman McInnes   ierr = VecNorm(y,ynorm); CHKERRQ(ierr);
2235e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2245e42470aSBarry Smith     scale = maxstep/(*ynorm);
2256b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
2266b5873e3SBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",real(scale));
2276b5873e3SBarry Smith #else
2285e42470aSBarry Smith     PLogInfo((PetscObject)snes,"Scaling step by %g\n",scale);
2296b5873e3SBarry Smith #endif
230*393d2d9aSLois 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)
235*393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr);
2365e42470aSBarry Smith   initslope = real(cinitslope);
2375e42470aSBarry Smith #else
238*393d2d9aSLois 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 
243*393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
244*393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,w); CHKERRQ(ierr);
24578b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
246*393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm);
2475e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
248*393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2495e42470aSBarry Smith     PLogInfo((PetscObject)snes,"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;
261*393d2d9aSLois Curfman McInnes   ierr = VecCopy(x,w); CHKERRQ(ierr);
2625e42470aSBarry Smith #if defined(PETSC_COMPLEX)
263*393d2d9aSLois Curfman McInnes   clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2645e42470aSBarry Smith #else
265*393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2665e42470aSBarry Smith #endif
26778b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
268*393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
2695e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
270*393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2715e42470aSBarry Smith     PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
272d93a2b8dSBarry Smith     goto theend;
2735e76c431SBarry Smith   }
2745e76c431SBarry Smith 
2755e76c431SBarry Smith   /* Fit points with cubic */
2765e76c431SBarry Smith   count = 1;
2775e76c431SBarry Smith   while (1) {
2785e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
2795e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
2805e42470aSBarry Smith       PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
2815e76c431SBarry Smith               fnorm,*gnorm, *ynorm,lambda);
282*393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
283761aaf1bSLois Curfman McInnes       *flag = -1; break;
2845e76c431SBarry Smith     }
2855e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2865e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
2875e76c431SBarry Smith     a = (t1/(lambda*lambda) -
2885e76c431SBarry Smith               t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2895e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2905e76c431SBarry Smith               lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2915e76c431SBarry Smith     d = b*b - 3*a*initslope;
2925e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2935e76c431SBarry Smith     if (a == 0.0) {
2945e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2955e76c431SBarry Smith     } else {
2965e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
2975e76c431SBarry Smith     }
2985e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
2995e76c431SBarry Smith       lambdatemp = .5*lambda;
3005e76c431SBarry Smith     }
3015e76c431SBarry Smith     lambdaprev = lambda;
3025e76c431SBarry Smith     gnormprev = *gnorm;
3035e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
3045e76c431SBarry Smith       lambda = .1*lambda;
3055e76c431SBarry Smith     }
3065e76c431SBarry Smith     else lambda = lambdatemp;
307*393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
3085e42470aSBarry Smith #if defined(PETSC_COMPLEX)
309*393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
3105e42470aSBarry Smith #else
311*393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
3125e42470aSBarry Smith #endif
31378b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
314*393d2d9aSLois Curfman McInnes     ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
3155e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
316*393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
3175e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Cubically determined step, lambda %g\n",lambda);
318761aaf1bSLois Curfman McInnes       *flag = -1; break;
3195e76c431SBarry Smith     }
3205e76c431SBarry Smith     count++;
3215e76c431SBarry Smith   }
322d93a2b8dSBarry Smith   theend:
3237857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3245e42470aSBarry Smith   return 0;
3255e76c431SBarry Smith }
32652392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3275e42470aSBarry Smith /*@
3285e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3295e76c431SBarry Smith 
3305e42470aSBarry Smith    Input Parameters:
331f59ffdedSLois Curfman McInnes .  snes - the SNES context
3325e42470aSBarry Smith .  x - current iterate
3335e42470aSBarry Smith .  f - residual evaluated at x
3345e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3355e42470aSBarry Smith .  w - work vector
3365e42470aSBarry Smith .  fnorm - 2-norm of f
3375e42470aSBarry Smith 
338c4a48953SLois Curfman McInnes    Output Parameters:
3395e42470aSBarry Smith .  g - residual evaluated at new iterate y
3405e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3415e42470aSBarry Smith .  gnorm - 2-norm of g
3425e42470aSBarry Smith .  ynorm - 2-norm of search length
343761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3445e42470aSBarry Smith 
345c4a48953SLois Curfman McInnes    Options Database Key:
346c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
347c4a48953SLois Curfman McInnes 
3485e42470aSBarry Smith    Notes:
349f59ffdedSLois Curfman McInnes    Use SNESSetLineSearchRoutine()
350f59ffdedSLois Curfman McInnes    to set this routine within the SNES_NLS method.
3515e42470aSBarry Smith 
352f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
353f59ffdedSLois Curfman McInnes 
354f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
3555e42470aSBarry Smith @*/
3565e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
357761aaf1bSLois Curfman McInnes                     double fnorm, double *ynorm, double *gnorm,int *flag)
3585e76c431SBarry Smith {
3595e42470aSBarry Smith   double  steptol, initslope;
3605e42470aSBarry Smith   double  lambdaprev, gnormprev;
3616b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3625e42470aSBarry Smith   Scalar  cinitslope,clambda;
3636b5873e3SBarry Smith #endif
3645e42470aSBarry Smith   int     ierr,count;
3655e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3665e42470aSBarry Smith   Scalar  one = 1.0,scale;
3675e42470aSBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
3685e76c431SBarry Smith 
3697857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
370761aaf1bSLois Curfman McInnes   *flag = 0;
3715e42470aSBarry Smith   alpha   = neP->alpha;
3725e42470aSBarry Smith   maxstep = neP->maxstep;
3735e42470aSBarry Smith   steptol = neP->steptol;
3745e76c431SBarry Smith 
3755e42470aSBarry Smith   VecNorm(y, ynorm );
3765e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3775e42470aSBarry Smith     scale = maxstep/(*ynorm);
378*393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3795e42470aSBarry Smith     *ynorm = maxstep;
3805e76c431SBarry Smith   }
3815e42470aSBarry Smith   minlambda = steptol/(*ynorm);
3825e42470aSBarry Smith #if defined(PETSC_COMPLEX)
383*393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr);
3845e42470aSBarry Smith   initslope = real(cinitslope);
3855e42470aSBarry Smith #else
386*393d2d9aSLois Curfman McInnes   ierr = VecDot(f,y,&initslope); CHKERRQ(ierr);
3875e42470aSBarry Smith #endif
3885e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3895e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3905e42470aSBarry Smith 
391*393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
392*393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&one,x,w); CHKERRQ(ierr);
39378b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
394*393d2d9aSLois Curfman McInnes   ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
3955e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
396*393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
3975e42470aSBarry Smith     PLogInfo((PetscObject)snes,"Using full step\n");
398d93a2b8dSBarry Smith     goto theend;
3995e42470aSBarry Smith   }
4005e42470aSBarry Smith 
4015e42470aSBarry Smith   /* Fit points with quadratic */
4025e42470aSBarry Smith   lambda = 1.0; count = 0;
4035e42470aSBarry Smith   count = 1;
4045e42470aSBarry Smith   while (1) {
4055e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
4065e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
4075e42470aSBarry Smith       PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
4085e42470aSBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
409*393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
410761aaf1bSLois Curfman McInnes       *flag = -1; break;
4115e42470aSBarry Smith     }
4125e42470aSBarry Smith     lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
4135e42470aSBarry Smith     lambdaprev = lambda;
4145e42470aSBarry Smith     gnormprev = *gnorm;
4155e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4165e42470aSBarry Smith       lambda = .1*lambda;
4175e42470aSBarry Smith     } else lambda = lambdatemp;
418*393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4195e42470aSBarry Smith #if defined(PETSC_COMPLEX)
420*393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4215e42470aSBarry Smith #else
422*393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4235e42470aSBarry Smith #endif
42478b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
425*393d2d9aSLois Curfman McInnes     ierr = VecNorm(g,gnorm); CHKERRQ(ierr);
4265e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
427*393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
4285e42470aSBarry Smith       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
42906259719SBarry Smith       break;
4305e42470aSBarry Smith     }
4315e42470aSBarry Smith     count++;
4325e42470aSBarry Smith   }
433d93a2b8dSBarry Smith   theend:
4347857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4355e42470aSBarry Smith   return 0;
4365e76c431SBarry Smith }
4375e76c431SBarry Smith /* ------------------------------------------------------------ */
438b1f0a012SBarry Smith /*@
4395e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
440fbe28522SBarry Smith    by the method SNES_LS.
4415e76c431SBarry Smith 
4425e76c431SBarry Smith    Input Parameters:
443eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4445e76c431SBarry Smith .  func - pointer to int function
4455e76c431SBarry Smith 
446c4a48953SLois Curfman McInnes    Available Routines:
447f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
448f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
449f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4505e76c431SBarry Smith 
451c4a48953SLois Curfman McInnes     Options Database Keys:
452c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
453c4a48953SLois Curfman McInnes 
4545e76c431SBarry Smith    Calling sequence of func:
455f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
456761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
457761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4585e76c431SBarry Smith 
4595e76c431SBarry Smith     Input parameters for func:
4605e42470aSBarry Smith .   snes - nonlinear context
4615e76c431SBarry Smith .   x - current iterate
4625e76c431SBarry Smith .   f - residual evaluated at x
4635e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4645e76c431SBarry Smith .   w - work vector
4655e76c431SBarry Smith .   fnorm - 2-norm of f
4665e76c431SBarry Smith 
4675e76c431SBarry Smith     Output parameters for func:
4685e76c431SBarry Smith .   g - residual evaluated at new iterate y
4695e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4705e76c431SBarry Smith .   gnorm - 2-norm of g
4715e76c431SBarry Smith .   ynorm - 2-norm of search length
472761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
473761aaf1bSLois Curfman McInnes            on failure.
474f59ffdedSLois Curfman McInnes 
475f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
476f59ffdedSLois Curfman McInnes 
477f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4785e76c431SBarry Smith @*/
4795e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
480761aaf1bSLois Curfman McInnes                              double,double *,double*,int*) )
4815e76c431SBarry Smith {
482fbe28522SBarry Smith   if ((snes)->type == SNES_NLS)
4835e42470aSBarry Smith     ((SNES_LS *)(snes->data))->LineSearch = func;
4845e42470aSBarry Smith   return 0;
4855e76c431SBarry Smith }
48652392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
4875e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes)
4885e42470aSBarry Smith {
4895e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
49052392280SLois Curfman McInnes   char    *p;
49152392280SLois Curfman McInnes   if (snes->prefix) p = snes->prefix; else p = "-";
49252392280SLois Curfman McInnes   MPIU_printf(snes->comm," method ls (system of nonlinear equations):\n");
49352392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search [basic,quadratic,cubic]\n",p);
49452392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_alpha alpha (default %g)\n",p,ls->alpha);
49552392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_maxstep max (default %g)\n",p,ls->maxstep);
49652392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_steptol tol (default %g)\n",p,ls->steptol);
4976b5873e3SBarry Smith   return 0;
4985e42470aSBarry Smith }
49952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
500a935fc98SLois Curfman McInnes static int SNESView_LS(PetscObject obj,Viewer viewer)
501a935fc98SLois Curfman McInnes {
502a935fc98SLois Curfman McInnes   SNES    snes = (SNES)obj;
503a935fc98SLois Curfman McInnes   SNES_LS *ls = (SNES_LS *)snes->data;
504a935fc98SLois Curfman McInnes   FILE    *fd = ViewerFileGetPointer_Private(viewer);
505a935fc98SLois Curfman McInnes   char    *cstring;
506a935fc98SLois Curfman McInnes 
507a935fc98SLois Curfman McInnes   if (ls->LineSearch == SNESNoLineSearch)
508a935fc98SLois Curfman McInnes     cstring = "SNESNoLineSearch";
509a935fc98SLois Curfman McInnes   else if (ls->LineSearch == SNESQuadraticLineSearch)
510a935fc98SLois Curfman McInnes     cstring = "SNESQuadraticLineSearch";
511a935fc98SLois Curfman McInnes   else if (ls->LineSearch == SNESCubicLineSearch)
512a935fc98SLois Curfman McInnes     cstring = "SNESCubicLineSearch";
513a935fc98SLois Curfman McInnes   else
514a935fc98SLois Curfman McInnes     cstring = "unknown";
515a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    line search variant: %s\n",cstring);
516a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
517a935fc98SLois Curfman McInnes      ls->alpha,ls->maxstep,ls->steptol);
518a935fc98SLois Curfman McInnes   return 0;
519a935fc98SLois Curfman McInnes }
52052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5215e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5225e42470aSBarry Smith {
5235e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5245e42470aSBarry Smith   char    ver[16];
5255e42470aSBarry Smith   double  tmp;
5265e42470aSBarry Smith 
527df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) {
5285e42470aSBarry Smith     ls->alpha = tmp;
5295e42470aSBarry Smith   }
530df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) {
5315e42470aSBarry Smith     ls->maxstep = tmp;
5325e42470aSBarry Smith   }
533df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) {
5345e42470aSBarry Smith     ls->steptol = tmp;
5355e42470aSBarry Smith   }
536df60cc22SBarry Smith   if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) {
5375e42470aSBarry Smith     if (!strcmp(ver,"basic")) {
5385e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5395e42470aSBarry Smith     }
5405e42470aSBarry Smith     else if (!strcmp(ver,"quadratic")) {
5415e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5425e42470aSBarry Smith     }
5435e42470aSBarry Smith     else if (!strcmp(ver,"cubic")) {
5445e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5455e42470aSBarry Smith     }
5468c48e012SBarry Smith     else {SETERRQ(1,"SNESSetFromOptions_LS: Unknown line search");}
5475e42470aSBarry Smith   }
5485e42470aSBarry Smith   return 0;
5495e42470aSBarry Smith }
5505e42470aSBarry Smith /* ------------------------------------------------------------ */
5515e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
5525e42470aSBarry Smith {
5535e42470aSBarry Smith   SNES_LS *neP;
5545e42470aSBarry Smith 
5551a3481a4SLois Curfman McInnes   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1,
5561a3481a4SLois Curfman McInnes     "SNESCreate_LS: Valid for SNES_NONLINEAR_EQUATIONS problems only");
55725c7317fSLois Curfman McInnes   snes->type		= SNES_EQ_NLS;
55849e3953dSBarry Smith   snes->setup		= SNESSetUp_LS;
55949e3953dSBarry Smith   snes->solve		= SNESSolve_LS;
5605e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
561bbb6d6a8SBarry Smith   snes->converged	= SNESDefaultConverged;
56249e3953dSBarry Smith   snes->printhelp       = SNESPrintHelp_LS;
56349e3953dSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_LS;
564a935fc98SLois Curfman McInnes   snes->view            = SNESView_LS;
5655e42470aSBarry Smith 
56678b31e54SBarry Smith   neP			= PETSCNEW(SNES_LS);   CHKPTRQ(neP);
5675e42470aSBarry Smith   snes->data    	= (void *) neP;
5685e42470aSBarry Smith   neP->alpha		= 1.e-4;
5695e42470aSBarry Smith   neP->maxstep		= 1.e8;
5705e42470aSBarry Smith   neP->steptol		= 1.e-12;
5715e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5725e42470aSBarry Smith   return 0;
5735e42470aSBarry Smith }
5745e42470aSBarry Smith 
5755e42470aSBarry Smith 
5765e42470aSBarry Smith 
5775e42470aSBarry Smith 
578