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