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