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