Actual source code: shellpc.c

  1: /*
  2:    This provides a simple shell for Fortran (and C programmers) to
  3:   create their own preconditioner without writing much interface code.
  4: */

  6: #include <petsc/private/pcimpl.h>

  8: typedef struct {
  9:   PetscCtx ctx; /* user provided contexts for preconditioner */

 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 (*matapplytranspose)(PC, Mat, Mat);
 23:   PetscErrorCode (*applyrich)(PC, Vec, Vec, Vec, PetscReal, PetscReal, PetscReal, PetscInt, PetscBool, PetscInt *, PCRichardsonConvergedReason *);

 25:   char *name;
 26: } PC_Shell;

 28: /*@C
 29:   PCShellGetContext - Returns the user-provided context associated with a shell `PC` that was provided with `PCShellSetContext()`

 31:   Not Collective

 33:   Input Parameter:
 34: . pc - of type `PCSHELL`

 36:   Output Parameter:
 37: . ctx - the user provided context

 39:   Level: advanced

 41:   Note:
 42:   This routine is intended for use within the various user-provided routines set with, for example, `PCShellSetApply()`

 44:   Fortran Notes:
 45:   This only works when the context is a Fortran derived type or a `PetscObject`. Define `ctx` with
 46: .vb
 47:   type(tUsertype), pointer :: ctx
 48: .ve

 50: .seealso: [](ch_ksp), `PC`, `PCSHELL`, `PCShellSetContext()`, `PCShellSetApply()`, `PCShellSetDestroy()`
 51: @*/
 52: PetscErrorCode PCShellGetContext(PC pc, PetscCtxRt ctx)
 53: {
 54:   PetscBool flg;

 56:   PetscFunctionBegin;
 58:   PetscAssertPointer(ctx, 2);
 59:   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCSHELL, &flg));
 60:   if (!flg) *(void **)ctx = NULL;
 61:   else *(void **)ctx = ((PC_Shell *)pc->data)->ctx;
 62:   PetscFunctionReturn(PETSC_SUCCESS);
 63: }

 65: /*@
 66:   PCShellSetContext - sets the context for a shell `PC` that can be accessed with `PCShellGetContext()`

 68:   Logically Collective

 70:   Input Parameters:
 71: + pc  - the `PC` of type `PCSHELL`
 72: - ctx - the context

 74:   Level: advanced

 76:   Notes:
 77:   This routine is intended for use within the various user-provided routines set with, for example, `PCShellSetApply()`

 79:   One should also provide a routine to destroy the context when `pc` is destroyed with `PCShellSetDestroy()`

 81:   Fortran Notes:
 82:   To use this from Fortran you must write a Fortran interface definition for this
 83:   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.

 85: .seealso: [](ch_ksp), `PC`, `PCShellGetContext()`, `PCSHELL`, `PCShellSetApply()`, `PCShellSetDestroy()`
 86: @*/
 87: PetscErrorCode PCShellSetContext(PC pc, PetscCtx ctx)
 88: {
 89:   PC_Shell *shell = (PC_Shell *)pc->data;
 90:   PetscBool flg;

 92:   PetscFunctionBegin;
 94:   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCSHELL, &flg));
 95:   if (flg) shell->ctx = ctx;
 96:   PetscFunctionReturn(PETSC_SUCCESS);
 97: }

 99: static PetscErrorCode PCSetUp_Shell(PC pc)
100: {
101:   PC_Shell *shell = (PC_Shell *)pc->data;

103:   PetscFunctionBegin;
104:   PetscCheck(shell->setup, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No setup() routine provided to Shell PC");
105:   PetscCallBack("PCSHELL callback setup", (*shell->setup)(pc));
106:   PetscFunctionReturn(PETSC_SUCCESS);
107: }

109: static PetscErrorCode PCApply_Shell(PC pc, Vec x, Vec y)
110: {
111:   PC_Shell        *shell = (PC_Shell *)pc->data;
112:   PetscObjectState instate, outstate;

114:   PetscFunctionBegin;
115:   PetscCheck(shell->apply, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No apply() routine provided to Shell PC");
116:   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
117:   PetscCallBack("PCSHELL callback apply", (*shell->apply)(pc, x, y));
118:   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
119:   /* increase the state of the output vector if the user did not update its state themself as should have been done */
120:   if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)y));
121:   PetscFunctionReturn(PETSC_SUCCESS);
122: }

124: static PetscErrorCode PCMatApply_Shell(PC pc, Mat X, Mat Y)
125: {
126:   PC_Shell        *shell = (PC_Shell *)pc->data;
127:   PetscObjectState instate, outstate;

129:   PetscFunctionBegin;
130:   PetscCheck(shell->matapply, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No apply() routine provided to Shell PC");
131:   PetscCall(PetscObjectStateGet((PetscObject)Y, &instate));
132:   PetscCallBack("PCSHELL callback apply", (*shell->matapply)(pc, X, Y));
133:   PetscCall(PetscObjectStateGet((PetscObject)Y, &outstate));
134:   /* increase the state of the output vector if the user did not update its state themself as should have been done */
135:   if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)Y));
136:   PetscFunctionReturn(PETSC_SUCCESS);
137: }

