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