1 #include <petsc-private/snesimpl.h> /*I "petscsnes.h" I*/ 2 3 typedef struct { 4 PetscInt sweeps; /* number of sweeps through the local subdomain before neighbor communication */ 5 PetscInt max_its; /* maximum iterations of the inner pointblock solver */ 6 PetscReal rtol; /* relative tolerance of the inner pointblock solver */ 7 PetscReal abstol; /* absolute tolerance of the inner pointblock solver */ 8 PetscReal stol; /* step tolerance of the inner pointblock solver */ 9 } SNES_GS; 10 11 12 #undef __FUNCT__ 13 #define __FUNCT__ "SNESGSSetTolerances" 14 /*@ 15 SNESGSSetTolerances - Sets various parameters used in convergence tests. 16 17 Logically Collective on SNES 18 19 Input Parameters: 20 + snes - the SNES context 21 . abstol - absolute convergence tolerance 22 . rtol - relative convergence tolerance 23 . stol - convergence tolerance in terms of the norm of the change in the solution between steps, || delta x || < stol*|| x || 24 - maxit - maximum number of iterations 25 26 27 Options Database Keys: 28 + -snes_gs_atol <abstol> - Sets abstol 29 . -snes_gs_rtol <rtol> - Sets rtol 30 . -snes_gs_stol <stol> - Sets stol 31 - -snes_max_it <maxit> - Sets maxit 32 33 Level: intermediate 34 35 .keywords: SNES, nonlinear, gauss-seidel, set, convergence, tolerances 36 37 .seealso: SNESSetTrustRegionTolerance() 38 @*/ 39 PetscErrorCode SNESGSSetTolerances(SNES snes,PetscReal abstol,PetscReal rtol,PetscReal stol,PetscInt maxit) 40 { 41 SNES_GS *gs = (SNES_GS*)snes->data; 42 43 PetscFunctionBegin; 44 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 45 46 if (abstol != PETSC_DEFAULT) { 47 if (abstol < 0.0) SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %G must be non-negative",abstol); 48 gs->abstol = abstol; 49 } 50 if (rtol != PETSC_DEFAULT) { 51 if (rtol < 0.0 || 1.0 <= rtol) SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Relative tolerance %G must be non-negative and less than 1.0",rtol); 52 gs->rtol = rtol; 53 } 54 if (stol != PETSC_DEFAULT) { 55 if (stol < 0.0) SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Step tolerance %G must be non-negative",stol); 56 gs->stol = stol; 57 } 58 if (maxit != PETSC_DEFAULT) { 59 if (maxit < 0) SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Maximum number of iterations %D must be non-negative",maxit); 60 gs->max_its = maxit; 61 } 62 PetscFunctionReturn(0); 63 } 64 65 #undef __FUNCT__ 66 #define __FUNCT__ "SNESGSGetTolerances" 67 /*@ 68 SNESGSGetTolerances - Gets various parameters used in convergence tests. 69 70 Not Collective 71 72 Input Parameters: 73 + snes - the SNES context 74 . atol - absolute convergence tolerance 75 . rtol - relative convergence tolerance 76 . stol - convergence tolerance in terms of the norm 77 of the change in the solution between steps 78 - maxit - maximum number of iterations 79 80 Notes: 81 The user can specify PETSC_NULL for any parameter that is not needed. 82 83 Level: intermediate 84 85 .keywords: SNES, nonlinear, get, convergence, tolerances 86 87 .seealso: SNESSetTolerances() 88 @*/ 89 PetscErrorCode SNESGSGetTolerances(SNES snes,PetscReal *atol,PetscReal *rtol,PetscReal *stol,PetscInt *maxit) 90 { 91 SNES_GS *gs = (SNES_GS*)snes->data; 92 93 PetscFunctionBegin; 94 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 95 if (atol) *atol = gs->abstol; 96 if (rtol) *rtol = gs->rtol; 97 if (stol) *stol = gs->stol; 98 if (maxit) *maxit = gs->max_its; 99 PetscFunctionReturn(0); 100 } 101 102 #undef __FUNCT__ 103 #define __FUNCT__ "SNESGSSetSweeps" 104 /*@ 105 SNESGSSetSweeps - Sets the number of sweeps of GS to use. 106 107 Input Parameters: 108 + snes - the SNES context 109 - sweeps - the number of sweeps of GS to perform. 110 111 Level: intermediate 112 113 .keywords: SNES, nonlinear, set, Gauss-Siedel 114 115 .seealso: SNESSetGS(), SNESGetGS(), SNESSetPC(), SNESGSGetSweeps() 116 @*/ 117 118 PetscErrorCode SNESGSSetSweeps(SNES snes, PetscInt sweeps) 119 { 120 SNES_GS *gs = (SNES_GS*)snes->data; 121 122 PetscFunctionBegin; 123 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 124 gs->sweeps = sweeps; 125 PetscFunctionReturn(0); 126 } 127 128 #undef __FUNCT__ 129 #define __FUNCT__ "SNESGSGetSweeps" 130 /*@ 131 SNESGSGetSweeps - Gets the number of sweeps GS will use. 132 133 Input Parameters: 134 . snes - the SNES context 135 136 Output Parameters: 137 . sweeps - the number of sweeps of GS to perform. 138 139 Level: intermediate 140 141 .keywords: SNES, nonlinear, set, Gauss-Siedel 142 143 .seealso: SNESSetGS(), SNESGetGS(), SNESSetPC(), SNESGSSetSweeps() 144 @*/ 145 PetscErrorCode SNESGSGetSweeps(SNES snes, PetscInt * sweeps) 146 { 147 SNES_GS *gs = (SNES_GS*)snes->data; 148 149 PetscFunctionBegin; 150 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 151 *sweeps = gs->sweeps; 152 PetscFunctionReturn(0); 153 } 154 155 156 #undef __FUNCT__ 157 #define __FUNCT__ "SNESDefaultApplyGS" 158 PetscErrorCode SNESDefaultApplyGS(SNES snes,Vec X,Vec F,void *ctx) 159 { 160 PetscFunctionBegin; 161 /* see if there's a coloring on the DM */ 162 PetscFunctionReturn(0); 163 } 164 165 #undef __FUNCT__ 166 #define __FUNCT__ "SNESReset_GS" 167 PetscErrorCode SNESReset_GS(SNES snes) 168 { 169 PetscFunctionBegin; 170 PetscFunctionReturn(0); 171 } 172 173 #undef __FUNCT__ 174 #define __FUNCT__ "SNESDestroy_GS" 175 PetscErrorCode SNESDestroy_GS(SNES snes) 176 { 177 PetscErrorCode ierr; 178 179 PetscFunctionBegin; 180 ierr = SNESReset_GS(snes);CHKERRQ(ierr); 181 ierr = PetscFree(snes->data);CHKERRQ(ierr); 182 PetscFunctionReturn(0); 183 } 184 185 #undef __FUNCT__ 186 #define __FUNCT__ "SNESSetUp_GS" 187 PetscErrorCode SNESSetUp_GS(SNES snes) 188 { 189 PetscFunctionBegin; 190 PetscFunctionReturn(0); 191 } 192 193 #undef __FUNCT__ 194 #define __FUNCT__ "SNESSetFromOptions_GS" 195 PetscErrorCode SNESSetFromOptions_GS(SNES snes) 196 { 197 SNES_GS *gs = (SNES_GS*)snes->data; 198 PetscErrorCode ierr; 199 PetscInt sweeps,max_its=PETSC_DEFAULT; 200 PetscReal rtol=PETSC_DEFAULT,atol=PETSC_DEFAULT,stol=PETSC_DEFAULT; 201 PetscBool flg,flg1,flg2,flg3; 202 203 PetscFunctionBegin; 204 ierr = PetscOptionsHead("SNES GS options");CHKERRQ(ierr); 205 /* GS Options */ 206 ierr = PetscOptionsInt("-snes_gs_sweeps","Number of sweeps of GS to apply","SNESComputeGS",gs->sweeps,&sweeps,&flg);CHKERRQ(ierr); 207 if (flg) { 208 ierr = SNESGSSetSweeps(snes,sweeps);CHKERRQ(ierr); 209 } 210 ierr = PetscOptionsReal("-snes_gs_atol","Number of sweeps of GS to apply","SNESComputeGS",gs->abstol,&atol,&flg);CHKERRQ(ierr); 211 ierr = PetscOptionsReal("-snes_gs_rtol","Number of sweeps of GS to apply","SNESComputeGS",gs->rtol,&rtol,&flg1);CHKERRQ(ierr); 212 ierr = PetscOptionsReal("-snes_gs_stol","Number of sweeps of GS to apply","SNESComputeGS",gs->stol,&stol,&flg2);CHKERRQ(ierr); 213 ierr = PetscOptionsInt("-snes_gs_max_it","Number of sweeps of GS to apply","SNESComputeGS",gs->max_its,&max_its,&flg3);CHKERRQ(ierr); 214 if (flg || flg1 || flg2 || flg3) { 215 ierr = SNESGSSetTolerances(snes,atol,rtol,stol,max_its);CHKERRQ(ierr); 216 } 217 ierr = PetscOptionsTail();CHKERRQ(ierr); 218 PetscFunctionReturn(0); 219 } 220 221 #undef __FUNCT__ 222 #define __FUNCT__ "SNESView_GS" 223 PetscErrorCode SNESView_GS(SNES snes, PetscViewer viewer) 224 { 225 PetscFunctionBegin; 226 PetscFunctionReturn(0); 227 } 228 229 #undef __FUNCT__ 230 #define __FUNCT__ "SNESSolve_GS" 231 PetscErrorCode SNESSolve_GS(SNES snes) 232 { 233 Vec F; 234 Vec X; 235 Vec B; 236 PetscInt i; 237 PetscReal fnorm; 238 PetscErrorCode ierr; 239 SNESNormType normtype; 240 241 PetscFunctionBegin; 242 X = snes->vec_sol; 243 F = snes->vec_func; 244 B = snes->vec_rhs; 245 246 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 247 snes->iter = 0; 248 snes->norm = 0.; 249 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 250 snes->reason = SNES_CONVERGED_ITERATING; 251 252 ierr = SNESGetNormType(snes, &normtype);CHKERRQ(ierr); 253 if (normtype == SNES_NORM_FUNCTION || normtype == SNES_NORM_INITIAL_ONLY || normtype == SNES_NORM_INITIAL_FINAL_ONLY) { 254 /* compute the initial function and preconditioned update delX */ 255 if (!snes->vec_func_init_set) { 256 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 257 if (snes->domainerror) { 258 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 259 PetscFunctionReturn(0); 260 } 261 } else snes->vec_func_init_set = PETSC_FALSE; 262 263 /* convergence test */ 264 if (!snes->norm_init_set) { 265 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 266 if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); 267 } else { 268 fnorm = snes->norm_init; 269 snes->norm_init_set = PETSC_FALSE; 270 } 271 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 272 snes->iter = 0; 273 snes->norm = fnorm; 274 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 275 SNESLogConvHistory(snes,snes->norm,0); 276 ierr = SNESMonitor(snes,0,snes->norm);CHKERRQ(ierr); 277 278 /* set parameter for default relative tolerance convergence test */ 279 snes->ttol = fnorm*snes->rtol; 280 281 /* test convergence */ 282 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 283 if (snes->reason) PetscFunctionReturn(0); 284 } else { 285 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 286 SNESLogConvHistory(snes,snes->norm,0); 287 ierr = SNESMonitor(snes,0,snes->norm);CHKERRQ(ierr); 288 } 289 290 291 /* Call general purpose update function */ 292 if (snes->ops->update) { 293 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 294 } 295 296 for (i = 0; i < snes->max_its; i++) { 297 ierr = SNESComputeGS(snes, B, X);CHKERRQ(ierr); 298 /* only compute norms if requested or about to exit due to maximum iterations */ 299 if (normtype == SNES_NORM_FUNCTION || ((i == snes->max_its - 1) && (normtype == SNES_NORM_INITIAL_FINAL_ONLY || normtype == SNES_NORM_FINAL_ONLY))) { 300 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 301 if (snes->domainerror) { 302 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 303 PetscFunctionReturn(0); 304 } 305 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 306 if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); 307 } 308 /* Monitor convergence */ 309 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 310 snes->iter = i+1; 311 snes->norm = fnorm; 312 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 313 SNESLogConvHistory(snes,snes->norm,0); 314 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 315 /* Test for convergence */ 316 if (normtype == SNES_NORM_FUNCTION) ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 317 if (snes->reason) PetscFunctionReturn(0); 318 /* Call general purpose update function */ 319 if (snes->ops->update) { 320 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 321 } 322 } 323 if (normtype == SNES_NORM_FUNCTION) { 324 if (i == snes->max_its) { 325 ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",snes->max_its);CHKERRQ(ierr); 326 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 327 } 328 } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; /* GS is meant to be used as a preconditioner */ 329 PetscFunctionReturn(0); 330 } 331 332 /*MC 333 SNESGS - Just calls the user-provided solution routine provided with SNESSetGS() 334 335 Level: advanced 336 337 Notes: 338 the Gauss-Seidel smoother is inherited through composition. If a solver has been created with SNESGetPC(), it will have 339 its parent's Gauss-Seidel routine associated with it. 340 341 .seealso: SNESCreate(), SNES, SNESSetType(), SNESSetGS(), SNESType (for list of available types) 342 M*/ 343 344 EXTERN_C_BEGIN 345 #undef __FUNCT__ 346 #define __FUNCT__ "SNESCreate_GS" 347 PetscErrorCode SNESCreate_GS(SNES snes) 348 { 349 SNES_GS *gs; 350 PetscErrorCode ierr; 351 352 PetscFunctionBegin; 353 snes->ops->destroy = SNESDestroy_GS; 354 snes->ops->setup = SNESSetUp_GS; 355 snes->ops->setfromoptions = SNESSetFromOptions_GS; 356 snes->ops->view = SNESView_GS; 357 snes->ops->solve = SNESSolve_GS; 358 snes->ops->reset = SNESReset_GS; 359 360 snes->usesksp = PETSC_FALSE; 361 snes->usespc = PETSC_FALSE; 362 363 if (!snes->tolerancesset) { 364 snes->max_its = 10000; 365 snes->max_funcs = 10000; 366 } 367 368 ierr = PetscNewLog(snes, SNES_GS, &gs);CHKERRQ(ierr); 369 370 gs->sweeps = 1; 371 gs->rtol = 1e-5; 372 gs->abstol = 1e-15; 373 gs->stol = 1e-12; 374 gs->max_its = 50; 375 376 snes->data = (void*) gs; 377 PetscFunctionReturn(0); 378 } 379 EXTERN_C_END 380