xref: /petsc/src/snes/utils/dmdasnes.c (revision 00d931fe9835bef04c3bcd2a9a1bf118d64cc4c2)
1 #include <petscdmda.h>          /*I "petscdmda.h" I*/
2 #include <petsc/private/dmimpl.h>
3 #include <petsc/private/snesimpl.h>   /*I "petscsnes.h" I*/
4 
5 /* This structure holds the user-provided DMDA callbacks */
6 typedef struct {
7   PetscErrorCode (*residuallocal)(DMDALocalInfo*,void*,void*,void*);
8   PetscErrorCode (*jacobianlocal)(DMDALocalInfo*,void*,Mat,Mat,void*);
9   PetscErrorCode (*objectivelocal)(DMDALocalInfo*,void*,PetscReal*,void*);
10   void       *residuallocalctx;
11   void       *jacobianlocalctx;
12   void       *objectivelocalctx;
13   InsertMode residuallocalimode;
14 
15   /*   For Picard iteration defined locally */
16   PetscErrorCode (*rhsplocal)(DMDALocalInfo*,void*,void*,void*);
17   PetscErrorCode (*jacobianplocal)(DMDALocalInfo*,void*,Mat,Mat,void*);
18   void *picardlocalctx;
19 } DMSNES_DA;
20 
21 #undef __FUNCT__
22 #define __FUNCT__ "DMSNESDestroy_DMDA"
23 static PetscErrorCode DMSNESDestroy_DMDA(DMSNES sdm)
24 {
25   PetscErrorCode ierr;
26 
27   PetscFunctionBegin;
28   ierr = PetscFree(sdm->data);CHKERRQ(ierr);
29   PetscFunctionReturn(0);
30 }
31 
32 #undef __FUNCT__
33 #define __FUNCT__ "DMSNESDuplicate_DMDA"
34 static PetscErrorCode DMSNESDuplicate_DMDA(DMSNES oldsdm,DMSNES sdm)
35 {
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   ierr = PetscNewLog(sdm,(DMSNES_DA**)&sdm->data);CHKERRQ(ierr);
40   if (oldsdm->data) {
41     ierr = PetscMemcpy(sdm->data,oldsdm->data,sizeof(DMSNES_DA));CHKERRQ(ierr);
42   }
43   PetscFunctionReturn(0);
44 }
45 
46 
47 #undef __FUNCT__
48 #define __FUNCT__ "DMDASNESGetContext"
49 static PetscErrorCode DMDASNESGetContext(DM dm,DMSNES sdm,DMSNES_DA  **dmdasnes)
50 {
51   PetscErrorCode ierr;
52 
53   PetscFunctionBegin;
54   *dmdasnes = NULL;
55   if (!sdm->data) {
56     ierr = PetscNewLog(dm,(DMSNES_DA**)&sdm->data);CHKERRQ(ierr);
57     sdm->ops->destroy   = DMSNESDestroy_DMDA;
58     sdm->ops->duplicate = DMSNESDuplicate_DMDA;
59   }
60   *dmdasnes = (DMSNES_DA*)sdm->data;
61   PetscFunctionReturn(0);
62 }
63 
64 #undef __FUNCT__
65 #define __FUNCT__ "SNESComputeFunction_DMDA"
66 static PetscErrorCode SNESComputeFunction_DMDA(SNES snes,Vec X,Vec F,void *ctx)
67 {
68   PetscErrorCode ierr;
69   DM             dm;
70   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
71   DMDALocalInfo  info;
72   Vec            Xloc;
73   void           *x,*f;
74 
75   PetscFunctionBegin;
76   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
77   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
78   PetscValidHeaderSpecific(F,VEC_CLASSID,3);
79   if (!dmdasnes->residuallocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
80   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
81   ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr);
82   ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
83   ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
84   ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr);
85   ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr);
86   switch (dmdasnes->residuallocalimode) {
87   case INSERT_VALUES: {
88     ierr = DMDAVecGetArray(dm,F,&f);CHKERRQ(ierr);
89     ierr = PetscLogEventBegin(SNES_FunctionEval,snes,X,F,0);CHKERRQ(ierr);
90     CHKMEMQ;
91     ierr = (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);CHKERRQ(ierr);
92     CHKMEMQ;
93     ierr = PetscLogEventEnd(SNES_FunctionEval,snes,X,F,0);CHKERRQ(ierr);
94     ierr = DMDAVecRestoreArray(dm,F,&f);CHKERRQ(ierr);
95   } break;
96   case ADD_VALUES: {
97     Vec Floc;
98     ierr = DMGetLocalVector(dm,&Floc);CHKERRQ(ierr);
99     ierr = VecZeroEntries(Floc);CHKERRQ(ierr);
100     ierr = DMDAVecGetArray(dm,Floc,&f);CHKERRQ(ierr);
101     ierr = PetscLogEventBegin(SNES_FunctionEval,snes,X,F,0);CHKERRQ(ierr);
102     CHKMEMQ;
103     ierr = (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);CHKERRQ(ierr);
104     CHKMEMQ;
105     ierr = PetscLogEventEnd(SNES_FunctionEval,snes,X,F,0);CHKERRQ(ierr);
106     ierr = DMDAVecRestoreArray(dm,Floc,&f);CHKERRQ(ierr);
107     ierr = VecZeroEntries(F);CHKERRQ(ierr);
108     ierr = DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr);
109     ierr = DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr);
110     ierr = DMRestoreLocalVector(dm,&Floc);CHKERRQ(ierr);
111   } break;
112   default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
113   }
114   ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr);
115   ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr);
116   if (snes->domainerror) {
117     ierr = VecSetInf(F);CHKERRQ(ierr);
118   }
119   PetscFunctionReturn(0);
120 }
121 
122 #undef __FUNCT__
123 #define __FUNCT__ "SNESComputeObjective_DMDA"
124 static PetscErrorCode SNESComputeObjective_DMDA(SNES snes,Vec X,PetscReal *ob,void *ctx)
125 {
126   PetscErrorCode ierr;
127   DM             dm;
128   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
129   DMDALocalInfo  info;
130   Vec            Xloc;
131   void           *x;
132 
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
135   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
136   PetscValidPointer(ob,3);
137   if (!dmdasnes->objectivelocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
138   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
139   ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr);
140   ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
141   ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
142   ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr);
143   ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr);
144   CHKMEMQ;
145   ierr = (*dmdasnes->objectivelocal)(&info,x,ob,dmdasnes->objectivelocalctx);CHKERRQ(ierr);
146   CHKMEMQ;
147   ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr);
148   ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr);
149   PetscFunctionReturn(0);
150 }
151 
152 
153 #undef __FUNCT__
154 #define __FUNCT__ "SNESComputeJacobian_DMDA"
155 PetscErrorCode SNESComputeJacobian_DMDA(SNES snes,Vec X,Mat A,Mat B,void *ctx)
156 {
157   PetscErrorCode ierr;
158   DM             dm;
159   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
160   DMDALocalInfo  info;
161   Vec            Xloc;
162   void           *x;
163 
164   PetscFunctionBegin;
165   if (!dmdasnes->residuallocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
166   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
167 
168   if (dmdasnes->jacobianlocal) {
169     ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr);
170     ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
171     ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
172     ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr);
173     ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr);
174     CHKMEMQ;
175     ierr = (*dmdasnes->jacobianlocal)(&info,x,A,B,dmdasnes->jacobianlocalctx);CHKERRQ(ierr);
176     CHKMEMQ;
177     ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr);
178     ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr);
179   } else {
180     MatFDColoring fdcoloring;
181     ierr = PetscObjectQuery((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject*)&fdcoloring);CHKERRQ(ierr);
182     if (!fdcoloring) {
183       ISColoring coloring;
184 
185       ierr = DMCreateColoring(dm,dm->coloringtype,&coloring);CHKERRQ(ierr);
186       ierr = MatFDColoringCreate(B,coloring,&fdcoloring);CHKERRQ(ierr);
187       switch (dm->coloringtype) {
188       case IS_COLORING_GLOBAL:
189         ierr = MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)(void))SNESComputeFunction_DMDA,dmdasnes);CHKERRQ(ierr);
190         break;
191       default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"No support for coloring type '%s'",ISColoringTypes[dm->coloringtype]);
192       }
193       ierr = PetscObjectSetOptionsPrefix((PetscObject)fdcoloring,((PetscObject)dm)->prefix);CHKERRQ(ierr);
194       ierr = MatFDColoringSetFromOptions(fdcoloring);CHKERRQ(ierr);
195       ierr = MatFDColoringSetUp(B,coloring,fdcoloring);CHKERRQ(ierr);
196       ierr = ISColoringDestroy(&coloring);CHKERRQ(ierr);
197       ierr = PetscObjectCompose((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject)fdcoloring);CHKERRQ(ierr);
198       ierr = PetscObjectDereference((PetscObject)fdcoloring);CHKERRQ(ierr);
199 
200       /* The following breaks an ugly reference counting loop that deserves a paragraph. MatFDColoringApply() will call
201        * VecDuplicate() with the state Vec and store inside the MatFDColoring. This Vec will duplicate the Vec, but the
202        * MatFDColoring is composed with the DM. We dereference the DM here so that the reference count will eventually
203        * drop to 0. Note the code in DMDestroy() that exits early for a negative reference count. That code path will be
204        * taken when the PetscObjectList for the Vec inside MatFDColoring is destroyed.
205        */
206       ierr = PetscObjectDereference((PetscObject)dm);CHKERRQ(ierr);
207     }
208     ierr  = MatFDColoringApply(B,fdcoloring,X,snes);CHKERRQ(ierr);
209   }
210   /* This will be redundant if the user called both, but it's too common to forget. */
211   if (A != B) {
212     ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
213     ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
214   }
215   PetscFunctionReturn(0);
216 }
217 
218 #undef __FUNCT__
219 #define __FUNCT__ "DMDASNESSetFunctionLocal"
220 /*@C
221    DMDASNESSetFunctionLocal - set a local residual evaluation function
222 
223    Logically Collective
224 
225    Input Arguments:
226 +  dm - DM to associate callback with
227 .  imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
228 .  func - local residual evaluation
229 -  ctx - optional context for local residual evaluation
230 
231    Calling sequence:
232    For PetscErrorCode (*func)(DMDALocalInfo *info,void *x, void *f, void *ctx),
233 +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
234 .  x - dimensional pointer to state at which to evaluate residual (e.g. PetscScalar *x or **x or ***x)
235 .  f - dimensional pointer to residual, write the residual here (e.g. PetscScalar *f or **f or ***f)
236 -  ctx - optional context passed above
237 
238    Level: beginner
239 
240 .seealso: DMDASNESSetJacobianLocal(), DMSNESSetFunction(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
241 @*/
242 PetscErrorCode DMDASNESSetFunctionLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),void *ctx)
243 {
244   PetscErrorCode ierr;
245   DMSNES         sdm;
246   DMSNES_DA      *dmdasnes;
247 
248   PetscFunctionBegin;
249   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
250   ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
251   ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr);
252 
253   dmdasnes->residuallocalimode = imode;
254   dmdasnes->residuallocal      = func;
255   dmdasnes->residuallocalctx   = ctx;
256 
257   ierr = DMSNESSetFunction(dm,SNESComputeFunction_DMDA,dmdasnes);CHKERRQ(ierr);
258   if (!sdm->ops->computejacobian) {  /* Call us for the Jacobian too, can be overridden by the user. */
259     ierr = DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);CHKERRQ(ierr);
260   }
261   PetscFunctionReturn(0);
262 }
263 
264 #undef __FUNCT__
265 #define __FUNCT__ "DMDASNESSetJacobianLocal"
266 /*@C
267    DMDASNESSetJacobianLocal - set a local Jacobian evaluation function
268 
269    Logically Collective
270 
271    Input Arguments:
272 +  dm - DM to associate callback with
273 .  func - local Jacobian evaluation
274 -  ctx - optional context for local Jacobian evaluation
275 
276    Calling sequence:
277    For PetscErrorCode (*func)(DMDALocalInfo *info,void *x,Mat J,Mat M,void *ctx),
278 +  info - DMDALocalInfo defining the subdomain to evaluate the Jacobian at
279 .  x - dimensional pointer to state at which to evaluate Jacobian (e.g. PetscScalar *x or **x or ***x)
280 .  J - Mat object for the Jacobian
281 .  M - Mat object for the Jacobian preconditioner matrix
282 -  ctx - optional context passed above
283 
284    Level: beginner
285 
286 .seealso: DMDASNESSetFunctionLocal(), DMSNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
287 @*/
288 PetscErrorCode DMDASNESSetJacobianLocal(DM dm,PetscErrorCode (*func)(DMDALocalInfo*,void*,Mat,Mat,void*),void *ctx)
289 {
290   PetscErrorCode ierr;
291   DMSNES         sdm;
292   DMSNES_DA      *dmdasnes;
293 
294   PetscFunctionBegin;
295   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
296   ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
297   ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr);
298 
299   dmdasnes->jacobianlocal    = func;
300   dmdasnes->jacobianlocalctx = ctx;
301 
302   ierr = DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);CHKERRQ(ierr);
303   PetscFunctionReturn(0);
304 }
305 
306 
307 #undef __FUNCT__
308 #define __FUNCT__ "DMDASNESSetObjectiveLocal"
309 /*@C
310    DMDASNESSetObjectiveLocal - set a local residual evaluation function
311 
312    Logically Collective
313 
314    Input Arguments:
315 +  dm - DM to associate callback with
316 .  func - local objective evaluation
317 -  ctx - optional context for local residual evaluation
318 
319    Calling sequence for func:
320 +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
321 .  x - dimensional pointer to state at which to evaluate residual
322 .  ob - eventual objective value
323 -  ctx - optional context passed above
324 
325    Level: beginner
326 
327 .seealso: DMSNESSetFunction(), DMDASNESSetJacobianLocal(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
328 @*/
329 PetscErrorCode DMDASNESSetObjectiveLocal(DM dm,DMDASNESObjective func,void *ctx)
330 {
331   PetscErrorCode ierr;
332   DMSNES         sdm;
333   DMSNES_DA      *dmdasnes;
334 
335   PetscFunctionBegin;
336   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
337   ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
338   ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr);
339 
340   dmdasnes->objectivelocal    = func;
341   dmdasnes->objectivelocalctx = ctx;
342 
343   ierr = DMSNESSetObjective(dm,SNESComputeObjective_DMDA,dmdasnes);CHKERRQ(ierr);
344   PetscFunctionReturn(0);
345 }
346 
347 #undef __FUNCT__
348 #define __FUNCT__ "SNESComputePicard_DMDA"
349 static PetscErrorCode SNESComputePicard_DMDA(SNES snes,Vec X,Vec F,void *ctx)
350 {
351   PetscErrorCode ierr;
352   DM             dm;
353   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
354   DMDALocalInfo  info;
355   Vec            Xloc;
356   void           *x,*f;
357 
358   PetscFunctionBegin;
359   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
360   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
361   PetscValidHeaderSpecific(F,VEC_CLASSID,3);
362   if (!dmdasnes->rhsplocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
363   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
364   ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr);
365   ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
366   ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
367   ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr);
368   ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr);
369   switch (dmdasnes->residuallocalimode) {
370   case INSERT_VALUES: {
371     ierr = DMDAVecGetArray(dm,F,&f);CHKERRQ(ierr);
372     CHKMEMQ;
373     ierr = (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);CHKERRQ(ierr);
374     CHKMEMQ;
375     ierr = DMDAVecRestoreArray(dm,F,&f);CHKERRQ(ierr);
376   } break;
377   case ADD_VALUES: {
378     Vec Floc;
379     ierr = DMGetLocalVector(dm,&Floc);CHKERRQ(ierr);
380     ierr = VecZeroEntries(Floc);CHKERRQ(ierr);
381     ierr = DMDAVecGetArray(dm,Floc,&f);CHKERRQ(ierr);
382     CHKMEMQ;
383     ierr = (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);CHKERRQ(ierr);
384     CHKMEMQ;
385     ierr = DMDAVecRestoreArray(dm,Floc,&f);CHKERRQ(ierr);
386     ierr = VecZeroEntries(F);CHKERRQ(ierr);
387     ierr = DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr);
388     ierr = DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr);
389     ierr = DMRestoreLocalVector(dm,&Floc);CHKERRQ(ierr);
390   } break;
391   default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
392   }
393   ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr);
394   ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr);
395   PetscFunctionReturn(0);
396 }
397 
398 #undef __FUNCT__
399 #define __FUNCT__ "SNESComputePicardJacobian_DMDA"
400 static PetscErrorCode SNESComputePicardJacobian_DMDA(SNES snes,Vec X,Mat A,Mat B,void *ctx)
401 {
402   PetscErrorCode ierr;
403   DM             dm;
404   DMSNES_DA      *dmdasnes = (DMSNES_DA*)ctx;
405   DMDALocalInfo  info;
406   Vec            Xloc;
407   void           *x;
408 
409   PetscFunctionBegin;
410   if (!dmdasnes->jacobianplocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
411   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
412 
413   ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr);
414   ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
415   ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
416   ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr);
417   ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr);
418   CHKMEMQ;
419   ierr = (*dmdasnes->jacobianplocal)(&info,x,A,B,dmdasnes->picardlocalctx);CHKERRQ(ierr);
420   CHKMEMQ;
421   ierr  = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr);
422   ierr  = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr);
423   if (A != B) {
424     ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
425     ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
426   }
427   PetscFunctionReturn(0);
428 }
429 
430 #undef __FUNCT__
431 #define __FUNCT__ "DMDASNESSetPicardLocal"
432 /*@C
433    DMDASNESSetPicardLocal - set a local right hand side and matrix evaluation function for Picard iteration
434 
435    Logically Collective
436 
437    Input Arguments:
438 +  dm - DM to associate callback with
439 .  imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
440 .  func - local residual evaluation
441 -  ctx - optional context for local residual evaluation
442 
443    Calling sequence for func:
444 +  info - DMDALocalInfo defining the subdomain to evaluate the residual on
445 .  x - dimensional pointer to state at which to evaluate residual
446 .  f - dimensional pointer to residual, write the residual here
447 -  ctx - optional context passed above
448 
449    Notes:  The user must use
450     extern PetscErrorCode  SNESPicardComputeFunction(SNES,Vec,Vec,void*);
451     extern PetscErrorCode  SNESPicardComputeJacobian(SNES,Vec,Mat,Mat,MatStructure*,void*);
452     ierr = SNESSetFunction(snes,NULL,SNESPicardComputeFunction,&user);CHKERRQ(ierr);
453     in their code before calling this routine.
454 
455 
456    Level: beginner
457 
458 .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
459 @*/
460 PetscErrorCode DMDASNESSetPicardLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),
461                                       PetscErrorCode (*jac)(DMDALocalInfo*,void*,Mat,Mat,void*),void *ctx)
462 {
463   PetscErrorCode ierr;
464   DMSNES         sdm;
465   DMSNES_DA      *dmdasnes;
466 
467   PetscFunctionBegin;
468   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
469   ierr = DMGetDMSNESWrite(dm,&sdm);CHKERRQ(ierr);
470   ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr);
471 
472   dmdasnes->residuallocalimode = imode;
473   dmdasnes->rhsplocal          = func;
474   dmdasnes->jacobianplocal     = jac;
475   dmdasnes->picardlocalctx     = ctx;
476 
477   ierr = DMSNESSetPicard(dm,SNESComputePicard_DMDA,SNESComputePicardJacobian_DMDA,dmdasnes);CHKERRQ(ierr);
478   PetscFunctionReturn(0);
479 }
480