1*4bcd95a3SBarry Smith# How the Solvers Handle User Provided Callbacks 2*4bcd95a3SBarry Smith 3*4bcd95a3SBarry SmithThe solver objects in PETSc, `KSP` (optionally), `SNES`, and `TS` 4*4bcd95a3SBarry Smithrequire user provided callback functions (and contexts for the 5*4bcd95a3SBarry Smithfunctions) that define the problem to be solved. These functions are 6*4bcd95a3SBarry Smithsupplied by the user with calls such as `SNESSetFunction(SNES,...)` 7*4bcd95a3SBarry Smithand `TSSetRHSFunction(TS,...)`. One would naturally think that the 8*4bcd95a3SBarry Smithfunctions provided would be attached to the appropriate solver object, 9*4bcd95a3SBarry Smiththat is, that the SNES callbacks would be attached to the `SNES` 10*4bcd95a3SBarry Smithobject and `TS` callbacks to the `TS` object. This is not the case. 11*4bcd95a3SBarry SmithOr possibly one might think the callbacks would be attached to the 12*4bcd95a3SBarry Smith`DM` object associated with the solver object. This is also not the 13*4bcd95a3SBarry Smithcase. Rather, the callback functions are attached to an inner nonpublic 14*4bcd95a3SBarry Smith`DMXXX` object (`XXX` is `KSP`, `SNES`, or `TS`) that is 15*4bcd95a3SBarry Smithattached to the `DM` that is attached to the `XXX` solver object. 16*4bcd95a3SBarry SmithThis convoluted design is to support multilevel and multidomain solvers 17*4bcd95a3SBarry Smithwhere different levels and different domains may (or may not) share the 18*4bcd95a3SBarry Smithsame callback function or callback context. You can control exactly what 19*4bcd95a3SBarry Smith`XXX`/`DM` objects share a common `DMXXX` object. 20*4bcd95a3SBarry Smith 21*4bcd95a3SBarry Smith:::{figure} /images/developers/callbacks1.svg 22*4bcd95a3SBarry Smith:name: fig_callbacks1 23*4bcd95a3SBarry Smith 24*4bcd95a3SBarry SmithThree levels of KSP/DM share the same DMKSP 25*4bcd95a3SBarry Smith::: 26*4bcd95a3SBarry Smith 27*4bcd95a3SBarry SmithIn the preceding figure, we depict how three levels of `KSP` 28*4bcd95a3SBarry Smithobjects share a common `DMKSP` object. The code to access the inner 29*4bcd95a3SBarry Smith`DMKSP` object is 30*4bcd95a3SBarry Smith 31*4bcd95a3SBarry Smith``` 32*4bcd95a3SBarry SmithDM dm_2; 33*4bcd95a3SBarry SmithDMKSP dmksp; 34*4bcd95a3SBarry SmithKSPGetDM(ksp_2,&dm_2); 35*4bcd95a3SBarry SmithDMGetDMKSP(dm_2,&dmksp); 36*4bcd95a3SBarry Smith``` 37*4bcd95a3SBarry Smith 38*4bcd95a3SBarry SmithTo obtain a new DMKSP object for which you can change the callback 39*4bcd95a3SBarry Smithfunctions (or their contexts) without affecting the original DMKSP, call 40*4bcd95a3SBarry Smith 41*4bcd95a3SBarry Smith``` 42*4bcd95a3SBarry SmithDM dm_2; 43*4bcd95a3SBarry SmithDMKSP dmksp; 44*4bcd95a3SBarry SmithKSPGetDM(ksp_2,&dm_2); 45*4bcd95a3SBarry SmithDMGetDMKSPWrite(dm_2,&dmksp_2); 46*4bcd95a3SBarry Smith``` 47*4bcd95a3SBarry Smith 48*4bcd95a3SBarry SmithThis results in the object organization as indicated in the following figure 49*4bcd95a3SBarry Smith 50*4bcd95a3SBarry Smith:::{figure} /images/developers/callbacks2.svg 51*4bcd95a3SBarry Smith:name: fig_callbacks2 52*4bcd95a3SBarry Smith 53*4bcd95a3SBarry SmithTwo levels of KSP/DM share the same DMKSP; one has its own private copy 54*4bcd95a3SBarry Smith::: 55*4bcd95a3SBarry Smith 56*4bcd95a3SBarry SmithThe `DMKSP` object is essentially the list of callback functions and 57*4bcd95a3SBarry Smiththeir contexts, for example, 58*4bcd95a3SBarry Smith 59*4bcd95a3SBarry Smith``` 60*4bcd95a3SBarry Smithtypedef struct _p_DMKSP *DMKSP; 61*4bcd95a3SBarry Smithtypedef struct _DMKSPOps *DMKSPOps; 62*4bcd95a3SBarry Smithstruct _DMKSPOps { 63*4bcd95a3SBarry Smith PetscErrorCode (*computeoperators)(KSP,Mat,Mat,void*); 64*4bcd95a3SBarry Smith PetscErrorCode (*computerhs)(KSP,Vec,void*); 65*4bcd95a3SBarry Smith PetscErrorCode (*computeinitialguess)(KSP,Vec,void*); 66*4bcd95a3SBarry Smith PetscErrorCode (*destroy)(DMKSP*); 67*4bcd95a3SBarry Smith PetscErrorCode (*duplicate)(DMKSP,DMKSP); 68*4bcd95a3SBarry Smith}; 69*4bcd95a3SBarry Smith 70*4bcd95a3SBarry Smithstruct _p_DMKSP { 71*4bcd95a3SBarry Smith PETSCHEADER(struct _DMKSPOps); 72*4bcd95a3SBarry Smith void *operatorsctx; 73*4bcd95a3SBarry Smith void *rhsctx; 74*4bcd95a3SBarry Smith void *initialguessctx; 75*4bcd95a3SBarry Smith void *data; 76*4bcd95a3SBarry Smith DM originaldm; 77*4bcd95a3SBarry Smith 78*4bcd95a3SBarry Smith void (*fortran_func_pointers[3])(void); /* Store our own function pointers so they are associated with the DMKSP instead of the DM */ 79*4bcd95a3SBarry Smith}; 80*4bcd95a3SBarry Smith``` 81*4bcd95a3SBarry Smith 82*4bcd95a3SBarry SmithWe now explore in more detail exactly how the solver calls set by the 83*4bcd95a3SBarry Smithuser are passed down to the inner `DMKSP` object. For each user level 84*4bcd95a3SBarry Smithsolver routine for setting a callback a similar routine exists at the 85*4bcd95a3SBarry Smith`DM` level. Thus, `XXXSetY(XXX,...)` has a routine 86*4bcd95a3SBarry Smith`DMXXXSetY(DM,...)`. 87*4bcd95a3SBarry Smith 88*4bcd95a3SBarry Smith``` 89*4bcd95a3SBarry SmithPetscErrorCode KSPSetComputeOperators(KSP ksp,PetscErrorCode (*func)(KSP,Mat,Mat,void*),void *ctx) 90*4bcd95a3SBarry Smith{ 91*4bcd95a3SBarry Smith DM dm; 92*4bcd95a3SBarry Smith 93*4bcd95a3SBarry Smith PetscFunctionBegin; 94*4bcd95a3SBarry Smith PetscValidHeaderSpecific(ksp,KSP_CLASSID,1); 95*4bcd95a3SBarry Smith PetscCall(KSPGetDM(ksp,&dm)); 96*4bcd95a3SBarry Smith PetscCall(DMKSPSetComputeOperators(dm,func,ctx)); 97*4bcd95a3SBarry Smith if (ksp->setupstage == KSP_SETUP_NEWRHS) ksp->setupstage = KSP_SETUP_NEWMATRIX; 98*4bcd95a3SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 99*4bcd95a3SBarry Smith} 100*4bcd95a3SBarry Smith``` 101*4bcd95a3SBarry Smith 102*4bcd95a3SBarry SmithThe implementation of `DMXXXSetY(DM,...)` gets a “writable” version of 103*4bcd95a3SBarry Smiththe `DMXXX` object via `DMGetDMXXXWrite(DM,DMXXX*)` and sets the 104*4bcd95a3SBarry Smithfunction callback and its context into the `DMXXX` object. 105*4bcd95a3SBarry Smith 106*4bcd95a3SBarry Smith``` 107*4bcd95a3SBarry SmithPetscErrorCode DMKSPSetComputeOperators(DM dm,PetscErrorCode (*func)(KSP,Mat,Mat,void*),void *ctx) 108*4bcd95a3SBarry Smith{ 109*4bcd95a3SBarry Smith DMKSP kdm; 110*4bcd95a3SBarry Smith 111*4bcd95a3SBarry Smith PetscFunctionBegin; 112*4bcd95a3SBarry Smith PetscValidHeaderSpecific(dm,DM_CLASSID,1); 113*4bcd95a3SBarry Smith PetscCall(DMGetDMKSPWrite(dm,&kdm)); 114*4bcd95a3SBarry Smith if (func) kdm->ops->computeoperators = func; 115*4bcd95a3SBarry Smith if (ctx) kdm->operatorsctx = ctx; 116*4bcd95a3SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 117*4bcd95a3SBarry Smith} 118*4bcd95a3SBarry Smith``` 119*4bcd95a3SBarry Smith 120*4bcd95a3SBarry SmithThe routine for `DMGetDMXXXWrite(DM,DMXXX*)` entails a duplication of 121*4bcd95a3SBarry Smiththe object unless the `DM` associated with the `DMXXX` object is the 122*4bcd95a3SBarry Smithoriginal `DM` that the `DMXXX` object was created with. This can be 123*4bcd95a3SBarry Smithseen in the following code. 124*4bcd95a3SBarry Smith 125*4bcd95a3SBarry Smith``` 126*4bcd95a3SBarry SmithPetscErrorCode DMGetDMKSPWrite(DM dm,DMKSP *kspdm) 127*4bcd95a3SBarry Smith{ 128*4bcd95a3SBarry Smith DMKSP kdm; 129*4bcd95a3SBarry Smith 130*4bcd95a3SBarry Smith PetscFunctionBegin; 131*4bcd95a3SBarry Smith PetscValidHeaderSpecific(dm,DM_CLASSID,1); 132*4bcd95a3SBarry Smith PetscCall(DMGetDMKSP(dm,&kdm)); 133*4bcd95a3SBarry Smith if (!kdm->originaldm) kdm->originaldm = dm; 134*4bcd95a3SBarry Smith if (kdm->originaldm != dm) { /* Copy on write */ 135*4bcd95a3SBarry Smith DMKSP oldkdm = kdm; 136*4bcd95a3SBarry Smith PetscCall(PetscInfo(dm,"Copying DMKSP due to write\n")); 137*4bcd95a3SBarry Smith PetscCall(DMKSPCreate(PetscObjectComm((PetscObject)dm),&kdm)); 138*4bcd95a3SBarry Smith PetscCall(DMKSPCopy(oldkdm,kdm)); 139*4bcd95a3SBarry Smith PetscCall(DMKSPDestroy((DMKSP*)&dm->dmksp)); 140*4bcd95a3SBarry Smith dm->dmksp = (PetscObject)kdm; 141*4bcd95a3SBarry Smith kdm->originaldm = dm; 142*4bcd95a3SBarry Smith } 143*4bcd95a3SBarry Smith *kspdm = kdm; 144*4bcd95a3SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 145*4bcd95a3SBarry Smith} 146*4bcd95a3SBarry Smith``` 147*4bcd95a3SBarry Smith 148*4bcd95a3SBarry SmithThe routine `DMGetDMXXX(DM,DMXXX*)` has the following form. 149*4bcd95a3SBarry Smith 150*4bcd95a3SBarry Smith``` 151*4bcd95a3SBarry SmithPetscErrorCode DMGetDMKSP(DM dm,DMKSP *kspdm) 152*4bcd95a3SBarry Smith{ 153*4bcd95a3SBarry Smith PetscFunctionBegin; 154*4bcd95a3SBarry Smith PetscValidHeaderSpecific(dm,DM_CLASSID,1); 155*4bcd95a3SBarry Smith *kspdm = (DMKSP) dm->dmksp; 156*4bcd95a3SBarry Smith if (!*kspdm) { 157*4bcd95a3SBarry Smith PetscCall(PetscInfo(dm,"Creating new DMKSP\n")); 158*4bcd95a3SBarry Smith PetscCall(DMKSPCreate(PetscObjectComm((PetscObject)dm),kspdm)); 159*4bcd95a3SBarry Smith dm->dmksp = (PetscObject) *kspdm; 160*4bcd95a3SBarry Smith (*kspdm)->originaldm = dm; 161*4bcd95a3SBarry Smith PetscCall(DMCoarsenHookAdd(dm,DMCoarsenHook_DMKSP,NULL,NULL)); 162*4bcd95a3SBarry Smith PetscCall(DMRefineHookAdd(dm,DMRefineHook_DMKSP,NULL,NULL)); 163*4bcd95a3SBarry Smith } 164*4bcd95a3SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 165*4bcd95a3SBarry Smith} 166*4bcd95a3SBarry Smith``` 167*4bcd95a3SBarry Smith 168*4bcd95a3SBarry SmithThis routine uses `DMCoarsenHookAdd()` and `DMRefineHookAdd()` to 169*4bcd95a3SBarry Smithattach to the `DM` object two functions that are automatically called 170*4bcd95a3SBarry Smithwhen the object is coarsened or refined. The hooks 171*4bcd95a3SBarry Smith`DMCoarsenHook_DMXXX()` and `DMRefineHook_DMXXX()` have the same form: 172*4bcd95a3SBarry Smith 173*4bcd95a3SBarry Smith``` 174*4bcd95a3SBarry Smithstatic PetscErrorCode DMCoarsenHook_DMKSP(DM dm,DM dmc,void *ctx) 175*4bcd95a3SBarry Smith{ 176*4bcd95a3SBarry Smith PetscFunctionBegin; 177*4bcd95a3SBarry Smith PetscCall(DMCopyDMKSP(dm,dmc)); 178*4bcd95a3SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 179*4bcd95a3SBarry Smith} 180*4bcd95a3SBarry Smith``` 181*4bcd95a3SBarry Smith 182*4bcd95a3SBarry Smithwhere 183*4bcd95a3SBarry Smith 184*4bcd95a3SBarry Smith``` 185*4bcd95a3SBarry SmithPetscErrorCode DMCopyDMKSP(DM dmsrc,DM dmdest) 186*4bcd95a3SBarry Smith{ 187*4bcd95a3SBarry Smith PetscFunctionBegin; 188*4bcd95a3SBarry Smith PetscValidHeaderSpecific(dmsrc,DM_CLASSID,1); 189*4bcd95a3SBarry Smith PetscValidHeaderSpecific(dmdest,DM_CLASSID,2); 190*4bcd95a3SBarry Smith PetscCall(DMKSPDestroy((DMKSP*)&dmdest->dmksp)); 191*4bcd95a3SBarry Smith dmdest->dmksp = dmsrc->dmksp; 192*4bcd95a3SBarry Smith PetscCall(PetscObjectReference(dmdest->dmksp)); 193*4bcd95a3SBarry Smith PetscCall(DMCoarsenHookAdd(dmdest,DMCoarsenHook_DMKSP,NULL,NULL)); 194*4bcd95a3SBarry Smith PetscCall(DMRefineHookAdd(dmdest,DMRefineHook_DMKSP,NULL,NULL)); 195*4bcd95a3SBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 196*4bcd95a3SBarry Smith} 197*4bcd95a3SBarry Smith``` 198*4bcd95a3SBarry Smith 199*4bcd95a3SBarry Smithensures that the new `DM` shares the same `DMXXX` as the parent 200*4bcd95a3SBarry Smith`DM` and also inherits the hooks if it is refined or coarsened. 201*4bcd95a3SBarry Smith 202*4bcd95a3SBarry SmithIf you provide callbacks to a solver *after* the `DM` associated with 203*4bcd95a3SBarry Smitha solver has been refined or coarsened, those child `DM`s will not 204*4bcd95a3SBarry Smithshare a common `DMXXX`. 205*4bcd95a3SBarry Smith 206*4bcd95a3SBarry SmithThe `TS` object manages its callback functions in a way similar to 207*4bcd95a3SBarry Smith`KSP` and `SNES`, although there are no multilevel `TS` 208*4bcd95a3SBarry Smithimplementations so in theory the `DMTS` object is currently unneeded. 209