1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: snesut.c,v 1.46 1999/04/19 22:15:28 bsmith Exp balay $"; 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 Returns: 173 + 2 - if ( fnorm < atol ), 174 . 3 - if ( pnorm < xtol*xnorm ), 175 . 4 - if ( fnorm < rtol*fnorm0 ), 176 . -2 - if ( nfct > maxf ), 177 - 0 - 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,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 /* Note: Reserve return code 1, -1 for compatibility with SNESConverged_EQ_TR */ 200 if (fnorm != fnorm) { 201 PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n"); 202 PetscFunctionReturn(-3); 203 } 204 if (fnorm <= snes->ttol) { 205 PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol); 206 PetscFunctionReturn(4); 207 } 208 209 if (fnorm < snes->atol) { 210 PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g\n",fnorm,snes->atol); 211 PetscFunctionReturn(2); 212 } 213 if (pnorm < snes->xtol*(xnorm)) { 214 PLogInfo(snes,"SNESConverged_EQ_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm); 215 PetscFunctionReturn(3); 216 } 217 if (snes->nfuncs > snes->max_funcs) { 218 PLogInfo(snes,"SNESConverged_EQ_LS:Exceeded maximum number of function evaluations: %d > %d\n",snes->nfuncs, snes->max_funcs); 219 PetscFunctionReturn(-2); 220 } 221 PetscFunctionReturn(0); 222 } 223 /* ------------------------------------------------------------ */ 224 #undef __FUNC__ 225 #define __FUNC__ "SNES_KSP_SetConvergenceTestEW" 226 /*@ 227 SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test 228 for the linear solvers within an inexact Newton method. 229 230 Collective on SNES 231 232 Input Parameter: 233 . snes - SNES context 234 235 Notes: 236 Currently, the default is to use a constant relative tolerance for 237 the inner linear solvers. Alternatively, one can use the 238 Eisenstat-Walker method, where the relative convergence tolerance 239 is reset at each Newton iteration according progress of the nonlinear 240 solver. 241 242 Level: advanced 243 244 Reference: 245 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 246 inexact Newton method", SISC 17 (1), pp.16-32, 1996. 247 248 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton 249 @*/ 250 int SNES_KSP_SetConvergenceTestEW(SNES snes) 251 { 252 PetscFunctionBegin; 253 snes->ksp_ewconv = 1; 254 PetscFunctionReturn(0); 255 } 256 257 #undef __FUNC__ 258 #define __FUNC__ "SNES_KSP_SetParametersEW" 259 /*@ 260 SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker 261 convergence criteria for the linear solvers within an inexact 262 Newton method. 263 264 Collective on SNES 265 266 Input Parameters: 267 + snes - SNES context 268 . version - version 1 or 2 (default is 2) 269 . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1) 270 . rtol_max - maximum relative tolerance (0 <= rtol_max < 1) 271 . alpha - power for version 2 rtol computation (1 < alpha <= 2) 272 . alpha2 - power for safeguard 273 . gamma2 - multiplicative factor for version 2 rtol computation 274 (0 <= gamma2 <= 1) 275 - threshold - threshold for imposing safeguard (0 < threshold < 1) 276 277 Note: 278 Use PETSC_DEFAULT to retain the default for any of the parameters. 279 280 Level: advanced 281 282 Reference: 283 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 284 inexact Newton method", Utah State University Math. Stat. Dept. Res. 285 Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 286 287 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters 288 289 .seealso: SNES_KSP_SetConvergenceTestEW() 290 @*/ 291 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0, 292 double rtol_max,double gamma2,double alpha, 293 double alpha2,double threshold) 294 { 295 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 296 297 PetscFunctionBegin; 298 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing"); 299 if (version != PETSC_DEFAULT) kctx->version = version; 300 if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0; 301 if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max; 302 if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2; 303 if (alpha != PETSC_DEFAULT) kctx->alpha = alpha; 304 if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2; 305 if (threshold != PETSC_DEFAULT) kctx->threshold = threshold; 306 if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) { 307 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0); 308 } 309 if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) { 310 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n",kctx->rtol_max); 311 } 312 if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) { 313 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n",kctx->threshold); 314 } 315 if (kctx->gamma < 0.0 || kctx->gamma > 1.0) { 316 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n",kctx->gamma); 317 } 318 if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) { 319 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n",kctx->alpha); 320 } 321 if (kctx->version != 1 && kctx->version !=2) { 322 SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported: %d",kctx->version); 323 } 324 PetscFunctionReturn(0); 325 } 326 327 #undef __FUNC__ 328 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private" 329 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp) 330 { 331 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 332 double rtol = 0.0, stol; 333 int ierr; 334 335 PetscFunctionBegin; 336 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists"); 337 if (snes->iter == 1) { 338 rtol = kctx->rtol_0; 339 } else { 340 if (kctx->version == 1) { 341 rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last; 342 if (rtol < 0.0) rtol = -rtol; 343 stol = pow(kctx->rtol_last,kctx->alpha2); 344 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 345 } else if (kctx->version == 2) { 346 rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha); 347 stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha); 348 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 349 } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported: %d",kctx->version); 350 } 351 rtol = PetscMin(rtol,kctx->rtol_max); 352 kctx->rtol_last = rtol; 353 PLogInfo(snes,"SNESConverged_EQ_LS: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n",snes->iter,kctx->version,rtol); 354 ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr); 355 kctx->norm_last = snes->norm; 356 PetscFunctionReturn(0); 357 } 358 359 #undef __FUNC__ 360 #define __FUNC__ "SNES_KSP_EW_Converged_Private" 361 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx) 362 { 363 SNES snes = (SNES)ctx; 364 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 365 int convinfo; 366 367 PetscFunctionBegin; 368 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set"); 369 if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp); 370 convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx); 371 kctx->lresid_last = rnorm; 372 if (convinfo) { 373 PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm); 374 } 375 PetscFunctionReturn(convinfo); 376 } 377 378 379