1 #ifndef lint 2 static char vcid[] = "$Id: tr.c,v 1.53 1996/03/26 00:10:17 curfman Exp bsmith $"; 3 #endif 4 5 #include <math.h> 6 #include "src/snes/impls/tr/tr.h" /*I "snes.h" I*/ 7 #include "pinclude/pviewer.h" 8 9 /* 10 This convergence test determines if the two norm of the 11 solution lies outside the trust region, if so it halts. 12 */ 13 int SNES_TR_KSPConverged_Private(KSP ksp,int n, double rnorm, void *ctx) 14 { 15 SNES snes = (SNES) ctx; 16 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 17 SNES_TR *neP = (SNES_TR*)snes->data; 18 Vec x; 19 double norm; 20 int ierr, convinfo; 21 22 if (snes->ksp_ewconv) { 23 if (!kctx) SETERRQ(1,"SNES_KSP_EW_Converged_Private:Convergence context does not exist"); 24 if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp); 25 kctx->lresid_last = rnorm; 26 } 27 convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx); 28 if (convinfo) { 29 PLogInfo(snes,"SNES: KSP iterations=%d, rnorm=%g\n",n,rnorm); 30 return convinfo; 31 } 32 33 /* Determine norm of solution */ 34 ierr = KSPBuildSolution(ksp,0,&x); CHKERRQ(ierr); 35 ierr = VecNorm(x,NORM_2,&norm); CHKERRQ(ierr); 36 if (norm >= neP->delta) { 37 PLogInfo(snes,"SNES: KSP iterations=%d, rnorm=%g\n",n,rnorm); 38 PLogInfo(snes, 39 "SNES: Ending linear iteration early, delta %g length %g\n",neP->delta,norm); 40 return 1; 41 } 42 return(0); 43 } 44 /* 45 SNESSolve_EQ_TR - Implements Newton's Method with a very simple trust 46 region approach for solving systems of nonlinear equations. 47 48 The basic algorithm is taken from "The Minpack Project", by More', 49 Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development 50 of Mathematical Software", Wayne Cowell, editor. 51 52 This is intended as a model implementation, since it does not 53 necessarily have many of the bells and whistles of other 54 implementations. 55 */ 56 static int SNESSolve_EQ_TR(SNES snes,int *its) 57 { 58 SNES_TR *neP = (SNES_TR *) snes->data; 59 Vec X, F, Y, G, TMP, Ytmp; 60 int maxits, i, history_len, ierr, lits; 61 MatStructure flg = DIFFERENT_NONZERO_PATTERN; 62 double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm,*history, ynorm; 63 Scalar mone = -1.0,cnorm; 64 KSP ksp; 65 SLES sles; 66 67 history = snes->conv_hist; /* convergence history */ 68 history_len = snes->conv_hist_len; /* convergence history length */ 69 maxits = snes->max_its; /* maximum number of iterations */ 70 X = snes->vec_sol; /* solution vector */ 71 F = snes->vec_func; /* residual vector */ 72 Y = snes->work[0]; /* work vectors */ 73 G = snes->work[1]; 74 Ytmp = snes->work[2]; 75 76 ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 77 78 ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* F(X) */ 79 ierr = VecNorm(F, NORM_2,&fnorm ); CHKERRQ(ierr); /* fnorm <- || F || */ 80 snes->norm = fnorm; 81 if (history && history_len > 0) history[0] = fnorm; 82 delta = neP->delta0*fnorm; 83 neP->delta = delta; 84 SNESMonitor(snes,0,fnorm); 85 86 /* set parameter for default relative tolerance convergence test */ 87 snes->ttol = fnorm*snes->rtol; 88 89 /* Set the stopping criteria to use the More' trick. */ 90 ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr); 91 ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr); 92 ierr = KSPSetConvergenceTest(ksp,SNES_TR_KSPConverged_Private,(void *)snes);CHKERRQ(ierr); 93 94 for ( i=0; i<maxits; i++ ) { 95 snes->iter = i+1; 96 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 97 ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 98 ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERRQ(ierr); 99 ierr = VecNorm(Ytmp,NORM_2,&norm); CHKERRQ(ierr); 100 while(1) { 101 ierr = VecCopy(Ytmp,Y); CHKERRQ(ierr); 102 /* Scale Y if need be and predict new value of F norm */ 103 104 if (norm >= delta) { 105 norm = delta/norm; 106 gpnorm = (1.0 - norm)*fnorm; 107 cnorm = norm; 108 PLogInfo(snes, "Scaling direction by %g \n",norm ); 109 ierr = VecScale(&cnorm,Y); CHKERRQ(ierr); 110 norm = gpnorm; 111 ynorm = delta; 112 } else { 113 gpnorm = 0.0; 114 PLogInfo(snes,"Direction is in Trust Region \n" ); 115 ynorm = norm; 116 } 117 ierr = VecAYPX(&mone,X,Y); CHKERRQ(ierr); /* Y <- X + Y */ 118 ierr = VecCopy(X,snes->vec_sol_update_always); CHKERRQ(ierr); 119 ierr = SNESComputeFunction(snes,Y,G); CHKERRQ(ierr); /* F(X) */ 120 ierr = VecNorm(G,NORM_2,&gnorm); CHKERRQ(ierr); /* gnorm <- || g || */ 121 if (fnorm == gpnorm) rho = 0.0; 122 else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 123 124 /* Update size of trust region */ 125 if (rho < neP->mu) delta *= neP->delta1; 126 else if (rho < neP->eta) delta *= neP->delta2; 127 else delta *= neP->delta3; 128 PLogInfo(snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 129 i, fnorm, gnorm, ynorm ); 130 PLogInfo(snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 131 gpnorm, rho, delta, lits); 132 neP->delta = delta; 133 if (rho > neP->sigma) break; 134 PLogInfo(snes,"Trying again in smaller region\n"); 135 /* check to see if progress is hopeless */ 136 neP->itflag = 0; 137 if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) { 138 /* We're not progressing, so return with the current iterate */ 139 if (X != snes->vec_sol) { 140 ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr); 141 snes->vec_sol_always = snes->vec_sol; 142 snes->vec_func_always = snes->vec_func; 143 } 144 } 145 snes->nfailures++; 146 } 147 fnorm = gnorm; 148 snes->norm = fnorm; 149 if (history && history_len > i+1) history[i+1] = fnorm; 150 TMP = F; F = G; snes->vec_func_always = F; G = TMP; 151 TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 152 VecNorm(X, NORM_2,&xnorm ); /* xnorm = || X || */ 153 SNESMonitor(snes,i+1,fnorm); 154 155 /* Test for convergence */ 156 neP->itflag = 1; 157 if ((*snes->converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 158 /* Verify solution is in corect location */ 159 if (X != snes->vec_sol) { 160 ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr); 161 snes->vec_sol_always = snes->vec_sol; 162 snes->vec_func_always = snes->vec_func; 163 } 164 break; 165 } 166 } 167 if (i == maxits) { 168 PLogInfo(snes,"Maximum number of iterations has been reached: %d\n",maxits); 169 i--; 170 } 171 *its = i+1; 172 return 0; 173 } 174 /*------------------------------------------------------------*/ 175 static int SNESSetUp_EQ_TR( SNES snes ) 176 { 177 int ierr; 178 snes->nwork = 4; 179 ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERRQ(ierr); 180 PLogObjectParents(snes,snes->nwork,snes->work); 181 snes->vec_sol_update_always = snes->work[3]; 182 return 0; 183 } 184 /*------------------------------------------------------------*/ 185 static int SNESDestroy_EQ_TR(PetscObject obj ) 186 { 187 SNES snes = (SNES) obj; 188 int ierr; 189 ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr); 190 PetscFree(snes->data); 191 return 0; 192 } 193 /*------------------------------------------------------------*/ 194 195 static int SNESSetFromOptions_EQ_TR(SNES snes) 196 { 197 SNES_TR *ctx = (SNES_TR *)snes->data; 198 double tmp; 199 int ierr,flg; 200 201 ierr = OptionsGetDouble(snes->prefix,"-mu",&tmp, &flg); CHKERRQ(ierr); 202 if (flg) {ctx->mu = tmp;} 203 ierr = OptionsGetDouble(snes->prefix,"-eta",&tmp, &flg); CHKERRQ(ierr); 204 if (flg) {ctx->eta = tmp;} 205 ierr = OptionsGetDouble(snes->prefix,"-sigma",&tmp, &flg); CHKERRQ(ierr); 206 if (flg) {ctx->sigma = tmp;} 207 ierr = OptionsGetDouble(snes->prefix,"-delta0",&tmp, &flg); CHKERRQ(ierr); 208 if (flg) {ctx->delta0 = tmp;} 209 ierr = OptionsGetDouble(snes->prefix,"-delta1",&tmp, &flg); CHKERRQ(ierr); 210 if (flg) {ctx->delta1 = tmp;} 211 ierr = OptionsGetDouble(snes->prefix,"-delta2",&tmp, &flg); CHKERRQ(ierr); 212 if (flg) {ctx->delta2 = tmp;} 213 ierr = OptionsGetDouble(snes->prefix,"-delta3",&tmp, &flg); CHKERRQ(ierr); 214 if (flg) {ctx->delta3 = tmp;} 215 return 0; 216 } 217 218 static int SNESPrintHelp_EQ_TR(SNES snes,char *p) 219 { 220 SNES_TR *ctx = (SNES_TR *)snes->data; 221 222 PetscFPrintf(snes->comm,stdout," method SNES_EQ_TR (tr) for systems of nonlinear equations:\n"); 223 PetscFPrintf(snes->comm,stdout," %ssnes_trust_region_mu <mu> (default %g)\n",p,ctx->mu); 224 PetscFPrintf(snes->comm,stdout," %ssnes_trust_region_eta <eta> (default %g)\n",p,ctx->eta); 225 PetscFPrintf(snes->comm,stdout," %ssnes_trust_region_sigma <sigma> (default %g)\n",p,ctx->sigma); 226 PetscFPrintf(snes->comm,stdout," %ssnes_trust_region_delta0 <delta0> (default %g)\n",p,ctx->delta0); 227 PetscFPrintf(snes->comm,stdout," %ssnes_trust_region_delta1 <delta1> (default %g)\n",p,ctx->delta1); 228 PetscFPrintf(snes->comm,stdout," %ssnes_trust_region_delta2 <delta2> (default %g)\n",p,ctx->delta2); 229 PetscFPrintf(snes->comm,stdout," %ssnes_trust_region_delta3 <delta3> (default %g)\n",p,ctx->delta3); 230 return 0; 231 } 232 233 static int SNESView_EQ_TR(PetscObject obj,Viewer viewer) 234 { 235 SNES snes = (SNES)obj; 236 SNES_TR *tr = (SNES_TR *)snes->data; 237 FILE *fd; 238 int ierr; 239 ViewerType vtype; 240 241 ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 242 if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 243 ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 244 PetscFPrintf(snes->comm,fd," mu=%g, eta=%g, sigma=%g\n",tr->mu,tr->eta,tr->sigma); 245 PetscFPrintf(snes->comm,fd," delta0=%g, delta1=%g, delta2=%g, delta3=%g\n", 246 tr->delta0,tr->delta1,tr->delta2,tr->delta3); 247 } 248 return 0; 249 } 250 251 /* ---------------------------------------------------------------- */ 252 /*@ 253 SNESConverged_EQ_TR - Default test for monitoring the convergence of the 254 trust region method SNES_EQ_TR for solving systems of nonlinear equations. 255 256 Input Parameters: 257 . snes - the SNES context 258 . xnorm - 2-norm of current iterate 259 . pnorm - 2-norm of current step 260 . fnorm - 2-norm of function 261 . dummy - unused context 262 263 Returns: 264 $ 1 if ( delta < xnorm*deltatol ), 265 $ 2 if ( fnorm < atol ), 266 $ 3 if ( pnorm < xtol*xnorm ), 267 $ -2 if ( nfct > maxf ), 268 $ -1 if ( delta < xnorm*epsmch ), 269 $ 0 otherwise, 270 271 where 272 $ delta - trust region paramenter 273 $ deltatol - trust region size tolerance, 274 $ set with SNESSetTrustRegionTolerance() 275 $ maxf - maximum number of function evaluations, 276 $ set with SNESSetTolerances() 277 $ nfct - number of function evaluations, 278 $ atol - absolute function norm tolerance, 279 $ set with SNESSetTolerances() 280 $ xtol - relative function norm tolerance, 281 $ set with SNESSetTolerances() 282 283 .keywords: SNES, nonlinear, default, converged, convergence 284 285 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged() 286 @*/ 287 int SNESConverged_EQ_TR(SNES snes,double xnorm,double pnorm,double fnorm,void *dummy) 288 { 289 SNES_TR *neP = (SNES_TR *)snes->data; 290 double epsmch = 1.0e-14; /* This must be fixed */ 291 int info; 292 293 if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 294 SETERRQ(1,"SNESConverged_EQ_LS:For SNES_NONLINEAR_EQUATIONS only"); 295 296 if (neP->delta < xnorm * snes->deltatol) { 297 PLogInfo(snes, 298 "SNES: Converged due to trust region param %g<%g*%g\n",neP->delta,xnorm,snes->deltatol); 299 return 1; 300 } 301 if (neP->itflag) { 302 info = SNESConverged_EQ_LS(snes,xnorm,pnorm,fnorm,dummy); 303 if (info) return info; 304 } 305 if (neP->delta < xnorm * epsmch) { 306 PLogInfo(snes, 307 "SNES: Converged due to trust region param %g < %g * %g\n",neP->delta,xnorm, epsmch); 308 return -1; 309 } 310 return 0; 311 } 312 /* ------------------------------------------------------------ */ 313 int SNESCreate_EQ_TR(SNES snes ) 314 { 315 SNES_TR *neP; 316 317 if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 318 SETERRQ(1,"SNESCreate_EQ_TR:For SNES_NONLINEAR_EQUATIONS only"); 319 snes->type = SNES_EQ_TR; 320 snes->setup = SNESSetUp_EQ_TR; 321 snes->solve = SNESSolve_EQ_TR; 322 snes->destroy = SNESDestroy_EQ_TR; 323 snes->converged = SNESConverged_EQ_TR; 324 snes->printhelp = SNESPrintHelp_EQ_TR; 325 snes->setfromoptions = SNESSetFromOptions_EQ_TR; 326 snes->view = SNESView_EQ_TR; 327 328 neP = PetscNew(SNES_TR); CHKPTRQ(neP); 329 PLogObjectMemory(snes,sizeof(SNES_TR)); 330 snes->data = (void *) neP; 331 neP->mu = 0.25; 332 neP->eta = 0.75; 333 neP->delta = 0.0; 334 neP->delta0 = 0.2; 335 neP->delta1 = 0.3; 336 neP->delta2 = 0.75; 337 neP->delta3 = 2.0; 338 neP->sigma = 0.0001; 339 neP->itflag = 0; 340 neP->rnorm0 = 0; 341 neP->ttol = 0; 342 return 0; 343 } 344