1 #ifndef lint 2 static char vcid[] = "$Id: tr.c,v 1.4 1995/04/19 03:01:26 bsmith Exp bsmith $"; 3 #endif 4 5 #include <math.h> 6 #include "tr.h" 7 8 9 /* 10 Implements Newton's Method with a simple trust region 11 approach for solving systems of nonlinear equations. 12 13 Input parameters: 14 . nlP - nonlinear context obtained from SNESCreate() 15 16 The basic algorithm is taken from "The Minpack Project", by More', 17 Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development 18 of Mathematical Software", Wayne Cowell, editor. See the examples 19 in nonlin/examples. 20 */ 21 /* 22 This is intended as a model implementation, since it does not 23 necessarily have many of the bells and whistles of other 24 implementations. 25 26 */ 27 static int SNESSolve_TR(SNES snes, int *its ) 28 { 29 SNES_TR *neP = (SNES_TR *) snes->data; 30 Vec X, F, Y, G, TMP, Ytmp; 31 int maxits, i, history_len, nlconv,ierr,lits, flg; 32 double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm; 33 double *history, ynorm; 34 Scalar one = 1.0,cnorm; 35 double epsmch = 1.0e-14; /* This must be fixed */ 36 37 nlconv = 0; /* convergence monitor */ 38 history = snes->conv_hist; /* convergence history */ 39 history_len = snes->conv_hist_len; /* convergence history length */ 40 maxits = snes->max_its; /* maximum number of iterations */ 41 X = snes->vec_sol; /* solution vector */ 42 F = snes->vec_res; /* residual vector */ 43 Y = snes->work[0]; /* work vectors */ 44 G = snes->work[1]; 45 Ytmp = snes->work[2]; 46 47 ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr); /* X <- X_0 */ 48 VecNorm(X, &xnorm ); /* xnorm = || X || */ 49 50 ierr = SNESComputeFunction(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */ 51 VecNorm(F, &fnorm ); /* fnorm <- || F || */ 52 snes->norm = fnorm; 53 if (history && history_len > 0) history[0] = fnorm; 54 delta = neP->delta0*fnorm; 55 neP->delta = delta; 56 if (snes->Monitor)(*snes->Monitor)(snes,0,fnorm,snes->monP); 57 58 for ( i=0; i<maxits; i++ ) { 59 snes->iter = i+1; 60 61 (*snes->ComputeJacobian)(snes,X,&snes->jacobian,&snes->jacobian_pre, 62 &flg,snes->jacP); 63 ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); 64 ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERR(ierr); 65 VecNorm( Ytmp, &norm ); 66 while(1) { 67 VecCopy(Ytmp,Y); 68 /* Scale Y if need be and predict new value of F norm */ 69 70 if (norm >= delta) { 71 norm = delta/norm; 72 gpnorm = (1.0 - norm)*fnorm; 73 cnorm = norm; 74 VecScale( &cnorm, Y ); 75 norm = gpnorm; 76 PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm ); 77 ynorm = delta; 78 } else { 79 gpnorm = 0.0; 80 PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" ); 81 ynorm = norm; 82 } 83 VecAXPY(&one, X, Y ); /* Y <- X + Y */ 84 ierr = SNESComputeFunction(snes,Y,G); CHKERR(ierr); /* (+/-) F(X) */ 85 VecNorm( G, &gnorm ); /* gnorm <- || g || */ 86 if (fnorm == gpnorm) rho = 0.0; 87 else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 88 89 /* Update size of trust region */ 90 if (rho < neP->mu) delta *= neP->delta1; 91 else if (rho < neP->eta) delta *= neP->delta2; 92 else delta *= neP->delta3; 93 94 PLogInfo((PetscObject)snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 95 i, fnorm, gnorm, ynorm ); 96 PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 97 gpnorm, rho, delta, lits); 98 99 neP->delta = delta; 100 if (rho > neP->sigma) break; 101 PLogInfo((PetscObject)snes,"Trying again in smaller region\n"); 102 /* check to see if progress is hopeless */ 103 if (neP->delta < xnorm * epsmch) return -1; 104 } 105 fnorm = gnorm; 106 snes->norm = fnorm; 107 if (history && history_len > i+1) history[i+1] = fnorm; 108 TMP = F; F = G; G = TMP; 109 TMP = X; X = Y; Y = TMP; 110 VecNorm(X, &xnorm ); /* xnorm = || X || */ 111 if (snes->Monitor) (*snes->Monitor)(snes,i,fnorm,snes->monP); 112 113 /* Test for convergence */ 114 if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 115 /* Verify solution is in corect location */ 116 if (X != snes->vec_sol) VecCopy(X, snes->vec_sol ); 117 break; 118 } 119 } 120 if (i == maxits) *its = i-1; else *its = i; 121 return 0; 122 } 123 /* -------------------------------------------------------------*/ 124 125 /*------------------------------------------------------------*/ 126 static int SNESSetUp_TR( SNES snes ) 127 { 128 int ierr; 129 snes->nwork = 3; 130 ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERR(ierr); 131 return 0; 132 } 133 /*------------------------------------------------------------*/ 134 static int SNESDestroy_TR(PetscObject obj ) 135 { 136 SNES snes = (SNES) obj; 137 VecFreeVecs(snes->work, snes->nwork ); 138 return 0; 139 } 140 /*------------------------------------------------------------*/ 141 142 #include "options.h" 143 static int SNESSetFromOptions_TR(SNES snes) 144 { 145 SNES_TR *ctx = (SNES_TR *)snes->data; 146 double tmp; 147 148 if (OptionsGetDouble(0,snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 149 if (OptionsGetDouble(0,snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 150 if (OptionsGetDouble(0,snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 151 if (OptionsGetDouble(0,snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 152 if (OptionsGetDouble(0,snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 153 if (OptionsGetDouble(0,snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 154 if (OptionsGetDouble(0,snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 155 return 0; 156 } 157 158 static int SNESPrintHelp_TR(SNES snes) 159 { 160 SNES_TR *ctx = (SNES_TR *)snes->data; 161 char *prefix = "-"; 162 if (snes->prefix) prefix = snes->prefix; 163 fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 164 fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 165 fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 166 fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 167 fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 168 fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 169 fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 170 return 0; 171 } 172 173 int SNESCreate_TR(SNES snes ) 174 { 175 SNES_TR *neP; 176 177 snes->type = SNES_NTR; 178 snes->Setup = SNESSetUp_TR; 179 snes->Solver = SNESSolve_TR; 180 snes->destroy = SNESDestroy_TR; 181 snes->Converged = SNESDefaultConverged; 182 snes->PrintHelp = SNESPrintHelp_TR; 183 snes->SetFromOptions = SNESSetFromOptions_TR; 184 185 neP = NEW(SNES_TR); CHKPTR(neP); 186 snes->data = (void *) neP; 187 neP->mu = 0.25; 188 neP->eta = 0.75; 189 neP->delta = 0.0; 190 neP->delta0 = 0.2; 191 neP->delta1 = 0.3; 192 neP->delta2 = 0.75; 193 neP->delta3 = 2.0; 194 neP->sigma = 0.0001; 195 neP->itflag = 0; 196 return 0; 197 } 198