xref: /petsc/src/ts/utils/dmts.c (revision 0e9bae810fdaeb60e2713eaa8ddb89f42e079fd1)
1 #include <petsc-private/tsimpl.h>     /*I "petscts.h" I*/
2 #include <petsc-private/dmimpl.h>     /*I "petscdm.h" I*/
3 
4 
5 #undef __FUNCT__
6 #define __FUNCT__ "DMCoarsenHook_TSDM"
7 /* Attaches the SNESDM to the coarse level.
8  * Under what conditions should we copy versus duplicate?
9  */
10 static PetscErrorCode DMCoarsenHook_TSDM(DM dm,DM dmc,void *ctx)
11 {
12   PetscErrorCode ierr;
13 
14   PetscFunctionBegin;
15   ierr = DMTSCopyContext(dm,dmc);CHKERRQ(ierr);
16   PetscFunctionReturn(0);
17 }
18 
19 #undef __FUNCT__
20 #define __FUNCT__ "DMRestrictHook_TSDM"
21 /* This could restrict auxiliary information to the coarse level.
22  */
23 static PetscErrorCode DMRestrictHook_TSDM(DM dm,Mat Restrict,Vec rscale,Mat Inject,DM dmc,void *ctx)
24 {
25 
26   PetscFunctionBegin;
27   PetscFunctionReturn(0);
28 }
29 
30 
31 #undef __FUNCT__
32 #define __FUNCT__ "PetscContainerDestroy_TSDM"
33 static PetscErrorCode PetscContainerDestroy_TSDM(void *ctx)
34 {
35   PetscErrorCode ierr;
36   TSDM tsdm = (TSDM)ctx;
37 
38   PetscFunctionBegin;
39   if (tsdm->destroy) {ierr = (*tsdm->destroy)(tsdm);CHKERRQ(ierr);}
40   ierr = PetscFree(tsdm);CHKERRQ(ierr);
41   PetscFunctionReturn(0);
42 }
43 
44 #undef __FUNCT__
45 #define __FUNCT__ "DMTSGetContext"
46 /*@C
47    DMTSGetContext - get read-only private TSDM context from a DM
48 
49    Not Collective
50 
51    Input Argument:
52 .  dm - DM to be used with TS
53 
54    Output Argument:
55 .  tsdm - private TSDM context
56 
57    Level: developer
58 
59    Notes:
60    Use DMTSGetContextWrite() if write access is needed. The DMTSSetXXX API should be used wherever possible.
61 
62 .seealso: DMTSGetContextWrite()
63 @*/
64 PetscErrorCode DMTSGetContext(DM dm,TSDM *tsdm)
65 {
66   PetscErrorCode ierr;
67   PetscContainer container;
68   TSDM           tsdmnew;
69 
70 
71   PetscFunctionBegin;
72   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
73   ierr = PetscObjectQuery((PetscObject)dm,"TSDM",(PetscObject*)&container);CHKERRQ(ierr);
74   if (container) {
75     ierr = PetscContainerGetPointer(container,(void**)tsdm);CHKERRQ(ierr);
76   } else {
77     ierr = PetscInfo(dm,"Creating new TSDM\n");CHKERRQ(ierr);
78     ierr = PetscContainerCreate(((PetscObject)dm)->comm,&container);CHKERRQ(ierr);
79     ierr = PetscNewLog(dm,struct _n_TSDM,&tsdmnew);CHKERRQ(ierr);
80     ierr = PetscContainerSetPointer(container,tsdmnew);CHKERRQ(ierr);
81     ierr = PetscContainerSetUserDestroy(container,PetscContainerDestroy_TSDM);CHKERRQ(ierr);
82     ierr = PetscObjectCompose((PetscObject)dm,"TSDM",(PetscObject)container);CHKERRQ(ierr);
83     ierr = DMCoarsenHookAdd(dm,DMCoarsenHook_TSDM,DMRestrictHook_TSDM,PETSC_NULL);CHKERRQ(ierr);
84     ierr = PetscContainerGetPointer(container,(void**)tsdm);CHKERRQ(ierr);
85     ierr = PetscContainerDestroy(&container);CHKERRQ(ierr);
86   }
87   PetscFunctionReturn(0);
88 }
89 
90 #undef __FUNCT__
91 #define __FUNCT__ "DMTSGetContextWrite"
92 /*@C
93    DMTSGetContextWrite - get write access to private TSDM context from a DM
94 
95    Not Collective
96 
97    Input Argument:
98 .  dm - DM to be used with TS
99 
100    Output Argument:
101 .  tsdm - private TSDM context
102 
103    Level: developer
104 
105 .seealso: DMTSGetContext()
106 @*/
107 PetscErrorCode DMTSGetContextWrite(DM dm,TSDM *tsdm)
108 {
109   PetscErrorCode ierr;
110   TSDM           sdm;
111 
112   PetscFunctionBegin;
113   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
114   ierr = DMTSGetContext(dm,&sdm);CHKERRQ(ierr);
115   if (!sdm->originaldm) sdm->originaldm = dm;
116   if (sdm->originaldm != dm) {  /* Copy on write */
117     PetscContainer container;
118     TSDM         oldsdm = sdm;
119     ierr = PetscInfo(dm,"Copying TSDM due to write\n");CHKERRQ(ierr);
120     ierr = PetscContainerCreate(((PetscObject)dm)->comm,&container);CHKERRQ(ierr);
121     ierr = PetscNewLog(dm,struct _n_TSDM,&sdm);CHKERRQ(ierr);
122     ierr = PetscMemcpy(sdm,oldsdm,sizeof *sdm);CHKERRQ(ierr);
123     ierr = PetscContainerSetPointer(container,sdm);CHKERRQ(ierr);
124     ierr = PetscContainerSetUserDestroy(container,PetscContainerDestroy_TSDM);CHKERRQ(ierr);
125     ierr = PetscObjectCompose((PetscObject)dm,"TSDM",(PetscObject)container);CHKERRQ(ierr);
126     ierr = PetscContainerDestroy(&container);CHKERRQ(ierr);
127   }
128   *tsdm = sdm;
129   PetscFunctionReturn(0);
130 }
131 
132 #undef __FUNCT__
133 #define __FUNCT__ "DMTSCopyContext"
134 /*@C
135    DMTSCopyContext - copies a DM context to a new DM
136 
137    Logically Collective
138 
139    Input Arguments:
140 +  dmsrc - DM to obtain context from
141 -  dmdest - DM to add context to
142 
143    Level: developer
144 
145    Note:
146    The context is copied by reference. This function does not ensure that a context exists.
147 
148 .seealso: DMTSGetContext(), TSSetDM()
149 @*/
150 PetscErrorCode DMTSCopyContext(DM dmsrc,DM dmdest)
151 {
152   PetscErrorCode ierr;
153   PetscContainer container;
154 
155   PetscFunctionBegin;
156   PetscValidHeaderSpecific(dmsrc,DM_CLASSID,1);
157   PetscValidHeaderSpecific(dmdest,DM_CLASSID,2);
158   ierr = PetscObjectQuery((PetscObject)dmsrc,"TSDM",(PetscObject*)&container);CHKERRQ(ierr);
159   if (container) {
160     ierr = PetscObjectCompose((PetscObject)dmdest,"TSDM",(PetscObject)container);CHKERRQ(ierr);
161     ierr = DMCoarsenHookAdd(dmdest,DMCoarsenHook_TSDM,DMRestrictHook_TSDM,PETSC_NULL);CHKERRQ(ierr);
162   }
163   PetscFunctionReturn(0);
164 }
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "DMTSSetIFunction"
168 /*@C
169    DMTSSetIFunction - set TS implicit function evaluation function
170 
171    Not Collective
172 
173    Input Arguments:
174 +  dm - DM to be used with TS
175 .  func - function evaluation function, see TSSetIFunction() for calling sequence
176 -  ctx - context for residual evaluation
177 
178    Level: advanced
179 
180    Note:
181    TSSetFunction() is normally used, but it calls this function internally because the user context is actually
182    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
183    not. If DM took a more central role at some later date, this could become the primary method of setting the residual.
184 
185 .seealso: DMTSSetContext(), TSSetFunction(), DMTSSetJacobian()
186 @*/
187 PetscErrorCode DMTSSetIFunction(DM dm,TSIFunction func,void *ctx)
188 {
189   PetscErrorCode ierr;
190   TSDM tsdm;
191 
192   PetscFunctionBegin;
193   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
194   ierr = DMTSGetContextWrite(dm,&tsdm);CHKERRQ(ierr);
195   if (func) tsdm->ifunction = func;
196   if (ctx)  tsdm->ifunctionctx = ctx;
197   PetscFunctionReturn(0);
198 }
199 
200 #undef __FUNCT__
201 #define __FUNCT__ "DMTSGetIFunction"
202 /*@C
203    DMTSGetIFunction - get TS implicit residual evaluation function
204 
205    Not Collective
206 
207    Input Argument:
208 .  dm - DM to be used with TS
209 
210    Output Arguments:
211 +  func - function evaluation function, see TSSetIFunction() for calling sequence
212 -  ctx - context for residual evaluation
213 
214    Level: advanced
215 
216    Note:
217    TSGetFunction() is normally used, but it calls this function internally because the user context is actually
218    associated with the DM.
219 
220 .seealso: DMTSSetContext(), DMTSSetFunction(), TSSetFunction()
221 @*/
222 PetscErrorCode DMTSGetIFunction(DM dm,TSIFunction *func,void **ctx)
223 {
224   PetscErrorCode ierr;
225   TSDM tsdm;
226 
227   PetscFunctionBegin;
228   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
229   ierr = DMTSGetContext(dm,&tsdm);CHKERRQ(ierr);
230   if (func) *func = tsdm->ifunction;
231   if (ctx)  *ctx = tsdm->ifunctionctx;
232   PetscFunctionReturn(0);
233 }
234 
235 
236 #undef __FUNCT__
237 #define __FUNCT__ "DMTSSetRHSFunction"
238 /*@C
239    DMTSSetRHSFunction - set TS explicit residual evaluation function
240 
241    Not Collective
242 
243    Input Arguments:
244 +  dm - DM to be used with TS
245 .  func - RHS function evaluation function, see TSSetRHSFunction() for calling sequence
246 -  ctx - context for residual evaluation
247 
248    Level: advanced
249 
250    Note:
251    TSSetFunction() is normally used, but it calls this function internally because the user context is actually
252    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
253    not. If DM took a more central role at some later date, this could become the primary method of setting the residual.
254 
255 .seealso: DMTSSetContext(), TSSetFunction(), DMTSSetJacobian()
256 @*/
257 PetscErrorCode DMTSSetRHSFunction(DM dm,TSRHSFunction func,void *ctx)
258 {
259   PetscErrorCode ierr;
260   TSDM tsdm;
261 
262   PetscFunctionBegin;
263   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
264   ierr = DMTSGetContextWrite(dm,&tsdm);CHKERRQ(ierr);
265   if (func) tsdm->rhsfunction = func;
266   if (ctx)  tsdm->rhsfunctionctx = ctx;
267   PetscFunctionReturn(0);
268 }
269 
270 #undef __FUNCT__
271 #define __FUNCT__ "DMTSGetRHSFunction"
272 /*@C
273    DMTSGetRHSFunction - get TS explicit residual evaluation function
274 
275    Not Collective
276 
277    Input Argument:
278 .  dm - DM to be used with TS
279 
280    Output Arguments:
281 +  func - residual evaluation function, see TSSetRHSFunction() for calling sequence
282 -  ctx - context for residual evaluation
283 
284    Level: advanced
285 
286    Note:
287    TSGetFunction() is normally used, but it calls this function internally because the user context is actually
288    associated with the DM.
289 
290 .seealso: DMTSSetContext(), DMTSSetFunction(), TSSetFunction()
291 @*/
292 PetscErrorCode DMTSGetRHSFunction(DM dm,TSRHSFunction *func,void **ctx)
293 {
294   PetscErrorCode ierr;
295   TSDM tsdm;
296 
297   PetscFunctionBegin;
298   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
299   ierr = DMTSGetContext(dm,&tsdm);CHKERRQ(ierr);
300   if (func) *func = tsdm->rhsfunction;
301   if (ctx)  *ctx = tsdm->rhsfunctionctx;
302   PetscFunctionReturn(0);
303 }
304 
305 #undef __FUNCT__
306 #define __FUNCT__ "DMTSSetIJacobian"
307 /*@C
308    DMTSSetIJacobian - set TS Jacobian evaluation function
309 
310    Not Collective
311 
312    Input Argument:
313 +  dm - DM to be used with TS
314 .  func - Jacobian evaluation function, see TSSetIJacobian() for calling sequence
315 -  ctx - context for residual evaluation
316 
317    Level: advanced
318 
319    Note:
320    TSSetJacobian() is normally used, but it calls this function internally because the user context is actually
321    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
322    not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian.
323 
324 .seealso: DMTSSetContext(), TSSetFunction(), DMTSGetJacobian(), TSSetJacobian()
325 @*/
326 PetscErrorCode DMTSSetIJacobian(DM dm,TSIJacobian func,void *ctx)
327 {
328   PetscErrorCode ierr;
329   TSDM sdm;
330 
331   PetscFunctionBegin;
332   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
333   ierr = DMTSGetContextWrite(dm,&sdm);CHKERRQ(ierr);
334   if (func) sdm->ijacobian = func;
335   if (ctx)  sdm->ijacobianctx = ctx;
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "DMTSGetIJacobian"
341 /*@C
342    DMTSGetIJacobian - get TS Jacobian evaluation function
343 
344    Not Collective
345 
346    Input Argument:
347 .  dm - DM to be used with TS
348 
349    Output Arguments:
350 +  func - Jacobian evaluation function, see TSSetIJacobian() for calling sequence
351 -  ctx - context for residual evaluation
352 
353    Level: advanced
354 
355    Note:
356    TSGetJacobian() is normally used, but it calls this function internally because the user context is actually
357    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
358    not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian.
359 
360 .seealso: DMTSSetContext(), TSSetFunction(), DMTSSetJacobian()
361 @*/
362 PetscErrorCode DMTSGetIJacobian(DM dm,TSIJacobian *func,void **ctx)
363 {
364   PetscErrorCode ierr;
365   TSDM tsdm;
366 
367   PetscFunctionBegin;
368   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
369   ierr = DMTSGetContext(dm,&tsdm);CHKERRQ(ierr);
370   if (func) *func = tsdm->ijacobian;
371   if (ctx)  *ctx = tsdm->ijacobianctx;
372   PetscFunctionReturn(0);
373 }
374 
375 
376 #undef __FUNCT__
377 #define __FUNCT__ "DMTSSetRHSJacobian"
378 /*@C
379    DMTSSetRHSJacobian - set TS Jacobian evaluation function
380 
381    Not Collective
382 
383    Input Argument:
384 +  dm - DM to be used with TS
385 .  func - Jacobian evaluation function, see TSSetRHSJacobian() for calling sequence
386 -  ctx - context for residual evaluation
387 
388    Level: advanced
389 
390    Note:
391    TSSetJacobian() is normally used, but it calls this function internally because the user context is actually
392    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
393    not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian.
394 
395 .seealso: DMTSSetContext(), TSSetFunction(), DMTSGetJacobian(), TSSetJacobian()
396 @*/
397 PetscErrorCode DMTSSetRHSJacobian(DM dm,TSRHSJacobian func,void *ctx)
398 {
399   PetscErrorCode ierr;
400   TSDM tsdm;
401 
402   PetscFunctionBegin;
403   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
404   ierr = DMTSGetContextWrite(dm,&tsdm);CHKERRQ(ierr);
405   if (func) tsdm->rhsjacobian = func;
406   if (ctx)  tsdm->rhsjacobianctx = ctx;
407   PetscFunctionReturn(0);
408 }
409 
410 #undef __FUNCT__
411 #define __FUNCT__ "DMTSGetRHSJacobian"
412 /*@C
413    DMTSGetRHSJacobian - get TS Jacobian evaluation function
414 
415    Not Collective
416 
417    Input Argument:
418 .  dm - DM to be used with TS
419 
420    Output Arguments:
421 +  func - Jacobian evaluation function, see TSSetRHSJacobian() for calling sequence
422 -  ctx - context for residual evaluation
423 
424    Level: advanced
425 
426    Note:
427    TSGetJacobian() is normally used, but it calls this function internally because the user context is actually
428    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
429    not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian.
430 
431 .seealso: DMTSSetContext(), TSSetFunction(), DMTSSetJacobian()
432 @*/
433 PetscErrorCode DMTSGetRHSJacobian(DM dm,TSRHSJacobian *func,void **ctx)
434 {
435   PetscErrorCode ierr;
436   TSDM tsdm;
437 
438   PetscFunctionBegin;
439   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
440   ierr = DMTSGetContext(dm,&tsdm);CHKERRQ(ierr);
441   if (func) *func = tsdm->rhsjacobian;
442   if (ctx)  *ctx = tsdm->rhsjacobianctx;
443   PetscFunctionReturn(0);
444 }
445