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