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