1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: snesut.c,v 1.38 1998/04/13 17:55:33 bsmith Exp curfman $"; 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 Collective on SNES 14 15 Input Parameters: 16 + snes - the SNES context 17 . its - iteration number 18 . fgnorm - 2-norm of residual (or gradient) 19 - dummy - unused context 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 Collective on SNES 85 86 Input Parameters: 87 + snes - the SNES context 88 . xnorm - 2-norm of current iterate 89 . pnorm - 2-norm of current step 90 . fnorm - 2-norm of function 91 - dummy - unused context 92 93 Returns: 94 + 2 - if ( fnorm < atol ), 95 . 3 - if ( pnorm < xtol*xnorm ), 96 . 4 - if ( fnorm < rtol*fnorm0 ), 97 . -2 - if ( nfct > maxf ), 98 - 0 - otherwise, 99 100 where 101 + maxf - maximum number of function evaluations, 102 set with SNESSetTolerances() 103 . nfct - number of function evaluations, 104 . atol - absolute function norm tolerance, 105 set with SNESSetTolerances() 106 - rtol - relative function norm tolerance, set with SNESSetTolerances() 107 108 .keywords: SNES, nonlinear, default, converged, convergence 109 110 .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged() 111 @*/ 112 int SNESConverged_EQ_LS(SNES snes,double xnorm,double pnorm,double fnorm,void *dummy) 113 { 114 PetscFunctionBegin; 115 if (snes->method_class != SNES_NONLINEAR_EQUATIONS) { 116 SETERRQ(PETSC_ERR_ARG_WRONG,0,"For SNES_NONLINEAR_EQUATIONS only"); 117 } 118 /* Note: Reserve return code 1, -1 for compatibility with SNESConverged_EQ_TR */ 119 if (fnorm != fnorm) { 120 PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n"); 121 PetscFunctionReturn(-3); 122 } 123 if (fnorm <= snes->ttol) { 124 PLogInfo(snes, 125 "SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol); 126 PetscFunctionReturn(4); 127 } 128 129 if (fnorm < snes->atol) { 130 PLogInfo(snes, 131 "SNESConverged_EQ_LS: Converged due to function norm %g < %g\n",fnorm,snes->atol); 132 PetscFunctionReturn(2); 133 } 134 if (pnorm < snes->xtol*(xnorm)) { 135 PLogInfo(snes, 136 "SNESConverged_EQ_LS: Converged due to small update length: %g < %g * %g\n", 137 pnorm,snes->xtol,xnorm); 138 PetscFunctionReturn(3); 139 } 140 if (snes->nfuncs > snes->max_funcs) { 141 PLogInfo(snes,"SNESConverged_EQ_LS: Exceeded maximum number of function evaluations: %d > %d\n", 142 snes->nfuncs, snes->max_funcs ); 143 PetscFunctionReturn(-2); 144 } 145 PetscFunctionReturn(0); 146 } 147 /* ------------------------------------------------------------ */ 148 #undef __FUNC__ 149 #define __FUNC__ "SNES_KSP_SetConvergenceTestEW" 150 /*@ 151 SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test 152 for the linear solvers within an inexact Newton method. 153 154 Collective on SNES 155 156 Input Parameter: 157 . snes - SNES context 158 159 Notes: 160 Currently, the default is to use a constant relative tolerance for 161 the inner linear solvers. Alternatively, one can use the 162 Eisenstat-Walker method, where the relative convergence tolerance 163 is reset at each Newton iteration according progress of the nonlinear 164 solver. 165 166 Reference: 167 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 168 inexact Newton method", SISC 17 (1), pp.16-32, 1996. 169 170 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton 171 @*/ 172 int SNES_KSP_SetConvergenceTestEW(SNES snes) 173 { 174 PetscFunctionBegin; 175 snes->ksp_ewconv = 1; 176 PetscFunctionReturn(0); 177 } 178 179 #undef __FUNC__ 180 #define __FUNC__ "SNES_KSP_SetParametersEW" 181 /*@ 182 SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker 183 convergence criteria for the linear solvers within an inexact 184 Newton method. 185 186 Collective on SNES 187 188 Input Parameters: 189 + snes - SNES context 190 . version - version 1 or 2 (default is 2) 191 . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1) 192 . rtol_max - maximum relative tolerance (0 <= rtol_max < 1) 193 . alpha - power for version 2 rtol computation (1 < alpha <= 2) 194 . alpha2 - power for safeguard 195 . gamma2 - multiplicative factor for version 2 rtol computation 196 (0 <= gamma2 <= 1) 197 - threshold - threshold for imposing safeguard (0 < threshold < 1) 198 199 Note: 200 Use PETSC_DEFAULT to retain the default for any of the parameters. 201 202 Reference: 203 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 204 inexact Newton method", Utah State University Math. Stat. Dept. Res. 205 Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 206 207 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters 208 209 .seealso: SNES_KSP_SetConvergenceTestEW() 210 @*/ 211 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0, 212 double rtol_max,double gamma2,double alpha, 213 double alpha2,double threshold) 214 { 215 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 216 217 PetscFunctionBegin; 218 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing"); 219 if (version != PETSC_DEFAULT) kctx->version = version; 220 if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0; 221 if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max; 222 if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2; 223 if (alpha != PETSC_DEFAULT) kctx->alpha = alpha; 224 if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2; 225 if (threshold != PETSC_DEFAULT) kctx->threshold = threshold; 226 if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) { 227 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0\n"); 228 } 229 if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) { 230 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n"); 231 } 232 if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) { 233 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n"); 234 } 235 if (kctx->gamma < 0.0 || kctx->gamma > 1.0) { 236 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n"); 237 } 238 if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) { 239 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n"); 240 } 241 if (kctx->version != 1 && kctx->version !=2) { 242 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported"); 243 } 244 PetscFunctionReturn(0); 245 } 246 247 #undef __FUNC__ 248 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private" 249 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp) 250 { 251 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 252 double rtol, stol; 253 int ierr; 254 255 PetscFunctionBegin; 256 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists"); 257 if (snes->iter == 1) { 258 rtol = kctx->rtol_0; 259 } else { 260 if (kctx->version == 1) { 261 rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last; 262 if (rtol < 0.0) rtol = -rtol; 263 stol = pow(kctx->rtol_last,kctx->alpha2); 264 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 265 } else if (kctx->version == 2) { 266 rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha); 267 stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha); 268 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 269 } else SETERRQ( PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported"); 270 } 271 rtol = PetscMin(rtol,kctx->rtol_max); 272 kctx->rtol_last = rtol; 273 PLogInfo(snes,"SNESConverged_EQ_LS: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n", 274 snes->iter,kctx->version,rtol); 275 ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT); CHKERRQ(ierr); 276 kctx->norm_last = snes->norm; 277 PetscFunctionReturn(0); 278 } 279 280 #undef __FUNC__ 281 #define __FUNC__ "SNES_KSP_EW_Converged_Private" 282 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx) 283 { 284 SNES snes = (SNES)ctx; 285 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 286 int convinfo; 287 288 PetscFunctionBegin; 289 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set"); 290 if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp); 291 convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx); 292 kctx->lresid_last = rnorm; 293 if (convinfo) { 294 PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm); 295 } 296 PetscFunctionReturn(convinfo); 297 } 298 299 300