1 2 #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/ 3 4 /*@C 5 PCMGResidualDefault - Default routine to calculate the residual. 6 7 Collective on mat 8 9 Input Parameters: 10 + mat - the matrix 11 . b - the right-hand-side 12 - x - the approximate solution 13 14 Output Parameter: 15 . r - location to store the residual 16 17 Level: developer 18 19 .seealso: `PCMG`, `PCMGSetResidual()`, `PCMGSetMatResidual()` 20 @*/ 21 PetscErrorCode PCMGResidualDefault(Mat mat, Vec b, Vec x, Vec r) 22 { 23 PetscFunctionBegin; 24 PetscCall(MatResidual(mat, b, x, r)); 25 PetscFunctionReturn(0); 26 } 27 28 /*@C 29 PCMGResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system 30 31 Collective on mat 32 33 Input Parameters: 34 + mat - the matrix 35 . b - the right-hand-side 36 - x - the approximate solution 37 38 Output Parameter: 39 . r - location to store the residual 40 41 Level: developer 42 43 .seealso: `PCMG`, `PCMGSetResidualTranspose()`, `PCMGMatResidualTransposeDefault()` 44 @*/ 45 PetscErrorCode PCMGResidualTransposeDefault(Mat mat, Vec b, Vec x, Vec r) 46 { 47 PetscFunctionBegin; 48 PetscCall(MatMultTranspose(mat, x, r)); 49 PetscCall(VecAYPX(r, -1.0, b)); 50 PetscFunctionReturn(0); 51 } 52 53 /*@C 54 PCMGMatResidualDefault - Default routine to calculate the residual. 55 56 Collective on mat 57 58 Input Parameters: 59 + mat - the matrix 60 . b - the right-hand-side 61 - x - the approximate solution 62 63 Output Parameter: 64 . r - location to store the residual 65 66 Level: developer 67 68 .seealso: `PCMG`, `PCMGSetMatResidual()`, `PCMGResidualDefault()` 69 @*/ 70 PetscErrorCode PCMGMatResidualDefault(Mat mat, Mat b, Mat x, Mat r) 71 { 72 PetscFunctionBegin; 73 PetscCall(MatMatMult(mat, x, MAT_REUSE_MATRIX, PETSC_DEFAULT, &r)); 74 PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN)); 75 PetscFunctionReturn(0); 76 } 77 78 /*@C 79 PCMGMatResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system 80 81 Collective on mat 82 83 Input Parameters: 84 + mat - the matrix 85 . b - the right-hand-side 86 - x - the approximate solution 87 88 Output Parameter: 89 . r - location to store the residual 90 91 Level: developer 92 93 .seealso: `PCMG`, `PCMGSetMatResidualTranspose()` 94 @*/ 95 PetscErrorCode PCMGMatResidualTransposeDefault(Mat mat, Mat b, Mat x, Mat r) 96 { 97 PetscFunctionBegin; 98 PetscCall(MatTransposeMatMult(mat, x, MAT_REUSE_MATRIX, PETSC_DEFAULT, &r)); 99 PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN)); 100 PetscFunctionReturn(0); 101 } 102 /*@ 103 PCMGGetCoarseSolve - Gets the solver context to be used on the coarse grid. 104 105 Not Collective 106 107 Input Parameter: 108 . pc - the multigrid context 109 110 Output Parameter: 111 . ksp - the coarse grid solver context 112 113 Level: advanced 114 115 .seealso: `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetSmoother()` 116 @*/ 117 PetscErrorCode PCMGGetCoarseSolve(PC pc, KSP *ksp) 118 { 119 PC_MG *mg = (PC_MG *)pc->data; 120 PC_MG_Levels **mglevels = mg->levels; 121 122 PetscFunctionBegin; 123 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 124 *ksp = mglevels[0]->smoothd; 125 PetscFunctionReturn(0); 126 } 127 128 /*@C 129 PCMGSetResidual - Sets the function to be used to calculate the residual on the lth level. 130 131 Logically Collective on pc 132 133 Input Parameters: 134 + pc - the multigrid context 135 . l - the level (0 is coarsest) to supply 136 . residual - function used to form residual, if none is provided the previously provide one is used, if no 137 previous one were provided then a default is used 138 - mat - matrix associated with residual 139 140 Level: advanced 141 142 .seealso: `PCMG`, `PCMGResidualDefault()` 143 @*/ 144 PetscErrorCode PCMGSetResidual(PC pc, PetscInt l, PetscErrorCode (*residual)(Mat, Vec, Vec, Vec), Mat mat) 145 { 146 PC_MG *mg = (PC_MG *)pc->data; 147 PC_MG_Levels **mglevels = mg->levels; 148 149 PetscFunctionBegin; 150 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 151 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 152 if (residual) mglevels[l]->residual = residual; 153 if (!mglevels[l]->residual) mglevels[l]->residual = PCMGResidualDefault; 154 mglevels[l]->matresidual = PCMGMatResidualDefault; 155 if (mat) PetscCall(PetscObjectReference((PetscObject)mat)); 156 PetscCall(MatDestroy(&mglevels[l]->A)); 157 mglevels[l]->A = mat; 158 PetscFunctionReturn(0); 159 } 160 161 /*@C 162 PCMGSetResidualTranspose - Sets the function to be used to calculate the residual of the transposed linear system 163 on the lth level. 164 165 Logically Collective on pc 166 167 Input Parameters: 168 + pc - the multigrid context 169 . l - the level (0 is coarsest) to supply 170 . residualt - function used to form transpose of residual, if none is provided the previously provide one is used, if no 171 previous one were provided then a default is used 172 - mat - matrix associated with residual 173 174 Level: advanced 175 176 .seealso: `PCMG`, `PCMGResidualTransposeDefault()` 177 @*/ 178 PetscErrorCode PCMGSetResidualTranspose(PC pc, PetscInt l, PetscErrorCode (*residualt)(Mat, Vec, Vec, Vec), Mat mat) 179 { 180 PC_MG *mg = (PC_MG *)pc->data; 181 PC_MG_Levels **mglevels = mg->levels; 182 183 PetscFunctionBegin; 184 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 185 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 186 if (residualt) mglevels[l]->residualtranspose = residualt; 187 if (!mglevels[l]->residualtranspose) mglevels[l]->residualtranspose = PCMGResidualTransposeDefault; 188 mglevels[l]->matresidualtranspose = PCMGMatResidualTransposeDefault; 189 if (mat) PetscCall(PetscObjectReference((PetscObject)mat)); 190 PetscCall(MatDestroy(&mglevels[l]->A)); 191 mglevels[l]->A = mat; 192 PetscFunctionReturn(0); 193 } 194 195 /*@ 196 PCMGSetInterpolation - Sets the function to be used to calculate the 197 interpolation from l-1 to the lth level 198 199 Logically Collective on pc 200 201 Input Parameters: 202 + pc - the multigrid context 203 . mat - the interpolation operator 204 - l - the level (0 is coarsest) to supply [do not supply 0] 205 206 Level: advanced 207 208 Notes: 209 Usually this is the same matrix used also to set the restriction 210 for the same level. 211 212 One can pass in the interpolation matrix or its transpose; PETSc figures 213 out from the matrix size which one it is. 214 215 .seealso: `PCMG`, `PCMGSetRestriction()` 216 @*/ 217 PetscErrorCode PCMGSetInterpolation(PC pc, PetscInt l, Mat mat) 218 { 219 PC_MG *mg = (PC_MG *)pc->data; 220 PC_MG_Levels **mglevels = mg->levels; 221 222 PetscFunctionBegin; 223 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 224 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 225 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set interpolation routine for coarsest level"); 226 PetscCall(PetscObjectReference((PetscObject)mat)); 227 PetscCall(MatDestroy(&mglevels[l]->interpolate)); 228 229 mglevels[l]->interpolate = mat; 230 PetscFunctionReturn(0); 231 } 232 233 /*@ 234 PCMGSetOperators - Sets operator and preconditioning matrix for lth level 235 236 Logically Collective on pc 237 238 Input Parameters: 239 + pc - the multigrid context 240 . Amat - the operator 241 . pmat - the preconditioning operator 242 - l - the level (0 is the coarsest) to supply 243 244 Level: advanced 245 246 .keywords: multigrid, set, interpolate, level 247 248 .seealso: `PCMG`, `PCMGSetGalerkin()`, `PCMGSetRestriction()`, `PCMGSetInterpolation()` 249 @*/ 250 PetscErrorCode PCMGSetOperators(PC pc, PetscInt l, Mat Amat, Mat Pmat) 251 { 252 PC_MG *mg = (PC_MG *)pc->data; 253 PC_MG_Levels **mglevels = mg->levels; 254 255 PetscFunctionBegin; 256 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 257 PetscValidHeaderSpecific(Amat, MAT_CLASSID, 3); 258 PetscValidHeaderSpecific(Pmat, MAT_CLASSID, 4); 259 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 260 PetscCall(KSPSetOperators(mglevels[l]->smoothd, Amat, Pmat)); 261 PetscFunctionReturn(0); 262 } 263 264 /*@ 265 PCMGGetInterpolation - Gets the function to be used to calculate the 266 interpolation from l-1 to the lth level 267 268 Logically Collective on pc 269 270 Input Parameters: 271 + pc - the multigrid context 272 - l - the level (0 is coarsest) to supply [Do not supply 0] 273 274 Output Parameter: 275 . mat - the interpolation matrix, can be NULL 276 277 Level: advanced 278 279 .seealso: `PCMG`, `PCMGGetRestriction()`, `PCMGSetInterpolation()`, `PCMGGetRScale()` 280 @*/ 281 PetscErrorCode PCMGGetInterpolation(PC pc, PetscInt l, Mat *mat) 282 { 283 PC_MG *mg = (PC_MG *)pc->data; 284 PC_MG_Levels **mglevels = mg->levels; 285 286 PetscFunctionBegin; 287 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 288 if (mat) PetscValidPointer(mat, 3); 289 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 290 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1); 291 if (!mglevels[l]->interpolate && mglevels[l]->restrct) PetscCall(PCMGSetInterpolation(pc, l, mglevels[l]->restrct)); 292 if (mat) *mat = mglevels[l]->interpolate; 293 PetscFunctionReturn(0); 294 } 295 296 /*@ 297 PCMGSetRestriction - Sets the function to be used to restrict dual vectors 298 from level l to l-1. 299 300 Logically Collective on pc 301 302 Input Parameters: 303 + pc - the multigrid context 304 . l - the level (0 is coarsest) to supply [Do not supply 0] 305 - mat - the restriction matrix 306 307 Level: advanced 308 309 Notes: 310 Usually this is the same matrix used also to set the interpolation 311 for the same level. 312 313 One can pass in the interpolation matrix or its transpose; PETSc figures 314 out from the matrix size which one it is. 315 316 If you do not set this, the transpose of the `Mat` set with `PCMGSetInterpolation()` 317 is used. 318 319 .seealso: `PCMG`, `PCMGSetInterpolation()` 320 @*/ 321 PetscErrorCode PCMGSetRestriction(PC pc, PetscInt l, Mat mat) 322 { 323 PC_MG *mg = (PC_MG *)pc->data; 324 PC_MG_Levels **mglevels = mg->levels; 325 326 PetscFunctionBegin; 327 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 328 PetscValidHeaderSpecific(mat, MAT_CLASSID, 3); 329 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 330 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level"); 331 PetscCall(PetscObjectReference((PetscObject)mat)); 332 PetscCall(MatDestroy(&mglevels[l]->restrct)); 333 334 mglevels[l]->restrct = mat; 335 PetscFunctionReturn(0); 336 } 337 338 /*@ 339 PCMGGetRestriction - Gets the function to be used to restrict dual vectors 340 from level l to l-1. 341 342 Logically Collective on pc 343 344 Input Parameters: 345 + pc - the multigrid context 346 - l - the level (0 is coarsest) to supply [Do not supply 0] 347 348 Output Parameter: 349 . mat - the restriction matrix 350 351 Level: advanced 352 353 .seealso: `PCMG`, `PCMGGetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGGetInjection()` 354 @*/ 355 PetscErrorCode PCMGGetRestriction(PC pc, PetscInt l, Mat *mat) 356 { 357 PC_MG *mg = (PC_MG *)pc->data; 358 PC_MG_Levels **mglevels = mg->levels; 359 360 PetscFunctionBegin; 361 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 362 if (mat) PetscValidPointer(mat, 3); 363 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 364 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1); 365 if (!mglevels[l]->restrct && mglevels[l]->interpolate) PetscCall(PCMGSetRestriction(pc, l, mglevels[l]->interpolate)); 366 if (mat) *mat = mglevels[l]->restrct; 367 PetscFunctionReturn(0); 368 } 369 370 /*@ 371 PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1. 372 373 Logically Collective on pc 374 375 Input Parameters: 376 + pc - the multigrid context 377 - l - the level (0 is coarsest) to supply [Do not supply 0] 378 . rscale - the scaling 379 380 Level: advanced 381 382 Note: 383 When evaluating a function on a coarse level one does not want to do F(R * x) one does F(rscale * R * x) where rscale is 1 over the row sums of R. 384 It is preferable to use `PCMGSetInjection()` to control moving primal vectors. 385 386 .seealso: `PCMG`, `PCMGSetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGSetInjection()` 387 @*/ 388 PetscErrorCode PCMGSetRScale(PC pc, PetscInt l, Vec rscale) 389 { 390 PC_MG *mg = (PC_MG *)pc->data; 391 PC_MG_Levels **mglevels = mg->levels; 392 393 PetscFunctionBegin; 394 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 395 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 396 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1); 397 PetscCall(PetscObjectReference((PetscObject)rscale)); 398 PetscCall(VecDestroy(&mglevels[l]->rscale)); 399 400 mglevels[l]->rscale = rscale; 401 PetscFunctionReturn(0); 402 } 403 404 /*@ 405 PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1. 406 407 Collective on pc 408 409 Input Parameters: 410 + pc - the multigrid context 411 . rscale - the scaling 412 - l - the level (0 is coarsest) to supply [Do not supply 0] 413 414 Level: advanced 415 416 Note: 417 When evaluating a function on a coarse level one does not want to do F(R * x) one does F(rscale * R * x) where rscale is 1 over the row sums of R. 418 It is preferable to use `PCMGGetInjection()` to control moving primal vectors. 419 420 .seealso: `PCMG`, `PCMGSetInterpolation()`, `PCMGGetRestriction()`, `PCMGGetInjection()` 421 @*/ 422 PetscErrorCode PCMGGetRScale(PC pc, PetscInt l, Vec *rscale) 423 { 424 PC_MG *mg = (PC_MG *)pc->data; 425 PC_MG_Levels **mglevels = mg->levels; 426 427 PetscFunctionBegin; 428 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 429 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 430 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1); 431 if (!mglevels[l]->rscale) { 432 Mat R; 433 Vec X, Y, coarse, fine; 434 PetscInt M, N; 435 436 PetscCall(PCMGGetRestriction(pc, l, &R)); 437 PetscCall(MatCreateVecs(R, &X, &Y)); 438 PetscCall(MatGetSize(R, &M, &N)); 439 PetscCheck(N != M, PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser"); 440 if (M < N) { 441 fine = X; 442 coarse = Y; 443 } else { 444 fine = Y; 445 coarse = X; 446 } 447 PetscCall(VecSet(fine, 1.)); 448 PetscCall(MatRestrict(R, fine, coarse)); 449 PetscCall(VecDestroy(&fine)); 450 PetscCall(VecReciprocal(coarse)); 451 mglevels[l]->rscale = coarse; 452 } 453 *rscale = mglevels[l]->rscale; 454 PetscFunctionReturn(0); 455 } 456 457 /*@ 458 PCMGSetInjection - Sets the function to be used to inject primal vectors 459 from level l to l-1. 460 461 Logically Collective on pc 462 463 Input Parameters: 464 + pc - the multigrid context 465 . l - the level (0 is coarsest) to supply [Do not supply 0] 466 - mat - the injection matrix 467 468 Level: advanced 469 470 .seealso: `PCMG`, `PCMGSetRestriction()` 471 @*/ 472 PetscErrorCode PCMGSetInjection(PC pc, PetscInt l, Mat mat) 473 { 474 PC_MG *mg = (PC_MG *)pc->data; 475 PC_MG_Levels **mglevels = mg->levels; 476 477 PetscFunctionBegin; 478 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 479 PetscValidHeaderSpecific(mat, MAT_CLASSID, 3); 480 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 481 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level"); 482 PetscCall(PetscObjectReference((PetscObject)mat)); 483 PetscCall(MatDestroy(&mglevels[l]->inject)); 484 485 mglevels[l]->inject = mat; 486 PetscFunctionReturn(0); 487 } 488 489 /*@ 490 PCMGGetInjection - Gets the function to be used to inject primal vectors 491 from level l to l-1. 492 493 Logically Collective on pc 494 495 Input Parameters: 496 + pc - the multigrid context 497 - l - the level (0 is coarsest) to supply [Do not supply 0] 498 499 Output Parameter: 500 . mat - the restriction matrix (may be NULL if no injection is available). 501 502 Level: advanced 503 504 .seealso: `PCMG`, `PCMGSetInjection()`, `PCMGetGetRestriction()` 505 @*/ 506 PetscErrorCode PCMGGetInjection(PC pc, PetscInt l, Mat *mat) 507 { 508 PC_MG *mg = (PC_MG *)pc->data; 509 PC_MG_Levels **mglevels = mg->levels; 510 511 PetscFunctionBegin; 512 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 513 if (mat) PetscValidPointer(mat, 3); 514 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 515 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1); 516 if (mat) *mat = mglevels[l]->inject; 517 PetscFunctionReturn(0); 518 } 519 520 /*@ 521 PCMGGetSmoother - Gets the `KSP` context to be used as smoother for 522 both pre- and post-smoothing. Call both `PCMGGetSmootherUp()` and 523 `PCMGGetSmootherDown()` to use different functions for pre- and 524 post-smoothing. 525 526 Not Collective, ksp returned is parallel if pc is 527 528 Input Parameters: 529 + pc - the multigrid context 530 - l - the level (0 is coarsest) to supply 531 532 Output Parameter: 533 . ksp - the smoother 534 535 Note: 536 Once you have called this routine, you can call `KSPSetOperators()` on the resulting ksp to provide the operators for the smoother for this level. 537 You can also modify smoother options by calling the various KSPSetXXX() options on this ksp. In addition you can call `KSPGetPC`(ksp,&pc) 538 and modify PC options for the smoother; for example `PCSetType`(pc,`PCSOR`); to use SOR smoothing. 539 540 Level: advanced 541 542 .seealso: PCMG`, ``PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetCoarseSolve()` 543 @*/ 544 PetscErrorCode PCMGGetSmoother(PC pc, PetscInt l, KSP *ksp) 545 { 546 PC_MG *mg = (PC_MG *)pc->data; 547 PC_MG_Levels **mglevels = mg->levels; 548 549 PetscFunctionBegin; 550 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 551 *ksp = mglevels[l]->smoothd; 552 PetscFunctionReturn(0); 553 } 554 555 /*@ 556 PCMGGetSmootherUp - Gets the KSP context to be used as smoother after 557 coarse grid correction (post-smoother). 558 559 Not Collective, ksp returned is parallel if pc is 560 561 Input Parameters: 562 + pc - the multigrid context 563 - l - the level (0 is coarsest) to supply 564 565 Output Parameter: 566 . ksp - the smoother 567 568 Level: advanced 569 570 Note: 571 Calling this will result in a different pre and post smoother so you may need to set options on the pre smoother also 572 573 .seealso: `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()` 574 @*/ 575 PetscErrorCode PCMGGetSmootherUp(PC pc, PetscInt l, KSP *ksp) 576 { 577 PC_MG *mg = (PC_MG *)pc->data; 578 PC_MG_Levels **mglevels = mg->levels; 579 const char *prefix; 580 MPI_Comm comm; 581 582 PetscFunctionBegin; 583 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 584 /* 585 This is called only if user wants a different pre-smoother from post. 586 Thus we check if a different one has already been allocated, 587 if not we allocate it. 588 */ 589 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "There is no such thing as a up smoother on the coarse grid"); 590 if (mglevels[l]->smoothu == mglevels[l]->smoothd) { 591 KSPType ksptype; 592 PCType pctype; 593 PC ipc; 594 PetscReal rtol, abstol, dtol; 595 PetscInt maxits; 596 KSPNormType normtype; 597 PetscCall(PetscObjectGetComm((PetscObject)mglevels[l]->smoothd, &comm)); 598 PetscCall(KSPGetOptionsPrefix(mglevels[l]->smoothd, &prefix)); 599 PetscCall(KSPGetTolerances(mglevels[l]->smoothd, &rtol, &abstol, &dtol, &maxits)); 600 PetscCall(KSPGetType(mglevels[l]->smoothd, &ksptype)); 601 PetscCall(KSPGetNormType(mglevels[l]->smoothd, &normtype)); 602 PetscCall(KSPGetPC(mglevels[l]->smoothd, &ipc)); 603 PetscCall(PCGetType(ipc, &pctype)); 604 605 PetscCall(KSPCreate(comm, &mglevels[l]->smoothu)); 606 PetscCall(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure)); 607 PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l)); 608 PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix)); 609 PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits)); 610 PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype)); 611 PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype)); 612 PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL)); 613 PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc)); 614 PetscCall(PCSetType(ipc, pctype)); 615 PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level)); 616 } 617 if (ksp) *ksp = mglevels[l]->smoothu; 618 PetscFunctionReturn(0); 619 } 620 621 /*@ 622 PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before 623 coarse grid correction (pre-smoother). 624 625 Not Collective, ksp returned is parallel if pc is 626 627 Input Parameters: 628 + pc - the multigrid context 629 - l - the level (0 is coarsest) to supply 630 631 Output Parameter: 632 . ksp - the smoother 633 634 Level: advanced 635 636 Note: 637 Calling this will result in a different pre and post smoother so you may need to 638 set options on the post smoother also 639 640 .seealso: `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()` 641 @*/ 642 PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp) 643 { 644 PC_MG *mg = (PC_MG *)pc->data; 645 PC_MG_Levels **mglevels = mg->levels; 646 647 PetscFunctionBegin; 648 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 649 /* make sure smoother up and down are different */ 650 if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL)); 651 *ksp = mglevels[l]->smoothd; 652 PetscFunctionReturn(0); 653 } 654 655 /*@ 656 PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level. 657 658 Logically Collective on pc 659 660 Input Parameters: 661 + pc - the multigrid context 662 . l - the level (0 is coarsest) 663 - c - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W` 664 665 Level: advanced 666 667 .seealso: `PCMG`, PCMGCycleType`, `PCMGSetCycleType()` 668 @*/ 669 PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c) 670 { 671 PC_MG *mg = (PC_MG *)pc->data; 672 PC_MG_Levels **mglevels = mg->levels; 673 674 PetscFunctionBegin; 675 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 676 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 677 PetscValidLogicalCollectiveInt(pc, l, 2); 678 PetscValidLogicalCollectiveEnum(pc, c, 3); 679 mglevels[l]->cycles = c; 680 PetscFunctionReturn(0); 681 } 682 683 /*@ 684 PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level. 685 686 Logically Collective on pc 687 688 Input Parameters: 689 + pc - the multigrid context 690 . l - the level (0 is coarsest) this is to be used for 691 - c - the Vec 692 693 Level: advanced 694 695 Note: 696 If this is not provided PETSc will automatically generate one. You do not need to keep a reference to this vector if you do not need it. `PCDestroy()` will properly free it. 697 698 .seealso: `PCMG`, `PCMGSetX()`, `PCMGSetR()` 699 @*/ 700 PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c) 701 { 702 PC_MG *mg = (PC_MG *)pc->data; 703 PC_MG_Levels **mglevels = mg->levels; 704 705 PetscFunctionBegin; 706 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 707 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 708 PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level"); 709 PetscCall(PetscObjectReference((PetscObject)c)); 710 PetscCall(VecDestroy(&mglevels[l]->b)); 711 712 mglevels[l]->b = c; 713 PetscFunctionReturn(0); 714 } 715 716 /*@ 717 PCMGSetX - Sets the vector to be used to store the solution on a particular level. 718 719 Logically Collective on pc 720 721 Input Parameters: 722 + pc - the multigrid context 723 . l - the level (0 is coarsest) this is to be used for (do not supply the finest level) 724 - c - the Vec 725 726 Level: advanced 727 728 Note: 729 If this is not provided PETSc will automatically generate one. You do not need to keep a reference to this vector if you do not need it. `PCDestroy()` will properly free it. 730 731 .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetR()` 732 @*/ 733 PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c) 734 { 735 PC_MG *mg = (PC_MG *)pc->data; 736 PC_MG_Levels **mglevels = mg->levels; 737 738 PetscFunctionBegin; 739 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 740 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 741 PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level"); 742 PetscCall(PetscObjectReference((PetscObject)c)); 743 PetscCall(VecDestroy(&mglevels[l]->x)); 744 745 mglevels[l]->x = c; 746 PetscFunctionReturn(0); 747 } 748 749 /*@ 750 PCMGSetR - Sets the vector to be used to store the residual on a particular level. 751 752 Logically Collective on pc 753 754 Input Parameters: 755 + pc - the multigrid context 756 . l - the level (0 is coarsest) this is to be used for 757 - c - the Vec 758 759 Level: advanced 760 761 Note: 762 If this is not provided PETSc will automatically generate one. You do not need to keep a reference to this vector if you do not need it. `PCDestroy()` will properly free it. 763 764 .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetX()` 765 @*/ 766 PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c) 767 { 768 PC_MG *mg = (PC_MG *)pc->data; 769 PC_MG_Levels **mglevels = mg->levels; 770 771 PetscFunctionBegin; 772 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 773 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 774 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid"); 775 PetscCall(PetscObjectReference((PetscObject)c)); 776 PetscCall(VecDestroy(&mglevels[l]->r)); 777 778 mglevels[l]->r = c; 779 PetscFunctionReturn(0); 780 } 781