14800dd8cSBarry Smith #ifndef lint 2*23242f5aSBarry Smith static char vcid[] = "$Id: tr.c,v 1.4 1995/04/19 03:01:26 bsmith Exp bsmith $"; 34800dd8cSBarry Smith #endif 44800dd8cSBarry Smith 54800dd8cSBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "tr.h" 74800dd8cSBarry Smith 8eafb4bcbSBarry 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; 31*23242f5aSBarry Smith int maxits, i, history_len, nlconv,ierr,lits, flg; 32fbe28522SBarry Smith double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm; 334800dd8cSBarry Smith double *history, ynorm; 34eafb4bcbSBarry 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 50eafb4bcbSBarry 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; 56eafb4bcbSBarry 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 61*23242f5aSBarry Smith (*snes->ComputeJacobian)(snes,X,&snes->jacobian,&snes->jacobian_pre, 62*23242f5aSBarry Smith &flg,snes->jacP); 63*23242f5aSBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); 646b5873e3SBarry Smith ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERR(ierr); 656b5873e3SBarry Smith VecNorm( Ytmp, &norm ); 666b5873e3SBarry Smith while(1) { 676b5873e3SBarry Smith VecCopy(Ytmp,Y); 68fbe28522SBarry Smith /* Scale Y if need be and predict new value of F norm */ 696b5873e3SBarry Smith 70eafb4bcbSBarry Smith if (norm >= delta) { 71fbe28522SBarry Smith norm = delta/norm; 72fbe28522SBarry Smith gpnorm = (1.0 - norm)*fnorm; 73eafb4bcbSBarry Smith cnorm = norm; 74eafb4bcbSBarry Smith VecScale( &cnorm, Y ); 75eafb4bcbSBarry Smith norm = gpnorm; 76fbe28522SBarry Smith PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm ); 77fbe28522SBarry Smith ynorm = delta; 78fbe28522SBarry Smith } else { 79fbe28522SBarry Smith gpnorm = 0.0; 80fbe28522SBarry Smith PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" ); 81fbe28522SBarry Smith ynorm = norm; 82fbe28522SBarry Smith } 83fbe28522SBarry Smith VecAXPY(&one, X, Y ); /* Y <- X + Y */ 84eafb4bcbSBarry Smith ierr = SNESComputeFunction(snes,Y,G); CHKERR(ierr); /* (+/-) F(X) */ 85fbe28522SBarry Smith VecNorm( G, &gnorm ); /* gnorm <- || g || */ 864800dd8cSBarry Smith if (fnorm == gpnorm) rho = 0.0; 87fbe28522SBarry Smith else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 884800dd8cSBarry Smith 894800dd8cSBarry Smith /* Update size of trust region */ 904800dd8cSBarry Smith if (rho < neP->mu) delta *= neP->delta1; 914800dd8cSBarry Smith else if (rho < neP->eta) delta *= neP->delta2; 924800dd8cSBarry Smith else delta *= neP->delta3; 934800dd8cSBarry Smith 94fbe28522SBarry Smith PLogInfo((PetscObject)snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 954800dd8cSBarry Smith i, fnorm, gnorm, ynorm ); 96fbe28522SBarry Smith PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 97fbe28522SBarry Smith gpnorm, rho, delta, lits); 984800dd8cSBarry Smith 994800dd8cSBarry Smith neP->delta = delta; 1004800dd8cSBarry Smith if (rho > neP->sigma) break; 101eafb4bcbSBarry Smith PLogInfo((PetscObject)snes,"Trying again in smaller region\n"); 1026b5873e3SBarry Smith /* check to see if progress is hopeless */ 1036b5873e3SBarry Smith if (neP->delta < xnorm * epsmch) return -1; 1044800dd8cSBarry Smith } 1054800dd8cSBarry Smith fnorm = gnorm; 106fbe28522SBarry Smith snes->norm = fnorm; 1074800dd8cSBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 1084800dd8cSBarry Smith TMP = F; F = G; G = TMP; 1094800dd8cSBarry Smith TMP = X; X = Y; Y = TMP; 110fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 111eafb4bcbSBarry Smith if (snes->Monitor) (*snes->Monitor)(snes,i,fnorm,snes->monP); 1124800dd8cSBarry Smith 1134800dd8cSBarry Smith /* Test for convergence */ 114fbe28522SBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 1154800dd8cSBarry Smith /* Verify solution is in corect location */ 116fbe28522SBarry Smith if (X != snes->vec_sol) VecCopy(X, snes->vec_sol ); 1174800dd8cSBarry Smith break; 1184800dd8cSBarry Smith } 1194800dd8cSBarry Smith } 120fbe28522SBarry Smith if (i == maxits) *its = i-1; else *its = i; 121fbe28522SBarry Smith return 0; 1224800dd8cSBarry Smith } 1234800dd8cSBarry Smith /* -------------------------------------------------------------*/ 1244800dd8cSBarry Smith 1254800dd8cSBarry Smith /*------------------------------------------------------------*/ 126fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes ) 1274800dd8cSBarry Smith { 128fbe28522SBarry Smith int ierr; 1296b5873e3SBarry Smith snes->nwork = 3; 130fbe28522SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERR(ierr); 131fbe28522SBarry Smith return 0; 1324800dd8cSBarry Smith } 1334800dd8cSBarry Smith /*------------------------------------------------------------*/ 134fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj ) 1354800dd8cSBarry Smith { 136fbe28522SBarry Smith SNES snes = (SNES) obj; 137fbe28522SBarry Smith VecFreeVecs(snes->work, snes->nwork ); 138fbe28522SBarry Smith return 0; 1394800dd8cSBarry Smith } 1404800dd8cSBarry Smith /*------------------------------------------------------------*/ 1414800dd8cSBarry Smith 1426b5873e3SBarry Smith #include "options.h" 143fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes) 1444800dd8cSBarry Smith { 145fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 146fbe28522SBarry Smith double tmp; 1474800dd8cSBarry Smith 148fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 149fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 150fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 151fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 152fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 153fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 154fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 155fbe28522SBarry Smith return 0; 1564800dd8cSBarry Smith } 1574800dd8cSBarry Smith 158fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes) 1594800dd8cSBarry Smith { 160fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 161fbe28522SBarry Smith char *prefix = "-"; 162fbe28522SBarry Smith if (snes->prefix) prefix = snes->prefix; 163fbe28522SBarry Smith fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 164fbe28522SBarry Smith fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 165fbe28522SBarry Smith fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 166fbe28522SBarry Smith fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 167fbe28522SBarry Smith fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 168fbe28522SBarry Smith fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 169fbe28522SBarry Smith fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 170fbe28522SBarry Smith return 0; 1714800dd8cSBarry Smith } 1724800dd8cSBarry Smith 173fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 1744800dd8cSBarry Smith { 175fbe28522SBarry Smith SNES_TR *neP; 1764800dd8cSBarry Smith 177fbe28522SBarry Smith snes->type = SNES_NTR; 178fbe28522SBarry Smith snes->Setup = SNESSetUp_TR; 179fbe28522SBarry Smith snes->Solver = SNESSolve_TR; 180fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 1816b5873e3SBarry Smith snes->Converged = SNESDefaultConverged; 182fbe28522SBarry Smith snes->PrintHelp = SNESPrintHelp_TR; 183fbe28522SBarry Smith snes->SetFromOptions = SNESSetFromOptions_TR; 184fbe28522SBarry Smith 185fbe28522SBarry Smith neP = NEW(SNES_TR); CHKPTR(neP); 186fbe28522SBarry Smith snes->data = (void *) neP; 187fbe28522SBarry Smith neP->mu = 0.25; 188fbe28522SBarry Smith neP->eta = 0.75; 189fbe28522SBarry Smith neP->delta = 0.0; 190fbe28522SBarry Smith neP->delta0 = 0.2; 191fbe28522SBarry Smith neP->delta1 = 0.3; 192fbe28522SBarry Smith neP->delta2 = 0.75; 193fbe28522SBarry Smith neP->delta3 = 2.0; 194fbe28522SBarry Smith neP->sigma = 0.0001; 195fbe28522SBarry Smith neP->itflag = 0; 1966b5873e3SBarry Smith return 0; 1974800dd8cSBarry Smith } 198