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