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