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