14800dd8cSBarry Smith #ifndef lint 2*eafb4bcbSBarry Smith static char vcid[] = "$Id: tr.c,v 1.3 1995/04/15 03:29:42 bsmith Exp bsmith $"; 34800dd8cSBarry Smith #endif 44800dd8cSBarry Smith 54800dd8cSBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "tr.h" 74800dd8cSBarry Smith 8*eafb4bcbSBarry Smith 9fbe28522SBarry Smith /* 106b5873e3SBarry Smith Implements Newton's Method with a simple trust region 114800dd8cSBarry Smith approach for solving systems of nonlinear equations. 124800dd8cSBarry Smith 134800dd8cSBarry Smith Input parameters: 146b5873e3SBarry Smith . nlP - nonlinear context obtained from SNESCreate() 154800dd8cSBarry Smith 164800dd8cSBarry Smith The basic algorithm is taken from "The Minpack Project", by More', 174800dd8cSBarry Smith Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development 184800dd8cSBarry Smith of Mathematical Software", Wayne Cowell, editor. See the examples 194800dd8cSBarry Smith in nonlin/examples. 20fbe28522SBarry Smith */ 214800dd8cSBarry Smith /* 224800dd8cSBarry Smith This is intended as a model implementation, since it does not 234800dd8cSBarry Smith necessarily have many of the bells and whistles of other 244800dd8cSBarry Smith implementations. 254800dd8cSBarry Smith 264800dd8cSBarry Smith */ 27fbe28522SBarry Smith static int SNESSolve_TR(SNES snes, int *its ) 284800dd8cSBarry Smith { 29fbe28522SBarry Smith SNES_TR *neP = (SNES_TR *) snes->data; 306b5873e3SBarry Smith Vec X, F, Y, G, TMP, Ytmp; 316b5873e3SBarry Smith int maxits, i, history_len, nlconv,ierr,lits; 32fbe28522SBarry Smith double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm; 334800dd8cSBarry Smith double *history, ynorm; 34*eafb4bcbSBarry Smith Scalar one = 1.0,cnorm; 356b5873e3SBarry Smith double epsmch = 1.0e-14; /* This must be fixed */ 364800dd8cSBarry Smith 374800dd8cSBarry Smith nlconv = 0; /* convergence monitor */ 38fbe28522SBarry Smith history = snes->conv_hist; /* convergence history */ 39fbe28522SBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 40fbe28522SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 41fbe28522SBarry Smith X = snes->vec_sol; /* solution vector */ 42fbe28522SBarry Smith F = snes->vec_res; /* residual vector */ 43fbe28522SBarry Smith Y = snes->work[0]; /* work vectors */ 44fbe28522SBarry Smith G = snes->work[1]; 456b5873e3SBarry Smith Ytmp = snes->work[2]; 464800dd8cSBarry Smith 47fbe28522SBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr); /* X <- X_0 */ 48fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 494800dd8cSBarry Smith 50*eafb4bcbSBarry Smith ierr = SNESComputeFunction(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */ 51fbe28522SBarry Smith VecNorm(F, &fnorm ); /* fnorm <- || F || */ 52fbe28522SBarry Smith snes->norm = fnorm; 534800dd8cSBarry Smith if (history && history_len > 0) history[0] = fnorm; 544800dd8cSBarry Smith delta = neP->delta0*fnorm; 554800dd8cSBarry Smith neP->delta = delta; 56*eafb4bcbSBarry Smith if (snes->Monitor)(*snes->Monitor)(snes,0,fnorm,snes->monP); 574800dd8cSBarry Smith 584800dd8cSBarry Smith for ( i=0; i<maxits; i++ ) { 59fbe28522SBarry Smith snes->iter = i+1; 604800dd8cSBarry Smith 61fbe28522SBarry Smith (*snes->ComputeJacobian)(X,&snes->jacobian,snes->jacP); 62fbe28522SBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian,0); 636b5873e3SBarry Smith ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERR(ierr); 646b5873e3SBarry Smith VecNorm( Ytmp, &norm ); 656b5873e3SBarry Smith while(1) { 666b5873e3SBarry Smith VecCopy(Ytmp,Y); 67fbe28522SBarry Smith /* Scale Y if need be and predict new value of F norm */ 686b5873e3SBarry Smith 69*eafb4bcbSBarry Smith if (norm >= delta) { 70fbe28522SBarry Smith norm = delta/norm; 71fbe28522SBarry Smith gpnorm = (1.0 - norm)*fnorm; 72*eafb4bcbSBarry Smith cnorm = norm; 73*eafb4bcbSBarry Smith VecScale( &cnorm, Y ); 74*eafb4bcbSBarry Smith norm = gpnorm; 75fbe28522SBarry Smith PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm ); 76fbe28522SBarry Smith ynorm = delta; 77fbe28522SBarry Smith } else { 78fbe28522SBarry Smith gpnorm = 0.0; 79fbe28522SBarry Smith PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" ); 80fbe28522SBarry Smith ynorm = norm; 81fbe28522SBarry Smith } 82fbe28522SBarry Smith VecAXPY(&one, X, Y ); /* Y <- X + Y */ 83*eafb4bcbSBarry Smith ierr = SNESComputeFunction(snes,Y,G); CHKERR(ierr); /* (+/-) F(X) */ 84fbe28522SBarry Smith VecNorm( G, &gnorm ); /* gnorm <- || g || */ 854800dd8cSBarry Smith if (fnorm == gpnorm) rho = 0.0; 86fbe28522SBarry Smith else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 874800dd8cSBarry Smith 884800dd8cSBarry Smith /* Update size of trust region */ 894800dd8cSBarry Smith if (rho < neP->mu) delta *= neP->delta1; 904800dd8cSBarry Smith else if (rho < neP->eta) delta *= neP->delta2; 914800dd8cSBarry Smith else delta *= neP->delta3; 924800dd8cSBarry Smith 93fbe28522SBarry Smith PLogInfo((PetscObject)snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 944800dd8cSBarry Smith i, fnorm, gnorm, ynorm ); 95fbe28522SBarry Smith PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 96fbe28522SBarry Smith gpnorm, rho, delta, lits); 974800dd8cSBarry Smith 984800dd8cSBarry Smith neP->delta = delta; 994800dd8cSBarry Smith if (rho > neP->sigma) break; 100*eafb4bcbSBarry Smith PLogInfo((PetscObject)snes,"Trying again in smaller region\n"); 1016b5873e3SBarry Smith /* check to see if progress is hopeless */ 1026b5873e3SBarry Smith if (neP->delta < xnorm * epsmch) return -1; 1034800dd8cSBarry Smith } 1044800dd8cSBarry Smith fnorm = gnorm; 105fbe28522SBarry Smith snes->norm = fnorm; 1064800dd8cSBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 1074800dd8cSBarry Smith TMP = F; F = G; G = TMP; 1084800dd8cSBarry Smith TMP = X; X = Y; Y = TMP; 109fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 110*eafb4bcbSBarry Smith if (snes->Monitor) (*snes->Monitor)(snes,i,fnorm,snes->monP); 1114800dd8cSBarry Smith 1124800dd8cSBarry Smith /* Test for convergence */ 113fbe28522SBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 1144800dd8cSBarry Smith /* Verify solution is in corect location */ 115fbe28522SBarry Smith if (X != snes->vec_sol) VecCopy(X, snes->vec_sol ); 1164800dd8cSBarry Smith break; 1174800dd8cSBarry Smith } 1184800dd8cSBarry Smith } 119fbe28522SBarry Smith if (i == maxits) *its = i-1; else *its = i; 120fbe28522SBarry Smith return 0; 1214800dd8cSBarry Smith } 1224800dd8cSBarry Smith /* -------------------------------------------------------------*/ 1234800dd8cSBarry Smith 1244800dd8cSBarry Smith /*------------------------------------------------------------*/ 125fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes ) 1264800dd8cSBarry Smith { 127fbe28522SBarry Smith int ierr; 1286b5873e3SBarry Smith snes->nwork = 3; 129fbe28522SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERR(ierr); 130fbe28522SBarry Smith return 0; 1314800dd8cSBarry Smith } 1324800dd8cSBarry Smith /*------------------------------------------------------------*/ 133fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj ) 1344800dd8cSBarry Smith { 135fbe28522SBarry Smith SNES snes = (SNES) obj; 136fbe28522SBarry Smith VecFreeVecs(snes->work, snes->nwork ); 137fbe28522SBarry Smith return 0; 1384800dd8cSBarry Smith } 1394800dd8cSBarry Smith /*------------------------------------------------------------*/ 1404800dd8cSBarry Smith 1416b5873e3SBarry Smith #include "options.h" 142fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes) 1434800dd8cSBarry Smith { 144fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 145fbe28522SBarry Smith double tmp; 1464800dd8cSBarry Smith 147fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 148fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 149fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 150fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 151fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 152fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 153fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 154fbe28522SBarry Smith return 0; 1554800dd8cSBarry Smith } 1564800dd8cSBarry Smith 157fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes) 1584800dd8cSBarry Smith { 159fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 160fbe28522SBarry Smith char *prefix = "-"; 161fbe28522SBarry Smith if (snes->prefix) prefix = snes->prefix; 162fbe28522SBarry Smith fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 163fbe28522SBarry Smith fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 164fbe28522SBarry Smith fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 165fbe28522SBarry Smith fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 166fbe28522SBarry Smith fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 167fbe28522SBarry Smith fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 168fbe28522SBarry Smith fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 169fbe28522SBarry Smith return 0; 1704800dd8cSBarry Smith } 1714800dd8cSBarry Smith 172fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 1734800dd8cSBarry Smith { 174fbe28522SBarry Smith SNES_TR *neP; 1754800dd8cSBarry Smith 176fbe28522SBarry Smith snes->type = SNES_NTR; 177fbe28522SBarry Smith snes->Setup = SNESSetUp_TR; 178fbe28522SBarry Smith snes->Solver = SNESSolve_TR; 179fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 1806b5873e3SBarry Smith snes->Converged = SNESDefaultConverged; 181fbe28522SBarry Smith snes->PrintHelp = SNESPrintHelp_TR; 182fbe28522SBarry Smith snes->SetFromOptions = SNESSetFromOptions_TR; 183fbe28522SBarry Smith 184fbe28522SBarry Smith neP = NEW(SNES_TR); CHKPTR(neP); 185fbe28522SBarry Smith snes->data = (void *) neP; 186fbe28522SBarry Smith neP->mu = 0.25; 187fbe28522SBarry Smith neP->eta = 0.75; 188fbe28522SBarry Smith neP->delta = 0.0; 189fbe28522SBarry Smith neP->delta0 = 0.2; 190fbe28522SBarry Smith neP->delta1 = 0.3; 191fbe28522SBarry Smith neP->delta2 = 0.75; 192fbe28522SBarry Smith neP->delta3 = 2.0; 193fbe28522SBarry Smith neP->sigma = 0.0001; 194fbe28522SBarry Smith neP->itflag = 0; 1956b5873e3SBarry Smith return 0; 1964800dd8cSBarry Smith } 197