xref: /petsc/src/snes/impls/ls/ls.c (revision 5e76c4312009b7634e32305adff9e37014db9055)
1*5e76c431SBarry Smith #ifndef lint
2*5e76c431SBarry Smith static char vcid[] = "$Id: newls1.c,v 1.9 1995/02/22 00:52:02 curfman Exp $";
3*5e76c431SBarry Smith #endif
4*5e76c431SBarry Smith 
5*5e76c431SBarry Smith #include <math.h>
6*5e76c431SBarry Smith #include "nonlin/nlall.h"
7*5e76c431SBarry Smith #include "nonlin/snes/nlepriv.h"
8*5e76c431SBarry Smith #include "system/system.h"
9*5e76c431SBarry Smith #include "system/time/usec.h"
10*5e76c431SBarry Smith 
11*5e76c431SBarry Smith /*D
12*5e76c431SBarry Smith     NLE_NLS1 - Implements a line search variant of Newton's Method
13*5e76c431SBarry Smith     for solving systems of nonlinear equations.
14*5e76c431SBarry Smith 
15*5e76c431SBarry Smith     Input parameters:
16*5e76c431SBarry Smith .   nlP - nonlinear context obtained from NLCreate()
17*5e76c431SBarry Smith 
18*5e76c431SBarry Smith     Returns:
19*5e76c431SBarry Smith     Number of global iterations until termination.  The precise type of
20*5e76c431SBarry Smith     termination can be examined by calling NLGetTerminationType() after
21*5e76c431SBarry Smith     NLSolve().
22*5e76c431SBarry Smith 
23*5e76c431SBarry Smith     Calling sequence:
24*5e76c431SBarry Smith $   nlP = NLCreate(NE_NLS1,0);
25*5e76c431SBarry Smith $   NLCreateDVectors()
26*5e76c431SBarry Smith $   NLSetXXX()
27*5e76c431SBarry Smith $   NLSetUp()
28*5e76c431SBarry Smith $   NLSolve()
29*5e76c431SBarry Smith $   NLDestroy()
30*5e76c431SBarry Smith 
31*5e76c431SBarry Smith     Notes:
32*5e76c431SBarry Smith     See NLCreate() and NLSetUp() for information on the definition and
33*5e76c431SBarry Smith     initialization of the nonlinear solver context.
34*5e76c431SBarry Smith 
35*5e76c431SBarry Smith     This implements essentially a truncated Newton method with a
36*5e76c431SBarry Smith     line search.  By default a cubic backtracking line search
37*5e76c431SBarry Smith     is employed, as described in the text "Numerical Methods for
38*5e76c431SBarry Smith     Unconstrained Optimization and Nonlinear Equations" by Dennis
39*5e76c431SBarry Smith     and Schnabel.  See the examples in nonlin/snes/examples.
40*5e76c431SBarry Smith D*/
41*5e76c431SBarry Smith /*
42*5e76c431SBarry Smith    This is intended as a model implementation, since it does not
43*5e76c431SBarry Smith    necessarily have many of the bells and whistles of other
44*5e76c431SBarry Smith    implementations.
45*5e76c431SBarry Smith 
46*5e76c431SBarry Smith    The code is DATA-STRUCTURE NEUTRAL and can be called RECURSIVELY.
47*5e76c431SBarry Smith    The following context variable is used:
48*5e76c431SBarry Smith       NLCtx *nlP - The nonlinear solver context, which is created by
49*5e76c431SBarry Smith                    calling NLCreate(NLE_NLS1).
50*5e76c431SBarry Smith  */
51*5e76c431SBarry Smith 
52*5e76c431SBarry Smith int NLENewtonLS1Solve( nlP )
53*5e76c431SBarry Smith NLCtx *nlP;
54*5e76c431SBarry Smith {
55*5e76c431SBarry Smith   NLENewtonLS1Ctx *neP = (NLENewtonLS1Ctx *) nlP->MethodPrivate;
56*5e76c431SBarry Smith   int             maxits, i, iters, line, nlconv, history_len;
57*5e76c431SBarry Smith   double          fnorm, gnorm, gpnorm, xnorm, ynorm, *history;
58*5e76c431SBarry Smith   double          t_elp, t_cpu;
59*5e76c431SBarry Smith   void            *Y, *X, *F, *G, *W, *TMP;
60*5e76c431SBarry Smith   FILE            *fp = nlP->fp;
61*5e76c431SBarry Smith   NLMonCore       *mc = &nlP->mon.core;
62*5e76c431SBarry Smith   VECntx          *vc = NLGetVectorCtx(nlP);
63*5e76c431SBarry Smith 
64*5e76c431SBarry Smith   CHKCOOKIEN(nlP,NL_COOKIE);
65*5e76c431SBarry Smith   nlconv	= 0;			/* convergence monitor */
66*5e76c431SBarry Smith   history	= nlP->conv_hist;	/* convergence history */
67*5e76c431SBarry Smith   history_len	= nlP->conv_hist_len;	/* convergence history length */
68*5e76c431SBarry Smith   maxits	= nlP->max_its;		/* maximum number of iterations */
69*5e76c431SBarry Smith   X		= nlP->vec_sol;		/* solution vector */
70*5e76c431SBarry Smith   F		= nlP->vec_rg;		/* residual vector */
71*5e76c431SBarry Smith   Y		= nlP->work[0];		/* work vectors */
72*5e76c431SBarry Smith   G		= nlP->work[1];
73*5e76c431SBarry Smith   W		= nlP->work[2];
74*5e76c431SBarry Smith 
75*5e76c431SBarry Smith   INITIAL_GUESS( X );			/* X <- X_0 */
76*5e76c431SBarry Smith   VNORM( vc, X, &xnorm );		/* xnorm = || X || */
77*5e76c431SBarry Smith   RESIDUAL( X, F );			/* Evaluate (+/-) F(X) */
78*5e76c431SBarry Smith   VNORM( vc, F, &fnorm );		/* fnorm <- || F || */
79*5e76c431SBarry Smith   nlP->norm = fnorm;
80*5e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
81*5e76c431SBarry Smith   mc->nvectors += 4; mc->nscalars += 2;
82*5e76c431SBarry Smith   MONITOR( X, F, &fnorm );		/* Monitor progress */
83*5e76c431SBarry Smith 
84*5e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
85*5e76c431SBarry Smith        nlP->iter = i+1;
86*5e76c431SBarry Smith 
87*5e76c431SBarry Smith        /* Solve J Y = -F, where J is Jacobian matrix */
88*5e76c431SBarry Smith        STEP_SETUP( X );			/* Step set-up phase */
89*5e76c431SBarry Smith        iters = STEP_COMPUTE( X, F, Y, &fnorm, &(neP->maxstep),
90*5e76c431SBarry Smith 	       &(nlP->trunctol), &gpnorm, &ynorm, (void *)0 );
91*5e76c431SBarry Smith 	       CHKERRV(1,-(NL));	/* Step compute phase,
92*5e76c431SBarry Smith 					   excluding line search */
93*5e76c431SBarry Smith 
94*5e76c431SBarry Smith        /* Line search should really be part of step compute phase */
95*5e76c431SBarry Smith        line = (*neP->line_search)( nlP, X, F, G, Y, W, fnorm,
96*5e76c431SBarry Smith               &ynorm, &gnorm );		CHKERRV(1,-(NL));
97*5e76c431SBarry Smith 
98*5e76c431SBarry Smith        if (!line) nlP->mon.nunsuc++;
99*5e76c431SBarry Smith        if (fp) fprintf(fp,"%d:  fnorm=%g, gnorm=%g, ynorm=%g, iters=%d\n",
100*5e76c431SBarry Smith                nlP->iter, fnorm, gnorm, ynorm, iters );
101*5e76c431SBarry Smith        TMP = F; F = G; G = TMP;
102*5e76c431SBarry Smith        TMP = X; X = Y; Y = TMP;
103*5e76c431SBarry Smith        fnorm = gnorm;
104*5e76c431SBarry Smith 
105*5e76c431SBarry Smith        STEP_DESTROY();			/* Step destroy phase */
106*5e76c431SBarry Smith        nlP->norm = fnorm;
107*5e76c431SBarry Smith        if (history && history_len > i+1) history[i+1] = fnorm;
108*5e76c431SBarry Smith        VNORM( vc, X, &xnorm );		/* xnorm = || X || */
109*5e76c431SBarry Smith        mc->nvectors += 2;
110*5e76c431SBarry Smith        mc->nscalars++;
111*5e76c431SBarry Smith        MONITOR( X, F, &fnorm );		/* Monitor progress */
112*5e76c431SBarry Smith 
113*5e76c431SBarry Smith        /* Test for convergence */
114*5e76c431SBarry Smith        if (CONVERGED( &xnorm, &ynorm, &fnorm )) {
115*5e76c431SBarry Smith            /* Verify that solution is in corect location */
116*5e76c431SBarry Smith            if (X != nlP->vec_sol) VCOPY( vc, X, nlP->vec_sol );
117*5e76c431SBarry Smith            break;
118*5e76c431SBarry Smith            }
119*5e76c431SBarry Smith        }
120*5e76c431SBarry Smith   if (i == maxits) i--;
121*5e76c431SBarry Smith   return i+1;
122*5e76c431SBarry Smith }
123*5e76c431SBarry Smith /* ------------------------------------------------------------ */
124*5e76c431SBarry Smith /*ARGSUSED*/
125*5e76c431SBarry Smith void NLENewtonLS1SetUp( nlP )
126*5e76c431SBarry Smith NLCtx *nlP;
127*5e76c431SBarry Smith {
128*5e76c431SBarry Smith   NLENewtonLS1Ctx *ctx = (NLENewtonLS1Ctx *)nlP->MethodPrivate;
129*5e76c431SBarry Smith 
130*5e76c431SBarry Smith   CHKCOOKIE(nlP,NL_COOKIE);
131*5e76c431SBarry Smith   nlP->nwork = 3;
132*5e76c431SBarry Smith   nlP->work = VGETVECS( nlP->vc, nlP->nwork );	CHKPTR(nlP->work);
133*5e76c431SBarry Smith   if (!ctx->line_search) {
134*5e76c431SBarry Smith       SETERRC(1,"NLENewtonLS1SetUp needs line search routine!\n");
135*5e76c431SBarry Smith       return;
136*5e76c431SBarry Smith       }
137*5e76c431SBarry Smith   NLiBasicSetUp( nlP, "NLENewtonLS1SetUp" );	CHKERR(1);
138*5e76c431SBarry Smith }
139*5e76c431SBarry Smith /* ------------------------------------------------------------ */
140*5e76c431SBarry Smith void NLENewtonLS1Create( nlP )
141*5e76c431SBarry Smith NLCtx *nlP;
142*5e76c431SBarry Smith {
143*5e76c431SBarry Smith   NLENewtonLS1Ctx *neP;
144*5e76c431SBarry Smith 
145*5e76c431SBarry Smith   CHKCOOKIE(nlP,NL_COOKIE);
146*5e76c431SBarry Smith   nlP->method		= NLE_NLS1;
147*5e76c431SBarry Smith   nlP->method_type	= NLE;
148*5e76c431SBarry Smith   nlP->setup		= NLENewtonLS1SetUp;
149*5e76c431SBarry Smith   nlP->solver		= NLENewtonLS1Solve;
150*5e76c431SBarry Smith   nlP->destroy		= NLENewtonLS1Destroy;
151*5e76c431SBarry Smith   nlP->set_param	= NLENewtonLS1SetParameter;
152*5e76c431SBarry Smith   nlP->get_param	= NLENewtonLS1GetParameter;
153*5e76c431SBarry Smith   nlP->usr_monitor	= NLENewtonDefaultMonitor;
154*5e76c431SBarry Smith   nlP->converged	= NLENewtonDefaultConverged;
155*5e76c431SBarry Smith   nlP->term_type	= NLENewtonDefaultConvergedType;
156*5e76c431SBarry Smith 
157*5e76c431SBarry Smith   neP			= NEW(NLENewtonLS1Ctx);   CHKPTR(neP);
158*5e76c431SBarry Smith   nlP->MethodPrivate	= (void *) neP;
159*5e76c431SBarry Smith   neP->line_search	= NLStepDefaultLineSearch;
160*5e76c431SBarry Smith   neP->alpha		= 1.e-4;
161*5e76c431SBarry Smith   neP->maxstep		= 1.e8;
162*5e76c431SBarry Smith   neP->steptol		= 1.e-12;
163*5e76c431SBarry Smith }
164*5e76c431SBarry Smith /* ------------------------------------------------------------ */
165*5e76c431SBarry Smith /*ARGSUSED*/
166*5e76c431SBarry Smith void NLENewtonLS1Destroy( nlP )
167*5e76c431SBarry Smith NLCtx *nlP;
168*5e76c431SBarry Smith {
169*5e76c431SBarry Smith    VFREEVECS( nlP->vc, nlP->work, nlP->nwork );
170*5e76c431SBarry Smith    NLiBasicDestroy( nlP );	CHKERR(1);
171*5e76c431SBarry Smith }
172*5e76c431SBarry Smith /* ------------------------------------------------------------ */
173*5e76c431SBarry Smith /*ARGSUSED*/
174*5e76c431SBarry Smith /*@
175*5e76c431SBarry Smith    NLStepSimpleLineSearch - This routine is not a line search at all;
176*5e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
177*5e76c431SBarry Smith    to serve as a template and is not recommended for general use.
178*5e76c431SBarry Smith 
179*5e76c431SBarry Smith    Input Parameters:
180*5e76c431SBarry Smith .  nlP - nonlinear context
181*5e76c431SBarry Smith .  x - current iterate
182*5e76c431SBarry Smith .  f - residual evaluated at x
183*5e76c431SBarry Smith .  y - search direction (contains new iterate on output)
184*5e76c431SBarry Smith .  w - work vector
185*5e76c431SBarry Smith .  fnorm - 2-norm of f
186*5e76c431SBarry Smith 
187*5e76c431SBarry Smith    Output parameters:
188*5e76c431SBarry Smith .  g - residual evaluated at new iterate y
189*5e76c431SBarry Smith .  y - new iterate (contains search direction on input)
190*5e76c431SBarry Smith .  gnorm - 2-norm of g
191*5e76c431SBarry Smith .  ynorm - 2-norm of search length
192*5e76c431SBarry Smith 
193*5e76c431SBarry Smith    Returns:
194*5e76c431SBarry Smith    1, indicating success of the step.
195*5e76c431SBarry Smith 
196*5e76c431SBarry Smith    Notes:
197*5e76c431SBarry Smith    Use either NLSetStepLineSearchRoutines() or NLSetLineSearchRoutine()
198*5e76c431SBarry Smith    to set this routine within the NLE_NLS1 method.
199*5e76c431SBarry Smith @*/
200*5e76c431SBarry Smith int NLStepSimpleLineSearch( nlP, x, f, g, y, w, fnorm,
201*5e76c431SBarry Smith                             ynorm, gnorm )
202*5e76c431SBarry Smith NLCtx  *nlP;
203*5e76c431SBarry Smith void   *x;
204*5e76c431SBarry Smith void   *f;
205*5e76c431SBarry Smith void   *g;
206*5e76c431SBarry Smith void   *y;
207*5e76c431SBarry Smith void   *w;
208*5e76c431SBarry Smith double fnorm;
209*5e76c431SBarry Smith double *ynorm;
210*5e76c431SBarry Smith double *gnorm;
211*5e76c431SBarry Smith {
212*5e76c431SBarry Smith   NLMonCore *mc = &nlP->mon.core;
213*5e76c431SBarry Smith   VECntx    *vc = NLGetVectorCtx(nlP);
214*5e76c431SBarry Smith 
215*5e76c431SBarry Smith   CHKCOOKIEN(nlP,NL_COOKIE);
216*5e76c431SBarry Smith   VNORM( vc, y, ynorm );	/* ynorm = || y ||    */
217*5e76c431SBarry Smith   VAXPY( vc, 1.0, x, y );	/* y <- x + y         */
218*5e76c431SBarry Smith   RESIDUAL( y, g );		/* Evaluate (+/-) g(y) */
219*5e76c431SBarry Smith   VNORM( vc, g, gnorm ); 	/* gnorm = || g ||    */
220*5e76c431SBarry Smith   mc->nvectors += 6;
221*5e76c431SBarry Smith   mc->nscalars += 2;
222*5e76c431SBarry Smith   return 1;
223*5e76c431SBarry Smith }
224*5e76c431SBarry Smith /* ------------------------------------------------------------------ */
225*5e76c431SBarry Smith /*@
226*5e76c431SBarry Smith    NLStepDefaultLineSearch - This routine performs a cubic line search.
227*5e76c431SBarry Smith 
228*5e76c431SBarry Smith    Input Parameters:
229*5e76c431SBarry Smith .  nlP - nonlinear context
230*5e76c431SBarry Smith .  x - current iterate
231*5e76c431SBarry Smith .  f - residual evaluated at x
232*5e76c431SBarry Smith .  y - search direction (contains new iterate on output)
233*5e76c431SBarry Smith .  w - work vector
234*5e76c431SBarry Smith .  fnorm - 2-norm of f
235*5e76c431SBarry Smith 
236*5e76c431SBarry Smith    Output parameters:
237*5e76c431SBarry Smith .  g - residual evaluated at new iterate y
238*5e76c431SBarry Smith .  y - new iterate (contains search direction on input)
239*5e76c431SBarry Smith .  gnorm - 2-norm of g
240*5e76c431SBarry Smith .  ynorm - 2-norm of search length
241*5e76c431SBarry Smith 
242*5e76c431SBarry Smith    Returns:
243*5e76c431SBarry Smith    1 if the line search succeeds; 0 if the line search fails.
244*5e76c431SBarry Smith 
245*5e76c431SBarry Smith    Notes:
246*5e76c431SBarry Smith    Use either NLSetStepLineSearchRoutines() or NLSetLineSearchRoutine()
247*5e76c431SBarry Smith    to set this routine within the NLE_NLS1 method.
248*5e76c431SBarry Smith 
249*5e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
250*5e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
251*5e76c431SBarry Smith 
252*5e76c431SBarry Smith @*/
253*5e76c431SBarry Smith int NLStepDefaultLineSearch( nlP, x, f, g, y, w, fnorm, ynorm, gnorm )
254*5e76c431SBarry Smith NLCtx  *nlP;
255*5e76c431SBarry Smith void   *x;
256*5e76c431SBarry Smith void   *f;
257*5e76c431SBarry Smith void   *g;
258*5e76c431SBarry Smith void   *y;
259*5e76c431SBarry Smith void   *w;
260*5e76c431SBarry Smith double fnorm;
261*5e76c431SBarry Smith double *ynorm;
262*5e76c431SBarry Smith double *gnorm;
263*5e76c431SBarry Smith {
264*5e76c431SBarry Smith   double          alpha, maxstep, steptol, initslope;
265*5e76c431SBarry Smith   double          minlambda, lambda, lambdaprev, gnormprev, lambdatemp;
266*5e76c431SBarry Smith   double          a, b, d, t1, t2;
267*5e76c431SBarry Smith   int             count;
268*5e76c431SBarry Smith   FILE            *fp = nlP->fp;
269*5e76c431SBarry Smith   NLENewtonLS1Ctx *neP = (NLENewtonLS1Ctx *) nlP->MethodPrivate;
270*5e76c431SBarry Smith   NLMonCore       *mc = &nlP->mon.core;
271*5e76c431SBarry Smith   VECntx          *vc = NLGetVectorCtx(nlP);
272*5e76c431SBarry Smith 
273*5e76c431SBarry Smith   CHKCOOKIEN(nlP,NL_COOKIE);
274*5e76c431SBarry Smith   alpha   = neP->alpha;
275*5e76c431SBarry Smith   maxstep = neP->maxstep;
276*5e76c431SBarry Smith   steptol = neP->steptol;
277*5e76c431SBarry Smith 
278*5e76c431SBarry Smith   VNORM( vc, y, ynorm );
279*5e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
280*5e76c431SBarry Smith       VSCALE( vc, maxstep/(*ynorm), y );
281*5e76c431SBarry Smith       *ynorm = maxstep;
282*5e76c431SBarry Smith       mc->nvectors++;
283*5e76c431SBarry Smith       }
284*5e76c431SBarry Smith   minlambda = steptol/(*ynorm);
285*5e76c431SBarry Smith   VDOT( vc, f, y, &initslope );
286*5e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
287*5e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
288*5e76c431SBarry Smith 
289*5e76c431SBarry Smith   VCOPY( vc, y, w );
290*5e76c431SBarry Smith   VAXPY( vc, 1.0, x, w );
291*5e76c431SBarry Smith   RESIDUAL( w, g );		/* Evaluate (+/-) g(w) */
292*5e76c431SBarry Smith   VNORM( vc, g, gnorm );
293*5e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
294*5e76c431SBarry Smith       if (fp) fprintf(fp,"Taking full Newton step\n");
295*5e76c431SBarry Smith       VCOPY( vc, w, y );
296*5e76c431SBarry Smith       mc->nvectors += 8; mc->nscalars += 3;
297*5e76c431SBarry Smith       return 1;
298*5e76c431SBarry Smith       }
299*5e76c431SBarry Smith 
300*5e76c431SBarry Smith   /* Fit points with quadratic */
301*5e76c431SBarry Smith   lambda = 1.0; count = 0;
302*5e76c431SBarry Smith   lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
303*5e76c431SBarry Smith   lambdaprev = lambda;
304*5e76c431SBarry Smith   gnormprev = *gnorm;
305*5e76c431SBarry Smith   if (lambdatemp <= .1*lambda) {
306*5e76c431SBarry Smith       lambda = .1*lambda;
307*5e76c431SBarry Smith       mc->nscalars++;
308*5e76c431SBarry Smith   } else lambda = lambdatemp;
309*5e76c431SBarry Smith   VCOPY( vc, x, w );
310*5e76c431SBarry Smith   VAXPY( vc, lambda, y, w );
311*5e76c431SBarry Smith   RESIDUAL( w, g );		/* Evaluate (+/-) g(w) */
312*5e76c431SBarry Smith   VNORM( vc, g, gnorm );
313*5e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
314*5e76c431SBarry Smith       if (fp) fprintf(fp,"Taking Newton step from quadratic \n");
315*5e76c431SBarry Smith       VCOPY( vc, w, y );
316*5e76c431SBarry Smith       mc->nvectors += 12; mc->nscalars += 8;
317*5e76c431SBarry Smith       return 1;
318*5e76c431SBarry Smith       }
319*5e76c431SBarry Smith 
320*5e76c431SBarry Smith   /* Fit points with cubic */
321*5e76c431SBarry Smith   count = 1;
322*5e76c431SBarry Smith   while (1) {
323*5e76c431SBarry Smith        if (lambda <= minlambda) { /* bad luck; use full step */
324*5e76c431SBarry Smith            fprintf(stderr,"Unable to find good step length! %d \n",count);
325*5e76c431SBarry Smith            fprintf(stderr, "f %g fnew %g ynorm %g lambda %g \n",
326*5e76c431SBarry Smith                    fnorm,*gnorm, *ynorm,lambda);
327*5e76c431SBarry Smith            VCOPY( vc, w, y );
328*5e76c431SBarry Smith            mc->nvectors += 12 + 4*(count-1);
329*5e76c431SBarry Smith            mc->nscalars += 8 + 28*(count-1);
330*5e76c431SBarry Smith            return 0;
331*5e76c431SBarry Smith            }
332*5e76c431SBarry Smith       t1 = *gnorm - fnorm - lambda*initslope;
333*5e76c431SBarry Smith       t2 = gnormprev  - fnorm - lambdaprev*initslope;
334*5e76c431SBarry Smith       a = (t1/(lambda*lambda) -
335*5e76c431SBarry Smith                 t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
336*5e76c431SBarry Smith       b = (-lambdaprev*t1/(lambda*lambda) +
337*5e76c431SBarry Smith                 lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
338*5e76c431SBarry Smith       d = b*b - 3*a*initslope;
339*5e76c431SBarry Smith       if (d < 0.0) d = 0.0;
340*5e76c431SBarry Smith       if (a == 0.0) {
341*5e76c431SBarry Smith          lambdatemp = -initslope/(2.0*b);
342*5e76c431SBarry Smith          mc->nscalars += 2;
343*5e76c431SBarry Smith       } else {
344*5e76c431SBarry Smith          lambdatemp = (-b + sqrt(d))/(3.0*a);
345*5e76c431SBarry Smith          mc->nscalars += 4;
346*5e76c431SBarry Smith          }
347*5e76c431SBarry Smith       if (lambdatemp > .5*lambda) {
348*5e76c431SBarry Smith          lambdatemp = .5*lambda;
349*5e76c431SBarry Smith          mc->nscalars++;
350*5e76c431SBarry Smith          }
351*5e76c431SBarry Smith       lambdaprev = lambda;
352*5e76c431SBarry Smith       gnormprev = *gnorm;
353*5e76c431SBarry Smith       if (lambdatemp <= .1*lambda) {
354*5e76c431SBarry Smith          lambda = .1*lambda;
355*5e76c431SBarry Smith          mc->nscalars++;
356*5e76c431SBarry Smith          }
357*5e76c431SBarry Smith       else lambda = lambdatemp;
358*5e76c431SBarry Smith       VCOPY( vc, x, w );
359*5e76c431SBarry Smith       VAXPY( vc, lambda, y, w );
360*5e76c431SBarry Smith       RESIDUAL( w, g );		/* Evaluate (+/-) g(w) */
361*5e76c431SBarry Smith       VNORM( vc, g, gnorm );
362*5e76c431SBarry Smith       if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
363*5e76c431SBarry Smith          if (fp) fprintf(fp,"Taking Newton step from cubic %d\n",count);
364*5e76c431SBarry Smith          VCOPY( vc, w, y );
365*5e76c431SBarry Smith          mc->nvectors += 12 + 4*count;
366*5e76c431SBarry Smith          mc->nscalars += 8 + 28*count;
367*5e76c431SBarry Smith          return 1;
368*5e76c431SBarry Smith          }
369*5e76c431SBarry Smith       count++;
370*5e76c431SBarry Smith       }
371*5e76c431SBarry Smith }
372*5e76c431SBarry Smith /* ------------------------------------------------------------ */
373*5e76c431SBarry Smith /*
374*5e76c431SBarry Smith    NLENewtonLS1SetParameter - Sets a chosen parameter used by the
375*5e76c431SBarry Smith    NLE_NLS1 method to the specified value.
376*5e76c431SBarry Smith 
377*5e76c431SBarry Smith    Note:
378*5e76c431SBarry Smith    Possible parameters for the NLE_NLS1 method are
379*5e76c431SBarry Smith $    param = "alpha" - used to determine sufficient reduction
380*5e76c431SBarry Smith $    param = "maxstep" - maximum step size
381*5e76c431SBarry Smith $    param = "steptol" - step comvergence tolerance
382*5e76c431SBarry Smith */
383*5e76c431SBarry Smith void NLENewtonLS1SetParameter( nlP, param, value )
384*5e76c431SBarry Smith NLCtx  *nlP;
385*5e76c431SBarry Smith char   *param;
386*5e76c431SBarry Smith double *value;
387*5e76c431SBarry Smith {
388*5e76c431SBarry Smith   NLENewtonLS1Ctx *ctx = (NLENewtonLS1Ctx *)nlP->MethodPrivate;
389*5e76c431SBarry Smith 
390*5e76c431SBarry Smith   CHKCOOKIE(nlP,NL_COOKIE);
391*5e76c431SBarry Smith   if (nlP->method != NLE_NLS1) {
392*5e76c431SBarry Smith       SETERRC(1,"Compatible only with NLE_NLS1 method");
393*5e76c431SBarry Smith       return;
394*5e76c431SBarry Smith       }
395*5e76c431SBarry Smith   if (!strcmp(param,"alpha"))		ctx->alpha   = *value;
396*5e76c431SBarry Smith   else if (!strcmp(param,"maxstep"))	ctx->maxstep = *value;
397*5e76c431SBarry Smith   else if (!strcmp(param,"steptol"))	ctx->steptol = *value;
398*5e76c431SBarry Smith   else SETERRC(1,"Invalid parameter name for NLE_NLS1 method");
399*5e76c431SBarry Smith }
400*5e76c431SBarry Smith /* ------------------------------------------------------------ */
401*5e76c431SBarry Smith /*
402*5e76c431SBarry Smith    NLENewtonLS1GetParameter - Returns the value of a chosen parameter
403*5e76c431SBarry Smith    used by the NLE_NLS1 method.
404*5e76c431SBarry Smith 
405*5e76c431SBarry Smith    Note:
406*5e76c431SBarry Smith    Possible parameters for the NLE_NLS1 method are
407*5e76c431SBarry Smith $    param = "alpha" - used to determine sufficient reduction
408*5e76c431SBarry Smith $    param = "maxstep" - maximum step size
409*5e76c431SBarry Smith $    param = "steptol" - step comvergence tolerance
410*5e76c431SBarry Smith */
411*5e76c431SBarry Smith double NLENewtonLS1GetParameter( nlP, param )
412*5e76c431SBarry Smith NLCtx  *nlP;
413*5e76c431SBarry Smith char   *param;
414*5e76c431SBarry Smith {
415*5e76c431SBarry Smith   NLENewtonLS1Ctx *ctx = (NLENewtonLS1Ctx *)nlP->MethodPrivate;
416*5e76c431SBarry Smith   double          value = 0.0;
417*5e76c431SBarry Smith 
418*5e76c431SBarry Smith   CHKCOOKIEN(nlP,NL_COOKIE);
419*5e76c431SBarry Smith   if (nlP->method != NLE_NLS1) {
420*5e76c431SBarry Smith       SETERRC(1,"Compatible only with NLE_NLS1 method");
421*5e76c431SBarry Smith       return value;
422*5e76c431SBarry Smith       }
423*5e76c431SBarry Smith   if (!strcmp(param,"alpha"))		value = ctx->alpha;
424*5e76c431SBarry Smith   else if (!strcmp(param,"maxstep"))	value = ctx->maxstep;
425*5e76c431SBarry Smith   else if (!strcmp(param,"steptol"))	value = ctx->steptol;
426*5e76c431SBarry Smith   else SETERRC(1,"Invalid parameter name for NLE_NLS1 method");
427*5e76c431SBarry Smith   return value;
428*5e76c431SBarry Smith }
429*5e76c431SBarry Smith /* ------------------------------------------------------------ */
430*5e76c431SBarry Smith /*@C
431*5e76c431SBarry Smith    NLSetLineSearchRoutine - Sets the line search routine to be used
432*5e76c431SBarry Smith    by the method NLE_NLS1.
433*5e76c431SBarry Smith 
434*5e76c431SBarry Smith    Input Parameters:
435*5e76c431SBarry Smith .  nlP - nonlinear context obtained from NLCreate()
436*5e76c431SBarry Smith .  func - pointer to int function
437*5e76c431SBarry Smith 
438*5e76c431SBarry Smith    Possible routines:
439*5e76c431SBarry Smith    NLStepDefaultLineSearch() - default line search
440*5e76c431SBarry Smith    NLStepSimpleLineSearch() - the full Newton step (actually not a
441*5e76c431SBarry Smith    line search)
442*5e76c431SBarry Smith 
443*5e76c431SBarry Smith    Calling sequence of func:
444*5e76c431SBarry Smith .  func (NLCtx *nlP, void *x, void *f, void *g, void *y,
445*5e76c431SBarry Smith          void *w, double fnorm, double *ynorm, double *gnorm )
446*5e76c431SBarry Smith 
447*5e76c431SBarry Smith     Input parameters for func:
448*5e76c431SBarry Smith .   nlP - nonlinear context
449*5e76c431SBarry Smith .   x - current iterate
450*5e76c431SBarry Smith .   f - residual evaluated at x
451*5e76c431SBarry Smith .   y - search direction (contains new iterate on output)
452*5e76c431SBarry Smith .   w - work vector
453*5e76c431SBarry Smith .   fnorm - 2-norm of f
454*5e76c431SBarry Smith 
455*5e76c431SBarry Smith     Output parameters for func:
456*5e76c431SBarry Smith .   g - residual evaluated at new iterate y
457*5e76c431SBarry Smith .   y - new iterate (contains search direction on input)
458*5e76c431SBarry Smith .   gnorm - 2-norm of g
459*5e76c431SBarry Smith .   ynorm - 2-norm of search length
460*5e76c431SBarry Smith 
461*5e76c431SBarry Smith     Returned by func:
462*5e76c431SBarry Smith     1 if the line search succeeds; 0 if the line search fails.
463*5e76c431SBarry Smith @*/
464*5e76c431SBarry Smith void NLSetLineSearchRoutine( nlP, func )
465*5e76c431SBarry Smith NLCtx *nlP;
466*5e76c431SBarry Smith int   (*func)();
467*5e76c431SBarry Smith {
468*5e76c431SBarry Smith   CHKCOOKIE(nlP,NL_COOKIE);
469*5e76c431SBarry Smith   if ((nlP)->method == NLE_NLS1)
470*5e76c431SBarry Smith      ((NLENewtonLS1Ctx *)(nlP->MethodPrivate))->line_search = func;
471*5e76c431SBarry Smith }
472