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