14800dd8cSBarry Smith #ifndef lint 2*39e2f89bSBarry Smith static char vcid[] = "$Id: tr.c,v 1.5 1995/05/02 16:06:34 bsmith Exp bsmith $"; 34800dd8cSBarry Smith #endif 44800dd8cSBarry Smith 54800dd8cSBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "tr.h" 74800dd8cSBarry Smith 8eafb4bcbSBarry Smith 9fbe28522SBarry Smith /* 10*39e2f89bSBarry 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; 3123242f5aSBarry 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 */ 42*39e2f89bSBarry Smith F = snes->vec_func; /* 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 6123242f5aSBarry Smith (*snes->ComputeJacobian)(snes,X,&snes->jacobian,&snes->jacobian_pre, 6223242f5aSBarry Smith &flg,snes->jacP); 6323242f5aSBarry 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; 108*39e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 109*39e2f89bSBarry Smith TMP = X; X = Y;snes->vec_sol_always = X; 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 */ 116*39e2f89bSBarry Smith if (X != snes->vec_sol) { 117*39e2f89bSBarry Smith VecCopy(X, snes->vec_sol ); 118*39e2f89bSBarry Smith snes->vec_sol_always = snes->vec_sol; 119*39e2f89bSBarry Smith snes->vec_func_always = snes->vec_func; 120*39e2f89bSBarry Smith } 1214800dd8cSBarry Smith break; 1224800dd8cSBarry Smith } 1234800dd8cSBarry Smith } 124fbe28522SBarry Smith if (i == maxits) *its = i-1; else *its = i; 125fbe28522SBarry Smith return 0; 1264800dd8cSBarry Smith } 1274800dd8cSBarry Smith /* -------------------------------------------------------------*/ 1284800dd8cSBarry Smith 1294800dd8cSBarry Smith /*------------------------------------------------------------*/ 130fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes ) 1314800dd8cSBarry Smith { 132fbe28522SBarry Smith int ierr; 1336b5873e3SBarry Smith snes->nwork = 3; 134fbe28522SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERR(ierr); 135fbe28522SBarry Smith return 0; 1364800dd8cSBarry Smith } 1374800dd8cSBarry Smith /*------------------------------------------------------------*/ 138fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj ) 1394800dd8cSBarry Smith { 140fbe28522SBarry Smith SNES snes = (SNES) obj; 141fbe28522SBarry Smith VecFreeVecs(snes->work, snes->nwork ); 142fbe28522SBarry Smith return 0; 1434800dd8cSBarry Smith } 1444800dd8cSBarry Smith /*------------------------------------------------------------*/ 1454800dd8cSBarry Smith 1466b5873e3SBarry Smith #include "options.h" 147fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes) 1484800dd8cSBarry Smith { 149fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 150fbe28522SBarry Smith double tmp; 1514800dd8cSBarry Smith 152fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 153fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 154fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 155fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 156fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 157fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 158fbe28522SBarry Smith if (OptionsGetDouble(0,snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 159fbe28522SBarry Smith return 0; 1604800dd8cSBarry Smith } 1614800dd8cSBarry Smith 162fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes) 1634800dd8cSBarry Smith { 164fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 165fbe28522SBarry Smith char *prefix = "-"; 166fbe28522SBarry Smith if (snes->prefix) prefix = snes->prefix; 167fbe28522SBarry Smith fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 168fbe28522SBarry Smith fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 169fbe28522SBarry Smith fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 170fbe28522SBarry Smith fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 171fbe28522SBarry Smith fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 172fbe28522SBarry Smith fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 173fbe28522SBarry Smith fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 174fbe28522SBarry Smith return 0; 1754800dd8cSBarry Smith } 1764800dd8cSBarry Smith 177fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 1784800dd8cSBarry Smith { 179fbe28522SBarry Smith SNES_TR *neP; 1804800dd8cSBarry Smith 181fbe28522SBarry Smith snes->type = SNES_NTR; 182fbe28522SBarry Smith snes->Setup = SNESSetUp_TR; 183fbe28522SBarry Smith snes->Solver = SNESSolve_TR; 184fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 1856b5873e3SBarry Smith snes->Converged = SNESDefaultConverged; 186fbe28522SBarry Smith snes->PrintHelp = SNESPrintHelp_TR; 187fbe28522SBarry Smith snes->SetFromOptions = SNESSetFromOptions_TR; 188fbe28522SBarry Smith 189fbe28522SBarry Smith neP = NEW(SNES_TR); CHKPTR(neP); 190fbe28522SBarry Smith snes->data = (void *) neP; 191fbe28522SBarry Smith neP->mu = 0.25; 192fbe28522SBarry Smith neP->eta = 0.75; 193fbe28522SBarry Smith neP->delta = 0.0; 194fbe28522SBarry Smith neP->delta0 = 0.2; 195fbe28522SBarry Smith neP->delta1 = 0.3; 196fbe28522SBarry Smith neP->delta2 = 0.75; 197fbe28522SBarry Smith neP->delta3 = 2.0; 198fbe28522SBarry Smith neP->sigma = 0.0001; 199fbe28522SBarry Smith neP->itflag = 0; 2006b5873e3SBarry Smith return 0; 2014800dd8cSBarry Smith } 202