14800dd8cSBarry Smith #ifndef lint 2*6b5873e3SBarry Smith static char vcid[] = "$Id: tr.c,v 1.2 1995/04/13 14:42:39 bsmith Exp bsmith $"; 34800dd8cSBarry Smith #endif 44800dd8cSBarry Smith 54800dd8cSBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "tr.h" 74800dd8cSBarry Smith 8fbe28522SBarry Smith /* 9*6b5873e3SBarry Smith Implements Newton's Method with a simple trust region 104800dd8cSBarry Smith approach for solving systems of nonlinear equations. 114800dd8cSBarry Smith 124800dd8cSBarry Smith Input parameters: 13*6b5873e3SBarry Smith . nlP - nonlinear context obtained from SNESCreate() 144800dd8cSBarry Smith 154800dd8cSBarry Smith The basic algorithm is taken from "The Minpack Project", by More', 164800dd8cSBarry Smith Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development 174800dd8cSBarry Smith of Mathematical Software", Wayne Cowell, editor. See the examples 184800dd8cSBarry Smith in nonlin/examples. 19fbe28522SBarry Smith */ 204800dd8cSBarry Smith /* 214800dd8cSBarry Smith This is intended as a model implementation, since it does not 224800dd8cSBarry Smith necessarily have many of the bells and whistles of other 234800dd8cSBarry Smith implementations. 244800dd8cSBarry Smith 254800dd8cSBarry Smith */ 26fbe28522SBarry Smith static int SNESSolve_TR(SNES snes, int *its ) 274800dd8cSBarry Smith { 28fbe28522SBarry Smith SNES_TR *neP = (SNES_TR *) snes->data; 29*6b5873e3SBarry Smith Vec X, F, Y, G, TMP, Ytmp; 30*6b5873e3SBarry Smith int maxits, i, history_len, nlconv,ierr,lits; 31fbe28522SBarry Smith double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm; 324800dd8cSBarry Smith double *history, ynorm; 33fbe28522SBarry Smith Scalar one = 1.0; 34*6b5873e3SBarry Smith double epsmch = 1.0e-14; /* This must be fixed */ 354800dd8cSBarry Smith 364800dd8cSBarry Smith nlconv = 0; /* convergence monitor */ 37fbe28522SBarry Smith history = snes->conv_hist; /* convergence history */ 38fbe28522SBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 39fbe28522SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 40fbe28522SBarry Smith X = snes->vec_sol; /* solution vector */ 41fbe28522SBarry Smith F = snes->vec_res; /* residual vector */ 42fbe28522SBarry Smith Y = snes->work[0]; /* work vectors */ 43fbe28522SBarry Smith G = snes->work[1]; 44*6b5873e3SBarry Smith Ytmp = snes->work[2]; 454800dd8cSBarry Smith 46fbe28522SBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr); /* X <- X_0 */ 47fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 484800dd8cSBarry Smith 49fbe28522SBarry Smith ierr = SNESComputeResidual(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */ 50fbe28522SBarry Smith VecNorm(F, &fnorm ); /* fnorm <- || F || */ 51fbe28522SBarry Smith snes->norm = fnorm; 524800dd8cSBarry Smith if (history && history_len > 0) history[0] = fnorm; 534800dd8cSBarry Smith delta = neP->delta0*fnorm; 544800dd8cSBarry Smith neP->delta = delta; 55fbe28522SBarry Smith if (snes->Monitor)(*snes->Monitor)(snes,0,X,F,fnorm,snes->monP); 564800dd8cSBarry Smith 574800dd8cSBarry Smith for ( i=0; i<maxits; i++ ) { 58fbe28522SBarry Smith snes->iter = i+1; 594800dd8cSBarry Smith 60fbe28522SBarry Smith (*snes->ComputeJacobian)(X,&snes->jacobian,snes->jacP); 61fbe28522SBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian,0); 62*6b5873e3SBarry Smith ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERR(ierr); 63*6b5873e3SBarry Smith VecNorm( Ytmp, &norm ); 64*6b5873e3SBarry Smith while(1) { 65*6b5873e3SBarry Smith VecCopy(Ytmp,Y); 66fbe28522SBarry Smith /* Scale Y if need be and predict new value of F norm */ 67*6b5873e3SBarry Smith 68fbe28522SBarry Smith if (norm > delta) { 69fbe28522SBarry Smith norm = delta/norm; 70fbe28522SBarry Smith gpnorm = (1.0 - norm)*fnorm; 71fbe28522SBarry Smith VecScale( &norm, Y ); 72fbe28522SBarry Smith PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm ); 73fbe28522SBarry Smith ynorm = delta; 74fbe28522SBarry Smith } else { 75fbe28522SBarry Smith gpnorm = 0.0; 76fbe28522SBarry Smith PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" ); 77fbe28522SBarry Smith ynorm = norm; 78fbe28522SBarry Smith } 79fbe28522SBarry Smith VecAXPY(&one, X, Y ); /* Y <- X + Y */ 80fbe28522SBarry Smith ierr = SNESComputeResidual(snes,Y,G); CHKERR(ierr); /* (+/-) F(X) */ 81fbe28522SBarry Smith VecNorm( G, &gnorm ); /* gnorm <- || g || */ 824800dd8cSBarry Smith if (fnorm == gpnorm) rho = 0.0; 83fbe28522SBarry Smith else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 844800dd8cSBarry Smith 854800dd8cSBarry Smith /* Update size of trust region */ 864800dd8cSBarry Smith if (rho < neP->mu) delta *= neP->delta1; 874800dd8cSBarry Smith else if (rho < neP->eta) delta *= neP->delta2; 884800dd8cSBarry Smith else delta *= neP->delta3; 894800dd8cSBarry Smith 90fbe28522SBarry Smith PLogInfo((PetscObject)snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 914800dd8cSBarry Smith i, fnorm, gnorm, ynorm ); 92fbe28522SBarry Smith PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 93fbe28522SBarry Smith gpnorm, rho, delta, lits); 944800dd8cSBarry Smith 954800dd8cSBarry Smith neP->delta = delta; 964800dd8cSBarry Smith if (rho > neP->sigma) break; 97*6b5873e3SBarry Smith /* check to see if progress is hopeless */ 98*6b5873e3SBarry Smith if (neP->delta < xnorm * epsmch) return -1; 99*6b5873e3SBarry Smith norm = delta; 1004800dd8cSBarry Smith } 1014800dd8cSBarry Smith fnorm = gnorm; 102fbe28522SBarry Smith snes->norm = fnorm; 1034800dd8cSBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 1044800dd8cSBarry Smith TMP = F; F = G; G = TMP; 1054800dd8cSBarry Smith TMP = X; X = Y; Y = TMP; 106fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 107fbe28522SBarry Smith if (snes->Monitor) (*snes->Monitor)(snes,0,X,F,fnorm,snes->monP); 1084800dd8cSBarry Smith 1094800dd8cSBarry Smith /* Test for convergence */ 110fbe28522SBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 1114800dd8cSBarry Smith /* Verify solution is in corect location */ 112fbe28522SBarry Smith if (X != snes->vec_sol) VecCopy(X, snes->vec_sol ); 1134800dd8cSBarry Smith break; 1144800dd8cSBarry Smith } 1154800dd8cSBarry Smith } 116fbe28522SBarry Smith if (i == maxits) *its = i-1; else *its = i; 117fbe28522SBarry Smith return 0; 1184800dd8cSBarry Smith } 1194800dd8cSBarry Smith /* -------------------------------------------------------------*/ 1204800dd8cSBarry Smith 1214800dd8cSBarry Smith /*------------------------------------------------------------*/ 122fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes ) 1234800dd8cSBarry Smith { 124fbe28522SBarry Smith int ierr; 125*6b5873e3SBarry Smith snes->nwork = 3; 126fbe28522SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERR(ierr); 127fbe28522SBarry Smith return 0; 1284800dd8cSBarry Smith } 1294800dd8cSBarry Smith /*------------------------------------------------------------*/ 130fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj ) 1314800dd8cSBarry Smith { 132fbe28522SBarry Smith SNES snes = (SNES) obj; 133fbe28522SBarry Smith VecFreeVecs(snes->work, snes->nwork ); 134fbe28522SBarry Smith return 0; 1354800dd8cSBarry Smith } 1364800dd8cSBarry Smith /*------------------------------------------------------------*/ 1374800dd8cSBarry Smith 138*6b5873e3SBarry Smith #include "options.h" 139fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes) 1404800dd8cSBarry Smith { 141fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 142fbe28522SBarry Smith double tmp; 1434800dd8cSBarry Smith 144fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 145fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 146fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 147fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 148fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 149fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 150fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 151fbe28522SBarry Smith return 0; 1524800dd8cSBarry Smith } 1534800dd8cSBarry Smith 154fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes) 1554800dd8cSBarry Smith { 156fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 157fbe28522SBarry Smith char *prefix = "-"; 158fbe28522SBarry Smith if (snes->prefix) prefix = snes->prefix; 159fbe28522SBarry Smith fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 160fbe28522SBarry Smith fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 161fbe28522SBarry Smith fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 162fbe28522SBarry Smith fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 163fbe28522SBarry Smith fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 164fbe28522SBarry Smith fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 165fbe28522SBarry Smith fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 166fbe28522SBarry Smith return 0; 1674800dd8cSBarry Smith } 1684800dd8cSBarry Smith 169fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 1704800dd8cSBarry Smith { 171fbe28522SBarry Smith SNES_TR *neP; 1724800dd8cSBarry Smith 173fbe28522SBarry Smith snes->type = SNES_NTR; 174fbe28522SBarry Smith snes->Setup = SNESSetUp_TR; 175fbe28522SBarry Smith snes->Solver = SNESSolve_TR; 176fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 177fbe28522SBarry Smith snes->Monitor = 0; 178*6b5873e3SBarry Smith snes->Converged = SNESDefaultConverged; 179fbe28522SBarry Smith snes->PrintHelp = SNESPrintHelp_TR; 180fbe28522SBarry Smith snes->SetFromOptions = SNESSetFromOptions_TR; 181fbe28522SBarry Smith 182fbe28522SBarry Smith neP = NEW(SNES_TR); CHKPTR(neP); 183fbe28522SBarry Smith snes->data = (void *) neP; 184fbe28522SBarry Smith neP->mu = 0.25; 185fbe28522SBarry Smith neP->eta = 0.75; 186fbe28522SBarry Smith neP->delta = 0.0; 187fbe28522SBarry Smith neP->delta0 = 0.2; 188fbe28522SBarry Smith neP->delta1 = 0.3; 189fbe28522SBarry Smith neP->delta2 = 0.75; 190fbe28522SBarry Smith neP->delta3 = 2.0; 191fbe28522SBarry Smith neP->sigma = 0.0001; 192fbe28522SBarry Smith neP->itflag = 0; 193*6b5873e3SBarry Smith return 0; 1944800dd8cSBarry Smith } 195