139: static PetscErrorCode PCApplySymmetricLeft_Shell(PC pc, Vec x, Vec y)
140: {
141:   PC_Shell *shell = (PC_Shell *)pc->data;

143:   PetscFunctionBegin;
144:   PetscCheck(shell->applysymmetricleft, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No apply() routine provided to Shell PC");
145:   PetscCallBack("PCSHELL callback apply symmetric left", (*shell->applysymmetricleft)(pc, x, y));
146:   PetscFunctionReturn(PETSC_SUCCESS);
147: }

149: static PetscErrorCode PCApplySymmetricRight_Shell(PC pc, Vec x, Vec y)
150: {
151:   PC_Shell *shell = (PC_Shell *)pc->data;

153:   PetscFunctionBegin;
154:   PetscCheck(shell->applysymmetricright, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No apply() routine provided to Shell PC");
155:   PetscCallBack("PCSHELL callback apply symmetric right", (*shell->applysymmetricright)(pc, x, y));
156:   PetscFunctionReturn(PETSC_SUCCESS);
157: }

159: static PetscErrorCode PCApplyBA_Shell(PC pc, PCSide side, Vec x, Vec y, Vec w)
160: {
161:   PC_Shell        *shell = (PC_Shell *)pc->data;
162:   PetscObjectState instate, outstate;

164:   PetscFunctionBegin;
165:   PetscCheck(shell->applyBA, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No applyBA() routine provided to Shell PC");
166:   PetscCall(PetscObjectStateGet((PetscObject)w, &instate));
167:   PetscCallBack("PCSHELL callback applyBA", (*shell->applyBA)(pc, side, x, y, w));
168:   PetscCall(PetscObjectStateGet((PetscObject)w, &outstate));
169:   /* increase the state of the output vector if the user did not update its state themself as should have been done */
170:   if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)w));
171:   PetscFunctionReturn(PETSC_SUCCESS);
172: }

174: static PetscErrorCode PCPreSolveChangeRHS_Shell(PC pc, PetscBool *change)
175: {
176:   PetscFunctionBegin;
177:   *change = PETSC_TRUE;
178:   PetscFunctionReturn(PETSC_SUCCESS);
179: }

181: static PetscErrorCode PCPreSolve_Shell(PC pc, KSP ksp, Vec b, Vec x)
182: {
183:   PC_Shell *shell = (PC_Shell *)pc->data;

185:   PetscFunctionBegin;
186:   PetscCheck(shell->presolve, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No presolve() routine provided to Shell PC");
187:   PetscCallBack("PCSHELL callback presolve", (*shell->presolve)(pc, ksp, b, x));
188:   PetscFunctionReturn(PETSC_SUCCESS);
189: }

191: static PetscErrorCode PCPostSolve_Shell(PC pc, KSP ksp, Vec b, Vec x)
192: {
193:   PC_Shell *shell = (PC_Shell *)pc->data;

195:   PetscFunctionBegin;
196:   PetscCheck(shell->postsolve, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No postsolve() routine provided to Shell PC");
197:   PetscCallBack("PCSHELL callback postsolve()", (*shell->postsolve)(pc, ksp, b, x));
198:   PetscFunctionReturn(PETSC_SUCCESS);
199: }

201: static PetscErrorCode PCApplyTranspose_Shell(PC pc, Vec x, Vec y)
202: {
203:   PC_Shell        *shell = (PC_Shell *)pc->data;
204:   PetscObjectState instate, outstate;

206:   PetscFunctionBegin;
207:   PetscCheck(shell->applytranspose, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No applytranspose() routine provided to Shell PC");
208:   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
209:   PetscCallBack("PCSHELL callback applytranspose", (*shell->applytranspose)(pc, x, y));
210:   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
211:   /* increase the state of the output vector if the user did not update its state themself as should have been done */
212:   if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)y));
213:   PetscFunctionReturn(PETSC_SUCCESS);
214: }

216: static PetscErrorCode PCMatApplyTranspose_Shell(PC pc, Mat x, Mat y)
217: {
218:   PC_Shell        *shell = (PC_Shell *)pc->data;
219:   PetscObjectState instate, outstate;

221:   PetscFunctionBegin;
222:   PetscCheck(shell->matapplytranspose, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No matapplytranspose() routine provided to Shell PC");
223:   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
224:   PetscCallBack("PCSHELL callback matapplytranspose", (*shell->matapplytranspose)(pc, x, y));
225:   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
226:   /* increase the state of the output matrix if the user did not update its state themself as should have been done */
227:   if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)y));
228:   PetscFunctionReturn(PETSC_SUCCESS);
229: }

