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 if (gsfunc) { 213 ierr = SNESSetGS(snes, gsfunc, ctx);CHKERRQ(ierr); 214 /* push the provided GS up the tree */ 215 if (fas->next) ierr = SNESFASSetGS(fas->next, gsfunc, ctx, use_gs);CHKERRQ(ierr); 216 } else if (snes->ops->computegs) { 217 /* assume that the user has set the GS solver at this level */ 218 if (fas->next) ierr = SNESFASSetGS(fas->next, PETSC_NULL, PETSC_NULL, use_gs);CHKERRQ(ierr); 219 } else if (use_gs) { 220 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "No user Gauss-Seidel function provided in SNESFASSetGS on level %d", fas->level); 221 } 222 PetscFunctionReturn(0); 223 } 224 225 #undef __FUNCT__ 226 #define __FUNCT__ "SNESFASSetGSOnLevel" 227 /*@C 228 SNESFASSetGSOnLevel - Sets the nonlinear smoother on a particular level. 229 230 Logically Collective on SNES 231 232 Input Parameters: 233 + snes - the multigrid context 234 . level - the level to set the nonlinear smoother on 235 . gsfunc - the nonlinear smoother function 236 . ctx - the user context for the nonlinear smoother 237 - use_gs - whether to use the nonlinear smoother or not 238 239 Level: advanced 240 241 .keywords: FAS, MG, set, cycles, Gauss-Seidel, multigrid 242 243 .seealso: SNESSetGS(), SNESFASSetGS() 244 @*/ 245 PetscErrorCode SNESFASSetGSOnLevel(SNES snes, PetscInt level, PetscErrorCode (*gsfunc)(SNES,Vec,Vec,void *), void * ctx, PetscBool use_gs) { 246 SNES_FAS *fas = (SNES_FAS *)snes->data; 247 PetscErrorCode ierr; 248 PetscInt top_level = fas->level,i; 249 SNES cur_snes = snes; 250 PetscFunctionBegin; 251 if (level > top_level) 252 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetCyclesOnLevel", level); 253 /* get to the correct level */ 254 for (i = fas->level; i > level; i--) { 255 fas = (SNES_FAS *)fas->next->data; 256 cur_snes = fas->next; 257 } 258 if (fas->level != level) 259 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetCyclesOnLevel"); 260 if (gsfunc) { 261 ierr = SNESSetGS(cur_snes, gsfunc, ctx);CHKERRQ(ierr); 262 } 263 PetscFunctionReturn(0); 264 } 265 266 #undef __FUNCT__ 267 #define __FUNCT__ "SNESFASGetSNES" 268 /*@ 269 SNESFASGetSNES - Gets the SNES corresponding to a particular 270 level of the FAS hierarchy. 271 272 Input Parameters: 273 + snes - the multigrid context 274 level - the level to get 275 - lsnes - whether to use the nonlinear smoother or not 276 277 Level: advanced 278 279 .keywords: FAS, MG, set, cycles, Gauss-Seidel, multigrid 280 281 .seealso: SNESFASSetLevels(), SNESFASGetLevels() 282 @*/ 283 PetscErrorCode SNESFASGetSNES(SNES snes, PetscInt level, SNES * lsnes) { 284 SNES_FAS * fas = (SNES_FAS *)snes->data; 285 PetscInt levels = fas->level; 286 PetscInt i; 287 PetscFunctionBegin; 288 *lsnes = snes; 289 if (fas->level < level) { 290 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "SNESFASGetSNES should only be called on a finer SNESFAS instance than the level."); 291 } 292 if (level > levels - 1) { 293 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Level %d doesn't exist in the SNESFAS."); 294 } 295 for (i = fas->level; i > level; i--) { 296 *lsnes = fas->next; 297 fas = (SNES_FAS *)(*lsnes)->data; 298 } 299 if (fas->level != level) SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "SNESFASGetSNES didn't return the right level!"); 300 PetscFunctionReturn(0); 301 } 302 303 #undef __FUNCT__ 304 #define __FUNCT__ "SNESFASSetType" 305 /*@ 306 SNESFASSetType - Sets the update and correction type used for FAS. 307 e 308 309 310 @*/ 311 PetscErrorCode SNESFASSetType(SNES snes,SNESFASType fastype) 312 { 313 SNES_FAS *fas = (SNES_FAS*)snes->data; 314 315 PetscFunctionBegin; 316 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 317 PetscValidLogicalCollectiveEnum(snes,fastype,2); 318 fas->fastype = fastype; 319 PetscFunctionReturn(0); 320 } 321 322 323 324 #undef __FUNCT__ 325 #define __FUNCT__ "SNESFASSetLevels" 326 /*@C 327 SNESFASSetLevels - Sets the number of levels to use with FAS. 328 Must be called before any other FAS routine. 329 330 Input Parameters: 331 + snes - the snes context 332 . levels - the number of levels 333 - comms - optional communicators for each level; this is to allow solving the coarser 334 problems on smaller sets of processors. Use PETSC_NULL_OBJECT for default in 335 Fortran. 336 337 Level: intermediate 338 339 Notes: 340 If the number of levels is one then the multigrid uses the -fas_levels prefix 341 for setting the level options rather than the -fas_coarse prefix. 342 343 .keywords: FAS, MG, set, levels, multigrid 344 345 .seealso: SNESFASGetLevels() 346 @*/ 347 PetscErrorCode SNESFASSetLevels(SNES snes, PetscInt levels, MPI_Comm * comms) { 348 PetscErrorCode ierr; 349 PetscInt i; 350 SNES_FAS * fas = (SNES_FAS *)snes->data; 351 SNES prevsnes; 352 MPI_Comm comm; 353 PetscFunctionBegin; 354 comm = ((PetscObject)snes)->comm; 355 if (levels == fas->levels) { 356 if (!comms) 357 PetscFunctionReturn(0); 358 } 359 /* user has changed the number of levels; reset */ 360 ierr = SNESReset(snes);CHKERRQ(ierr); 361 /* destroy any coarser levels if necessary */ 362 if (fas->next) SNESDestroy(&fas->next);CHKERRQ(ierr); 363 fas->next = PETSC_NULL; 364 fas->previous = PETSC_NULL; 365 prevsnes = snes; 366 /* setup the finest level */ 367 for (i = levels - 1; i >= 0; i--) { 368 if (comms) comm = comms[i]; 369 fas->level = i; 370 fas->levels = levels; 371 fas->next = PETSC_NULL; 372 if (i > 0) { 373 ierr = SNESCreate(comm, &fas->next);CHKERRQ(ierr); 374 ierr = SNESSetOptionsPrefix(fas->next,((PetscObject)snes)->prefix);CHKERRQ(ierr); 375 ierr = SNESSetType(fas->next, SNESFAS);CHKERRQ(ierr); 376 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->next, (PetscObject)snes, levels - i);CHKERRQ(ierr); 377 ((SNES_FAS *)fas->next->data)->previous = prevsnes; 378 prevsnes = fas->next; 379 fas = (SNES_FAS *)prevsnes->data; 380 } 381 } 382 PetscFunctionReturn(0); 383 } 384 385 #undef __FUNCT__ 386 #define __FUNCT__ "SNESFASSetNumberSmoothUp" 387 /*@ 388 SNESFASSetNumberSmoothUp - Sets the number of post-smoothing steps to 389 use on all levels. 390 391 Logically Collective on SNES 392 393 Input Parameters: 394 + snes - the multigrid context 395 - n - the number of smoothing steps 396 397 Options Database Key: 398 . -snes_fas_smoothup <n> - Sets number of pre-smoothing steps 399 400 Level: advanced 401 402 .keywords: FAS, MG, smooth, down, pre-smoothing, steps, multigrid 403 404 .seealso: SNESFASSetNumberSmoothDown() 405 @*/ 406 PetscErrorCode SNESFASSetNumberSmoothUp(SNES snes, PetscInt n) { 407 SNES_FAS * fas = (SNES_FAS *)snes->data; 408 PetscErrorCode ierr = 0; 409 PetscFunctionBegin; 410 fas->max_up_it = n; 411 if (fas->next) { 412 ierr = SNESFASSetNumberSmoothUp(fas->next, n);CHKERRQ(ierr); 413 } 414 PetscFunctionReturn(0); 415 } 416 417 #undef __FUNCT__ 418 #define __FUNCT__ "SNESFASSetNumberSmoothDown" 419 /*@ 420 SNESFASSetNumberSmoothDown - Sets the number of pre-smoothing steps to 421 use on all levels. 422 423 Logically Collective on SNES 424 425 Input Parameters: 426 + snes - the multigrid context 427 - n - the number of smoothing steps 428 429 Options Database Key: 430 . -snes_fas_smoothdown <n> - Sets number of pre-smoothing steps 431 432 Level: advanced 433 434 .keywords: FAS, MG, smooth, down, pre-smoothing, steps, multigrid 435 436 .seealso: SNESFASSetNumberSmoothUp() 437 @*/ 438 PetscErrorCode SNESFASSetNumberSmoothDown(SNES snes, PetscInt n) { 439 SNES_FAS * fas = (SNES_FAS *)snes->data; 440 PetscErrorCode ierr = 0; 441 PetscFunctionBegin; 442 fas->max_down_it = n; 443 if (fas->next) { 444 ierr = SNESFASSetNumberSmoothDown(fas->next, n);CHKERRQ(ierr); 445 } 446 PetscFunctionReturn(0); 447 } 448 449 #undef __FUNCT__ 450 #define __FUNCT__ "SNESFASSetInterpolation" 451 /*@ 452 SNESFASSetInterpolation - Sets the function to be used to calculate the 453 interpolation from l-1 to the lth level 454 455 Input Parameters: 456 + snes - the multigrid context 457 . mat - the interpolation operator 458 - level - the level (0 is coarsest) to supply [do not supply 0] 459 460 Level: advanced 461 462 Notes: 463 Usually this is the same matrix used also to set the restriction 464 for the same level. 465 466 One can pass in the interpolation matrix or its transpose; PETSc figures 467 out from the matrix size which one it is. 468 469 .keywords: FAS, multigrid, set, interpolate, level 470 471 .seealso: SNESFASSetInjection(), SNESFASSetRestriction(), SNESFASSetRScale() 472 @*/ 473 PetscErrorCode SNESFASSetInterpolation(SNES snes, PetscInt level, Mat mat) { 474 SNES_FAS * fas = (SNES_FAS *)snes->data; 475 PetscInt top_level = fas->level,i; 476 PetscErrorCode ierr; 477 478 PetscFunctionBegin; 479 if (level > top_level) 480 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetInterpolation", level); 481 /* get to the correct level */ 482 for (i = fas->level; i > level; i--) { 483 fas = (SNES_FAS *)fas->next->data; 484 } 485 if (fas->level != level) 486 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetInterpolation"); 487 ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr); 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 SNESFASSetInterpolation() 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 PetscErrorCode ierr; 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 ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr); 534 fas->restrct = mat; 535 PetscFunctionReturn(0); 536 } 537 538 539 #undef __FUNCT__ 540 #define __FUNCT__ "SNESFASSetRScale" 541 /*@ 542 SNESFASSetRScale - Sets the scaling factor of the restriction 543 operator from level l to l-1. 544 545 Input Parameters: 546 + snes - the multigrid context 547 . rscale - the restriction scaling 548 - level - the level (0 is coarsest) to supply [Do not supply 0] 549 550 Level: advanced 551 552 Notes: 553 This is only used in the case that the injection is not set. 554 555 .keywords: FAS, MG, set, multigrid, restriction, level 556 557 .seealso: SNESFASSetInjection(), SNESFASSetRestriction() 558 @*/ 559 PetscErrorCode SNESFASSetRScale(SNES snes, PetscInt level, Vec rscale) { 560 SNES_FAS * fas = (SNES_FAS *)snes->data; 561 PetscInt top_level = fas->level,i; 562 PetscErrorCode ierr; 563 564 PetscFunctionBegin; 565 if (level > top_level) 566 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetRestriction", level); 567 /* get to the correct level */ 568 for (i = fas->level; i > level; i--) { 569 fas = (SNES_FAS *)fas->next->data; 570 } 571 if (fas->level != level) 572 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetRestriction"); 573 ierr = PetscObjectReference((PetscObject)rscale);CHKERRQ(ierr); 574 fas->rscale = rscale; 575 PetscFunctionReturn(0); 576 } 577 578 579 #undef __FUNCT__ 580 #define __FUNCT__ "SNESFASSetInjection" 581 /*@ 582 SNESFASSetInjection - Sets the function to be used to inject the solution 583 from level l to l-1. 584 585 Input Parameters: 586 + snes - the multigrid context 587 . mat - the restriction matrix 588 - level - the level (0 is coarsest) to supply [Do not supply 0] 589 590 Level: advanced 591 592 Notes: 593 If you do not set this, the restriction and rscale is used to 594 project the solution instead. 595 596 .keywords: FAS, MG, set, multigrid, restriction, level 597 598 .seealso: SNESFASSetInterpolation(), SNESFASSetRestriction() 599 @*/ 600 PetscErrorCode SNESFASSetInjection(SNES snes, PetscInt level, Mat mat) { 601 SNES_FAS * fas = (SNES_FAS *)snes->data; 602 PetscInt top_level = fas->level,i; 603 PetscErrorCode ierr; 604 605 PetscFunctionBegin; 606 if (level > top_level) 607 SETERRQ1(((PetscObject)snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Bad level number %d in SNESFASSetInjection", level); 608 /* get to the correct level */ 609 for (i = fas->level; i > level; i--) { 610 fas = (SNES_FAS *)fas->next->data; 611 } 612 if (fas->level != level) 613 SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_ARG_WRONG, "Inconsistent level labelling in SNESFASSetInjection"); 614 ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr); 615 fas->inject = mat; 616 PetscFunctionReturn(0); 617 } 618 619 #undef __FUNCT__ 620 #define __FUNCT__ "SNESReset_FAS" 621 PetscErrorCode SNESReset_FAS(SNES snes) 622 { 623 PetscErrorCode ierr = 0; 624 SNES_FAS * fas = (SNES_FAS *)snes->data; 625 626 PetscFunctionBegin; 627 ierr = SNESDestroy(&fas->upsmooth);CHKERRQ(ierr); 628 ierr = SNESDestroy(&fas->downsmooth);CHKERRQ(ierr); 629 ierr = MatDestroy(&fas->inject);CHKERRQ(ierr); 630 ierr = MatDestroy(&fas->interpolate);CHKERRQ(ierr); 631 ierr = MatDestroy(&fas->restrct);CHKERRQ(ierr); 632 ierr = VecDestroy(&fas->rscale);CHKERRQ(ierr); 633 634 if (fas->upsmooth) ierr = SNESReset(fas->upsmooth);CHKERRQ(ierr); 635 if (fas->downsmooth) ierr = SNESReset(fas->downsmooth);CHKERRQ(ierr); 636 if (fas->next) ierr = SNESReset(fas->next);CHKERRQ(ierr); 637 PetscFunctionReturn(0); 638 } 639 640 #undef __FUNCT__ 641 #define __FUNCT__ "SNESDestroy_FAS" 642 PetscErrorCode SNESDestroy_FAS(SNES snes) 643 { 644 SNES_FAS * fas = (SNES_FAS *)snes->data; 645 PetscErrorCode ierr = 0; 646 647 PetscFunctionBegin; 648 /* recursively resets and then destroys */ 649 ierr = SNESReset(snes);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 Vec vec_sol, vec_func, vec_sol_update, vec_rhs; /* preserve these if they're set through the reset */ 665 666 PetscFunctionBegin; 667 668 if (fas->usedmfornumberoflevels && (fas->level == fas->levels - 1)) { 669 ierr = DMGetRefineLevel(snes->dm,&dm_levels);CHKERRQ(ierr); 670 dm_levels++; 671 if (dm_levels > fas->levels) { 672 673 /* we don't want the solution and func vectors to be destroyed in the SNESReset when it's called in SNESSetUp_FAS*/ 674 vec_sol = snes->vec_sol; 675 vec_func = snes->vec_func; 676 vec_sol_update = snes->vec_sol_update; 677 vec_rhs = snes->vec_rhs; 678 snes->vec_sol = PETSC_NULL; 679 snes->vec_func = PETSC_NULL; 680 snes->vec_sol_update = PETSC_NULL; 681 snes->vec_rhs = PETSC_NULL; 682 683 /* reset the number of levels */ 684 ierr = SNESFASSetLevels(snes,dm_levels,PETSC_NULL);CHKERRQ(ierr); 685 ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); 686 687 snes->vec_sol = vec_sol; 688 snes->vec_func = vec_func; 689 snes->vec_rhs = vec_rhs; 690 snes->vec_sol_update = vec_sol_update; 691 } 692 } 693 694 if (fas->level != fas->levels - 1) snes->gridsequence = 0; /* no grid sequencing inside the multigrid hierarchy! */ 695 696 if (fas->fastype == SNES_FAS_MULTIPLICATIVE) { 697 ierr = SNESDefaultGetWork(snes, 4);CHKERRQ(ierr); /* work vectors used for intergrid transfers */ 698 } else { 699 ierr = SNESDefaultGetWork(snes, 4);CHKERRQ(ierr); /* work vectors used for intergrid transfers */ 700 } 701 702 if (snes->dm) { 703 /* construct EVERYTHING from the DM -- including the progressive set of smoothers */ 704 if (fas->next) { 705 /* for now -- assume the DM and the evaluation functions have been set externally */ 706 if (!fas->next->dm) { 707 ierr = DMCoarsen(snes->dm, ((PetscObject)fas->next)->comm, &fas->next->dm);CHKERRQ(ierr); 708 ierr = SNESSetDM(fas->next, fas->next->dm);CHKERRQ(ierr); 709 } 710 /* set the interpolation and restriction from the DM */ 711 if (!fas->interpolate) { 712 ierr = DMCreateInterpolation(fas->next->dm, snes->dm, &fas->interpolate, &fas->rscale);CHKERRQ(ierr); 713 if (!fas->restrct) { 714 ierr = PetscObjectReference((PetscObject)fas->interpolate);CHKERRQ(ierr); 715 fas->restrct = fas->interpolate; 716 } 717 } 718 /* set the injection from the DM */ 719 if (!fas->inject) { 720 ierr = DMCreateInjection(fas->next->dm, snes->dm, &injscatter);CHKERRQ(ierr); 721 ierr = MatCreateScatter(((PetscObject)snes)->comm, injscatter, &fas->inject);CHKERRQ(ierr); 722 ierr = VecScatterDestroy(&injscatter);CHKERRQ(ierr); 723 } 724 } 725 /* set the DMs of the pre and post-smoothers here */ 726 if (fas->upsmooth) {ierr = SNESSetDM(fas->upsmooth, snes->dm);CHKERRQ(ierr);} 727 if (fas->downsmooth){ierr = SNESSetDM(fas->downsmooth, snes->dm);CHKERRQ(ierr);} 728 } 729 /*pass the smoother, function, and jacobian up to the next level if it's not user set already */ 730 731 if (fas->next) { 732 if (fas->galerkin) { 733 ierr = SNESSetFunction(fas->next, PETSC_NULL, SNESFASGalerkinDefaultFunction, fas->next);CHKERRQ(ierr); 734 } else { 735 if (snes->ops->computefunction && !fas->next->ops->computefunction) { 736 ierr = SNESSetFunction(fas->next, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr); 737 } 738 if (snes->ops->computejacobian && !fas->next->ops->computejacobian) { 739 ierr = SNESSetJacobian(fas->next, fas->next->jacobian, fas->next->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr); 740 } 741 if (snes->ops->computegs && !fas->next->ops->computegs) { 742 ierr = SNESSetGS(fas->next, snes->ops->computegs, snes->gsP);CHKERRQ(ierr); 743 } 744 } 745 } 746 747 if (fas->next) { 748 /* gotta set up the solution vector for this to work */ 749 if (!fas->next->vec_sol) {ierr = VecDuplicate(fas->rscale, &fas->next->vec_sol);CHKERRQ(ierr);} 750 if (!fas->next->vec_rhs) {ierr = VecDuplicate(fas->rscale, &fas->next->vec_rhs);CHKERRQ(ierr);} 751 ierr = SNESSetUp(fas->next);CHKERRQ(ierr); 752 } 753 754 /* setup the pre and post smoothers and set their function, jacobian, and gs evaluation routines if the user has neglected this */ 755 if (fas->upsmooth) { 756 if (snes->ops->computefunction && !fas->upsmooth->ops->computefunction) { 757 ierr = SNESSetFunction(fas->upsmooth, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr); 758 } 759 if (snes->ops->computejacobian && !fas->upsmooth->ops->computejacobian) { 760 ierr = SNESSetJacobian(fas->upsmooth, fas->upsmooth->jacobian, fas->upsmooth->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr); 761 } 762 if (snes->ops->computegs && !fas->upsmooth->ops->computegs) { 763 ierr = SNESSetGS(fas->upsmooth, snes->ops->computegs, snes->gsP);CHKERRQ(ierr); 764 } 765 ierr = SNESSetFromOptions(fas->upsmooth);CHKERRQ(ierr); 766 } 767 if (fas->downsmooth) { 768 if (snes->ops->computefunction && !fas->downsmooth->ops->computefunction) { 769 ierr = SNESSetFunction(fas->downsmooth, PETSC_NULL, snes->ops->computefunction, snes->funP);CHKERRQ(ierr); 770 } 771 if (snes->ops->computejacobian && !fas->downsmooth->ops->computejacobian) { 772 ierr = SNESSetJacobian(fas->downsmooth, fas->downsmooth->jacobian, fas->downsmooth->jacobian_pre, snes->ops->computejacobian, snes->jacP);CHKERRQ(ierr); 773 } 774 if (snes->ops->computegs && !fas->downsmooth->ops->computegs) { 775 ierr = SNESSetGS(fas->downsmooth, snes->ops->computegs, snes->gsP);CHKERRQ(ierr); 776 } 777 ierr = SNESSetFromOptions(fas->downsmooth);CHKERRQ(ierr); 778 } 779 780 /* setup FAS work vectors */ 781 if (fas->galerkin) { 782 ierr = VecDuplicate(snes->vec_sol, &fas->Xg);CHKERRQ(ierr); 783 ierr = VecDuplicate(snes->vec_sol, &fas->Fg);CHKERRQ(ierr); 784 } 785 786 787 /* got to set them all up at once */ 788 PetscFunctionReturn(0); 789 } 790 791 #undef __FUNCT__ 792 #define __FUNCT__ "SNESSetFromOptions_FAS" 793 PetscErrorCode SNESSetFromOptions_FAS(SNES snes) 794 { 795 SNES_FAS *fas = (SNES_FAS *) snes->data; 796 PetscInt levels = 1; 797 PetscBool flg, smoothflg, smoothupflg, smoothdownflg, smoothcoarseflg = PETSC_FALSE, monflg; 798 PetscErrorCode ierr; 799 char monfilename[PETSC_MAX_PATH_LEN]; 800 SNESFASType fastype; 801 const char *optionsprefix; 802 const char *prefix; 803 804 PetscFunctionBegin; 805 ierr = PetscOptionsHead("SNESFAS Options-----------------------------------");CHKERRQ(ierr); 806 807 /* number of levels -- only process on the finest level */ 808 if (fas->levels - 1 == fas->level) { 809 ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr); 810 if (!flg && snes->dm) { 811 ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr); 812 levels++; 813 fas->usedmfornumberoflevels = PETSC_TRUE; 814 } 815 ierr = SNESFASSetLevels(snes, levels, PETSC_NULL);CHKERRQ(ierr); 816 } 817 fastype = fas->fastype; 818 ierr = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr); 819 if (flg) { 820 ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr); 821 } 822 823 ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr); 824 825 /* smoother setup options */ 826 ierr = PetscOptionsHasName(optionsprefix, "-fas_snes_type", &smoothflg);CHKERRQ(ierr); 827 ierr = PetscOptionsHasName(optionsprefix, "-fas_up_snes_type", &smoothupflg);CHKERRQ(ierr); 828 ierr = PetscOptionsHasName(optionsprefix, "-fas_down_snes_type", &smoothdownflg);CHKERRQ(ierr); 829 if (fas->level == 0) { 830 ierr = PetscOptionsHasName(optionsprefix, "-fas_coarse_snes_type", &smoothcoarseflg);CHKERRQ(ierr); 831 } 832 /* options for the number of preconditioning cycles and cycle type */ 833 834 ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&fas->n_cycles,&flg);CHKERRQ(ierr); 835 836 ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFAS",fas->galerkin,&fas->galerkin,&flg);CHKERRQ(ierr); 837 838 ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESMonitorSet","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr); 839 840 841 ierr = PetscOptionsTail();CHKERRQ(ierr); 842 /* setup from the determined types if there is no pointwise procedure or smoother defined */ 843 844 if ((!fas->downsmooth) && smoothcoarseflg) { 845 ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr); 846 ierr = SNESCreate(((PetscObject)snes)->comm, &fas->downsmooth);CHKERRQ(ierr); 847 ierr = SNESSetOptionsPrefix(fas->downsmooth,prefix);CHKERRQ(ierr); 848 ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_coarse_");CHKERRQ(ierr); 849 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->downsmooth, (PetscObject)snes, 1);CHKERRQ(ierr); 850 } 851 852 if ((!fas->downsmooth) && smoothdownflg) { 853 ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr); 854 ierr = SNESCreate(((PetscObject)snes)->comm, &fas->downsmooth);CHKERRQ(ierr); 855 ierr = SNESSetOptionsPrefix(fas->downsmooth,prefix);CHKERRQ(ierr); 856 ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_down_");CHKERRQ(ierr); 857 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->downsmooth, (PetscObject)snes, 1);CHKERRQ(ierr); 858 } 859 860 if ((!fas->upsmooth) && (fas->level != 0) && smoothupflg) { 861 ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr); 862 ierr = SNESCreate(((PetscObject)snes)->comm, &fas->upsmooth);CHKERRQ(ierr); 863 ierr = SNESSetOptionsPrefix(fas->upsmooth,prefix);CHKERRQ(ierr); 864 ierr = SNESAppendOptionsPrefix(fas->upsmooth,"fas_up_");CHKERRQ(ierr); 865 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->upsmooth, (PetscObject)snes, 1);CHKERRQ(ierr); 866 } 867 868 if ((!fas->downsmooth) && smoothflg) { 869 ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr); 870 ierr = SNESCreate(((PetscObject)snes)->comm, &fas->downsmooth);CHKERRQ(ierr); 871 ierr = SNESSetOptionsPrefix(fas->downsmooth,prefix);CHKERRQ(ierr); 872 ierr = SNESAppendOptionsPrefix(fas->downsmooth,"fas_");CHKERRQ(ierr); 873 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->downsmooth, (PetscObject)snes, 1);CHKERRQ(ierr); 874 } 875 876 if ((!fas->upsmooth) && (fas->level != 0) && smoothflg) { 877 ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr); 878 ierr = SNESCreate(((PetscObject)snes)->comm, &fas->upsmooth);CHKERRQ(ierr); 879 ierr = SNESSetOptionsPrefix(fas->upsmooth,prefix);CHKERRQ(ierr); 880 ierr = SNESAppendOptionsPrefix(fas->upsmooth,"fas_");CHKERRQ(ierr); 881 ierr = PetscObjectIncrementTabLevel((PetscObject)fas->upsmooth, (PetscObject)snes, 1);CHKERRQ(ierr); 882 } 883 884 if (fas->upsmooth) { 885 ierr = SNESSetTolerances(fas->upsmooth, fas->upsmooth->abstol, fas->upsmooth->rtol, fas->upsmooth->xtol, 1, 1000);CHKERRQ(ierr); 886 } 887 888 if (fas->downsmooth) { 889 ierr = SNESSetTolerances(fas->downsmooth, fas->downsmooth->abstol, fas->downsmooth->rtol, fas->downsmooth->xtol, 1, 1000);CHKERRQ(ierr); 890 } 891 892 if (fas->level != fas->levels - 1) { 893 ierr = SNESSetTolerances(snes, snes->abstol, snes->rtol, snes->xtol, fas->n_cycles, 1000);CHKERRQ(ierr); 894 } 895 896 /* control the simple Richardson smoother that is default if there's no upsmooth or downsmooth */ 897 if (!fas->downsmooth) { 898 ierr = PetscOptionsInt("-fas_down_snes_max_it","Down smooth iterations","SNESFASSetCycles",fas->max_down_it,&fas->max_down_it,&flg);CHKERRQ(ierr); 899 ierr = PetscOptionsInt("-fas_snes_max_it","Down smooth iterations","SNESFASSetCycles",fas->max_down_it,&fas->max_down_it,&flg);CHKERRQ(ierr); 900 if (fas->level == 0) { 901 ierr = PetscOptionsInt("-fas_coarse_snes_max_it","Coarse smooth iterations","SNESFASSetCycles",fas->max_down_it,&fas->max_down_it,&flg);CHKERRQ(ierr); 902 } 903 } 904 905 if (!fas->upsmooth) { 906 ierr = PetscOptionsInt("-fas_up_snes_max_it","Upsmooth iterations","SNESFASSetCycles",fas->max_up_it,&fas->max_up_it,&flg);CHKERRQ(ierr); 907 ierr = PetscOptionsInt("-fas_snes_max_it","Upsmooth iterations","SNESFASSetCycles",fas->max_up_it,&fas->max_up_it,&flg);CHKERRQ(ierr); 908 } 909 910 if (monflg) { 911 fas->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr); 912 /* set the monitors for the upsmoother and downsmoother */ 913 ierr = SNESMonitorCancel(snes);CHKERRQ(ierr); 914 ierr = SNESMonitorSet(snes,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); 915 if (fas->upsmooth) ierr = SNESMonitorSet(fas->upsmooth,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); 916 if (fas->downsmooth) ierr = SNESMonitorSet(fas->downsmooth,SNESMonitorDefault,PETSC_NULL,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); 917 } else { 918 /* unset the monitors on the coarse levels */ 919 if (fas->level != fas->levels - 1) { 920 ierr = SNESMonitorCancel(snes);CHKERRQ(ierr); 921 } 922 } 923 924 /* recursive option setting for the smoothers */ 925 if (fas->next) {ierr = SNESSetFromOptions(fas->next);CHKERRQ(ierr);} 926 PetscFunctionReturn(0); 927 } 928 929 #undef __FUNCT__ 930 #define __FUNCT__ "SNESView_FAS" 931 PetscErrorCode SNESView_FAS(SNES snes, PetscViewer viewer) 932 { 933 SNES_FAS *fas = (SNES_FAS *) snes->data; 934 PetscBool iascii; 935 PetscErrorCode ierr; 936 937 PetscFunctionBegin; 938 ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 939 if (iascii) { 940 ierr = PetscViewerASCIIPrintf(viewer, "FAS, levels = %d\n", fas->levels);CHKERRQ(ierr); 941 ierr = PetscViewerASCIIPushTab(viewer); 942 ierr = PetscViewerASCIIPrintf(viewer, "level: %d\n", fas->level);CHKERRQ(ierr); 943 if (fas->upsmooth) { 944 ierr = PetscViewerASCIIPrintf(viewer, "up-smoother on level %D:\n", fas->level);CHKERRQ(ierr); 945 ierr = PetscViewerASCIIPushTab(viewer); 946 ierr = SNESView(fas->upsmooth, viewer);CHKERRQ(ierr); 947 ierr = PetscViewerASCIIPopTab(viewer); 948 } else { 949 ierr = PetscViewerASCIIPrintf(viewer, "no up-smoother on level %D\n", fas->level);CHKERRQ(ierr); 950 } 951 if (fas->downsmooth) { 952 ierr = PetscViewerASCIIPrintf(viewer, "down-smoother on level %D:\n", fas->level);CHKERRQ(ierr); 953 ierr = PetscViewerASCIIPushTab(viewer); 954 ierr = SNESView(fas->downsmooth, viewer);CHKERRQ(ierr); 955 ierr = PetscViewerASCIIPopTab(viewer); 956 } else { 957 ierr = PetscViewerASCIIPrintf(viewer, "no down-smoother on level %D\n", fas->level);CHKERRQ(ierr); 958 } 959 ierr = PetscViewerASCIIPopTab(viewer); 960 } else { 961 SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for SNESFAS",((PetscObject)viewer)->type_name); 962 } 963 PetscFunctionReturn(0); 964 } 965 966 #undef __FUNCT__ 967 #define __FUNCT__ "FASDownSmooth" 968 /* 969 Defines the action of the downsmoother 970 */ 971 PetscErrorCode FASDownSmooth(SNES snes, Vec B, Vec X, Vec F){ 972 PetscErrorCode ierr = 0; 973 PetscReal fnorm, gnorm, ynorm, xnorm = 0.0; 974 SNESConvergedReason reason; 975 SNES_FAS *fas = (SNES_FAS *)snes->data; 976 Vec G, W, Y, FPC; 977 PetscBool lssuccess; 978 PetscInt k; 979 PetscFunctionBegin; 980 G = snes->work[1]; 981 W = snes->work[2]; 982 Y = snes->work[3]; 983 if (fas->downsmooth) { 984 ierr = SNESSolve(fas->downsmooth, B, X);CHKERRQ(ierr); 985 /* check convergence reason for the smoother */ 986 ierr = SNESGetConvergedReason(fas->downsmooth,&reason);CHKERRQ(ierr); 987 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 988 snes->reason = SNES_DIVERGED_INNER; 989 PetscFunctionReturn(0); 990 } 991 ierr = SNESGetFunction(fas->downsmooth, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 992 ierr = VecCopy(FPC, F);CHKERRQ(ierr); 993 } else { 994 /* basic richardson smoother */ 995 for (k = 0; k < fas->max_up_it; k++) { 996 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 997 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 998 ierr = VecCopy(F, Y);CHKERRQ(ierr); 999 ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Y,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssuccess);CHKERRQ(ierr); 1000 if (!lssuccess) { 1001 if (++snes->numFailures >= snes->maxFailures) { 1002 snes->reason = SNES_DIVERGED_LINE_SEARCH; 1003 PetscFunctionReturn(0); 1004 } 1005 } 1006 ierr = VecCopy(W, X);CHKERRQ(ierr); 1007 ierr = VecCopy(G, F);CHKERRQ(ierr); 1008 fnorm = gnorm; 1009 } 1010 } 1011 PetscFunctionReturn(0); 1012 } 1013 1014 1015 #undef __FUNCT__ 1016 #define __FUNCT__ "FASUpSmooth" 1017 /* 1018 Defines the action of the upsmoother 1019 */ 1020 PetscErrorCode FASUpSmooth (SNES snes, Vec B, Vec X, Vec F) { 1021 PetscErrorCode ierr = 0; 1022 PetscReal fnorm, gnorm, ynorm, xnorm = 0.0; 1023 SNESConvergedReason reason; 1024 SNES_FAS *fas = (SNES_FAS *)snes->data; 1025 Vec G, W, Y, FPC; 1026 PetscBool lssuccess; 1027 PetscInt k; 1028 PetscFunctionBegin; 1029 G = snes->work[1]; 1030 W = snes->work[2]; 1031 Y = snes->work[3]; 1032 if (fas->upsmooth) { 1033 ierr = SNESSolve(fas->upsmooth, B, X);CHKERRQ(ierr); 1034 /* check convergence reason for the smoother */ 1035 ierr = SNESGetConvergedReason(fas->upsmooth,&reason);CHKERRQ(ierr); 1036 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 1037 snes->reason = SNES_DIVERGED_INNER; 1038 PetscFunctionReturn(0); 1039 } 1040 ierr = SNESGetFunction(fas->upsmooth, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 1041 ierr = VecCopy(FPC, F);CHKERRQ(ierr); 1042 } else { 1043 /* basic richardson smoother */ 1044 for (k = 0; k < fas->max_up_it; k++) { 1045 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 1046 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 1047 ierr = VecCopy(F, Y);CHKERRQ(ierr); 1048 ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Y,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssuccess);CHKERRQ(ierr); 1049 if (!lssuccess) { 1050 if (++snes->numFailures >= snes->maxFailures) { 1051 snes->reason = SNES_DIVERGED_LINE_SEARCH; 1052 PetscFunctionReturn(0); 1053 } 1054 } 1055 ierr = VecCopy(W, X);CHKERRQ(ierr); 1056 ierr = VecCopy(G, F);CHKERRQ(ierr); 1057 fnorm = gnorm; 1058 } 1059 } 1060 PetscFunctionReturn(0); 1061 } 1062 1063 #undef __FUNCT__ 1064 #define __FUNCT__ "FASCoarseCorrection" 1065 /* 1066 1067 Performs the FAS coarse correction as: 1068 1069 fine problem: F(x) = 0 1070 coarse problem: F^c(x) = b^c 1071 1072 b^c = F^c(I^c_fx^f - I^c_fF(x)) 1073 1074 with correction: 1075 1076 1077 1078 */ 1079 PetscErrorCode FASCoarseCorrection(SNES snes, Vec X, Vec F, Vec X_new) { 1080 PetscErrorCode ierr; 1081 Vec X_c, Xo_c, F_c, B_c; 1082 SNES_FAS *fas = (SNES_FAS *)snes->data; 1083 SNESConvergedReason reason; 1084 PetscFunctionBegin; 1085 if (fas->next) { 1086 X_c = fas->next->vec_sol; 1087 Xo_c = fas->next->work[0]; 1088 F_c = fas->next->vec_func; 1089 B_c = fas->next->vec_rhs; 1090 1091 /* inject the solution */ 1092 if (fas->inject) { 1093 ierr = MatRestrict(fas->inject, X, Xo_c);CHKERRQ(ierr); 1094 } else { 1095 ierr = MatRestrict(fas->restrct, X, Xo_c);CHKERRQ(ierr); 1096 ierr = VecPointwiseMult(Xo_c, fas->rscale, Xo_c);CHKERRQ(ierr); 1097 } 1098 ierr = VecScale(F, -1.0);CHKERRQ(ierr); 1099 1100 /* restrict the defect */ 1101 ierr = MatRestrict(fas->restrct, F, B_c);CHKERRQ(ierr); 1102 1103 /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */ 1104 fas->next->vec_rhs = PETSC_NULL; /*unset the RHS to evaluate function instead of residual*/ 1105 ierr = SNESComputeFunction(fas->next, Xo_c, F_c);CHKERRQ(ierr); 1106 1107 ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr); /* add F_c(X) to the RHS */ 1108 1109 /* set initial guess of the coarse problem to the projected fine solution */ 1110 ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr); 1111 1112 /* recurse to the next level */ 1113 fas->next->vec_rhs = B_c; 1114 /* ierr = FASCycle_Private(fas->next, X_c);CHKERRQ(ierr); */ 1115 ierr = SNESSolve(fas->next, B_c, X_c);CHKERRQ(ierr); 1116 ierr = SNESGetConvergedReason(fas->next,&reason);CHKERRQ(ierr); 1117 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 1118 snes->reason = SNES_DIVERGED_INNER; 1119 PetscFunctionReturn(0); 1120 } 1121 /* fas->next->vec_rhs = PETSC_NULL; */ 1122 1123 /* correct as x <- x + I(x^c - Rx)*/ 1124 ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr); 1125 ierr = MatInterpolateAdd(fas->interpolate, X_c, X, X_new);CHKERRQ(ierr); 1126 } 1127 PetscFunctionReturn(0); 1128 } 1129 1130 #undef __FUNCT__ 1131 #define __FUNCT__ "FASCycle_Additive" 1132 /* 1133 1134 The additive cycle looks like: 1135 1136 xhat = x 1137 xhat = dS(x, b) 1138 x = coarsecorrection(xhat, b_d) 1139 x = x + nu*(xhat - x); 1140 (optional) x = uS(x, b) 1141 1142 With the coarse RHS (defect correction) as below. 1143 1144 */ 1145 PetscErrorCode FASCycle_Additive(SNES snes, Vec X) { 1146 Vec F, B, Xhat; 1147 Vec X_c, Xo_c, F_c, B_c, G, W; 1148 PetscErrorCode ierr; 1149 SNES_FAS * fas = (SNES_FAS *)snes->data; 1150 SNESConvergedReason reason; 1151 PetscReal xnorm = 0., fnorm = 0., gnorm = 0., ynorm = 0.; 1152 PetscBool lssucceed; 1153 PetscFunctionBegin; 1154 1155 F = snes->vec_func; 1156 B = snes->vec_rhs; 1157 Xhat = snes->work[3]; 1158 G = snes->work[1]; 1159 W = snes->work[2]; 1160 ierr = VecCopy(X, Xhat);CHKERRQ(ierr); 1161 /* recurse first */ 1162 if (fas->next) { 1163 ierr = SNESComputeFunction(snes, Xhat, F);CHKERRQ(ierr); 1164 1165 X_c = fas->next->vec_sol; 1166 Xo_c = fas->next->work[0]; 1167 F_c = fas->next->vec_func; 1168 B_c = fas->next->vec_rhs; 1169 1170 /* inject the solution */ 1171 if (fas->inject) { 1172 ierr = MatRestrict(fas->inject, Xhat, Xo_c);CHKERRQ(ierr); 1173 } else { 1174 ierr = MatRestrict(fas->restrct, Xhat, Xo_c);CHKERRQ(ierr); 1175 ierr = VecPointwiseMult(Xo_c, fas->rscale, Xo_c);CHKERRQ(ierr); 1176 } 1177 ierr = VecScale(F, -1.0);CHKERRQ(ierr); 1178 1179 /* restrict the defect */ 1180 ierr = MatRestrict(fas->restrct, F, B_c);CHKERRQ(ierr); 1181 1182 /* solve the coarse problem corresponding to F^c(x^c) = b^c = Rb + F^c(Rx) - RF(x) */ 1183 fas->next->vec_rhs = PETSC_NULL; /*unset the RHS to evaluate function instead of residual*/ 1184 ierr = SNESComputeFunction(fas->next, Xo_c, F_c);CHKERRQ(ierr); 1185 1186 ierr = VecAXPY(B_c, 1.0, F_c);CHKERRQ(ierr); /* add F_c(X) to the RHS */ 1187 1188 /* set initial guess of the coarse problem to the projected fine solution */ 1189 ierr = VecCopy(Xo_c, X_c);CHKERRQ(ierr); 1190 1191 /* recurse */ 1192 fas->next->vec_rhs = B_c; 1193 ierr = SNESSolve(fas->next, B_c, X_c);CHKERRQ(ierr); 1194 1195 /* smooth on this level */ 1196 ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr); 1197 1198 ierr = SNESGetConvergedReason(fas->next,&reason);CHKERRQ(ierr); 1199 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 1200 snes->reason = SNES_DIVERGED_INNER; 1201 PetscFunctionReturn(0); 1202 } 1203 1204 /* correct as x <- x + I(x^c - Rx)*/ 1205 ierr = VecAXPY(X_c, -1.0, Xo_c);CHKERRQ(ierr); 1206 ierr = MatInterpolate(fas->interpolate, X_c, Xhat);CHKERRQ(ierr); 1207 1208 /* additive correction of the coarse direction*/ 1209 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 1210 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 1211 ierr = VecScale(Xhat, -1.0);CHKERRQ(ierr); 1212 ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Xhat,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr); 1213 ierr = VecCopy(W, X);CHKERRQ(ierr); 1214 ierr = VecCopy(G, F);CHKERRQ(ierr); 1215 fnorm = gnorm; 1216 } else { 1217 ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr); 1218 } 1219 PetscFunctionReturn(0); 1220 } 1221 1222 #undef __FUNCT__ 1223 #define __FUNCT__ "FASCycle_Multiplicative" 1224 /* 1225 1226 Defines the FAS cycle as: 1227 1228 fine problem: F(x) = 0 1229 coarse problem: F^c(x) = b^c 1230 1231 b^c = F^c(I^c_fx^f - I^c_fF(x)) 1232 1233 correction: 1234 1235 x = x + I(x^c - Rx) 1236 1237 */ 1238 PetscErrorCode FASCycle_Multiplicative(SNES snes, Vec X) { 1239 1240 PetscErrorCode ierr; 1241 Vec F,B; 1242 SNES_FAS *fas = (SNES_FAS *)snes->data; 1243 1244 PetscFunctionBegin; 1245 F = snes->vec_func; 1246 B = snes->vec_rhs; 1247 /* pre-smooth -- just update using the pre-smoother */ 1248 ierr = FASDownSmooth(snes, B, X, F);CHKERRQ(ierr); 1249 1250 ierr = FASCoarseCorrection(snes, X, F, X);CHKERRQ(ierr); 1251 1252 if (fas->level != 0) { 1253 ierr = FASUpSmooth(snes, B, X, F);CHKERRQ(ierr); 1254 } 1255 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 1256 1257 PetscFunctionReturn(0); 1258 } 1259 1260 #undef __FUNCT__ 1261 #define __FUNCT__ "SNESSolve_FAS" 1262 1263 PetscErrorCode SNESSolve_FAS(SNES snes) 1264 { 1265 PetscErrorCode ierr; 1266 PetscInt i, maxits; 1267 Vec X, F; 1268 PetscReal fnorm; 1269 SNES_FAS *fas = (SNES_FAS *)snes->data; 1270 PetscFunctionBegin; 1271 maxits = snes->max_its; /* maximum number of iterations */ 1272 snes->reason = SNES_CONVERGED_ITERATING; 1273 X = snes->vec_sol; 1274 F = snes->vec_func; 1275 1276 /*norm setup */ 1277 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1278 snes->iter = 0; 1279 snes->norm = 0.; 1280 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 1281 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 1282 if (snes->domainerror) { 1283 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 1284 PetscFunctionReturn(0); 1285 } 1286 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 1287 if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); 1288 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1289 snes->norm = fnorm; 1290 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 1291 SNESLogConvHistory(snes,fnorm,0); 1292 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 1293 1294 /* set parameter for default relative tolerance convergence test */ 1295 snes->ttol = fnorm*snes->rtol; 1296 /* test convergence */ 1297 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 1298 if (snes->reason) PetscFunctionReturn(0); 1299 for (i = 0; i < maxits; i++) { 1300 /* Call general purpose update function */ 1301 1302 if (snes->ops->update) { 1303 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 1304 } 1305 if (fas->fastype == SNES_FAS_MULTIPLICATIVE) { 1306 ierr = FASCycle_Multiplicative(snes, X);CHKERRQ(ierr); 1307 } else { 1308 ierr = FASCycle_Additive(snes, X);CHKERRQ(ierr); 1309 } 1310 1311 /* check for FAS cycle divergence */ 1312 if (snes->reason != SNES_CONVERGED_ITERATING) { 1313 PetscFunctionReturn(0); 1314 } 1315 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 1316 /* Monitor convergence */ 1317 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 1318 snes->iter = i+1; 1319 snes->norm = fnorm; 1320 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 1321 SNESLogConvHistory(snes,snes->norm,0); 1322 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 1323 /* Test for convergence */ 1324 ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 1325 if (snes->reason) break; 1326 } 1327 if (i == maxits) { 1328 ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr); 1329 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 1330 } 1331 PetscFunctionReturn(0); 1332 } 1333