xref: /petsc/src/dm/impls/da/da2.c (revision 5ec1a3fa3a66d5e31f30db08e2b361315eb0c3c4)
1 
2 #include <petsc-private/daimpl.h>    /*I   "petscdmda.h"   I*/
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "DMView_DA_2d"
6 PetscErrorCode DMView_DA_2d(DM da,PetscViewer viewer)
7 {
8   PetscErrorCode ierr;
9   PetscMPIInt    rank;
10   PetscBool      iascii,isdraw,isbinary;
11   DM_DA          *dd = (DM_DA*)da->data;
12 #if defined(PETSC_HAVE_MATLAB_ENGINE)
13   PetscBool      ismatlab;
14 #endif
15 
16   PetscFunctionBegin;
17   ierr = MPI_Comm_rank(((PetscObject)da)->comm,&rank);CHKERRQ(ierr);
18 
19   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
20   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
21   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
22 #if defined(PETSC_HAVE_MATLAB_ENGINE)
23   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERMATLAB,&ismatlab);CHKERRQ(ierr);
24 #endif
25   if (iascii) {
26     PetscViewerFormat format;
27 
28     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
29     if (format != PETSC_VIEWER_ASCII_VTK && format != PETSC_VIEWER_ASCII_VTK_CELL) {
30       DMDALocalInfo info;
31       ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
32       ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
33       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Processor [%d] M %D N %D m %D n %D w %D s %D\n",rank,dd->M,dd->N,dd->m,dd->n,dd->w,dd->s);CHKERRQ(ierr);
34       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"X range of indices: %D %D, Y range of indices: %D %D\n",info.xs,info.xs+info.xm,info.ys,info.ys+info.ym);CHKERRQ(ierr);
35       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
36       ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);CHKERRQ(ierr);
37     } else {
38       ierr = DMView_DA_VTK(da,viewer);CHKERRQ(ierr);
39     }
40   } else if (isdraw) {
41     PetscDraw  draw;
42     double     ymin = -1*dd->s-1,ymax = dd->N+dd->s;
43     double     xmin = -1*dd->s-1,xmax = dd->M+dd->s;
44     double     x,y;
45     PetscInt   base,*idx;
46     char       node[10];
47     PetscBool  isnull;
48 
49     ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
50     ierr = PetscDrawIsNull(draw,&isnull);CHKERRQ(ierr); if (isnull) PetscFunctionReturn(0);
51     if (!dd->coordinates) {
52       ierr = PetscDrawSetCoordinates(draw,xmin,ymin,xmax,ymax);CHKERRQ(ierr);
53     }
54     ierr = PetscDrawSynchronizedClear(draw);CHKERRQ(ierr);
55 
56     /* first processor draw all node lines */
57     if (!rank) {
58       ymin = 0.0; ymax = dd->N - 1;
59       for (xmin=0; xmin<dd->M; xmin++) {
60         ierr = PetscDrawLine(draw,xmin,ymin,xmin,ymax,PETSC_DRAW_BLACK);CHKERRQ(ierr);
61       }
62       xmin = 0.0; xmax = dd->M - 1;
63       for (ymin=0; ymin<dd->N; ymin++) {
64         ierr = PetscDrawLine(draw,xmin,ymin,xmax,ymin,PETSC_DRAW_BLACK);CHKERRQ(ierr);
65       }
66     }
67     ierr = PetscDrawSynchronizedFlush(draw);CHKERRQ(ierr);
68     ierr = PetscDrawPause(draw);CHKERRQ(ierr);
69 
70     /* draw my box */
71     ymin = dd->ys; ymax = dd->ye - 1; xmin = dd->xs/dd->w;
72     xmax =(dd->xe-1)/dd->w;
73     ierr = PetscDrawLine(draw,xmin,ymin,xmax,ymin,PETSC_DRAW_RED);CHKERRQ(ierr);
74     ierr = PetscDrawLine(draw,xmin,ymin,xmin,ymax,PETSC_DRAW_RED);CHKERRQ(ierr);
75     ierr = PetscDrawLine(draw,xmin,ymax,xmax,ymax,PETSC_DRAW_RED);CHKERRQ(ierr);
76     ierr = PetscDrawLine(draw,xmax,ymin,xmax,ymax,PETSC_DRAW_RED);CHKERRQ(ierr);
77 
78     /* put in numbers */
79     base = (dd->base)/dd->w;
80     for (y=ymin; y<=ymax; y++) {
81       for (x=xmin; x<=xmax; x++) {
82         sprintf(node,"%d",(int)base++);
83         ierr = PetscDrawString(draw,x,y,PETSC_DRAW_BLACK,node);CHKERRQ(ierr);
84       }
85     }
86 
87     ierr = PetscDrawSynchronizedFlush(draw);CHKERRQ(ierr);
88     ierr = PetscDrawPause(draw);CHKERRQ(ierr);
89     /* overlay ghost numbers, useful for error checking */
90     /* put in numbers */
91 
92     base = 0; idx = dd->idx;
93     ymin = dd->Ys; ymax = dd->Ye; xmin = dd->Xs; xmax = dd->Xe;
94     for (y=ymin; y<ymax; y++) {
95       for (x=xmin; x<xmax; x++) {
96         if ((base % dd->w) == 0) {
97           sprintf(node,"%d",(int)(idx[base]/dd->w));
98           ierr = PetscDrawString(draw,x/dd->w,y,PETSC_DRAW_BLUE,node);CHKERRQ(ierr);
99         }
100         base++;
101       }
102     }
103     ierr = PetscDrawSynchronizedFlush(draw);CHKERRQ(ierr);
104     ierr = PetscDrawPause(draw);CHKERRQ(ierr);
105   } else if (isbinary){
106     ierr = DMView_DA_Binary(da,viewer);CHKERRQ(ierr);
107 #if defined(PETSC_HAVE_MATLAB_ENGINE)
108   } else if (ismatlab) {
109     ierr = DMView_DA_Matlab(da,viewer);CHKERRQ(ierr);
110 #endif
111   } else SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for DMDA 1d",((PetscObject)viewer)->type_name);
112   PetscFunctionReturn(0);
113 }
114 
115 /*
116       M is number of grid points
117       m is number of processors
118 
119 */
120 #undef __FUNCT__
121 #define __FUNCT__ "DMDASplitComm2d"
122 PetscErrorCode  DMDASplitComm2d(MPI_Comm comm,PetscInt M,PetscInt N,PetscInt sw,MPI_Comm *outcomm)
123 {
124   PetscErrorCode ierr;
125   PetscInt       m,n = 0,x = 0,y = 0;
126   PetscMPIInt    size,csize,rank;
127 
128   PetscFunctionBegin;
129   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
130   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
131 
132   csize = 4*size;
133   do {
134     if (csize % 4) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cannot split communicator of size %d tried %d %D %D",size,csize,x,y);
135     csize   = csize/4;
136 
137     m = (PetscInt)(0.5 + sqrt(((double)M)*((double)csize)/((double)N)));
138     if (!m) m = 1;
139     while (m > 0) {
140       n = csize/m;
141       if (m*n == csize) break;
142       m--;
143     }
144     if (M > N && m < n) {PetscInt _m = m; m = n; n = _m;}
145 
146     x = M/m + ((M % m) > ((csize-1) % m));
147     y = (N + (csize-1)/m)/n;
148   } while ((x < 4 || y < 4) && csize > 1);
149   if (size != csize) {
150     MPI_Group    entire_group,sub_group;
151     PetscMPIInt  i,*groupies;
152 
153     ierr = MPI_Comm_group(comm,&entire_group);CHKERRQ(ierr);
154     ierr = PetscMalloc(csize*sizeof(PetscInt),&groupies);CHKERRQ(ierr);
155     for (i=0; i<csize; i++) {
156       groupies[i] = (rank/csize)*csize + i;
157     }
158     ierr = MPI_Group_incl(entire_group,csize,groupies,&sub_group);CHKERRQ(ierr);
159     ierr = PetscFree(groupies);CHKERRQ(ierr);
160     ierr = MPI_Comm_create(comm,sub_group,outcomm);CHKERRQ(ierr);
161     ierr = MPI_Group_free(&entire_group);CHKERRQ(ierr);
162     ierr = MPI_Group_free(&sub_group);CHKERRQ(ierr);
163     ierr = PetscInfo1(0,"DMDASplitComm2d:Creating redundant coarse problems of size %d\n",csize);CHKERRQ(ierr);
164   } else {
165     *outcomm = comm;
166   }
167   PetscFunctionReturn(0);
168 }
169 
170 #undef __FUNCT__
171 #define __FUNCT__ "DMDAFunction"
172 static PetscErrorCode DMDAFunction(DM dm,Vec x,Vec F)
173 {
174   PetscErrorCode ierr;
175   Vec            localX;
176 
177   PetscFunctionBegin;
178   ierr = DMGetLocalVector(dm,&localX);CHKERRQ(ierr);
179   ierr = DMGlobalToLocalBegin(dm,x,INSERT_VALUES,localX);CHKERRQ(ierr);
180   ierr = DMGlobalToLocalEnd(dm,x,INSERT_VALUES,localX);CHKERRQ(ierr);
181   ierr = DMDAComputeFunction1(dm,localX,F,dm->ctx);CHKERRQ(ierr);
182   ierr = DMRestoreLocalVector(dm,&localX);CHKERRQ(ierr);
183   PetscFunctionReturn(0);
184 }
185 
186 #undef __FUNCT__
187 #define __FUNCT__ "DMDASetLocalFunction"
188 /*@C
189        DMDASetLocalFunction - Caches in a DM a local function.
190 
191    Logically Collective on DMDA
192 
193    Input Parameter:
194 +  da - initial distributed array
195 -  lf - the local function
196 
197    Level: intermediate
198 
199    Notes:
200       If you used SNESSetFunction(snes,r,SNESDMDAComputeFunction,ctx); then the context passed to your function is the ctx set here.
201 
202       If you use SNESSetDM() and did not use SNESSetFunction() then the context passed to your function is the context set with DMSetApplicationContext()
203 
204    Developer Notes: It is possibly confusing which context is passed to the user function, it would be nice to unify them somehow.
205 
206 .keywords:  distributed array, refine
207 
208 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunctioni()
209 @*/
210 PetscErrorCode  DMDASetLocalFunction(DM da,DMDALocalFunction1 lf)
211 {
212   PetscErrorCode ierr;
213   DM_DA          *dd = (DM_DA*)da->data;
214 
215   PetscFunctionBegin;
216   PetscValidHeaderSpecific(da,DM_CLASSID,1);
217   ierr = DMSetFunction(da,DMDAFunction);CHKERRQ(ierr);
218   dd->lf       = lf;
219   PetscFunctionReturn(0);
220 }
221 
222 #undef __FUNCT__
223 #define __FUNCT__ "DMDASetLocalFunctioni"
224 /*@C
225        DMDASetLocalFunctioni - Caches in a DM a local function that evaluates a single component
226 
227    Logically Collective on DMDA
228 
229    Input Parameter:
230 +  da - initial distributed array
231 -  lfi - the local function
232 
233    Level: intermediate
234 
235 .keywords:  distributed array, refine
236 
237 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunction()
238 @*/
239 PetscErrorCode  DMDASetLocalFunctioni(DM da,PetscErrorCode (*lfi)(DMDALocalInfo*,MatStencil*,void*,PetscScalar*,void*))
240 {
241   DM_DA          *dd = (DM_DA*)da->data;
242   PetscFunctionBegin;
243   PetscValidHeaderSpecific(da,DM_CLASSID,1);
244   dd->lfi = lfi;
245   PetscFunctionReturn(0);
246 }
247 
248 #undef __FUNCT__
249 #define __FUNCT__ "DMDASetLocalFunctionib"
250 /*@C
251        DMDASetLocalFunctionib - Caches in a DM a block local function that evaluates a single component
252 
253    Logically Collective on DMDA
254 
255    Input Parameter:
256 +  da - initial distributed array
257 -  lfi - the local function
258 
259    Level: intermediate
260 
261 .keywords:  distributed array, refine
262 
263 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunction()
264 @*/
265 PetscErrorCode  DMDASetLocalFunctionib(DM da,PetscErrorCode (*lfi)(DMDALocalInfo*,MatStencil*,void*,PetscScalar*,void*))
266 {
267   DM_DA          *dd = (DM_DA*)da->data;
268   PetscFunctionBegin;
269   PetscValidHeaderSpecific(da,DM_CLASSID,1);
270   dd->lfib = lfi;
271   PetscFunctionReturn(0);
272 }
273 
274 #undef __FUNCT__
275 #define __FUNCT__ "DMDASetLocalAdicFunction_Private"
276 PetscErrorCode DMDASetLocalAdicFunction_Private(DM da,DMDALocalFunction1 ad_lf)
277 {
278   DM_DA          *dd = (DM_DA*)da->data;
279   PetscFunctionBegin;
280   PetscValidHeaderSpecific(da,DM_CLASSID,1);
281   dd->adic_lf = ad_lf;
282   PetscFunctionReturn(0);
283 }
284 
285 /*MC
286        DMDASetLocalAdicFunctioni - Caches in a DM a local functioni computed by ADIC/ADIFOR
287 
288    Synopsis:
289    PetscErrorCode DMDASetLocalAdicFunctioni(DM da,PetscInt (ad_lf*)(DMDALocalInfo*,MatStencil*,void*,void*,void*)
290 
291    Logically Collective on DMDA
292 
293    Input Parameter:
294 +  da - initial distributed array
295 -  ad_lfi - the local function as computed by ADIC/ADIFOR
296 
297    Level: intermediate
298 
299 .keywords:  distributed array, refine
300 
301 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunction(),
302           DMDASetLocalJacobian(), DMDASetLocalFunctioni()
303 M*/
304 
305 #undef __FUNCT__
306 #define __FUNCT__ "DMDASetLocalAdicFunctioni_Private"
307 PetscErrorCode DMDASetLocalAdicFunctioni_Private(DM da,PetscErrorCode (*ad_lfi)(DMDALocalInfo*,MatStencil*,void*,void*,void*))
308 {
309   DM_DA          *dd = (DM_DA*)da->data;
310   PetscFunctionBegin;
311   PetscValidHeaderSpecific(da,DM_CLASSID,1);
312   dd->adic_lfi = ad_lfi;
313   PetscFunctionReturn(0);
314 }
315 
316 /*MC
317        DMDASetLocalAdicMFFunctioni - Caches in a DM a local functioni computed by ADIC/ADIFOR
318 
319    Synopsis:
320    PetscErrorCode  DMDASetLocalAdicFunctioni(DM da,int (ad_lf*)(DMDALocalInfo*,MatStencil*,void*,void*,void*)
321 
322    Logically Collective on DMDA
323 
324    Input Parameter:
325 +  da - initial distributed array
326 -  admf_lfi - the local matrix-free function as computed by ADIC/ADIFOR
327 
328    Level: intermediate
329 
330 .keywords:  distributed array, refine
331 
332 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunction(),
333           DMDASetLocalJacobian(), DMDASetLocalFunctioni()
334 M*/
335 
336 #undef __FUNCT__
337 #define __FUNCT__ "DMDASetLocalAdicMFFunctioni_Private"
338 PetscErrorCode DMDASetLocalAdicMFFunctioni_Private(DM da,PetscErrorCode (*admf_lfi)(DMDALocalInfo*,MatStencil*,void*,void*,void*))
339 {
340   DM_DA          *dd = (DM_DA*)da->data;
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(da,DM_CLASSID,1);
343   dd->adicmf_lfi = admf_lfi;
344   PetscFunctionReturn(0);
345 }
346 
347 /*MC
348        DMDASetLocalAdicFunctionib - Caches in a DM a block local functioni computed by ADIC/ADIFOR
349 
350    Synopsis:
351    PetscErrorCode DMDASetLocalAdicFunctionib(DM da,PetscInt (ad_lf*)(DMDALocalInfo*,MatStencil*,void*,void*,void*)
352 
353    Logically Collective on DMDA
354 
355    Input Parameter:
356 +  da - initial distributed array
357 -  ad_lfi - the local function as computed by ADIC/ADIFOR
358 
359    Level: intermediate
360 
361 .keywords:  distributed array, refine
362 
363 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunction(),
364           DMDASetLocalJacobian(), DMDASetLocalFunctionib()
365 M*/
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMDASetLocalAdicFunctionib_Private"
369 PetscErrorCode DMDASetLocalAdicFunctionib_Private(DM da,PetscErrorCode (*ad_lfi)(DMDALocalInfo*,MatStencil*,void*,void*,void*))
370 {
371   DM_DA          *dd = (DM_DA*)da->data;
372   PetscFunctionBegin;
373   PetscValidHeaderSpecific(da,DM_CLASSID,1);
374   dd->adic_lfib = ad_lfi;
375   PetscFunctionReturn(0);
376 }
377 
378 /*MC
379        DMDASetLocalAdicMFFunctionib - Caches in a DM a block local functioni computed by ADIC/ADIFOR
380 
381    Synopsis:
382    PetscErrorCode  DMDASetLocalAdicFunctionib(DM da,int (ad_lf*)(DMDALocalInfo*,MatStencil*,void*,void*,void*)
383 
384    Logically Collective on DMDA
385 
386    Input Parameter:
387 +  da - initial distributed array
388 -  admf_lfi - the local matrix-free function as computed by ADIC/ADIFOR
389 
390    Level: intermediate
391 
392 .keywords:  distributed array, refine
393 
394 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunction(),
395           DMDASetLocalJacobian(), DMDASetLocalFunctionib()
396 M*/
397 
398 #undef __FUNCT__
399 #define __FUNCT__ "DMDASetLocalAdicMFFunctionib_Private"
400 PetscErrorCode DMDASetLocalAdicMFFunctionib_Private(DM da,PetscErrorCode (*admf_lfi)(DMDALocalInfo*,MatStencil*,void*,void*,void*))
401 {
402   DM_DA          *dd = (DM_DA*)da->data;
403   PetscFunctionBegin;
404   PetscValidHeaderSpecific(da,DM_CLASSID,1);
405   dd->adicmf_lfib = admf_lfi;
406   PetscFunctionReturn(0);
407 }
408 
409 /*MC
410        DMDASetLocalAdicMFFunction - Caches in a DM a local function computed by ADIC/ADIFOR
411 
412    Synopsis:
413    PetscErrorCode DMDASetLocalAdicMFFunction(DM da,DMDALocalFunction1 ad_lf)
414 
415    Logically Collective on DMDA
416 
417    Input Parameter:
418 +  da - initial distributed array
419 -  ad_lf - the local function as computed by ADIC/ADIFOR
420 
421    Level: intermediate
422 
423 .keywords:  distributed array, refine
424 
425 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunction(),
426           DMDASetLocalJacobian()
427 M*/
428 
429 #undef __FUNCT__
430 #define __FUNCT__ "DMDASetLocalAdicMFFunction_Private"
431 PetscErrorCode DMDASetLocalAdicMFFunction_Private(DM da,DMDALocalFunction1 ad_lf)
432 {
433   DM_DA          *dd = (DM_DA*)da->data;
434   PetscFunctionBegin;
435   PetscValidHeaderSpecific(da,DM_CLASSID,1);
436   dd->adicmf_lf = ad_lf;
437   PetscFunctionReturn(0);
438 }
439 
440 #undef __FUNCT__
441 #define __FUNCT__ "DMDAJacobianDefaultLocal"
442 PetscErrorCode DMDAJacobianLocal(DM dm,Vec x,Mat A,Mat B, MatStructure *str)
443 {
444   PetscErrorCode ierr;
445   Vec            localX;
446 
447   PetscFunctionBegin;
448   ierr = DMGetLocalVector(dm,&localX);CHKERRQ(ierr);
449   ierr = DMGlobalToLocalBegin(dm,x,INSERT_VALUES,localX);CHKERRQ(ierr);
450   ierr = DMGlobalToLocalEnd(dm,x,INSERT_VALUES,localX);CHKERRQ(ierr);
451   ierr = MatFDColoringApply(B,dm->fd,localX,str,dm);CHKERRQ(ierr);
452   ierr = DMRestoreLocalVector(dm,&localX);CHKERRQ(ierr);
453   /* Assemble true Jacobian; if it is different */
454   if (A != B) {
455     ierr  = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
456     ierr  = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
457   }
458   ierr  = MatSetOption(B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
459   *str = SAME_NONZERO_PATTERN;
460   PetscFunctionReturn(0);
461 }
462 
463 
464 #undef __FUNCT__
465 #define __FUNCT__ "DMDAJacobian"
466 static PetscErrorCode DMDAJacobian(DM dm,Vec x,Mat A,Mat B, MatStructure *str)
467 {
468   PetscErrorCode ierr;
469   Vec            localX;
470 
471   PetscFunctionBegin;
472   ierr = DMGetLocalVector(dm,&localX);CHKERRQ(ierr);
473   ierr = DMGlobalToLocalBegin(dm,x,INSERT_VALUES,localX);CHKERRQ(ierr);
474   ierr = DMGlobalToLocalEnd(dm,x,INSERT_VALUES,localX);CHKERRQ(ierr);
475   ierr = DMDAComputeJacobian1(dm,localX,B,dm->ctx);CHKERRQ(ierr);
476   ierr = DMRestoreLocalVector(dm,&localX);CHKERRQ(ierr);
477   /* Assemble true Jacobian; if it is different */
478   if (A != B) {
479     ierr  = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
480     ierr  = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
481   }
482   ierr  = MatSetOption(B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
483   *str = SAME_NONZERO_PATTERN;
484   PetscFunctionReturn(0);
485 }
486 
487 /*@C
488        DMDASetLocalJacobian - Caches in a DM a local Jacobian computation function
489 
490    Logically Collective on DMDA
491 
492 
493    Input Parameter:
494 +  da - initial distributed array
495 -  lj - the local Jacobian
496 
497    Level: intermediate
498 
499    Notes: The routine SNESDMDAComputeFunction() uses this the cached function to evaluate the user provided function.
500 
501 .keywords:  distributed array, refine
502 
503 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalFunction()
504 @*/
505 #undef __FUNCT__
506 #define __FUNCT__ "DMDASetLocalJacobian"
507 PetscErrorCode  DMDASetLocalJacobian(DM da,DMDALocalFunction1 lj)
508 {
509   PetscErrorCode ierr;
510   DM_DA          *dd = (DM_DA*)da->data;
511 
512   PetscFunctionBegin;
513   PetscValidHeaderSpecific(da,DM_CLASSID,1);
514   ierr = DMSetJacobian(da,DMDAJacobian);CHKERRQ(ierr);
515   dd->lj    = lj;
516   PetscFunctionReturn(0);
517 }
518 
519 #undef __FUNCT__
520 #define __FUNCT__ "DMDAGetLocalFunction"
521 /*@C
522        DMDAGetLocalFunction - Gets from a DM a local function and its ADIC/ADIFOR Jacobian
523 
524    Note Collective
525 
526    Input Parameter:
527 .  da - initial distributed array
528 
529    Output Parameter:
530 .  lf - the local function
531 
532    Level: intermediate
533 
534 .keywords:  distributed array, refine
535 
536 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalJacobian(), DMDASetLocalFunction()
537 @*/
538 PetscErrorCode  DMDAGetLocalFunction(DM da,DMDALocalFunction1 *lf)
539 {
540   DM_DA *dd = (DM_DA*)da->data;
541   PetscFunctionBegin;
542   PetscValidHeaderSpecific(da,DM_CLASSID,1);
543   if (lf) *lf = dd->lf;
544   PetscFunctionReturn(0);
545 }
546 
547 #undef __FUNCT__
548 #define __FUNCT__ "DMDAGetLocalJacobian"
549 /*@C
550        DMDAGetLocalJacobian - Gets from a DM a local jacobian
551 
552    Not Collective
553 
554    Input Parameter:
555 .  da - initial distributed array
556 
557    Output Parameter:
558 .  lj - the local jacobian
559 
560    Level: intermediate
561 
562 .keywords:  distributed array, refine
563 
564 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDAGetLocalFunction(), DMDASetLocalJacobian()
565 @*/
566 PetscErrorCode  DMDAGetLocalJacobian(DM da,DMDALocalFunction1 *lj)
567 {
568   DM_DA *dd = (DM_DA*)da->data;
569   PetscFunctionBegin;
570   PetscValidHeaderSpecific(da,DM_CLASSID,1);
571   if (lj) *lj = dd->lj;
572   PetscFunctionReturn(0);
573 }
574 
575 #undef __FUNCT__
576 #define __FUNCT__ "DMDAComputeFunction"
577 /*@
578     DMDAComputeFunction - Evaluates a user provided function on each processor that
579         share a DMDA
580 
581    Input Parameters:
582 +    da - the DM that defines the grid
583 .    vu - input vector
584 .    vfu - output vector
585 -    w - any user data
586 
587     Notes: Does NOT do ghost updates on vu upon entry
588 
589            This should eventually replace DMDAComputeFunction1
590 
591     Level: advanced
592 
593 .seealso: DMDAComputeJacobian1WithAdic()
594 
595 @*/
596 PetscErrorCode  DMDAComputeFunction(DM da,PetscErrorCode (*lf)(void),Vec vu,Vec vfu,void *w)
597 {
598   PetscErrorCode ierr;
599   void           *u,*fu;
600   DMDALocalInfo  info;
601   PetscErrorCode (*f)(DMDALocalInfo*,void*,void*,void*) = (PetscErrorCode (*)(DMDALocalInfo*,void*,void*,void*))lf;
602 
603   PetscFunctionBegin;
604   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
605   ierr = DMDAVecGetArray(da,vu,&u);CHKERRQ(ierr);
606   ierr = DMDAVecGetArray(da,vfu,&fu);CHKERRQ(ierr);
607 
608   ierr = (*f)(&info,u,fu,w);CHKERRQ(ierr);
609 
610   ierr = DMDAVecRestoreArray(da,vu,&u);CHKERRQ(ierr);
611   ierr = DMDAVecRestoreArray(da,vfu,&fu);CHKERRQ(ierr);
612   PetscFunctionReturn(0);
613 }
614 
615 #undef __FUNCT__
616 #define __FUNCT__ "DMDAComputeFunctionLocal"
617 /*@C
618    DMDAComputeFunctionLocal - This is a universal function evaluation routine for
619    a local DM function.
620 
621    Collective on DMDA
622 
623    Input Parameters:
624 +  da - the DM context
625 .  func - The local function
626 .  X - input vector
627 .  F - function vector
628 -  ctx - A user context
629 
630    Level: intermediate
631 
632 .seealso: DMDASetLocalFunction(), DMDASetLocalJacobian(), DMDASetLocalAdicFunction(), DMDASetLocalAdicMFFunction(),
633           SNESSetFunction(), SNESSetJacobian()
634 
635 @*/
636 PetscErrorCode  DMDAComputeFunctionLocal(DM da, DMDALocalFunction1 func, Vec X, Vec F, void *ctx)
637 {
638   Vec            localX;
639   DMDALocalInfo  info;
640   void           *u;
641   void           *fu;
642   PetscErrorCode ierr;
643 
644   PetscFunctionBegin;
645   ierr = DMGetLocalVector(da,&localX);CHKERRQ(ierr);
646   /*
647      Scatter ghost points to local vector, using the 2-step process
648         DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
649   */
650   ierr = DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
651   ierr = DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
652   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
653   ierr = DMDAVecGetArray(da,localX,&u);CHKERRQ(ierr);
654   ierr = DMDAVecGetArray(da,F,&fu);CHKERRQ(ierr);
655   ierr = (*func)(&info,u,fu,ctx);CHKERRQ(ierr);
656   ierr = DMDAVecRestoreArray(da,localX,&u);CHKERRQ(ierr);
657   ierr = DMDAVecRestoreArray(da,F,&fu);CHKERRQ(ierr);
658   ierr = DMRestoreLocalVector(da,&localX);CHKERRQ(ierr);
659   PetscFunctionReturn(0);
660 }
661 
662 #undef __FUNCT__
663 #define __FUNCT__ "DMDAComputeFunctionLocalGhost"
664 /*@C
665    DMDAComputeFunctionLocalGhost - This is a universal function evaluation routine for
666    a local DM function, but the ghost values of the output are communicated and added.
667 
668    Collective on DMDA
669 
670    Input Parameters:
671 +  da - the DM context
672 .  func - The local function
673 .  X - input vector
674 .  F - function vector
675 -  ctx - A user context
676 
677    Level: intermediate
678 
679 .seealso: DMDASetLocalFunction(), DMDASetLocalJacobian(), DMDASetLocalAdicFunction(), DMDASetLocalAdicMFFunction(),
680           SNESSetFunction(), SNESSetJacobian()
681 
682 @*/
683 PetscErrorCode  DMDAComputeFunctionLocalGhost(DM da, DMDALocalFunction1 func, Vec X, Vec F, void *ctx)
684 {
685   Vec            localX, localF;
686   DMDALocalInfo  info;
687   void           *u;
688   void           *fu;
689   PetscErrorCode ierr;
690 
691   PetscFunctionBegin;
692   ierr = DMGetLocalVector(da,&localX);CHKERRQ(ierr);
693   ierr = DMGetLocalVector(da,&localF);CHKERRQ(ierr);
694   /*
695      Scatter ghost points to local vector, using the 2-step process
696         DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
697   */
698   ierr = DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
699   ierr = DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
700   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
701   ierr = VecSet(localF, 0.0);CHKERRQ(ierr);
702   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
703   ierr = DMDAVecGetArray(da,localX,&u);CHKERRQ(ierr);
704   ierr = DMDAVecGetArray(da,localF,&fu);CHKERRQ(ierr);
705   ierr = (*func)(&info,u,fu,ctx);CHKERRQ(ierr);
706   ierr = DMLocalToGlobalBegin(da,localF,ADD_VALUES,F);CHKERRQ(ierr);
707   ierr = DMLocalToGlobalEnd(da,localF,ADD_VALUES,F);CHKERRQ(ierr);
708   ierr = DMDAVecRestoreArray(da,localX,&u);CHKERRQ(ierr);
709   ierr = DMDAVecRestoreArray(da,localF,&fu);CHKERRQ(ierr);
710   ierr = DMRestoreLocalVector(da,&localX);CHKERRQ(ierr);
711   ierr = DMRestoreLocalVector(da,&localF);CHKERRQ(ierr);
712   PetscFunctionReturn(0);
713 }
714 
715 #undef __FUNCT__
716 #define __FUNCT__ "DMDAComputeFunction1"
717 /*@
718     DMDAComputeFunction1 - Evaluates a user provided function on each processor that
719         share a DMDA
720 
721    Input Parameters:
722 +    da - the DM that defines the grid
723 .    vu - input vector
724 .    vfu - output vector
725 -    w - any user data
726 
727     Notes: Does NOT do ghost updates on vu upon entry
728 
729     Level: advanced
730 
731 .seealso: DMDAComputeJacobian1WithAdic()
732 
733 @*/
734 PetscErrorCode  DMDAComputeFunction1(DM da,Vec vu,Vec vfu,void *w)
735 {
736   PetscErrorCode ierr;
737   void           *u,*fu;
738   DMDALocalInfo  info;
739   DM_DA          *dd = (DM_DA*)da->data;
740 
741   PetscFunctionBegin;
742   if (!dd->lf) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_NULL,"DMDASetLocalFunction() never called");
743   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
744   ierr = DMDAVecGetArray(da,vu,&u);CHKERRQ(ierr);
745   ierr = DMDAVecGetArray(da,vfu,&fu);CHKERRQ(ierr);
746 
747   CHKMEMQ;
748   ierr = (*dd->lf)(&info,u,fu,w);CHKERRQ(ierr);
749   CHKMEMQ;
750 
751   ierr = DMDAVecRestoreArray(da,vu,&u);CHKERRQ(ierr);
752   ierr = DMDAVecRestoreArray(da,vfu,&fu);CHKERRQ(ierr);
753   PetscFunctionReturn(0);
754 }
755 
756 #undef __FUNCT__
757 #define __FUNCT__ "DMDAComputeFunctioniTest1"
758 PetscErrorCode  DMDAComputeFunctioniTest1(DM da,void *w)
759 {
760   Vec            vu,fu,fui;
761   PetscErrorCode ierr;
762   PetscInt       i,n;
763   PetscScalar    *ui;
764   PetscRandom    rnd;
765   PetscReal      norm;
766 
767   PetscFunctionBegin;
768   ierr = DMGetLocalVector(da,&vu);CHKERRQ(ierr);
769   ierr = PetscRandomCreate(PETSC_COMM_SELF,&rnd);CHKERRQ(ierr);
770   ierr = PetscRandomSetFromOptions(rnd);CHKERRQ(ierr);
771   ierr = VecSetRandom(vu,rnd);CHKERRQ(ierr);
772   ierr = PetscRandomDestroy(&rnd);CHKERRQ(ierr);
773 
774   ierr = DMGetGlobalVector(da,&fu);CHKERRQ(ierr);
775   ierr = DMGetGlobalVector(da,&fui);CHKERRQ(ierr);
776 
777   ierr = DMDAComputeFunction1(da,vu,fu,w);CHKERRQ(ierr);
778 
779   ierr = VecGetArray(fui,&ui);CHKERRQ(ierr);
780   ierr = VecGetLocalSize(fui,&n);CHKERRQ(ierr);
781   for (i=0; i<n; i++) {
782     ierr = DMDAComputeFunctioni1(da,i,vu,ui+i,w);CHKERRQ(ierr);
783   }
784   ierr = VecRestoreArray(fui,&ui);CHKERRQ(ierr);
785 
786   ierr = VecAXPY(fui,-1.0,fu);CHKERRQ(ierr);
787   ierr = VecNorm(fui,NORM_2,&norm);CHKERRQ(ierr);
788   ierr = PetscPrintf(((PetscObject)da)->comm,"Norm of difference in vectors %G\n",norm);CHKERRQ(ierr);
789   ierr = VecView(fu,0);CHKERRQ(ierr);
790   ierr = VecView(fui,0);CHKERRQ(ierr);
791 
792   ierr = DMRestoreLocalVector(da,&vu);CHKERRQ(ierr);
793   ierr = DMRestoreGlobalVector(da,&fu);CHKERRQ(ierr);
794   ierr = DMRestoreGlobalVector(da,&fui);CHKERRQ(ierr);
795   PetscFunctionReturn(0);
796 }
797 
798 #undef __FUNCT__
799 #define __FUNCT__ "DMDAComputeFunctioni1"
800 /*@
801     DMDAComputeFunctioni1 - Evaluates a user provided point-wise function
802 
803    Input Parameters:
804 +    da - the DM that defines the grid
805 .    i - the component of the function we wish to compute (must be local)
806 .    vu - input vector
807 .    vfu - output value
808 -    w - any user data
809 
810     Notes: Does NOT do ghost updates on vu upon entry
811 
812     Level: advanced
813 
814 .seealso: DMDAComputeJacobian1WithAdic()
815 
816 @*/
817 PetscErrorCode  DMDAComputeFunctioni1(DM da,PetscInt i,Vec vu,PetscScalar *vfu,void *w)
818 {
819   PetscErrorCode ierr;
820   void           *u;
821   DMDALocalInfo  info;
822   MatStencil     stencil;
823   DM_DA          *dd = (DM_DA*)da->data;
824 
825   PetscFunctionBegin;
826 
827   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
828   ierr = DMDAVecGetArray(da,vu,&u);CHKERRQ(ierr);
829 
830   /* figure out stencil value from i */
831   stencil.c = i % info.dof;
832   stencil.i = (i % (info.xm*info.dof))/info.dof;
833   stencil.j = (i % (info.xm*info.ym*info.dof))/(info.xm*info.dof);
834   stencil.k = i/(info.xm*info.ym*info.dof);
835 
836   ierr = (*dd->lfi)(&info,&stencil,u,vfu,w);CHKERRQ(ierr);
837 
838   ierr = DMDAVecRestoreArray(da,vu,&u);CHKERRQ(ierr);
839   PetscFunctionReturn(0);
840 }
841 
842 #undef __FUNCT__
843 #define __FUNCT__ "DMDAComputeFunctionib1"
844 /*@
845     DMDAComputeFunctionib1 - Evaluates a user provided point-block function
846 
847    Input Parameters:
848 +    da - the DM that defines the grid
849 .    i - the component of the function we wish to compute (must be local)
850 .    vu - input vector
851 .    vfu - output value
852 -    w - any user data
853 
854     Notes: Does NOT do ghost updates on vu upon entry
855 
856     Level: advanced
857 
858 .seealso: DMDAComputeJacobian1WithAdic()
859 
860 @*/
861 PetscErrorCode  DMDAComputeFunctionib1(DM da,PetscInt i,Vec vu,PetscScalar *vfu,void *w)
862 {
863   PetscErrorCode ierr;
864   void           *u;
865   DMDALocalInfo  info;
866   MatStencil     stencil;
867   DM_DA          *dd = (DM_DA*)da->data;
868 
869   PetscFunctionBegin;
870   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
871   ierr = DMDAVecGetArray(da,vu,&u);CHKERRQ(ierr);
872 
873   /* figure out stencil value from i */
874   stencil.c = i % info.dof;
875   if (stencil.c) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONG,"Point-block functions can only be called for the entire block");
876   stencil.i = (i % (info.xm*info.dof))/info.dof;
877   stencil.j = (i % (info.xm*info.ym*info.dof))/(info.xm*info.dof);
878   stencil.k = i/(info.xm*info.ym*info.dof);
879 
880   ierr = (*dd->lfib)(&info,&stencil,u,vfu,w);CHKERRQ(ierr);
881 
882   ierr = DMDAVecRestoreArray(da,vu,&u);CHKERRQ(ierr);
883   PetscFunctionReturn(0);
884 }
885 
886 #if defined(new)
887 #undef __FUNCT__
888 #define __FUNCT__ "DMDAGetDiagonal_MFFD"
889 /*
890   DMDAGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix where local
891     function lives on a DMDA
892 
893         y ~= (F(u + ha) - F(u))/h,
894   where F = nonlinear function, as set by SNESSetFunction()
895         u = current iterate
896         h = difference interval
897 */
898 PetscErrorCode DMDAGetDiagonal_MFFD(DM da,Vec U,Vec a)
899 {
900   PetscScalar    h,*aa,*ww,v;
901   PetscReal      epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
902   PetscErrorCode ierr;
903   PetscInt       gI,nI;
904   MatStencil     stencil;
905   DMDALocalInfo  info;
906 
907   PetscFunctionBegin;
908   ierr = (*ctx->func)(0,U,a,ctx->funcctx);CHKERRQ(ierr);
909   ierr = (*ctx->funcisetbase)(U,ctx->funcctx);CHKERRQ(ierr);
910 
911   ierr = VecGetArray(U,&ww);CHKERRQ(ierr);
912   ierr = VecGetArray(a,&aa);CHKERRQ(ierr);
913 
914   nI = 0;
915     h  = ww[gI];
916     if (h == 0.0) h = 1.0;
917 #if !defined(PETSC_USE_COMPLEX)
918     if (h < umin && h >= 0.0)      h = umin;
919     else if (h < 0.0 && h > -umin) h = -umin;
920 #else
921     if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0)     h = umin;
922     else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
923 #endif
924     h     *= epsilon;
925 
926     ww[gI] += h;
927     ierr          = (*ctx->funci)(i,w,&v,ctx->funcctx);CHKERRQ(ierr);
928     aa[nI]  = (v - aa[nI])/h;
929     ww[gI] -= h;
930     nI++;
931   }
932   ierr = VecRestoreArray(U,&ww);CHKERRQ(ierr);
933   ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr);
934   PetscFunctionReturn(0);
935 }
936 #endif
937 
938 #if defined(PETSC_HAVE_ADIC)
939 EXTERN_C_BEGIN
940 #include <adic/ad_utils.h>
941 EXTERN_C_END
942 
943 #undef __FUNCT__
944 #define __FUNCT__ "DMDAComputeJacobian1WithAdic"
945 /*@C
946     DMDAComputeJacobian1WithAdic - Evaluates a adiC provided Jacobian function on each processor that
947         share a DMDA
948 
949    Input Parameters:
950 +    da - the DM that defines the grid
951 .    vu - input vector (ghosted)
952 .    J - output matrix
953 -    w - any user data
954 
955    Level: advanced
956 
957     Notes: Does NOT do ghost updates on vu upon entry
958 
959 .seealso: DMDAComputeFunction1()
960 
961 @*/
962 PetscErrorCode  DMDAComputeJacobian1WithAdic(DM da,Vec vu,Mat J,void *w)
963 {
964   PetscErrorCode ierr;
965   PetscInt       gtdof,tdof;
966   PetscScalar    *ustart;
967   DMDALocalInfo  info;
968   void           *ad_u,*ad_f,*ad_ustart,*ad_fstart;
969   ISColoring     iscoloring;
970 
971   PetscFunctionBegin;
972   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
973 
974   PetscADResetIndep();
975 
976   /* get space for derivative objects.  */
977   ierr = DMDAGetAdicArray(da,PETSC_TRUE,&ad_u,&ad_ustart,&gtdof);CHKERRQ(ierr);
978   ierr = DMDAGetAdicArray(da,PETSC_FALSE,&ad_f,&ad_fstart,&tdof);CHKERRQ(ierr);
979   ierr = VecGetArray(vu,&ustart);CHKERRQ(ierr);
980   ierr = DMCreateColoring(da,IS_COLORING_GHOSTED,MATAIJ,&iscoloring);CHKERRQ(ierr);
981 
982   PetscADSetValueAndColor(ad_ustart,gtdof,iscoloring->colors,ustart);
983 
984   ierr = VecRestoreArray(vu,&ustart);CHKERRQ(ierr);
985   ierr = ISColoringDestroy(&iscoloring);CHKERRQ(ierr);
986   ierr = PetscADIncrementTotalGradSize(iscoloring->n);CHKERRQ(ierr);
987   PetscADSetIndepDone();
988 
989   ierr = PetscLogEventBegin(DMDA_LocalADFunction,0,0,0,0);CHKERRQ(ierr);
990   ierr = (*dd->adic_lf)(&info,ad_u,ad_f,w);CHKERRQ(ierr);
991   ierr = PetscLogEventEnd(DMDA_LocalADFunction,0,0,0,0);CHKERRQ(ierr);
992 
993   /* stick the values into the matrix */
994   ierr = MatSetValuesAdic(J,(PetscScalar**)ad_fstart);CHKERRQ(ierr);
995 
996   /* return space for derivative objects.  */
997   ierr = DMDARestoreAdicArray(da,PETSC_TRUE,&ad_u,&ad_ustart,&gtdof);CHKERRQ(ierr);
998   ierr = DMDARestoreAdicArray(da,PETSC_FALSE,&ad_f,&ad_fstart,&tdof);CHKERRQ(ierr);
999   PetscFunctionReturn(0);
1000 }
1001 
1002 #undef __FUNCT__
1003 #define __FUNCT__ "DMDAMultiplyByJacobian1WithAdic"
1004 /*@C
1005     DMDAMultiplyByJacobian1WithAdic - Applies an ADIC-provided Jacobian function to a vector on
1006     each processor that shares a DMDA.
1007 
1008     Input Parameters:
1009 +   da - the DM that defines the grid
1010 .   vu - Jacobian is computed at this point (ghosted)
1011 .   v - product is done on this vector (ghosted)
1012 .   fu - output vector = J(vu)*v (not ghosted)
1013 -   w - any user data
1014 
1015     Notes:
1016     This routine does NOT do ghost updates on vu upon entry.
1017 
1018    Level: advanced
1019 
1020 .seealso: DMDAComputeFunction1()
1021 
1022 @*/
1023 PetscErrorCode  DMDAMultiplyByJacobian1WithAdic(DM da,Vec vu,Vec v,Vec f,void *w)
1024 {
1025   PetscErrorCode ierr;
1026   PetscInt       i,gtdof,tdof;
1027   PetscScalar    *avu,*av,*af,*ad_vustart,*ad_fstart;
1028   DMDALocalInfo  info;
1029   void           *ad_vu,*ad_f;
1030 
1031   PetscFunctionBegin;
1032   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
1033 
1034   /* get space for derivative objects.  */
1035   ierr = DMDAGetAdicMFArray(da,PETSC_TRUE,&ad_vu,&ad_vustart,&gtdof);CHKERRQ(ierr);
1036   ierr = DMDAGetAdicMFArray(da,PETSC_FALSE,&ad_f,&ad_fstart,&tdof);CHKERRQ(ierr);
1037 
1038   /* copy input vector into derivative object */
1039   ierr = VecGetArray(vu,&avu);CHKERRQ(ierr);
1040   ierr = VecGetArray(v,&av);CHKERRQ(ierr);
1041   for (i=0; i<gtdof; i++) {
1042     ad_vustart[2*i]   = avu[i];
1043     ad_vustart[2*i+1] = av[i];
1044   }
1045   ierr = VecRestoreArray(vu,&avu);CHKERRQ(ierr);
1046   ierr = VecRestoreArray(v,&av);CHKERRQ(ierr);
1047 
1048   PetscADResetIndep();
1049   ierr = PetscADIncrementTotalGradSize(1);CHKERRQ(ierr);
1050   PetscADSetIndepDone();
1051 
1052   ierr = (*dd->adicmf_lf)(&info,ad_vu,ad_f,w);CHKERRQ(ierr);
1053 
1054   /* stick the values into the vector */
1055   ierr = VecGetArray(f,&af);CHKERRQ(ierr);
1056   for (i=0; i<tdof; i++) {
1057     af[i] = ad_fstart[2*i+1];
1058   }
1059   ierr = VecRestoreArray(f,&af);CHKERRQ(ierr);
1060 
1061   /* return space for derivative objects.  */
1062   ierr = DMDARestoreAdicMFArray(da,PETSC_TRUE,&ad_vu,&ad_vustart,&gtdof);CHKERRQ(ierr);
1063   ierr = DMDARestoreAdicMFArray(da,PETSC_FALSE,&ad_f,&ad_fstart,&tdof);CHKERRQ(ierr);
1064   PetscFunctionReturn(0);
1065 }
1066 #endif
1067 
1068 #undef __FUNCT__
1069 #define __FUNCT__ "DMDAComputeJacobian1"
1070 /*@
1071     DMDAComputeJacobian1 - Evaluates a local Jacobian function on each processor that
1072         share a DMDA
1073 
1074    Input Parameters:
1075 +    da - the DM that defines the grid
1076 .    vu - input vector (ghosted)
1077 .    J - output matrix
1078 -    w - any user data
1079 
1080     Notes: Does NOT do ghost updates on vu upon entry
1081 
1082     Level: advanced
1083 
1084 .seealso: DMDAComputeFunction1()
1085 
1086 @*/
1087 PetscErrorCode  DMDAComputeJacobian1(DM da,Vec vu,Mat J,void *w)
1088 {
1089   PetscErrorCode ierr;
1090   void           *u;
1091   DMDALocalInfo  info;
1092   DM_DA          *dd = (DM_DA*)da->data;
1093 
1094   PetscFunctionBegin;
1095   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
1096   ierr = DMDAVecGetArray(da,vu,&u);CHKERRQ(ierr);
1097   ierr = (*dd->lj)(&info,u,J,w);CHKERRQ(ierr);
1098   ierr = DMDAVecRestoreArray(da,vu,&u);CHKERRQ(ierr);
1099   PetscFunctionReturn(0);
1100 }
1101 
1102 
1103 #undef __FUNCT__
1104 #define __FUNCT__ "DMDAComputeJacobian1WithAdifor"
1105 /*
1106     DMDAComputeJacobian1WithAdifor - Evaluates a ADIFOR provided Jacobian local function on each processor that
1107         share a DMDA
1108 
1109    Input Parameters:
1110 +    da - the DM that defines the grid
1111 .    vu - input vector (ghosted)
1112 .    J - output matrix
1113 -    w - any user data
1114 
1115     Notes: Does NOT do ghost updates on vu upon entry
1116 
1117 .seealso: DMDAComputeFunction1()
1118 
1119 */
1120 PetscErrorCode  DMDAComputeJacobian1WithAdifor(DM da,Vec vu,Mat J,void *w)
1121 {
1122   PetscErrorCode  ierr;
1123   PetscInt        i,Nc,N;
1124   ISColoringValue *color;
1125   DMDALocalInfo   info;
1126   PetscScalar     *u,*g_u,*g_f,*f = 0,*p_u;
1127   ISColoring      iscoloring;
1128   DM_DA          *dd = (DM_DA*)da->data;
1129   void            (*lf)(PetscInt*,DMDALocalInfo*,PetscScalar*,PetscScalar*,PetscInt*,PetscScalar*,PetscScalar*,PetscInt*,void*,PetscErrorCode*) =
1130                   (void (*)(PetscInt*,DMDALocalInfo*,PetscScalar*,PetscScalar*,PetscInt*,PetscScalar*,PetscScalar*,PetscInt*,void*,PetscErrorCode*))*dd->adifor_lf;
1131 
1132   PetscFunctionBegin;
1133   ierr = DMCreateColoring(da,IS_COLORING_GHOSTED,MATAIJ,&iscoloring);CHKERRQ(ierr);
1134   Nc   = iscoloring->n;
1135   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
1136   N    = info.gxm*info.gym*info.gzm*info.dof;
1137 
1138   /* get space for derivative objects.  */
1139   ierr  = PetscMalloc(Nc*info.gxm*info.gym*info.gzm*info.dof*sizeof(PetscScalar),&g_u);CHKERRQ(ierr);
1140   ierr  = PetscMemzero(g_u,Nc*info.gxm*info.gym*info.gzm*info.dof*sizeof(PetscScalar));CHKERRQ(ierr);
1141   p_u   = g_u;
1142   color = iscoloring->colors;
1143   for (i=0; i<N; i++) {
1144     p_u[*color++] = 1.0;
1145     p_u          += Nc;
1146   }
1147   ierr = ISColoringDestroy(&iscoloring);CHKERRQ(ierr);
1148   ierr = PetscMalloc2(Nc*info.xm*info.ym*info.zm*info.dof,PetscScalar,&g_f,info.xm*info.ym*info.zm*info.dof,PetscScalar,&f);CHKERRQ(ierr);
1149 
1150   /* Seed the input array g_u with coloring information */
1151 
1152   ierr = VecGetArray(vu,&u);CHKERRQ(ierr);
1153   (lf)(&Nc,&info,u,g_u,&Nc,f,g_f,&Nc,w,&ierr);CHKERRQ(ierr);
1154   ierr = VecRestoreArray(vu,&u);CHKERRQ(ierr);
1155 
1156   /* stick the values into the matrix */
1157   /* PetscScalarView(Nc*info.xm*info.ym,g_f,0); */
1158   ierr = MatSetValuesAdifor(J,Nc,g_f);CHKERRQ(ierr);
1159 
1160   /* return space for derivative objects.  */
1161   ierr = PetscFree(g_u);CHKERRQ(ierr);
1162   ierr = PetscFree2(g_f,f);CHKERRQ(ierr);
1163   PetscFunctionReturn(0);
1164 }
1165 
1166 #undef __FUNCT__
1167 #define __FUNCT__ "DMDAFormJacobianLocal"
1168 /*@C
1169    DMDAFormjacobianLocal - This is a universal Jacobian evaluation routine for
1170    a local DM function.
1171 
1172    Collective on DMDA
1173 
1174    Input Parameters:
1175 +  da - the DM context
1176 .  func - The local function
1177 .  X - input vector
1178 .  J - Jacobian matrix
1179 -  ctx - A user context
1180 
1181    Level: intermediate
1182 
1183 .seealso: DMDASetLocalFunction(), DMDASetLocalJacobian(), DMDASetLocalAdicFunction(), DMDASetLocalAdicMFFunction(),
1184           SNESSetFunction(), SNESSetJacobian()
1185 
1186 @*/
1187 PetscErrorCode  DMDAFormJacobianLocal(DM da, DMDALocalFunction1 func, Vec X, Mat J, void *ctx)
1188 {
1189   Vec            localX;
1190   DMDALocalInfo  info;
1191   void           *u;
1192   PetscErrorCode ierr;
1193 
1194   PetscFunctionBegin;
1195   ierr = DMGetLocalVector(da,&localX);CHKERRQ(ierr);
1196   /*
1197      Scatter ghost points to local vector, using the 2-step process
1198         DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
1199   */
1200   ierr = DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
1201   ierr = DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
1202   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
1203   ierr = DMDAVecGetArray(da,localX,&u);CHKERRQ(ierr);
1204   ierr = (*func)(&info,u,J,ctx);CHKERRQ(ierr);
1205   ierr = DMDAVecRestoreArray(da,localX,&u);CHKERRQ(ierr);
1206   ierr = DMRestoreLocalVector(da,&localX);CHKERRQ(ierr);
1207   PetscFunctionReturn(0);
1208 }
1209 
1210 #undef __FUNCT__
1211 #define __FUNCT__ "DMDAMultiplyByJacobian1WithAD"
1212 /*@C
1213     DMDAMultiplyByJacobian1WithAD - Applies a Jacobian function supplied by ADIFOR or ADIC
1214     to a vector on each processor that shares a DMDA.
1215 
1216    Input Parameters:
1217 +    da - the DM that defines the grid
1218 .    vu - Jacobian is computed at this point (ghosted)
1219 .    v - product is done on this vector (ghosted)
1220 .    fu - output vector = J(vu)*v (not ghosted)
1221 -    w - any user data
1222 
1223     Notes:
1224     This routine does NOT do ghost updates on vu and v upon entry.
1225 
1226     Automatically calls DMDAMultiplyByJacobian1WithAdifor() or DMDAMultiplyByJacobian1WithAdic()
1227     depending on whether DMDASetLocalAdicMFFunction() or DMDASetLocalAdiforMFFunction() was called.
1228 
1229    Level: advanced
1230 
1231 .seealso: DMDAComputeFunction1(), DMDAMultiplyByJacobian1WithAdifor(), DMDAMultiplyByJacobian1WithAdic()
1232 
1233 @*/
1234 PetscErrorCode  DMDAMultiplyByJacobian1WithAD(DM da,Vec u,Vec v,Vec f,void *w)
1235 {
1236   PetscErrorCode ierr;
1237   DM_DA          *dd = (DM_DA*)da->data;
1238 
1239   PetscFunctionBegin;
1240   if (dd->adicmf_lf) {
1241 #if defined(PETSC_HAVE_ADIC)
1242     ierr = DMDAMultiplyByJacobian1WithAdic(da,u,v,f,w);CHKERRQ(ierr);
1243 #else
1244     SETERRQ(((PetscObject)da)->comm,PETSC_ERR_SUP_SYS,"Requires ADIC to be installed and cannot use complex numbers");
1245 #endif
1246   } else if (dd->adiformf_lf) {
1247     ierr = DMDAMultiplyByJacobian1WithAdifor(da,u,v,f,w);CHKERRQ(ierr);
1248   } else {
1249     SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ORDER,"Must call DMDASetLocalAdiforMFFunction() or DMDASetLocalAdicMFFunction() before using");
1250   }
1251   PetscFunctionReturn(0);
1252 }
1253 
1254 
1255 #undef __FUNCT__
1256 #define __FUNCT__ "DMDAMultiplyByJacobian1WithAdifor"
1257 /*@C
1258     DMDAMultiplyByJacobian1WithAdifor - Applies a ADIFOR provided Jacobian function on each processor that
1259         share a DM to a vector
1260 
1261    Input Parameters:
1262 +    da - the DM that defines the grid
1263 .    vu - Jacobian is computed at this point (ghosted)
1264 .    v - product is done on this vector (ghosted)
1265 .    fu - output vector = J(vu)*v (not ghosted)
1266 -    w - any user data
1267 
1268     Notes: Does NOT do ghost updates on vu and v upon entry
1269 
1270    Level: advanced
1271 
1272 .seealso: DMDAComputeFunction1()
1273 
1274 @*/
1275 PetscErrorCode  DMDAMultiplyByJacobian1WithAdifor(DM da,Vec u,Vec v,Vec f,void *w)
1276 {
1277   PetscErrorCode ierr;
1278   PetscScalar    *au,*av,*af,*awork;
1279   Vec            work;
1280   DMDALocalInfo  info;
1281   DM_DA          *dd = (DM_DA*)da->data;
1282   void           (*lf)(DMDALocalInfo*,PetscScalar*,PetscScalar*,PetscScalar*,PetscScalar*,void*,PetscErrorCode*) =
1283                  (void (*)(DMDALocalInfo*,PetscScalar*,PetscScalar*,PetscScalar*,PetscScalar*,void*,PetscErrorCode*))*dd->adiformf_lf;
1284 
1285   PetscFunctionBegin;
1286   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
1287 
1288   ierr = DMGetGlobalVector(da,&work);CHKERRQ(ierr);
1289   ierr = VecGetArray(u,&au);CHKERRQ(ierr);
1290   ierr = VecGetArray(v,&av);CHKERRQ(ierr);
1291   ierr = VecGetArray(f,&af);CHKERRQ(ierr);
1292   ierr = VecGetArray(work,&awork);CHKERRQ(ierr);
1293   (lf)(&info,au,av,awork,af,w,&ierr);CHKERRQ(ierr);
1294   ierr = VecRestoreArray(u,&au);CHKERRQ(ierr);
1295   ierr = VecRestoreArray(v,&av);CHKERRQ(ierr);
1296   ierr = VecRestoreArray(f,&af);CHKERRQ(ierr);
1297   ierr = VecRestoreArray(work,&awork);CHKERRQ(ierr);
1298   ierr = DMRestoreGlobalVector(da,&work);CHKERRQ(ierr);
1299 
1300   PetscFunctionReturn(0);
1301 }
1302 
1303 #undef __FUNCT__
1304 #define __FUNCT__ "DMSetUp_DA_2D"
1305 PetscErrorCode  DMSetUp_DA_2D(DM da)
1306 {
1307   DM_DA                  *dd = (DM_DA*)da->data;
1308   const PetscInt         M            = dd->M;
1309   const PetscInt         N            = dd->N;
1310   PetscInt               m            = dd->m;
1311   PetscInt               n            = dd->n;
1312   const PetscInt         dof          = dd->w;
1313   const PetscInt         s            = dd->s;
1314   const DMDABoundaryType bx         = dd->bx;
1315   const DMDABoundaryType by         = dd->by;
1316   const DMDAStencilType  stencil_type = dd->stencil_type;
1317   PetscInt               *lx           = dd->lx;
1318   PetscInt               *ly           = dd->ly;
1319   MPI_Comm               comm;
1320   PetscMPIInt            rank,size;
1321   PetscInt               xs,xe,ys,ye,x,y,Xs,Xe,Ys,Ye,start,end,IXs,IXe,IYs,IYe;
1322   PetscInt               up,down,left,right,i,n0,n1,n2,n3,n5,n6,n7,n8,*idx,nn,*idx_cpy;
1323   const PetscInt         *idx_full;
1324   PetscInt               xbase,*bases,*ldims,j,x_t,y_t,s_t,base,count;
1325   PetscInt               s_x,s_y; /* s proportionalized to w */
1326   PetscInt               sn0 = 0,sn2 = 0,sn6 = 0,sn8 = 0;
1327   Vec                    local,global;
1328   VecScatter             ltog,gtol;
1329   IS                     to,from,ltogis;
1330   PetscErrorCode         ierr;
1331 
1332   PetscFunctionBegin;
1333   if (dof < 1) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Must have 1 or more degrees of freedom per node: %D",dof);
1334   if (s < 0) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Stencil width cannot be negative: %D",s);
1335   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
1336 #if !defined(PETSC_USE_64BIT_INDICES)
1337   if (((Petsc64bitInt) M)*((Petsc64bitInt) N)*((Petsc64bitInt) dof) > (Petsc64bitInt) PETSC_MPI_INT_MAX) SETERRQ3(comm,PETSC_ERR_INT_OVERFLOW,"Mesh of %D by %D by %D (dof) is too large for 32 bit indices",M,N,dof);
1338 #endif
1339 
1340   if (dof < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Must have 1 or more degrees of freedom per node: %D",dof);
1341   if (s < 0) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Stencil width cannot be negative: %D",s);
1342 
1343   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1344   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1345 
1346   dd->dim         = 2;
1347   ierr = PetscMalloc(dof*sizeof(char*),&dd->fieldname);CHKERRQ(ierr);
1348   ierr = PetscMemzero(dd->fieldname,dof*sizeof(char*));CHKERRQ(ierr);
1349 
1350   if (m != PETSC_DECIDE) {
1351     if (m < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in X direction: %D",m);
1352     else if (m > size) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in X direction: %D %d",m,size);
1353   }
1354   if (n != PETSC_DECIDE) {
1355     if (n < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in Y direction: %D",n);
1356     else if (n > size) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in Y direction: %D %d",n,size);
1357   }
1358 
1359   if (m == PETSC_DECIDE || n == PETSC_DECIDE) {
1360     if (n != PETSC_DECIDE) {
1361       m = size/n;
1362     } else if (m != PETSC_DECIDE) {
1363       n = size/m;
1364     } else {
1365       /* try for squarish distribution */
1366       m = (PetscInt)(0.5 + sqrt(((double)M)*((double)size)/((double)N)));
1367       if (!m) m = 1;
1368       while (m > 0) {
1369 	n = size/m;
1370 	if (m*n == size) break;
1371 	m--;
1372       }
1373       if (M > N && m < n) {PetscInt _m = m; m = n; n = _m;}
1374     }
1375     if (m*n != size) SETERRQ(comm,PETSC_ERR_PLIB,"Unable to create partition, check the size of the communicator and input m and n ");
1376   } else if (m*n != size) SETERRQ(comm,PETSC_ERR_ARG_OUTOFRANGE,"Given Bad partition");
1377 
1378   if (M < m) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Partition in x direction is too fine! %D %D",M,m);
1379   if (N < n) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Partition in y direction is too fine! %D %D",N,n);
1380 
1381   /*
1382      Determine locally owned region
1383      xs is the first local node number, x is the number of local nodes
1384   */
1385   if (!lx) {
1386     ierr = PetscMalloc(m*sizeof(PetscInt), &dd->lx);CHKERRQ(ierr);
1387     lx = dd->lx;
1388     for (i=0; i<m; i++) {
1389       lx[i] = M/m + ((M % m) > i);
1390     }
1391   }
1392   x  = lx[rank % m];
1393   xs = 0;
1394   for (i=0; i<(rank % m); i++) {
1395     xs += lx[i];
1396   }
1397 #if defined(PETSC_USE_DEBUG)
1398   left = xs;
1399   for (i=(rank % m); i<m; i++) {
1400     left += lx[i];
1401   }
1402   if (left != M) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Sum of lx across processors not equal to M: %D %D",left,M);
1403 #endif
1404 
1405   /*
1406      Determine locally owned region
1407      ys is the first local node number, y is the number of local nodes
1408   */
1409   if (!ly) {
1410     ierr = PetscMalloc(n*sizeof(PetscInt), &dd->ly);CHKERRQ(ierr);
1411     ly = dd->ly;
1412     for (i=0; i<n; i++) {
1413       ly[i] = N/n + ((N % n) > i);
1414     }
1415   }
1416   y  = ly[rank/m];
1417   ys = 0;
1418   for (i=0; i<(rank/m); i++) {
1419     ys += ly[i];
1420   }
1421 #if defined(PETSC_USE_DEBUG)
1422   left = ys;
1423   for (i=(rank/m); i<n; i++) {
1424     left += ly[i];
1425   }
1426   if (left != N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Sum of ly across processors not equal to N: %D %D",left,N);
1427 #endif
1428 
1429   /*
1430    check if the scatter requires more than one process neighbor or wraps around
1431    the domain more than once
1432   */
1433   if ((x < s) && ((m > 1) || (bx == DMDA_BOUNDARY_PERIODIC))) {
1434     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local x-width of domain x %D is smaller than stencil width s %D",x,s);
1435   }
1436   if ((y < s) && ((n > 1) || (by == DMDA_BOUNDARY_PERIODIC))) {
1437     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local y-width of domain y %D is smaller than stencil width s %D",y,s);
1438   }
1439   xe = xs + x;
1440   ye = ys + y;
1441 
1442   /* determine ghost region (Xs) and region scattered into (IXs)  */
1443   /* Assume No Periodicity */
1444   if (xs-s > 0) { Xs = xs - s; IXs = xs - s; } else { Xs = 0; IXs = 0; }
1445   if (xe+s <= M) { Xe = xe + s; IXe = xe + s; } else { Xe = M; IXe = M; }
1446   if (ys-s > 0) { Ys = ys - s; IYs = ys - s; } else { Ys = 0; IYs = 0; }
1447   if (ye+s <= N) { Ye = ye + s; IYe = ye + s; } else { Ye = N; IYe = N; }
1448 
1449   /* fix for periodicity/ghosted */
1450   if (bx) { Xs = xs - s; Xe = xe + s; }
1451   if (bx == DMDA_BOUNDARY_PERIODIC) { IXs = xs - s; IXe = xe + s; }
1452   if (by) { Ys = ys - s; Ye = ye + s; }
1453   if (by == DMDA_BOUNDARY_PERIODIC) { IYs = ys - s; IYe = ye + s; }
1454 
1455   /* Resize all X parameters to reflect w */
1456   s_x = s;
1457   s_y = s;
1458 
1459   /* determine starting point of each processor */
1460   nn    = x*y;
1461   ierr  = PetscMalloc2(size+1,PetscInt,&bases,size,PetscInt,&ldims);CHKERRQ(ierr);
1462   ierr  = MPI_Allgather(&nn,1,MPIU_INT,ldims,1,MPIU_INT,comm);CHKERRQ(ierr);
1463   bases[0] = 0;
1464   for (i=1; i<=size; i++) {
1465     bases[i] = ldims[i-1];
1466   }
1467   for (i=1; i<=size; i++) {
1468     bases[i] += bases[i-1];
1469   }
1470   base = bases[rank]*dof;
1471 
1472   /* allocate the base parallel and sequential vectors */
1473   dd->Nlocal = x*y*dof;
1474   ierr = VecCreateMPIWithArray(comm,dof,dd->Nlocal,PETSC_DECIDE,0,&global);CHKERRQ(ierr);
1475   dd->nlocal = (Xe-Xs)*(Ye-Ys)*dof;
1476   ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,dof,dd->nlocal,0,&local);CHKERRQ(ierr);
1477 
1478   /* generate appropriate vector scatters */
1479   /* local to global inserts non-ghost point region into global */
1480   ierr = VecGetOwnershipRange(global,&start,&end);CHKERRQ(ierr);
1481   ierr = ISCreateStride(comm,x*y*dof,start,1,&to);CHKERRQ(ierr);
1482 
1483   count = x*y;
1484   ierr = PetscMalloc(x*y*sizeof(PetscInt),&idx);CHKERRQ(ierr);
1485   left = xs - Xs; right = left + x;
1486   down = ys - Ys; up = down + y;
1487   count = 0;
1488   for (i=down; i<up; i++) {
1489     for (j=left; j<right; j++) {
1490       idx[count++] = i*(Xe-Xs) + j;
1491     }
1492   }
1493 
1494   ierr = ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&from);CHKERRQ(ierr);
1495   ierr = VecScatterCreate(local,from,global,to,&ltog);CHKERRQ(ierr);
1496   ierr = PetscLogObjectParent(dd,ltog);CHKERRQ(ierr);
1497   ierr = ISDestroy(&from);CHKERRQ(ierr);
1498   ierr = ISDestroy(&to);CHKERRQ(ierr);
1499 
1500   /* global to local must include ghost points within the domain,
1501      but not ghost points outside the domain that aren't periodic */
1502   if (stencil_type == DMDA_STENCIL_BOX) {
1503     count = (IXe-IXs)*(IYe-IYs);
1504     ierr  = PetscMalloc(count*sizeof(PetscInt),&idx);CHKERRQ(ierr);
1505 
1506     left = IXs - Xs; right = left + (IXe-IXs);
1507     down = IYs - Ys; up = down + (IYe-IYs);
1508     count = 0;
1509     for (i=down; i<up; i++) {
1510       for (j=left; j<right; j++) {
1511         idx[count++] = j + i*(Xe-Xs);
1512       }
1513     }
1514     ierr = ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&to);CHKERRQ(ierr);
1515 
1516   } else {
1517     /* must drop into cross shape region */
1518     /*       ---------|
1519             |  top    |
1520          |---         ---| up
1521          |   middle      |
1522          |               |
1523          ----         ---- down
1524             | bottom  |
1525             -----------
1526          Xs xs        xe Xe */
1527     count = (ys-IYs)*x + y*(IXe-IXs) + (IYe-ye)*x;
1528     ierr  = PetscMalloc(count*sizeof(PetscInt),&idx);CHKERRQ(ierr);
1529 
1530     left = xs - Xs; right = left + x;
1531     down = ys - Ys; up = down + y;
1532     count = 0;
1533     /* bottom */
1534     for (i=(IYs-Ys); i<down; i++) {
1535       for (j=left; j<right; j++) {
1536         idx[count++] = j + i*(Xe-Xs);
1537       }
1538     }
1539     /* middle */
1540     for (i=down; i<up; i++) {
1541       for (j=(IXs-Xs); j<(IXe-Xs); j++) {
1542         idx[count++] = j + i*(Xe-Xs);
1543       }
1544     }
1545     /* top */
1546     for (i=up; i<up+IYe-ye; i++) {
1547       for (j=left; j<right; j++) {
1548         idx[count++] = j + i*(Xe-Xs);
1549       }
1550     }
1551     ierr = ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&to);CHKERRQ(ierr);
1552   }
1553 
1554 
1555   /* determine who lies on each side of us stored in    n6 n7 n8
1556                                                         n3    n5
1557                                                         n0 n1 n2
1558   */
1559 
1560   /* Assume the Non-Periodic Case */
1561   n1 = rank - m;
1562   if (rank % m) {
1563     n0 = n1 - 1;
1564   } else {
1565     n0 = -1;
1566   }
1567   if ((rank+1) % m) {
1568     n2 = n1 + 1;
1569     n5 = rank + 1;
1570     n8 = rank + m + 1; if (n8 >= m*n) n8 = -1;
1571   } else {
1572     n2 = -1; n5 = -1; n8 = -1;
1573   }
1574   if (rank % m) {
1575     n3 = rank - 1;
1576     n6 = n3 + m; if (n6 >= m*n) n6 = -1;
1577   } else {
1578     n3 = -1; n6 = -1;
1579   }
1580   n7 = rank + m; if (n7 >= m*n) n7 = -1;
1581 
1582   if (bx == DMDA_BOUNDARY_PERIODIC && by == DMDA_BOUNDARY_PERIODIC) {
1583   /* Modify for Periodic Cases */
1584     /* Handle all four corners */
1585     if ((n6 < 0) && (n7 < 0) && (n3 < 0)) n6 = m-1;
1586     if ((n8 < 0) && (n7 < 0) && (n5 < 0)) n8 = 0;
1587     if ((n2 < 0) && (n5 < 0) && (n1 < 0)) n2 = size-m;
1588     if ((n0 < 0) && (n3 < 0) && (n1 < 0)) n0 = size-1;
1589 
1590     /* Handle Top and Bottom Sides */
1591     if (n1 < 0) n1 = rank + m * (n-1);
1592     if (n7 < 0) n7 = rank - m * (n-1);
1593     if ((n3 >= 0) && (n0 < 0)) n0 = size - m + rank - 1;
1594     if ((n3 >= 0) && (n6 < 0)) n6 = (rank%m)-1;
1595     if ((n5 >= 0) && (n2 < 0)) n2 = size - m + rank + 1;
1596     if ((n5 >= 0) && (n8 < 0)) n8 = (rank%m)+1;
1597 
1598     /* Handle Left and Right Sides */
1599     if (n3 < 0) n3 = rank + (m-1);
1600     if (n5 < 0) n5 = rank - (m-1);
1601     if ((n1 >= 0) && (n0 < 0)) n0 = rank-1;
1602     if ((n1 >= 0) && (n2 < 0)) n2 = rank-2*m+1;
1603     if ((n7 >= 0) && (n6 < 0)) n6 = rank+2*m-1;
1604     if ((n7 >= 0) && (n8 < 0)) n8 = rank+1;
1605   } else if (by == DMDA_BOUNDARY_PERIODIC) {  /* Handle Top and Bottom Sides */
1606     if (n1 < 0) n1 = rank + m * (n-1);
1607     if (n7 < 0) n7 = rank - m * (n-1);
1608     if ((n3 >= 0) && (n0 < 0)) n0 = size - m + rank - 1;
1609     if ((n3 >= 0) && (n6 < 0)) n6 = (rank%m)-1;
1610     if ((n5 >= 0) && (n2 < 0)) n2 = size - m + rank + 1;
1611     if ((n5 >= 0) && (n8 < 0)) n8 = (rank%m)+1;
1612   } else if (bx == DMDA_BOUNDARY_PERIODIC) { /* Handle Left and Right Sides */
1613     if (n3 < 0) n3 = rank + (m-1);
1614     if (n5 < 0) n5 = rank - (m-1);
1615     if ((n1 >= 0) && (n0 < 0)) n0 = rank-1;
1616     if ((n1 >= 0) && (n2 < 0)) n2 = rank-2*m+1;
1617     if ((n7 >= 0) && (n6 < 0)) n6 = rank+2*m-1;
1618     if ((n7 >= 0) && (n8 < 0)) n8 = rank+1;
1619   }
1620 
1621   ierr = PetscMalloc(9*sizeof(PetscInt),&dd->neighbors);CHKERRQ(ierr);
1622   dd->neighbors[0] = n0;
1623   dd->neighbors[1] = n1;
1624   dd->neighbors[2] = n2;
1625   dd->neighbors[3] = n3;
1626   dd->neighbors[4] = rank;
1627   dd->neighbors[5] = n5;
1628   dd->neighbors[6] = n6;
1629   dd->neighbors[7] = n7;
1630   dd->neighbors[8] = n8;
1631 
1632   if (stencil_type == DMDA_STENCIL_STAR) {
1633     /* save corner processor numbers */
1634     sn0 = n0; sn2 = n2; sn6 = n6; sn8 = n8;
1635     n0 = n2 = n6 = n8 = -1;
1636   }
1637 
1638   ierr = PetscMalloc((Xe-Xs)*(Ye-Ys)*sizeof(PetscInt),&idx);CHKERRQ(ierr);
1639   ierr = PetscLogObjectMemory(da,(Xe-Xs)*(Ye-Ys)*sizeof(PetscInt));CHKERRQ(ierr);
1640 
1641   nn = 0;
1642   xbase = bases[rank];
1643   for (i=1; i<=s_y; i++) {
1644     if (n0 >= 0) { /* left below */
1645       x_t = lx[n0 % m];
1646       y_t = ly[(n0/m)];
1647       s_t = bases[n0] + x_t*y_t - (s_y-i)*x_t - s_x;
1648       for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1649     }
1650     if (n1 >= 0) { /* directly below */
1651       x_t = x;
1652       y_t = ly[(n1/m)];
1653       s_t = bases[n1] + x_t*y_t - (s_y+1-i)*x_t;
1654       for (j=0; j<x_t; j++) { idx[nn++] = s_t++;}
1655     }
1656     if (n2 >= 0) { /* right below */
1657       x_t = lx[n2 % m];
1658       y_t = ly[(n2/m)];
1659       s_t = bases[n2] + x_t*y_t - (s_y+1-i)*x_t;
1660       for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1661     }
1662   }
1663 
1664   for (i=0; i<y; i++) {
1665     if (n3 >= 0) { /* directly left */
1666       x_t = lx[n3 % m];
1667       /* y_t = y; */
1668       s_t = bases[n3] + (i+1)*x_t - s_x;
1669       for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1670     }
1671 
1672     for (j=0; j<x; j++) { idx[nn++] = xbase++; } /* interior */
1673 
1674     if (n5 >= 0) { /* directly right */
1675       x_t = lx[n5 % m];
1676       /* y_t = y; */
1677       s_t = bases[n5] + (i)*x_t;
1678       for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1679     }
1680   }
1681 
1682   for (i=1; i<=s_y; i++) {
1683     if (n6 >= 0) { /* left above */
1684       x_t = lx[n6 % m];
1685       /* y_t = ly[(n6/m)]; */
1686       s_t = bases[n6] + (i)*x_t - s_x;
1687       for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1688     }
1689     if (n7 >= 0) { /* directly above */
1690       x_t = x;
1691       /* y_t = ly[(n7/m)]; */
1692       s_t = bases[n7] + (i-1)*x_t;
1693       for (j=0; j<x_t; j++) { idx[nn++] = s_t++;}
1694     }
1695     if (n8 >= 0) { /* right above */
1696       x_t = lx[n8 % m];
1697       /* y_t = ly[(n8/m)]; */
1698       s_t = bases[n8] + (i-1)*x_t;
1699       for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1700     }
1701   }
1702 
1703   ierr = ISCreateBlock(comm,dof,nn,idx,PETSC_COPY_VALUES,&from);CHKERRQ(ierr);
1704   ierr = VecScatterCreate(global,from,local,to,&gtol);CHKERRQ(ierr);
1705   ierr = PetscLogObjectParent(da,gtol);CHKERRQ(ierr);
1706   ierr = ISDestroy(&to);CHKERRQ(ierr);
1707   ierr = ISDestroy(&from);CHKERRQ(ierr);
1708 
1709   if (stencil_type == DMDA_STENCIL_STAR) {
1710     n0 = sn0; n2 = sn2; n6 = sn6; n8 = sn8;
1711   }
1712 
1713   if ((stencil_type == DMDA_STENCIL_STAR) ||
1714       (bx && bx != DMDA_BOUNDARY_PERIODIC) ||
1715       (by && by != DMDA_BOUNDARY_PERIODIC)) {
1716     /*
1717         Recompute the local to global mappings, this time keeping the
1718       information about the cross corner processor numbers and any ghosted
1719       but not periodic indices.
1720     */
1721     nn = 0;
1722     xbase = bases[rank];
1723     for (i=1; i<=s_y; i++) {
1724       if (n0 >= 0) { /* left below */
1725         x_t = lx[n0 % m];
1726         y_t = ly[(n0/m)];
1727         s_t = bases[n0] + x_t*y_t - (s_y-i)*x_t - s_x;
1728         for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1729       } else if (xs-Xs > 0 && ys-Ys > 0) {
1730         for (j=0; j<s_x; j++) { idx[nn++] = -1;}
1731       }
1732       if (n1 >= 0) { /* directly below */
1733         x_t = x;
1734         y_t = ly[(n1/m)];
1735         s_t = bases[n1] + x_t*y_t - (s_y+1-i)*x_t;
1736         for (j=0; j<x_t; j++) { idx[nn++] = s_t++;}
1737       } else if (ys-Ys > 0) {
1738         for (j=0; j<x; j++) { idx[nn++] = -1;}
1739       }
1740       if (n2 >= 0) { /* right below */
1741         x_t = lx[n2 % m];
1742         y_t = ly[(n2/m)];
1743         s_t = bases[n2] + x_t*y_t - (s_y+1-i)*x_t;
1744         for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1745       } else if (Xe-xe> 0 && ys-Ys > 0) {
1746         for (j=0; j<s_x; j++) { idx[nn++] = -1;}
1747       }
1748     }
1749 
1750     for (i=0; i<y; i++) {
1751       if (n3 >= 0) { /* directly left */
1752         x_t = lx[n3 % m];
1753         /* y_t = y; */
1754         s_t = bases[n3] + (i+1)*x_t - s_x;
1755         for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1756       } else if (xs-Xs > 0) {
1757         for (j=0; j<s_x; j++) { idx[nn++] = -1;}
1758       }
1759 
1760       for (j=0; j<x; j++) { idx[nn++] = xbase++; } /* interior */
1761 
1762       if (n5 >= 0) { /* directly right */
1763         x_t = lx[n5 % m];
1764         /* y_t = y; */
1765         s_t = bases[n5] + (i)*x_t;
1766         for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1767       } else if (Xe-xe > 0) {
1768         for (j=0; j<s_x; j++) { idx[nn++] = -1;}
1769       }
1770     }
1771 
1772     for (i=1; i<=s_y; i++) {
1773       if (n6 >= 0) { /* left above */
1774         x_t = lx[n6 % m];
1775         /* y_t = ly[(n6/m)]; */
1776         s_t = bases[n6] + (i)*x_t - s_x;
1777         for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1778       } else if (xs-Xs > 0 && Ye-ye > 0) {
1779         for (j=0; j<s_x; j++) { idx[nn++] = -1;}
1780       }
1781       if (n7 >= 0) { /* directly above */
1782         x_t = x;
1783         /* y_t = ly[(n7/m)]; */
1784         s_t = bases[n7] + (i-1)*x_t;
1785         for (j=0; j<x_t; j++) { idx[nn++] = s_t++;}
1786       } else if (Ye-ye > 0) {
1787         for (j=0; j<x; j++) { idx[nn++] = -1;}
1788       }
1789       if (n8 >= 0) { /* right above */
1790         x_t = lx[n8 % m];
1791         /* y_t = ly[(n8/m)]; */
1792         s_t = bases[n8] + (i-1)*x_t;
1793         for (j=0; j<s_x; j++) { idx[nn++] = s_t++;}
1794       } else if (Xe-xe > 0 && Ye-ye > 0) {
1795         for (j=0; j<s_x; j++) { idx[nn++] = -1;}
1796       }
1797     }
1798   }
1799   /*
1800      Set the local to global ordering in the global vector, this allows use
1801      of VecSetValuesLocal().
1802   */
1803   ierr = ISCreateBlock(comm,dof,nn,idx,PETSC_OWN_POINTER,&ltogis);CHKERRQ(ierr);
1804   ierr = PetscMalloc(nn*dof*sizeof(PetscInt),&idx_cpy);CHKERRQ(ierr);
1805   ierr = PetscLogObjectMemory(da,nn*dof*sizeof(PetscInt));CHKERRQ(ierr);
1806   ierr = ISGetIndices(ltogis, &idx_full);
1807   ierr = PetscMemcpy(idx_cpy,idx_full,nn*dof*sizeof(PetscInt));CHKERRQ(ierr);
1808   ierr = ISRestoreIndices(ltogis, &idx_full);
1809   ierr = ISLocalToGlobalMappingCreateIS(ltogis,&da->ltogmap);CHKERRQ(ierr);
1810   ierr = PetscLogObjectParent(da,da->ltogmap);CHKERRQ(ierr);
1811   ierr = ISDestroy(&ltogis);CHKERRQ(ierr);
1812   ierr = ISLocalToGlobalMappingBlock(da->ltogmap,dd->w,&da->ltogmapb);CHKERRQ(ierr);
1813   ierr = PetscLogObjectParent(da,da->ltogmap);CHKERRQ(ierr);
1814 
1815   ierr = PetscFree2(bases,ldims);CHKERRQ(ierr);
1816   dd->m  = m;  dd->n  = n;
1817   /* note petsc expects xs/xe/Xs/Xe to be multiplied by #dofs in many places */
1818   dd->xs = xs*dof; dd->xe = xe*dof; dd->ys = ys; dd->ye = ye; dd->zs = 0; dd->ze = 1;
1819   dd->Xs = Xs*dof; dd->Xe = Xe*dof; dd->Ys = Ys; dd->Ye = Ye; dd->Zs = 0; dd->Ze = 1;
1820 
1821   ierr = VecDestroy(&local);CHKERRQ(ierr);
1822   ierr = VecDestroy(&global);CHKERRQ(ierr);
1823 
1824   dd->gtol      = gtol;
1825   dd->ltog      = ltog;
1826   dd->idx       = idx_cpy;
1827   dd->Nl        = nn*dof;
1828   dd->base      = base;
1829   da->ops->view = DMView_DA_2d;
1830   dd->ltol = PETSC_NULL;
1831   dd->ao   = PETSC_NULL;
1832 
1833   PetscFunctionReturn(0);
1834 }
1835 
1836 #undef __FUNCT__
1837 #define __FUNCT__ "DMDACreate2d"
1838 /*@C
1839    DMDACreate2d -  Creates an object that will manage the communication of  two-dimensional
1840    regular array data that is distributed across some processors.
1841 
1842    Collective on MPI_Comm
1843 
1844    Input Parameters:
1845 +  comm - MPI communicator
1846 .  bx,by - type of ghost nodes the array have.
1847          Use one of DMDA_BOUNDARY_NONE, DMDA_BOUNDARY_GHOSTED, DMDA_BOUNDARY_PERIODIC.
1848 .  stencil_type - stencil type.  Use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
1849 .  M,N - global dimension in each direction of the array (use -M and or -N to indicate that it may be set to a different value
1850             from the command line with -da_grid_x <M> -da_grid_y <N>)
1851 .  m,n - corresponding number of processors in each dimension
1852          (or PETSC_DECIDE to have calculated)
1853 .  dof - number of degrees of freedom per node
1854 .  s - stencil width
1855 -  lx, ly - arrays containing the number of nodes in each cell along
1856            the x and y coordinates, or PETSC_NULL. If non-null, these
1857            must be of length as m and n, and the corresponding
1858            m and n cannot be PETSC_DECIDE. The sum of the lx[] entries
1859            must be M, and the sum of the ly[] entries must be N.
1860 
1861    Output Parameter:
1862 .  da - the resulting distributed array object
1863 
1864    Options Database Key:
1865 +  -da_view - Calls DMView() at the conclusion of DMDACreate2d()
1866 .  -da_grid_x <nx> - number of grid points in x direction, if M < 0
1867 .  -da_grid_y <ny> - number of grid points in y direction, if N < 0
1868 .  -da_processors_x <nx> - number of processors in x direction
1869 .  -da_processors_y <ny> - number of processors in y direction
1870 .  -da_refine_x <rx> - refinement ratio in x direction
1871 .  -da_refine_y <ry> - refinement ratio in y direction
1872 -  -da_refine <n> - refine the DMDA n times before creating, if M or N < 0
1873 
1874 
1875    Level: beginner
1876 
1877    Notes:
1878    The stencil type DMDA_STENCIL_STAR with width 1 corresponds to the
1879    standard 5-pt stencil, while DMDA_STENCIL_BOX with width 1 denotes
1880    the standard 9-pt stencil.
1881 
1882    The array data itself is NOT stored in the DMDA, it is stored in Vec objects;
1883    The appropriate vector objects can be obtained with calls to DMCreateGlobalVector()
1884    and DMCreateLocalVector() and calls to VecDuplicate() if more are needed.
1885 
1886 .keywords: distributed array, create, two-dimensional
1887 
1888 .seealso: DMDestroy(), DMView(), DMDACreate1d(), DMDACreate3d(), DMGlobalToLocalBegin(), DMDAGetRefinementFactor(),
1889           DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMDALocalToLocalBegin(), DMDALocalToLocalEnd(), DMDASetRefinementFactor(),
1890           DMDAGetInfo(), DMCreateGlobalVector(), DMCreateLocalVector(), DMDACreateNaturalVector(), DMLoad(), DMDAGetOwnershipRanges()
1891 
1892 @*/
1893 
1894 PetscErrorCode  DMDACreate2d(MPI_Comm comm,DMDABoundaryType bx,DMDABoundaryType by,DMDAStencilType stencil_type,
1895                           PetscInt M,PetscInt N,PetscInt m,PetscInt n,PetscInt dof,PetscInt s,const PetscInt lx[],const PetscInt ly[],DM *da)
1896 {
1897   PetscErrorCode ierr;
1898 
1899   PetscFunctionBegin;
1900   ierr = DMDACreate(comm, da);CHKERRQ(ierr);
1901   ierr = DMDASetDim(*da, 2);CHKERRQ(ierr);
1902   ierr = DMDASetSizes(*da, M, N, 1);CHKERRQ(ierr);
1903   ierr = DMDASetNumProcs(*da, m, n, PETSC_DECIDE);CHKERRQ(ierr);
1904   ierr = DMDASetBoundaryType(*da, bx, by, DMDA_BOUNDARY_NONE);CHKERRQ(ierr);
1905   ierr = DMDASetDof(*da, dof);CHKERRQ(ierr);
1906   ierr = DMDASetStencilType(*da, stencil_type);CHKERRQ(ierr);
1907   ierr = DMDASetStencilWidth(*da, s);CHKERRQ(ierr);
1908   ierr = DMDASetOwnershipRanges(*da, lx, ly, PETSC_NULL);CHKERRQ(ierr);
1909   /* This violates the behavior for other classes, but right now users expect negative dimensions to be handled this way */
1910   ierr = DMSetFromOptions(*da);CHKERRQ(ierr);
1911   ierr = DMSetUp(*da);CHKERRQ(ierr);
1912   ierr = DMView_DA_Private(*da);CHKERRQ(ierr);
1913   PetscFunctionReturn(0);
1914 }
1915