231: 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)
232: {
233:   PC_Shell        *shell = (PC_Shell *)pc->data;
234:   PetscObjectState instate, outstate;

236:   PetscFunctionBegin;
237:   PetscCheck(shell->applyrich, PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "No applyrichardson() routine provided to Shell PC");
238:   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
239:   PetscCallBack("PCSHELL callback applyrichardson", (*shell->applyrich)(pc, x, y, w, rtol, abstol, dtol, it, guesszero, outits, reason));
240:   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
241:   /* increase the state of the output vector since the user did not update its state themself as should have been done */
242:   if (instate == outstate) PetscCall(PetscObjectStateIncrease((PetscObject)y));
243:   PetscFunctionReturn(PETSC_SUCCESS);
244: }

246: static PetscErrorCode PCDestroy_Shell(PC pc)
247: {
248:   PC_Shell *shell = (PC_Shell *)pc->data;

250:   PetscFunctionBegin;
251:   PetscCall(PetscFree(shell->name));
252:   if (shell->destroy) PetscCallBack("PCSHELL callback destroy", (*shell->destroy)(pc));
253:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetDestroy_C", NULL));
254:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetSetUp_C", NULL));
255:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApply_C", NULL));
256:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetMatApply_C", NULL));
257:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplySymmetricLeft_C", NULL));
258:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplySymmetricRight_C", NULL));
259:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyBA_C", NULL));
260:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetPreSolve_C", NULL));
261:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetPostSolve_C", NULL));
262:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetView_C", NULL));
263:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyTranspose_C", NULL));
264:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetMatApplyTranspose_C", NULL));
265:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetName_C", NULL));
266:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellGetName_C", NULL));
267:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyRichardson_C", NULL));
268:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", NULL));
269:   PetscCall(PetscFree(pc->data));
270:   PetscFunctionReturn(PETSC_SUCCESS);
271: }

273: static PetscErrorCode PCView_Shell(PC pc, PetscViewer viewer)
274: {
275:   PC_Shell *shell = (PC_Shell *)pc->data;
276:   PetscBool isascii;

278:   PetscFunctionBegin;
279:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
280:   if (isascii) {
281:     if (shell->name) PetscCall(PetscViewerASCIIPrintf(viewer, "  %s\n", shell->name));
282:     else PetscCall(PetscViewerASCIIPrintf(viewer, "  no name\n"));
283:   }
284:   if (shell->view) {
285:     PetscCall(PetscViewerASCIIPushTab(viewer));
286:     PetscCall((*shell->view)(pc, viewer));
287:     PetscCall(PetscViewerASCIIPopTab(viewer));
288:   }
289:   PetscFunctionReturn(PETSC_SUCCESS);
290: }

292: static PetscErrorCode PCShellSetDestroy_Shell(PC pc, PetscErrorCode (*destroy)(PC))
293: {
294:   PC_Shell *shell = (PC_Shell *)pc->data;

296:   PetscFunctionBegin;
297:   shell->destroy = destroy;
298:   PetscFunctionReturn(PETSC_SUCCESS);
299: }

301: static PetscErrorCode PCShellSetSetUp_Shell(PC pc, PetscErrorCode (*setup)(PC))
302: {
303:   PC_Shell *shell = (PC_Shell *)pc->data;

305:   PetscFunctionBegin;
306:   shell->setup = setup;
307:   if (setup) pc->ops->setup = PCSetUp_Shell;
308:   else pc->ops->setup = NULL;
309:   PetscFunctionReturn(PETSC_SUCCESS);
310: }

312: static PetscErrorCode PCShellSetApply_Shell(PC pc, PetscErrorCode (*apply)(PC, Vec, Vec))
313: {
314:   PC_Shell *shell = (PC_Shell *)pc->data;

316:   PetscFunctionBegin;
317:   shell->apply = apply;
318:   PetscFunctionReturn(PETSC_SUCCESS);
319: }

321: static PetscErrorCode PCShellSetMatApply_Shell(PC pc, PetscErrorCode (*matapply)(PC, Mat, Mat))
322: {
323:   PC_Shell *shell = (PC_Shell *)pc->data;

325:   PetscFunctionBegin;
326:   shell->matapply = matapply;
327:   if (matapply) pc->ops->matapply = PCMatApply_Shell;
328:   else pc->ops->matapply = NULL;
329:   PetscFunctionReturn(PETSC_SUCCESS);
330: }

332: static PetscErrorCode PCShellSetApplySymmetricLeft_Shell(PC pc, PetscErrorCode (*apply)(PC, Vec, Vec))
333: {
334:   PC_Shell *shell = (PC_Shell *)pc->data;

336:   PetscFunctionBegin;
337:   shell->applysymmetricleft = apply;
338:   PetscFunctionReturn(PETSC_SUCCESS);
339: }

341: static PetscErrorCode PCShellSetApplySymmetricRight_Shell(PC pc, PetscErrorCode (*apply)(PC, Vec, Vec))
342: {
343:   PC_Shell *shell = (PC_Shell *)pc->data;

345:   PetscFunctionBegin;
346:   shell->applysymmetricright = apply;
347:   PetscFunctionReturn(PETSC_SUCCESS);
348: }

