1 /* 2 This provides a simple shell for Fortran (and C programmers) to 3 create their own preconditioner without writing much interface code. 4 */ 5 6 #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 7 8 typedef struct { 9 void *ctx; /* user provided contexts for preconditioner */ 10 11 PetscErrorCode (*destroy)(PC); 12 PetscErrorCode (*setup)(PC); 13 PetscErrorCode (*apply)(PC, Vec, Vec); 14 PetscErrorCode (*matapply)(PC, Mat, Mat); 15 PetscErrorCode (*applysymmetricleft)(PC, Vec, Vec); 16 PetscErrorCode (*applysymmetricright)(PC, Vec, Vec); 17 PetscErrorCode (*applyBA)(PC, PCSide, Vec, Vec, Vec); 18 PetscErrorCode (*presolve)(PC, KSP, Vec, Vec); 19 PetscErrorCode (*postsolve)(PC, KSP, Vec, Vec); 20 PetscErrorCode (*view)(PC, PetscViewer); 21 PetscErrorCode (*applytranspose)(PC, Vec, Vec); 22 PetscErrorCode (*applyrich)(PC, Vec, Vec, Vec, PetscReal, PetscReal, PetscReal, PetscInt, PetscBool, PetscInt *, PCRichardsonConvergedReason *); 23 24 char *name; 25 } PC_Shell; 26 27 /*@C 28 PCShellGetContext - Returns the user-provided context associated with a shell `PC` that was provided with `PCShellSetContext()` 29 30 Not Collective 31 32 Input Parameter: 33 . pc - of type `PCSHELL` 34 35 Output Parameter: 36 . ctx - the user provided context 37 38 Level: advanced 39 40 Note: 41 This routine is intended for use within the various user-provided routines set with, for example, `PCShellSetApply()` 42 43 Fortran Note: 44 To use this from Fortran you must write a Fortran interface definition for this 45 function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 46 47 .seealso: [](ch_ksp), `PC`, `PCSHELL`, `PCShellSetContext()`, `PCShellSetApply()`, `PCShellSetDestroy()` 48 @*/ 49 PetscErrorCode PCShellGetContext(PC pc, void *ctx) 50 { 51 PetscBool flg; 52 53 PetscFunctionBegin; 54 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 55 PetscAssertPointer(ctx, 2); 56 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCSHELL, &flg)); 57 if (!flg) *(void **)ctx = NULL; 58 else *(void **)ctx = ((PC_Shell *)pc->data)->ctx; 59 PetscFunctionReturn(PETSC_SUCCESS); 60 } 61 62 /*@ 63 PCShellSetContext - sets the context for a shell `PC` that can be accessed with `PCShellGetContext()` 64 65 Logically Collective 66 67 Input Parameters: 68 + pc - the `PC` of type `PCSHELL` 69 - ctx - the context 70 71 Level: advanced 72 73 Notes: 74 This routine is intended for use within the various user-provided routines set with, for example, `PCShellSetApply()` 75 76 One should also provide a routine to destroy the context when `pc` is destroyed with `PCShellSetDestroy()` 77 78 Fortran Notes: 79 To use this from Fortran you must write a Fortran interface definition for this 80 function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 81 82 .seealso: [](ch_ksp), `PC`, `PCShellGetContext()`, `PCSHELL`, `PCShellSetApply()`, `PCShellSetDestroy()` 83 @*/ 84 PetscErrorCode PCShellSetContext(PC pc, void *ctx) 85 { 86 PC_Shell *shell = (PC_Shell *)pc->data; 87 PetscBool flg; 88 89 PetscFunctionBegin; 90 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 91 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCSHELL, &flg)); 92 if (flg) shell->ctx = ctx; 93 PetscFunctionReturn(PETSC_SUCCESS); 94 } 95 96 static PetscErrorCode PCSetUp_Shell(PC pc) 97 { 98 PC_Shell *shell = (PC_Shell *)pc->data; 99 100 PetscFunctionBegin; 101 PetscCheck(shell->setup, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No setup() routine provided to Shell PC"); 102 PetscCallBack("PCSHELL callback setup", (*shell->setup)(pc)); 103 PetscFunctionReturn(PETSC_SUCCESS); 104 } 105 106 static PetscErrorCode PCApply_Shell(PC pc, Vec x, Vec y) 107 { 108 PC_Shell *shell = (PC_Shell *)pc->data; 109 PetscObjectState instate, outstate; 110 111 PetscFunctionBegin; 112 PetscCheck(shell->apply, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No apply() routine provided to Shell PC"); 113 PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 114 PetscCallBack("PCSHELL callback apply", (*shell->apply)(pc, x, y)); 115 PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 116 /* increase the state of the output vector if the user did not update its state themself as should have been done */ 117 if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)y)); 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 static PetscErrorCode PCMatApply_Shell(PC pc, Mat X, Mat Y) 122 { 123 PC_Shell *shell = (PC_Shell *)pc->data; 124 PetscObjectState instate, outstate; 125 126 PetscFunctionBegin; 127 PetscCheck(shell->matapply, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No apply() routine provided to Shell PC"); 128 PetscCall(PetscObjectStateGet((PetscObject)Y, &instate)); 129 PetscCallBack("PCSHELL callback apply", (*shell->matapply)(pc, X, Y)); 130 PetscCall(PetscObjectStateGet((PetscObject)Y, &outstate)); 131 /* increase the state of the output vector if the user did not update its state themself as should have been done */ 132 if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)Y)); 133 PetscFunctionReturn(PETSC_SUCCESS); 134 } 135 136 static PetscErrorCode PCApplySymmetricLeft_Shell(PC pc, Vec x, Vec y) 137 { 138 PC_Shell *shell = (PC_Shell *)pc->data; 139 140 PetscFunctionBegin; 141 PetscCheck(shell->applysymmetricleft, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No apply() routine provided to Shell PC"); 142 PetscCallBack("PCSHELL callback apply symmetric left", (*shell->applysymmetricleft)(pc, x, y)); 143 PetscFunctionReturn(PETSC_SUCCESS); 144 } 145 146 static PetscErrorCode PCApplySymmetricRight_Shell(PC pc, Vec x, Vec y) 147 { 148 PC_Shell *shell = (PC_Shell *)pc->data; 149 150 PetscFunctionBegin; 151 PetscCheck(shell->applysymmetricright, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No apply() routine provided to Shell PC"); 152 PetscCallBack("PCSHELL callback apply symmetric right", (*shell->applysymmetricright)(pc, x, y)); 153 PetscFunctionReturn(PETSC_SUCCESS); 154 } 155 156 static PetscErrorCode PCApplyBA_Shell(PC pc, PCSide side, Vec x, Vec y, Vec w) 157 { 158 PC_Shell *shell = (PC_Shell *)pc->data; 159 PetscObjectState instate, outstate; 160 161 PetscFunctionBegin; 162 PetscCheck(shell->applyBA, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No applyBA() routine provided to Shell PC"); 163 PetscCall(PetscObjectStateGet((PetscObject)w, &instate)); 164 PetscCallBack("PCSHELL callback applyBA", (*shell->applyBA)(pc, side, x, y, w)); 165 PetscCall(PetscObjectStateGet((PetscObject)w, &outstate)); 166 /* increase the state of the output vector if the user did not update its state themself as should have been done */ 167 if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)w)); 168 PetscFunctionReturn(PETSC_SUCCESS); 169 } 170 171 static PetscErrorCode PCPreSolveChangeRHS_Shell(PC pc, PetscBool *change) 172 { 173 PetscFunctionBegin; 174 *change = PETSC_TRUE; 175 PetscFunctionReturn(PETSC_SUCCESS); 176 } 177 178 static PetscErrorCode PCPreSolve_Shell(PC pc, KSP ksp, Vec b, Vec x) 179 { 180 PC_Shell *shell = (PC_Shell *)pc->data; 181 182 PetscFunctionBegin; 183 PetscCheck(shell->presolve, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No presolve() routine provided to Shell PC"); 184 PetscCallBack("PCSHELL callback presolve", (*shell->presolve)(pc, ksp, b, x)); 185 PetscFunctionReturn(PETSC_SUCCESS); 186 } 187 188 static PetscErrorCode PCPostSolve_Shell(PC pc, KSP ksp, Vec b, Vec x) 189 { 190 PC_Shell *shell = (PC_Shell *)pc->data; 191 192 PetscFunctionBegin; 193 PetscCheck(shell->postsolve, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No postsolve() routine provided to Shell PC"); 194 PetscCallBack("PCSHELL callback postsolve()", (*shell->postsolve)(pc, ksp, b, x)); 195 PetscFunctionReturn(PETSC_SUCCESS); 196 } 197 198 static PetscErrorCode PCApplyTranspose_Shell(PC pc, Vec x, Vec y) 199 { 200 PC_Shell *shell = (PC_Shell *)pc->data; 201 PetscObjectState instate, outstate; 202 203 PetscFunctionBegin; 204 PetscCheck(shell->applytranspose, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No applytranspose() routine provided to Shell PC"); 205 PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 206 PetscCallBack("PCSHELL callback applytranspose", (*shell->applytranspose)(pc, x, y)); 207 PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 208 /* increase the state of the output vector if the user did not update its state themself as should have been done */ 209 if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)y)); 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 static PetscErrorCode PCApplyRichardson_Shell(PC pc, Vec x, Vec y, Vec w, PetscReal rtol, PetscReal abstol, PetscReal dtol, PetscInt it, PetscBool guesszero, PetscInt *outits, PCRichardsonConvergedReason *reason) 214 { 215 PC_Shell *shell = (PC_Shell *)pc->data; 216 PetscObjectState instate, outstate; 217 218 PetscFunctionBegin; 219 PetscCheck(shell->applyrich, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No applyrichardson() routine provided to Shell PC"); 220 PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 221 PetscCallBack("PCSHELL callback applyrichardson", (*shell->applyrich)(pc, x, y, w, rtol, abstol, dtol, it, guesszero, outits, reason)); 222 PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 223 /* increase the state of the output vector since the user did not update its state themself as should have been done */ 224 if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)y)); 225 PetscFunctionReturn(PETSC_SUCCESS); 226 } 227 228 static PetscErrorCode PCDestroy_Shell(PC pc) 229 { 230 PC_Shell *shell = (PC_Shell *)pc->data; 231 232 PetscFunctionBegin; 233 PetscCall(PetscFree(shell->name)); 234 if (shell->destroy) PetscCallBack("PCSHELL callback destroy", (*shell->destroy)(pc)); 235 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetDestroy_C", NULL)); 236 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetSetUp_C", NULL)); 237 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApply_C", NULL)); 238 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetMatApply_C", NULL)); 239 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplySymmetricLeft_C", NULL)); 240 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplySymmetricRight_C", NULL)); 241 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyBA_C", NULL)); 242 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetPreSolve_C", NULL)); 243 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetPostSolve_C", NULL)); 244 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetView_C", NULL)); 245 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyTranspose_C", NULL)); 246 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetName_C", NULL)); 247 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellGetName_C", NULL)); 248 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyRichardson_C", NULL)); 249 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", NULL)); 250 PetscCall(PetscFree(pc->data)); 251 PetscFunctionReturn(PETSC_SUCCESS); 252 } 253 254 static PetscErrorCode PCView_Shell(PC pc, PetscViewer viewer) 255 { 256 PC_Shell *shell = (PC_Shell *)pc->data; 257 PetscBool iascii; 258 259 PetscFunctionBegin; 260 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 261 if (iascii) { 262 if (shell->name) PetscCall(PetscViewerASCIIPrintf(viewer, " %s\n", shell->name)); 263 else PetscCall(PetscViewerASCIIPrintf(viewer, " no name\n")); 264 } 265 if (shell->view) { 266 PetscCall(PetscViewerASCIIPushTab(viewer)); 267 PetscCall((*shell->view)(pc, viewer)); 268 PetscCall(PetscViewerASCIIPopTab(viewer)); 269 } 270 PetscFunctionReturn(PETSC_SUCCESS); 271 } 272 273 static PetscErrorCode PCShellSetDestroy_Shell(PC pc, PetscErrorCode (*destroy)(PC)) 274 { 275 PC_Shell *shell = (PC_Shell *)pc->data; 276 277 PetscFunctionBegin; 278 shell->destroy = destroy; 279 PetscFunctionReturn(PETSC_SUCCESS); 280 } 281 282 static PetscErrorCode PCShellSetSetUp_Shell(PC pc, PetscErrorCode (*setup)(PC)) 283 { 284 PC_Shell *shell = (PC_Shell *)pc->data; 285 286 PetscFunctionBegin; 287 shell->setup = setup; 288 if (setup) pc->ops->setup = PCSetUp_Shell; 289 else pc->ops->setup = NULL; 290 PetscFunctionReturn(PETSC_SUCCESS); 291 } 292 293 static PetscErrorCode PCShellSetApply_Shell(PC pc, PetscErrorCode (*apply)(PC, Vec, Vec)) 294 { 295 PC_Shell *shell = (PC_Shell *)pc->data; 296 297 PetscFunctionBegin; 298 shell->apply = apply; 299 PetscFunctionReturn(PETSC_SUCCESS); 300 } 301 302 static PetscErrorCode PCShellSetMatApply_Shell(PC pc, PetscErrorCode (*matapply)(PC, Mat, Mat)) 303 { 304 PC_Shell *shell = (PC_Shell *)pc->data; 305 306 PetscFunctionBegin; 307 shell->matapply = matapply; 308 if (matapply) pc->ops->matapply = PCMatApply_Shell; 309 else pc->ops->matapply = NULL; 310 PetscFunctionReturn(PETSC_SUCCESS); 311 } 312 313 static PetscErrorCode PCShellSetApplySymmetricLeft_Shell(PC pc, PetscErrorCode (*apply)(PC, Vec, Vec)) 314 { 315 PC_Shell *shell = (PC_Shell *)pc->data; 316 317 PetscFunctionBegin; 318 shell->applysymmetricleft = apply; 319 PetscFunctionReturn(PETSC_SUCCESS); 320 } 321 322 static PetscErrorCode PCShellSetApplySymmetricRight_Shell(PC pc, PetscErrorCode (*apply)(PC, Vec, Vec)) 323 { 324 PC_Shell *shell = (PC_Shell *)pc->data; 325 326 PetscFunctionBegin; 327 shell->applysymmetricright = apply; 328 PetscFunctionReturn(PETSC_SUCCESS); 329 } 330 331 static PetscErrorCode PCShellSetApplyBA_Shell(PC pc, PetscErrorCode (*applyBA)(PC, PCSide, Vec, Vec, Vec)) 332 { 333 PC_Shell *shell = (PC_Shell *)pc->data; 334 335 PetscFunctionBegin; 336 shell->applyBA = applyBA; 337 if (applyBA) pc->ops->applyBA = PCApplyBA_Shell; 338 else pc->ops->applyBA = NULL; 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 static PetscErrorCode PCShellSetPreSolve_Shell(PC pc, PetscErrorCode (*presolve)(PC, KSP, Vec, Vec)) 343 { 344 PC_Shell *shell = (PC_Shell *)pc->data; 345 346 PetscFunctionBegin; 347 shell->presolve = presolve; 348 if (presolve) { 349 pc->ops->presolve = PCPreSolve_Shell; 350 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", PCPreSolveChangeRHS_Shell)); 351 } else { 352 pc->ops->presolve = NULL; 353 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", NULL)); 354 } 355 PetscFunctionReturn(PETSC_SUCCESS); 356 } 357 358 static PetscErrorCode PCShellSetPostSolve_Shell(PC pc, PetscErrorCode (*postsolve)(PC, KSP, Vec, Vec)) 359 { 360 PC_Shell *shell = (PC_Shell *)pc->data; 361 362 PetscFunctionBegin; 363 shell->postsolve = postsolve; 364 if (postsolve) pc->ops->postsolve = PCPostSolve_Shell; 365 else pc->ops->postsolve = NULL; 366 PetscFunctionReturn(PETSC_SUCCESS); 367 } 368 369 static PetscErrorCode PCShellSetView_Shell(PC pc, PetscErrorCode (*view)(PC, PetscViewer)) 370 { 371 PC_Shell *shell = (PC_Shell *)pc->data; 372 373 PetscFunctionBegin; 374 shell->view = view; 375 PetscFunctionReturn(PETSC_SUCCESS); 376 } 377 378 static PetscErrorCode PCShellSetApplyTranspose_Shell(PC pc, PetscErrorCode (*applytranspose)(PC, Vec, Vec)) 379 { 380 PC_Shell *shell = (PC_Shell *)pc->data; 381 382 PetscFunctionBegin; 383 shell->applytranspose = applytranspose; 384 if (applytranspose) pc->ops->applytranspose = PCApplyTranspose_Shell; 385 else pc->ops->applytranspose = NULL; 386 PetscFunctionReturn(PETSC_SUCCESS); 387 } 388 389 static PetscErrorCode PCShellSetApplyRichardson_Shell(PC pc, PetscErrorCode (*applyrich)(PC, Vec, Vec, Vec, PetscReal, PetscReal, PetscReal, PetscInt, PetscBool, PetscInt *, PCRichardsonConvergedReason *)) 390 { 391 PC_Shell *shell = (PC_Shell *)pc->data; 392 393 PetscFunctionBegin; 394 shell->applyrich = applyrich; 395 if (applyrich) pc->ops->applyrichardson = PCApplyRichardson_Shell; 396 else pc->ops->applyrichardson = NULL; 397 PetscFunctionReturn(PETSC_SUCCESS); 398 } 399 400 static PetscErrorCode PCShellSetName_Shell(PC pc, const char name[]) 401 { 402 PC_Shell *shell = (PC_Shell *)pc->data; 403 404 PetscFunctionBegin; 405 PetscCall(PetscFree(shell->name)); 406 PetscCall(PetscStrallocpy(name, &shell->name)); 407 PetscFunctionReturn(PETSC_SUCCESS); 408 } 409 410 static PetscErrorCode PCShellGetName_Shell(PC pc, const char *name[]) 411 { 412 PC_Shell *shell = (PC_Shell *)pc->data; 413 414 PetscFunctionBegin; 415 *name = shell->name; 416 PetscFunctionReturn(PETSC_SUCCESS); 417 } 418 419 /*@C 420 PCShellSetDestroy - Sets routine to use to destroy the user-provided application context that was provided with `PCShellSetContext()` 421 422 Logically Collective 423 424 Input Parameters: 425 + pc - the preconditioner context 426 - destroy - the application-provided destroy routine 427 428 Calling sequence of `destroy`: 429 . pc - the preconditioner 430 431 Level: intermediate 432 433 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetContext()`, `PCShellGetContext()` 434 @*/ 435 PetscErrorCode PCShellSetDestroy(PC pc, PetscErrorCode (*destroy)(PC pc)) 436 { 437 PetscFunctionBegin; 438 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 439 PetscTryMethod(pc, "PCShellSetDestroy_C", (PC, PetscErrorCode (*)(PC)), (pc, destroy)); 440 PetscFunctionReturn(PETSC_SUCCESS); 441 } 442 443 /*@C 444 PCShellSetSetUp - Sets routine to use to "setup" the preconditioner whenever the 445 matrix operator is changed. 446 447 Logically Collective 448 449 Input Parameters: 450 + pc - the preconditioner context 451 - setup - the application-provided setup routine 452 453 Calling sequence of `setup`: 454 . pc - the preconditioner 455 456 Level: intermediate 457 458 Note: 459 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `setup`. 460 461 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetApply()`, `PCShellSetContext()`, , `PCShellGetContext()` 462 @*/ 463 PetscErrorCode PCShellSetSetUp(PC pc, PetscErrorCode (*setup)(PC pc)) 464 { 465 PetscFunctionBegin; 466 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 467 PetscTryMethod(pc, "PCShellSetSetUp_C", (PC, PetscErrorCode (*)(PC)), (pc, setup)); 468 PetscFunctionReturn(PETSC_SUCCESS); 469 } 470 471 /*@C 472 PCShellSetView - Sets routine to use as viewer of a `PCSHELL` shell preconditioner 473 474 Logically Collective 475 476 Input Parameters: 477 + pc - the preconditioner context 478 - view - the application-provided view routine 479 480 Calling sequence of `view`: 481 + pc - the preconditioner 482 - v - viewer 483 484 Level: advanced 485 486 Note: 487 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `view`. 488 489 .seealso: [](ch_ksp), `PC`, `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`, `PCShellGetContext()` 490 @*/ 491 PetscErrorCode PCShellSetView(PC pc, PetscErrorCode (*view)(PC pc, PetscViewer v)) 492 { 493 PetscFunctionBegin; 494 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 495 PetscTryMethod(pc, "PCShellSetView_C", (PC, PetscErrorCode (*)(PC, PetscViewer)), (pc, view)); 496 PetscFunctionReturn(PETSC_SUCCESS); 497 } 498 499 /*@C 500 PCShellSetApply - Sets routine to use as preconditioner. 501 502 Logically Collective 503 504 Input Parameters: 505 + pc - the preconditioner context 506 - apply - the application-provided preconditioning routine 507 508 Calling sequence of `apply`: 509 + pc - the preconditioner, get the application context with `PCShellGetContext()` 510 . xin - input vector 511 - xout - output vector 512 513 Level: intermediate 514 515 Note: 516 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `apply`. 517 518 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`, `PCShellSetApplyBA()`, `PCShellSetApplySymmetricRight()`, `PCShellSetApplySymmetricLeft()`, `PCShellGetContext()` 519 @*/ 520 PetscErrorCode PCShellSetApply(PC pc, PetscErrorCode (*apply)(PC pc, Vec xin, Vec xout)) 521 { 522 PetscFunctionBegin; 523 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 524 PetscTryMethod(pc, "PCShellSetApply_C", (PC, PetscErrorCode (*)(PC, Vec, Vec)), (pc, apply)); 525 PetscFunctionReturn(PETSC_SUCCESS); 526 } 527 528 /*@C 529 PCShellSetMatApply - Sets routine to use as preconditioner on a block of vectors. 530 531 Logically Collective 532 533 Input Parameters: 534 + pc - the preconditioner context 535 - matapply - the application-provided preconditioning routine 536 537 Calling sequence of `matapply`: 538 + pc - the preconditioner 539 . Xin - input block of vectors represented as a dense `Mat` 540 - Xout - output block of vectors represented as a dense `Mat` 541 542 Level: advanced 543 544 Note: 545 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `matapply`. 546 547 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetContext()`, `PCShellGetContext()` 548 @*/ 549 PetscErrorCode PCShellSetMatApply(PC pc, PetscErrorCode (*matapply)(PC pc, Mat Xin, Mat Xout)) 550 { 551 PetscFunctionBegin; 552 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 553 PetscTryMethod(pc, "PCShellSetMatApply_C", (PC, PetscErrorCode (*)(PC, Mat, Mat)), (pc, matapply)); 554 PetscFunctionReturn(PETSC_SUCCESS); 555 } 556 557 /*@C 558 PCShellSetApplySymmetricLeft - Sets routine to use as left preconditioner (when the `PC_SYMMETRIC` is used). 559 560 Logically Collective 561 562 Input Parameters: 563 + pc - the preconditioner context 564 - apply - the application-provided left preconditioning routine 565 566 Calling sequence of `apply`: 567 + pc - the preconditioner 568 . xin - input vector 569 - xout - output vector 570 571 Level: advanced 572 573 Note: 574 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `apply`. 575 576 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()` 577 @*/ 578 PetscErrorCode PCShellSetApplySymmetricLeft(PC pc, PetscErrorCode (*apply)(PC pc, Vec xin, Vec xout)) 579 { 580 PetscFunctionBegin; 581 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 582 PetscTryMethod(pc, "PCShellSetApplySymmetricLeft_C", (PC, PetscErrorCode (*)(PC, Vec, Vec)), (pc, apply)); 583 PetscFunctionReturn(PETSC_SUCCESS); 584 } 585 586 /*@C 587 PCShellSetApplySymmetricRight - Sets routine to use as right preconditioner (when the `PC_SYMMETRIC` is used). 588 589 Logically Collective 590 591 Input Parameters: 592 + pc - the preconditioner context 593 - apply - the application-provided right preconditioning routine 594 595 Calling sequence of `apply`: 596 + pc - the preconditioner 597 . xin - input vector 598 - xout - output vector 599 600 Level: advanced 601 602 Note: 603 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `apply`. 604 605 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetApplySymmetricLeft()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`, `PCShellGetContext()` 606 @*/ 607 PetscErrorCode PCShellSetApplySymmetricRight(PC pc, PetscErrorCode (*apply)(PC pc, Vec xin, Vec xout)) 608 { 609 PetscFunctionBegin; 610 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 611 PetscTryMethod(pc, "PCShellSetApplySymmetricRight_C", (PC, PetscErrorCode (*)(PC, Vec, Vec)), (pc, apply)); 612 PetscFunctionReturn(PETSC_SUCCESS); 613 } 614 615 /*@C 616 PCShellSetApplyBA - Sets routine to use as the preconditioner times the operator. 617 618 Logically Collective 619 620 Input Parameters: 621 + pc - the preconditioner context 622 - applyBA - the application-provided BA routine 623 624 Calling sequence of `applyBA`: 625 + pc - the preconditioner 626 . side - `PC_LEFT`, `PC_RIGHT`, or `PC_SYMMETRIC` 627 . xin - input vector 628 . xout - output vector 629 - w - work vector 630 631 Level: intermediate 632 633 Note: 634 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `applyBA`. 635 636 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`, `PCShellSetApply()`, `PCShellGetContext()`, `PCSide` 637 @*/ 638 PetscErrorCode PCShellSetApplyBA(PC pc, PetscErrorCode (*applyBA)(PC pc, PCSide side, Vec xin, Vec xout, Vec w)) 639 { 640 PetscFunctionBegin; 641 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 642 PetscTryMethod(pc, "PCShellSetApplyBA_C", (PC, PetscErrorCode (*)(PC, PCSide, Vec, Vec, Vec)), (pc, applyBA)); 643 PetscFunctionReturn(PETSC_SUCCESS); 644 } 645 646 /*@C 647 PCShellSetApplyTranspose - Sets routine to use as preconditioner transpose. 648 649 Logically Collective 650 651 Input Parameters: 652 + pc - the preconditioner context 653 - applytranspose - the application-provided preconditioning transpose routine 654 655 Calling sequence of `applytranspose`: 656 + pc - the preconditioner 657 . xin - input vector 658 - xout - output vector 659 660 Level: intermediate 661 662 Note: 663 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `applytranspose`. 664 665 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApply()`, `PCShellSetContext()`, `PCShellSetApplyBA()`, `PCShellGetContext()` 666 @*/ 667 PetscErrorCode PCShellSetApplyTranspose(PC pc, PetscErrorCode (*applytranspose)(PC pc, Vec xin, Vec xout)) 668 { 669 PetscFunctionBegin; 670 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 671 PetscTryMethod(pc, "PCShellSetApplyTranspose_C", (PC, PetscErrorCode (*)(PC, Vec, Vec)), (pc, applytranspose)); 672 PetscFunctionReturn(PETSC_SUCCESS); 673 } 674 675 /*@C 676 PCShellSetPreSolve - Sets routine to apply to the operators/vectors before a `KSPSolve()` is 677 applied. This usually does something like scale the linear system in some application 678 specific way. 679 680 Logically Collective 681 682 Input Parameters: 683 + pc - the preconditioner context 684 - presolve - the application-provided presolve routine 685 686 Calling sequence of `presolve`: 687 + pc - the preconditioner 688 . ksp - the `KSP` that contains `pc` 689 . xin - input vector 690 - xout - output vector 691 692 Level: advanced 693 694 Note: 695 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `presolve`. 696 697 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetPostSolve()`, `PCShellSetContext()`, `PCShellGetContext()` 698 @*/ 699 PetscErrorCode PCShellSetPreSolve(PC pc, PetscErrorCode (*presolve)(PC pc, KSP ksp, Vec xin, Vec xout)) 700 { 701 PetscFunctionBegin; 702 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 703 PetscTryMethod(pc, "PCShellSetPreSolve_C", (PC, PetscErrorCode (*)(PC, KSP, Vec, Vec)), (pc, presolve)); 704 PetscFunctionReturn(PETSC_SUCCESS); 705 } 706 707 /*@C 708 PCShellSetPostSolve - Sets routine to apply to the operators/vectors after a `KSPSolve()` is 709 applied. This usually does something like scale the linear system in some application 710 specific way. 711 712 Logically Collective 713 714 Input Parameters: 715 + pc - the preconditioner context 716 - postsolve - the application-provided presolve routine 717 718 Calling sequence of `postsolve`: 719 + pc - the preconditioner 720 . ksp - the `KSP` that contains `pc` 721 . xin - input vector 722 - xout - output vector 723 724 Level: advanced 725 726 Note: 727 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `postsolve`. 728 729 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetPreSolve()`, `PCShellSetContext()`, `PCShellGetContext()` 730 @*/ 731 PetscErrorCode PCShellSetPostSolve(PC pc, PetscErrorCode (*postsolve)(PC pc, KSP ksp, Vec xin, Vec xout)) 732 { 733 PetscFunctionBegin; 734 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 735 PetscTryMethod(pc, "PCShellSetPostSolve_C", (PC, PetscErrorCode (*)(PC, KSP, Vec, Vec)), (pc, postsolve)); 736 PetscFunctionReturn(PETSC_SUCCESS); 737 } 738 739 /*@ 740 PCShellSetName - Sets an optional name to associate with a `PCSHELL` 741 preconditioner. 742 743 Not Collective 744 745 Input Parameters: 746 + pc - the preconditioner context 747 - name - character string describing shell preconditioner 748 749 Level: intermediate 750 751 Note: 752 This is separate from the name you can provide with `PetscObjectSetName()` 753 754 .seealso: [](ch_ksp), `PCSHELL`, `PCShellGetName()`, `PetscObjectSetName()`, `PetscObjectGetName()` 755 @*/ 756 PetscErrorCode PCShellSetName(PC pc, const char name[]) 757 { 758 PetscFunctionBegin; 759 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 760 PetscTryMethod(pc, "PCShellSetName_C", (PC, const char[]), (pc, name)); 761 PetscFunctionReturn(PETSC_SUCCESS); 762 } 763 764 /*@ 765 PCShellGetName - Gets an optional name that the user has set for a `PCSHELL` with `PCShellSetName()` 766 preconditioner. 767 768 Not Collective 769 770 Input Parameter: 771 . pc - the preconditioner context 772 773 Output Parameter: 774 . name - character string describing shell preconditioner (you should not free this) 775 776 Level: intermediate 777 778 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetName()`, `PetscObjectSetName()`, `PetscObjectGetName()` 779 @*/ 780 PetscErrorCode PCShellGetName(PC pc, const char *name[]) 781 { 782 PetscFunctionBegin; 783 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 784 PetscAssertPointer(name, 2); 785 PetscUseMethod(pc, "PCShellGetName_C", (PC, const char *[]), (pc, name)); 786 PetscFunctionReturn(PETSC_SUCCESS); 787 } 788 789 /*@C 790 PCShellSetApplyRichardson - Sets routine to use as preconditioner 791 in Richardson iteration. 792 793 Logically Collective 794 795 Input Parameters: 796 + pc - the preconditioner context 797 - apply - the application-provided preconditioning routine 798 799 Calling sequence of `apply`: 800 + pc - the preconditioner 801 . b - right-hand side 802 . x - current iterate 803 . r - work space 804 . rtol - relative tolerance of residual norm to stop at 805 . abstol - absolute tolerance of residual norm to stop at 806 . dtol - if residual norm increases by this factor than return 807 . maxits - number of iterations to run 808 . zeroinitialguess - `PETSC_TRUE` if `x` is known to be initially zero 809 . its - returns the number of iterations used 810 - reason - returns the reason the iteration has converged 811 812 Level: advanced 813 814 Notes: 815 You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `apply`. 816 817 This is used when one can provide code for multiple steps of Richardson's method that is more efficient than computing a single step, 818 recomputing the residual via $ r = b - A x $, and then computing the next step. SOR is an algorithm for which this is true. 819 820 .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetContext()`, `PCRichardsonConvergedReason()`, `PCShellGetContext()`, `KSPRICHARDSON` 821 @*/ 822 PetscErrorCode PCShellSetApplyRichardson(PC pc, PetscErrorCode (*apply)(PC pc, Vec b, Vec x, Vec r, PetscReal rtol, PetscReal abstol, PetscReal dtol, PetscInt maxits, PetscBool zeroinitialguess, PetscInt *its, PCRichardsonConvergedReason *reason)) 823 { 824 PetscFunctionBegin; 825 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 826 PetscTryMethod(pc, "PCShellSetApplyRichardson_C", (PC, PetscErrorCode (*)(PC, Vec, Vec, Vec, PetscReal, PetscReal, PetscReal, PetscInt, PetscBool, PetscInt *, PCRichardsonConvergedReason *)), (pc, apply)); 827 PetscFunctionReturn(PETSC_SUCCESS); 828 } 829 830 /*MC 831 PCSHELL - Creates a new preconditioner class for use with a users 832 own private data storage format and preconditioner application code 833 834 Level: advanced 835 836 Usage: 837 .vb 838 extern PetscErrorCode apply(PC,Vec,Vec); 839 extern PetscErrorCode applyba(PC,PCSide,Vec,Vec,Vec); 840 extern PetscErrorCode applytranspose(PC,Vec,Vec); 841 extern PetscErrorCode setup(PC); 842 extern PetscErrorCode destroy(PC); 843 844 PCCreate(comm,&pc); 845 PCSetType(pc,PCSHELL); 846 PCShellSetContext(pc,ctx) 847 PCShellSetApply(pc,apply); 848 PCShellSetApplyBA(pc,applyba); (optional) 849 PCShellSetApplyTranspose(pc,applytranspose); (optional) 850 PCShellSetSetUp(pc,setup); (optional) 851 PCShellSetDestroy(pc,destroy); (optional) 852 .ve 853 854 Notes: 855 Information required for the preconditioner and its internal datastructures can be set with `PCShellSetContext()` and then accessed 856 with `PCShellGetContext()` inside the routines provided above. 857 858 When using `MATSHELL`, where the explicit entries of matrix are not available to build the preconditioner, `PCSHELL` can be used 859 to construct a custom preconditioner for the `MATSHELL`, assuming the user knows enough about their problem to provide a 860 custom preconditioner. 861 862 .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, 863 `MATSHELL`, `PCShellSetSetUp()`, `PCShellSetApply()`, `PCShellSetView()`, `PCShellSetDestroy()`, `PCShellSetPostSolve()`, 864 `PCShellSetApplyTranspose()`, `PCShellSetName()`, `PCShellSetApplyRichardson()`, `PCShellSetPreSolve()`, `PCShellSetView()`, 865 `PCShellGetName()`, `PCShellSetContext()`, `PCShellGetContext()`, `PCShellSetApplyBA()`, `MATSHELL`, `PCShellSetMatApply()`, 866 M*/ 867 868 PETSC_EXTERN PetscErrorCode PCCreate_Shell(PC pc) 869 { 870 PC_Shell *shell; 871 872 PetscFunctionBegin; 873 PetscCall(PetscNew(&shell)); 874 pc->data = (void *)shell; 875 876 pc->ops->destroy = PCDestroy_Shell; 877 pc->ops->view = PCView_Shell; 878 pc->ops->apply = PCApply_Shell; 879 pc->ops->applysymmetricleft = PCApplySymmetricLeft_Shell; 880 pc->ops->applysymmetricright = PCApplySymmetricRight_Shell; 881 pc->ops->matapply = NULL; 882 pc->ops->applytranspose = NULL; 883 pc->ops->applyrichardson = NULL; 884 pc->ops->setup = NULL; 885 pc->ops->presolve = NULL; 886 pc->ops->postsolve = NULL; 887 888 shell->apply = NULL; 889 shell->applytranspose = NULL; 890 shell->name = NULL; 891 shell->applyrich = NULL; 892 shell->presolve = NULL; 893 shell->postsolve = NULL; 894 shell->ctx = NULL; 895 shell->setup = NULL; 896 shell->view = NULL; 897 shell->destroy = NULL; 898 shell->applysymmetricleft = NULL; 899 shell->applysymmetricright = NULL; 900 901 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetDestroy_C", PCShellSetDestroy_Shell)); 902 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetSetUp_C", PCShellSetSetUp_Shell)); 903 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApply_C", PCShellSetApply_Shell)); 904 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetMatApply_C", PCShellSetMatApply_Shell)); 905 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplySymmetricLeft_C", PCShellSetApplySymmetricLeft_Shell)); 906 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplySymmetricRight_C", PCShellSetApplySymmetricRight_Shell)); 907 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyBA_C", PCShellSetApplyBA_Shell)); 908 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetPreSolve_C", PCShellSetPreSolve_Shell)); 909 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetPostSolve_C", PCShellSetPostSolve_Shell)); 910 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetView_C", PCShellSetView_Shell)); 911 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyTranspose_C", PCShellSetApplyTranspose_Shell)); 912 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetName_C", PCShellSetName_Shell)); 913 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellGetName_C", PCShellGetName_Shell)); 914 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyRichardson_C", PCShellSetApplyRichardson_Shell)); 915 PetscFunctionReturn(PETSC_SUCCESS); 916 } 917