1 /*$Id: snesut.c,v 1.65 2001/06/21 21:18:37 bsmith Exp bsmith $*/ 2 3 #include "src/snes/snesimpl.h" /*I "petscsnes.h" I*/ 4 5 #undef __FUNCT__ 6 #define __FUNCT__ "SNESVecViewMonitor" 7 /*@C 8 SNESVecViewMonitor - Monitors progress of the SNES solvers by calling 9 VecView() for the approximate solution at each iteration. 10 11 Collective on SNES 12 13 Input Parameters: 14 + snes - the SNES context 15 . its - iteration number 16 . fgnorm - 2-norm of residual (or gradient) 17 - dummy - either a viewer or PETSC_NULL 18 19 Level: intermediate 20 21 .keywords: SNES, nonlinear, vector, monitor, view 22 23 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView() 24 @*/ 25 int SNESVecViewMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy) 26 { 27 int ierr; 28 Vec x; 29 PetscViewer viewer = (PetscViewer) dummy; 30 31 PetscFunctionBegin; 32 ierr = SNESGetSolution(snes,&x);CHKERRQ(ierr); 33 if (!viewer) { 34 MPI_Comm comm; 35 ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr); 36 viewer = PETSC_VIEWER_DRAW_(comm); 37 } 38 ierr = VecView(x,viewer);CHKERRQ(ierr); 39 40 PetscFunctionReturn(0); 41 } 42 43 #undef __FUNCT__ 44 #define __FUNCT__ "SNESVecViewUpdateMonitor" 45 /*@C 46 SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling 47 VecView() for the UPDATE to the solution at each iteration. 48 49 Collective on SNES 50 51 Input Parameters: 52 + snes - the SNES context 53 . its - iteration number 54 . fgnorm - 2-norm of residual (or gradient) 55 - dummy - either a viewer or PETSC_NULL 56 57 Level: intermediate 58 59 .keywords: SNES, nonlinear, vector, monitor, view 60 61 .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView() 62 @*/ 63 int SNESVecViewUpdateMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy) 64 { 65 int ierr; 66 Vec x; 67 PetscViewer viewer = (PetscViewer) dummy; 68 69 PetscFunctionBegin; 70 ierr = SNESGetSolutionUpdate(snes,&x);CHKERRQ(ierr); 71 if (!viewer) { 72 MPI_Comm comm; 73 ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr); 74 viewer = PETSC_VIEWER_DRAW_(comm); 75 } 76 ierr = VecView(x,viewer);CHKERRQ(ierr); 77 78 PetscFunctionReturn(0); 79 } 80 81 #undef __FUNCT__ 82 #define __FUNCT__ "SNESDefaultMonitor" 83 /*@C 84 SNESDefaultMonitor - Monitoring progress of the SNES solvers (default). 85 86 Collective on SNES 87 88 Input Parameters: 89 + snes - the SNES context 90 . its - iteration number 91 . fgnorm - 2-norm of residual (or gradient) 92 - dummy - unused context 93 94 Notes: 95 For SNES_NONLINEAR_EQUATIONS methods the routine prints the 96 residual norm at each iteration. 97 98 For SNES_UNCONSTRAINED_MINIMIZATION methods the routine prints the 99 function value and gradient norm at each iteration. 100 101 Level: intermediate 102 103 .keywords: SNES, nonlinear, default, monitor, norm 104 105 .seealso: SNESSetMonitor(), SNESVecViewMonitor() 106 @*/ 107 int SNESDefaultMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy) 108 { 109 int ierr; 110 PetscViewer viewer = (PetscViewer) dummy; 111 112 PetscFunctionBegin; 113 if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm); 114 115 if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 116 ierr = PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr); 117 } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 118 ierr = PetscViewerASCIIPrintf(viewer,"%3d SNES Function value %14.12e, Gradient norm %14.12e \n",its,snes->fc,fgnorm);CHKERRQ(ierr); 119 } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown method class"); 120 PetscFunctionReturn(0); 121 } 122 123 #undef __FUNCT__ 124 #define __FUNCT__ "SNESRatioMonitor" 125 /*@C 126 SNESRatioMonitor - Monitoring progress of the SNES solvers, prints ratio 127 of residual norm at each iteration to previous 128 129 Collective on SNES 130 131 Input Parameters: 132 + snes - the SNES context 133 . its - iteration number 134 . fgnorm - 2-norm of residual (or gradient) 135 - dummy - unused context 136 137 Level: intermediate 138 139 .keywords: SNES, nonlinear, monitor, norm 140 141 .seealso: SNESSetMonitor(), SNESVecViewMonitor() 142 @*/ 143 int SNESRatioMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy) 144 { 145 int ierr,len; 146 PetscReal *history; 147 PetscViewer viewer; 148 149 PetscFunctionBegin; 150 viewer = PETSC_VIEWER_STDOUT_(snes->comm); 151 152 ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);CHKERRQ(ierr); 153 if (its == 0 || !history || its > len) { 154 ierr = PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e \n",its,fgnorm);CHKERRQ(ierr); 155 } else { 156 PetscReal ratio = fgnorm/history[its-1]; 157 ierr = PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e %g \n",its,fgnorm,ratio);CHKERRQ(ierr); 158 } 159 PetscFunctionReturn(0); 160 } 161 162 /* 163 If the we set the history monitor space then we must destroy it 164 */ 165 #undef __FUNCT__ 166 #define __FUNCT__ "SNESRatioMonitorDestroy" 167 int SNESRatioMonitorDestroy(void *history) 168 { 169 int ierr; 170 171 PetscFunctionBegin; 172 ierr = PetscFree(history);CHKERRQ(ierr); 173 PetscFunctionReturn(0); 174 } 175 176 #undef __FUNCT__ 177 #define __FUNCT__ "SNESSetRatioMonitor" 178 /*@C 179 SNESSetRatioMonitor - Sets SNES to use a monitor that prints the 180 ratio of the function norm at each iteration 181 182 Collective on SNES 183 184 Input Parameters: 185 . snes - the SNES context 186 187 Level: intermediate 188 189 .keywords: SNES, nonlinear, monitor, norm 190 191 .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor() 192 @*/ 193 int SNESSetRatioMonitor(SNES snes) 194 { 195 int ierr; 196 PetscReal *history; 197 198 PetscFunctionBegin; 199 200 ierr = SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 201 if (!history) { 202 ierr = PetscMalloc(100*sizeof(double),&history);CHKERRQ(ierr); 203 ierr = SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);CHKERRQ(ierr); 204 ierr = SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);CHKERRQ(ierr); 205 } else { 206 ierr = SNESSetMonitor(snes,SNESRatioMonitor,0,0);CHKERRQ(ierr); 207 } 208 PetscFunctionReturn(0); 209 } 210 211 /* ---------------------------------------------------------------- */ 212 #undef __FUNCT__ 213 #define __FUNCT__ "SNESDefaultSMonitor" 214 /* 215 Default (short) SNES Monitor, same as SNESDefaultMonitor() except 216 it prints fewer digits of the residual as the residual gets smaller. 217 This is because the later digits are meaningless and are often 218 different on different machines; by using this routine different 219 machines will usually generate the same output. 220 */ 221 int SNESDefaultSMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy) 222 { 223 int ierr; 224 225 PetscFunctionBegin; 226 if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 227 if (fgnorm > 1.e-9) { 228 ierr = PetscPrintf(snes->comm,"%3d SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr); 229 } else if (fgnorm > 1.e-11){ 230 ierr = PetscPrintf(snes->comm,"%3d SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr); 231 } else { 232 ierr = PetscPrintf(snes->comm,"%3d SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr); 233 } 234 } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 235 if (fgnorm > 1.e-9) { 236 ierr = PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);CHKERRQ(ierr); 237 } else if (fgnorm > 1.e-11) { 238 ierr = PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm %5.3e \n",its,snes->fc,fgnorm);CHKERRQ(ierr); 239 } else { 240 ierr = PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm < 1.e-11\n",its,snes->fc);CHKERRQ(ierr); 241 } 242 } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown method class"); 243 PetscFunctionReturn(0); 244 } 245 /* ---------------------------------------------------------------- */ 246 #undef __FUNCT__ 247 #define __FUNCT__ "SNESConverged_EQ_LS" 248 /*@C 249 SNESConverged_EQ_LS - Monitors the convergence of the solvers for 250 systems of nonlinear equations (default). 251 252 Collective on SNES 253 254 Input Parameters: 255 + snes - the SNES context 256 . xnorm - 2-norm of current iterate 257 . pnorm - 2-norm of current step 258 . fnorm - 2-norm of function 259 - dummy - unused context 260 261 Output Parameter: 262 . reason - one of 263 $ SNES_CONVERGED_FNORM_ABS - (fnorm < atol), 264 $ SNES_CONVERGED_PNORM_RELATIVE - (pnorm < xtol*xnorm), 265 $ SNES_CONVERGED_FNORM_RELATIVE - (fnorm < rtol*fnorm0), 266 $ SNES_DIVERGED_FUNCTION_COUNT - (nfct > maxf), 267 $ SNES_DIVERGED_FNORM_NAN - (fnorm == NaN), 268 $ SNES_CONVERGED_ITERATING - (otherwise), 269 270 where 271 + maxf - maximum number of function evaluations, 272 set with SNESSetTolerances() 273 . nfct - number of function evaluations, 274 . atol - absolute function norm tolerance, 275 set with SNESSetTolerances() 276 - rtol - relative function norm tolerance, set with SNESSetTolerances() 277 278 Level: intermediate 279 280 .keywords: SNES, nonlinear, default, converged, convergence 281 282 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged() 283 @*/ 284 int SNESConverged_EQ_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy) 285 { 286 PetscFunctionBegin; 287 if (snes->method_class != SNES_NONLINEAR_EQUATIONS) { 288 SETERRQ(PETSC_ERR_ARG_WRONG,"For SNES_NONLINEAR_EQUATIONS only"); 289 } 290 291 if (fnorm != fnorm) { 292 PetscLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n"); 293 *reason = SNES_DIVERGED_FNORM_NAN; 294 } else if (fnorm <= snes->ttol) { 295 PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol); 296 *reason = SNES_CONVERGED_FNORM_RELATIVE; 297 } else if (fnorm < snes->atol) { 298 PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g\n",fnorm,snes->atol); 299 *reason = SNES_CONVERGED_FNORM_ABS; 300 } else if (pnorm < snes->xtol*(xnorm)) { 301 PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm); 302 *reason = SNES_CONVERGED_PNORM_RELATIVE; 303 } else if (snes->nfuncs > snes->max_funcs) { 304 PetscLogInfo(snes,"SNESConverged_EQ_LS:Exceeded maximum number of function evaluations: %d > %d\n",snes->nfuncs,snes->max_funcs); 305 *reason = SNES_DIVERGED_FUNCTION_COUNT ; 306 } else { 307 *reason = SNES_CONVERGED_ITERATING; 308 } 309 PetscFunctionReturn(0); 310 } 311 /* ------------------------------------------------------------ */ 312 #undef __FUNCT__ 313 #define __FUNCT__ "SNES_KSP_SetConvergenceTestEW" 314 /*@ 315 SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test 316 for the linear solvers within an inexact Newton method. 317 318 Collective on SNES 319 320 Input Parameter: 321 . snes - SNES context 322 323 Notes: 324 Currently, the default is to use a constant relative tolerance for 325 the inner linear solvers. Alternatively, one can use the 326 Eisenstat-Walker method, where the relative convergence tolerance 327 is reset at each Newton iteration according progress of the nonlinear 328 solver. 329 330 Level: advanced 331 332 Reference: 333 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 334 inexact Newton method", SISC 17 (1), pp.16-32, 1996. 335 336 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton 337 @*/ 338 int SNES_KSP_SetConvergenceTestEW(SNES snes) 339 { 340 PetscFunctionBegin; 341 snes->ksp_ewconv = PETSC_TRUE; 342 PetscFunctionReturn(0); 343 } 344 345 #undef __FUNCT__ 346 #define __FUNCT__ "SNES_KSP_SetParametersEW" 347 /*@ 348 SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker 349 convergence criteria for the linear solvers within an inexact 350 Newton method. 351 352 Collective on SNES 353 354 Input Parameters: 355 + snes - SNES context 356 . version - version 1 or 2 (default is 2) 357 . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1) 358 . rtol_max - maximum relative tolerance (0 <= rtol_max < 1) 359 . alpha - power for version 2 rtol computation (1 < alpha <= 2) 360 . alpha2 - power for safeguard 361 . gamma2 - multiplicative factor for version 2 rtol computation 362 (0 <= gamma2 <= 1) 363 - threshold - threshold for imposing safeguard (0 < threshold < 1) 364 365 Note: 366 Use PETSC_DEFAULT to retain the default for any of the parameters. 367 368 Level: advanced 369 370 Reference: 371 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 372 inexact Newton method", Utah State University Math. Stat. Dept. Res. 373 Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 374 375 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters 376 377 .seealso: SNES_KSP_SetConvergenceTestEW() 378 @*/ 379 int SNES_KSP_SetParametersEW(SNES snes,int version,PetscReal rtol_0, 380 PetscReal rtol_max,PetscReal gamma2,PetscReal alpha, 381 PetscReal alpha2,PetscReal threshold) 382 { 383 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 384 385 PetscFunctionBegin; 386 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing"); 387 if (version != PETSC_DEFAULT) kctx->version = version; 388 if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0; 389 if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max; 390 if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2; 391 if (alpha != PETSC_DEFAULT) kctx->alpha = alpha; 392 if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2; 393 if (threshold != PETSC_DEFAULT) kctx->threshold = threshold; 394 if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) { 395 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0); 396 } 397 if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) { 398 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max < 1.0\n",kctx->rtol_max); 399 } 400 if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) { 401 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold < 1.0\n",kctx->threshold); 402 } 403 if (kctx->gamma < 0.0 || kctx->gamma > 1.0) { 404 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= alpha <= 1.0\n",kctx->gamma); 405 } 406 if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) { 407 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha <= 2.0\n",kctx->alpha); 408 } 409 if (kctx->version != 1 && kctx->version !=2) { 410 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %d",kctx->version); 411 } 412 PetscFunctionReturn(0); 413 } 414 415 #undef __FUNCT__ 416 #define __FUNCT__ "SNES_KSP_EW_ComputeRelativeTolerance_Private" 417 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp) 418 { 419 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 420 PetscReal rtol = 0.0,stol; 421 int ierr; 422 423 PetscFunctionBegin; 424 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists"); 425 if (!snes->iter) { /* first time in, so use the original user rtol */ 426 rtol = kctx->rtol_0; 427 } else { 428 if (kctx->version == 1) { 429 rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last; 430 if (rtol < 0.0) rtol = -rtol; 431 stol = pow(kctx->rtol_last,kctx->alpha2); 432 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 433 } else if (kctx->version == 2) { 434 rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha); 435 stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha); 436 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 437 } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %d",kctx->version); 438 } 439 rtol = PetscMin(rtol,kctx->rtol_max); 440 kctx->rtol_last = rtol; 441 PetscLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n",snes->iter,kctx->version,rtol); 442 ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 443 kctx->norm_last = snes->norm; 444 PetscFunctionReturn(0); 445 } 446 447 #undef __FUNCT__ 448 #define __FUNCT__ "SNES_KSP_EW_Converged_Private" 449 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx) 450 { 451 SNES snes = (SNES)ctx; 452 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 453 int ierr; 454 455 PetscFunctionBegin; 456 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set"); 457 if (n == 0) {ierr = SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);CHKERRQ(ierr);} 458 ierr = KSPDefaultConverged(ksp,n,rnorm,reason,ctx);CHKERRQ(ierr); 459 kctx->lresid_last = rnorm; 460 if (*reason) { 461 PetscLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm); 462 } 463 PetscFunctionReturn(0); 464 } 465 466 467