1 #ifndef lint 2 static char vcid[] = "$Id: snesut.c,v 1.26 1997/01/06 20:29:45 balay 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 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,0,"Unknown method class"); 72 return 0; 73 } 74 /* ---------------------------------------------------------------- */ 75 #undef __FUNC__ 76 #define __FUNC__ "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) { 111 SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only"); 112 } 113 /* Note: Reserve return code 1, -1 for compatibility with SNESConverged_EQ_TR */ 114 if (fnorm != fnorm) { 115 PLogInfo(snes,"SNES:Failed to converged, function norm is NaN\n"); 116 return -3; 117 } 118 if (fnorm <= snes->ttol) { 119 PLogInfo(snes, 120 "SNES:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol); 121 return 4; 122 } 123 124 if (fnorm < snes->atol) { 125 PLogInfo(snes, 126 "SNES: Converged due to function norm %g < %g\n",fnorm,snes->atol); 127 return 2; 128 } 129 if (pnorm < snes->xtol*(xnorm)) { 130 PLogInfo(snes, 131 "SNES: Converged due to small update length: %g < %g * %g\n", 132 pnorm,snes->xtol,xnorm); 133 return 3; 134 } 135 if (snes->nfuncs > snes->max_funcs) { 136 PLogInfo(snes,"SNES: Exceeded maximum number of function evaluations: %d > %d\n", 137 snes->nfuncs, snes->max_funcs ); 138 return -2; 139 } 140 return 0; 141 } 142 /* ------------------------------------------------------------ */ 143 #undef __FUNC__ 144 #define __FUNC__ "SNES_KSP_SetConvergenceTestEW" 145 /*@ 146 SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test 147 for the linear solvers within an inexact Newton method. 148 149 Input Parameter: 150 . snes - SNES context 151 152 Notes: 153 Currently, the default is to use a constant relative tolerance for 154 the inner linear solvers. Alternatively, one can use the 155 Eisenstat-Walker method, where the relative convergence tolerance 156 is reset at each Newton iteration according progress of the nonlinear 157 solver. 158 159 Reference: 160 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 161 inexact Newton method", Utah State University Math. Stat. Dept. Res. 162 Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 163 164 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton 165 @*/ 166 int SNES_KSP_SetConvergenceTestEW(SNES snes) 167 { 168 snes->ksp_ewconv = 1; 169 return 0; 170 } 171 172 #undef __FUNC__ 173 #define __FUNC__ "SNES_KSP_SetParametersEW" 174 /*@ 175 SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker 176 convergence criteria for the linear solvers within an inexact 177 Newton method. 178 179 Input Parameters: 180 . snes - SNES context 181 . version - version 1 or 2 (default is 2) 182 . rtol_0 - initial relative tolerance 183 $ (0 <= rtol_0 < 1) 184 . rtol_max - maximum relative tolerance 185 $ (0 <= rtol_max < 1) 186 . alpha - power for version 2 rtol computation 187 $ (1 < alpha <= 2) 188 . alpha2 - power for safeguard 189 . gamma2 - multiplicative factor for version 2 rtol computation 190 $ (0 <= gamma2 <= 1) 191 . threshold - threshold for imposing safeguard 192 $ (0 < threshold < 1) 193 194 Note: 195 Use PETSC_DEFAULT to retain the default for any of the parameters. 196 197 Reference: 198 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 199 inexact Newton method", Utah State University Math. Stat. Dept. Res. 200 Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 201 202 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters 203 204 .seealso: SNES_KSP_SetConvergenceTestEW() 205 @*/ 206 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0, 207 double rtol_max,double gamma2,double alpha, 208 double alpha2,double threshold) 209 { 210 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 211 if (!kctx) SETERRQ(1,0,"No context"); 212 if (version != PETSC_DEFAULT) kctx->version = version; 213 if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0; 214 if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max; 215 if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2; 216 if (alpha != PETSC_DEFAULT) kctx->alpha = alpha; 217 if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2; 218 if (threshold != PETSC_DEFAULT) kctx->threshold = threshold; 219 if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) SETERRQ(1,0, 220 "0.0 <= rtol_0 < 1.0\n"); 221 if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) SETERRQ(1,0, 222 "0.0 <= rtol_max < 1.0\n"); 223 if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) SETERRQ(1,0, 224 "0.0 < threshold < 1.0\n"); 225 if (kctx->gamma < 0.0 || kctx->gamma > 1.0) SETERRQ(1,0, 226 "0.0 <= alpha <= 1.0\n"); 227 if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) SETERRQ(1,0, 228 "1.0 < alpha <= 2.0\n"); 229 if (kctx->version != 1 && kctx->version !=2) SETERRQ(1,0, 230 "Only versions 1 and 2 are supported"); 231 return 0; 232 } 233 234 #undef __FUNC__ 235 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private" 236 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp) 237 { 238 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 239 double rtol, stol; 240 int ierr; 241 if (!kctx) 242 SETERRQ(1,0,"No context"); 243 if (snes->iter == 1) { 244 rtol = kctx->rtol_0; 245 } else { 246 if (kctx->version == 1) { 247 rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last; 248 if (rtol < 0.0) rtol = -rtol; 249 stol = pow(kctx->rtol_last,kctx->alpha2); 250 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 251 } else if (kctx->version == 2) { 252 rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha); 253 stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha); 254 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 255 } else SETERRQ(1,0, 256 "Only versions 1 or 2 are supported"); 257 } 258 rtol = PetscMin(rtol,kctx->rtol_max); 259 kctx->rtol_last = rtol; 260 PLogInfo(snes, 261 "SNES: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n", 262 snes->iter,kctx->version,rtol); 263 ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT); 264 CHKERRQ(ierr); 265 kctx->norm_last = snes->norm; 266 return 0; 267 } 268 269 #undef __FUNC__ 270 #define __FUNC__ "SNES_KSP_EW_Converged_Private" 271 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx) 272 { 273 SNES snes = (SNES)ctx; 274 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 275 int convinfo; 276 277 if (!kctx) SETERRQ(1,0,"No convergence context"); 278 if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp); 279 convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx); 280 kctx->lresid_last = rnorm; 281 if (convinfo) 282 PLogInfo(snes,"SNES: KSP iterations=%d, rnorm=%g\n",n,rnorm); 283 return convinfo; 284 } 285 286 287