350: static PetscErrorCode PCShellSetApplyBA_Shell(PC pc, PetscErrorCode (*applyBA)(PC, PCSide, Vec, Vec, Vec))
351: {
352:   PC_Shell *shell = (PC_Shell *)pc->data;

354:   PetscFunctionBegin;
355:   shell->applyBA = applyBA;
356:   if (applyBA) pc->ops->applyBA = PCApplyBA_Shell;
357:   else pc->ops->applyBA = NULL;
358:   PetscFunctionReturn(PETSC_SUCCESS);
359: }

361: static PetscErrorCode PCShellSetPreSolve_Shell(PC pc, PCShellPSolveFn *presolve)
362: {
363:   PC_Shell *shell = (PC_Shell *)pc->data;

365:   PetscFunctionBegin;
366:   shell->presolve = presolve;
367:   if (presolve) {
368:     pc->ops->presolve = PCPreSolve_Shell;
369:     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", PCPreSolveChangeRHS_Shell));
370:   } else {
371:     pc->ops->presolve = NULL;
372:     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", NULL));
373:   }
374:   PetscFunctionReturn(PETSC_SUCCESS);
375: }

377: static PetscErrorCode PCShellSetPostSolve_Shell(PC pc, PCShellPSolveFn *postsolve)
378: {
379:   PC_Shell *shell = (PC_Shell *)pc->data;

381:   PetscFunctionBegin;
382:   shell->postsolve = postsolve;
383:   if (postsolve) pc->ops->postsolve = PCPostSolve_Shell;
384:   else pc->ops->postsolve = NULL;
385:   PetscFunctionReturn(PETSC_SUCCESS);
386: }

388: static PetscErrorCode PCShellSetView_Shell(PC pc, PetscErrorCode (*view)(PC, PetscViewer))
389: {
390:   PC_Shell *shell = (PC_Shell *)pc->data;

392:   PetscFunctionBegin;
393:   shell->view = view;
394:   PetscFunctionReturn(PETSC_SUCCESS);
395: }

397: static PetscErrorCode PCShellSetApplyTranspose_Shell(PC pc, PetscErrorCode (*applytranspose)(PC, Vec, Vec))
398: {
399:   PC_Shell *shell = (PC_Shell *)pc->data;

401:   PetscFunctionBegin;
402:   shell->applytranspose = applytranspose;
403:   if (applytranspose) pc->ops->applytranspose = PCApplyTranspose_Shell;
404:   else pc->ops->applytranspose = NULL;
405:   PetscFunctionReturn(PETSC_SUCCESS);
406: }

408: static PetscErrorCode PCShellSetMatApplyTranspose_Shell(PC pc, PetscErrorCode (*matapplytranspose)(PC, Mat, Mat))
409: {
410:   PC_Shell *shell = (PC_Shell *)pc->data;

412:   PetscFunctionBegin;
413:   shell->matapplytranspose = matapplytranspose;
414:   if (matapplytranspose) pc->ops->matapplytranspose = PCMatApplyTranspose_Shell;
415:   else pc->ops->matapplytranspose = NULL;
416:   PetscFunctionReturn(PETSC_SUCCESS);
417: }

419: static PetscErrorCode PCShellSetApplyRichardson_Shell(PC pc, PetscErrorCode (*applyrich)(PC, Vec, Vec, Vec, PetscReal, PetscReal, PetscReal, PetscInt, PetscBool, PetscInt *, PCRichardsonConvergedReason *))
420: {
421:   PC_Shell *shell = (PC_Shell *)pc->data;

423:   PetscFunctionBegin;
424:   shell->applyrich = applyrich;
425:   if (applyrich) pc->ops->applyrichardson = PCApplyRichardson_Shell;
426:   else pc->ops->applyrichardson = NULL;
427:   PetscFunctionReturn(PETSC_SUCCESS);
428: }

430: static PetscErrorCode PCShellSetName_Shell(PC pc, const char name[])
431: {
432:   PC_Shell *shell = (PC_Shell *)pc->data;

434:   PetscFunctionBegin;
435:   PetscCall(PetscFree(shell->name));
436:   PetscCall(PetscStrallocpy(name, &shell->name));
437:   PetscFunctionReturn(PETSC_SUCCESS);
438: }

440: static PetscErrorCode PCShellGetName_Shell(PC pc, const char *name[])
441: {
442:   PC_Shell *shell = (PC_Shell *)pc->data;

444:   PetscFunctionBegin;
445:   *name = shell->name;
446:   PetscFunctionReturn(PETSC_SUCCESS);
447: }

449: /*@C
450:   PCShellSetDestroy - Sets routine to use to destroy the user-provided application context that was provided with `PCShellSetContext()`

452:   Logically Collective

454:   Input Parameters:
455: + pc      - the preconditioner context
456: - destroy - the application-provided destroy routine

458:   Calling sequence of `destroy`:
459: . pc - the preconditioner

461:   Level: intermediate

463: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetContext()`, `PCShellGetContext()`
464: @*/
465: PetscErrorCode PCShellSetDestroy(PC pc, PetscErrorCode (*destroy)(PC pc))
466: {
467:   PetscFunctionBegin;
469:   PetscTryMethod(pc, "PCShellSetDestroy_C", (PC, PetscErrorCode (*)(PC)), (pc, destroy));
470:   PetscFunctionReturn(PETSC_SUCCESS);
471: }

