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