xref: /petsc/src/snes/utils/dmsnes.c (revision f8e4bde84cdee892096ab78baf4256ae384d8e42)
1 #include <petsc-private/snesimpl.h>   /*I "petscsnes.h" I*/
2 #include <petsc-private/dmimpl.h>     /*I "petscdm.h" I*/
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "DMSNESDestroy"
6 static PetscErrorCode DMSNESDestroy(DMSNES *kdm)
7 {
8   PetscErrorCode ierr;
9 
10   PetscFunctionBegin;
11   if (!*kdm) PetscFunctionReturn(0);
12   PetscValidHeaderSpecific((*kdm),DMSNES_CLASSID,1);
13   if (--((PetscObject)(*kdm))->refct > 0) {*kdm = 0; PetscFunctionReturn(0);}
14   if ((*kdm)->ops->destroy) {ierr = ((*kdm)->ops->destroy)(*kdm);CHKERRQ(ierr);}
15   ierr = PetscHeaderDestroy(kdm);CHKERRQ(ierr);
16   PetscFunctionReturn(0);
17 }
18 
19 #undef __FUNCT__
20 #define __FUNCT__ "DMSNESLoad"
21 PetscErrorCode DMSNESLoad(DMSNES kdm,PetscViewer viewer)
22 {
23   PetscInt       num = 1;
24   PetscErrorCode ierr;
25 
26   PetscFunctionBegin;
27   ierr = PetscViewerBinaryRead(viewer,&kdm->ops->computefunction,&num,PETSC_FUNCTION);CHKERRQ(ierr);
28   ierr = PetscViewerBinaryRead(viewer,&kdm->ops->computejacobian,&num,PETSC_FUNCTION);CHKERRQ(ierr);
29   PetscFunctionReturn(0);
30 }
31 
32 #undef __FUNCT__
33 #define __FUNCT__ "DMSNESView"
34 PetscErrorCode DMSNESView(DMSNES kdm,PetscViewer viewer)
35 {
36   PetscErrorCode ierr;
37   PetscBool      isascii,isbinary;
38 
39   PetscFunctionBegin;
40   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
41   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
42   if (isascii) {
43 #if defined(PETSC_SERIALIZE_FUNCTIONS)
44     const char *fname;
45 
46     ierr = PetscFPTFind(kdm->ops->computefunction,&fname);CHKERRQ(ierr);
47     if (fname) {
48       ierr = PetscViewerASCIIPrintf(viewer,"Function used by SNES: %s\n",fname);CHKERRQ(ierr);
49     }
50     ierr = PetscFPTFind(kdm->ops->computejacobian,&fname);CHKERRQ(ierr);
51     if (fname) {
52       ierr = PetscViewerASCIIPrintf(viewer,"Jacobian function used by SNES: %s\n",fname);CHKERRQ(ierr);
53     }
54 #endif
55   } else if (isbinary) {
56     struct {
57       PetscErrorCode (*func)(SNES,Vec,Vec,void*);
58     } funcstruct;
59     struct {
60       PetscErrorCode (*jac)(SNES,Vec,Mat,Mat,void*);
61     } jacstruct;
62     funcstruct.func = kdm->ops->computefunction;
63     jacstruct.jac   = kdm->ops->computejacobian;
64     ierr = PetscViewerBinaryWrite(viewer,&funcstruct,1,PETSC_FUNCTION,PETSC_FALSE);CHKERRQ(ierr);
65     ierr = PetscViewerBinaryWrite(viewer,&jacstruct,1,PETSC_FUNCTION,PETSC_FALSE);CHKERRQ(ierr);
66   }
67   PetscFunctionReturn(0);
68 }
69 
70 #undef __FUNCT__
71 #define __FUNCT__ "DMSNESCreate"
72 static PetscErrorCode DMSNESCreate(MPI_Comm comm,DMSNES *kdm)
73 {
74   PetscErrorCode ierr;
75 
76   PetscFunctionBegin;
77   ierr = SNESInitializePackage();CHKERRQ(ierr);
78   ierr = PetscHeaderCreate(*kdm, _p_DMSNES, struct _DMSNESOps, DMSNES_CLASSID,  "DMSNES", "DMSNES", "DMSNES", comm, DMSNESDestroy, DMSNESView);CHKERRQ(ierr);
79   ierr = PetscMemzero((*kdm)->ops, sizeof(struct _DMSNESOps));CHKERRQ(ierr);
80   PetscFunctionReturn(0);
81 }
82 
83 #undef __FUNCT__
84 #define __FUNCT__ "DMCoarsenHook_DMSNES"
85 /* Attaches the DMSNES to the coarse level.
86  * Under what conditions should we copy versus duplicate?
87  */
88 static PetscErrorCode DMCoarsenHook_DMSNES(DM dm,DM dmc,void *ctx)
89 {
90   PetscErrorCode ierr;
91 
92   PetscFunctionBegin;
93   ierr = DMCopyDMSNES(dm,dmc);CHKERRQ(ierr);
94   PetscFunctionReturn(0);
95 }
96 
97 #undef __FUNCT__
98 #define __FUNCT__ "DMRestrictHook_DMSNES"
99 /* This could restrict auxiliary information to the coarse level.
100  */
101 static PetscErrorCode DMRestrictHook_DMSNES(DM dm,Mat Restrict,Vec rscale,Mat Inject,DM dmc,void *ctx)
102 {
103 
104   PetscFunctionBegin;
105   PetscFunctionReturn(0);
106 }
107 
108 #undef __FUNCT__
109 #define __FUNCT__ "DMSubDomainHook_DMSNES"
110 /* Attaches the DMSNES to the subdomain. */
111 static PetscErrorCode DMSubDomainHook_DMSNES(DM dm,DM subdm,void *ctx)
112 {
113   PetscErrorCode ierr;
114 
115   PetscFunctionBegin;
116   ierr = DMCopyDMSNES(dm,subdm);CHKERRQ(ierr);
117   PetscFunctionReturn(0);
118 }
119 
120 #undef __FUNCT__
121 #define __FUNCT__ "DMSubDomainRestrictHook_DMSNES"
122 /* This could restrict auxiliary information to the coarse level.
123  */
124 static PetscErrorCode DMSubDomainRestrictHook_DMSNES(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
125 {
126 
127   PetscFunctionBegin;
128   PetscFunctionReturn(0);
129 }
130 
131 #undef __FUNCT__
132 #define __FUNCT__ "DMRefineHook_DMSNES"
133 static PetscErrorCode DMRefineHook_DMSNES(DM dm,DM dmf,void *ctx)
134 {
135   PetscErrorCode ierr;
136 
137   PetscFunctionBegin;
138   ierr = DMCopyDMSNES(dm,dmf);CHKERRQ(ierr);
139   PetscFunctionReturn(0);
140 }
141 
142 #undef __FUNCT__
143 #define __FUNCT__ "DMInterpolateHook_DMSNES"
144 /* This could restrict auxiliary information to the coarse level.
145  */
146 static PetscErrorCode DMInterpolateHook_DMSNES(DM dm,Mat Interp,DM dmf,void *ctx)
147 {
148 
149   PetscFunctionBegin;
150   PetscFunctionReturn(0);
151 }
152 
153 #undef __FUNCT__
154 #define __FUNCT__ "DMSNESCopy"
155 /*@C
156    DMSNESCopy - copies the information in a DMSNES to another DMSNES
157 
158    Not Collective
159 
160    Input Argument:
161 +  kdm - Original DMSNES
162 -  nkdm - DMSNES to receive the data, should have been created with DMSNESCreate()
163 
164    Level: developer
165 
166 .seealso: DMSNESCreate(), DMSNESDestroy()
167 @*/
168 PetscErrorCode DMSNESCopy(DMSNES kdm,DMSNES nkdm)
169 {
170   PetscErrorCode ierr;
171 
172   PetscFunctionBegin;
173   PetscValidHeaderSpecific(kdm,DMSNES_CLASSID,1);
174   PetscValidHeaderSpecific(nkdm,DMSNES_CLASSID,2);
175   nkdm->ops->computefunction  = kdm->ops->computefunction;
176   nkdm->ops->computejacobian  = kdm->ops->computejacobian;
177   nkdm->ops->computegs        = kdm->ops->computegs;
178   nkdm->ops->computeobjective = kdm->ops->computeobjective;
179   nkdm->ops->computepjacobian = kdm->ops->computepjacobian;
180   nkdm->ops->computepfunction = kdm->ops->computepfunction;
181   nkdm->ops->destroy          = kdm->ops->destroy;
182   nkdm->ops->duplicate        = kdm->ops->duplicate;
183 
184   nkdm->functionctx  = kdm->functionctx;
185   nkdm->gsctx        = kdm->gsctx;
186   nkdm->pctx         = kdm->pctx;
187   nkdm->jacobianctx  = kdm->jacobianctx;
188   nkdm->objectivectx = kdm->objectivectx;
189   nkdm->data         = kdm->data;
190 
191   /*
192   nkdm->fortran_func_pointers[0] = kdm->fortran_func_pointers[0];
193   nkdm->fortran_func_pointers[1] = kdm->fortran_func_pointers[1];
194   nkdm->fortran_func_pointers[2] = kdm->fortran_func_pointers[2];
195   */
196 
197   /* implementation specific copy hooks */
198   if (kdm->ops->duplicate) {ierr = (*kdm->ops->duplicate)(kdm,nkdm);CHKERRQ(ierr);}
199   PetscFunctionReturn(0);
200 }
201 
202 #undef __FUNCT__
203 #define __FUNCT__ "DMGetDMSNES"
204 /*@C
205    DMGetDMSNES - get read-only private DMSNES context from a DM
206 
207    Not Collective
208 
209    Input Argument:
210 .  dm - DM to be used with SNES
211 
212    Output Argument:
213 .  snesdm - private DMSNES context
214 
215    Level: developer
216 
217    Notes:
218    Use DMGetDMSNESWrite() if write access is needed. The DMSNESSetXXX API should be used wherever possible.
219 
220 .seealso: DMGetDMSNESWrite()
221 @*/
222 PetscErrorCode DMGetDMSNES(DM dm,DMSNES *snesdm)
223 {
224   PetscErrorCode ierr;
225 
226   PetscFunctionBegin;
227   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
228   *snesdm = (DMSNES) dm->dmsnes;
229   if (!*snesdm) {
230     ierr = PetscInfo(dm,"Creating new DMSNES\n");CHKERRQ(ierr);
231     ierr = DMSNESCreate(PetscObjectComm((PetscObject)dm),snesdm);CHKERRQ(ierr);
232 
233     dm->dmsnes = (PetscObject) *snesdm;
234 
235     ierr = DMCoarsenHookAdd(dm,DMCoarsenHook_DMSNES,DMRestrictHook_DMSNES,NULL);CHKERRQ(ierr);
236     ierr = DMRefineHookAdd(dm,DMRefineHook_DMSNES,DMInterpolateHook_DMSNES,NULL);CHKERRQ(ierr);
237     ierr = DMSubDomainHookAdd(dm,DMSubDomainHook_DMSNES,DMSubDomainRestrictHook_DMSNES,NULL);CHKERRQ(ierr);
238   }
239   PetscFunctionReturn(0);
240 }
241 
242 #undef __FUNCT__
243 #define __FUNCT__ "DMGetDMSNESWrite"
244 /*@C
245    DMGetDMSNESWrite - get write access to private DMSNES context from a DM
246 
247    Not Collective
248 
249    Input Argument:
250 .  dm - DM to be used with SNES
251 
252    Output Argument:
253 .  snesdm - private DMSNES context
254 
255    Level: developer
256 
257 .seealso: DMGetDMSNES()
258 @*/
259 PetscErrorCode DMGetDMSNESWrite(DM dm,DMSNES *snesdm)
260 {
261   PetscErrorCode ierr;
262   DMSNES         sdm;
263 
264   PetscFunctionBegin;
265   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
266   ierr = DMGetDMSNES(dm,&sdm);CHKERRQ(ierr);
267   if (!sdm->originaldm) sdm->originaldm = dm;
268   if (sdm->originaldm != dm) {  /* Copy on write */
269     DMSNES oldsdm = sdm;
270     ierr       = PetscInfo(dm,"Copying DMSNES due to write\n");CHKERRQ(ierr);
271     ierr       = DMSNESCreate(PetscObjectComm((PetscObject)dm),&sdm);CHKERRQ(ierr);
272     ierr       = DMSNESCopy(oldsdm,sdm);CHKERRQ(ierr);
273     ierr       = DMSNESDestroy((DMSNES*)&dm->dmsnes);CHKERRQ(ierr);
274     dm->dmsnes = (PetscObject)sdm;
275   }
276   *snesdm = sdm;
277   PetscFunctionReturn(0);
278 }
279 
280 #undef __FUNCT__
281 #define __FUNCT__ "DMCopyDMSNES"
282 /*@C
283    DMCopyDMSNES - copies a DM context to a new DM
284 
285    Logically Collective
286 
287    Input Arguments:
288 +  dmsrc - DM to obtain context from
289 -  dmdest - DM to add context to
290 
291    Level: developer
292 
293    Note:
294    The context is copied by reference. This function does not ensure that a context exists.
295 
296 .seealso: DMGetDMSNES(), SNESSetDM()
297 @*/
298 PetscErrorCode DMCopyDMSNES(DM dmsrc,DM dmdest)
299 {
300   PetscErrorCode ierr;
301 
302   PetscFunctionBegin;
303   PetscValidHeaderSpecific(dmsrc,DM_CLASSID,1);
304   PetscValidHeaderSpecific(dmdest,DM_CLASSID,2);
305   if (!dmdest->dmsnes) {ierr = DMSNESCreate(PetscObjectComm((PetscObject) dmdest), (DMSNES *) &dmdest->dmsnes);CHKERRQ(ierr);}
306   ierr = DMSNESCopy((DMSNES) dmsrc->dmsnes, (DMSNES) dmdest->dmsnes);CHKERRQ(ierr);
307   ierr = DMCoarsenHookAdd(dmdest,DMCoarsenHook_DMSNES,NULL,NULL);CHKERRQ(ierr);
308   ierr = DMRefineHookAdd(dmdest,DMRefineHook_DMSNES,NULL,NULL);CHKERRQ(ierr);
309   ierr = DMSubDomainHookAdd(dmdest,DMSubDomainHook_DMSNES,DMSubDomainRestrictHook_DMSNES,NULL);CHKERRQ(ierr);
310   PetscFunctionReturn(0);
311 }
312 
313 #undef __FUNCT__
314 #define __FUNCT__ "DMSNESSetFunction"
315 /*@C
316    DMSNESSetFunction - set SNES residual evaluation function
317 
318    Not Collective
319 
320    Input Arguments:
321 +  dm - DM to be used with SNES
322 .  f - residual evaluation function; see SNESFunction for details
323 -  ctx - context for residual evaluation
324 
325    Level: advanced
326 
327    Note:
328    SNESSetFunction() is normally used, but it calls this function internally because the user context is actually
329    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
330    not. If DM took a more central role at some later date, this could become the primary method of setting the residual.
331 
332 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian(), SNESFunction
333 @*/
334 PetscErrorCode DMSNESSetFunction(DM dm,PetscErrorCode (*f)(SNES,Vec,Vec,void*),void *ctx)
335 {
336   PetscErrorCode ierr;
337   DMSNES         sdm;
338 
339   PetscFunctionBegin;
340   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
341   if (f || ctx) {
342     ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
343   }
344   if (f) sdm->ops->computefunction = f;
345   if (ctx) sdm->functionctx = ctx;
346   PetscFunctionReturn(0);
347 }
348 
349 #undef __FUNCT__
350 #define __FUNCT__ "DMSNESGetFunction"
351 /*@C
352    DMSNESGetFunction - get SNES residual evaluation function
353 
354    Not Collective
355 
356    Input Argument:
357 .  dm - DM to be used with SNES
358 
359    Output Arguments:
360 +  f - residual evaluation function; see SNESFunction for details
361 -  ctx - context for residual evaluation
362 
363    Level: advanced
364 
365    Note:
366    SNESGetFunction() is normally used, but it calls this function internally because the user context is actually
367    associated with the DM.
368 
369 .seealso: DMSNESSetContext(), DMSNESSetFunction(), SNESSetFunction(), SNESFunction
370 @*/
371 PetscErrorCode DMSNESGetFunction(DM dm,PetscErrorCode (**f)(SNES,Vec,Vec,void*),void **ctx)
372 {
373   PetscErrorCode ierr;
374   DMSNES         sdm;
375 
376   PetscFunctionBegin;
377   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
378   ierr = DMGetDMSNES(dm,&sdm);CHKERRQ(ierr);
379   if (f) *f = sdm->ops->computefunction;
380   if (ctx) *ctx = sdm->functionctx;
381   PetscFunctionReturn(0);
382 }
383 
384 #undef __FUNCT__
385 #define __FUNCT__ "DMSNESSetObjective"
386 /*@C
387    DMSNESSetObjective - set SNES objective evaluation function
388 
389    Not Collective
390 
391    Input Arguments:
392 +  dm - DM to be used with SNES
393 .  obj - objective evaluation function; see SNESObjectiveFunction for details
394 -  ctx - context for residual evaluation
395 
396    Level: advanced
397 
398 .seealso: DMSNESSetContext(), SNESGetObjective(), DMSNESSetFunction()
399 @*/
400 PetscErrorCode DMSNESSetObjective(DM dm,PetscErrorCode (*obj)(SNES,Vec,PetscReal*,void*),void *ctx)
401 {
402   PetscErrorCode ierr;
403   DMSNES         sdm;
404 
405   PetscFunctionBegin;
406   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
407   if (obj || ctx) {
408     ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
409   }
410   if (obj) sdm->ops->computeobjective = obj;
411   if (ctx) sdm->objectivectx = ctx;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "DMSNESGetObjective"
417 /*@C
418    DMSNESGetObjective - get SNES objective evaluation function
419 
420    Not Collective
421 
422    Input Argument:
423 .  dm - DM to be used with SNES
424 
425    Output Arguments:
426 +  obj- residual evaluation function; see SNESObjectiveFunction for details
427 -  ctx - context for residual evaluation
428 
429    Level: advanced
430 
431    Note:
432    SNESGetFunction() is normally used, but it calls this function internally because the user context is actually
433    associated with the DM.
434 
435 .seealso: DMSNESSetContext(), DMSNESSetObjective(), SNESSetFunction()
436 @*/
437 PetscErrorCode DMSNESGetObjective(DM dm,PetscErrorCode (**obj)(SNES,Vec,PetscReal*,void*),void **ctx)
438 {
439   PetscErrorCode ierr;
440   DMSNES         sdm;
441 
442   PetscFunctionBegin;
443   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
444   ierr = DMGetDMSNES(dm,&sdm);CHKERRQ(ierr);
445   if (obj) *obj = sdm->ops->computeobjective;
446   if (ctx) *ctx = sdm->objectivectx;
447   PetscFunctionReturn(0);
448 }
449 
450 #undef __FUNCT__
451 #define __FUNCT__ "DMSNESSetNGS"
452 /*@C
453    DMSNESSetNGS - set SNES Gauss-Seidel relaxation function
454 
455    Not Collective
456 
457    Input Argument:
458 +  dm - DM to be used with SNES
459 .  f  - relaxation function, see SNESGSFunction
460 -  ctx - context for residual evaluation
461 
462    Level: advanced
463 
464    Note:
465    SNESSetNGS() is normally used, but it calls this function internally because the user context is actually
466    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
467    not. If DM took a more central role at some later date, this could become the primary method of setting the residual.
468 
469 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian(), DMSNESSetFunction(), SNESGSFunction
470 @*/
471 PetscErrorCode DMSNESSetNGS(DM dm,PetscErrorCode (*f)(SNES,Vec,Vec,void*),void *ctx)
472 {
473   PetscErrorCode ierr;
474   DMSNES         sdm;
475 
476   PetscFunctionBegin;
477   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
478   if (f || ctx) {
479     ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
480   }
481   if (f) sdm->ops->computegs = f;
482   if (ctx) sdm->gsctx = ctx;
483   PetscFunctionReturn(0);
484 }
485 
486 #undef __FUNCT__
487 #define __FUNCT__ "DMSNESGetNGS"
488 /*@C
489    DMSNESGetNGS - get SNES Gauss-Seidel relaxation function
490 
491    Not Collective
492 
493    Input Argument:
494 .  dm - DM to be used with SNES
495 
496    Output Arguments:
497 +  f - relaxation function which performs Gauss-Seidel sweeps, see SNESGSFunction
498 -  ctx - context for residual evaluation
499 
500    Level: advanced
501 
502    Note:
503    SNESGetNGS() is normally used, but it calls this function internally because the user context is actually
504    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
505    not. If DM took a more central role at some later date, this could become the primary method of setting the residual.
506 
507 .seealso: DMSNESSetContext(), SNESGetNGS(), DMSNESGetJacobian(), DMSNESGetFunction(), SNESNGSFunction
508 @*/
509 PetscErrorCode DMSNESGetNGS(DM dm,PetscErrorCode (**f)(SNES,Vec,Vec,void*),void **ctx)
510 {
511   PetscErrorCode ierr;
512   DMSNES         sdm;
513 
514   PetscFunctionBegin;
515   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
516   ierr = DMGetDMSNES(dm,&sdm);CHKERRQ(ierr);
517   if (f) *f = sdm->ops->computegs;
518   if (ctx) *ctx = sdm->gsctx;
519   PetscFunctionReturn(0);
520 }
521 
522 #undef __FUNCT__
523 #define __FUNCT__ "DMSNESSetJacobian"
524 /*@C
525    DMSNESSetJacobian - set SNES Jacobian evaluation function
526 
527    Not Collective
528 
529    Input Argument:
530 +  dm - DM to be used with SNES
531 .  J - Jacobian evaluation function
532 -  ctx - context for residual evaluation
533 
534    Level: advanced
535 
536    Note:
537    SNESSetJacobian() is normally used, but it calls this function internally because the user context is actually
538    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
539    not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian.
540 
541 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESGetJacobian(), SNESSetJacobian(), SNESJacobianFunction
542 @*/
543 PetscErrorCode DMSNESSetJacobian(DM dm,PetscErrorCode (*J)(SNES,Vec,Mat,Mat,void*),void *ctx)
544 {
545   PetscErrorCode ierr;
546   DMSNES         sdm;
547 
548   PetscFunctionBegin;
549   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
550   if (J || ctx) {
551     ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
552   }
553   if (J) sdm->ops->computejacobian = J;
554   if (ctx) sdm->jacobianctx = ctx;
555   PetscFunctionReturn(0);
556 }
557 
558 #undef __FUNCT__
559 #define __FUNCT__ "DMSNESGetJacobian"
560 /*@C
561    DMSNESGetJacobian - get SNES Jacobian evaluation function
562 
563    Not Collective
564 
565    Input Argument:
566 .  dm - DM to be used with SNES
567 
568    Output Arguments:
569 +  J - Jacobian evaluation function; see SNESJacobianFunction for all calling sequence
570 -  ctx - context for residual evaluation
571 
572    Level: advanced
573 
574    Note:
575    SNESGetJacobian() is normally used, but it calls this function internally because the user context is actually
576    associated with the DM.  This makes the interface consistent regardless of whether the user interacts with a DM or
577    not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian.
578 
579 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian(), SNESJacobianFunction
580 @*/
581 PetscErrorCode DMSNESGetJacobian(DM dm,PetscErrorCode (**J)(SNES,Vec,Mat,Mat,void*),void **ctx)
582 {
583   PetscErrorCode ierr;
584   DMSNES         sdm;
585 
586   PetscFunctionBegin;
587   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
588   ierr = DMGetDMSNES(dm,&sdm);CHKERRQ(ierr);
589   if (J) *J = sdm->ops->computejacobian;
590   if (ctx) *ctx = sdm->jacobianctx;
591   PetscFunctionReturn(0);
592 }
593 
594 #undef __FUNCT__
595 #define __FUNCT__ "DMSNESSetPicard"
596 /*@C
597    DMSNESSetPicard - set SNES Picard iteration matrix and RHS evaluation functions.
598 
599    Not Collective
600 
601    Input Argument:
602 +  dm - DM to be used with SNES
603 .  b - RHS evaluation function
604 .  J - Picard matrix evaluation function
605 -  ctx - context for residual evaluation
606 
607    Level: advanced
608 
609 .seealso: SNESSetPicard(), DMSNESSetFunction(), DMSNESSetJacobian()
610 @*/
611 PetscErrorCode DMSNESSetPicard(DM dm,PetscErrorCode (*b)(SNES,Vec,Vec,void*),PetscErrorCode (*J)(SNES,Vec,Mat,Mat,void*),void *ctx)
612 {
613   PetscErrorCode ierr;
614   DMSNES         sdm;
615 
616   PetscFunctionBegin;
617   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
618   ierr = DMGetDMSNES(dm,&sdm);CHKERRQ(ierr);
619   if (b) sdm->ops->computepfunction = b;
620   if (J) sdm->ops->computepjacobian = J;
621   if (ctx) sdm->pctx = ctx;
622   PetscFunctionReturn(0);
623 }
624 
625 #undef __FUNCT__
626 #define __FUNCT__ "DMSNESGetPicard"
627 /*@C
628    DMSNESGetPicard - get SNES Picard iteration evaluation functions
629 
630    Not Collective
631 
632    Input Argument:
633 .  dm - DM to be used with SNES
634 
635    Output Arguments:
636 +  b - RHS evaluation function; see SNESFunction for details
637 .  J  - RHS evaluation function; see SNESJacobianFunction for detailsa
638 -  ctx - context for residual evaluation
639 
640    Level: advanced
641 
642 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian()
643 @*/
644 PetscErrorCode DMSNESGetPicard(DM dm,PetscErrorCode (**b)(SNES,Vec,Vec,void*),PetscErrorCode (**J)(SNES,Vec,Mat,Mat,void*),void **ctx)
645 {
646   PetscErrorCode ierr;
647   DMSNES         sdm;
648 
649   PetscFunctionBegin;
650   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
651   ierr = DMGetDMSNES(dm,&sdm);CHKERRQ(ierr);
652   if (b) *b = sdm->ops->computepfunction;
653   if (J) *J = sdm->ops->computepjacobian;
654   if (ctx) *ctx = sdm->pctx;
655   PetscFunctionReturn(0);
656 }
657