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