xref: /petsc/doc/developers/callbacks.md (revision 4bcd95a3096906c174cd1a87ff30988eadf5695d)
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