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