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