473: /*@C
474:   PCShellSetSetUp - Sets routine to use to "setup" the preconditioner whenever the
475:   matrix operator is changed.

477:   Logically Collective

479:   Input Parameters:
480: + pc    - the preconditioner context
481: - setup - the application-provided setup routine

483:   Calling sequence of `setup`:
484: . pc - the preconditioner

486:   Level: intermediate

488:   Note:
489:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `setup`.

491: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetApply()`, `PCShellSetContext()`, , `PCShellGetContext()`
492: @*/
493: PetscErrorCode PCShellSetSetUp(PC pc, PetscErrorCode (*setup)(PC pc))
494: {
495:   PetscFunctionBegin;
497:   PetscTryMethod(pc, "PCShellSetSetUp_C", (PC, PetscErrorCode (*)(PC)), (pc, setup));
498:   PetscFunctionReturn(PETSC_SUCCESS);
499: }

501: /*@C
502:   PCShellSetView - Sets routine to use as viewer of a `PCSHELL` shell preconditioner

504:   Logically Collective

506:   Input Parameters:
507: + pc   - the preconditioner context
508: - view - the application-provided view routine

510:   Calling sequence of `view`:
511: + pc - the preconditioner
512: - v  - viewer

514:   Level: advanced

516:   Note:
517:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `view`.

519: .seealso: [](ch_ksp), `PC`, `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`, `PCShellGetContext()`
520: @*/
521: PetscErrorCode PCShellSetView(PC pc, PetscErrorCode (*view)(PC pc, PetscViewer v))
522: {
523:   PetscFunctionBegin;
525:   PetscTryMethod(pc, "PCShellSetView_C", (PC, PetscErrorCode (*)(PC, PetscViewer)), (pc, view));
526:   PetscFunctionReturn(PETSC_SUCCESS);
527: }

529: /*@C
530:   PCShellSetApply - Sets routine to use as preconditioner.

532:   Logically Collective

534:   Input Parameters:
535: + pc    - the preconditioner context
536: - apply - the application-provided preconditioning routine

538:   Calling sequence of `apply`:
539: + pc   - the preconditioner, get the application context with `PCShellGetContext()`
540: . xin  - input vector
541: - xout - output vector

543:   Level: intermediate

545:   Note:
546:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `apply`.

548: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`, `PCShellSetApplyBA()`, `PCShellSetApplySymmetricRight()`, `PCShellSetApplySymmetricLeft()`, `PCShellGetContext()`
549: @*/
550: PetscErrorCode PCShellSetApply(PC pc, PetscErrorCode (*apply)(PC pc, Vec xin, Vec xout))
551: {
552:   PetscFunctionBegin;
554:   PetscTryMethod(pc, "PCShellSetApply_C", (PC, PetscErrorCode (*)(PC, Vec, Vec)), (pc, apply));
555:   PetscFunctionReturn(PETSC_SUCCESS);
556: }

558: /*@C
559:   PCShellSetMatApply - Sets routine to use as preconditioner on a block of vectors.

561:   Logically Collective

563:   Input Parameters:
564: + pc       - the preconditioner context
565: - matapply - the application-provided preconditioning routine

567:   Calling sequence of `matapply`:
568: + pc   - the preconditioner
569: . Xin  - input block of vectors represented as a dense `Mat`
570: - Xout - output block of vectors represented as a dense `Mat`

572:   Level: advanced

574:   Note:
575:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `matapply`.

577: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetContext()`, `PCShellGetContext()`
578: @*/
579: PetscErrorCode PCShellSetMatApply(PC pc, PetscErrorCode (*matapply)(PC pc, Mat Xin, Mat Xout))
580: {
581:   PetscFunctionBegin;
583:   PetscTryMethod(pc, "PCShellSetMatApply_C", (PC, PetscErrorCode (*)(PC, Mat, Mat)), (pc, matapply));
584:   PetscFunctionReturn(PETSC_SUCCESS);
585: }

587: /*@C
588:   PCShellSetApplySymmetricLeft - Sets routine to use as left preconditioner (when the `PC_SYMMETRIC` is used).

590:   Logically Collective

592:   Input Parameters:
593: + pc    - the preconditioner context
594: - apply - the application-provided left preconditioning routine

596:   Calling sequence of `apply`:
597: + pc   - the preconditioner
598: . xin  - input vector
599: - xout - output vector

601:   Level: advanced

603:   Note:
604:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `apply`.

606: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`
607: @*/
608: PetscErrorCode PCShellSetApplySymmetricLeft(PC pc, PetscErrorCode (*apply)(PC pc, Vec xin, Vec xout))
609: {
610:   PetscFunctionBegin;
612:   PetscTryMethod(pc, "PCShellSetApplySymmetricLeft_C", (PC, PetscErrorCode (*)(PC, Vec, Vec)), (pc, apply));
613:   PetscFunctionReturn(PETSC_SUCCESS);
614: }

