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