1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: snesut.c,v 1.35 1998/01/06 20:12:19 bsmith 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 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", Utah State University Math. Stat. Dept. Res. 164 Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 165 166 .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton 167 @*/ 168 int SNES_KSP_SetConvergenceTestEW(SNES snes) 169 { 170 PetscFunctionBegin; 171 snes->ksp_ewconv = 1; 172 PetscFunctionReturn(0); 173 } 174 175 #undef __FUNC__ 176 #define __FUNC__ "SNES_KSP_SetParametersEW" 177 /*@ 178 SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker 179 convergence criteria for the linear solvers within an inexact 180 Newton method. 181 182 Input Parameters: 183 . snes - SNES context 184 . version - version 1 or 2 (default is 2) 185 . rtol_0 - initial relative tolerance 186 $ (0 <= rtol_0 < 1) 187 . rtol_max - maximum relative tolerance 188 $ (0 <= rtol_max < 1) 189 . alpha - power for version 2 rtol computation 190 $ (1 < alpha <= 2) 191 . alpha2 - power for safeguard 192 . gamma2 - multiplicative factor for version 2 rtol computation 193 $ (0 <= gamma2 <= 1) 194 . threshold - threshold for imposing safeguard 195 $ (0 < threshold < 1) 196 197 Note: 198 Use PETSC_DEFAULT to retain the default for any of the parameters. 199 200 Reference: 201 S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 202 inexact Newton method", Utah State University Math. Stat. Dept. Res. 203 Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 204 205 .keywords: SNES, KSP, Eisenstat, Walker, set, parameters 206 207 .seealso: SNES_KSP_SetConvergenceTestEW() 208 @*/ 209 int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0, 210 double rtol_max,double gamma2,double alpha, 211 double alpha2,double threshold) 212 { 213 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 214 215 PetscFunctionBegin; 216 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing"); 217 if (version != PETSC_DEFAULT) kctx->version = version; 218 if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0; 219 if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max; 220 if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2; 221 if (alpha != PETSC_DEFAULT) kctx->alpha = alpha; 222 if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2; 223 if (threshold != PETSC_DEFAULT) kctx->threshold = threshold; 224 if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) { 225 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0\n"); 226 } 227 if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) { 228 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n"); 229 } 230 if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) { 231 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n"); 232 } 233 if (kctx->gamma < 0.0 || kctx->gamma > 1.0) { 234 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n"); 235 } 236 if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) { 237 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n"); 238 } 239 if (kctx->version != 1 && kctx->version !=2) { 240 SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported"); 241 } 242 PetscFunctionReturn(0); 243 } 244 245 #undef __FUNC__ 246 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private" 247 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp) 248 { 249 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 250 double rtol, stol; 251 int ierr; 252 253 PetscFunctionBegin; 254 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists"); 255 if (snes->iter == 1) { 256 rtol = kctx->rtol_0; 257 } else { 258 if (kctx->version == 1) { 259 rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last; 260 if (rtol < 0.0) rtol = -rtol; 261 stol = pow(kctx->rtol_last,kctx->alpha2); 262 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 263 } else if (kctx->version == 2) { 264 rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha); 265 stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha); 266 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 267 } else SETERRQ( PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported"); 268 } 269 rtol = PetscMin(rtol,kctx->rtol_max); 270 kctx->rtol_last = rtol; 271 PLogInfo(snes,"SNESConverged_EQ_LS: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n", 272 snes->iter,kctx->version,rtol); 273 ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT); CHKERRQ(ierr); 274 kctx->norm_last = snes->norm; 275 PetscFunctionReturn(0); 276 } 277 278 #undef __FUNC__ 279 #define __FUNC__ "SNES_KSP_EW_Converged_Private" 280 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx) 281 { 282 SNES snes = (SNES)ctx; 283 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 284 int convinfo; 285 286 PetscFunctionBegin; 287 if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set"); 288 if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp); 289 convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx); 290 kctx->lresid_last = rnorm; 291 if (convinfo) { 292 PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm); 293 } 294 PetscFunctionReturn(convinfo); 295 } 296 297 298