xref: /petsc/src/dm/impls/da/da2.c (revision 7453f77509fc006cbcc7de2dd772f60dc49feac5)
1 
2 #include <petsc/private/dmdaimpl.h>    /*I   "petscdmda.h"   I*/
3 #include <petscdraw.h>
4 
5 #undef __FUNCT__
6 #define __FUNCT__ "DMView_DA_2d"
7 static PetscErrorCode DMView_DA_2d(DM da,PetscViewer viewer)
8 {
9   PetscErrorCode ierr;
10   PetscMPIInt    rank;
11   PetscBool      iascii,isdraw,isbinary;
12   DM_DA          *dd = (DM_DA*)da->data;
13 #if defined(PETSC_HAVE_MATLAB_ENGINE)
14   PetscBool ismatlab;
15 #endif
16 
17   PetscFunctionBegin;
18   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)da),&rank);CHKERRQ(ierr);
19 
20   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
21   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
22   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
23 #if defined(PETSC_HAVE_MATLAB_ENGINE)
24   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERMATLAB,&ismatlab);CHKERRQ(ierr);
25 #endif
26   if (iascii) {
27     PetscViewerFormat format;
28 
29     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
30     if (format != PETSC_VIEWER_ASCII_VTK && format != PETSC_VIEWER_ASCII_VTK_CELL) {
31       DMDALocalInfo info;
32       ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
33       ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
34       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);
35       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);
36       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
37       ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
38     } else {
39       ierr = DMView_DA_VTK(da,viewer);CHKERRQ(ierr);
40     }
41   } else if (isdraw) {
42     PetscDraw      draw;
43     double         ymin = -1*dd->s-1,ymax = dd->N+dd->s;
44     double         xmin = -1*dd->s-1,xmax = dd->M+dd->s;
45     double         x,y;
46     PetscInt       base;
47     const PetscInt *idx;
48     char           node[10];
49     PetscBool      isnull;
50 
51     ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
52     ierr = PetscDrawIsNull(draw,&isnull);CHKERRQ(ierr);
53     if (isnull) PetscFunctionReturn(0);
54 
55     ierr = PetscDrawCheckResizedWindow(draw);CHKERRQ(ierr);
56     ierr = PetscDrawClear(draw);CHKERRQ(ierr);
57     ierr = PetscDrawSetCoordinates(draw,xmin,ymin,xmax,ymax);CHKERRQ(ierr);
58 
59     ierr = PetscDrawCollectiveBegin(draw);CHKERRQ(ierr);
60     /* first processor draw all node lines */
61     if (!rank) {
62       ymin = 0.0; ymax = dd->N - 1;
63       for (xmin=0; xmin<dd->M; xmin++) {
64         ierr = PetscDrawLine(draw,xmin,ymin,xmin,ymax,PETSC_DRAW_BLACK);CHKERRQ(ierr);
65       }
66       xmin = 0.0; xmax = dd->M - 1;
67       for (ymin=0; ymin<dd->N; ymin++) {
68         ierr = PetscDrawLine(draw,xmin,ymin,xmax,ymin,PETSC_DRAW_BLACK);CHKERRQ(ierr);
69       }
70     }
71     ierr = PetscDrawCollectiveEnd(draw);CHKERRQ(ierr);
72     ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
73     ierr = PetscDrawPause(draw);CHKERRQ(ierr);
74 
75     ierr = PetscDrawCollectiveBegin(draw);CHKERRQ(ierr);
76     /* draw my box */
77     xmin = dd->xs/dd->w; xmax =(dd->xe-1)/dd->w; ymin = dd->ys; ymax = dd->ye - 1;
78     ierr = PetscDrawLine(draw,xmin,ymin,xmax,ymin,PETSC_DRAW_RED);CHKERRQ(ierr);
79     ierr = PetscDrawLine(draw,xmin,ymin,xmin,ymax,PETSC_DRAW_RED);CHKERRQ(ierr);
80     ierr = PetscDrawLine(draw,xmin,ymax,xmax,ymax,PETSC_DRAW_RED);CHKERRQ(ierr);
81     ierr = PetscDrawLine(draw,xmax,ymin,xmax,ymax,PETSC_DRAW_RED);CHKERRQ(ierr);
82     /* put in numbers */
83     base = (dd->base)/dd->w;
84     for (y=ymin; y<=ymax; y++) {
85       for (x=xmin; x<=xmax; x++) {
86         ierr = PetscSNPrintf(node,sizeof(node),"%d",(int)base++);CHKERRQ(ierr);
87         ierr = PetscDrawString(draw,x,y,PETSC_DRAW_BLACK,node);CHKERRQ(ierr);
88       }
89     }
90     ierr = PetscDrawCollectiveEnd(draw);CHKERRQ(ierr);
91     ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
92     ierr = PetscDrawPause(draw);CHKERRQ(ierr);
93 
94     ierr = PetscDrawCollectiveBegin(draw);CHKERRQ(ierr);
95     /* overlay ghost numbers, useful for error checking */
96     ierr = ISLocalToGlobalMappingGetBlockIndices(da->ltogmap,&idx);CHKERRQ(ierr);
97     base = 0; xmin = dd->Xs; xmax = dd->Xe; ymin = dd->Ys; ymax = dd->Ye;
98     for (y=ymin; y<ymax; y++) {
99       for (x=xmin; x<xmax; x++) {
100         if ((base % dd->w) == 0) {
101           ierr = PetscSNPrintf(node,sizeof(node),"%d",(int)(idx[base/dd->w]));CHKERRQ(ierr);
102           ierr = PetscDrawString(draw,x/dd->w,y,PETSC_DRAW_BLUE,node);CHKERRQ(ierr);
103         }
104         base++;
105       }
106     }
107     ierr = ISLocalToGlobalMappingRestoreBlockIndices(da->ltogmap,&idx);CHKERRQ(ierr);
108     ierr = PetscDrawCollectiveEnd(draw);CHKERRQ(ierr);
109     ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
110     ierr = PetscDrawPause(draw);CHKERRQ(ierr);
111     ierr = PetscDrawSave(draw);CHKERRQ(ierr);
112   } else if (isbinary) {
113     ierr = DMView_DA_Binary(da,viewer);CHKERRQ(ierr);
114 #if defined(PETSC_HAVE_MATLAB_ENGINE)
115   } else if (ismatlab) {
116     ierr = DMView_DA_Matlab(da,viewer);CHKERRQ(ierr);
117 #endif
118   }
119   PetscFunctionReturn(0);
120 }
121 
122 /*
123       M is number of grid points
124       m is number of processors
125 
126 */
127 #undef __FUNCT__
128 #define __FUNCT__ "DMDASplitComm2d"
129 PetscErrorCode  DMDASplitComm2d(MPI_Comm comm,PetscInt M,PetscInt N,PetscInt sw,MPI_Comm *outcomm)
130 {
131   PetscErrorCode ierr;
132   PetscInt       m,n = 0,x = 0,y = 0;
133   PetscMPIInt    size,csize,rank;
134 
135   PetscFunctionBegin;
136   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
137   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
138 
139   csize = 4*size;
140   do {
141     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);
142     csize = csize/4;
143 
144     m = (PetscInt)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)csize)/((PetscReal)N)));
145     if (!m) m = 1;
146     while (m > 0) {
147       n = csize/m;
148       if (m*n == csize) break;
149       m--;
150     }
151     if (M > N && m < n) {PetscInt _m = m; m = n; n = _m;}
152 
153     x = M/m + ((M % m) > ((csize-1) % m));
154     y = (N + (csize-1)/m)/n;
155   } while ((x < 4 || y < 4) && csize > 1);
156   if (size != csize) {
157     MPI_Group   entire_group,sub_group;
158     PetscMPIInt i,*groupies;
159 
160     ierr = MPI_Comm_group(comm,&entire_group);CHKERRQ(ierr);
161     ierr = PetscMalloc1(csize,&groupies);CHKERRQ(ierr);
162     for (i=0; i<csize; i++) {
163       groupies[i] = (rank/csize)*csize + i;
164     }
165     ierr = MPI_Group_incl(entire_group,csize,groupies,&sub_group);CHKERRQ(ierr);
166     ierr = PetscFree(groupies);CHKERRQ(ierr);
167     ierr = MPI_Comm_create(comm,sub_group,outcomm);CHKERRQ(ierr);
168     ierr = MPI_Group_free(&entire_group);CHKERRQ(ierr);
169     ierr = MPI_Group_free(&sub_group);CHKERRQ(ierr);
170     ierr = PetscInfo1(0,"DMDASplitComm2d:Creating redundant coarse problems of size %d\n",csize);CHKERRQ(ierr);
171   } else {
172     *outcomm = comm;
173   }
174   PetscFunctionReturn(0);
175 }
176 
177 #if defined(new)
178 #undef __FUNCT__
179 #define __FUNCT__ "DMDAGetDiagonal_MFFD"
180 /*
181   DMDAGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix where local
182     function lives on a DMDA
183 
184         y ~= (F(u + ha) - F(u))/h,
185   where F = nonlinear function, as set by SNESSetFunction()
186         u = current iterate
187         h = difference interval
188 */
189 PetscErrorCode DMDAGetDiagonal_MFFD(DM da,Vec U,Vec a)
190 {
191   PetscScalar    h,*aa,*ww,v;
192   PetscReal      epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
193   PetscErrorCode ierr;
194   PetscInt       gI,nI;
195   MatStencil     stencil;
196   DMDALocalInfo  info;
197 
198   PetscFunctionBegin;
199   ierr = (*ctx->func)(0,U,a,ctx->funcctx);CHKERRQ(ierr);
200   ierr = (*ctx->funcisetbase)(U,ctx->funcctx);CHKERRQ(ierr);
201 
202   ierr = VecGetArray(U,&ww);CHKERRQ(ierr);
203   ierr = VecGetArray(a,&aa);CHKERRQ(ierr);
204 
205   nI = 0;
206   h  = ww[gI];
207   if (h == 0.0) h = 1.0;
208   if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin;
209   else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
210   h *= epsilon;
211 
212   ww[gI] += h;
213   ierr    = (*ctx->funci)(i,w,&v,ctx->funcctx);CHKERRQ(ierr);
214   aa[nI]  = (v - aa[nI])/h;
215   ww[gI] -= h;
216   nI++;
217 
218   ierr = VecRestoreArray(U,&ww);CHKERRQ(ierr);
219   ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr);
220   PetscFunctionReturn(0);
221 }
222 #endif
223 
224 #undef __FUNCT__
225 #define __FUNCT__ "DMSetUp_DA_2D"
226 PetscErrorCode  DMSetUp_DA_2D(DM da)
227 {
228   DM_DA            *dd = (DM_DA*)da->data;
229   const PetscInt   M            = dd->M;
230   const PetscInt   N            = dd->N;
231   PetscInt         m            = dd->m;
232   PetscInt         n            = dd->n;
233   const PetscInt   dof          = dd->w;
234   const PetscInt   s            = dd->s;
235   DMBoundaryType   bx           = dd->bx;
236   DMBoundaryType   by           = dd->by;
237   DMDAStencilType  stencil_type = dd->stencil_type;
238   PetscInt         *lx          = dd->lx;
239   PetscInt         *ly          = dd->ly;
240   MPI_Comm         comm;
241   PetscMPIInt      rank,size;
242   PetscInt         xs,xe,ys,ye,x,y,Xs,Xe,Ys,Ye,IXs,IXe,IYs,IYe;
243   PetscInt         up,down,left,right,i,n0,n1,n2,n3,n5,n6,n7,n8,*idx,nn;
244   PetscInt         xbase,*bases,*ldims,j,x_t,y_t,s_t,base,count;
245   PetscInt         s_x,s_y; /* s proportionalized to w */
246   PetscInt         sn0 = 0,sn2 = 0,sn6 = 0,sn8 = 0;
247   Vec              local,global;
248   VecScatter       gtol;
249   IS               to,from;
250   PetscErrorCode   ierr;
251 
252   PetscFunctionBegin;
253   if (stencil_type == DMDA_STENCIL_BOX && (bx == DM_BOUNDARY_MIRROR || by == DM_BOUNDARY_MIRROR)) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Mirror boundary and box stencil");
254   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
255 #if !defined(PETSC_USE_64BIT_INDICES)
256   if (((PetscInt64) M)*((PetscInt64) N)*((PetscInt64) dof) > (PetscInt64) 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);
257 #endif
258 
259   if (dof < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Must have 1 or more degrees of freedom per node: %D",dof);
260   if (s < 0) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Stencil width cannot be negative: %D",s);
261 
262   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
263   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
264 
265   dd->p = 1;
266   if (m != PETSC_DECIDE) {
267     if (m < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in X direction: %D",m);
268     else if (m > size) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in X direction: %D %d",m,size);
269   }
270   if (n != PETSC_DECIDE) {
271     if (n < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in Y direction: %D",n);
272     else if (n > size) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in Y direction: %D %d",n,size);
273   }
274 
275   if (m == PETSC_DECIDE || n == PETSC_DECIDE) {
276     if (n != PETSC_DECIDE) {
277       m = size/n;
278     } else if (m != PETSC_DECIDE) {
279       n = size/m;
280     } else {
281       /* try for squarish distribution */
282       m = (PetscInt)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)size)/((PetscReal)N)));
283       if (!m) m = 1;
284       while (m > 0) {
285         n = size/m;
286         if (m*n == size) break;
287         m--;
288       }
289       if (M > N && m < n) {PetscInt _m = m; m = n; n = _m;}
290     }
291     if (m*n != size) SETERRQ(comm,PETSC_ERR_PLIB,"Unable to create partition, check the size of the communicator and input m and n ");
292   } else if (m*n != size) SETERRQ(comm,PETSC_ERR_ARG_OUTOFRANGE,"Given Bad partition");
293 
294   if (M < m) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Partition in x direction is too fine! %D %D",M,m);
295   if (N < n) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Partition in y direction is too fine! %D %D",N,n);
296 
297   /*
298      Determine locally owned region
299      xs is the first local node number, x is the number of local nodes
300   */
301   if (!lx) {
302     ierr = PetscMalloc1(m, &dd->lx);CHKERRQ(ierr);
303     lx   = dd->lx;
304     for (i=0; i<m; i++) {
305       lx[i] = M/m + ((M % m) > i);
306     }
307   }
308   x  = lx[rank % m];
309   xs = 0;
310   for (i=0; i<(rank % m); i++) {
311     xs += lx[i];
312   }
313 #if defined(PETSC_USE_DEBUG)
314   left = xs;
315   for (i=(rank % m); i<m; i++) {
316     left += lx[i];
317   }
318   if (left != M) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Sum of lx across processors not equal to M: %D %D",left,M);
319 #endif
320 
321   /*
322      Determine locally owned region
323      ys is the first local node number, y is the number of local nodes
324   */
325   if (!ly) {
326     ierr = PetscMalloc1(n, &dd->ly);CHKERRQ(ierr);
327     ly   = dd->ly;
328     for (i=0; i<n; i++) {
329       ly[i] = N/n + ((N % n) > i);
330     }
331   }
332   y  = ly[rank/m];
333   ys = 0;
334   for (i=0; i<(rank/m); i++) {
335     ys += ly[i];
336   }
337 #if defined(PETSC_USE_DEBUG)
338   left = ys;
339   for (i=(rank/m); i<n; i++) {
340     left += ly[i];
341   }
342   if (left != N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Sum of ly across processors not equal to N: %D %D",left,N);
343 #endif
344 
345   /*
346    check if the scatter requires more than one process neighbor or wraps around
347    the domain more than once
348   */
349   if ((x < s) && ((m > 1) || (bx == DM_BOUNDARY_PERIODIC))) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local x-width of domain x %D is smaller than stencil width s %D",x,s);
350   if ((y < s) && ((n > 1) || (by == DM_BOUNDARY_PERIODIC))) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local y-width of domain y %D is smaller than stencil width s %D",y,s);
351   xe = xs + x;
352   ye = ys + y;
353 
354   /* determine ghost region (Xs) and region scattered into (IXs)  */
355   if (xs-s > 0) {
356     Xs = xs - s; IXs = xs - s;
357   } else {
358     if (bx) {
359       Xs = xs - s;
360     } else {
361       Xs = 0;
362     }
363     IXs = 0;
364   }
365   if (xe+s <= M) {
366     Xe = xe + s; IXe = xe + s;
367   } else {
368     if (bx) {
369       Xs = xs - s; Xe = xe + s;
370     } else {
371       Xe = M;
372     }
373     IXe = M;
374   }
375 
376   if (bx == DM_BOUNDARY_PERIODIC || bx == DM_BOUNDARY_MIRROR) {
377     IXs = xs - s;
378     IXe = xe + s;
379     Xs  = xs - s;
380     Xe  = xe + s;
381   }
382 
383   if (ys-s > 0) {
384     Ys = ys - s; IYs = ys - s;
385   } else {
386     if (by) {
387       Ys = ys - s;
388     } else {
389       Ys = 0;
390     }
391     IYs = 0;
392   }
393   if (ye+s <= N) {
394     Ye = ye + s; IYe = ye + s;
395   } else {
396     if (by) {
397       Ye = ye + s;
398     } else {
399       Ye = N;
400     }
401     IYe = N;
402   }
403 
404   if (by == DM_BOUNDARY_PERIODIC || by == DM_BOUNDARY_MIRROR) {
405     IYs = ys - s;
406     IYe = ye + s;
407     Ys  = ys - s;
408     Ye  = ye + s;
409   }
410 
411   /* stencil length in each direction */
412   s_x = s;
413   s_y = s;
414 
415   /* determine starting point of each processor */
416   nn       = x*y;
417   ierr     = PetscMalloc2(size+1,&bases,size,&ldims);CHKERRQ(ierr);
418   ierr     = MPI_Allgather(&nn,1,MPIU_INT,ldims,1,MPIU_INT,comm);CHKERRQ(ierr);
419   bases[0] = 0;
420   for (i=1; i<=size; i++) {
421     bases[i] = ldims[i-1];
422   }
423   for (i=1; i<=size; i++) {
424     bases[i] += bases[i-1];
425   }
426   base = bases[rank]*dof;
427 
428   /* allocate the base parallel and sequential vectors */
429   dd->Nlocal = x*y*dof;
430   ierr       = VecCreateMPIWithArray(comm,dof,dd->Nlocal,PETSC_DECIDE,NULL,&global);CHKERRQ(ierr);
431   dd->nlocal = (Xe-Xs)*(Ye-Ys)*dof;
432   ierr       = VecCreateSeqWithArray(PETSC_COMM_SELF,dof,dd->nlocal,NULL,&local);CHKERRQ(ierr);
433 
434   /* generate appropriate vector scatters */
435   /* local to global inserts non-ghost point region into global */
436   ierr  = PetscMalloc1((IXe-IXs)*(IYe-IYs),&idx);CHKERRQ(ierr);
437   left  = xs - Xs; right = left + x;
438   down  = ys - Ys; up = down + y;
439   count = 0;
440   for (i=down; i<up; i++) {
441     for (j=left; j<right; j++) {
442       idx[count++] = i*(Xe-Xs) + j;
443     }
444   }
445 
446   /* global to local must include ghost points within the domain,
447      but not ghost points outside the domain that aren't periodic */
448   if (stencil_type == DMDA_STENCIL_BOX) {
449     left  = IXs - Xs; right = left + (IXe-IXs);
450     down  = IYs - Ys; up = down + (IYe-IYs);
451     count = 0;
452     for (i=down; i<up; i++) {
453       for (j=left; j<right; j++) {
454         idx[count++] = j + i*(Xe-Xs);
455       }
456     }
457     ierr = ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&to);CHKERRQ(ierr);
458 
459   } else {
460     /* must drop into cross shape region */
461     /*       ---------|
462             |  top    |
463          |---         ---| up
464          |   middle      |
465          |               |
466          ----         ---- down
467             | bottom  |
468             -----------
469          Xs xs        xe Xe */
470     left  = xs - Xs; right = left + x;
471     down  = ys - Ys; up = down + y;
472     count = 0;
473     /* bottom */
474     for (i=(IYs-Ys); i<down; i++) {
475       for (j=left; j<right; j++) {
476         idx[count++] = j + i*(Xe-Xs);
477       }
478     }
479     /* middle */
480     for (i=down; i<up; i++) {
481       for (j=(IXs-Xs); j<(IXe-Xs); j++) {
482         idx[count++] = j + i*(Xe-Xs);
483       }
484     }
485     /* top */
486     for (i=up; i<up+IYe-ye; i++) {
487       for (j=left; j<right; j++) {
488         idx[count++] = j + i*(Xe-Xs);
489       }
490     }
491     ierr = ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&to);CHKERRQ(ierr);
492   }
493 
494 
495   /* determine who lies on each side of us stored in    n6 n7 n8
496                                                         n3    n5
497                                                         n0 n1 n2
498   */
499 
500   /* Assume the Non-Periodic Case */
501   n1 = rank - m;
502   if (rank % m) {
503     n0 = n1 - 1;
504   } else {
505     n0 = -1;
506   }
507   if ((rank+1) % m) {
508     n2 = n1 + 1;
509     n5 = rank + 1;
510     n8 = rank + m + 1; if (n8 >= m*n) n8 = -1;
511   } else {
512     n2 = -1; n5 = -1; n8 = -1;
513   }
514   if (rank % m) {
515     n3 = rank - 1;
516     n6 = n3 + m; if (n6 >= m*n) n6 = -1;
517   } else {
518     n3 = -1; n6 = -1;
519   }
520   n7 = rank + m; if (n7 >= m*n) n7 = -1;
521 
522   if (bx == DM_BOUNDARY_PERIODIC && by == DM_BOUNDARY_PERIODIC) {
523     /* Modify for Periodic Cases */
524     /* Handle all four corners */
525     if ((n6 < 0) && (n7 < 0) && (n3 < 0)) n6 = m-1;
526     if ((n8 < 0) && (n7 < 0) && (n5 < 0)) n8 = 0;
527     if ((n2 < 0) && (n5 < 0) && (n1 < 0)) n2 = size-m;
528     if ((n0 < 0) && (n3 < 0) && (n1 < 0)) n0 = size-1;
529 
530     /* Handle Top and Bottom Sides */
531     if (n1 < 0) n1 = rank + m * (n-1);
532     if (n7 < 0) n7 = rank - m * (n-1);
533     if ((n3 >= 0) && (n0 < 0)) n0 = size - m + rank - 1;
534     if ((n3 >= 0) && (n6 < 0)) n6 = (rank%m)-1;
535     if ((n5 >= 0) && (n2 < 0)) n2 = size - m + rank + 1;
536     if ((n5 >= 0) && (n8 < 0)) n8 = (rank%m)+1;
537 
538     /* Handle Left and Right Sides */
539     if (n3 < 0) n3 = rank + (m-1);
540     if (n5 < 0) n5 = rank - (m-1);
541     if ((n1 >= 0) && (n0 < 0)) n0 = rank-1;
542     if ((n1 >= 0) && (n2 < 0)) n2 = rank-2*m+1;
543     if ((n7 >= 0) && (n6 < 0)) n6 = rank+2*m-1;
544     if ((n7 >= 0) && (n8 < 0)) n8 = rank+1;
545   } else if (by == DM_BOUNDARY_PERIODIC) {  /* Handle Top and Bottom Sides */
546     if (n1 < 0) n1 = rank + m * (n-1);
547     if (n7 < 0) n7 = rank - m * (n-1);
548     if ((n3 >= 0) && (n0 < 0)) n0 = size - m + rank - 1;
549     if ((n3 >= 0) && (n6 < 0)) n6 = (rank%m)-1;
550     if ((n5 >= 0) && (n2 < 0)) n2 = size - m + rank + 1;
551     if ((n5 >= 0) && (n8 < 0)) n8 = (rank%m)+1;
552   } else if (bx == DM_BOUNDARY_PERIODIC) { /* Handle Left and Right Sides */
553     if (n3 < 0) n3 = rank + (m-1);
554     if (n5 < 0) n5 = rank - (m-1);
555     if ((n1 >= 0) && (n0 < 0)) n0 = rank-1;
556     if ((n1 >= 0) && (n2 < 0)) n2 = rank-2*m+1;
557     if ((n7 >= 0) && (n6 < 0)) n6 = rank+2*m-1;
558     if ((n7 >= 0) && (n8 < 0)) n8 = rank+1;
559   }
560 
561   ierr = PetscMalloc1(9,&dd->neighbors);CHKERRQ(ierr);
562 
563   dd->neighbors[0] = n0;
564   dd->neighbors[1] = n1;
565   dd->neighbors[2] = n2;
566   dd->neighbors[3] = n3;
567   dd->neighbors[4] = rank;
568   dd->neighbors[5] = n5;
569   dd->neighbors[6] = n6;
570   dd->neighbors[7] = n7;
571   dd->neighbors[8] = n8;
572 
573   if (stencil_type == DMDA_STENCIL_STAR) {
574     /* save corner processor numbers */
575     sn0 = n0; sn2 = n2; sn6 = n6; sn8 = n8;
576     n0  = n2 = n6 = n8 = -1;
577   }
578 
579   ierr = PetscMalloc1((Xe-Xs)*(Ye-Ys),&idx);CHKERRQ(ierr);
580 
581   nn = 0;
582   xbase = bases[rank];
583   for (i=1; i<=s_y; i++) {
584     if (n0 >= 0) { /* left below */
585       x_t = lx[n0 % m];
586       y_t = ly[(n0/m)];
587       s_t = bases[n0] + x_t*y_t - (s_y-i)*x_t - s_x;
588       for (j=0; j<s_x; j++) idx[nn++] = s_t++;
589     }
590 
591     if (n1 >= 0) { /* directly below */
592       x_t = x;
593       y_t = ly[(n1/m)];
594       s_t = bases[n1] + x_t*y_t - (s_y+1-i)*x_t;
595       for (j=0; j<x_t; j++) idx[nn++] = s_t++;
596     } else if (by == DM_BOUNDARY_MIRROR) {
597       for (j=0; j<x; j++) idx[nn++] = bases[rank] + x*(s_y - i + 1)  + j;
598     }
599 
600     if (n2 >= 0) { /* right below */
601       x_t = lx[n2 % m];
602       y_t = ly[(n2/m)];
603       s_t = bases[n2] + x_t*y_t - (s_y+1-i)*x_t;
604       for (j=0; j<s_x; j++) idx[nn++] = s_t++;
605     }
606   }
607 
608   for (i=0; i<y; i++) {
609     if (n3 >= 0) { /* directly left */
610       x_t = lx[n3 % m];
611       /* y_t = y; */
612       s_t = bases[n3] + (i+1)*x_t - s_x;
613       for (j=0; j<s_x; j++) idx[nn++] = s_t++;
614     } else if (bx == DM_BOUNDARY_MIRROR) {
615       for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x*i + s_x - j;
616     }
617 
618     for (j=0; j<x; j++) idx[nn++] = xbase++; /* interior */
619 
620     if (n5 >= 0) { /* directly right */
621       x_t = lx[n5 % m];
622       /* y_t = y; */
623       s_t = bases[n5] + (i)*x_t;
624       for (j=0; j<s_x; j++) idx[nn++] = s_t++;
625     } else if (bx == DM_BOUNDARY_MIRROR) {
626       for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x*(i + 1) - 2 - j;
627     }
628   }
629 
630   for (i=1; i<=s_y; i++) {
631     if (n6 >= 0) { /* left above */
632       x_t = lx[n6 % m];
633       /* y_t = ly[(n6/m)]; */
634       s_t = bases[n6] + (i)*x_t - s_x;
635       for (j=0; j<s_x; j++) idx[nn++] = s_t++;
636     }
637 
638     if (n7 >= 0) { /* directly above */
639       x_t = x;
640       /* y_t = ly[(n7/m)]; */
641       s_t = bases[n7] + (i-1)*x_t;
642       for (j=0; j<x_t; j++) idx[nn++] = s_t++;
643     } else if (by == DM_BOUNDARY_MIRROR) {
644       for (j=0; j<x; j++) idx[nn++] = bases[rank] + x*(y - i - 1)  + j;
645     }
646 
647     if (n8 >= 0) { /* right above */
648       x_t = lx[n8 % m];
649       /* y_t = ly[(n8/m)]; */
650       s_t = bases[n8] + (i-1)*x_t;
651       for (j=0; j<s_x; j++) idx[nn++] = s_t++;
652     }
653   }
654 
655   ierr = ISCreateBlock(comm,dof,nn,idx,PETSC_USE_POINTER,&from);CHKERRQ(ierr);
656   ierr = VecScatterCreate(global,from,local,to,&gtol);CHKERRQ(ierr);
657   ierr = PetscLogObjectParent((PetscObject)da,(PetscObject)gtol);CHKERRQ(ierr);
658   ierr = ISDestroy(&to);CHKERRQ(ierr);
659   ierr = ISDestroy(&from);CHKERRQ(ierr);
660 
661   if (stencil_type == DMDA_STENCIL_STAR) {
662     n0 = sn0; n2 = sn2; n6 = sn6; n8 = sn8;
663   }
664 
665   if (((stencil_type == DMDA_STENCIL_STAR)  ||
666        (bx && bx != DM_BOUNDARY_PERIODIC) ||
667        (by && by != DM_BOUNDARY_PERIODIC))) {
668     /*
669         Recompute the local to global mappings, this time keeping the
670       information about the cross corner processor numbers and any ghosted
671       but not periodic indices.
672     */
673     nn    = 0;
674     xbase = bases[rank];
675     for (i=1; i<=s_y; i++) {
676       if (n0 >= 0) { /* left below */
677         x_t = lx[n0 % m];
678         y_t = ly[(n0/m)];
679         s_t = bases[n0] + x_t*y_t - (s_y-i)*x_t - s_x;
680         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
681       } else if (xs-Xs > 0 && ys-Ys > 0) {
682         for (j=0; j<s_x; j++) idx[nn++] = -1;
683       }
684       if (n1 >= 0) { /* directly below */
685         x_t = x;
686         y_t = ly[(n1/m)];
687         s_t = bases[n1] + x_t*y_t - (s_y+1-i)*x_t;
688         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
689       } else if (ys-Ys > 0) {
690         if (by == DM_BOUNDARY_MIRROR) {
691           for (j=0; j<x; j++) idx[nn++] = bases[rank] + x*(s_y - i + 1)  + j;
692         } else {
693           for (j=0; j<x; j++) idx[nn++] = -1;
694         }
695       }
696       if (n2 >= 0) { /* right below */
697         x_t = lx[n2 % m];
698         y_t = ly[(n2/m)];
699         s_t = bases[n2] + x_t*y_t - (s_y+1-i)*x_t;
700         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
701       } else if (Xe-xe> 0 && ys-Ys > 0) {
702         for (j=0; j<s_x; j++) idx[nn++] = -1;
703       }
704     }
705 
706     for (i=0; i<y; i++) {
707       if (n3 >= 0) { /* directly left */
708         x_t = lx[n3 % m];
709         /* y_t = y; */
710         s_t = bases[n3] + (i+1)*x_t - s_x;
711         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
712       } else if (xs-Xs > 0) {
713         if (bx == DM_BOUNDARY_MIRROR) {
714           for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x*i + s_x - j;
715         } else {
716           for (j=0; j<s_x; j++) idx[nn++] = -1;
717         }
718       }
719 
720       for (j=0; j<x; j++) idx[nn++] = xbase++; /* interior */
721 
722       if (n5 >= 0) { /* directly right */
723         x_t = lx[n5 % m];
724         /* y_t = y; */
725         s_t = bases[n5] + (i)*x_t;
726         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
727       } else if (Xe-xe > 0) {
728         if (bx == DM_BOUNDARY_MIRROR) {
729           for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x*(i + 1) - 2 - j;
730         } else {
731           for (j=0; j<s_x; j++) idx[nn++] = -1;
732         }
733       }
734     }
735 
736     for (i=1; i<=s_y; i++) {
737       if (n6 >= 0) { /* left above */
738         x_t = lx[n6 % m];
739         /* y_t = ly[(n6/m)]; */
740         s_t = bases[n6] + (i)*x_t - s_x;
741         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
742       } else if (xs-Xs > 0 && Ye-ye > 0) {
743         for (j=0; j<s_x; j++) idx[nn++] = -1;
744       }
745       if (n7 >= 0) { /* directly above */
746         x_t = x;
747         /* y_t = ly[(n7/m)]; */
748         s_t = bases[n7] + (i-1)*x_t;
749         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
750       } else if (Ye-ye > 0) {
751         if (by == DM_BOUNDARY_MIRROR) {
752           for (j=0; j<x; j++) idx[nn++] = bases[rank] + x*(y - i - 1)  + j;
753         } else {
754           for (j=0; j<x; j++) idx[nn++] = -1;
755         }
756       }
757       if (n8 >= 0) { /* right above */
758         x_t = lx[n8 % m];
759         /* y_t = ly[(n8/m)]; */
760         s_t = bases[n8] + (i-1)*x_t;
761         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
762       } else if (Xe-xe > 0 && Ye-ye > 0) {
763         for (j=0; j<s_x; j++) idx[nn++] = -1;
764       }
765     }
766   }
767   /*
768      Set the local to global ordering in the global vector, this allows use
769      of VecSetValuesLocal().
770   */
771   ierr = ISLocalToGlobalMappingCreate(comm,dof,nn,idx,PETSC_OWN_POINTER,&da->ltogmap);CHKERRQ(ierr);
772   ierr = PetscLogObjectParent((PetscObject)da,(PetscObject)da->ltogmap);CHKERRQ(ierr);
773 
774   ierr  = PetscFree2(bases,ldims);CHKERRQ(ierr);
775   dd->m = m;  dd->n  = n;
776   /* note petsc expects xs/xe/Xs/Xe to be multiplied by #dofs in many places */
777   dd->xs = xs*dof; dd->xe = xe*dof; dd->ys = ys; dd->ye = ye; dd->zs = 0; dd->ze = 1;
778   dd->Xs = Xs*dof; dd->Xe = Xe*dof; dd->Ys = Ys; dd->Ye = Ye; dd->Zs = 0; dd->Ze = 1;
779 
780   ierr = VecDestroy(&local);CHKERRQ(ierr);
781   ierr = VecDestroy(&global);CHKERRQ(ierr);
782 
783   dd->gtol      = gtol;
784   dd->base      = base;
785   da->ops->view = DMView_DA_2d;
786   dd->ltol      = NULL;
787   dd->ao        = NULL;
788   PetscFunctionReturn(0);
789 }
790 
791 #undef __FUNCT__
792 #define __FUNCT__ "DMDACreate2d"
793 /*@C
794    DMDACreate2d -  Creates an object that will manage the communication of  two-dimensional
795    regular array data that is distributed across some processors.
796 
797    Collective on MPI_Comm
798 
799    Input Parameters:
800 +  comm - MPI communicator
801 .  bx,by - type of ghost nodes the array have.
802          Use one of DM_BOUNDARY_NONE, DM_BOUNDARY_GHOSTED, DM_BOUNDARY_PERIODIC.
803 .  stencil_type - stencil type.  Use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
804 .  M,N - global dimension in each direction of the array
805 .  m,n - corresponding number of processors in each dimension
806          (or PETSC_DECIDE to have calculated)
807 .  dof - number of degrees of freedom per node
808 .  s - stencil width
809 -  lx, ly - arrays containing the number of nodes in each cell along
810            the x and y coordinates, or NULL. If non-null, these
811            must be of length as m and n, and the corresponding
812            m and n cannot be PETSC_DECIDE. The sum of the lx[] entries
813            must be M, and the sum of the ly[] entries must be N.
814 
815    Output Parameter:
816 .  da - the resulting distributed array object
817 
818    Options Database Key:
819 +  -dm_view - Calls DMView() at the conclusion of DMDACreate2d()
820 .  -da_grid_x <nx> - number of grid points in x direction, if M < 0
821 .  -da_grid_y <ny> - number of grid points in y direction, if N < 0
822 .  -da_processors_x <nx> - number of processors in x direction
823 .  -da_processors_y <ny> - number of processors in y direction
824 .  -da_refine_x <rx> - refinement ratio in x direction
825 .  -da_refine_y <ry> - refinement ratio in y direction
826 -  -da_refine <n> - refine the DMDA n times before creating, if M or N < 0
827 
828 
829    Level: beginner
830 
831    Notes:
832    The stencil type DMDA_STENCIL_STAR with width 1 corresponds to the
833    standard 5-pt stencil, while DMDA_STENCIL_BOX with width 1 denotes
834    the standard 9-pt stencil.
835 
836    The array data itself is NOT stored in the DMDA, it is stored in Vec objects;
837    The appropriate vector objects can be obtained with calls to DMCreateGlobalVector()
838    and DMCreateLocalVector() and calls to VecDuplicate() if more are needed.
839 
840    You must call DMSetUp() after this call before using this DM.
841 
842    If you wish to use the options database to change values in the DMDA call DMSetFromOptions() after this call
843    but before DMSetUp().
844 
845 .keywords: distributed array, create, two-dimensional
846 
847 .seealso: DMDestroy(), DMView(), DMDACreate1d(), DMDACreate3d(), DMGlobalToLocalBegin(), DMDAGetRefinementFactor(),
848           DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToLocalBegin(), DMLocalToLocalEnd(), DMDASetRefinementFactor(),
849           DMDAGetInfo(), DMCreateGlobalVector(), DMCreateLocalVector(), DMDACreateNaturalVector(), DMLoad(), DMDAGetOwnershipRanges()
850 
851 @*/
852 
853 PetscErrorCode  DMDACreate2d(MPI_Comm comm,DMBoundaryType bx,DMBoundaryType by,DMDAStencilType stencil_type,
854                           PetscInt M,PetscInt N,PetscInt m,PetscInt n,PetscInt dof,PetscInt s,const PetscInt lx[],const PetscInt ly[],DM *da)
855 {
856   PetscErrorCode ierr;
857 
858   PetscFunctionBegin;
859   ierr = DMDACreate(comm, da);CHKERRQ(ierr);
860   ierr = DMSetDimension(*da, 2);CHKERRQ(ierr);
861   ierr = DMDASetSizes(*da, M, N, 1);CHKERRQ(ierr);
862   ierr = DMDASetNumProcs(*da, m, n, PETSC_DECIDE);CHKERRQ(ierr);
863   ierr = DMDASetBoundaryType(*da, bx, by, DM_BOUNDARY_NONE);CHKERRQ(ierr);
864   ierr = DMDASetDof(*da, dof);CHKERRQ(ierr);
865   ierr = DMDASetStencilType(*da, stencil_type);CHKERRQ(ierr);
866   ierr = DMDASetStencilWidth(*da, s);CHKERRQ(ierr);
867   ierr = DMDASetOwnershipRanges(*da, lx, ly, NULL);CHKERRQ(ierr);
868   PetscFunctionReturn(0);
869 }
870