616: /*@C
617:   PCShellSetApplySymmetricRight - Sets routine to use as right preconditioner (when the `PC_SYMMETRIC` is used).

619:   Logically Collective

621:   Input Parameters:
622: + pc    - the preconditioner context
623: - apply - the application-provided right preconditioning routine

625:   Calling sequence of `apply`:
626: + pc   - the preconditioner
627: . xin  - input vector
628: - xout - output vector

630:   Level: advanced

632:   Note:
633:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `apply`.

635: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetApplySymmetricLeft()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`, `PCShellGetContext()`
636: @*/
637: PetscErrorCode PCShellSetApplySymmetricRight(PC pc, PetscErrorCode (*apply)(PC pc, Vec xin, Vec xout))
638: {
639:   PetscFunctionBegin;
641:   PetscTryMethod(pc, "PCShellSetApplySymmetricRight_C", (PC, PetscErrorCode (*)(PC, Vec, Vec)), (pc, apply));
642:   PetscFunctionReturn(PETSC_SUCCESS);
643: }

645: /*@C
646:   PCShellSetApplyBA - Sets routine to use as the preconditioner times the operator.

648:   Logically Collective

650:   Input Parameters:
651: + pc      - the preconditioner context
652: - applyBA - the application-provided BA routine

654:   Calling sequence of `applyBA`:
655: + pc   - the preconditioner
656: . side - `PC_LEFT`, `PC_RIGHT`, or `PC_SYMMETRIC`
657: . xin  - input vector
658: . xout - output vector
659: - w    - work vector

661:   Level: intermediate

663:   Note:
664:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `applyBA`.

666: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetContext()`, `PCShellSetApply()`, `PCShellGetContext()`, `PCSide`
667: @*/
668: PetscErrorCode PCShellSetApplyBA(PC pc, PetscErrorCode (*applyBA)(PC pc, PCSide side, Vec xin, Vec xout, Vec w))
669: {
670:   PetscFunctionBegin;
672:   PetscTryMethod(pc, "PCShellSetApplyBA_C", (PC, PetscErrorCode (*)(PC, PCSide, Vec, Vec, Vec)), (pc, applyBA));
673:   PetscFunctionReturn(PETSC_SUCCESS);
674: }

676: /*@C
677:   PCShellSetApplyTranspose - Sets routine to use as preconditioner transpose.

679:   Logically Collective

681:   Input Parameters:
682: + pc             - the preconditioner context
683: - applytranspose - the application-provided preconditioning transpose routine

685:   Calling sequence of `applytranspose`:
686: + pc   - the preconditioner
687: . xin  - input vector
688: - xout - output vector

690:   Level: intermediate

692:   Note:
693:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `applytranspose`.

695: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApply()`, `PCShellSetContext()`, `PCShellSetApplyBA()`, `PCShellGetContext()`
696: @*/
697: PetscErrorCode PCShellSetApplyTranspose(PC pc, PetscErrorCode (*applytranspose)(PC pc, Vec xin, Vec xout))
698: {
699:   PetscFunctionBegin;
701:   PetscTryMethod(pc, "PCShellSetApplyTranspose_C", (PC, PetscErrorCode (*)(PC, Vec, Vec)), (pc, applytranspose));
702:   PetscFunctionReturn(PETSC_SUCCESS);
703: }

705: /*@C
706:   PCShellSetMatApplyTranspose - Sets routine to use as preconditioner transpose.

708:   Logically Collective

710:   Input Parameters:
711: + pc                - the preconditioner context
712: - matapplytranspose - the application-provided preconditioning transpose routine

714:   Calling sequence of `matapplytranspose`:
715: + pc   - the preconditioner
716: . xin  - input matrix
717: - xout - output matrix

719:   Level: intermediate

721:   Note:
722:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `matapplytranspose`.

724: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApply()`, `PCShellSetContext()`, `PCShellSetApplyBA()`, `PCShellGetContext()`
725: @*/
726: PetscErrorCode PCShellSetMatApplyTranspose(PC pc, PetscErrorCode (*matapplytranspose)(PC pc, Mat xin, Mat xout))
727: {
728:   PetscFunctionBegin;
730:   PetscTryMethod(pc, "PCShellSetMatApplyTranspose_C", (PC, PetscErrorCode (*)(PC, Mat, Mat)), (pc, matapplytranspose));
731:   PetscFunctionReturn(PETSC_SUCCESS);
732: }

