xref: /petsc/doc/developers/callbacks.md (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
14bcd95a3SBarry Smith# How the Solvers Handle User Provided Callbacks
24bcd95a3SBarry Smith
34bcd95a3SBarry SmithThe solver objects in PETSc, `KSP` (optionally), `SNES`, and `TS`
44bcd95a3SBarry Smithrequire user provided callback functions (and contexts for the
54bcd95a3SBarry Smithfunctions) that define the problem to be solved. These functions are
64bcd95a3SBarry Smithsupplied by the user with calls such as `SNESSetFunction(SNES,...)`
74bcd95a3SBarry Smithand `TSSetRHSFunction(TS,...)`. One would naturally think that the
84bcd95a3SBarry Smithfunctions provided would be attached to the appropriate solver object,
94bcd95a3SBarry Smiththat is, that the SNES callbacks would be attached to the `SNES`
104bcd95a3SBarry Smithobject and `TS` callbacks to the `TS` object. This is not the case.
114bcd95a3SBarry SmithOr possibly one might think the callbacks would be attached to the
124bcd95a3SBarry Smith`DM` object associated with the solver object. This is also not the
134bcd95a3SBarry Smithcase. Rather, the callback functions are attached to an inner nonpublic
144bcd95a3SBarry Smith`DMXXX` object (`XXX` is `KSP`, `SNES`, or `TS`) that is
154bcd95a3SBarry Smithattached to the `DM` that is attached to the `XXX` solver object.
164bcd95a3SBarry SmithThis convoluted design is to support multilevel and multidomain solvers
174bcd95a3SBarry Smithwhere different levels and different domains may (or may not) share the
184bcd95a3SBarry Smithsame callback function or callback context. You can control exactly what
194bcd95a3SBarry Smith`XXX`/`DM` objects share a common `DMXXX` object.
204bcd95a3SBarry Smith
214bcd95a3SBarry Smith:::{figure} /images/developers/callbacks1.svg
224bcd95a3SBarry Smith:name: fig_callbacks1
234bcd95a3SBarry Smith
244bcd95a3SBarry SmithThree levels of KSP/DM share the same DMKSP
254bcd95a3SBarry Smith:::
264bcd95a3SBarry Smith
274bcd95a3SBarry SmithIn the preceding figure, we depict how three levels of `KSP`
284bcd95a3SBarry Smithobjects share a common `DMKSP` object. The code to access the inner
294bcd95a3SBarry Smith`DMKSP` object is
304bcd95a3SBarry Smith
314bcd95a3SBarry Smith```
324bcd95a3SBarry SmithDM    dm_2;
334bcd95a3SBarry SmithDMKSP dmksp;
344bcd95a3SBarry SmithKSPGetDM(ksp_2,&dm_2);
354bcd95a3SBarry SmithDMGetDMKSP(dm_2,&dmksp);
364bcd95a3SBarry Smith```
374bcd95a3SBarry Smith
384bcd95a3SBarry SmithTo obtain a new DMKSP object for which you can change the callback
394bcd95a3SBarry Smithfunctions (or their contexts) without affecting the original DMKSP, call
404bcd95a3SBarry Smith
414bcd95a3SBarry Smith```
424bcd95a3SBarry SmithDM    dm_2;
434bcd95a3SBarry SmithDMKSP dmksp;
444bcd95a3SBarry SmithKSPGetDM(ksp_2,&dm_2);
454bcd95a3SBarry SmithDMGetDMKSPWrite(dm_2,&dmksp_2);
464bcd95a3SBarry Smith```
474bcd95a3SBarry Smith
484bcd95a3SBarry SmithThis results in the object organization as indicated in the following figure
494bcd95a3SBarry Smith
504bcd95a3SBarry Smith:::{figure} /images/developers/callbacks2.svg
514bcd95a3SBarry Smith:name: fig_callbacks2
524bcd95a3SBarry Smith
534bcd95a3SBarry SmithTwo levels of KSP/DM share the same DMKSP; one has its own private copy
544bcd95a3SBarry Smith:::
554bcd95a3SBarry Smith
564bcd95a3SBarry SmithThe `DMKSP` object is essentially the list of callback functions and
574bcd95a3SBarry Smiththeir contexts, for example,
584bcd95a3SBarry Smith
594bcd95a3SBarry Smith```
604bcd95a3SBarry Smithtypedef struct _p_DMKSP *DMKSP;
614bcd95a3SBarry Smithtypedef struct _DMKSPOps *DMKSPOps;
624bcd95a3SBarry Smithstruct _DMKSPOps {
634bcd95a3SBarry Smith  PetscErrorCode (*computeoperators)(KSP,Mat,Mat,void*);
644bcd95a3SBarry Smith  PetscErrorCode (*computerhs)(KSP,Vec,void*);
654bcd95a3SBarry Smith  PetscErrorCode (*computeinitialguess)(KSP,Vec,void*);
664bcd95a3SBarry Smith  PetscErrorCode (*destroy)(DMKSP*);
674bcd95a3SBarry Smith  PetscErrorCode (*duplicate)(DMKSP,DMKSP);
684bcd95a3SBarry Smith};
694bcd95a3SBarry Smith
704bcd95a3SBarry Smithstruct _p_DMKSP {
714bcd95a3SBarry Smith  PETSCHEADER(struct _DMKSPOps);
724bcd95a3SBarry Smith  void *operatorsctx;
734bcd95a3SBarry Smith  void *rhsctx;
744bcd95a3SBarry Smith  void *initialguessctx;
754bcd95a3SBarry Smith  void *data;
764bcd95a3SBarry Smith  DM originaldm;
774bcd95a3SBarry Smith
784bcd95a3SBarry Smith  void (*fortran_func_pointers[3])(void); /* Store our own function pointers so they are associated with the DMKSP instead of the DM */
794bcd95a3SBarry Smith};
804bcd95a3SBarry Smith```
814bcd95a3SBarry Smith
824bcd95a3SBarry SmithWe now explore in more detail exactly how the solver calls set by the
834bcd95a3SBarry Smithuser are passed down to the inner `DMKSP` object. For each user level
844bcd95a3SBarry Smithsolver routine for setting a callback a similar routine exists at the
854bcd95a3SBarry Smith`DM` level. Thus, `XXXSetY(XXX,...)` has a routine
864bcd95a3SBarry Smith`DMXXXSetY(DM,...)`.
874bcd95a3SBarry Smith
884bcd95a3SBarry Smith```
89*2a8381b2SBarry SmithPetscErrorCode KSPSetComputeOperators(KSP ksp, PetscErrorCode (*func)(KSP, Mat, Mat, PetscCtx), PetscCtx ctx)
904bcd95a3SBarry Smith{
914bcd95a3SBarry Smith  DM dm;
924bcd95a3SBarry Smith
934bcd95a3SBarry Smith  PetscFunctionBegin;
944bcd95a3SBarry Smith  PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
954bcd95a3SBarry Smith  PetscCall(KSPGetDM(ksp,&dm));
964bcd95a3SBarry Smith  PetscCall(DMKSPSetComputeOperators(dm,func,ctx));
974bcd95a3SBarry Smith  if (ksp->setupstage == KSP_SETUP_NEWRHS) ksp->setupstage = KSP_SETUP_NEWMATRIX;
984bcd95a3SBarry Smith  PetscFunctionReturn(PETSC_SUCCESS);
994bcd95a3SBarry Smith}
1004bcd95a3SBarry Smith```
1014bcd95a3SBarry Smith
1024bcd95a3SBarry SmithThe implementation of `DMXXXSetY(DM,...)` gets a “writable” version of
1034bcd95a3SBarry Smiththe `DMXXX` object via `DMGetDMXXXWrite(DM,DMXXX*)` and sets the
1044bcd95a3SBarry Smithfunction callback and its context into the `DMXXX` object.
1054bcd95a3SBarry Smith
1064bcd95a3SBarry Smith```
107*2a8381b2SBarry SmithPetscErrorCode DMKSPSetComputeOperators(DM dm, PetscErrorCode (*func)(KSP, Mat, Mat, PetscCtx), PetscCtx ctx)
1084bcd95a3SBarry Smith{
1094bcd95a3SBarry Smith  DMKSP kdm;
1104bcd95a3SBarry Smith
1114bcd95a3SBarry Smith  PetscFunctionBegin;
1124bcd95a3SBarry Smith  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1134bcd95a3SBarry Smith  PetscCall(DMGetDMKSPWrite(dm,&kdm));
1144bcd95a3SBarry Smith  if (func) kdm->ops->computeoperators = func;
1154bcd95a3SBarry Smith  if (ctx) kdm->operatorsctx = ctx;
1164bcd95a3SBarry Smith  PetscFunctionReturn(PETSC_SUCCESS);
1174bcd95a3SBarry Smith}
1184bcd95a3SBarry Smith```
1194bcd95a3SBarry Smith
1204bcd95a3SBarry SmithThe routine for `DMGetDMXXXWrite(DM,DMXXX*)` entails a duplication of
1214bcd95a3SBarry Smiththe object unless the `DM` associated with the `DMXXX` object is the
1224bcd95a3SBarry Smithoriginal `DM` that the `DMXXX` object was created with. This can be
1234bcd95a3SBarry Smithseen in the following code.
1244bcd95a3SBarry Smith
1254bcd95a3SBarry Smith```
1264bcd95a3SBarry SmithPetscErrorCode DMGetDMKSPWrite(DM dm,DMKSP *kspdm)
1274bcd95a3SBarry Smith{
1284bcd95a3SBarry Smith  DMKSP kdm;
1294bcd95a3SBarry Smith
1304bcd95a3SBarry Smith  PetscFunctionBegin;
1314bcd95a3SBarry Smith  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1324bcd95a3SBarry Smith  PetscCall(DMGetDMKSP(dm,&kdm));
1334bcd95a3SBarry Smith  if (!kdm->originaldm) kdm->originaldm = dm;
1344bcd95a3SBarry Smith  if (kdm->originaldm != dm) {  /* Copy on write */
1354bcd95a3SBarry Smith    DMKSP oldkdm = kdm;
1364bcd95a3SBarry Smith    PetscCall(PetscInfo(dm,"Copying DMKSP due to write\n"));
1374bcd95a3SBarry Smith    PetscCall(DMKSPCreate(PetscObjectComm((PetscObject)dm),&kdm));
1384bcd95a3SBarry Smith    PetscCall(DMKSPCopy(oldkdm,kdm));
1394bcd95a3SBarry Smith    PetscCall(DMKSPDestroy((DMKSP*)&dm->dmksp));
1404bcd95a3SBarry Smith    dm->dmksp = (PetscObject)kdm;
1414bcd95a3SBarry Smith    kdm->originaldm = dm;
1424bcd95a3SBarry Smith  }
1434bcd95a3SBarry Smith  *kspdm = kdm;
1444bcd95a3SBarry Smith  PetscFunctionReturn(PETSC_SUCCESS);
1454bcd95a3SBarry Smith}
1464bcd95a3SBarry Smith```
1474bcd95a3SBarry Smith
1484bcd95a3SBarry SmithThe routine `DMGetDMXXX(DM,DMXXX*)` has the following form.
1494bcd95a3SBarry Smith
1504bcd95a3SBarry Smith```
1514bcd95a3SBarry SmithPetscErrorCode DMGetDMKSP(DM dm,DMKSP *kspdm)
1524bcd95a3SBarry Smith{
1534bcd95a3SBarry Smith  PetscFunctionBegin;
1544bcd95a3SBarry Smith  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1554bcd95a3SBarry Smith  *kspdm = (DMKSP) dm->dmksp;
1564bcd95a3SBarry Smith  if (!*kspdm) {
1574bcd95a3SBarry Smith    PetscCall(PetscInfo(dm,"Creating new DMKSP\n"));
1584bcd95a3SBarry Smith    PetscCall(DMKSPCreate(PetscObjectComm((PetscObject)dm),kspdm));
1594bcd95a3SBarry Smith    dm->dmksp = (PetscObject) *kspdm;
1604bcd95a3SBarry Smith    (*kspdm)->originaldm = dm;
1614bcd95a3SBarry Smith    PetscCall(DMCoarsenHookAdd(dm,DMCoarsenHook_DMKSP,NULL,NULL));
1624bcd95a3SBarry Smith    PetscCall(DMRefineHookAdd(dm,DMRefineHook_DMKSP,NULL,NULL));
1634bcd95a3SBarry Smith  }
1644bcd95a3SBarry Smith  PetscFunctionReturn(PETSC_SUCCESS);
1654bcd95a3SBarry Smith}
1664bcd95a3SBarry Smith```
1674bcd95a3SBarry Smith
1684bcd95a3SBarry SmithThis routine uses `DMCoarsenHookAdd()` and `DMRefineHookAdd()` to
1694bcd95a3SBarry Smithattach to the `DM` object two functions that are automatically called
1704bcd95a3SBarry Smithwhen the object is coarsened or refined. The hooks
1714bcd95a3SBarry Smith`DMCoarsenHook_DMXXX()` and `DMRefineHook_DMXXX()` have the same form:
1724bcd95a3SBarry Smith
1734bcd95a3SBarry Smith```
174*2a8381b2SBarry Smithstatic PetscErrorCode DMCoarsenHook_DMKSP(DM dm, DM dmc, PetscCtx ctx)
1754bcd95a3SBarry Smith{
1764bcd95a3SBarry Smith  PetscFunctionBegin;
1774bcd95a3SBarry Smith  PetscCall(DMCopyDMKSP(dm,dmc));
1784bcd95a3SBarry Smith  PetscFunctionReturn(PETSC_SUCCESS);
1794bcd95a3SBarry Smith}
1804bcd95a3SBarry Smith```
1814bcd95a3SBarry Smith
1824bcd95a3SBarry Smithwhere
1834bcd95a3SBarry Smith
1844bcd95a3SBarry Smith```
1854bcd95a3SBarry SmithPetscErrorCode DMCopyDMKSP(DM dmsrc,DM dmdest)
1864bcd95a3SBarry Smith{
1874bcd95a3SBarry Smith  PetscFunctionBegin;
1884bcd95a3SBarry Smith  PetscValidHeaderSpecific(dmsrc,DM_CLASSID,1);
1894bcd95a3SBarry Smith  PetscValidHeaderSpecific(dmdest,DM_CLASSID,2);
1904bcd95a3SBarry Smith  PetscCall(DMKSPDestroy((DMKSP*)&dmdest->dmksp));
1914bcd95a3SBarry Smith  dmdest->dmksp = dmsrc->dmksp;
1924bcd95a3SBarry Smith  PetscCall(PetscObjectReference(dmdest->dmksp));
1934bcd95a3SBarry Smith  PetscCall(DMCoarsenHookAdd(dmdest,DMCoarsenHook_DMKSP,NULL,NULL));
1944bcd95a3SBarry Smith  PetscCall(DMRefineHookAdd(dmdest,DMRefineHook_DMKSP,NULL,NULL));
1954bcd95a3SBarry Smith  PetscFunctionReturn(PETSC_SUCCESS);
1964bcd95a3SBarry Smith}
1974bcd95a3SBarry Smith```
1984bcd95a3SBarry Smith
1994bcd95a3SBarry Smithensures that the new `DM` shares the same `DMXXX` as the parent
2004bcd95a3SBarry Smith`DM` and also inherits the hooks if it is refined or coarsened.
2014bcd95a3SBarry Smith
2024bcd95a3SBarry SmithIf you provide callbacks to a solver *after* the `DM` associated with
2034bcd95a3SBarry Smitha solver has been refined or coarsened, those child `DM`s will not
2044bcd95a3SBarry Smithshare a common `DMXXX`.
2054bcd95a3SBarry Smith
2064bcd95a3SBarry SmithThe `TS` object manages its callback functions in a way similar to
2074bcd95a3SBarry Smith`KSP` and `SNES`, although there are no multilevel `TS`
2084bcd95a3SBarry Smithimplementations so in theory the `DMTS` object is currently unneeded.
209