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:   void *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 Note:
 45:   To use this from Fortran you must write a Fortran interface definition for this
 46:   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.

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

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

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

 66:   Logically Collective

 68:   Input Parameters:
 69: + pc  - the `PC` of type `PCSHELL`
 70: - ctx - the context

 72:   Level: advanced

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

294:   PetscFunctionBegin;
295:   shell->destroy = destroy;
296:   PetscFunctionReturn(PETSC_SUCCESS);
297: }

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

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

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

314:   PetscFunctionBegin;
315:   shell->apply = apply;
316:   PetscFunctionReturn(PETSC_SUCCESS);
317: }

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

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

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

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

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

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

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

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

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

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

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

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

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

390:   PetscFunctionBegin;
391:   shell->view = view;
392:   PetscFunctionReturn(PETSC_SUCCESS);
393: }

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

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

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

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

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

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

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

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

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

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

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

450:   Logically Collective

452:   Input Parameters:
453: + pc      - the preconditioner context
454: - destroy - the application-provided destroy routine

456:   Calling sequence of `destroy`:
457: . pc - the preconditioner

459:   Level: intermediate

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

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

475:   Logically Collective

477:   Input Parameters:
478: + pc    - the preconditioner context
479: - setup - the application-provided setup routine

481:   Calling sequence of `setup`:
482: . pc - the preconditioner

484:   Level: intermediate

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

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

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

502:   Logically Collective

504:   Input Parameters:
505: + pc   - the preconditioner context
506: - view - the application-provided view routine

508:   Calling sequence of `view`:
509: + pc - the preconditioner
510: - v  - viewer

512:   Level: advanced

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

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

527: /*@C
528:   PCShellSetApply - Sets routine to use as preconditioner.

530:   Logically Collective

532:   Input Parameters:
533: + pc    - the preconditioner context
534: - apply - the application-provided preconditioning routine

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

541:   Level: intermediate

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

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

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

559:   Logically Collective

561:   Input Parameters:
562: + pc       - the preconditioner context
563: - matapply - the application-provided preconditioning routine

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

570:   Level: advanced

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

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

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

588:   Logically Collective

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

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

599:   Level: advanced

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

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

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

617:   Logically Collective

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

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

628:   Level: advanced

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

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

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

646:   Logically Collective

648:   Input Parameters:
649: + pc      - the preconditioner context
650: - applyBA - the application-provided BA routine

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

659:   Level: intermediate

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

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

674: /*@C
675:   PCShellSetApplyTranspose - Sets routine to use as preconditioner transpose.

677:   Logically Collective

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

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

688:   Level: intermediate

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

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

703: /*@C
704:   PCShellSetMatApplyTranspose - Sets routine to use as preconditioner transpose.

706:   Logically Collective

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

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

717:   Level: intermediate

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

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

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

737:   Logically Collective

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

743:   Level: advanced

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

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

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

763:   Logically Collective

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

769:   Level: advanced

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

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

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

788:   Not Collective

790:   Input Parameters:
791: + pc   - the preconditioner context
792: - name - character string describing shell preconditioner

794:   Level: intermediate

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

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

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

813:   Not Collective

815:   Input Parameter:
816: . pc - the preconditioner context

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

821:   Level: intermediate

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

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

838:   Logically Collective

840:   Input Parameters:
841: + pc    - the preconditioner context
842: - apply - the application-provided preconditioning routine

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

857:   Level: advanced

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

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

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

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

879:   Level: advanced

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

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

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

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

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

913: PETSC_EXTERN PetscErrorCode PCCreate_Shell(PC pc)
914: {
915:   PC_Shell *shell;

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

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

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

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