734: /*@C
735:   PCShellSetPreSolve - Sets routine to apply to the operators/vectors before a `KSPSolve()` is
736:   applied. This usually does something like scale the linear system in some application
737:   specific way.

739:   Logically Collective

741:   Input Parameters:
742: + pc       - the preconditioner context
743: - presolve - the application-provided presolve routine, see `PCShellPSolveFn`

745:   Level: advanced

747:   Note:
748:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `presolve`.

750: .seealso: [](ch_ksp), `PCSHELL`, `PCShellPSolveFn`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetPostSolve()`, `PCShellSetContext()`, `PCShellGetContext()`
751: @*/
752: PetscErrorCode PCShellSetPreSolve(PC pc, PCShellPSolveFn *presolve)
753: {
754:   PetscFunctionBegin;
756:   PetscTryMethod(pc, "PCShellSetPreSolve_C", (PC, PCShellPSolveFn *), (pc, presolve));
757:   PetscFunctionReturn(PETSC_SUCCESS);
758: }

760: /*@C
761:   PCShellSetPostSolve - Sets routine to apply to the operators/vectors after a `KSPSolve()` is
762:   applied. This usually does something like scale the linear system in some application
763:   specific way.

765:   Logically Collective

767:   Input Parameters:
768: + pc        - the preconditioner context
769: - postsolve - the application-provided postsolve routine, see `PCShellPSolveFn`

771:   Level: advanced

773:   Note:
774:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `postsolve`.

776: .seealso: [](ch_ksp), `PCSHELL`, `PCShellPSolveFn`, `PCShellSetApplyRichardson()`, `PCShellSetSetUp()`, `PCShellSetApplyTranspose()`, `PCShellSetPreSolve()`, `PCShellSetContext()`, `PCShellGetContext()`
777: @*/
778: PetscErrorCode PCShellSetPostSolve(PC pc, PCShellPSolveFn *postsolve)
779: {
780:   PetscFunctionBegin;
782:   PetscTryMethod(pc, "PCShellSetPostSolve_C", (PC, PCShellPSolveFn *), (pc, postsolve));
783:   PetscFunctionReturn(PETSC_SUCCESS);
784: }

786: /*@
787:   PCShellSetName - Sets an optional name to associate with a `PCSHELL`
788:   preconditioner.

790:   Not Collective

792:   Input Parameters:
793: + pc   - the preconditioner context
794: - name - character string describing shell preconditioner

796:   Level: intermediate

798:   Note:
799:   This is separate from the name you can provide with `PetscObjectSetName()`

801: .seealso: [](ch_ksp), `PCSHELL`, `PCShellGetName()`, `PetscObjectSetName()`, `PetscObjectGetName()`
802: @*/
803: PetscErrorCode PCShellSetName(PC pc, const char name[])
804: {
805:   PetscFunctionBegin;
807:   PetscTryMethod(pc, "PCShellSetName_C", (PC, const char[]), (pc, name));
808:   PetscFunctionReturn(PETSC_SUCCESS);
809: }

811: /*@
812:   PCShellGetName - Gets an optional name that the user has set for a `PCSHELL` with `PCShellSetName()`
813:   preconditioner.

815:   Not Collective

817:   Input Parameter:
818: . pc - the preconditioner context

820:   Output Parameter:
821: . name - character string describing shell preconditioner (you should not free this)

823:   Level: intermediate

825: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetName()`, `PetscObjectSetName()`, `PetscObjectGetName()`
826: @*/
827: PetscErrorCode PCShellGetName(PC pc, const char *name[])
828: {
829:   PetscFunctionBegin;
831:   PetscAssertPointer(name, 2);
832:   PetscUseMethod(pc, "PCShellGetName_C", (PC, const char *[]), (pc, name));
833:   PetscFunctionReturn(PETSC_SUCCESS);
834: }

836: /*@C
837:   PCShellSetApplyRichardson - Sets routine to use as preconditioner
838:   in Richardson iteration.

840:   Logically Collective

842:   Input Parameters:
843: + pc    - the preconditioner context
844: - apply - the application-provided preconditioning routine

846:   Calling sequence of `apply`:
847: + pc               - the preconditioner
848: . b                - right-hand side
849: . x                - current iterate
850: . r                - work space
851: . rtol             - relative tolerance of residual norm to stop at
852: . abstol           - absolute tolerance of residual norm to stop at
853: . dtol             - if residual norm increases by this factor than return
854: . maxits           - number of iterations to run
855: . zeroinitialguess - `PETSC_TRUE` if `x` is known to be initially zero
856: . its              - returns the number of iterations used
857: - reason           - returns the reason the iteration has converged

859:   Level: advanced

861:   Notes:
862:   You can get the `PCSHELL` context set with `PCShellSetContext()` using `PCShellGetContext()` if needed by `apply`.

864:   This is used when one can provide code for multiple steps of Richardson's method that is more efficient than computing a single step,
865:   recomputing the residual via $ r = b - A x $, and then computing the next step. SOR is an algorithm for which this is true.

867: .seealso: [](ch_ksp), `PCSHELL`, `PCShellSetApply()`, `PCShellSetContext()`, `PCRichardsonConvergedReason()`, `PCShellGetContext()`, `KSPRICHARDSON`
868: @*/
869: 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))
870: {
871:   PetscFunctionBegin;
873:   PetscTryMethod(pc, "PCShellSetApplyRichardson_C", (PC, PetscErrorCode (*)(PC, Vec, Vec, Vec, PetscReal, PetscReal, PetscReal, PetscInt, PetscBool, PetscInt *, PCRichardsonConvergedReason *)), (pc, apply));
874:   PetscFunctionReturn(PETSC_SUCCESS);
875: }

