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