14800dd8cSBarry Smith #ifndef lint 2*edd2f0e1SBarry Smith static char vcid[] = "$Id: tr.c,v 1.7 1995/05/12 04:18:49 bsmith Exp bsmith $"; 34800dd8cSBarry Smith #endif 44800dd8cSBarry Smith 54800dd8cSBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "tr.h" 74800dd8cSBarry Smith 8eafb4bcbSBarry Smith 9fbe28522SBarry Smith /* 1039e2f89bSBarry Smith Implements Newton's Method with a very 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*edd2f0e1SBarry Smith int maxits, i, history_len, nlconv,ierr,lits; 32*edd2f0e1SBarry Smith MatStructure flg; 33fbe28522SBarry Smith double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm; 344800dd8cSBarry Smith double *history, ynorm; 35eafb4bcbSBarry Smith Scalar one = 1.0,cnorm; 366b5873e3SBarry Smith double epsmch = 1.0e-14; /* This must be fixed */ 374800dd8cSBarry Smith 384800dd8cSBarry Smith nlconv = 0; /* convergence monitor */ 39fbe28522SBarry Smith history = snes->conv_hist; /* convergence history */ 40fbe28522SBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 41fbe28522SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 42fbe28522SBarry Smith X = snes->vec_sol; /* solution vector */ 4339e2f89bSBarry Smith F = snes->vec_func; /* residual vector */ 44fbe28522SBarry Smith Y = snes->work[0]; /* work vectors */ 45fbe28522SBarry Smith G = snes->work[1]; 466b5873e3SBarry Smith Ytmp = snes->work[2]; 474800dd8cSBarry Smith 48fbe28522SBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr); /* X <- X_0 */ 49fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 504800dd8cSBarry Smith 51eafb4bcbSBarry Smith ierr = SNESComputeFunction(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */ 52fbe28522SBarry Smith VecNorm(F, &fnorm ); /* fnorm <- || F || */ 53fbe28522SBarry Smith snes->norm = fnorm; 544800dd8cSBarry Smith if (history && history_len > 0) history[0] = fnorm; 554800dd8cSBarry Smith delta = neP->delta0*fnorm; 564800dd8cSBarry Smith neP->delta = delta; 57eafb4bcbSBarry Smith if (snes->Monitor)(*snes->Monitor)(snes,0,fnorm,snes->monP); 584800dd8cSBarry Smith 594800dd8cSBarry Smith for ( i=0; i<maxits; i++ ) { 60fbe28522SBarry Smith snes->iter = i+1; 614800dd8cSBarry Smith 6223242f5aSBarry Smith (*snes->ComputeJacobian)(snes,X,&snes->jacobian,&snes->jacobian_pre, 6323242f5aSBarry Smith &flg,snes->jacP); 6423242f5aSBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); 656b5873e3SBarry Smith ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERR(ierr); 666b5873e3SBarry Smith VecNorm( Ytmp, &norm ); 676b5873e3SBarry Smith while(1) { 686b5873e3SBarry Smith VecCopy(Ytmp,Y); 69fbe28522SBarry Smith /* Scale Y if need be and predict new value of F norm */ 706b5873e3SBarry Smith 71eafb4bcbSBarry Smith if (norm >= delta) { 72fbe28522SBarry Smith norm = delta/norm; 73fbe28522SBarry Smith gpnorm = (1.0 - norm)*fnorm; 74eafb4bcbSBarry Smith cnorm = norm; 75eafb4bcbSBarry Smith VecScale( &cnorm, Y ); 76eafb4bcbSBarry Smith norm = gpnorm; 77fbe28522SBarry Smith PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm ); 78fbe28522SBarry Smith ynorm = delta; 79fbe28522SBarry Smith } else { 80fbe28522SBarry Smith gpnorm = 0.0; 81fbe28522SBarry Smith PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" ); 82fbe28522SBarry Smith ynorm = norm; 83fbe28522SBarry Smith } 84fbe28522SBarry Smith VecAXPY(&one, X, Y ); /* Y <- X + Y */ 85eafb4bcbSBarry Smith ierr = SNESComputeFunction(snes,Y,G); CHKERR(ierr); /* (+/-) F(X) */ 86fbe28522SBarry Smith VecNorm( G, &gnorm ); /* gnorm <- || g || */ 874800dd8cSBarry Smith if (fnorm == gpnorm) rho = 0.0; 88fbe28522SBarry Smith else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 894800dd8cSBarry Smith 904800dd8cSBarry Smith /* Update size of trust region */ 914800dd8cSBarry Smith if (rho < neP->mu) delta *= neP->delta1; 924800dd8cSBarry Smith else if (rho < neP->eta) delta *= neP->delta2; 934800dd8cSBarry Smith else delta *= neP->delta3; 944800dd8cSBarry Smith 95fbe28522SBarry Smith PLogInfo((PetscObject)snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 964800dd8cSBarry Smith i, fnorm, gnorm, ynorm ); 97fbe28522SBarry Smith PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 98fbe28522SBarry Smith gpnorm, rho, delta, lits); 994800dd8cSBarry Smith 1004800dd8cSBarry Smith neP->delta = delta; 1014800dd8cSBarry Smith if (rho > neP->sigma) break; 102eafb4bcbSBarry Smith PLogInfo((PetscObject)snes,"Trying again in smaller region\n"); 1036b5873e3SBarry Smith /* check to see if progress is hopeless */ 1046b5873e3SBarry Smith if (neP->delta < xnorm * epsmch) return -1; 1054800dd8cSBarry Smith } 1064800dd8cSBarry Smith fnorm = gnorm; 107fbe28522SBarry Smith snes->norm = fnorm; 1084800dd8cSBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 10939e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 11039e2f89bSBarry Smith TMP = X; X = Y;snes->vec_sol_always = X; Y = TMP; 111fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 112eafb4bcbSBarry Smith if (snes->Monitor) (*snes->Monitor)(snes,i,fnorm,snes->monP); 1134800dd8cSBarry Smith 1144800dd8cSBarry Smith /* Test for convergence */ 115fbe28522SBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 1164800dd8cSBarry Smith /* Verify solution is in corect location */ 11739e2f89bSBarry Smith if (X != snes->vec_sol) { 11839e2f89bSBarry Smith VecCopy(X, snes->vec_sol ); 11939e2f89bSBarry Smith snes->vec_sol_always = snes->vec_sol; 12039e2f89bSBarry Smith snes->vec_func_always = snes->vec_func; 12139e2f89bSBarry Smith } 1224800dd8cSBarry Smith break; 1234800dd8cSBarry Smith } 1244800dd8cSBarry Smith } 125fbe28522SBarry Smith if (i == maxits) *its = i-1; else *its = i; 126fbe28522SBarry Smith return 0; 1274800dd8cSBarry Smith } 1284800dd8cSBarry Smith /* -------------------------------------------------------------*/ 1294800dd8cSBarry Smith 1304800dd8cSBarry Smith /*------------------------------------------------------------*/ 131fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes ) 1324800dd8cSBarry Smith { 133fbe28522SBarry Smith int ierr; 1346b5873e3SBarry Smith snes->nwork = 3; 135fbe28522SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERR(ierr); 136fbe28522SBarry Smith return 0; 1374800dd8cSBarry Smith } 1384800dd8cSBarry Smith /*------------------------------------------------------------*/ 139fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj ) 1404800dd8cSBarry Smith { 141fbe28522SBarry Smith SNES snes = (SNES) obj; 142fbe28522SBarry Smith VecFreeVecs(snes->work, snes->nwork ); 143fbe28522SBarry Smith return 0; 1444800dd8cSBarry Smith } 1454800dd8cSBarry Smith /*------------------------------------------------------------*/ 1464800dd8cSBarry Smith 1476b5873e3SBarry Smith #include "options.h" 148fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes) 1494800dd8cSBarry Smith { 150fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 151fbe28522SBarry Smith double tmp; 1524800dd8cSBarry Smith 153fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 154fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 155fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 156fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 157fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 158fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 159fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 160fbe28522SBarry Smith return 0; 1614800dd8cSBarry Smith } 1624800dd8cSBarry Smith 163fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes) 1644800dd8cSBarry Smith { 165fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 166fbe28522SBarry Smith char *prefix = "-"; 167fbe28522SBarry Smith if (snes->prefix) prefix = snes->prefix; 168fbe28522SBarry Smith fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 169fbe28522SBarry Smith fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 170fbe28522SBarry Smith fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 171fbe28522SBarry Smith fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 172fbe28522SBarry Smith fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 173fbe28522SBarry Smith fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 174fbe28522SBarry Smith fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 175fbe28522SBarry Smith return 0; 1764800dd8cSBarry Smith } 1774800dd8cSBarry Smith 178fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 1794800dd8cSBarry Smith { 180fbe28522SBarry Smith SNES_TR *neP; 1814800dd8cSBarry Smith 182fbe28522SBarry Smith snes->type = SNES_NTR; 18306be10caSBarry Smith snes->setup = SNESSetUp_TR; 18406be10caSBarry Smith snes->solve = SNESSolve_TR; 185fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 1866b5873e3SBarry Smith snes->Converged = SNESDefaultConverged; 18706be10caSBarry Smith snes->printhelp = SNESPrintHelp_TR; 18806be10caSBarry Smith snes->setfromoptions = SNESSetFromOptions_TR; 189fbe28522SBarry Smith 190fbe28522SBarry Smith neP = NEW(SNES_TR); CHKPTR(neP); 191fbe28522SBarry Smith snes->data = (void *) neP; 192fbe28522SBarry Smith neP->mu = 0.25; 193fbe28522SBarry Smith neP->eta = 0.75; 194fbe28522SBarry Smith neP->delta = 0.0; 195fbe28522SBarry Smith neP->delta0 = 0.2; 196fbe28522SBarry Smith neP->delta1 = 0.3; 197fbe28522SBarry Smith neP->delta2 = 0.75; 198fbe28522SBarry Smith neP->delta3 = 2.0; 199fbe28522SBarry Smith neP->sigma = 0.0001; 200fbe28522SBarry Smith neP->itflag = 0; 2016b5873e3SBarry Smith return 0; 2024800dd8cSBarry Smith } 203