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