xref: /petsc/src/dm/impls/da/da3.c (revision 8fb5bd83c3955fefcf33a54e3bb66920a9fa884b)
1 
2 /*
3    Code for manipulating distributed regular 3d arrays in parallel.
4    File created by Peter Mell  7/14/95
5  */
6 
7 #include <petsc/private/dmdaimpl.h>     /*I   "petscdmda.h"    I*/
8 
9 #include <petscdraw.h>
10 static PetscErrorCode DMView_DA_3d(DM da,PetscViewer viewer)
11 {
12   PetscMPIInt    rank;
13   PetscBool      iascii,isdraw,isglvis,isbinary;
14   DM_DA          *dd = (DM_DA*)da->data;
15   Vec            coordinates;
16 #if defined(PETSC_HAVE_MATLAB_ENGINE)
17   PetscBool ismatlab;
18 #endif
19 
20   PetscFunctionBegin;
21   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)da),&rank));
22 
23   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
24   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
25   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERGLVIS,&isglvis));
26   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary));
27 #if defined(PETSC_HAVE_MATLAB_ENGINE)
28   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERMATLAB,&ismatlab));
29 #endif
30   if (iascii) {
31     PetscViewerFormat format;
32 
33     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
34     PetscCall(PetscViewerGetFormat(viewer, &format));
35     if (format == PETSC_VIEWER_LOAD_BALANCE) {
36       PetscInt      i,nmax = 0,nmin = PETSC_MAX_INT,navg = 0,*nz,nzlocal;
37       DMDALocalInfo info;
38       PetscMPIInt   size;
39       PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)da),&size));
40       PetscCall(DMDAGetLocalInfo(da,&info));
41       nzlocal = info.xm*info.ym*info.zm;
42       PetscCall(PetscMalloc1(size,&nz));
43       PetscCallMPI(MPI_Allgather(&nzlocal,1,MPIU_INT,nz,1,MPIU_INT,PetscObjectComm((PetscObject)da)));
44       for (i=0; i<(PetscInt)size; i++) {
45         nmax = PetscMax(nmax,nz[i]);
46         nmin = PetscMin(nmin,nz[i]);
47         navg += nz[i];
48       }
49       PetscCall(PetscFree(nz));
50       navg = navg/size;
51       PetscCall(PetscViewerASCIIPrintf(viewer,"  Load Balance - Grid Points: Min %" PetscInt_FMT "  avg %" PetscInt_FMT "  max %" PetscInt_FMT "\n",nmin,navg,nmax));
52       PetscFunctionReturn(0);
53     }
54     if (format != PETSC_VIEWER_ASCII_VTK_DEPRECATED && format != PETSC_VIEWER_ASCII_VTK_CELL_DEPRECATED && format != PETSC_VIEWER_ASCII_GLVIS) {
55       DMDALocalInfo info;
56       PetscCall(DMDAGetLocalInfo(da,&info));
57       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"Processor [%d] M %" PetscInt_FMT " N %" PetscInt_FMT " P %" PetscInt_FMT " m %" PetscInt_FMT " n %" PetscInt_FMT " p %" PetscInt_FMT " w %" PetscInt_FMT " s %" PetscInt_FMT "\n",rank,dd->M,dd->N,dd->P,dd->m,dd->n,dd->p,dd->w,dd->s));
58       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"X range of indices: %" PetscInt_FMT " %" PetscInt_FMT ", Y range of indices: %" PetscInt_FMT " %" PetscInt_FMT ", Z range of indices: %" PetscInt_FMT " %" PetscInt_FMT "\n",
59                                                  info.xs,info.xs+info.xm,info.ys,info.ys+info.ym,info.zs,info.zs+info.zm));
60       PetscCall(DMGetCoordinates(da, &coordinates));
61 #if !defined(PETSC_USE_COMPLEX)
62       if (coordinates) {
63         PetscInt        last;
64         const PetscReal *coors;
65         PetscCall(VecGetArrayRead(coordinates,&coors));
66         PetscCall(VecGetLocalSize(coordinates,&last));
67         last = last - 3;
68         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer,"Lower left corner %g %g %g : Upper right %g %g %g\n",(double)coors[0],(double)coors[1],(double)coors[2],(double)coors[last],(double)coors[last+1],(double)coors[last+2]));
69         PetscCall(VecRestoreArrayRead(coordinates,&coors));
70       }
71 #endif
72       PetscCall(PetscViewerFlush(viewer));
73       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
74     } else if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMView_DA_GLVis(da,viewer));
75     else PetscCall(DMView_DA_VTK(da,viewer));
76   } else if (isdraw) {
77     PetscDraw      draw;
78     PetscReal      ymin = -1.0,ymax = (PetscReal)dd->N;
79     PetscReal      xmin = -1.0,xmax = (PetscReal)((dd->M+2)*dd->P),x,y,ycoord,xcoord;
80     PetscInt       k,plane,base;
81     const PetscInt *idx;
82     char           node[10];
83     PetscBool      isnull;
84 
85     PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
86     PetscCall(PetscDrawIsNull(draw,&isnull));
87     if (isnull) PetscFunctionReturn(0);
88 
89     PetscCall(PetscDrawCheckResizedWindow(draw));
90     PetscCall(PetscDrawClear(draw));
91     PetscCall(PetscDrawSetCoordinates(draw,xmin,ymin,xmax,ymax));
92 
93     PetscDrawCollectiveBegin(draw);
94     /* first processor draw all node lines */
95     if (rank == 0) {
96       for (k=0; k<dd->P; k++) {
97         ymin = 0.0; ymax = (PetscReal)(dd->N - 1);
98         for (xmin=(PetscReal)(k*(dd->M+1)); xmin<(PetscReal)(dd->M+(k*(dd->M+1))); xmin++) {
99           PetscCall(PetscDrawLine(draw,xmin,ymin,xmin,ymax,PETSC_DRAW_BLACK));
100         }
101         xmin = (PetscReal)(k*(dd->M+1)); xmax = xmin + (PetscReal)(dd->M - 1);
102         for (ymin=0; ymin<(PetscReal)dd->N; ymin++) {
103           PetscCall(PetscDrawLine(draw,xmin,ymin,xmax,ymin,PETSC_DRAW_BLACK));
104         }
105       }
106     }
107     PetscDrawCollectiveEnd(draw);
108     PetscCall(PetscDrawFlush(draw));
109     PetscCall(PetscDrawPause(draw));
110 
111     PetscDrawCollectiveBegin(draw);
112     /*Go through and draw for each plane*/
113     for (k=0; k<dd->P; k++) {
114       if ((k >= dd->zs) && (k < dd->ze)) {
115         /* draw my box */
116         ymin = dd->ys;
117         ymax = dd->ye - 1;
118         xmin = dd->xs/dd->w    + (dd->M+1)*k;
119         xmax =(dd->xe-1)/dd->w + (dd->M+1)*k;
120 
121         PetscCall(PetscDrawLine(draw,xmin,ymin,xmax,ymin,PETSC_DRAW_RED));
122         PetscCall(PetscDrawLine(draw,xmin,ymin,xmin,ymax,PETSC_DRAW_RED));
123         PetscCall(PetscDrawLine(draw,xmin,ymax,xmax,ymax,PETSC_DRAW_RED));
124         PetscCall(PetscDrawLine(draw,xmax,ymin,xmax,ymax,PETSC_DRAW_RED));
125 
126         xmin = dd->xs/dd->w;
127         xmax =(dd->xe-1)/dd->w;
128 
129         /* identify which processor owns the box */
130         PetscCall(PetscSNPrintf(node,sizeof(node),"%d",(int)rank));
131         PetscCall(PetscDrawString(draw,xmin+(dd->M+1)*k+.2,ymin+.3,PETSC_DRAW_RED,node));
132         /* put in numbers*/
133         base = (dd->base+(dd->xe-dd->xs)*(dd->ye-dd->ys)*(k-dd->zs))/dd->w;
134         for (y=ymin; y<=ymax; y++) {
135           for (x=xmin+(dd->M+1)*k; x<=xmax+(dd->M+1)*k; x++) {
136             PetscCall(PetscSNPrintf(node,sizeof(node),"%d",(int)base++));
137             PetscCall(PetscDrawString(draw,x,y,PETSC_DRAW_BLACK,node));
138           }
139         }
140 
141       }
142     }
143     PetscDrawCollectiveEnd(draw);
144     PetscCall(PetscDrawFlush(draw));
145     PetscCall(PetscDrawPause(draw));
146 
147     PetscDrawCollectiveBegin(draw);
148     for (k=0-dd->s; k<dd->P+dd->s; k++) {
149       /* Go through and draw for each plane */
150       if ((k >= dd->Zs) && (k < dd->Ze)) {
151         /* overlay ghost numbers, useful for error checking */
152         base = (dd->Xe-dd->Xs)*(dd->Ye-dd->Ys)*(k-dd->Zs)/dd->w;
153         PetscCall(ISLocalToGlobalMappingGetBlockIndices(da->ltogmap,&idx));
154         plane=k;
155         /* Keep z wrap around points on the drawing */
156         if (k<0) plane=dd->P+k;
157         if (k>=dd->P) plane=k-dd->P;
158         ymin = dd->Ys; ymax = dd->Ye;
159         xmin = (dd->M+1)*plane*dd->w;
160         xmax = (dd->M+1)*plane*dd->w+dd->M*dd->w;
161         for (y=ymin; y<ymax; y++) {
162           for (x=xmin+dd->Xs; x<xmin+dd->Xe; x+=dd->w) {
163             sprintf(node,"%d",(int)(idx[base]));
164             ycoord = y;
165             /*Keep y wrap around points on drawing */
166             if (y<0) ycoord = dd->N+y;
167             if (y>=dd->N) ycoord = y-dd->N;
168             xcoord = x;   /* Keep x wrap points on drawing */
169             if (x<xmin) xcoord = xmax - (xmin-x);
170             if (x>=xmax) xcoord = xmin + (x-xmax);
171             PetscCall(PetscDrawString(draw,xcoord/dd->w,ycoord,PETSC_DRAW_BLUE,node));
172             base++;
173           }
174         }
175         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(da->ltogmap,&idx));
176       }
177     }
178     PetscDrawCollectiveEnd(draw);
179     PetscCall(PetscDrawFlush(draw));
180     PetscCall(PetscDrawPause(draw));
181     PetscCall(PetscDrawSave(draw));
182   } else if (isglvis) {
183     PetscCall(DMView_DA_GLVis(da,viewer));
184   } else if (isbinary) {
185     PetscCall(DMView_DA_Binary(da,viewer));
186 #if defined(PETSC_HAVE_MATLAB_ENGINE)
187   } else if (ismatlab) {
188     PetscCall(DMView_DA_Matlab(da,viewer));
189 #endif
190   }
191   PetscFunctionReturn(0);
192 }
193 
194 PetscErrorCode  DMSetUp_DA_3D(DM da)
195 {
196   DM_DA            *dd          = (DM_DA*)da->data;
197   const PetscInt   M            = dd->M;
198   const PetscInt   N            = dd->N;
199   const PetscInt   P            = dd->P;
200   PetscInt         m            = dd->m;
201   PetscInt         n            = dd->n;
202   PetscInt         p            = dd->p;
203   const PetscInt   dof          = dd->w;
204   const PetscInt   s            = dd->s;
205   DMBoundaryType   bx           = dd->bx;
206   DMBoundaryType   by           = dd->by;
207   DMBoundaryType   bz           = dd->bz;
208   DMDAStencilType  stencil_type = dd->stencil_type;
209   PetscInt         *lx          = dd->lx;
210   PetscInt         *ly          = dd->ly;
211   PetscInt         *lz          = dd->lz;
212   MPI_Comm         comm;
213   PetscMPIInt      rank,size;
214   PetscInt         xs = 0,xe,ys = 0,ye,zs = 0,ze,x = 0,y = 0,z = 0;
215   PetscInt         Xs,Xe,Ys,Ye,Zs,Ze,IXs,IXe,IYs,IYe,IZs,IZe,pm;
216   PetscInt         left,right,up,down,bottom,top,i,j,k,*idx,nn;
217   PetscInt         n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n14;
218   PetscInt         n15,n16,n17,n18,n19,n20,n21,n22,n23,n24,n25,n26;
219   PetscInt         *bases,*ldims,base,x_t,y_t,z_t,s_t,count,s_x,s_y,s_z;
220   PetscInt         sn0  = 0,sn1 = 0,sn2 = 0,sn3 = 0,sn5 = 0,sn6 = 0,sn7 = 0;
221   PetscInt         sn8  = 0,sn9 = 0,sn11 = 0,sn15 = 0,sn24 = 0,sn25 = 0,sn26 = 0;
222   PetscInt         sn17 = 0,sn18 = 0,sn19 = 0,sn20 = 0,sn21 = 0,sn23 = 0;
223   Vec              local,global;
224   VecScatter       gtol;
225   IS               to,from;
226   PetscBool        twod;
227 
228   PetscFunctionBegin;
229   PetscCheck(stencil_type != DMDA_STENCIL_BOX || (bx != DM_BOUNDARY_MIRROR && by != DM_BOUNDARY_MIRROR && bz != DM_BOUNDARY_MIRROR),PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Mirror boundary and box stencil");
230   PetscCall(PetscObjectGetComm((PetscObject) da, &comm));
231 #if !defined(PETSC_USE_64BIT_INDICES)
232   PetscCheck(((PetscInt64) M)*((PetscInt64) N)*((PetscInt64) P)*((PetscInt64) dof) <= (PetscInt64) PETSC_MPI_INT_MAX,comm,PETSC_ERR_INT_OVERFLOW,"Mesh of %" PetscInt_FMT " by %" PetscInt_FMT " by %" PetscInt_FMT " by %" PetscInt_FMT " (dof) is too large for 32 bit indices",M,N,P,dof);
233 #endif
234 
235   PetscCallMPI(MPI_Comm_size(comm,&size));
236   PetscCallMPI(MPI_Comm_rank(comm,&rank));
237 
238   if (m != PETSC_DECIDE) {
239     PetscCheck(m >= 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in X direction: %" PetscInt_FMT,m);
240     else PetscCheck(m <= size,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in X direction: %" PetscInt_FMT " %d",m,size);
241   }
242   if (n != PETSC_DECIDE) {
243     PetscCheck(n >= 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in Y direction: %" PetscInt_FMT,n);
244     else PetscCheck(n <= size,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in Y direction: %" PetscInt_FMT " %d",n,size);
245   }
246   if (p != PETSC_DECIDE) {
247     PetscCheck(p >= 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in Z direction: %" PetscInt_FMT,p);
248     else PetscCheck(p <= size,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in Z direction: %" PetscInt_FMT " %d",p,size);
249   }
250   PetscCheck(m <= 0 || n <= 0 || p <= 0 || m*n*p == size,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"m %" PetscInt_FMT " * n %" PetscInt_FMT " * p %" PetscInt_FMT " != size %d",m,n,p,size);
251 
252   /* Partition the array among the processors */
253   if (m == PETSC_DECIDE && n != PETSC_DECIDE && p != PETSC_DECIDE) {
254     m = size/(n*p);
255   } else if (m != PETSC_DECIDE && n == PETSC_DECIDE && p != PETSC_DECIDE) {
256     n = size/(m*p);
257   } else if (m != PETSC_DECIDE && n != PETSC_DECIDE && p == PETSC_DECIDE) {
258     p = size/(m*n);
259   } else if (m == PETSC_DECIDE && n == PETSC_DECIDE && p != PETSC_DECIDE) {
260     /* try for squarish distribution */
261     m = (int)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)size)/((PetscReal)N*p)));
262     if (!m) m = 1;
263     while (m > 0) {
264       n = size/(m*p);
265       if (m*n*p == size) break;
266       m--;
267     }
268     PetscCheck(m,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"bad p value: p = %" PetscInt_FMT,p);
269     if (M > N && m < n) {PetscInt _m = m; m = n; n = _m;}
270   } else if (m == PETSC_DECIDE && n != PETSC_DECIDE && p == PETSC_DECIDE) {
271     /* try for squarish distribution */
272     m = (int)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)size)/((PetscReal)P*n)));
273     if (!m) m = 1;
274     while (m > 0) {
275       p = size/(m*n);
276       if (m*n*p == size) break;
277       m--;
278     }
279     PetscCheck(m,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"bad n value: n = %" PetscInt_FMT,n);
280     if (M > P && m < p) {PetscInt _m = m; m = p; p = _m;}
281   } else if (m != PETSC_DECIDE && n == PETSC_DECIDE && p == PETSC_DECIDE) {
282     /* try for squarish distribution */
283     n = (int)(0.5 + PetscSqrtReal(((PetscReal)N)*((PetscReal)size)/((PetscReal)P*m)));
284     if (!n) n = 1;
285     while (n > 0) {
286       p = size/(m*n);
287       if (m*n*p == size) break;
288       n--;
289     }
290     PetscCheck(n,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"bad m value: m = %" PetscInt_FMT,n);
291     if (N > P && n < p) {PetscInt _n = n; n = p; p = _n;}
292   } else if (m == PETSC_DECIDE && n == PETSC_DECIDE && p == PETSC_DECIDE) {
293     /* try for squarish distribution */
294     n = (PetscInt)(0.5 + PetscPowReal(((PetscReal)N*N)*((PetscReal)size)/((PetscReal)P*M),(PetscReal)(1./3.)));
295     if (!n) n = 1;
296     while (n > 0) {
297       pm = size/n;
298       if (n*pm == size) break;
299       n--;
300     }
301     if (!n) n = 1;
302     m = (PetscInt)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)size)/((PetscReal)P*n)));
303     if (!m) m = 1;
304     while (m > 0) {
305       p = size/(m*n);
306       if (m*n*p == size) break;
307       m--;
308     }
309     if (M > P && m < p) {PetscInt _m = m; m = p; p = _m;}
310   } else PetscCheck(m*n*p == size,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"Given Bad partition");
311 
312   PetscCheck(m*n*p == size,PetscObjectComm((PetscObject)da),PETSC_ERR_PLIB,"Could not find good partition");
313   PetscCheck(M >= m,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"Partition in x direction is too fine! %" PetscInt_FMT " %" PetscInt_FMT,M,m);
314   PetscCheck(N >= n,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"Partition in y direction is too fine! %" PetscInt_FMT " %" PetscInt_FMT,N,n);
315   PetscCheck(P >= p,PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"Partition in z direction is too fine! %" PetscInt_FMT " %" PetscInt_FMT,P,p);
316 
317   /*
318      Determine locally owned region
319      [x, y, or z]s is the first local node number, [x, y, z] is the number of local nodes
320   */
321 
322   if (!lx) {
323     PetscCall(PetscMalloc1(m, &dd->lx));
324     lx   = dd->lx;
325     for (i=0; i<m; i++) lx[i] = M/m + ((M % m) > (i % m));
326   }
327   x  = lx[rank % m];
328   xs = 0;
329   for (i=0; i<(rank%m); i++) xs += lx[i];
330   PetscCheck(x >= s || (m <= 1 && bx != DM_BOUNDARY_PERIODIC),PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local x-width of domain x %" PetscInt_FMT " is smaller than stencil width s %" PetscInt_FMT,x,s);
331 
332   if (!ly) {
333     PetscCall(PetscMalloc1(n, &dd->ly));
334     ly   = dd->ly;
335     for (i=0; i<n; i++) ly[i] = N/n + ((N % n) > (i % n));
336   }
337   y = ly[(rank % (m*n))/m];
338   PetscCheck(y >= s || (n <= 1 && by != DM_BOUNDARY_PERIODIC),PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local y-width of domain y %" PetscInt_FMT " is smaller than stencil width s %" PetscInt_FMT,y,s);
339 
340   ys = 0;
341   for (i=0; i<(rank % (m*n))/m; i++) ys += ly[i];
342 
343   if (!lz) {
344     PetscCall(PetscMalloc1(p, &dd->lz));
345     lz = dd->lz;
346     for (i=0; i<p; i++) lz[i] = P/p + ((P % p) > (i % p));
347   }
348   z = lz[rank/(m*n)];
349 
350   /* note this is different than x- and y-, as we will handle as an important special
351    case when p=P=1 and DM_BOUNDARY_PERIODIC and s > z.  This is to deal with 2D problems
352    in a 3D code.  Additional code for this case is noted with "2d case" comments */
353   twod = PETSC_FALSE;
354   if (P == 1) twod = PETSC_TRUE;
355   else PetscCheck(z >= s || (p <= 1 && bz != DM_BOUNDARY_PERIODIC),PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local z-width of domain z %" PetscInt_FMT " is smaller than stencil width s %" PetscInt_FMT,z,s);
356   zs = 0;
357   for (i=0; i<(rank/(m*n)); i++) zs += lz[i];
358   ye = ys + y;
359   xe = xs + x;
360   ze = zs + z;
361 
362   /* determine ghost region (Xs) and region scattered into (IXs)  */
363   if (xs-s > 0) {
364     Xs = xs - s; IXs = xs - s;
365   } else {
366     if (bx) Xs = xs - s;
367     else Xs = 0;
368     IXs = 0;
369   }
370   if (xe+s <= M) {
371     Xe = xe + s; IXe = xe + s;
372   } else {
373     if (bx) {
374       Xs = xs - s; Xe = xe + s;
375     } else Xe = M;
376     IXe = M;
377   }
378 
379   if (bx == DM_BOUNDARY_PERIODIC || bx == DM_BOUNDARY_MIRROR) {
380     IXs = xs - s;
381     IXe = xe + s;
382     Xs  = xs - s;
383     Xe  = xe + s;
384   }
385 
386   if (ys-s > 0) {
387     Ys = ys - s; IYs = ys - s;
388   } else {
389     if (by) Ys = ys - s;
390     else Ys = 0;
391     IYs = 0;
392   }
393   if (ye+s <= N) {
394     Ye = ye + s; IYe = ye + s;
395   } else {
396     if (by) Ye = ye + s;
397     else Ye = N;
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   if (zs-s > 0) {
409     Zs = zs - s; IZs = zs - s;
410   } else {
411     if (bz) Zs = zs - s;
412     else Zs = 0;
413     IZs = 0;
414   }
415   if (ze+s <= P) {
416     Ze = ze + s; IZe = ze + s;
417   } else {
418     if (bz) Ze = ze + s;
419     else Ze = P;
420     IZe = P;
421   }
422 
423   if (bz == DM_BOUNDARY_PERIODIC || bz == DM_BOUNDARY_MIRROR) {
424     IZs = zs - s;
425     IZe = ze + s;
426     Zs  = zs - s;
427     Ze  = ze + s;
428   }
429 
430   /* Resize all X parameters to reflect w */
431   s_x = s;
432   s_y = s;
433   s_z = s;
434 
435   /* determine starting point of each processor */
436   nn       = x*y*z;
437   PetscCall(PetscMalloc2(size+1,&bases,size,&ldims));
438   PetscCallMPI(MPI_Allgather(&nn,1,MPIU_INT,ldims,1,MPIU_INT,comm));
439   bases[0] = 0;
440   for (i=1; i<=size; i++) bases[i] = ldims[i-1];
441   for (i=1; i<=size; i++) bases[i] += bases[i-1];
442   base = bases[rank]*dof;
443 
444   /* allocate the base parallel and sequential vectors */
445   dd->Nlocal = x*y*z*dof;
446   PetscCall(VecCreateMPIWithArray(comm,dof,dd->Nlocal,PETSC_DECIDE,NULL,&global));
447   dd->nlocal = (Xe-Xs)*(Ye-Ys)*(Ze-Zs)*dof;
448   PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,dof,dd->nlocal,NULL,&local));
449 
450   /* generate global to local vector scatter and local to global mapping*/
451 
452   /* global to local must include ghost points within the domain,
453      but not ghost points outside the domain that aren't periodic */
454   PetscCall(PetscMalloc1((IXe-IXs)*(IYe-IYs)*(IZe-IZs),&idx));
455   if (stencil_type == DMDA_STENCIL_BOX) {
456     left   = IXs - Xs; right = left + (IXe-IXs);
457     bottom = IYs - Ys; top = bottom + (IYe-IYs);
458     down   = IZs - Zs; up  = down + (IZe-IZs);
459     count  = 0;
460     for (i=down; i<up; i++) {
461       for (j=bottom; j<top; j++) {
462         for (k=left; k<right; k++) {
463           idx[count++] = (i*(Ye-Ys) + j)*(Xe-Xs) + k;
464         }
465       }
466     }
467     PetscCall(ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&to));
468   } else {
469     /* This is way ugly! We need to list the funny cross type region */
470     left   = xs - Xs; right = left + x;
471     bottom = ys - Ys; top = bottom + y;
472     down   = zs - Zs;   up  = down + z;
473     count  = 0;
474     /* the bottom chunk */
475     for (i=(IZs-Zs); i<down; i++) {
476       for (j=bottom; j<top; j++) {
477         for (k=left; k<right; k++) idx[count++] = (i*(Ye-Ys) + j)*(Xe-Xs) + k;
478       }
479     }
480     /* the middle piece */
481     for (i=down; i<up; i++) {
482       /* front */
483       for (j=(IYs-Ys); j<bottom; j++) {
484         for (k=left; k<right; k++) idx[count++] = (i*(Ye-Ys) + j)*(Xe-Xs) + k;
485       }
486       /* middle */
487       for (j=bottom; j<top; j++) {
488         for (k=IXs-Xs; k<IXe-Xs; k++) idx[count++] = (i*(Ye-Ys) + j)*(Xe-Xs) + k;
489       }
490       /* back */
491       for (j=top; j<top+IYe-ye; j++) {
492         for (k=left; k<right; k++) idx[count++] = (i*(Ye-Ys) + j)*(Xe-Xs) + k;
493       }
494     }
495     /* the top piece */
496     for (i=up; i<up+IZe-ze; i++) {
497       for (j=bottom; j<top; j++) {
498         for (k=left; k<right; k++) idx[count++] = (i*(Ye-Ys) + j)*(Xe-Xs) + k;
499       }
500     }
501     PetscCall(ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&to));
502   }
503 
504   /* determine who lies on each side of use stored in    n24 n25 n26
505                                                          n21 n22 n23
506                                                          n18 n19 n20
507 
508                                                          n15 n16 n17
509                                                          n12     n14
510                                                          n9  n10 n11
511 
512                                                          n6  n7  n8
513                                                          n3  n4  n5
514                                                          n0  n1  n2
515   */
516 
517   /* Solve for X,Y, and Z Periodic Case First, Then Modify Solution */
518   /* Assume Nodes are Internal to the Cube */
519   n0 = rank - m*n - m - 1;
520   n1 = rank - m*n - m;
521   n2 = rank - m*n - m + 1;
522   n3 = rank - m*n -1;
523   n4 = rank - m*n;
524   n5 = rank - m*n + 1;
525   n6 = rank - m*n + m - 1;
526   n7 = rank - m*n + m;
527   n8 = rank - m*n + m + 1;
528 
529   n9  = rank - m - 1;
530   n10 = rank - m;
531   n11 = rank - m + 1;
532   n12 = rank - 1;
533   n14 = rank + 1;
534   n15 = rank + m - 1;
535   n16 = rank + m;
536   n17 = rank + m + 1;
537 
538   n18 = rank + m*n - m - 1;
539   n19 = rank + m*n - m;
540   n20 = rank + m*n - m + 1;
541   n21 = rank + m*n - 1;
542   n22 = rank + m*n;
543   n23 = rank + m*n + 1;
544   n24 = rank + m*n + m - 1;
545   n25 = rank + m*n + m;
546   n26 = rank + m*n + m + 1;
547 
548   /* Assume Pieces are on Faces of Cube */
549 
550   if (xs == 0) { /* First assume not corner or edge */
551     n0  = rank       -1 - (m*n);
552     n3  = rank + m   -1 - (m*n);
553     n6  = rank + 2*m -1 - (m*n);
554     n9  = rank       -1;
555     n12 = rank + m   -1;
556     n15 = rank + 2*m -1;
557     n18 = rank       -1 + (m*n);
558     n21 = rank + m   -1 + (m*n);
559     n24 = rank + 2*m -1 + (m*n);
560   }
561 
562   if (xe == M) { /* First assume not corner or edge */
563     n2  = rank -2*m +1 - (m*n);
564     n5  = rank - m  +1 - (m*n);
565     n8  = rank      +1 - (m*n);
566     n11 = rank -2*m +1;
567     n14 = rank - m  +1;
568     n17 = rank      +1;
569     n20 = rank -2*m +1 + (m*n);
570     n23 = rank - m  +1 + (m*n);
571     n26 = rank      +1 + (m*n);
572   }
573 
574   if (ys==0) { /* First assume not corner or edge */
575     n0  = rank + m * (n-1) -1 - (m*n);
576     n1  = rank + m * (n-1)    - (m*n);
577     n2  = rank + m * (n-1) +1 - (m*n);
578     n9  = rank + m * (n-1) -1;
579     n10 = rank + m * (n-1);
580     n11 = rank + m * (n-1) +1;
581     n18 = rank + m * (n-1) -1 + (m*n);
582     n19 = rank + m * (n-1)    + (m*n);
583     n20 = rank + m * (n-1) +1 + (m*n);
584   }
585 
586   if (ye == N) { /* First assume not corner or edge */
587     n6  = rank - m * (n-1) -1 - (m*n);
588     n7  = rank - m * (n-1)    - (m*n);
589     n8  = rank - m * (n-1) +1 - (m*n);
590     n15 = rank - m * (n-1) -1;
591     n16 = rank - m * (n-1);
592     n17 = rank - m * (n-1) +1;
593     n24 = rank - m * (n-1) -1 + (m*n);
594     n25 = rank - m * (n-1)    + (m*n);
595     n26 = rank - m * (n-1) +1 + (m*n);
596   }
597 
598   if (zs == 0) { /* First assume not corner or edge */
599     n0 = size - (m*n) + rank - m - 1;
600     n1 = size - (m*n) + rank - m;
601     n2 = size - (m*n) + rank - m + 1;
602     n3 = size - (m*n) + rank - 1;
603     n4 = size - (m*n) + rank;
604     n5 = size - (m*n) + rank + 1;
605     n6 = size - (m*n) + rank + m - 1;
606     n7 = size - (m*n) + rank + m;
607     n8 = size - (m*n) + rank + m + 1;
608   }
609 
610   if (ze == P) { /* First assume not corner or edge */
611     n18 = (m*n) - (size-rank) - m - 1;
612     n19 = (m*n) - (size-rank) - m;
613     n20 = (m*n) - (size-rank) - m + 1;
614     n21 = (m*n) - (size-rank) - 1;
615     n22 = (m*n) - (size-rank);
616     n23 = (m*n) - (size-rank) + 1;
617     n24 = (m*n) - (size-rank) + m - 1;
618     n25 = (m*n) - (size-rank) + m;
619     n26 = (m*n) - (size-rank) + m + 1;
620   }
621 
622   if ((xs==0) && (zs==0)) { /* Assume an edge, not corner */
623     n0 = size - m*n + rank + m-1 - m;
624     n3 = size - m*n + rank + m-1;
625     n6 = size - m*n + rank + m-1 + m;
626   }
627 
628   if ((xs==0) && (ze==P)) { /* Assume an edge, not corner */
629     n18 = m*n - (size - rank) + m-1 - m;
630     n21 = m*n - (size - rank) + m-1;
631     n24 = m*n - (size - rank) + m-1 + m;
632   }
633 
634   if ((xs==0) && (ys==0)) { /* Assume an edge, not corner */
635     n0  = rank + m*n -1 - m*n;
636     n9  = rank + m*n -1;
637     n18 = rank + m*n -1 + m*n;
638   }
639 
640   if ((xs==0) && (ye==N)) { /* Assume an edge, not corner */
641     n6  = rank - m*(n-1) + m-1 - m*n;
642     n15 = rank - m*(n-1) + m-1;
643     n24 = rank - m*(n-1) + m-1 + m*n;
644   }
645 
646   if ((xe==M) && (zs==0)) { /* Assume an edge, not corner */
647     n2 = size - (m*n-rank) - (m-1) - m;
648     n5 = size - (m*n-rank) - (m-1);
649     n8 = size - (m*n-rank) - (m-1) + m;
650   }
651 
652   if ((xe==M) && (ze==P)) { /* Assume an edge, not corner */
653     n20 = m*n - (size - rank) - (m-1) - m;
654     n23 = m*n - (size - rank) - (m-1);
655     n26 = m*n - (size - rank) - (m-1) + m;
656   }
657 
658   if ((xe==M) && (ys==0)) { /* Assume an edge, not corner */
659     n2  = rank + m*(n-1) - (m-1) - m*n;
660     n11 = rank + m*(n-1) - (m-1);
661     n20 = rank + m*(n-1) - (m-1) + m*n;
662   }
663 
664   if ((xe==M) && (ye==N)) { /* Assume an edge, not corner */
665     n8  = rank - m*n +1 - m*n;
666     n17 = rank - m*n +1;
667     n26 = rank - m*n +1 + m*n;
668   }
669 
670   if ((ys==0) && (zs==0)) { /* Assume an edge, not corner */
671     n0 = size - m + rank -1;
672     n1 = size - m + rank;
673     n2 = size - m + rank +1;
674   }
675 
676   if ((ys==0) && (ze==P)) { /* Assume an edge, not corner */
677     n18 = m*n - (size - rank) + m*(n-1) -1;
678     n19 = m*n - (size - rank) + m*(n-1);
679     n20 = m*n - (size - rank) + m*(n-1) +1;
680   }
681 
682   if ((ye==N) && (zs==0)) { /* Assume an edge, not corner */
683     n6 = size - (m*n-rank) - m * (n-1) -1;
684     n7 = size - (m*n-rank) - m * (n-1);
685     n8 = size - (m*n-rank) - m * (n-1) +1;
686   }
687 
688   if ((ye==N) && (ze==P)) { /* Assume an edge, not corner */
689     n24 = rank - (size-m) -1;
690     n25 = rank - (size-m);
691     n26 = rank - (size-m) +1;
692   }
693 
694   /* Check for Corners */
695   if ((xs==0) && (ys==0) && (zs==0)) n0  = size -1;
696   if ((xs==0) && (ys==0) && (ze==P)) n18 = m*n-1;
697   if ((xs==0) && (ye==N) && (zs==0)) n6  = (size-1)-m*(n-1);
698   if ((xs==0) && (ye==N) && (ze==P)) n24 = m-1;
699   if ((xe==M) && (ys==0) && (zs==0)) n2  = size-m;
700   if ((xe==M) && (ys==0) && (ze==P)) n20 = m*n-m;
701   if ((xe==M) && (ye==N) && (zs==0)) n8  = size-m*n;
702   if ((xe==M) && (ye==N) && (ze==P)) n26 = 0;
703 
704   /* Check for when not X,Y, and Z Periodic */
705 
706   /* If not X periodic */
707   if (bx != DM_BOUNDARY_PERIODIC) {
708     if (xs==0) n0 = n3 = n6 = n9  = n12 = n15 = n18 = n21 = n24 = -2;
709     if (xe==M) n2 = n5 = n8 = n11 = n14 = n17 = n20 = n23 = n26 = -2;
710   }
711 
712   /* If not Y periodic */
713   if (by != DM_BOUNDARY_PERIODIC) {
714     if (ys==0) n0 = n1 = n2 = n9  = n10 = n11 = n18 = n19 = n20 = -2;
715     if (ye==N) n6 = n7 = n8 = n15 = n16 = n17 = n24 = n25 = n26 = -2;
716   }
717 
718   /* If not Z periodic */
719   if (bz != DM_BOUNDARY_PERIODIC) {
720     if (zs==0) n0  = n1  = n2  = n3  = n4  = n5  = n6  = n7  = n8  = -2;
721     if (ze==P) n18 = n19 = n20 = n21 = n22 = n23 = n24 = n25 = n26 = -2;
722   }
723 
724   PetscCall(PetscMalloc1(27,&dd->neighbors));
725 
726   dd->neighbors[0]  = n0;
727   dd->neighbors[1]  = n1;
728   dd->neighbors[2]  = n2;
729   dd->neighbors[3]  = n3;
730   dd->neighbors[4]  = n4;
731   dd->neighbors[5]  = n5;
732   dd->neighbors[6]  = n6;
733   dd->neighbors[7]  = n7;
734   dd->neighbors[8]  = n8;
735   dd->neighbors[9]  = n9;
736   dd->neighbors[10] = n10;
737   dd->neighbors[11] = n11;
738   dd->neighbors[12] = n12;
739   dd->neighbors[13] = rank;
740   dd->neighbors[14] = n14;
741   dd->neighbors[15] = n15;
742   dd->neighbors[16] = n16;
743   dd->neighbors[17] = n17;
744   dd->neighbors[18] = n18;
745   dd->neighbors[19] = n19;
746   dd->neighbors[20] = n20;
747   dd->neighbors[21] = n21;
748   dd->neighbors[22] = n22;
749   dd->neighbors[23] = n23;
750   dd->neighbors[24] = n24;
751   dd->neighbors[25] = n25;
752   dd->neighbors[26] = n26;
753 
754   /* If star stencil then delete the corner neighbors */
755   if (stencil_type == DMDA_STENCIL_STAR) {
756     /* save information about corner neighbors */
757     sn0 = n0; sn1 = n1; sn2 = n2; sn3 = n3; sn5 = n5; sn6 = n6; sn7 = n7;
758     sn8 = n8; sn9 = n9; sn11 = n11; sn15 = n15; sn17 = n17; sn18 = n18;
759     sn19 = n19; sn20 = n20; sn21 = n21; sn23 = n23; sn24 = n24; sn25 = n25;
760     sn26 = n26;
761     n0 = n1 = n2 = n3 = n5 = n6 = n7 = n8 = n9 = n11 = n15 = n17 = n18 = n19 = n20 = n21 = n23 = n24 = n25 = n26 = -1;
762   }
763 
764   PetscCall(PetscMalloc1((Xe-Xs)*(Ye-Ys)*(Ze-Zs),&idx));
765 
766   nn = 0;
767   /* Bottom Level */
768   for (k=0; k<s_z; k++) {
769     for (i=1; i<=s_y; i++) {
770       if (n0 >= 0) { /* left below */
771         x_t = lx[n0 % m];
772         y_t = ly[(n0 % (m*n))/m];
773         z_t = lz[n0 / (m*n)];
774         s_t = bases[n0] + x_t*y_t*z_t - (s_y-i)*x_t - s_x - (s_z-k-1)*x_t*y_t;
775         if (twod && (s_t < 0)) s_t = bases[n0] + x_t*y_t*z_t - (s_y-i)*x_t - s_x; /* 2D case */
776         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
777       }
778       if (n1 >= 0) { /* directly below */
779         x_t = x;
780         y_t = ly[(n1 % (m*n))/m];
781         z_t = lz[n1 / (m*n)];
782         s_t = bases[n1] + x_t*y_t*z_t - (s_y+1-i)*x_t - (s_z-k-1)*x_t*y_t;
783         if (twod && (s_t < 0)) s_t = bases[n1] + x_t*y_t*z_t - (s_y+1-i)*x_t; /* 2D case */
784         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
785       }
786       if (n2 >= 0) { /* right below */
787         x_t = lx[n2 % m];
788         y_t = ly[(n2 % (m*n))/m];
789         z_t = lz[n2 / (m*n)];
790         s_t = bases[n2] + x_t*y_t*z_t - (s_y+1-i)*x_t - (s_z-k-1)*x_t*y_t;
791         if (twod && (s_t < 0)) s_t = bases[n2] + x_t*y_t*z_t - (s_y+1-i)*x_t; /* 2D case */
792         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
793       }
794     }
795 
796     for (i=0; i<y; i++) {
797       if (n3 >= 0) { /* directly left */
798         x_t = lx[n3 % m];
799         y_t = y;
800         z_t = lz[n3 / (m*n)];
801         s_t = bases[n3] + (i+1)*x_t - s_x + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
802         if (twod && (s_t < 0)) s_t = bases[n3] + (i+1)*x_t - s_x + x_t*y_t*z_t - x_t*y_t; /* 2D case */
803         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
804       }
805 
806       if (n4 >= 0) { /* middle */
807         x_t = x;
808         y_t = y;
809         z_t = lz[n4 / (m*n)];
810         s_t = bases[n4] + i*x_t + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
811         if (twod && (s_t < 0)) s_t = bases[n4] + i*x_t + x_t*y_t*z_t - x_t*y_t; /* 2D case */
812         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
813       } else if (bz == DM_BOUNDARY_MIRROR) {
814         for (j=0; j<x; j++) idx[nn++] = bases[rank] + j + x*i + (s_z - k - 1)*x*y;
815       }
816 
817       if (n5 >= 0) { /* directly right */
818         x_t = lx[n5 % m];
819         y_t = y;
820         z_t = lz[n5 / (m*n)];
821         s_t = bases[n5] + i*x_t + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
822         if (twod && (s_t < 0)) s_t = bases[n5] + i*x_t + x_t*y_t*z_t - x_t*y_t; /* 2D case */
823         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
824       }
825     }
826 
827     for (i=1; i<=s_y; i++) {
828       if (n6 >= 0) { /* left above */
829         x_t = lx[n6 % m];
830         y_t = ly[(n6 % (m*n))/m];
831         z_t = lz[n6 / (m*n)];
832         s_t = bases[n6] + i*x_t - s_x + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
833         if (twod && (s_t < 0)) s_t = bases[n6] + i*x_t - s_x + x_t*y_t*z_t - x_t*y_t; /* 2D case */
834         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
835       }
836       if (n7 >= 0) { /* directly above */
837         x_t = x;
838         y_t = ly[(n7 % (m*n))/m];
839         z_t = lz[n7 / (m*n)];
840         s_t = bases[n7] + (i-1)*x_t + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
841         if (twod && (s_t < 0)) s_t = bases[n7] + (i-1)*x_t + x_t*y_t*z_t - x_t*y_t; /* 2D case */
842         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
843       }
844       if (n8 >= 0) { /* right above */
845         x_t = lx[n8 % m];
846         y_t = ly[(n8 % (m*n))/m];
847         z_t = lz[n8 / (m*n)];
848         s_t = bases[n8] + (i-1)*x_t + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
849         if (twod && (s_t < 0)) s_t = bases[n8] + (i-1)*x_t + x_t*y_t*z_t - x_t*y_t; /* 2D case */
850         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
851       }
852     }
853   }
854 
855   /* Middle Level */
856   for (k=0; k<z; k++) {
857     for (i=1; i<=s_y; i++) {
858       if (n9 >= 0) { /* left below */
859         x_t = lx[n9 % m];
860         y_t = ly[(n9 % (m*n))/m];
861         /* z_t = z; */
862         s_t = bases[n9] - (s_y-i)*x_t -s_x + (k+1)*x_t*y_t;
863         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
864       }
865       if (n10 >= 0) { /* directly below */
866         x_t = x;
867         y_t = ly[(n10 % (m*n))/m];
868         /* z_t = z; */
869         s_t = bases[n10] - (s_y+1-i)*x_t + (k+1)*x_t*y_t;
870         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
871       }  else if (by == DM_BOUNDARY_MIRROR) {
872         for (j=0; j<x; j++) idx[nn++] = bases[rank] + j + k*x*y + (s_y - i)*x;
873       }
874       if (n11 >= 0) { /* right below */
875         x_t = lx[n11 % m];
876         y_t = ly[(n11 % (m*n))/m];
877         /* z_t = z; */
878         s_t = bases[n11] - (s_y+1-i)*x_t + (k+1)*x_t*y_t;
879         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
880       }
881     }
882 
883     for (i=0; i<y; i++) {
884       if (n12 >= 0) { /* directly left */
885         x_t = lx[n12 % m];
886         y_t = y;
887         /* z_t = z; */
888         s_t = bases[n12] + (i+1)*x_t - s_x + k*x_t*y_t;
889         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
890       }  else if (bx == DM_BOUNDARY_MIRROR) {
891         for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + s_x - j - 1 + k*x*y + i*x;
892       }
893 
894       /* Interior */
895       s_t = bases[rank] + i*x + k*x*y;
896       for (j=0; j<x; j++) idx[nn++] = s_t++;
897 
898       if (n14 >= 0) { /* directly right */
899         x_t = lx[n14 % m];
900         y_t = y;
901         /* z_t = z; */
902         s_t = bases[n14] + i*x_t + k*x_t*y_t;
903         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
904       } else if (bx == DM_BOUNDARY_MIRROR) {
905         for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x - j - 1 + k*x*y + i*x;
906       }
907     }
908 
909     for (i=1; i<=s_y; i++) {
910       if (n15 >= 0) { /* left above */
911         x_t = lx[n15 % m];
912         y_t = ly[(n15 % (m*n))/m];
913         /* z_t = z; */
914         s_t = bases[n15] + i*x_t - s_x + k*x_t*y_t;
915         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
916       }
917       if (n16 >= 0) { /* directly above */
918         x_t = x;
919         y_t = ly[(n16 % (m*n))/m];
920         /* z_t = z; */
921         s_t = bases[n16] + (i-1)*x_t + k*x_t*y_t;
922         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
923       } else if (by == DM_BOUNDARY_MIRROR) {
924         for (j=0; j<x; j++) idx[nn++] = bases[rank] + j + k*x*y + (y-i)*x;
925       }
926       if (n17 >= 0) { /* right above */
927         x_t = lx[n17 % m];
928         y_t = ly[(n17 % (m*n))/m];
929         /* z_t = z; */
930         s_t = bases[n17] + (i-1)*x_t + k*x_t*y_t;
931         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
932       }
933     }
934   }
935 
936   /* Upper Level */
937   for (k=0; k<s_z; k++) {
938     for (i=1; i<=s_y; i++) {
939       if (n18 >= 0) { /* left below */
940         x_t = lx[n18 % m];
941         y_t = ly[(n18 % (m*n))/m];
942         /* z_t = lz[n18 / (m*n)]; */
943         s_t = bases[n18] - (s_y-i)*x_t -s_x + (k+1)*x_t*y_t;
944         if (twod && (s_t >= M*N*P)) s_t = bases[n18] - (s_y-i)*x_t -s_x + x_t*y_t; /* 2d case */
945         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
946       }
947       if (n19 >= 0) { /* directly below */
948         x_t = x;
949         y_t = ly[(n19 % (m*n))/m];
950         /* z_t = lz[n19 / (m*n)]; */
951         s_t = bases[n19] - (s_y+1-i)*x_t + (k+1)*x_t*y_t;
952         if (twod && (s_t >= M*N*P)) s_t = bases[n19] - (s_y+1-i)*x_t + x_t*y_t; /* 2d case */
953         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
954       }
955       if (n20 >= 0) { /* right below */
956         x_t = lx[n20 % m];
957         y_t = ly[(n20 % (m*n))/m];
958         /* z_t = lz[n20 / (m*n)]; */
959         s_t = bases[n20] - (s_y+1-i)*x_t + (k+1)*x_t*y_t;
960         if (twod && (s_t >= M*N*P)) s_t = bases[n20] - (s_y+1-i)*x_t + x_t*y_t; /* 2d case */
961         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
962       }
963     }
964 
965     for (i=0; i<y; i++) {
966       if (n21 >= 0) { /* directly left */
967         x_t = lx[n21 % m];
968         y_t = y;
969         /* z_t = lz[n21 / (m*n)]; */
970         s_t = bases[n21] + (i+1)*x_t - s_x + k*x_t*y_t;
971         if (twod && (s_t >= M*N*P)) s_t = bases[n21] + (i+1)*x_t - s_x;  /* 2d case */
972         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
973       }
974 
975       if (n22 >= 0) { /* middle */
976         x_t = x;
977         y_t = y;
978         /* z_t = lz[n22 / (m*n)]; */
979         s_t = bases[n22] + i*x_t + k*x_t*y_t;
980         if (twod && (s_t >= M*N*P)) s_t = bases[n22] + i*x_t; /* 2d case */
981         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
982       } else if (bz == DM_BOUNDARY_MIRROR) {
983         for (j=0; j<x; j++) idx[nn++] = bases[rank] + j + (z-k-1)*x*y + i*x;
984       }
985 
986       if (n23 >= 0) { /* directly right */
987         x_t = lx[n23 % m];
988         y_t = y;
989         /* z_t = lz[n23 / (m*n)]; */
990         s_t = bases[n23] + i*x_t + k*x_t*y_t;
991         if (twod && (s_t >= M*N*P)) s_t = bases[n23] + i*x_t; /* 2d case */
992         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
993       }
994     }
995 
996     for (i=1; i<=s_y; i++) {
997       if (n24 >= 0) { /* left above */
998         x_t = lx[n24 % m];
999         y_t = ly[(n24 % (m*n))/m];
1000         /* z_t = lz[n24 / (m*n)]; */
1001         s_t = bases[n24] + i*x_t - s_x + k*x_t*y_t;
1002         if (twod && (s_t >= M*N*P)) s_t = bases[n24] + i*x_t - s_x; /* 2d case */
1003         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1004       }
1005       if (n25 >= 0) { /* directly above */
1006         x_t = x;
1007         y_t = ly[(n25 % (m*n))/m];
1008         /* z_t = lz[n25 / (m*n)]; */
1009         s_t = bases[n25] + (i-1)*x_t + k*x_t*y_t;
1010         if (twod && (s_t >= M*N*P)) s_t = bases[n25] + (i-1)*x_t; /* 2d case */
1011         for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1012       }
1013       if (n26 >= 0) { /* right above */
1014         x_t = lx[n26 % m];
1015         y_t = ly[(n26 % (m*n))/m];
1016         /* z_t = lz[n26 / (m*n)]; */
1017         s_t = bases[n26] + (i-1)*x_t + k*x_t*y_t;
1018         if (twod && (s_t >= M*N*P)) s_t = bases[n26] + (i-1)*x_t; /* 2d case */
1019         for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1020       }
1021     }
1022   }
1023 
1024   PetscCall(ISCreateBlock(comm,dof,nn,idx,PETSC_USE_POINTER,&from));
1025   PetscCall(VecScatterCreate(global,from,local,to,&gtol));
1026   PetscCall(PetscLogObjectParent((PetscObject)da,(PetscObject)gtol));
1027   PetscCall(ISDestroy(&to));
1028   PetscCall(ISDestroy(&from));
1029 
1030   if (stencil_type == DMDA_STENCIL_STAR) {
1031     n0  = sn0;  n1  = sn1;  n2  = sn2;  n3  = sn3;  n5  = sn5;  n6  = sn6; n7 = sn7;
1032     n8  = sn8;  n9  = sn9;  n11 = sn11; n15 = sn15; n17 = sn17; n18 = sn18;
1033     n19 = sn19; n20 = sn20; n21 = sn21; n23 = sn23; n24 = sn24; n25 = sn25;
1034     n26 = sn26;
1035   }
1036 
1037   if (((stencil_type == DMDA_STENCIL_STAR) || (bx != DM_BOUNDARY_PERIODIC && bx) || (by != DM_BOUNDARY_PERIODIC && by) || (bz != DM_BOUNDARY_PERIODIC && bz))) {
1038     /*
1039         Recompute the local to global mappings, this time keeping the
1040       information about the cross corner processor numbers.
1041     */
1042     nn = 0;
1043     /* Bottom Level */
1044     for (k=0; k<s_z; k++) {
1045       for (i=1; i<=s_y; i++) {
1046         if (n0 >= 0) { /* left below */
1047           x_t = lx[n0 % m];
1048           y_t = ly[(n0 % (m*n))/m];
1049           z_t = lz[n0 / (m*n)];
1050           s_t = bases[n0] + x_t*y_t*z_t - (s_y-i)*x_t - s_x - (s_z-k-1)*x_t*y_t;
1051           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1052         } else if (Xs-xs < 0 && Ys-ys < 0 && Zs-zs < 0) {
1053           for (j=0; j<s_x; j++) idx[nn++] = -1;
1054         }
1055         if (n1 >= 0) { /* directly below */
1056           x_t = x;
1057           y_t = ly[(n1 % (m*n))/m];
1058           z_t = lz[n1 / (m*n)];
1059           s_t = bases[n1] + x_t*y_t*z_t - (s_y+1-i)*x_t - (s_z-k-1)*x_t*y_t;
1060           for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1061         } else if (Ys-ys < 0 && Zs-zs < 0) {
1062           for (j=0; j<x; j++) idx[nn++] = -1;
1063         }
1064         if (n2 >= 0) { /* right below */
1065           x_t = lx[n2 % m];
1066           y_t = ly[(n2 % (m*n))/m];
1067           z_t = lz[n2 / (m*n)];
1068           s_t = bases[n2] + x_t*y_t*z_t - (s_y+1-i)*x_t - (s_z-k-1)*x_t*y_t;
1069           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1070         } else if (xe-Xe < 0 && Ys-ys < 0 && Zs-zs < 0) {
1071           for (j=0; j<s_x; j++) idx[nn++] = -1;
1072         }
1073       }
1074 
1075       for (i=0; i<y; i++) {
1076         if (n3 >= 0) { /* directly left */
1077           x_t = lx[n3 % m];
1078           y_t = y;
1079           z_t = lz[n3 / (m*n)];
1080           s_t = bases[n3] + (i+1)*x_t - s_x + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
1081           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1082         } else if (Xs-xs < 0 && Zs-zs < 0) {
1083           for (j=0; j<s_x; j++) idx[nn++] = -1;
1084         }
1085 
1086         if (n4 >= 0) { /* middle */
1087           x_t = x;
1088           y_t = y;
1089           z_t = lz[n4 / (m*n)];
1090           s_t = bases[n4] + i*x_t + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
1091           for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1092         } else if (Zs-zs < 0) {
1093           if (bz == DM_BOUNDARY_MIRROR) {
1094             for (j=0; j<x; j++) idx[nn++] = bases[rank] + j + x*i + (s_z - k - 1)*x*y;
1095           } else {
1096             for (j=0; j<x; j++) idx[nn++] = -1;
1097           }
1098         }
1099 
1100         if (n5 >= 0) { /* directly right */
1101           x_t = lx[n5 % m];
1102           y_t = y;
1103           z_t = lz[n5 / (m*n)];
1104           s_t = bases[n5] + i*x_t + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
1105           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1106         } else if (xe-Xe < 0 && Zs-zs < 0) {
1107           for (j=0; j<s_x; j++) idx[nn++] = -1;
1108         }
1109       }
1110 
1111       for (i=1; i<=s_y; i++) {
1112         if (n6 >= 0) { /* left above */
1113           x_t = lx[n6 % m];
1114           y_t = ly[(n6 % (m*n))/m];
1115           z_t = lz[n6 / (m*n)];
1116           s_t = bases[n6] + i*x_t - s_x + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
1117           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1118         } else if (Xs-xs < 0 && ye-Ye < 0 && Zs-zs < 0) {
1119           for (j=0; j<s_x; j++) idx[nn++] = -1;
1120         }
1121         if (n7 >= 0) { /* directly above */
1122           x_t = x;
1123           y_t = ly[(n7 % (m*n))/m];
1124           z_t = lz[n7 / (m*n)];
1125           s_t = bases[n7] + (i-1)*x_t + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
1126           for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1127         } else if (ye-Ye < 0 && Zs-zs < 0) {
1128           for (j=0; j<x; j++) idx[nn++] = -1;
1129         }
1130         if (n8 >= 0) { /* right above */
1131           x_t = lx[n8 % m];
1132           y_t = ly[(n8 % (m*n))/m];
1133           z_t = lz[n8 / (m*n)];
1134           s_t = bases[n8] + (i-1)*x_t + x_t*y_t*z_t - (s_z-k)*x_t*y_t;
1135           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1136         } else if (xe-Xe < 0 && ye-Ye < 0 && Zs-zs < 0) {
1137           for (j=0; j<s_x; j++) idx[nn++] = -1;
1138         }
1139       }
1140     }
1141 
1142     /* Middle Level */
1143     for (k=0; k<z; k++) {
1144       for (i=1; i<=s_y; i++) {
1145         if (n9 >= 0) { /* left below */
1146           x_t = lx[n9 % m];
1147           y_t = ly[(n9 % (m*n))/m];
1148           /* z_t = z; */
1149           s_t = bases[n9] - (s_y-i)*x_t -s_x + (k+1)*x_t*y_t;
1150           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1151         } else if (Xs-xs < 0 && Ys-ys < 0) {
1152           for (j=0; j<s_x; j++) idx[nn++] = -1;
1153         }
1154         if (n10 >= 0) { /* directly below */
1155           x_t = x;
1156           y_t = ly[(n10 % (m*n))/m];
1157           /* z_t = z; */
1158           s_t = bases[n10] - (s_y+1-i)*x_t + (k+1)*x_t*y_t;
1159           for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1160         } else if (Ys-ys < 0) {
1161           if (by == DM_BOUNDARY_MIRROR) {
1162             for (j=0; j<x; j++) idx[nn++] = bases[rank] + j + k*x*y + (s_y - i)*x;
1163           } else {
1164             for (j=0; j<x; j++) idx[nn++] = -1;
1165           }
1166         }
1167         if (n11 >= 0) { /* right below */
1168           x_t = lx[n11 % m];
1169           y_t = ly[(n11 % (m*n))/m];
1170           /* z_t = z; */
1171           s_t = bases[n11] - (s_y+1-i)*x_t + (k+1)*x_t*y_t;
1172           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1173         } else if (xe-Xe < 0 && Ys-ys < 0) {
1174           for (j=0; j<s_x; j++) idx[nn++] = -1;
1175         }
1176       }
1177 
1178       for (i=0; i<y; i++) {
1179         if (n12 >= 0) { /* directly left */
1180           x_t = lx[n12 % m];
1181           y_t = y;
1182           /* z_t = z; */
1183           s_t = bases[n12] + (i+1)*x_t - s_x + k*x_t*y_t;
1184           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1185         } else if (Xs-xs < 0) {
1186           if (bx == DM_BOUNDARY_MIRROR) {
1187             for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + s_x - j - 1 + k*x*y + i*x;
1188           } else {
1189             for (j=0; j<s_x; j++) idx[nn++] = -1;
1190           }
1191         }
1192 
1193         /* Interior */
1194         s_t = bases[rank] + i*x + k*x*y;
1195         for (j=0; j<x; j++) idx[nn++] = s_t++;
1196 
1197         if (n14 >= 0) { /* directly right */
1198           x_t = lx[n14 % m];
1199           y_t = y;
1200           /* z_t = z; */
1201           s_t = bases[n14] + i*x_t + k*x_t*y_t;
1202           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1203         } else if (xe-Xe < 0) {
1204           if (bx == DM_BOUNDARY_MIRROR) {
1205             for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x - j - 1 + k*x*y + i*x;
1206           } else {
1207             for (j=0; j<s_x; j++) idx[nn++] = -1;
1208           }
1209         }
1210       }
1211 
1212       for (i=1; i<=s_y; i++) {
1213         if (n15 >= 0) { /* left above */
1214           x_t = lx[n15 % m];
1215           y_t = ly[(n15 % (m*n))/m];
1216           /* z_t = z; */
1217           s_t = bases[n15] + i*x_t - s_x + k*x_t*y_t;
1218           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1219         } else if (Xs-xs < 0 && ye-Ye < 0) {
1220           for (j=0; j<s_x; j++) idx[nn++] = -1;
1221         }
1222         if (n16 >= 0) { /* directly above */
1223           x_t = x;
1224           y_t = ly[(n16 % (m*n))/m];
1225           /* z_t = z; */
1226           s_t = bases[n16] + (i-1)*x_t + k*x_t*y_t;
1227           for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1228         } else if (ye-Ye < 0) {
1229           if (by == DM_BOUNDARY_MIRROR) {
1230             for (j=0; j<x; j++) idx[nn++] = bases[rank] + j + k*x*y + (y-i)*x;
1231           } else {
1232             for (j=0; j<x; j++) idx[nn++] = -1;
1233           }
1234         }
1235         if (n17 >= 0) { /* right above */
1236           x_t = lx[n17 % m];
1237           y_t = ly[(n17 % (m*n))/m];
1238           /* z_t = z; */
1239           s_t = bases[n17] + (i-1)*x_t + k*x_t*y_t;
1240           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1241         } else if (xe-Xe < 0 && ye-Ye < 0) {
1242           for (j=0; j<s_x; j++) idx[nn++] = -1;
1243         }
1244       }
1245     }
1246 
1247     /* Upper Level */
1248     for (k=0; k<s_z; k++) {
1249       for (i=1; i<=s_y; i++) {
1250         if (n18 >= 0) { /* left below */
1251           x_t = lx[n18 % m];
1252           y_t = ly[(n18 % (m*n))/m];
1253           /* z_t = lz[n18 / (m*n)]; */
1254           s_t = bases[n18] - (s_y-i)*x_t -s_x + (k+1)*x_t*y_t;
1255           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1256         } else if (Xs-xs < 0 && Ys-ys < 0 && ze-Ze < 0) {
1257           for (j=0; j<s_x; j++) idx[nn++] = -1;
1258         }
1259         if (n19 >= 0) { /* directly below */
1260           x_t = x;
1261           y_t = ly[(n19 % (m*n))/m];
1262           /* z_t = lz[n19 / (m*n)]; */
1263           s_t = bases[n19] - (s_y+1-i)*x_t + (k+1)*x_t*y_t;
1264           for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1265         } else if (Ys-ys < 0 && ze-Ze < 0) {
1266           for (j=0; j<x; j++) idx[nn++] = -1;
1267         }
1268         if (n20 >= 0) { /* right below */
1269           x_t = lx[n20 % m];
1270           y_t = ly[(n20 % (m*n))/m];
1271           /* z_t = lz[n20 / (m*n)]; */
1272           s_t = bases[n20] - (s_y+1-i)*x_t + (k+1)*x_t*y_t;
1273           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1274         } else if (xe-Xe < 0 && Ys-ys < 0 && ze-Ze < 0) {
1275           for (j=0; j<s_x; j++) idx[nn++] = -1;
1276         }
1277       }
1278 
1279       for (i=0; i<y; i++) {
1280         if (n21 >= 0) { /* directly left */
1281           x_t = lx[n21 % m];
1282           y_t = y;
1283           /* z_t = lz[n21 / (m*n)]; */
1284           s_t = bases[n21] + (i+1)*x_t - s_x + k*x_t*y_t;
1285           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1286         } else if (Xs-xs < 0 && ze-Ze < 0) {
1287           for (j=0; j<s_x; j++) idx[nn++] = -1;
1288         }
1289 
1290         if (n22 >= 0) { /* middle */
1291           x_t = x;
1292           y_t = y;
1293           /* z_t = lz[n22 / (m*n)]; */
1294           s_t = bases[n22] + i*x_t + k*x_t*y_t;
1295           for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1296         } else if (ze-Ze < 0) {
1297           if (bz == DM_BOUNDARY_MIRROR) {
1298             for (j=0; j<x; j++) idx[nn++] = bases[rank] + j + (z-k-1)*x*y + i*x;
1299           } else {
1300             for (j=0; j<x; j++) idx[nn++] = -1;
1301           }
1302         }
1303 
1304         if (n23 >= 0) { /* directly right */
1305           x_t = lx[n23 % m];
1306           y_t = y;
1307           /* z_t = lz[n23 / (m*n)]; */
1308           s_t = bases[n23] + i*x_t + k*x_t*y_t;
1309           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1310         } else if (xe-Xe < 0 && ze-Ze < 0) {
1311           for (j=0; j<s_x; j++) idx[nn++] = -1;
1312         }
1313       }
1314 
1315       for (i=1; i<=s_y; i++) {
1316         if (n24 >= 0) { /* left above */
1317           x_t = lx[n24 % m];
1318           y_t = ly[(n24 % (m*n))/m];
1319           /* z_t = lz[n24 / (m*n)]; */
1320           s_t = bases[n24] + i*x_t - s_x + k*x_t*y_t;
1321           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1322         } else if (Xs-xs < 0 && ye-Ye < 0 && ze-Ze < 0) {
1323           for (j=0; j<s_x; j++) idx[nn++] = -1;
1324         }
1325         if (n25 >= 0) { /* directly above */
1326           x_t = x;
1327           y_t = ly[(n25 % (m*n))/m];
1328           /* z_t = lz[n25 / (m*n)]; */
1329           s_t = bases[n25] + (i-1)*x_t + k*x_t*y_t;
1330           for (j=0; j<x_t; j++) idx[nn++] = s_t++;
1331         } else if (ye-Ye < 0 && ze-Ze < 0) {
1332           for (j=0; j<x; j++) idx[nn++] = -1;
1333         }
1334         if (n26 >= 0) { /* right above */
1335           x_t = lx[n26 % m];
1336           y_t = ly[(n26 % (m*n))/m];
1337           /* z_t = lz[n26 / (m*n)]; */
1338           s_t = bases[n26] + (i-1)*x_t + k*x_t*y_t;
1339           for (j=0; j<s_x; j++) idx[nn++] = s_t++;
1340         } else if (xe-Xe < 0 && ye-Ye < 0 && ze-Ze < 0) {
1341           for (j=0; j<s_x; j++) idx[nn++] = -1;
1342         }
1343       }
1344     }
1345   }
1346   /*
1347      Set the local to global ordering in the global vector, this allows use
1348      of VecSetValuesLocal().
1349   */
1350   PetscCall(ISLocalToGlobalMappingCreate(comm,dof,nn,idx,PETSC_OWN_POINTER,&da->ltogmap));
1351   PetscCall(PetscLogObjectParent((PetscObject)da,(PetscObject)da->ltogmap));
1352 
1353   PetscCall(PetscFree2(bases,ldims));
1354   dd->m = m;  dd->n  = n;  dd->p  = p;
1355   /* note petsc expects xs/xe/Xs/Xe to be multiplied by #dofs in many places */
1356   dd->xs = xs*dof; dd->xe = xe*dof; dd->ys = ys; dd->ye = ye; dd->zs = zs; dd->ze = ze;
1357   dd->Xs = Xs*dof; dd->Xe = Xe*dof; dd->Ys = Ys; dd->Ye = Ye; dd->Zs = Zs; dd->Ze = Ze;
1358 
1359   PetscCall(VecDestroy(&local));
1360   PetscCall(VecDestroy(&global));
1361 
1362   dd->gtol      = gtol;
1363   dd->base      = base;
1364   da->ops->view = DMView_DA_3d;
1365   dd->ltol      = NULL;
1366   dd->ao        = NULL;
1367   PetscFunctionReturn(0);
1368 }
1369 
1370 /*@C
1371    DMDACreate3d - Creates an object that will manage the communication of three-dimensional
1372    regular array data that is distributed across some processors.
1373 
1374    Collective
1375 
1376    Input Parameters:
1377 +  comm - MPI communicator
1378 .  bx,by,bz - type of ghost nodes the array have.
1379          Use one of DM_BOUNDARY_NONE, DM_BOUNDARY_GHOSTED, DM_BOUNDARY_PERIODIC.
1380 .  stencil_type - Type of stencil (DMDA_STENCIL_STAR or DMDA_STENCIL_BOX)
1381 .  M,N,P - global dimension in each direction of the array
1382 .  m,n,p - corresponding number of processors in each dimension
1383            (or PETSC_DECIDE to have calculated)
1384 .  dof - number of degrees of freedom per node
1385 .  s - stencil width
1386 -  lx, ly, lz - arrays containing the number of nodes in each cell along
1387           the x, y, and z coordinates, or NULL. If non-null, these
1388           must be of length as m,n,p and the corresponding
1389           m,n, or p cannot be PETSC_DECIDE. Sum of the lx[] entries must be M, sum of
1390           the ly[] must N, sum of the lz[] must be P
1391 
1392    Output Parameter:
1393 .  da - the resulting distributed array object
1394 
1395    Options Database Key:
1396 +  -dm_view - Calls DMView() at the conclusion of DMDACreate3d()
1397 .  -da_grid_x <nx> - number of grid points in x direction
1398 .  -da_grid_y <ny> - number of grid points in y direction
1399 .  -da_grid_z <nz> - number of grid points in z direction
1400 .  -da_processors_x <MX> - number of processors in x direction
1401 .  -da_processors_y <MY> - number of processors in y direction
1402 .  -da_processors_z <MZ> - number of processors in z direction
1403 .  -da_refine_x <rx> - refinement ratio in x direction
1404 .  -da_refine_y <ry> - refinement ratio in y direction
1405 .  -da_refine_z <rz>- refinement ratio in z directio
1406 -  -da_refine <n> - refine the DMDA n times before creating it
1407 
1408    Level: beginner
1409 
1410    Notes:
1411    The stencil type DMDA_STENCIL_STAR with width 1 corresponds to the
1412    standard 7-pt stencil, while DMDA_STENCIL_BOX with width 1 denotes
1413    the standard 27-pt stencil.
1414 
1415    The array data itself is NOT stored in the DMDA, it is stored in Vec objects;
1416    The appropriate vector objects can be obtained with calls to DMCreateGlobalVector()
1417    and DMCreateLocalVector() and calls to VecDuplicate() if more are needed.
1418 
1419    You must call DMSetUp() after this call before using this DM.
1420 
1421    If you wish to use the options database to change values in the DMDA call DMSetFromOptions() after this call
1422    but before DMSetUp().
1423 
1424 .seealso: `DMDestroy()`, `DMView()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMGlobalToLocalBegin()`, `DMDAGetRefinementFactor()`,
1425           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToLocalBegin()`, `DMLocalToLocalEnd()`, `DMDASetRefinementFactor()`,
1426           `DMDAGetInfo()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`, `DMDACreateNaturalVector()`, `DMLoad()`, `DMDAGetOwnershipRanges()`,
1427           `DMStagCreate3d()`
1428 
1429 @*/
1430 PetscErrorCode  DMDACreate3d(MPI_Comm comm,DMBoundaryType bx,DMBoundaryType by,DMBoundaryType bz,DMDAStencilType stencil_type,PetscInt M,
1431                PetscInt N,PetscInt P,PetscInt m,PetscInt n,PetscInt p,PetscInt dof,PetscInt s,const PetscInt lx[],const PetscInt ly[],const PetscInt lz[],DM *da)
1432 {
1433   PetscFunctionBegin;
1434   PetscCall(DMDACreate(comm, da));
1435   PetscCall(DMSetDimension(*da, 3));
1436   PetscCall(DMDASetSizes(*da, M, N, P));
1437   PetscCall(DMDASetNumProcs(*da, m, n, p));
1438   PetscCall(DMDASetBoundaryType(*da, bx, by, bz));
1439   PetscCall(DMDASetDof(*da, dof));
1440   PetscCall(DMDASetStencilType(*da, stencil_type));
1441   PetscCall(DMDASetStencilWidth(*da, s));
1442   PetscCall(DMDASetOwnershipRanges(*da, lx, ly, lz));
1443   PetscFunctionReturn(0);
1444 }
1445