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 PetscCall(PCMGGetRestriction(pc, l, &R)); 436 PetscCall(MatCreateVecs(R, &X, &Y)); 437 PetscCall(MatGetSize(R, &M, &N)); 438 if (M < N) { 439 fine = X; 440 coarse = Y; 441 } else if (N < M) { 442 fine = Y; 443 coarse = X; 444 } else SETERRQ(PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser"); 445 PetscCall(VecSet(fine, 1.)); 446 PetscCall(MatRestrict(R, fine, coarse)); 447 PetscCall(VecDestroy(&fine)); 448 PetscCall(VecReciprocal(coarse)); 449 mglevels[l]->rscale = coarse; 450 } 451 *rscale = mglevels[l]->rscale; 452 PetscFunctionReturn(0); 453 } 454 455 /*@ 456 PCMGSetInjection - Sets the function to be used to inject primal vectors 457 from level l to l-1. 458 459 Logically Collective on pc 460 461 Input Parameters: 462 + pc - the multigrid context 463 . l - the level (0 is coarsest) to supply [Do not supply 0] 464 - mat - the injection matrix 465 466 Level: advanced 467 468 .seealso: `PCMG`, `PCMGSetRestriction()` 469 @*/ 470 PetscErrorCode PCMGSetInjection(PC pc, PetscInt l, Mat mat) 471 { 472 PC_MG *mg = (PC_MG *)pc->data; 473 PC_MG_Levels **mglevels = mg->levels; 474 475 PetscFunctionBegin; 476 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 477 PetscValidHeaderSpecific(mat, MAT_CLASSID, 3); 478 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 479 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level"); 480 PetscCall(PetscObjectReference((PetscObject)mat)); 481 PetscCall(MatDestroy(&mglevels[l]->inject)); 482 483 mglevels[l]->inject = mat; 484 PetscFunctionReturn(0); 485 } 486 487 /*@ 488 PCMGGetInjection - Gets the function to be used to inject primal vectors 489 from level l to l-1. 490 491 Logically Collective on pc 492 493 Input Parameters: 494 + pc - the multigrid context 495 - l - the level (0 is coarsest) to supply [Do not supply 0] 496 497 Output Parameter: 498 . mat - the restriction matrix (may be NULL if no injection is available). 499 500 Level: advanced 501 502 .seealso: `PCMG`, `PCMGSetInjection()`, `PCMGetGetRestriction()` 503 @*/ 504 PetscErrorCode PCMGGetInjection(PC pc, PetscInt l, Mat *mat) 505 { 506 PC_MG *mg = (PC_MG *)pc->data; 507 PC_MG_Levels **mglevels = mg->levels; 508 509 PetscFunctionBegin; 510 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 511 if (mat) PetscValidPointer(mat, 3); 512 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 513 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); 514 if (mat) *mat = mglevels[l]->inject; 515 PetscFunctionReturn(0); 516 } 517 518 /*@ 519 PCMGGetSmoother - Gets the `KSP` context to be used as smoother for 520 both pre- and post-smoothing. Call both `PCMGGetSmootherUp()` and 521 `PCMGGetSmootherDown()` to use different functions for pre- and 522 post-smoothing. 523 524 Not Collective, ksp returned is parallel if pc is 525 526 Input Parameters: 527 + pc - the multigrid context 528 - l - the level (0 is coarsest) to supply 529 530 Output Parameter: 531 . ksp - the smoother 532 533 Note: 534 Once you have called this routine, you can call `KSPSetOperators()` on the resulting ksp to provide the operators for the smoother for this level. 535 You can also modify smoother options by calling the various KSPSetXXX() options on this ksp. In addition you can call `KSPGetPC`(ksp,&pc) 536 and modify PC options for the smoother; for example `PCSetType`(pc,`PCSOR`); to use SOR smoothing. 537 538 Level: advanced 539 540 .seealso: PCMG`, ``PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetCoarseSolve()` 541 @*/ 542 PetscErrorCode PCMGGetSmoother(PC pc, PetscInt l, KSP *ksp) 543 { 544 PC_MG *mg = (PC_MG *)pc->data; 545 PC_MG_Levels **mglevels = mg->levels; 546 547 PetscFunctionBegin; 548 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 549 *ksp = mglevels[l]->smoothd; 550 PetscFunctionReturn(0); 551 } 552 553 /*@ 554 PCMGGetSmootherUp - Gets the KSP context to be used as smoother after 555 coarse grid correction (post-smoother). 556 557 Not Collective, ksp returned is parallel if pc is 558 559 Input Parameters: 560 + pc - the multigrid context 561 - l - the level (0 is coarsest) to supply 562 563 Output Parameter: 564 . ksp - the smoother 565 566 Level: advanced 567 568 Note: 569 Calling this will result in a different pre and post smoother so you may need to set options on the pre smoother also 570 571 .seealso: `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()` 572 @*/ 573 PetscErrorCode PCMGGetSmootherUp(PC pc, PetscInt l, KSP *ksp) 574 { 575 PC_MG *mg = (PC_MG *)pc->data; 576 PC_MG_Levels **mglevels = mg->levels; 577 const char *prefix; 578 MPI_Comm comm; 579 580 PetscFunctionBegin; 581 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 582 /* 583 This is called only if user wants a different pre-smoother from post. 584 Thus we check if a different one has already been allocated, 585 if not we allocate it. 586 */ 587 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "There is no such thing as a up smoother on the coarse grid"); 588 if (mglevels[l]->smoothu == mglevels[l]->smoothd) { 589 KSPType ksptype; 590 PCType pctype; 591 PC ipc; 592 PetscReal rtol, abstol, dtol; 593 PetscInt maxits; 594 KSPNormType normtype; 595 PetscCall(PetscObjectGetComm((PetscObject)mglevels[l]->smoothd, &comm)); 596 PetscCall(KSPGetOptionsPrefix(mglevels[l]->smoothd, &prefix)); 597 PetscCall(KSPGetTolerances(mglevels[l]->smoothd, &rtol, &abstol, &dtol, &maxits)); 598 PetscCall(KSPGetType(mglevels[l]->smoothd, &ksptype)); 599 PetscCall(KSPGetNormType(mglevels[l]->smoothd, &normtype)); 600 PetscCall(KSPGetPC(mglevels[l]->smoothd, &ipc)); 601 PetscCall(PCGetType(ipc, &pctype)); 602 603 PetscCall(KSPCreate(comm, &mglevels[l]->smoothu)); 604 PetscCall(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure)); 605 PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l)); 606 PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix)); 607 PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits)); 608 PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype)); 609 PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype)); 610 PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL)); 611 PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc)); 612 PetscCall(PCSetType(ipc, pctype)); 613 PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level)); 614 } 615 if (ksp) *ksp = mglevels[l]->smoothu; 616 PetscFunctionReturn(0); 617 } 618 619 /*@ 620 PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before 621 coarse grid correction (pre-smoother). 622 623 Not Collective, ksp returned is parallel if pc is 624 625 Input Parameters: 626 + pc - the multigrid context 627 - l - the level (0 is coarsest) to supply 628 629 Output Parameter: 630 . ksp - the smoother 631 632 Level: advanced 633 634 Note: 635 Calling this will result in a different pre and post smoother so you may need to 636 set options on the post smoother also 637 638 .seealso: `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()` 639 @*/ 640 PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp) 641 { 642 PC_MG *mg = (PC_MG *)pc->data; 643 PC_MG_Levels **mglevels = mg->levels; 644 645 PetscFunctionBegin; 646 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 647 /* make sure smoother up and down are different */ 648 if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL)); 649 *ksp = mglevels[l]->smoothd; 650 PetscFunctionReturn(0); 651 } 652 653 /*@ 654 PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level. 655 656 Logically Collective on pc 657 658 Input Parameters: 659 + pc - the multigrid context 660 . l - the level (0 is coarsest) 661 - c - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W` 662 663 Level: advanced 664 665 .seealso: `PCMG`, PCMGCycleType`, `PCMGSetCycleType()` 666 @*/ 667 PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c) 668 { 669 PC_MG *mg = (PC_MG *)pc->data; 670 PC_MG_Levels **mglevels = mg->levels; 671 672 PetscFunctionBegin; 673 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 674 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 675 PetscValidLogicalCollectiveInt(pc, l, 2); 676 PetscValidLogicalCollectiveEnum(pc, c, 3); 677 mglevels[l]->cycles = c; 678 PetscFunctionReturn(0); 679 } 680 681 /*@ 682 PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level. 683 684 Logically Collective on pc 685 686 Input Parameters: 687 + pc - the multigrid context 688 . l - the level (0 is coarsest) this is to be used for 689 - c - the Vec 690 691 Level: advanced 692 693 Note: 694 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. 695 696 .seealso: `PCMG`, `PCMGSetX()`, `PCMGSetR()` 697 @*/ 698 PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c) 699 { 700 PC_MG *mg = (PC_MG *)pc->data; 701 PC_MG_Levels **mglevels = mg->levels; 702 703 PetscFunctionBegin; 704 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 705 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 706 PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level"); 707 PetscCall(PetscObjectReference((PetscObject)c)); 708 PetscCall(VecDestroy(&mglevels[l]->b)); 709 710 mglevels[l]->b = c; 711 PetscFunctionReturn(0); 712 } 713 714 /*@ 715 PCMGSetX - Sets the vector to be used to store the solution on a particular level. 716 717 Logically Collective on pc 718 719 Input Parameters: 720 + pc - the multigrid context 721 . l - the level (0 is coarsest) this is to be used for (do not supply the finest level) 722 - c - the Vec 723 724 Level: advanced 725 726 Note: 727 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. 728 729 .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetR()` 730 @*/ 731 PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c) 732 { 733 PC_MG *mg = (PC_MG *)pc->data; 734 PC_MG_Levels **mglevels = mg->levels; 735 736 PetscFunctionBegin; 737 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 738 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 739 PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level"); 740 PetscCall(PetscObjectReference((PetscObject)c)); 741 PetscCall(VecDestroy(&mglevels[l]->x)); 742 743 mglevels[l]->x = c; 744 PetscFunctionReturn(0); 745 } 746 747 /*@ 748 PCMGSetR - Sets the vector to be used to store the residual on a particular level. 749 750 Logically Collective on pc 751 752 Input Parameters: 753 + pc - the multigrid context 754 . l - the level (0 is coarsest) this is to be used for 755 - c - the Vec 756 757 Level: advanced 758 759 Note: 760 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. 761 762 .seealso: `PCMG`, `PCMGSetRhs()`, `PCMGSetX()` 763 @*/ 764 PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c) 765 { 766 PC_MG *mg = (PC_MG *)pc->data; 767 PC_MG_Levels **mglevels = mg->levels; 768 769 PetscFunctionBegin; 770 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 771 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling"); 772 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid"); 773 PetscCall(PetscObjectReference((PetscObject)c)); 774 PetscCall(VecDestroy(&mglevels[l]->r)); 775 776 mglevels[l]->r = c; 777 PetscFunctionReturn(0); 778 } 779