14800dd8cSBarry Smith #ifndef lint 2*fbe28522SBarry Smith static char vcid[] = "$Id: tr.c,v 1.1 1995/04/12 20:36:40 bsmith Exp bsmith $"; 34800dd8cSBarry Smith #endif 44800dd8cSBarry Smith 54800dd8cSBarry Smith #include <math.h> 6*fbe28522SBarry Smith #include "tr.h" 74800dd8cSBarry Smith 8*fbe28522SBarry Smith /* 94800dd8cSBarry Smith NLE_NTR1 - Implements Newton's Method with a trust region 104800dd8cSBarry Smith approach for solving systems of nonlinear equations. 114800dd8cSBarry Smith 124800dd8cSBarry Smith Input parameters: 134800dd8cSBarry Smith . nlP - nonlinear context obtained from NLCreate() 144800dd8cSBarry Smith 154800dd8cSBarry Smith Returns: 164800dd8cSBarry Smith Number of global iterations until termination. The precise type of 174800dd8cSBarry Smith termination can be examined by calling NLGetTerminationType() after 184800dd8cSBarry Smith NLSolve(). 194800dd8cSBarry Smith 204800dd8cSBarry Smith Calling sequence: 214800dd8cSBarry Smith $ nlP = NLCreate(NLE_NTR1,0) 224800dd8cSBarry Smith $ NLCreateDVectors() 234800dd8cSBarry Smith $ NLSet***() 244800dd8cSBarry Smith $ NLSetUp() 254800dd8cSBarry Smith $ NLSolve() 264800dd8cSBarry Smith $ NLDestroy() 274800dd8cSBarry Smith 284800dd8cSBarry Smith Notes: 294800dd8cSBarry Smith See NLCreate() and NLSetUp() for information on the definition and 304800dd8cSBarry Smith initialization of the nonlinear solver context. 314800dd8cSBarry Smith 324800dd8cSBarry Smith The basic algorithm is taken from "The Minpack Project", by More', 334800dd8cSBarry Smith Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development 344800dd8cSBarry Smith of Mathematical Software", Wayne Cowell, editor. See the examples 354800dd8cSBarry Smith in nonlin/examples. 36*fbe28522SBarry Smith */ 374800dd8cSBarry Smith /* 384800dd8cSBarry Smith This is intended as a model implementation, since it does not 394800dd8cSBarry Smith necessarily have many of the bells and whistles of other 404800dd8cSBarry Smith implementations. 414800dd8cSBarry Smith 424800dd8cSBarry Smith The code is DATA-STRUCTURE NEUTRAL and can be called RECURSIVELY. 434800dd8cSBarry Smith The following context variable is used: 444800dd8cSBarry Smith NLCtx *nlP - The nonlinear solver context, which is created by 454800dd8cSBarry Smith calling NLCreate(NLE_NTR1). 464800dd8cSBarry Smith 474800dd8cSBarry Smith The step_compute routine must return two values: 484800dd8cSBarry Smith 1) ynorm - the norm of the step 494800dd8cSBarry Smith 2) gpnorm - the predicted value for the residual norm at the new 504800dd8cSBarry Smith point, assuming a local linearization. The value is 0 if the 514800dd8cSBarry Smith step lies within the trust region and is > 0 otherwise. 524800dd8cSBarry Smith */ 53*fbe28522SBarry Smith static int SNESSolve_TR(SNES snes, int *its ) 544800dd8cSBarry Smith { 55*fbe28522SBarry Smith SNES_TR *neP = (SNES_TR *) snes->data; 56*fbe28522SBarry Smith Vec X, F, Y, G, TMP; 57*fbe28522SBarry Smith int maxits, i, iters, history_len, nlconv,ierr,lits; 58*fbe28522SBarry Smith double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm; 594800dd8cSBarry Smith double *history, ynorm; 60*fbe28522SBarry Smith Scalar one = 1.0; 614800dd8cSBarry Smith 624800dd8cSBarry Smith nlconv = 0; /* convergence monitor */ 63*fbe28522SBarry Smith history = snes->conv_hist; /* convergence history */ 64*fbe28522SBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 65*fbe28522SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 66*fbe28522SBarry Smith X = snes->vec_sol; /* solution vector */ 67*fbe28522SBarry Smith F = snes->vec_res; /* residual vector */ 68*fbe28522SBarry Smith Y = snes->work[0]; /* work vectors */ 69*fbe28522SBarry Smith G = snes->work[1]; 704800dd8cSBarry Smith 71*fbe28522SBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr); /* X <- X_0 */ 72*fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 734800dd8cSBarry Smith 74*fbe28522SBarry Smith ierr = SNESComputeResidual(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */ 75*fbe28522SBarry Smith VecNorm(F, &fnorm ); /* fnorm <- || F || */ 76*fbe28522SBarry Smith snes->norm = fnorm; 774800dd8cSBarry Smith if (history && history_len > 0) history[0] = fnorm; 784800dd8cSBarry Smith delta = neP->delta0*fnorm; 794800dd8cSBarry Smith neP->delta = delta; 80*fbe28522SBarry Smith if (snes->Monitor)(*snes->Monitor)(snes,0,X,F,fnorm,snes->monP); 814800dd8cSBarry Smith 824800dd8cSBarry Smith for ( i=0; i<maxits; i++ ) { 83*fbe28522SBarry Smith snes->iter = i+1; 844800dd8cSBarry Smith 85*fbe28522SBarry Smith (*snes->ComputeJacobian)(X,&snes->jacobian,snes->jacP); 864800dd8cSBarry Smith while(1) { 87*fbe28522SBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian,0); 88*fbe28522SBarry Smith ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERR(ierr); 89*fbe28522SBarry Smith /* Scale Y if need be and predict new value of F norm */ 90*fbe28522SBarry Smith VecNorm( Y, &norm ); 91*fbe28522SBarry Smith if (norm > delta) { 92*fbe28522SBarry Smith norm = delta/norm; 93*fbe28522SBarry Smith gpnorm = (1.0 - norm)*fnorm; 94*fbe28522SBarry Smith VecScale( &norm, Y ); 95*fbe28522SBarry Smith PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm ); 96*fbe28522SBarry Smith ynorm = delta; 97*fbe28522SBarry Smith } else { 98*fbe28522SBarry Smith gpnorm = 0.0; 99*fbe28522SBarry Smith PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" ); 100*fbe28522SBarry Smith ynorm = norm; 101*fbe28522SBarry Smith } 102*fbe28522SBarry Smith VecAXPY(&one, X, Y ); /* Y <- X + Y */ 103*fbe28522SBarry Smith ierr = SNESComputeResidual(snes,Y,G); CHKERR(ierr); /* (+/-) F(X) */ 104*fbe28522SBarry Smith VecNorm( G, &gnorm ); /* gnorm <- || g || */ 1054800dd8cSBarry Smith if (fnorm == gpnorm) rho = 0.0; 106*fbe28522SBarry Smith else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 1074800dd8cSBarry Smith 1084800dd8cSBarry Smith /* Update size of trust region */ 1094800dd8cSBarry Smith if (rho < neP->mu) delta *= neP->delta1; 1104800dd8cSBarry Smith else if (rho < neP->eta) delta *= neP->delta2; 1114800dd8cSBarry Smith else delta *= neP->delta3; 1124800dd8cSBarry Smith 113*fbe28522SBarry Smith PLogInfo((PetscObject)snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 1144800dd8cSBarry Smith i, fnorm, gnorm, ynorm ); 115*fbe28522SBarry Smith PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 116*fbe28522SBarry Smith gpnorm, rho, delta, lits); 1174800dd8cSBarry Smith 1184800dd8cSBarry Smith neP->delta = delta; 1194800dd8cSBarry Smith if (rho > neP->sigma) break; 1204800dd8cSBarry Smith neP->itflag = 0; 121*fbe28522SBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP)) { 1224800dd8cSBarry Smith /* We're not progressing, so return with the current iterate */ 123*fbe28522SBarry Smith if (X != snes->vec_sol) VecCopy( X, snes->vec_sol ); 1244800dd8cSBarry Smith return i; 1254800dd8cSBarry Smith } 1264800dd8cSBarry Smith } 1274800dd8cSBarry Smith fnorm = gnorm; 128*fbe28522SBarry Smith snes->norm = fnorm; 1294800dd8cSBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 1304800dd8cSBarry Smith TMP = F; F = G; G = TMP; 1314800dd8cSBarry Smith TMP = X; X = Y; Y = TMP; 132*fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 133*fbe28522SBarry Smith if (snes->Monitor) (*snes->Monitor)(snes,0,X,F,fnorm,snes->monP); 1344800dd8cSBarry Smith 1354800dd8cSBarry Smith /* Test for convergence */ 1364800dd8cSBarry Smith neP->itflag = 1; 137*fbe28522SBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 1384800dd8cSBarry Smith /* Verify solution is in corect location */ 139*fbe28522SBarry Smith if (X != snes->vec_sol) VecCopy(X, snes->vec_sol ); 1404800dd8cSBarry Smith break; 1414800dd8cSBarry Smith } 1424800dd8cSBarry Smith } 143*fbe28522SBarry Smith if (i == maxits) *its = i-1; else *its = i; 144*fbe28522SBarry Smith return 0; 1454800dd8cSBarry Smith } 1464800dd8cSBarry Smith /* -------------------------------------------------------------*/ 1474800dd8cSBarry Smith 1484800dd8cSBarry Smith /*------------------------------------------------------------*/ 149*fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes ) 1504800dd8cSBarry Smith { 151*fbe28522SBarry Smith int ierr; 152*fbe28522SBarry Smith snes->nwork = 2; 153*fbe28522SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERR(ierr); 154*fbe28522SBarry Smith return 0; 1554800dd8cSBarry Smith } 1564800dd8cSBarry Smith /*------------------------------------------------------------*/ 157*fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj ) 1584800dd8cSBarry Smith { 159*fbe28522SBarry Smith SNES snes = (SNES) obj; 160*fbe28522SBarry Smith VecFreeVecs(snes->work, snes->nwork ); 161*fbe28522SBarry Smith return 0; 1624800dd8cSBarry Smith } 1634800dd8cSBarry Smith /*------------------------------------------------------------*/ 1644800dd8cSBarry Smith /*@ 165*fbe28522SBarry Smith SNESTRDefaultConverged - Default test for monitoring the 1664800dd8cSBarry Smith convergence of the method NLENewtonTR1Solve. 1674800dd8cSBarry Smith 1684800dd8cSBarry Smith Input Parameters: 169*fbe28522SBarry Smith . snes - nonlinear context obtained from NLCreate() 1704800dd8cSBarry Smith . xnorm - 2-norm of current iterate 1714800dd8cSBarry Smith . pnorm - 2-norm of current step 1724800dd8cSBarry Smith . fnorm - 2-norm of residual 1734800dd8cSBarry Smith 1744800dd8cSBarry Smith Returns: 1754800dd8cSBarry Smith $ 1 if ( delta < xnorm*deltatol ), 1764800dd8cSBarry Smith $ 2 if ( fnorm < atol ), 1774800dd8cSBarry Smith $ 3 if ( pnorm < xtol*xnorm ), 1784800dd8cSBarry Smith $ -2 if ( nres > max_res ), 1794800dd8cSBarry Smith $ -1 if ( delta < xnorm*epsmch ), 1804800dd8cSBarry Smith $ 0 otherwise, 1814800dd8cSBarry Smith 1824800dd8cSBarry Smith where 1834800dd8cSBarry Smith $ atol - absolute residual norm tolerance, 1844800dd8cSBarry Smith $ set with NLSetAbsConvergenceTol() 1854800dd8cSBarry Smith $ delta - trust region paramenter 1864800dd8cSBarry Smith $ deltatol - trust region size tolerance, 1874800dd8cSBarry Smith $ set with NLSetTrustRegionTol() 1884800dd8cSBarry Smith $ epsmch - machine epsilon 1894800dd8cSBarry Smith $ max_res - maximum number of residual evaluations, 1904800dd8cSBarry Smith $ set with NLSetMaxResidualEvaluations() 1914800dd8cSBarry Smith $ nres - number of residual evaluations 1924800dd8cSBarry Smith $ xtol - relative residual norm tolerance, 1934800dd8cSBarry Smith $ set with NLSetRelConvergenceTol() 1944800dd8cSBarry Smith 1954800dd8cSBarry Smith Note: 1964800dd8cSBarry Smith Call NLGetConvergenceType() after calling NLSolve() to obtain 1974800dd8cSBarry Smith information about the type of termination which occurred for the 1984800dd8cSBarry Smith nonlinear solver. 1994800dd8cSBarry Smith @*/ 200*fbe28522SBarry Smith int SNESTRDefaultConverged(SNES snes, double xnorm, double pnorm, 201*fbe28522SBarry Smith double fnorm, void *ctx ) 2024800dd8cSBarry Smith { 203*fbe28522SBarry Smith SNES_TR *neP = (SNES_TR *)snes->data; 2044800dd8cSBarry Smith double epsmch = 1.0e-14; /* This must be fixed */ 2054800dd8cSBarry Smith 206*fbe28522SBarry Smith if (neP->delta < xnorm * neP->deltatol) return 1; 207*fbe28522SBarry Smith if (neP->itflag) { 208*fbe28522SBarry Smith return SNESDefaultConverged( snes, xnorm, pnorm, fnorm,ctx ); 209*fbe28522SBarry Smith } 210*fbe28522SBarry Smith if (neP->delta < xnorm * epsmch) return -1; 2114800dd8cSBarry Smith return 0; 2124800dd8cSBarry Smith } 2134800dd8cSBarry Smith 214*fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes) 2154800dd8cSBarry Smith { 216*fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 217*fbe28522SBarry Smith double tmp; 2184800dd8cSBarry Smith 219*fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 220*fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 221*fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 222*fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 223*fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 224*fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 225*fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 226*fbe28522SBarry Smith return 0; 2274800dd8cSBarry Smith } 2284800dd8cSBarry Smith 229*fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes) 2304800dd8cSBarry Smith { 231*fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 232*fbe28522SBarry Smith char *prefix = "-"; 233*fbe28522SBarry Smith if (snes->prefix) prefix = snes->prefix; 234*fbe28522SBarry Smith fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 235*fbe28522SBarry Smith fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 236*fbe28522SBarry Smith fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 237*fbe28522SBarry Smith fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 238*fbe28522SBarry Smith fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 239*fbe28522SBarry Smith fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 240*fbe28522SBarry Smith fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 241*fbe28522SBarry Smith return 0; 2424800dd8cSBarry Smith } 2434800dd8cSBarry Smith 244*fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 2454800dd8cSBarry Smith { 246*fbe28522SBarry Smith SNES_TR *neP; 2474800dd8cSBarry Smith 248*fbe28522SBarry Smith snes->type = SNES_NTR; 249*fbe28522SBarry Smith snes->Setup = SNESSetUp_TR; 250*fbe28522SBarry Smith snes->Solver = SNESSolve_TR; 251*fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 252*fbe28522SBarry Smith snes->Monitor = 0; 253*fbe28522SBarry Smith snes->Converged = SNESTRDefaultConverged; 254*fbe28522SBarry Smith snes->PrintHelp = SNESPrintHelp_TR; 255*fbe28522SBarry Smith snes->SetFromOptions = SNESSetFromOptions_TR; 256*fbe28522SBarry Smith 257*fbe28522SBarry Smith neP = NEW(SNES_TR); CHKPTR(neP); 258*fbe28522SBarry Smith snes->data = (void *) neP; 259*fbe28522SBarry Smith neP->mu = 0.25; 260*fbe28522SBarry Smith neP->eta = 0.75; 261*fbe28522SBarry Smith neP->delta = 0.0; 262*fbe28522SBarry Smith neP->delta0 = 0.2; 263*fbe28522SBarry Smith neP->delta1 = 0.3; 264*fbe28522SBarry Smith neP->delta2 = 0.75; 265*fbe28522SBarry Smith neP->delta3 = 2.0; 266*fbe28522SBarry Smith neP->sigma = 0.0001; 267*fbe28522SBarry Smith neP->itflag = 0; 2684800dd8cSBarry Smith } 269