877: /*MC
878:   PCSHELL - Creates a new preconditioner class for use with a users
879:             own private data storage format and preconditioner application code

881:   Level: advanced

883:   Usage:
884: .vb
885:   extern PetscErrorCode apply(PC,Vec,Vec);
886:   extern PetscErrorCode applyba(PC,PCSide,Vec,Vec,Vec);
887:   extern PetscErrorCode applytranspose(PC,Vec,Vec);
888:   extern PetscErrorCode setup(PC);
889:   extern PetscErrorCode destroy(PC);

891:   PCCreate(comm,&pc);
892:   PCSetType(pc,PCSHELL);
893:   PCShellSetContext(pc,ctx)
894:   PCShellSetApply(pc,apply);
895:   PCShellSetApplyBA(pc,applyba);               (optional)
896:   PCShellSetApplyTranspose(pc,applytranspose); (optional)
897:   PCShellSetSetUp(pc,setup);                   (optional)
898:   PCShellSetDestroy(pc,destroy);               (optional)
899: .ve

901:   Notes:
902:   Information required for the preconditioner and its internal datastructures can be set with `PCShellSetContext()` and then accessed
903:   with `PCShellGetContext()` inside the routines provided above.

905:   When using `MATSHELL`, where the explicit entries of matrix are not available to build the preconditioner, `PCSHELL` can be used
906:   to construct a custom preconditioner for the `MATSHELL`, assuming the user knows enough about their problem to provide a
907:   custom preconditioner.

909: .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
910:           `MATSHELL`, `PCShellSetSetUp()`, `PCShellSetApply()`, `PCShellSetView()`, `PCShellSetDestroy()`, `PCShellSetPostSolve()`,
911:           `PCShellSetApplyTranspose()`, `PCShellSetName()`, `PCShellSetApplyRichardson()`, `PCShellSetPreSolve()`, `PCShellSetView()`,
912:           `PCShellGetName()`, `PCShellSetContext()`, `PCShellGetContext()`, `PCShellSetApplyBA()`, `MATSHELL`, `PCShellSetMatApply()`,
913: M*/

915: PETSC_EXTERN PetscErrorCode PCCreate_Shell(PC pc)
916: {
917:   PC_Shell *shell;

919:   PetscFunctionBegin;
920:   PetscCall(PetscNew(&shell));
921:   pc->data = (void *)shell;

923:   pc->ops->destroy             = PCDestroy_Shell;
924:   pc->ops->view                = PCView_Shell;
925:   pc->ops->apply               = PCApply_Shell;
926:   pc->ops->applysymmetricleft  = PCApplySymmetricLeft_Shell;
927:   pc->ops->applysymmetricright = PCApplySymmetricRight_Shell;
928:   pc->ops->matapply            = NULL;
929:   pc->ops->applytranspose      = NULL;
930:   pc->ops->applyrichardson     = NULL;
931:   pc->ops->setup               = NULL;
932:   pc->ops->presolve            = NULL;
933:   pc->ops->postsolve           = NULL;

935:   shell->apply               = NULL;
936:   shell->applytranspose      = NULL;
937:   shell->name                = NULL;
938:   shell->applyrich           = NULL;
939:   shell->presolve            = NULL;
940:   shell->postsolve           = NULL;
941:   shell->ctx                 = NULL;
942:   shell->setup               = NULL;
943:   shell->view                = NULL;
944:   shell->destroy             = NULL;
945:   shell->applysymmetricleft  = NULL;
946:   shell->applysymmetricright = NULL;

948:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetDestroy_C", PCShellSetDestroy_Shell));
949:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetSetUp_C", PCShellSetSetUp_Shell));
950:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApply_C", PCShellSetApply_Shell));
951:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetMatApply_C", PCShellSetMatApply_Shell));
952:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplySymmetricLeft_C", PCShellSetApplySymmetricLeft_Shell));
953:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplySymmetricRight_C", PCShellSetApplySymmetricRight_Shell));
954:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyBA_C", PCShellSetApplyBA_Shell));
955:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetPreSolve_C", PCShellSetPreSolve_Shell));
956:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetPostSolve_C", PCShellSetPostSolve_Shell));
957:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetView_C", PCShellSetView_Shell));
958:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyTranspose_C", PCShellSetApplyTranspose_Shell));
959:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetMatApplyTranspose_C", PCShellSetMatApplyTranspose_Shell));
960:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetName_C", PCShellSetName_Shell));
961:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellGetName_C", PCShellGetName_Shell));
962:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCShellSetApplyRichardson_C", PCShellSetApplyRichardson_Shell));
963:   PetscFunctionReturn(PETSC_SUCCESS);
964: }