1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: snesut.c,v 1.32 1997/08/22 15:17:50 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(1,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(1,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(1,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,"SNES:Failed to converged, function norm is NaN\n"); 118 PetscFunctionReturn(-3); 119 } 120 if (fnorm <= snes->ttol) { 121 PLogInfo(snes, 122 "SNES: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 "SNES: 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 "SNES: 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,"SNES: 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(1,0,"No context"); 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) SETERRQ(1,0, 225 "0.0 <= rtol_0 < 1.0\n"); 226 if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) SETERRQ(1,0, 227 "0.0 <= rtol_max < 1.0\n"); 228 if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) SETERRQ(1,0, 229 "0.0 < threshold < 1.0\n"); 230 if (kctx->gamma < 0.0 || kctx->gamma > 1.0) SETERRQ(1,0, 231 "0.0 <= alpha <= 1.0\n"); 232 if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) SETERRQ(1,0, 233 "1.0 < alpha <= 2.0\n"); 234 if (kctx->version != 1 && kctx->version !=2) SETERRQ(1,0, 235 "Only versions 1 and 2 are supported"); 236 PetscFunctionReturn(0); 237 } 238 239 #undef __FUNC__ 240 #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private" 241 int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp) 242 { 243 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 244 double rtol, stol; 245 int ierr; 246 247 PetscFunctionBegin; 248 if (!kctx) SETERRQ(1,0,"No context"); 249 if (snes->iter == 1) { 250 rtol = kctx->rtol_0; 251 } else { 252 if (kctx->version == 1) { 253 rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last; 254 if (rtol < 0.0) rtol = -rtol; 255 stol = pow(kctx->rtol_last,kctx->alpha2); 256 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 257 } else if (kctx->version == 2) { 258 rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha); 259 stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha); 260 if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 261 } else SETERRQ(1,0,"Only versions 1 or 2 are supported"); 262 } 263 rtol = PetscMin(rtol,kctx->rtol_max); 264 kctx->rtol_last = rtol; 265 PLogInfo(snes, 266 "SNES: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n", 267 snes->iter,kctx->version,rtol); 268 ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT); CHKERRQ(ierr); 269 kctx->norm_last = snes->norm; 270 PetscFunctionReturn(0); 271 } 272 273 #undef __FUNC__ 274 #define __FUNC__ "SNES_KSP_EW_Converged_Private" 275 int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx) 276 { 277 SNES snes = (SNES)ctx; 278 SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 279 int convinfo; 280 281 PetscFunctionBegin; 282 if (!kctx) SETERRQ(1,0,"No convergence context"); 283 if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp); 284 convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx); 285 kctx->lresid_last = rnorm; 286 if (convinfo) { 287 PLogInfo(snes,"SNES: KSP iterations=%d, rnorm=%g\n",n,rnorm); 288 } 289 PetscFunctionReturn(convinfo); 290 } 291 292 293