1 /* Defines the basic SNES object */ 2 #include <../src/snes/impls/fas/fasimpls.h> /*I "petscsnesfas.h" I*/ 3 4 const char *SNESFASTypes[] = {"MULTIPLICATIVE","ADDITIVE","SNESFASType","SNES_FAS",0}; 5 6 /*MC 7 8 SNESFAS - Full Approximation Scheme nonlinear multigrid solver. 9 10 The nonlinear problem is solved via the repeated application of nonlinear preconditioners and coarse-grid corrections 11 12 .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types) 13 M*/ 14 15 extern PetscErrorCode SNESDestroy_FAS(SNES snes); 16 extern PetscErrorCode SNESSetUp_FAS(SNES snes); 17 extern PetscErrorCode SNESSetFromOptions_FAS(SNES snes); 18 extern PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer); 19 extern PetscErrorCode SNESSolve_FAS(SNES snes); 20 extern PetscErrorCode SNESReset_FAS(SNES snes); 21 extern PetscErrorCode SNESFASGalerkinDefaultFunction(SNES, Vec, Vec, void *); 22 23 EXTERN_C_BEGIN 24 #undef __FUNCT__ 25 #define __FUNCT__ "SNESLineSearchSetType_FAS" 26 PetscErrorCode SNESLineSearchSetType_FAS(SNES snes, SNESLineSearchType type) 27 { 28 PetscErrorCode ierr; 29 PetscFunctionBegin; 30 31 switch (type) { 32 case SNES_LS_BASIC: 33 ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr); 34 break; 35 case SNES_LS_BASIC_NONORMS: 36 ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr); 37 break; 38 case SNES_LS_QUADRATIC: 39 ierr = SNESLineSearchSet(snes,SNESLineSearchQuadraticSecant,PETSC_NULL);CHKERRQ(ierr); 40 break; 41 default: 42 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type."); 43 break; 44 } 45 snes->ls_type = type; 46 PetscFunctionReturn(0); 47 } 48 EXTERN_C_END 49 50 EXTERN_C_BEGIN 51 52 #undef __FUNCT__ 53 #define __FUNCT__ "SNESCreate_FAS" 54 PetscErrorCode SNESCreate_FAS(SNES snes) 55 { 56 SNES_FAS * fas; 57 PetscErrorCode ierr; 58 59 PetscFunctionBegin; 60 snes->ops->destroy = SNESDestroy_FAS; 61 snes->ops->setup = SNESSetUp_FAS; 62 snes->ops->setfromoptions = SNESSetFromOptions_FAS; 63 snes->ops->view = SNESView_FAS; 64 snes->ops->solve = SNESSolve_FAS; 65 snes->ops->reset = SNESReset_FAS; 66 67 snes->usesksp = PETSC_FALSE; 68 snes->usespc = PETSC_FALSE; 69 70 ierr = PetscNewLog(snes, SNES_FAS, &fas);CHKERRQ(ierr); 71 snes->data = (void*) fas; 72 fas->level = 0; 73 fas->levels = 1; 74 fas->n_cycles = 1; 75 fas->max_up_it = 1; 76 fas->max_down_it = 1; 77 fas->upsmooth = PETSC_NULL; 78 fas->downsmooth = PETSC_NULL; 79 fas->next = PETSC_NULL; 80 fas->previous = PETSC_NULL; 81 fas->interpolate = PETSC_NULL; 82 fas->restrct = PETSC_NULL; 83 fas->inject = PETSC_NULL; 84 fas->monitor = PETSC_NULL; 85 fas->usedmfornumberoflevels = PETSC_FALSE; 86 fas->fastype = SNES_FAS_MULTIPLICATIVE; 87 88 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_FAS",SNESLineSearchSetType_FAS);CHKERRQ(ierr); 89 ierr = SNESLineSearchSetType(snes, SNES_LS_QUADRATIC);CHKERRQ(ierr); 90 91 PetscFunctionReturn(0); 92 } 93 EXTERN_C_END 94 95 #undef __FUNCT__ 96 #define __FUNCT__ "SNESFASGetLevels" 97 /*@ 98 SNESFASGetLevels - Gets the number of levels in a FAS. 99 100 Input Parameter: 101 . snes - the preconditioner context 102 103 Output parameter: 104 . levels - the number of levels 105 106 Level: advanced 107 108 .keywords: MG, get, levels, multigrid 109 110 .seealso: SNESFASSetLevels(), PCMGGetLevels() 111 @*/ 112 PetscErrorCode SNESFASGetLevels(SNES snes, PetscInt * levels) { 113 SNES_FAS * fas = (SNES_FAS *)snes->data; 114 PetscFunctionBegin; 115 *levels = fas->levels; 116 PetscFunctionReturn(0); 117 } 118 119 #undef __FUNCT__ 120 #define __FUNCT__ "SNESFASSetCycles" 121 /*@ 122 SNESFASSetCycles - Sets the type cycles to use. Use SNESFASSetCyclesOnLevel() for more 123 complicated cycling. 124 125 Logically Collective on SNES 126 127 Input Parameters: 128 + snes - the multigrid context 129 - cycles - the number of cycles -- 1 for V-cycle, 2 for W-cycle 130 131 Options Database Key: 132 $ -snes_fas_cycles 1 or 2 133 134 Level: advanced 135 136 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid 137 138 .seealso: SNESFASSetCyclesOnLevel() 139 @*/ 140 PetscErrorCode SNESFASSetCycles(SNES snes, PetscInt cycles) { 141 SNES_FAS * fas = (SNES_FAS *)snes->data; 142 PetscErrorCode ierr; 143 PetscFunctionBegin; 144 fas->n_cycles = cycles; 145 if (fas->next) { 146 ierr = SNESFASSetCycles(fas->next, cycles);CHKERRQ(ierr); 147 } 148 PetscFunctionReturn(0); 149 } 150 151 #undef __FUNCT__ 152 #define __FUNCT__ "SNESFASSetCyclesOnLevel" 153 /*@ 154 SNESFASSetCyclesOnLevel - Sets the type cycles to use on a particular level. 155 156 Logically Collective on SNES 157 158 Input Parameters: 159 + snes - the multigrid context 160 . level - the level to set the number of cycles on 161 - cycles - the number of cycles -- 1 for V-cycle, 2 for W-cycle 162 163 Level: advanced 164 165 .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid 166 167 .seealso: SNESFASSetCycles() 168 @*/ 169 PetscErrorCode SNESFASSetCyclesOnLevel(SNES snes, PetscInt level, PetscInt cycles) { 170 SNES_FAS * fas = (SNES_FAS *)snes->data; 171 PetscInt top_level = fas->level,i; 172 173 PetscFunctionBegin; 174 if (level > top_level) 175 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetCyclesOnLevel", level); 176 /* get to the correct level */ 177 for (i = fas->level; i > level; i--) { 178 fas = (SNES_FAS *)fas->next->data; 179 } 180 if (fas->level != level) 181 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetCyclesOnLevel"); 182 fas->n_cycles = cycles; 183 PetscFunctionReturn(0); 184 } 185 186 #undef __FUNCT__ 187 #define __FUNCT__ "SNESFASSetGS" 188 /*@C 189 SNESFASSetGS - Sets a nonlinear GS smoother and if it should be used. 190 Use SNESFASSetGSOnLevel() for more complicated staging of smoothers 191 and nonlinear preconditioners. 192 193 Logically Collective on SNES 194 195 Input Parameters: 196 + snes - the multigrid context 197 . gsfunc - the nonlinear smoother function 198 . ctx - the user context for the nonlinear smoother 199 - use_gs - whether to use the nonlinear smoother or not 200 201 Level: advanced 202 203 .keywords: FAS, MG, set, cycles, gauss-seidel, multigrid 204 205 .seealso: SNESSetGS(), SNESFASSetGSOnLevel() 206 @*/ 207 PetscErrorCode SNESFASSetGS(SNES snes, PetscErrorCode (*gsfunc)(SNES,Vec,Vec,void *), void * ctx, PetscBool use_gs) { 208 PetscErrorCode ierr = 0; 209 SNES_FAS *fas = (SNES_FAS *)snes->data; 210 PetscFunctionBegin; 211 212 /* use or don't use it according to user wishes*/ 213 snes->usegs = use_gs; 214 if (gsfunc) { 215 ierr = SNESSetGS(snes, gsfunc, ctx);CHKERRQ(ierr); 216 /* push the provided GS up the tree */ 217 if (fas->next) ierr = SNESFASSetGS(fas->next, gsfunc, ctx, use_gs);CHKERRQ(ierr); 218 } else if (snes->ops->computegs) { 219 /* assume that the user has set the GS solver at this level */ 220 if (fas->next) ierr = SNESFASSetGS(fas->next, PETSC_NULL, PETSC_NULL, use_gs);CHKERRQ(ierr); 221 } else if (use_gs) { 222 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "No user Gauss-Seidel function provided in SNESFASSetGS on level %d", fas->level); 223 } 224 PetscFunctionReturn(0); 225 } 226 227 #undef __FUNCT__ 228 #define __FUNCT__ "SNESFASSetGSOnLevel" 229 /*@C 230 SNESFASSetGSOnLevel - Sets the nonlinear smoother on a particular level. 231 232 Logically Collective on SNES 233 234 Input Parameters: 235 + snes - the multigrid context 236 . level - the level to set the nonlinear smoother on 237 . gsfunc - the nonlinear smoother function 238 . ctx - the user context for the nonlinear smoother 239 - use_gs - whether to use the nonlinear smoother or not 240 241 Level: advanced 242 243 .keywords: FAS, MG, set, cycles, Gauss-Seidel, multigrid 244 245 .seealso: SNESSetGS(), SNESFASSetGS() 246 @*/ 247 PetscErrorCode SNESFASSetGSOnLevel(SNES snes, PetscInt level, PetscErrorCode (*gsfunc)(SNES,Vec,Vec,void *), void * ctx, PetscBool use_gs) { 248 SNES_FAS *fas = (SNES_FAS *)snes->data; 249 PetscErrorCode ierr; 250 PetscInt top_level = fas->level,i; 251 SNES cur_snes = snes; 252 PetscFunctionBegin; 253 if (level > top_level) 254 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetCyclesOnLevel", level); 255 /* get to the correct level */ 256 for (i = fas->level; i > level; i--) { 257 fas = (SNES_FAS *)fas->next->data; 258 cur_snes = fas->next; 259 } 260 if (fas->level != level) 261 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetCyclesOnLevel"); 262 snes->usegs = use_gs; 263 if (gsfunc) { 264 ierr = SNESSetGS(cur_snes, gsfunc, ctx);CHKERRQ(ierr); 265 } 266 PetscFunctionReturn(0); 267 } 268 269 #undef __FUNCT__ 270 #define __FUNCT__ "SNESFASGetSNES" 271 /*@ 272 SNESFASGetSNES - Gets the SNES corresponding to a particular 273 level of the FAS hierarchy. 274 275 Input Parameters: 276 + snes - the multigrid context 277 level - the level to get 278 - lsnes - whether to use the nonlinear smoother or not 279 280 Level: advanced 281 282 .keywords: FAS, MG, set, cycles, Gauss-Seidel, multigrid 283 284 .seealso: SNESFASSetLevels(), SNESFASGetLevels() 285 @*/ 286 PetscErrorCode SNESFASGetSNES(SNES snes, PetscInt level, SNES * lsnes) { 287 SNES_FAS * fas = (SNES_FAS *)snes->data; 288 PetscInt levels = fas->level; 289 PetscInt i; 290 PetscFunctionBegin; 291 *lsnes = snes; 292 if (fas->level < level) { 293 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "SNESFASGetSNES should only be called on a finer SNESFAS instance than the level."); 294 } 295 if (level > levels - 1) { 296 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Level %d doesn't exist in the SNESFAS."); 297 } 298 for (i = fas->level; i > level; i--) { 299 *lsnes = fas->next; 300 fas = (SNES_FAS *)(*lsnes)->data; 301 } 302 if (fas->level != level) SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "SNESFASGetSNES didn't return the right level!"); 303 PetscFunctionReturn(0); 304 } 305 306 #undef __FUNCT__ 307 #define __FUNCT__ "SNESFASSetType" 308 /*@ 309 SNESFASSetType - Sets the update and correction type used for FAS. 310 e 311 312 313 @*/ 314 PetscErrorCode SNESFASSetType(SNES snes,SNESFASType fastype) 315 { 316 SNES_FAS *fas = (SNES_FAS*)snes->data; 317 318 PetscFunctionBegin; 319 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 320 PetscValidLogicalCollectiveEnum(snes,fastype,2); 321 fas->fastype = fastype; 322 PetscFunctionReturn(0); 323 } 324 325 326 327 #undef __FUNCT__ 328 #define __FUNCT__ "SNESFASSetLevels" 329 /*@C 330 SNESFASSetLevels - Sets the number of levels to use with FAS. 331 Must be called before any other FAS routine. 332 333 Input Parameters: 334 + snes - the snes context 335 . levels - the number of levels 336 - comms - optional communicators for each level; this is to allow solving the coarser 337 problems on smaller sets of processors. Use PETSC_NULL_OBJECT for default in 338 Fortran. 339 340 Level: intermediate 341 342 Notes: 343 If the number of levels is one then the multigrid uses the -fas_levels prefix 344 for setting the level options rather than the -fas_coarse prefix. 345 346 .keywords: FAS, MG, set, levels, multigrid 347 348 .seealso: SNESFASGetLevels() 349 @*/ 350 PetscErrorCode SNESFASSetLevels(SNES snes, PetscInt levels, MPI_Comm * comms) { 351 PetscErrorCode ierr; 352 PetscInt i; 353 SNES_FAS * fas = (SNES_FAS *)snes->data; 354 SNES prevsnes; 355 MPI_Comm comm; 356 PetscFunctionBegin; 357 comm = ((PetscObject)snes)->comm; 358 if (levels == fas->levels) { 359 if (!comms) 360 PetscFunctionReturn(0); 361 } 362 /* user has changed the number of levels; reset */ 363 ierr = SNESReset(snes);CHKERRQ(ierr); 364 /* destroy any coarser levels if necessary */ 365 if (fas->next) SNESDestroy(&fas->next);CHKERRQ(ierr); 366 fas->next = PETSC_NULL; 367 fas->previous = PETSC_NULL; 368 prevsnes = snes; 369 /* setup the finest level */ 370 for (i = levels - 1; i >= 0; i--) { 371 if (comms) comm = comms[i]; 372 fas->level = i; 373 fas->levels = levels; 374 fas->next = PETSC_NULL; 375 if (i > 0) { 376 ierr = SNESCreate(comm, &fas->next);CHKERRQ(ierr); 377 ierr = SNESSetOptionsPrefix(fas->next,((PetscObject)snes)->prefix);CHKERRQ(ierr); 378 ierr = SNESSetType(fas->next, SNESFAS);CHKERRQ(ierr); 379 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->next, (PetscObject)snes, levels - i);CHKERRQ(ierr); 380 ((SNES_FAS *)fas->next->data)->previous = prevsnes; 381 prevsnes = fas->next; 382 fas = (SNES_FAS *)prevsnes->data; 383 } 384 } 385 PetscFunctionReturn(0); 386 } 387 388 #undef __FUNCT__ 389 #define __FUNCT__ "SNESFASSetNumberSmoothUp" 390 /*@ 391 SNESFASSetNumberSmoothUp - Sets the number of post-smoothing steps to 392 use on all levels. 393 394 Logically Collective on PC 395 396 Input Parameters: 397 + snes - the multigrid context 398 - n - the number of smoothing steps 399 400 Options Database Key: 401 . -snes_fas_smoothup <n> - Sets number of pre-smoothing steps 402 403 Level: advanced 404 405 .keywords: FAS, MG, smooth, down, pre-smoothing, steps, multigrid 406 407 .seealso: SNESFASSetNumberSmoothDown() 408 @*/ 409 PetscErrorCode SNESFASSetNumberSmoothUp(SNES snes, PetscInt n) { 410 SNES_FAS * fas = (SNES_FAS *)snes->data; 411 PetscErrorCode ierr = 0; 412 PetscFunctionBegin; 413 fas->max_up_it = n; 414 if (fas->next) { 415 ierr = SNESFASSetNumberSmoothUp(fas->next, n);CHKERRQ(ierr); 416 } 417 PetscFunctionReturn(0); 418 } 419 420 #undef __FUNCT__ 421 #define __FUNCT__ "SNESFASSetNumberSmoothDown" 422 /*@ 423 SNESFASSetNumberSmoothDown - Sets the number of pre-smoothing steps to 424 use on all levels. 425 426 Logically Collective on PC 427 428 Input Parameters: 429 + snes - the multigrid context 430 - n - the number of smoothing steps 431 432 Options Database Key: 433 . -snes_fas_smoothdown <n> - Sets number of pre-smoothing steps 434 435 Level: advanced 436 437 .keywords: FAS, MG, smooth, down, pre-smoothing, steps, multigrid 438 439 .seealso: SNESFASSetNumberSmoothUp() 440 @*/ 441 PetscErrorCode SNESFASSetNumberSmoothDown(SNES snes, PetscInt n) { 442 SNES_FAS * fas = (SNES_FAS *)snes->data; 443 PetscErrorCode ierr = 0; 444 PetscFunctionBegin; 445 fas->max_down_it = n; 446 if (fas->next) { 447 ierr = SNESFASSetNumberSmoothDown(fas->next, n);CHKERRQ(ierr); 448 } 449 PetscFunctionReturn(0); 450 } 451 452 #undef __FUNCT__ 453 #define __FUNCT__ "SNESFASSetInterpolation" 454 /*@ 455 SNESFASSetInterpolation - Sets the function to be used to calculate the 456 interpolation from l-1 to the lth level 457 458 Input Parameters: 459 + snes - the multigrid context 460 . mat - the interpolation operator 461 - level - the level (0 is coarsest) to supply [do not supply 0] 462 463 Level: advanced 464 465 Notes: 466 Usually this is the same matrix used also to set the restriction 467 for the same level. 468 469 One can pass in the interpolation matrix or its transpose; PETSc figures 470 out from the matrix size which one it is. 471 472 .keywords: FAS, multigrid, set, interpolate, level 473 474 .seealso: SNESFASSetInjection(), SNESFASSetRestriction(), SNESFASSetRscale() 475 @*/ 476 PetscErrorCode SNESFASSetInterpolation(SNES snes, PetscInt level, Mat mat) { 477 SNES_FAS * fas = (SNES_FAS *)snes->data; 478 PetscInt top_level = fas->level,i; 479 480 PetscFunctionBegin; 481 if (level > top_level) 482 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetInterpolation", level); 483 /* get to the correct level */ 484 for (i = fas->level; i > level; i--) { 485 fas = (SNES_FAS *)fas->next->data; 486 } 487 if (fas->level != level) 488 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetInterpolation"); 489 fas->interpolate = mat; 490 PetscFunctionReturn(0); 491 } 492 493 #undef __FUNCT__ 494 #define __FUNCT__ "SNESFASSetRestriction" 495 /*@ 496 SNESFASSetRestriction - Sets the function to be used to restrict the defect 497 from level l to l-1. 498 499 Input Parameters: 500 + snes - the multigrid context 501 . mat - the restriction matrix 502 - level - the level (0 is coarsest) to supply [Do not supply 0] 503 504 Level: advanced 505 506 Notes: 507 Usually this is the same matrix used also to set the interpolation 508 for the same level. 509 510 One can pass in the interpolation matrix or its transpose; PETSc figures 511 out from the matrix size which one it is. 512 513 If you do not set this, the transpose of the Mat set with PCMGSetInterpolation() 514 is used. 515 516 .keywords: FAS, MG, set, multigrid, restriction, level 517 518 .seealso: SNESFASSetInterpolation(), SNESFASSetInjection() 519 @*/ 520 PetscErrorCode SNESFASSetRestriction(SNES snes, PetscInt level, Mat mat) { 521 SNES_FAS * fas = (SNES_FAS *)snes->data; 522 PetscInt top_level = fas->level,i; 523 524 PetscFunctionBegin; 525 if (level > top_level) 526 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetRestriction", level); 527 /* get to the correct level */ 528 for (i = fas->level; i > level; i--) { 529 fas = (SNES_FAS *)fas->next->data; 530 } 531 if (fas->level != level) 532 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetRestriction"); 533 fas->restrct = mat; 534 PetscFunctionReturn(0); 535 } 536 537 538 #undef __FUNCT__ 539 #define __FUNCT__ "SNESFASSetRScale" 540 /*@ 541 SNESFASSetRScale - Sets the scaling factor of the restriction 542 operator from level l to l-1. 543 544 Input Parameters: 545 + snes - the multigrid context 546 . rscale - the restriction scaling 547 - level - the level (0 is coarsest) to supply [Do not supply 0] 548 549 Level: advanced 550 551 Notes: 552 This is only used in the case that the injection is not set. 553 554 .keywords: FAS, MG, set, multigrid, restriction, level 555 556 .seealso: SNESFASSetInjection(), SNESFASSetRestriction() 557 @*/ 558 PetscErrorCode SNESFASSetRScale(SNES snes, PetscInt level, Vec rscale) { 559 SNES_FAS * fas = (SNES_FAS *)snes->data; 560 PetscInt top_level = fas->level,i; 561 562 PetscFunctionBegin; 563 if (level > top_level) 564 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetRestriction", level); 565 /* get to the correct level */ 566 for (i = fas->level; i > level; i--) { 567 fas = (SNES_FAS *)fas->next->data; 568 } 569 if (fas->level != level) 570 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetRestriction"); 571 fas->rscale = rscale; 572 PetscFunctionReturn(0); 573 } 574 575 576 #undef __FUNCT__ 577 #define __FUNCT__ "SNESFASSetInjection" 578 /*@ 579 SNESFASSetInjection - Sets the function to be used to inject the solution 580 from level l to l-1. 581 582 Input Parameters: 583 + snes - the multigrid context 584 . mat - the restriction matrix 585 - level - the level (0 is coarsest) to supply [Do not supply 0] 586 587 Level: advanced 588 589 Notes: 590 If you do not set this, the restriction and rscale is used to 591 project the solution instead. 592 593 .keywords: FAS, MG, set, multigrid, restriction, level 594 595 .seealso: SNESFASSetInterpolation(), SNESFASSetRestriction() 596 @*/ 597 PetscErrorCode SNESFASSetInjection(SNES snes, PetscInt level, Mat mat) { 598 SNES_FAS * fas = (SNES_FAS *)snes->data; 599 PetscInt top_level = fas->level,i; 600 601 PetscFunctionBegin; 602 if (level > top_level) 603 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetInjection", level); 604 /* get to the correct level */ 605 for (i = fas->level; i > level; i--) { 606 fas = (SNES_FAS *)fas->next->data; 607 } 608 if (fas->level != level) 609 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetInjection"); 610 fas->inject = mat; 611 PetscFunctionReturn(0); 612 } 613 614 #undef __FUNCT__ 615 #define __FUNCT__ "SNESReset_FAS" 616 PetscErrorCode SNESReset_FAS(SNES snes) 617 { 618 PetscErrorCode ierr = 0; 619 SNES_FAS * fas = (SNES_FAS *)snes->data; 620 621 PetscFunctionBegin; 622 if (fas->upsmooth) ierr = SNESReset(fas->upsmooth);CHKERRQ(ierr); 623 if (fas->downsmooth) ierr = SNESReset(fas->downsmooth);CHKERRQ(ierr); 624 if (fas->next) ierr = SNESReset(fas->next);CHKERRQ(ierr); 625 PetscFunctionReturn(0); 626 } 627 628 #undef __FUNCT__ 629 #define __FUNCT__ "SNESDestroy_FAS" 630 PetscErrorCode SNESDestroy_FAS(SNES snes) 631 { 632 SNES_FAS * fas = (SNES_FAS *)snes->data; 633 PetscErrorCode ierr = 0; 634 635 PetscFunctionBegin; 636 /* recursively resets and then destroys */ 637 if (fas->upsmooth) ierr = SNESDestroy(&fas->upsmooth);CHKERRQ(ierr); 638 if (fas->downsmooth) ierr = SNESDestroy(&fas->downsmooth);CHKERRQ(ierr); 639 if (fas->inject) { 640 ierr = MatDestroy(&fas->inject);CHKERRQ(ierr); 641 } 642 if (fas->interpolate == fas->restrct) { 643 if (fas->interpolate) ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr); 644 fas->restrct = PETSC_NULL; 645 } else { 646 if (fas->interpolate) ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr); 647 if (fas->restrct) ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr); 648 } 649 if (fas->rscale) ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr); 650 if (fas->next) ierr = SNESDestroy(&fas->next);CHKERRQ(ierr); 651 ierr = PetscFree(fas);CHKERRQ(ierr); 652 653 PetscFunctionReturn(0); 654 } 655 656 #undef __FUNCT__ 657 #define __FUNCT__ "SNESSetUp_FAS" 658 PetscErrorCode SNESSetUp_FAS(SNES snes) 659 { 660 SNES_FAS *fas = (SNES_FAS *) snes->data; 661 PetscErrorCode ierr; 662 VecScatter injscatter; 663 PetscInt dm_levels; 664 665 PetscFunctionBegin; 666 667 if (fas->usedmfornumberoflevels && (fas->level == fas->levels - 1)) { 668 ierr = DMGetRefineLevel(snes->dm,&dm_levels);CHKERRQ(ierr); 669 dm_levels++; 670 if (dm_levels > fas->levels) { 671 ierr = SNESFASSetLevels(snes,dm_levels,PETSC_NULL);CHKERRQ(ierr); 672 ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); 673 } 674 } 675 676 if (fas->fastype == SNES_FAS_MULTIPLICATIVE) { 677 ierr = SNESDefaultGetWork(snes, 1);CHKERRQ(ierr); /* work vectors used for intergrid transfers */ 678 } else { 679 ierr = SNESDefaultGetWork(snes, 4);CHKERRQ(ierr); /* work vectors used for intergrid transfers */ 680 } 681 682 /* setup the pre and post smoothers and set their function, jacobian, and gs evaluation routines if the user has neglected this */ 683 if (fas->upsmooth) { 684 ierr = SNESSetFromOptions(fas->upsmooth);CHKERRQ(ierr); 685 if (snes->ops->computefunction && !fas->upsmooth->ops->computefunction) { 686 ierr = SNESSetFunction(fas->upsmooth, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr); 687 } 688 if (snes->ops->computejacobian && !fas->upsmooth->ops->computejacobian) { 689 ierr = SNESSetJacobian(fas->upsmooth, fas->upsmooth->jacobian, fas->upsmooth->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr); 690 } 691 if (snes->ops->computegs && !fas->upsmooth->ops->computegs) { 692 ierr = SNESSetGS(fas->upsmooth, snes->ops->computegs, snes->gsP);CHKERRQ(ierr); 693 } 694 } 695 if (fas->downsmooth) { 696 ierr = SNESSetFromOptions(fas->downsmooth);CHKERRQ(ierr); 697 if (snes->ops->computefunction && !fas->downsmooth->ops->computefunction) { 698 ierr = SNESSetFunction(fas->downsmooth, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr); 699 } 700 if (snes->ops->computejacobian && !fas->downsmooth->ops->computejacobian) { 701 ierr = SNESSetJacobian(fas->downsmooth, fas->downsmooth->jacobian, fas->downsmooth->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr); 702 } 703 if (snes->ops->computegs && !fas->downsmooth->ops->computegs) { 704 ierr = SNESSetGS(fas->downsmooth, snes->ops->computegs, snes->gsP);CHKERRQ(ierr); 705 } 706 } 707 /*pass the smoother, function, and jacobian up to the next level if it's not user set already */ 708 if (fas->next) { 709 if (fas->galerkin) { 710 ierr = SNESSetFunction(fas->next, PETSC_NULL, SNESFASGalerkinDefaultFunction, fas->next);CHKERRQ(ierr); 711 } else { 712 if (snes->ops->computefunction && !fas->next->ops->computefunction) { 713 ierr = SNESSetFunction(fas->next, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr); 714 } 715 if (snes->ops->computejacobian && !fas->next->ops->computejacobian) { 716 ierr = SNESSetJacobian(fas->next, fas->next->jacobian, fas->next->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr); 717 } 718 if (snes->ops->computegs && !fas->next->ops->computegs) { 719 ierr = SNESSetGS(fas->next, snes->ops->computegs, snes->gsP);CHKERRQ(ierr); 720 } 721 } 722 } 723 if (snes->dm) { 724 /* construct EVERYTHING from the DM -- including the progressive set of smoothers */ 725 if (fas->next) { 726 /* for now -- assume the DM and the evaluation functions have been set externally */ 727 if (!fas->next->dm) { 728 ierr = DMCoarsen(snes->dm, ((PetscObject)fas->next)->comm, &fas->next->dm);CHKERRQ(ierr); 729 ierr = SNESSetDM(fas->next, fas->next->dm);CHKERRQ(ierr); 730 } 731 /* set the interpolation and restriction from the DM */ 732 if (!fas->interpolate) { 733 ierr = DMCreateInterpolation(fas->next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr); 734 fas->restrct = fas->interpolate; 735 } 736 /* set the injection from the DM */ 737 if (!fas->inject) { 738 ierr = DMCreateInjection(fas->next->dm, snes->dm, &injscatter);CHKERRQ(ierr); 739 ierr = MatCreateScatter(((PetscObject)snes)->comm, injscatter, &fas->inject);CHKERRQ(ierr); 740 ierr = VecScatterDestroy(&injscatter);CHKERRQ(ierr); 741 } 742 } 743 /* set the DMs of the pre and post-smoothers here */ 744 if (fas->upsmooth) {ierr = SNESSetDM(fas->upsmooth, snes->dm);CHKERRQ(ierr);} 745 if (fas->downsmooth){ierr = SNESSetDM(fas->downsmooth, snes->dm);CHKERRQ(ierr);} 746 } 747 748 /* setup FAS work vectors */ 749 if (fas->galerkin) { 750 ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr); 751 ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr); 752 } 753 754 if (fas->next) { 755 /* gotta set up the solution vector for this to work */ 756 if (!fas->next->vec_sol) {ierr = VecDuplicate(fas->rscale, &fas->next->vec_sol);CHKERRQ(ierr);} 757 if (!fas->next->vec_rhs) {ierr = VecDuplicate(fas->rscale, &fas->next->vec_rhs);CHKERRQ(ierr);} 758 ierr = SNESSetUp(fas->next);CHKERRQ(ierr); 759 } 760 /* got to set them all up at once */ 761 PetscFunctionReturn(0); 762 } 763 764 #undef __FUNCT__ 765 #define __FUNCT__ "SNESSetFromOptions_FAS" 766 PetscErrorCode SNESSetFromOptions_FAS(SNES snes) 767 { 768 SNES_FAS *fas = (SNES_FAS *) snes->data; 769 PetscInt levels = 1; 770 PetscBool flg, smoothflg, smoothupflg, smoothdownflg, monflg; 771 PetscErrorCode ierr; 772 const char *def_smooth = SNESNRICHARDSON; 773 char pre_type[256]; 774 char post_type[256]; 775 char monfilename[PETSC_MAX_PATH_LEN]; 776 SNESFASType fastype; 777 778 PetscFunctionBegin; 779 ierr = PetscOptionsHead("SNESFAS Options-----------------------------------");CHKERRQ(ierr); 780 781 /* number of levels -- only process on the finest level */ 782 if (fas->levels - 1 == fas->level) { 783 ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr); 784 if (!flg && snes->dm) { 785 ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr); 786 levels++; 787 fas->usedmfornumberoflevels = PETSC_TRUE; 788 } 789 ierr = SNESFASSetLevels(snes, levels, PETSC_NULL);CHKERRQ(ierr); 790 } 791 792 /* type of pre and/or post smoothers -- set both at once */ 793 ierr = PetscMemcpy(post_type, def_smooth, 256);CHKERRQ(ierr); 794 ierr = PetscMemcpy(pre_type, def_smooth, 256);CHKERRQ(ierr); 795 fastype = fas->fastype; 796 ierr = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr); 797 if (flg) { 798 ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr); 799 } 800 ierr = PetscOptionsList("-snes_fas_smoother_type","Nonlinear smoother method","SNESSetType",SNESList,def_smooth,pre_type,256,&smoothflg);CHKERRQ(ierr); 801 if (smoothflg) { 802 ierr = PetscMemcpy(post_type, pre_type, 256);CHKERRQ(ierr); 803 } else { 804 ierr = PetscOptionsList("-snes_fas_smoothup_type", "Nonlinear smoother method","SNESSetType",SNESList,def_smooth,pre_type, 256,&smoothupflg);CHKERRQ(ierr); 805 ierr = PetscOptionsList("-snes_fas_smoothdown_type","Nonlinear smoother method","SNESSetType",SNESList,def_smooth,post_type,256,&smoothdownflg);CHKERRQ(ierr); 806 } 807 808 /* options for the number of preconditioning cycles and cycle type */ 809 ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smooth iterations","SNESFASSetNumberSmoothUp",fas->max_up_it,&fas->max_up_it,&flg);CHKERRQ(ierr); 810 ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smooth iterations","SNESFASSetNumberSmoothUp",fas->max_down_it,&fas->max_down_it,&flg);CHKERRQ(ierr); 811 ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&fas->n_cycles,&flg);CHKERRQ(ierr); 812 813 ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFAS",fas->galerkin,&fas->galerkin,&flg);CHKERRQ(ierr); 814 815 ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr); 816 817 /* other options for the coarsest level */ 818 if (fas->level == 0) { 819 ierr = PetscOptionsList("-snes_fas_coarse_smoother_type","Coarsest smoother method","SNESSetType",SNESList,def_smooth,pre_type,256,&smoothflg);CHKERRQ(ierr); 820 } 821 822 ierr = PetscOptionsTail();CHKERRQ(ierr); 823 /* setup from the determined types if there is no pointwise procedure or smoother defined */ 824 825 if ((!fas->downsmooth) && ((smoothdownflg || smoothflg) || !snes->usegs)) { 826 const char *prefix; 827 ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr); 828 ierr = SNESCreate(((PetscObject)snes)->comm, &fas->downsmooth);CHKERRQ(ierr); 829 ierr = SNESSetOptionsPrefix(fas->downsmooth,prefix);CHKERRQ(ierr); 830 if (fas->level || (fas->levels == 1)) { 831 ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_levels_down_");CHKERRQ(ierr); 832 } else { 833 ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_coarse_");CHKERRQ(ierr); 834 } 835 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->downsmooth, (PetscObject)snes, 1);CHKERRQ(ierr); 836 ierr = SNESSetType(fas->downsmooth, pre_type);CHKERRQ(ierr); 837 } 838 839 if ((!fas->upsmooth) && (fas->level != 0) && ((smoothupflg || smoothflg) || !snes->usegs)) { 840 const char *prefix; 841 ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr); 842 ierr = SNESCreate(((PetscObject)snes)->comm, &fas->upsmooth);CHKERRQ(ierr); 843 ierr = SNESSetOptionsPrefix(fas->upsmooth,prefix);CHKERRQ(ierr); 844 ierr = SNESAppendOptionsPrefix(fas->upsmooth,"fas_levels_up_");CHKERRQ(ierr); 845 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->upsmooth, (PetscObject)snes, 1);CHKERRQ(ierr); 846 ierr = SNESSetType(fas->upsmooth, pre_type);CHKERRQ(ierr); 847 } 848 if (fas->upsmooth) { 849 ierr = SNESSetTolerances(fas->upsmooth, 0.0, 0.0, 0.0, fas->max_up_it, 1000);CHKERRQ(ierr); 850 } 851 852 if (fas->downsmooth) { 853 ierr = SNESSetTolerances(fas->downsmooth, 0.0, 0.0, 0.0, fas->max_down_it, 1000);CHKERRQ(ierr); 854 } 855 856 if (fas->level != fas->levels - 1) { 857 ierr = SNESSetTolerances(snes, 0.0, 0.0, 0.0, fas->n_cycles, 1000);CHKERRQ(ierr); 858 } 859 860 if (monflg) { 861 fas->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr); 862 /* set the monitors for the upsmoother and downsmoother */ 863 ierr = SNESMonitorCancel(snes);CHKERRQ(ierr); 864 ierr = SNESMonitorSet(snes,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); 865 if (fas->upsmooth) ierr = SNESMonitorSet(fas->upsmooth,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); 866 if (fas->downsmooth) ierr = SNESMonitorSet(fas->downsmooth,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); 867 } else { 868 /* unset the monitors on the coarse levels */ 869 if (fas->level != fas->levels - 1) { 870 ierr = SNESMonitorCancel(snes);CHKERRQ(ierr); 871 } 872 } 873 874 /* recursive option setting for the smoothers */ 875 if (fas->next) {ierr = SNESSetFromOptions(fas->next);CHKERRQ(ierr);} 876 PetscFunctionReturn(0); 877 } 878 879 #undef __FUNCT__ 880 #define __FUNCT__ "SNESView_FAS" 881 PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer) 882 { 883 SNES_FAS *fas = (SNES_FAS *) snes->data; 884 PetscBool iascii; 885 PetscErrorCode ierr; 886 887 PetscFunctionBegin; 888 if (fas->level != fas->levels - 1) PetscFunctionReturn(0); 889 ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 890 if (iascii) { 891 ierr = PetscViewerASCIIPrintf(viewer, "FAS, levels = %d\n", fas->levels);CHKERRQ(ierr); 892 ierr = PetscViewerASCIIPushTab(viewer); 893 ierr = PetscViewerASCIIPrintf(viewer, "level: %d\n", fas->level);CHKERRQ(ierr); 894 if (fas->upsmooth) { 895 ierr = PetscViewerASCIIPrintf(viewer, "up-smoother on level %D:\n", fas->level);CHKERRQ(ierr); 896 ierr = PetscViewerASCIIPushTab(viewer); 897 ierr = SNESView(fas->upsmooth, viewer);CHKERRQ(ierr); 898 ierr = PetscViewerASCIIPopTab(viewer); 899 } else { 900 ierr = PetscViewerASCIIPrintf(viewer, "no up-smoother on level %D\n", fas->level);CHKERRQ(ierr); 901 } 902 if (fas->downsmooth) { 903 ierr = PetscViewerASCIIPrintf(viewer, "down-smoother on level %D:\n", fas->level);CHKERRQ(ierr); 904 ierr = PetscViewerASCIIPushTab(viewer); 905 ierr = SNESView(fas->downsmooth, viewer);CHKERRQ(ierr); 906 ierr = PetscViewerASCIIPopTab(viewer); 907 } else { 908 ierr = PetscViewerASCIIPrintf(viewer, "no down-smoother on level %D\n", fas->level);CHKERRQ(ierr); 909 } 910 if (snes->usegs) { 911 ierr = PetscViewerASCIIPrintf(viewer, "Using user Gauss-Seidel on level %D -- smoothdown=%D, smoothup=%D\n", 912 fas->level, fas->max_down_it, fas->max_up_it);CHKERRQ(ierr); 913 } 914 ierr = PetscViewerASCIIPopTab(viewer); 915 } else { 916 SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for SNESFAS",((PetscObject)viewer)->type_name); 917 } 918 PetscFunctionReturn(0); 919 } 920 921 #undef __FUNCT__ 922 #define __FUNCT__ "FASDownSmooth" 923 /* 924 Defines the action of the downsmoother 925 */ 926 PetscErrorCode FASDownSmooth(SNES snes, Vec B, Vec X, Vec F){ 927 PetscErrorCode ierr = 0; 928 PetscReal fnorm; 929 SNESConvergedReason reason; 930 SNES_FAS *fas = (SNES_FAS *)snes->data; 931 PetscFunctionBegin; 932 if (fas->downsmooth) { 933 ierr = SNESSolve(fas->downsmooth, B, X);CHKERRQ(ierr); 934 /* check convergence reason for the smoother */ 935 ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr); 936 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 937 snes->reason = SNES_DIVERGED_INNER; 938 PetscFunctionReturn(0); 939 } 940 } else if (snes->usegs && snes->ops->computegs) { 941 if (fas->monitor) { 942 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 943 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 944 ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr); 945 ierr = PetscViewerASCIIPrintf(fas->monitor, "%d SNES GS Function norm %14.12e\n", 0, fnorm);CHKERRQ(ierr); 946 ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr); 947 } 948 ierr = SNESSetGSSweeps(snes, fas->max_down_it);CHKERRQ(ierr); 949 ierr = SNESComputeGS(snes, B, X);CHKERRQ(ierr); 950 if (fas->monitor) { 951 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 952 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 953 ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr); 954 ierr = PetscViewerASCIIPrintf(fas->monitor, "1 SNES GS Function norm %14.12e\n", fnorm);CHKERRQ(ierr); 955 ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr); 956 } 957 } else if (snes->pc) { 958 ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); 959 ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr); 960 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 961 snes->reason = SNES_DIVERGED_INNER; 962 PetscFunctionReturn(0); 963 } 964 } 965 PetscFunctionReturn(0); 966 } 967 968 969 #undef __FUNCT__ 970 #define __FUNCT__ "FASUpSmooth" 971 /* 972 Defines the action of the upsmoother 973 */ 974 PetscErrorCode FASUpSmooth (SNES snes, Vec B, Vec X, Vec F) { 975 PetscErrorCode ierr = 0; 976 PetscReal fnorm; 977 SNESConvergedReason reason; 978 SNES_FAS *fas = (SNES_FAS *)snes->data; 979 PetscFunctionBegin; 980 if (fas->upsmooth) { 981 ierr = SNESSolve(fas->downsmooth, B, X);CHKERRQ(ierr); 982 /* check convergence reason for the smoother */ 983 ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr); 984 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 985 snes->reason = SNES_DIVERGED_INNER; 986 PetscFunctionReturn(0); 987 } 988 } else if (snes->usegs && snes->ops->computegs) { 989 if (fas->monitor) { 990 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 991 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 992 ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr); 993 ierr = PetscViewerASCIIPrintf(fas->monitor, "%d SNES GS Function norm %14.12e\n", 0, fnorm);CHKERRQ(ierr); 994 ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr); 995 } 996 ierr = SNESSetGSSweeps(snes, fas->max_up_it);CHKERRQ(ierr); 997 ierr = SNESComputeGS(snes, B, X);CHKERRQ(ierr); 998 if (fas->monitor) { 999 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 1000 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 1001 ierr = PetscViewerASCIIAddTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr); 1002 ierr = PetscViewerASCIIPrintf(fas->monitor, "1 SNES GS Function norm %14.12e\n", fnorm);CHKERRQ(ierr); 1003 ierr = PetscViewerASCIISubtractTab(fas->monitor,((PetscObject)snes)->tablevel + 2);CHKERRQ(ierr); 1004 } 1005 } else if (snes->pc) { 1006 ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); 1007 ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr); 1008 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 1009 snes->reason = SNES_DIVERGED_INNER; 1010 PetscFunctionReturn(0); 1011 } 1012 } 1013 PetscFunctionReturn(0); 1014 } 1015 1016 #undef __FUNCT__ 1017 #define __FUNCT__ "FASCoarseCorrection" 1018 /* 1019 1020 Performs the FAS coarse correction as: 1021 1022 fine problem: F(x) = 0 1023 coarse problem: F^c(x) = b^c 1024 1025 b^c = F^c(I^c_fx^f - I^c_fF(x)) 1026 1027 with correction: 1028 1029 1030 1031 */ 1032 PetscErrorCode FASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new) { 1033 PetscErrorCode ierr; 1034 Vec X_c, Xo_c, F_c, B_c; 1035 SNES_FAS *fas = (SNES_FAS *)snes->data; 1036 SNESConvergedReason reason; 1037 PetscFunctionBegin; 1038 if (fas->next) { 1039 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 1040 1041 X_c = fas->next->vec_sol; 1042 Xo_c = fas->next->work[0]; 1043 F_c = fas->next->vec_func; 1044 B_c = fas->next->vec_rhs; 1045 1046 /* inject the solution */ 1047 if (fas->inject) { 1048 ierr = MatRestrict(fas->inject, X, Xo_c);CHKERRQ(ierr); 1049 } else { 1050 ierr = MatRestrict(fas->restrct, X, Xo_c);CHKERRQ(ierr); 1051 ierr = VecPointwiseMult(Xo_c, fas->rscale, Xo_c);CHKERRQ(ierr); 1052 } 1053 ierr = VecScale(F, -1.0);CHKERRQ(ierr); 1054 1055 /* restrict the defect */ 1056 ierr = MatRestrict(fas->restrct, F, B_c);CHKERRQ(ierr); 1057 1058 /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */ 1059 fas->next->vec_rhs = PETSC_NULL; /*unset the RHS to evaluate function instead of residual*/ 1060 ierr = SNESComputeFunction(fas->next, Xo_c, F_c);CHKERRQ(ierr); 1061 1062 ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr); /* add F_c(X) to the RHS */ 1063 1064 /* set initial guess of the coarse problem to the projected fine solution */ 1065 ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr); 1066 1067 /* recurse to the next level */ 1068 fas->next->vec_rhs = B_c; 1069 /* ierr = FASCycle_Private(fas->next, X_c);CHKERRQ(ierr); */ 1070 ierr = SNESSolve(fas->next, B_c, X_c);CHKERRQ(ierr); 1071 ierr = SNESGetConvergedReason(fas->next,&reason);CHKERRQ(ierr); 1072 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 1073 snes->reason = SNES_DIVERGED_INNER; 1074 PetscFunctionReturn(0); 1075 } 1076 /* fas->next->vec_rhs = PETSC_NULL; */ 1077 1078 /* correct as x <- x + I(x^c - Rx)*/ 1079 ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr); 1080 ierr = MatInterpolateAdd(fas->interpolate, X_c, X, X_new);CHKERRQ(ierr); 1081 } 1082 PetscFunctionReturn(0); 1083 } 1084 1085 #undef __FUNCT__ 1086 #define __FUNCT__ "FASCycle_Additive" 1087 /* 1088 1089 The additive cycle looks like: 1090 1091 xhat = x 1092 xhat = dS(x, b) 1093 x = coarsecorrection(xhat, b_d) 1094 x = x + nu*(xhat - x); 1095 (optional) x = uS(x, b) 1096 1097 With the coarse RHS (defect correction) as below. 1098 1099 */ 1100 PetscErrorCode FASCycle_Additive(SNES snes, Vec X) { 1101 Vec F, B, Xhat; 1102 Vec X_c, Xo_c, F_c, B_c, G, W; 1103 PetscErrorCode ierr; 1104 SNES_FAS * fas = (SNES_FAS *)snes->data; 1105 SNESConvergedReason reason; 1106 PetscReal xnorm = 0., fnorm = 0., gnorm = 0., ynorm = 0.; 1107 PetscBool lssucceed; 1108 PetscFunctionBegin; 1109 1110 F = snes->vec_func; 1111 B = snes->vec_rhs; 1112 Xhat = snes->work[1]; 1113 G = snes->work[2]; 1114 W = snes->work[3]; 1115 ierr = VecCopy(X, Xhat);CHKERRQ(ierr); 1116 /* recurse first */ 1117 if (fas->next) { 1118 ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr); 1119 1120 X_c = fas->next->vec_sol; 1121 Xo_c = fas->next->work[0]; 1122 F_c = fas->next->vec_func; 1123 B_c = fas->next->vec_rhs; 1124 1125 /* inject the solution */ 1126 if (fas->inject) { 1127 ierr = MatRestrict(fas->inject, Xhat, Xo_c);CHKERRQ(ierr); 1128 } else { 1129 ierr = MatRestrict(fas->restrct, Xhat, Xo_c);CHKERRQ(ierr); 1130 ierr = VecPointwiseMult(Xo_c, fas->rscale, Xo_c);CHKERRQ(ierr); 1131 } 1132 ierr = VecScale(F, -1.0);CHKERRQ(ierr); 1133 1134 /* restrict the defect */ 1135 ierr = MatRestrict(fas->restrct, F, B_c);CHKERRQ(ierr); 1136 1137 /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */ 1138 fas->next->vec_rhs = PETSC_NULL; /*unset the RHS to evaluate function instead of residual*/ 1139 ierr = SNESComputeFunction(fas->next, Xo_c, F_c);CHKERRQ(ierr); 1140 1141 ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr); /* add F_c(X) to the RHS */ 1142 1143 /* set initial guess of the coarse problem to the projected fine solution */ 1144 ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr); 1145 1146 /* recurse */ 1147 fas->next->vec_rhs = B_c; 1148 ierr = SNESSolve(fas->next, B_c, X_c);CHKERRQ(ierr); 1149 1150 /* smooth on this level */ 1151 ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr); 1152 1153 ierr = SNESGetConvergedReason(fas->next,&reason);CHKERRQ(ierr); 1154 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 1155 snes->reason = SNES_DIVERGED_INNER; 1156 PetscFunctionReturn(0); 1157 } 1158 1159 /* correct as x <- x + I(x^c - Rx)*/ 1160 ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr); 1161 ierr = MatInterpolate(fas->interpolate, X_c, Xhat);CHKERRQ(ierr); 1162 1163 /* additive correction of the coarse direction*/ 1164 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 1165 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 1166 ierr = VecScale(Xhat, -1.0);CHKERRQ(ierr); 1167 ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Xhat,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr); 1168 ierr = VecCopy(W, X);CHKERRQ(ierr); 1169 ierr = VecCopy(G, F);CHKERRQ(ierr); 1170 fnorm = gnorm; 1171 } else { 1172 ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr); 1173 } 1174 PetscFunctionReturn(0); 1175 } 1176 1177 #undef __FUNCT__ 1178 #define __FUNCT__ "FASCycle_Multiplicative" 1179 /* 1180 1181 Defines the FAS cycle as: 1182 1183 fine problem: F(x) = 0 1184 coarse problem: F^c(x) = b^c 1185 1186 b^c = F^c(I^c_fx^f - I^c_fF(x)) 1187 1188 correction: 1189 1190 x = x + I(x^c - Rx) 1191 1192 */ 1193 PetscErrorCode FASCycle_Multiplicative(SNES snes, Vec X) { 1194 1195 PetscErrorCode ierr; 1196 Vec F,B; 1197 SNES_FAS *fas = (SNES_FAS *)snes->data; 1198 1199 PetscFunctionBegin; 1200 F = snes->vec_func; 1201 B = snes->vec_rhs; 1202 /* pre-smooth -- just update using the pre-smoother */ 1203 ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr); 1204 1205 ierr = FASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr); 1206 1207 if (fas->level != 0) { 1208 ierr = FASUpSmooth(snes, B, X, F);CHKERRQ(ierr); 1209 } 1210 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 1211 1212 PetscFunctionReturn(0); 1213 } 1214 1215 #undef __FUNCT__ 1216 #define __FUNCT__ "SNESSolve_FAS" 1217 1218 PetscErrorCode SNESSolve_FAS(SNES snes) 1219 { 1220 PetscErrorCode ierr; 1221 PetscInt i, maxits; 1222 Vec X, F; 1223 PetscReal fnorm; 1224 SNES_FAS *fas = (SNES_FAS *)snes->data; 1225 PetscFunctionBegin; 1226 maxits = snes->max_its; /* maximum number of iterations */ 1227 snes->reason = SNES_CONVERGED_ITERATING; 1228 X = snes->vec_sol; 1229 F = snes->vec_func; 1230 1231 /*norm setup */ 1232 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1233 snes->iter = 0; 1234 snes->norm = 0.; 1235 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 1236 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 1237 if (snes->domainerror) { 1238 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 1239 PetscFunctionReturn(0); 1240 } 1241 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 1242 if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); 1243 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1244 snes->norm = fnorm; 1245 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 1246 SNESLogConvHistory(snes,fnorm,0); 1247 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 1248 1249 /* set parameter for default relative tolerance convergence test */ 1250 snes->ttol = fnorm*snes->rtol; 1251 /* test convergence */ 1252 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 1253 if (snes->reason) PetscFunctionReturn(0); 1254 for (i = 0; i < maxits; i++) { 1255 /* Call general purpose update function */ 1256 1257 if (snes->ops->update) { 1258 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 1259 } 1260 if (fas->fastype == SNES_FAS_MULTIPLICATIVE) { 1261 ierr = FASCycle_Multiplicative(snes, X);CHKERRQ(ierr); 1262 } else { 1263 ierr = FASCycle_Additive(snes, X);CHKERRQ(ierr); 1264 } 1265 1266 /* check for FAS cycle divergence */ 1267 if (snes->reason != SNES_CONVERGED_ITERATING) { 1268 PetscFunctionReturn(0); 1269 } 1270 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 1271 /* Monitor convergence */ 1272 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1273 snes->iter = i+1; 1274 snes->norm = fnorm; 1275 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 1276 SNESLogConvHistory(snes,snes->norm,0); 1277 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 1278 /* Test for convergence */ 1279 ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 1280 if (snes->reason) break; 1281 } 1282 if (i == maxits) { 1283 ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr); 1284 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 1285 } 1286 PetscFunctionReturn(0); 1287 } 1288