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