1 /*
2    Implementation of DMStag, defining dimension-independent functions in the
3    DM API. stag1d.c, stag2d.c, and stag3d.c may include dimension-specific
4    implementations of DM API functions, and other files here contain additional
5    DMStag-specific API functions, as well as internal functions.
6 */
7 #include <petsc/private/dmstagimpl.h>
8 #include <petscsf.h>
9 
DMClone_Stag(DM dm,DM * newdm)10 static PetscErrorCode DMClone_Stag(DM dm,DM *newdm)
11 {
12   PetscErrorCode ierr;
13 
14   PetscFunctionBegin;
15   /* Destroy the DM created by generic logic in DMClone() */
16   if (*newdm) {
17     ierr = DMDestroy(newdm);CHKERRQ(ierr);
18   }
19   ierr = DMStagDuplicateWithoutSetup(dm,PetscObjectComm((PetscObject)dm),newdm);CHKERRQ(ierr);
20   ierr = DMSetUp(*newdm);CHKERRQ(ierr);
21   PetscFunctionReturn(0);
22 }
23 
DMDestroy_Stag(DM dm)24 static PetscErrorCode DMDestroy_Stag(DM dm)
25 {
26   PetscErrorCode ierr;
27   DM_Stag        *stag;
28   PetscInt       i;
29 
30   PetscFunctionBegin;
31   stag = (DM_Stag*)dm->data;
32   for (i=0; i<DMSTAG_MAX_DIM; ++i) {
33     ierr = PetscFree(stag->l[i]);CHKERRQ(ierr);
34   }
35   ierr = VecScatterDestroy(&stag->gtol);CHKERRQ(ierr);
36   ierr = VecScatterDestroy(&stag->ltog_injective);CHKERRQ(ierr);
37   ierr = PetscFree(stag->neighbors);CHKERRQ(ierr);
38   ierr = PetscFree(stag->locationOffsets);CHKERRQ(ierr);
39   ierr = PetscFree(stag->coordinateDMType);CHKERRQ(ierr);
40   ierr = PetscFree(stag);CHKERRQ(ierr);
41   PetscFunctionReturn(0);
42 }
43 
DMCreateGlobalVector_Stag(DM dm,Vec * vec)44 static PetscErrorCode DMCreateGlobalVector_Stag(DM dm,Vec *vec)
45 {
46   PetscErrorCode  ierr;
47   DM_Stag * const stag = (DM_Stag*)dm->data;
48 
49   PetscFunctionBegin;
50   ierr = VecCreateMPI(PetscObjectComm((PetscObject)dm),stag->entries,PETSC_DECIDE,vec);CHKERRQ(ierr);
51   ierr = VecSetDM(*vec,dm);CHKERRQ(ierr);
52   /* Could set some ops, as DMDA does */
53   ierr = VecSetLocalToGlobalMapping(*vec,dm->ltogmap);CHKERRQ(ierr);
54   PetscFunctionReturn(0);
55 }
56 
DMCreateLocalVector_Stag(DM dm,Vec * vec)57 static PetscErrorCode DMCreateLocalVector_Stag(DM dm,Vec *vec)
58 {
59   PetscErrorCode  ierr;
60   DM_Stag * const stag = (DM_Stag*)dm->data;
61 
62   PetscFunctionBegin;
63   ierr = VecCreateSeq(PETSC_COMM_SELF,stag->entriesGhost,vec);CHKERRQ(ierr);
64   ierr = VecSetBlockSize(*vec,stag->entriesPerElement);CHKERRQ(ierr);
65   ierr = VecSetDM(*vec,dm);CHKERRQ(ierr);
66   PetscFunctionReturn(0);
67 }
68 
DMCreateMatrix_Stag(DM dm,Mat * mat)69 static PetscErrorCode DMCreateMatrix_Stag(DM dm,Mat *mat)
70 {
71   PetscErrorCode         ierr;
72   MatType                matType;
73   PetscBool              isaij,isshell;
74   PetscInt               entries,width,nNeighbors,dim,dof[DMSTAG_MAX_STRATA],stencilWidth;
75   DMStagStencilType      stencilType;
76   ISLocalToGlobalMapping ltogmap;
77 
78   PetscFunctionBegin;
79   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
80   ierr = DMGetMatType(dm,&matType);CHKERRQ(ierr);
81   ierr = PetscStrcmp(matType,MATAIJ,&isaij);CHKERRQ(ierr);
82   ierr = PetscStrcmp(matType,MATSHELL,&isshell);CHKERRQ(ierr);
83   ierr = DMStagGetEntries(dm,&entries);CHKERRQ(ierr);
84   ierr = DMStagGetDOF(dm,&dof[0],&dof[1],&dof[2],&dof[3]);CHKERRQ(ierr);
85   ierr = DMStagGetStencilWidth(dm,&stencilWidth);CHKERRQ(ierr);
86   ierr = DMStagGetStencilType(dm,&stencilType);CHKERRQ(ierr);
87 
88   if (isaij) {
89     /* This implementation gives a very dense stencil, which is likely unsuitable for
90        real applications. */
91     switch (stencilType) {
92       case DMSTAG_STENCIL_NONE:
93         nNeighbors = 1;
94         break;
95       case DMSTAG_STENCIL_STAR:
96         switch (dim) {
97           case 1 :
98             nNeighbors = 2*stencilWidth + 1;
99             break;
100           case 2 :
101             nNeighbors = 4*stencilWidth + 3;
102             break;
103           case 3 :
104             nNeighbors = 6*stencilWidth + 5;
105             break;
106           default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported dimension %d",dim);
107         }
108         break;
109       case DMSTAG_STENCIL_BOX:
110         switch (dim) {
111           case 1 :
112             nNeighbors = (2*stencilWidth + 1);
113             break;
114           case 2 :
115             nNeighbors = (2*stencilWidth + 1) * (2*stencilWidth + 1);
116             break;
117           case 3 :
118             nNeighbors = (2*stencilWidth + 1) * (2*stencilWidth + 1) * (2*stencilWidth + 1);
119             break;
120           default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported dimension %d",dim);
121         }
122         break;
123       default : SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported stencil");
124     }
125     width = (dof[0] + dof[1] + dof[2] + dof[3]) * nNeighbors;
126     ierr = MatCreateAIJ(PETSC_COMM_WORLD,entries,entries,PETSC_DETERMINE,PETSC_DETERMINE,width,NULL,width,NULL,mat);CHKERRQ(ierr);
127   } else if (isshell) {
128     ierr = MatCreate(PetscObjectComm((PetscObject)dm),mat);CHKERRQ(ierr);
129     ierr = MatSetSizes(*mat,entries,entries,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
130     ierr = MatSetType(*mat,MATSHELL);CHKERRQ(ierr);
131     ierr = MatSetUp(*mat);CHKERRQ(ierr);
132   } else SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not implemented for Mattype %s",matType);
133 
134   ierr = DMGetLocalToGlobalMapping(dm,&ltogmap);CHKERRQ(ierr);
135   ierr = MatSetLocalToGlobalMapping(*mat,ltogmap,ltogmap);CHKERRQ(ierr);
136   ierr = MatSetDM(*mat,dm);CHKERRQ(ierr);
137   PetscFunctionReturn(0);
138 }
139 
DMGetCompatibility_Stag(DM dm,DM dm2,PetscBool * compatible,PetscBool * set)140 static PetscErrorCode DMGetCompatibility_Stag(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
141 {
142   PetscErrorCode  ierr;
143   const DM_Stag * const stag  = (DM_Stag*)dm->data;
144   const DM_Stag * const stag2 = (DM_Stag*)dm2->data;
145   PetscInt              dim,dim2,i;
146   MPI_Comm              comm;
147   PetscMPIInt           sameComm;
148   DMType                type2;
149   PetscBool             sameType;
150 
151   PetscFunctionBegin;
152   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
153   ierr = PetscStrcmp(DMSTAG,type2,&sameType);CHKERRQ(ierr);
154   if (!sameType) {
155     ierr = PetscInfo1((PetscObject)dm,"DMStag compatibility check not implemented with DM of type %s\n",type2);CHKERRQ(ierr);
156     *set = PETSC_FALSE;
157     PetscFunctionReturn(0);
158   }
159 
160   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
161   ierr = MPI_Comm_compare(comm,PetscObjectComm((PetscObject)dm2),&sameComm);CHKERRQ(ierr);
162   if (sameComm != MPI_IDENT) {
163     ierr = PetscInfo2((PetscObject)dm,"DMStag objects have different communicators: %d != %d\n",comm,PetscObjectComm((PetscObject)dm2));CHKERRQ(ierr);
164     *set = PETSC_FALSE;
165     PetscFunctionReturn(0);
166   }
167   ierr = DMGetDimension(dm ,&dim);CHKERRQ(ierr);
168   ierr = DMGetDimension(dm2,&dim2);CHKERRQ(ierr);
169   if (dim != dim2) {
170     ierr = PetscInfo((PetscObject)dm,"DMStag objects have different dimensions");CHKERRQ(ierr);
171     *set = PETSC_TRUE;
172     *compatible = PETSC_FALSE;
173     PetscFunctionReturn(0);
174   }
175   for (i=0; i<dim; ++i) {
176     if (stag->N[i] != stag2->N[i]) {
177       ierr = PetscInfo3((PetscObject)dm,"DMStag objects have different global numbers of elements in dimension %D: %D != %D\n",i,stag->n[i],stag2->n[i]);CHKERRQ(ierr);
178       *set = PETSC_TRUE;
179       *compatible = PETSC_FALSE;
180       PetscFunctionReturn(0);
181     }
182     if (stag->n[i] != stag2->n[i]) {
183       ierr = PetscInfo3((PetscObject)dm,"DMStag objects have different local numbers of elements in dimension %D: %D != %D\n",i,stag->n[i],stag2->n[i]);CHKERRQ(ierr);
184       *set = PETSC_TRUE;
185       *compatible = PETSC_FALSE;
186       PetscFunctionReturn(0);
187     }
188     if (stag->boundaryType[i] != stag2->boundaryType[i]) {
189       ierr = PetscInfo3((PetscObject)dm,"DMStag objects have different boundary types in dimension %d: %s != %s\n",i,stag->boundaryType[i],stag2->boundaryType[i]);CHKERRQ(ierr);
190       *set = PETSC_TRUE;
191       *compatible = PETSC_FALSE;
192       PetscFunctionReturn(0);
193     }
194   }
195   /* Note: we include stencil type and width in the notion of compatibility, as this affects
196      the "atlas" (local subdomains). This might be irritating in legitimate cases
197      of wanting to transfer between two other-wise compatible DMs with different
198      stencil characteristics. */
199   if (stag->stencilType != stag2->stencilType) {
200     ierr = PetscInfo2((PetscObject)dm,"DMStag objects have different ghost stencil types: %s != %s\n",DMStagStencilTypes[stag->stencilType],DMStagStencilTypes[stag2->stencilType]);CHKERRQ(ierr);
201     *set = PETSC_TRUE;
202     *compatible = PETSC_FALSE;
203     PetscFunctionReturn(0);
204   }
205   if (stag->stencilWidth != stag2->stencilWidth) {
206     ierr = PetscInfo2((PetscObject)dm,"DMStag objects have different ghost stencil widths: %D != %D\n",stag->stencilWidth,stag->stencilWidth);CHKERRQ(ierr);
207     *set = PETSC_TRUE;
208     *compatible = PETSC_FALSE;
209     PetscFunctionReturn(0);
210   }
211   *set = PETSC_TRUE;
212   *compatible = PETSC_TRUE;
213   PetscFunctionReturn(0);
214 }
215 
216 
217 /*
218 Note there are several orderings in play here.
219 In all cases, non-element dof are associated with the element that they are below/left/behind, and the order in 2D proceeds vertex/bottom edge/left edge/element (with all dof on each together).
220 Also in all cases, only subdomains which are the last in their dimension have partial elements.
221 
222 1) "Natural" Ordering (not used). Number adding each full or partial (on the right or top) element, starting at the bottom left (i=0,j=0) and proceeding across the entire domain, row by row to get a global numbering.
223 2) Global ("PETSc") ordering. The same as natural, but restricted to each domain. So, traverse all elements (again starting at the bottom left and going row-by-row) on rank 0, then continue numbering with rank 1, and so on.
224 3) Local ordering. Including ghost elements (both interior and on the right/top/front to complete partial elements), use the same convention to create a local numbering.
225 */
226 
DMLocalToGlobalBegin_Stag(DM dm,Vec l,InsertMode mode,Vec g)227 static PetscErrorCode DMLocalToGlobalBegin_Stag(DM dm,Vec l,InsertMode mode,Vec g)
228 {
229   PetscErrorCode  ierr;
230   DM_Stag * const stag = (DM_Stag*)dm->data;
231 
232   PetscFunctionBegin;
233   if (mode == ADD_VALUES) {
234     ierr = VecScatterBegin(stag->gtol,l,g,mode,SCATTER_REVERSE);CHKERRQ(ierr);
235   } else if (mode == INSERT_VALUES) {
236     if (stag->ltog_injective) {
237       ierr = VecScatterBegin(stag->ltog_injective,l,g,mode,SCATTER_FORWARD);CHKERRQ(ierr);
238     } else {
239       ierr = VecScatterBegin(stag->gtol,l,g,mode,SCATTER_REVERSE_LOCAL);CHKERRQ(ierr);
240     }
241   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unsupported InsertMode");
242   PetscFunctionReturn(0);
243 }
244 
DMLocalToGlobalEnd_Stag(DM dm,Vec l,InsertMode mode,Vec g)245 static PetscErrorCode DMLocalToGlobalEnd_Stag(DM dm,Vec l,InsertMode mode,Vec g)
246 {
247   PetscErrorCode  ierr;
248   DM_Stag * const stag = (DM_Stag*)dm->data;
249 
250   PetscFunctionBegin;
251   if (mode == ADD_VALUES) {
252     ierr = VecScatterEnd(stag->gtol,l,g,mode,SCATTER_REVERSE);CHKERRQ(ierr);
253   } else if (mode == INSERT_VALUES) {
254     if (stag->ltog_injective) {
255       ierr = VecScatterEnd(stag->ltog_injective,l,g,mode,SCATTER_FORWARD);CHKERRQ(ierr);
256     } else {
257       ierr = VecScatterEnd(stag->gtol,l,g,mode,SCATTER_REVERSE_LOCAL);CHKERRQ(ierr);
258     }
259   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unsupported InsertMode");
260   PetscFunctionReturn(0);
261 }
262 
DMGlobalToLocalBegin_Stag(DM dm,Vec g,InsertMode mode,Vec l)263 static PetscErrorCode DMGlobalToLocalBegin_Stag(DM dm,Vec g,InsertMode mode,Vec l)
264 {
265   PetscErrorCode  ierr;
266   DM_Stag * const stag = (DM_Stag*)dm->data;
267 
268   PetscFunctionBegin;
269   ierr = VecScatterBegin(stag->gtol,g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
270   PetscFunctionReturn(0);
271 }
272 
DMGlobalToLocalEnd_Stag(DM dm,Vec g,InsertMode mode,Vec l)273 static PetscErrorCode DMGlobalToLocalEnd_Stag(DM dm,Vec g,InsertMode mode,Vec l)
274 {
275   PetscErrorCode  ierr;
276   DM_Stag * const stag = (DM_Stag*)dm->data;
277 
278   PetscFunctionBegin;
279   ierr = VecScatterEnd(stag->gtol,g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
280   PetscFunctionReturn(0);
281 }
282 
283 /*
284 If a stratum is active (non-zero dof), make it active in the coordinate DM.
285 */
DMCreateCoordinateDM_Stag(DM dm,DM * dmc)286 static PetscErrorCode DMCreateCoordinateDM_Stag(DM dm,DM *dmc)
287 {
288   PetscErrorCode  ierr;
289   DM_Stag * const stag = (DM_Stag*)dm->data;
290   PetscInt        dim;
291   PetscBool       isstag,isproduct;
292 
293   PetscFunctionBegin;
294 
295   if (!stag->coordinateDMType) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Before creating a coordinate DM, a type must be specified with DMStagSetCoordinateDMType()");
296 
297   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
298   ierr = PetscStrcmp(stag->coordinateDMType,DMSTAG,&isstag);CHKERRQ(ierr);
299   ierr = PetscStrcmp(stag->coordinateDMType,DMPRODUCT,&isproduct);CHKERRQ(ierr);
300   if (isstag) {
301     ierr = DMStagCreateCompatibleDMStag(dm,
302         stag->dof[0] > 0 ? dim : 0,
303         stag->dof[1] > 0 ? dim : 0,
304         stag->dof[2] > 0 ? dim : 0,
305         stag->dof[3] > 0 ? dim : 0,
306         dmc);CHKERRQ(ierr);
307   } else if (isproduct) {
308     ierr = DMCreate(PETSC_COMM_WORLD,dmc);CHKERRQ(ierr);
309     ierr = DMSetType(*dmc,DMPRODUCT);CHKERRQ(ierr);
310     ierr = DMSetDimension(*dmc,dim);CHKERRQ(ierr);
311   } else SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unsupported coordinate DM type %s",stag->coordinateDMType);
312   PetscFunctionReturn(0);
313 }
314 
DMGetNeighbors_Stag(DM dm,PetscInt * nRanks,const PetscMPIInt * ranks[])315 static PetscErrorCode DMGetNeighbors_Stag(DM dm,PetscInt *nRanks,const PetscMPIInt *ranks[])
316 {
317   PetscErrorCode  ierr;
318   DM_Stag * const stag = (DM_Stag*)dm->data;
319   PetscInt        dim;
320 
321   PetscFunctionBegin;
322   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
323   switch (dim) {
324     case 1: *nRanks = 3; break;
325     case 2: *nRanks = 9; break;
326     case 3: *nRanks = 27; break;
327     default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Get neighbors not implemented for dim = %D",dim);
328   }
329   *ranks = stag->neighbors;
330   PetscFunctionReturn(0);
331 }
332 
DMView_Stag(DM dm,PetscViewer viewer)333 static PetscErrorCode DMView_Stag(DM dm,PetscViewer viewer)
334 {
335   PetscErrorCode  ierr;
336   DM_Stag * const stag = (DM_Stag*)dm->data;
337   PetscBool       isascii,viewAllRanks;
338   PetscMPIInt     rank,size;
339   PetscInt        dim,maxRanksToView,i;
340 
341   PetscFunctionBegin;
342   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
343   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);CHKERRQ(ierr);
344   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
345   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
346   if (isascii) {
347     ierr = PetscViewerASCIIPrintf(viewer,"Dimension: %D\n",dim);CHKERRQ(ierr);
348     switch (dim) {
349       case 1:
350         ierr = PetscViewerASCIIPrintf(viewer,"Global size: %D\n",stag->N[0]);CHKERRQ(ierr);
351         break;
352       case 2:
353         ierr = PetscViewerASCIIPrintf(viewer,"Global sizes: %D x %D\n",stag->N[0],stag->N[1]);CHKERRQ(ierr);
354         ierr = PetscViewerASCIIPrintf(viewer,"Parallel decomposition: %D x %D ranks\n",stag->nRanks[0],stag->nRanks[1]);CHKERRQ(ierr);
355         break;
356       case 3:
357         ierr = PetscViewerASCIIPrintf(viewer,"Global sizes: %D x %D x %D\n",stag->N[0],stag->N[1],stag->N[2]);CHKERRQ(ierr);
358         ierr = PetscViewerASCIIPrintf(viewer,"Parallel decomposition: %D x %D x %D ranks\n",stag->nRanks[0],stag->nRanks[1],stag->nRanks[2]);CHKERRQ(ierr);
359         break;
360       default: SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"not implemented for dim==%D",dim);
361     }
362     ierr = PetscViewerASCIIPrintf(viewer,"Boundary ghosting:");CHKERRQ(ierr);
363     for (i=0; i<dim; ++i) {
364       ierr = PetscViewerASCIIPrintf(viewer," %s",DMBoundaryTypes[stag->boundaryType[i]]);CHKERRQ(ierr);
365     }
366     ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
367     ierr = PetscViewerASCIIPrintf(viewer,"Elementwise ghost stencil: %s, width %D\n",DMStagStencilTypes[stag->stencilType],stag->stencilWidth);CHKERRQ(ierr);
368     ierr = PetscViewerASCIIPrintf(viewer,"Stratum dof:");CHKERRQ(ierr);
369     for (i=0; i<dim+1; ++i) {
370       ierr = PetscViewerASCIIPrintf(viewer," %D:%D",i,stag->dof[i]);CHKERRQ(ierr);
371     }
372     ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
373     if (dm->coordinateDM) {
374       ierr = PetscViewerASCIIPrintf(viewer,"Has coordinate DM\n");CHKERRQ(ierr);
375     }
376     maxRanksToView = 16;
377     viewAllRanks = (PetscBool)(size <= maxRanksToView);
378     if (viewAllRanks) {
379       ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
380       switch (dim) {
381         case 1:
382           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Local elements : %D (%D with ghosts)\n",rank,stag->n[0],stag->nGhost[0]);CHKERRQ(ierr);
383           break;
384         case 2:
385           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Rank coordinates (%d,%d)\n",rank,stag->rank[0],stag->rank[1]);CHKERRQ(ierr);
386           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Local elements : %D x %D (%D x %D with ghosts)\n",rank,stag->n[0],stag->n[1],stag->nGhost[0],stag->nGhost[1]);CHKERRQ(ierr);
387           break;
388         case 3:
389           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Rank coordinates (%d,%d,%d)\n",rank,stag->rank[0],stag->rank[1],stag->rank[2]);CHKERRQ(ierr);
390           ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Local elements : %D x %D x %D (%D x %D x %D with ghosts)\n",rank,stag->n[0],stag->n[1],stag->n[2],stag->nGhost[0],stag->nGhost[1],stag->nGhost[2]);CHKERRQ(ierr);
391           break;
392         default: SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"not implemented for dim==%D",dim);
393       }
394       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Local native entries: %d\n",rank,stag->entries);CHKERRQ(ierr);
395       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Local entries total : %d\n",rank,stag->entriesGhost);CHKERRQ(ierr);
396       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
397       ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
398     } else {
399       ierr = PetscViewerASCIIPrintf(viewer,"(Per-rank information omitted since >%D ranks used)\n",maxRanksToView);CHKERRQ(ierr);
400     }
401   }
402   PetscFunctionReturn(0);
403 }
404 
DMSetFromOptions_Stag(PetscOptionItems * PetscOptionsObject,DM dm)405 static PetscErrorCode DMSetFromOptions_Stag(PetscOptionItems *PetscOptionsObject,DM dm)
406 {
407   PetscErrorCode  ierr;
408   DM_Stag * const stag = (DM_Stag*)dm->data;
409   PetscInt        dim;
410 
411   PetscFunctionBegin;
412   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
413   ierr = PetscOptionsHead(PetscOptionsObject,"DMStag Options");CHKERRQ(ierr);
414   ierr = PetscOptionsInt("-stag_grid_x","Number of grid points in x direction","DMStagSetGlobalSizes",stag->N[0],&stag->N[0],NULL);CHKERRQ(ierr);
415   if (dim > 1) { ierr = PetscOptionsInt("-stag_grid_y","Number of grid points in y direction","DMStagSetGlobalSizes",stag->N[1],&stag->N[1],NULL);CHKERRQ(ierr); }
416   if (dim > 2) { ierr = PetscOptionsInt("-stag_grid_z","Number of grid points in z direction","DMStagSetGlobalSizes",stag->N[2],&stag->N[2],NULL);CHKERRQ(ierr); }
417   ierr = PetscOptionsInt("-stag_ranks_x","Number of ranks in x direction","DMStagSetNumRanks",stag->nRanks[0],&stag->nRanks[0],NULL);CHKERRQ(ierr);
418   if (dim > 1) { ierr = PetscOptionsInt("-stag_ranks_y","Number of ranks in y direction","DMStagSetNumRanks",stag->nRanks[1],&stag->nRanks[1],NULL);CHKERRQ(ierr); }
419   if (dim > 2) { ierr = PetscOptionsInt("-stag_ranks_z","Number of ranks in z direction","DMStagSetNumRanks",stag->nRanks[2],&stag->nRanks[2],NULL);CHKERRQ(ierr); }
420   ierr = PetscOptionsInt("-stag_stencil_width","Elementwise stencil width","DMStagSetStencilWidth",stag->stencilWidth,&stag->stencilWidth,NULL);CHKERRQ(ierr);
421   ierr = PetscOptionsEnum("-stag_stencil_type","Elementwise stencil stype","DMStagSetStencilType",DMStagStencilTypes,(PetscEnum)stag->stencilType,(PetscEnum*)&stag->stencilType,NULL);CHKERRQ(ierr);
422   ierr = PetscOptionsEnum("-stag_boundary_type_x","Treatment of (physical) boundaries in x direction","DMStagSetBoundaryTypes",DMBoundaryTypes,(PetscEnum)stag->boundaryType[0],(PetscEnum*)&stag->boundaryType[0],NULL);CHKERRQ(ierr);
423   ierr = PetscOptionsEnum("-stag_boundary_type_y","Treatment of (physical) boundaries in y direction","DMStagSetBoundaryTypes",DMBoundaryTypes,(PetscEnum)stag->boundaryType[1],(PetscEnum*)&stag->boundaryType[1],NULL);CHKERRQ(ierr);
424   ierr = PetscOptionsEnum("-stag_boundary_type_z","Treatment of (physical) boundaries in z direction","DMStagSetBoundaryTypes",DMBoundaryTypes,(PetscEnum)stag->boundaryType[2],(PetscEnum*)&stag->boundaryType[2],NULL);CHKERRQ(ierr);
425   ierr = PetscOptionsInt("-stag_dof_0","Number of dof per 0-cell (vertex/corner)","DMStagSetDOF",stag->dof[0],&stag->dof[0],NULL);CHKERRQ(ierr);
426   ierr = PetscOptionsInt("-stag_dof_1","Number of dof per 1-cell (edge)",         "DMStagSetDOF",stag->dof[1],&stag->dof[1],NULL);CHKERRQ(ierr);
427   ierr = PetscOptionsInt("-stag_dof_2","Number of dof per 2-cell (face)",         "DMStagSetDOF",stag->dof[2],&stag->dof[2],NULL);CHKERRQ(ierr);
428   ierr = PetscOptionsInt("-stag_dof_3","Number of dof per 3-cell (hexahedron)",   "DMStagSetDOF",stag->dof[3],&stag->dof[3],NULL);CHKERRQ(ierr);
429   ierr = PetscOptionsTail();CHKERRQ(ierr);
430   PetscFunctionReturn(0);
431 }
432 
433 /*MC
434   DMSTAG = "stag" - A DM object representing a "staggered grid" or a structured cell complex.
435 
436   This implementation parallels the DMDA implementation in many ways, but allows degrees of freedom
437   to be associated with all "strata" in a logically-rectangular grid: vertices, edges, faces, and elements.
438 
439   Level: beginner
440 
441 .seealso: DM, DMPRODUCT, DMDA, DMPLEX, DMStagCreate1d(), DMStagCreate2d(), DMStagCreate3d(), DMType, DMCreate(), DMSetType()
442 M*/
443 
DMCreate_Stag(DM dm)444 PETSC_EXTERN PetscErrorCode DMCreate_Stag(DM dm)
445 {
446   PetscErrorCode ierr;
447   DM_Stag        *stag;
448   PetscInt       i,dim;
449 
450   PetscFunctionBegin;
451   PetscValidPointer(dm,1);
452   ierr = PetscNewLog(dm,&stag);CHKERRQ(ierr);
453   dm->data = stag;
454 
455   stag->gtol                                          = NULL;
456   stag->ltog_injective                                = NULL;
457   for (i=0; i<DMSTAG_MAX_STRATA; ++i) stag->dof[i]    = 0;
458   for (i=0; i<DMSTAG_MAX_DIM;    ++i) stag->l[i]      = NULL;
459   stag->stencilType                                   = DMSTAG_STENCIL_NONE;
460   stag->stencilWidth                                  = 0;
461   for (i=0; i<DMSTAG_MAX_DIM;    ++i) stag->nRanks[i] = -1;
462   stag->coordinateDMType                              = NULL;
463 
464   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
465   if (dim != 1 && dim != 2 && dim != 3) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"DMSetDimension() must be called to set a dimension with value 1, 2, or 3");
466 
467   ierr = PetscMemzero(dm->ops,sizeof(*(dm->ops)));CHKERRQ(ierr);
468   dm->ops->createcoordinatedm  = DMCreateCoordinateDM_Stag;
469   dm->ops->createglobalvector  = DMCreateGlobalVector_Stag;
470   dm->ops->createinterpolation = NULL;
471   dm->ops->createlocalvector   = DMCreateLocalVector_Stag;
472   dm->ops->creatematrix        = DMCreateMatrix_Stag;
473   dm->ops->destroy             = DMDestroy_Stag;
474   dm->ops->getneighbors        = DMGetNeighbors_Stag;
475   dm->ops->globaltolocalbegin  = DMGlobalToLocalBegin_Stag;
476   dm->ops->globaltolocalend    = DMGlobalToLocalEnd_Stag;
477   dm->ops->localtoglobalbegin  = DMLocalToGlobalBegin_Stag;
478   dm->ops->localtoglobalend    = DMLocalToGlobalEnd_Stag;
479   dm->ops->setfromoptions      = DMSetFromOptions_Stag;
480   switch (dim) {
481     case 1: dm->ops->setup     = DMSetUp_Stag_1d; break;
482     case 2: dm->ops->setup     = DMSetUp_Stag_2d; break;
483     case 3: dm->ops->setup     = DMSetUp_Stag_3d; break;
484     default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported dimension %d",dim);
485   }
486   dm->ops->clone               = DMClone_Stag;
487   dm->ops->view                = DMView_Stag;
488   dm->ops->getcompatibility    = DMGetCompatibility_Stag;
489   PetscFunctionReturn(0);
490 }
491