1 /*$Id: snesut.c,v 1.49 1999/10/24 14:03:31 bsmith Exp bsmith $*/ 2 3 #include "src/snes/snesimpl.h" /*I "snes.h" I*/ 4 5 #undef __FUNC__ 6 #define __FUNC__ "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,double fgnorm,void *dummy) 26 { 27 int ierr; 28 Vec x; 29 Viewer viewer = (Viewer) 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 = VIEWER_DRAW_(comm); 37 } 38 ierr = VecView(x,viewer);CHKERRQ(ierr); 39 40 PetscFunctionReturn(0); 41 } 42 43 #undef __FUNC__ 44 #define __FUNC__ "SNESVecViewMonitorUpdate" 45 /*@C 46 SNESVecViewMonitorUpdate - 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 SNESVecViewMonitorUpdate(SNES snes,int its,double fgnorm,void *dummy) 64 { 65 int ierr; 66 Vec x; 67 Viewer viewer = (Viewer) 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 = VIEWER_DRAW_(comm); 75 } 76 ierr = VecView(x,viewer);CHKERRQ(ierr); 77 78 PetscFunctionReturn(0); 79 } 80 81 #undef __FUNC__ 82 #define __FUNC__ "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,double fgnorm,void *dummy) 108 { 109 int ierr; 110 111 PetscFunctionBegin; 112 if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 113 ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr); 114 } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 115 ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);CHKERRQ(ierr); 116 } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class"); 117 PetscFunctionReturn(0); 118 } 119 120 /* ---------------------------------------------------------------- */ 121 #undef __FUNC__ 122 #define __FUNC__ "SNESDefaultSMonitor" 123 /* 124 Default (short) SNES Monitor, same as SNESDefaultMonitor() except 125 it prints fewer digits of the residual as the residual gets smaller. 126 This is because the later digits are meaningless and are often 127 different on different machines; by using this routine different 128 machines will usually generate the same output. 129 */ 130 int SNESDefaultSMonitor(SNES snes,int its, double fgnorm,void *dummy) 131 { 132 int ierr; 133 134 PetscFunctionBegin; 135 if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 136 if (fgnorm > 1.e-9) { 137 ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm);CHKERRQ(ierr); 138 } else if (fgnorm > 1.e-11){ 139 ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm %5.3e \n",its,fgnorm);CHKERRQ(ierr); 140 } else { 141 ierr = PetscPrintf(snes->comm, "iter = %d, SNES Function norm < 1.e-11\n",its);CHKERRQ(ierr); 142 } 143 } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 144 if (fgnorm > 1.e-9) { 145 ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm);CHKERRQ(ierr); 146 } else if (fgnorm > 1.e-11) { 147 ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %5.3e \n",its,snes->fc,fgnorm);CHKERRQ(ierr); 148 } else { 149 ierr = PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm < 1.e-11\n",its,snes->fc);CHKERRQ(ierr); 150 } 151 } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class"); 152 PetscFunctionReturn(0); 153 } 154 /* ---------------------------------------------------------------- */ 155 #undef __FUNC__ 156 #define __FUNC__ "SNESConverged_EQ_LS" 157 /*@C 158 SNESConverged_EQ_LS - Monitors the convergence of the solvers for 159 systems of nonlinear equations (default). 160 161 Collective on SNES 162 163 Input Parameters: 164 + snes - the SNES context 165 . xnorm - 2-norm of current iterate 166 . pnorm - 2-norm of current step 167 . fnorm - 2-norm of function 168 - dummy - unused context 169 170 Output Parameter: 171 . reason - one of 172 $ SNES_CONVERGED_FNORM_ABS - ( fnorm < atol ), 173 $ SNES_CONVERGED_PNORM_RELATIVE - ( pnorm < xtol*xnorm ), 174 $ SNES_CONVERGED_FNORM_RELATIVE - ( fnorm < rtol*fnorm0 ), 175 $ SNES_DIVERGED_FUNCTION_COUNT - ( nfct > maxf ), 176 $ SNES_DIVERGED_FNORM_NAN - ( fnorm == NaN ), 177 $ SNES_CONVERGED_ITERATING - ( otherwise ), 178 179 where 180 + maxf - maximum number of function evaluations, 181 set with SNESSetTolerances() 182 . nfct - number of function evaluations, 183 . atol - absolute function norm tolerance, 184 set with SNESSetTolerances() 185 - rtol - relative function norm tolerance, set with SNESSetTolerances() 186 187 Level: intermediate 188 189 .keywords: SNES, nonlinear, default, converged, convergence 190 191 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged() 192 @*/ 193 int SNESConverged_EQ_LS(SNES snes,double xnorm,double pnorm,double fnorm,SNESConvergedReason *reason,void *dummy) 194 { 195 PetscFunctionBegin; 196 if (snes->method_class != SNES_NONLINEAR_EQUATIONS) { 197 SETERRQ(PETSC_ERR_ARG_WRONG,0,"For SNES_NONLINEAR_EQUATIONS only"); 198 } 199 200 if (fnorm != fnorm) { 201 PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n"); 202 *reason = SNES_DIVERGED_FNORM_NAN; 203 } else if (fnorm <= snes->ttol) { 204 PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol); 205 *reason = SNES_CONVERGED_FNORM_RELATIVE; 206 } else if (fnorm < snes->atol) { 207 PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g\n",fnorm,snes->atol); 208 *reason = SNES_CONVERGED_FNORM_ABS; 209 } else if (pnorm < snes->xtol*(xnorm)) { 210 PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm); 211 *reason = SNES_CONVERGED_PNORM_RELATIVE; 212 } else if (snes->nfuncs > snes->max_funcs) { 213 PLogInfo(snes,"SNESConverged_EQ_LS:Exceeded maximum number of function evaluations: %d > %d\n",snes->nfuncs, snes->max_funcs); 214 *reason = SNES_DIVERGED_FUNCTION_COUNT ; 215 } else { 216 *reason = SNES_CONVERGED_ITERATING; 217 } 218 PetscFunctionReturn(0); 219 } 220 /* ------------------------------------------------------------ */ 221 #undef __FUNC__ 222 #define __FUNC__ "SNES_KSP_SetConvergenceTestEW" 223 /*@ 224 SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test 225 for the linear solvers within an inexact Newton method. 226 227 Collective on SNES 228 229 Input Parameter: 230 . snes - SNES context 231 232 Notes: 233 Currently, the default is to use a constant relative tolerance for 234 the inner linear solvers. Alternatively, one can use the 235 Eisenstat-Walker method, where the relative convergence tolerance 236 is reset at each Newton iteration according progress of the nonlinear 237 solver. 238 239 Level: advanced 240 241 Reference: 242 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 243 inexact Newton method", SISC 17 (1), pp.16-32, 1996. 244 245 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton 246 @*/ 247 int SNES_KSP_SetConvergenceTestEW(SNES snes) 248 { 249 PetscFunctionBegin; 250 snes->ksp_ewconv = 1; 251 PetscFunctionReturn(0); 252 } 253 254 #undef __FUNC__ 255 #define __FUNC__ "SNES_KSP_SetParametersEW" 256 /*@ 257 SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker 258 convergence criteria for the linear solvers within an inexact 259 Newton method. 260 261 Collective on SNES 262 263 Input Parameters: 264 + snes - SNES context 265 . version - version 1 or 2 (default is 2) 266 . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1) 267 . rtol_max - maximum relative tolerance (0 <= rtol_max < 1) 268 . alpha - power for version 2 rtol computation (1 < alpha <= 2) 269 . alpha2 - power for safeguard 270 . gamma2 - multiplicative factor for version 2 rtol computation 271 (0 <= gamma2 <= 1) 272 - threshold - threshold for imposing safeguard (0 < threshold < 1) 273 274 Note: 275 Use PETSC_DEFAULT to retain the default for any of the parameters. 276 277 Level: advanced 278 279 Reference: 280 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 281 inexact Newton method", Utah State University Math. Stat. Dept. Res. 282 Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 283 284 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters 285 286 .seealso: SNES_KSP_SetConvergenceTestEW() 287 @*/ 288 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0, 289 double rtol_max,double gamma2,double alpha, 290 double alpha2,double threshold) 291 { 292 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 293 294 PetscFunctionBegin; 295 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing"); 296 if (version != PETSC_DEFAULT) kctx->version = version; 297 if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0; 298 if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max; 299 if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2; 300 if (alpha != PETSC_DEFAULT) kctx->alpha = alpha; 301 if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2; 302 if (threshold != PETSC_DEFAULT) kctx->threshold = threshold; 303 if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) { 304 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0); 305 } 306 if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) { 307 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n",kctx->rtol_max); 308 } 309 if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) { 310 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n",kctx->threshold); 311 } 312 if (kctx->gamma < 0.0 || kctx->gamma > 1.0) { 313 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n",kctx->gamma); 314 } 315 if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) { 316 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n",kctx->alpha); 317 } 318 if (kctx->version != 1 && kctx->version !=2) { 319 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported: %d",kctx->version); 320 } 321 PetscFunctionReturn(0); 322 } 323 324 #undef __FUNC__ 325 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private" 326 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp) 327 { 328 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 329 double rtol = 0.0, stol; 330 int ierr; 331 332 PetscFunctionBegin; 333 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists"); 334 if (!snes->iter) { /* first time in, so use the original user rtol */ 335 rtol = kctx->rtol_0; 336 } else { 337 if (kctx->version == 1) { 338 rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last; 339 if (rtol < 0.0) rtol = -rtol; 340 stol = pow(kctx->rtol_last,kctx->alpha2); 341 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 342 } else if (kctx->version == 2) { 343 rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha); 344 stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha); 345 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 346 } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported: %d",kctx->version); 347 } 348 rtol = PetscMin(rtol,kctx->rtol_max); 349 kctx->rtol_last = rtol; 350 PLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n",snes->iter,kctx->version,rtol); 351 ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 352 kctx->norm_last = snes->norm; 353 PetscFunctionReturn(0); 354 } 355 356 #undef __FUNC__ 357 #define __FUNC__ "SNES_KSP_EW_Converged_Private" 358 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx) 359 { 360 SNES snes = (SNES)ctx; 361 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 362 int convinfo,ierr; 363 364 PetscFunctionBegin; 365 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set"); 366 if (n == 0) {ierr = SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);CHKERRQ(ierr);} 367 convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx); 368 kctx->lresid_last = rnorm; 369 if (convinfo) { 370 PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm); 371 } 372 PetscFunctionReturn(convinfo); 373 } 374 375 376