Actual source code: stag.c
petsc-3.11.4 2019-09-28
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 (and internal functions).
6: */
7: #include <petsc/private/dmstagimpl.h>
8: #include <petscsf.h>
10: /*MC
11: DMSTAG = "stag"
13: Level: intermediate
15: .seealso: DMType, DMCreate(), DMSetType()
16: M*/
18: static PetscErrorCode DMDestroy_Stag(DM dm)
19: {
21: DM_Stag *stag;
22: PetscInt i;
25: stag = (DM_Stag*)dm->data;
26: for (i=0; i<DMSTAG_MAX_DIM; ++i) {
27: if (stag->l[i]) {
28: PetscFree(stag->l[i]);
29: }
30: }
31: if (stag->gton) {VecScatterDestroy(&stag->gton);}
32: if (stag->gtol) {VecScatterDestroy(&stag->gtol);}
33: if (stag->neighbors) {PetscFree(stag->neighbors);}
34: if (stag->locationOffsets) {PetscFree(stag->locationOffsets);}
35: PetscFree(stag);
36: return(0);
37: }
39: static PetscErrorCode DMCreateGlobalVector_Stag(DM dm,Vec *vec)
40: {
41: PetscErrorCode ierr;
42: DM_Stag * const stag = (DM_Stag*)dm->data;
45: VecCreateMPI(PetscObjectComm((PetscObject)dm),stag->entries,PETSC_DECIDE,vec);
46: VecSetDM(*vec,dm);
47: /* Could set some ops, as DMDA does */
48: VecSetLocalToGlobalMapping(*vec,dm->ltogmap);
49: return(0);
50: }
52: static PetscErrorCode DMCreateLocalVector_Stag(DM dm,Vec *vec)
53: {
54: PetscErrorCode ierr;
55: DM_Stag * const stag = (DM_Stag*)dm->data;
58: VecCreateSeq(PETSC_COMM_SELF,stag->entriesGhost,vec);
59: VecSetBlockSize(*vec,stag->entriesPerElement);
60: VecSetDM(*vec,dm);
61: return(0);
62: }
64: static PetscErrorCode DMCreateMatrix_Stag(DM dm,Mat *mat)
65: {
66: PetscErrorCode ierr;
67: const DM_Stag * const stag = (DM_Stag*)dm->data;
68: MatType matType;
69: PetscBool isaij,isshell;
70: PetscInt width,nNeighbors,dim;
71: ISLocalToGlobalMapping ltogmap;
74: DMGetDimension(dm,&dim);
75: DMGetMatType(dm,&matType);
76: PetscStrcmp(matType,MATAIJ,&isaij);
77: PetscStrcmp(matType,MATSHELL,&isshell);
79: if (isaij) {
80: /* This implementation gives a very dense stencil, which is likely unsuitable for
81: real applications. */
82: switch (stag->stencilType) {
83: case DMSTAG_STENCIL_NONE:
84: nNeighbors = 1;
85: break;
86: case DMSTAG_STENCIL_STAR:
87: switch (dim) {
88: case 1 :
89: nNeighbors = 2*stag->stencilWidth + 1;
90: break;
91: case 2 :
92: nNeighbors = 4*stag->stencilWidth + 3;
93: break;
94: case 3 :
95: nNeighbors = 6*stag->stencilWidth + 5;
96: break;
97: default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported dimension %d",dim);
98: }
99: break;
100: case DMSTAG_STENCIL_BOX:
101: switch (dim) {
102: case 1 :
103: nNeighbors = (2*stag->stencilWidth + 1);
104: break;
105: case 2 :
106: nNeighbors = (2*stag->stencilWidth + 1) * (2*stag->stencilWidth + 1);
107: break;
108: case 3 :
109: nNeighbors = (2*stag->stencilWidth + 1) * (2*stag->stencilWidth + 1) * (2*stag->stencilWidth + 1);
110: break;
111: default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported dimension %d",dim);
112: }
113: break;
114: default : SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported stencil");
115: }
116: width = (stag->dof[0] + stag->dof[1] + stag->dof[2] + stag->dof[3]) * nNeighbors;
117: MatCreateAIJ(PETSC_COMM_WORLD,stag->entries,stag->entries,PETSC_DETERMINE,PETSC_DETERMINE,width,NULL,width,NULL,mat);
118: } else if (isshell) {
119: MatCreate(PetscObjectComm((PetscObject)dm),mat);
120: MatSetSizes(*mat,stag->entries,stag->entries,PETSC_DETERMINE,PETSC_DETERMINE);
121: MatSetType(*mat,MATSHELL);
122: MatSetUp(*mat);
123: } else SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not implemented for Mattype %s",matType);
125: DMGetLocalToGlobalMapping(dm,<ogmap);
126: MatSetLocalToGlobalMapping(*mat,ltogmap,ltogmap);
127: MatSetDM(*mat,dm);
128: return(0);
129: }
131: static PetscErrorCode DMGetCompatibility_Stag(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
132: {
133: PetscErrorCode ierr;
134: const DM_Stag * const stag = (DM_Stag*)dm->data;
135: const DM_Stag * const stag2 = (DM_Stag*)dm2->data;
136: PetscInt dim,dim2,i;
137: MPI_Comm comm;
138: PetscMPIInt sameComm;
139: DMType type2;
140: PetscBool sameType;
143: DMGetType(dm2,&type2);
144: PetscStrcmp(DMSTAG,type2,&sameType);
145: if (!sameType) {
146: PetscInfo1((PetscObject)dm,"DMStag compatibility check not implemented with DM of type %s\n",type2);
147: *set = PETSC_FALSE;
148: return(0);
149: }
151: PetscObjectGetComm((PetscObject)dm,&comm);
152: MPI_Comm_compare(comm,PetscObjectComm((PetscObject)dm2),&sameComm);
153: if (sameComm != MPI_IDENT) {
154: PetscInfo2((PetscObject)dm,"DMStag objects have different communicators: %d != %d\n",comm,PetscObjectComm((PetscObject)dm2));
155: *set = PETSC_FALSE;
156: return(0);
157: }
158: DMGetDimension(dm ,&dim );
159: DMGetDimension(dm2,&dim2);
160: if (dim != dim2) {
161: PetscInfo((PetscObject)dm,"DMStag objects have different dimensions");
162: *set = PETSC_TRUE;
163: *compatible = PETSC_FALSE;
164: return(0);
165: }
166: for (i=0; i<dim; ++i) {
167: if (stag->N[i] != stag2->N[i]) {
168: PetscInfo3((PetscObject)dm,"DMStag objects have different global numbers of elements in dimension %D: %D != %D\n",i,stag->n[i],stag2->n[i]);
169: *set = PETSC_TRUE;
170: *compatible = PETSC_FALSE;
171: return(0);
172: }
173: if (stag->n[i] != stag2->n[i]) {
174: PetscInfo3((PetscObject)dm,"DMStag objects have different local numbers of elements in dimension %D: %D != %D\n",i,stag->n[i],stag2->n[i]);
175: *set = PETSC_TRUE;
176: *compatible = PETSC_FALSE;
177: return(0);
178: }
179: if (stag->boundaryType[i] != stag2->boundaryType[i]) {
180: PetscInfo3((PetscObject)dm,"DMStag objects have different boundary types in dimension %d: %s != %s\n",i,stag->boundaryType[i],stag2->boundaryType[i]);
181: *set = PETSC_TRUE;
182: *compatible = PETSC_FALSE;
183: return(0);
184: }
185: }
186: /* Note: we include stencil type and width in the notion of compatibility, as this affects
187: the "atlas" (local subdomains). This might be irritating in legitimate cases
188: of wanting to transfer between two other-wise compatible DMs with different
189: stencil characteristics. */
190: if (stag->stencilType != stag2->stencilType) {
191: PetscInfo2((PetscObject)dm,"DMStag objects have different ghost stencil types: %s != %s\n",DMStagStencilTypes[stag->stencilType],DMStagStencilTypes[stag2->stencilType]);
192: *set = PETSC_TRUE;
193: *compatible = PETSC_FALSE;
194: return(0);
195: }
196: if (stag->stencilWidth != stag2->stencilWidth) {
197: PetscInfo2((PetscObject)dm,"DMStag objects have different ghost stencil widths: %D != %D\n",stag->stencilWidth,stag->stencilWidth);
198: *set = PETSC_TRUE;
199: *compatible = PETSC_FALSE;
200: return(0);
201: }
202: *set = PETSC_TRUE;
203: *compatible = PETSC_TRUE;
204: return(0);
205: }
208: /*
209: Note there are several orderings in play here.
210: 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).
211: Also in all cases, only subdomains which are the last in their dimension have partial elements.
213: 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.
214: 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.
215: 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.
216: */
218: static PetscErrorCode DMLocalToGlobalBegin_Stag(DM dm,Vec l,InsertMode mode,Vec g)
219: {
220: PetscErrorCode ierr;
221: DM_Stag * const stag = (DM_Stag*)dm->data;
222: PetscInt dim,d;
225: if (mode == ADD_VALUES) {
226: VecScatterBegin(stag->gtol,l,g,mode,SCATTER_REVERSE);
227: } else if (mode == INSERT_VALUES) {
228: DMGetDimension(dm,&dim);
229: for (d=0; d<dim; ++d) {
230: if (stag->nRanks[d] == 1 && stag->stencilWidth > 0 && stag->boundaryType[d] != DM_BOUNDARY_GHOSTED && stag->boundaryType[d] != DM_BOUNDARY_NONE) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Local to Global scattering with INSERT_VALUES is not supported for single rank in a direction with boundary conditions (e.g. periodic) inducing a non-injective local->global map. Either change the boundary conditions, use a stencil width of zero, or use more than one rank in the relevant direction (e.g. -stag_ranks_x 2)");
231: }
232: VecScatterBegin(stag->gtol,l,g,mode,SCATTER_REVERSE_LOCAL);
233: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unsupported InsertMode");
234: return(0);
235: }
237: static PetscErrorCode DMLocalToGlobalEnd_Stag(DM dm,Vec l,InsertMode mode,Vec g)
238: {
239: PetscErrorCode ierr;
240: DM_Stag * const stag = (DM_Stag*)dm->data;
243: if (mode == ADD_VALUES) {
244: VecScatterEnd(stag->gtol,l,g,mode,SCATTER_REVERSE);
245: } else if (mode == INSERT_VALUES) {
246: VecScatterEnd(stag->gtol,l,g,mode,SCATTER_REVERSE_LOCAL);
247: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unsupported InsertMode");
248: return(0);
249: }
251: static PetscErrorCode DMGlobalToLocalBegin_Stag(DM dm,Vec g,InsertMode mode,Vec l)
252: {
253: PetscErrorCode ierr;
254: DM_Stag * const stag = (DM_Stag*)dm->data;
257: VecScatterBegin(stag->gtol,g,l,mode,SCATTER_FORWARD);
258: return(0);
259: }
261: static PetscErrorCode DMGlobalToLocalEnd_Stag(DM dm,Vec g,InsertMode mode,Vec l)
262: {
263: PetscErrorCode ierr;
264: DM_Stag * const stag = (DM_Stag*)dm->data;
267: VecScatterEnd(stag->gtol,g,l,mode,SCATTER_FORWARD);
268: return(0);
269: }
271: /*
272: If a stratum is active (non-zero dof), make it active in the coordinate DM.
273: */
274: static PetscErrorCode DMCreateCoordinateDM_Stag(DM dm,DM *dmc)
275: {
276: PetscErrorCode ierr;
277: DM_Stag * const stag = (DM_Stag*)dm->data;
278: PetscInt dim;
279: PetscBool isstag,isproduct;
283: if (!stag->coordinateDMType) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Before creating a coordinate DM, a type must be specified with DMStagSetCoordinateDMType()");
285: DMGetDimension(dm,&dim);
286: PetscStrcmp(stag->coordinateDMType,DMSTAG,&isstag);
287: PetscStrcmp(stag->coordinateDMType,DMPRODUCT,&isproduct);
288: if (isstag) {
289: DMStagCreateCompatibleDMStag(dm,
290: stag->dof[0] > 0 ? dim : 0,
291: stag->dof[1] > 0 ? dim : 0,
292: stag->dof[2] > 0 ? dim : 0,
293: stag->dof[3] > 0 ? dim : 0,
294: dmc);
295: } else if (isproduct) {
296: DMCreate(PETSC_COMM_WORLD,dmc);
297: DMSetType(*dmc,DMPRODUCT);
298: DMSetDimension(*dmc,dim);
299: } else SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unsupported coordinate DM type %s",stag->coordinateDMType);
300: return(0);
301: }
303: static PetscErrorCode DMGetNeighbors_Stag(DM dm,PetscInt *nRanks,const PetscMPIInt *ranks[])
304: {
305: PetscErrorCode ierr;
306: DM_Stag * const stag = (DM_Stag*)dm->data;
307: PetscInt dim;
310: DMGetDimension(dm,&dim);
311: switch (dim) {
312: case 1: *nRanks = 3; break;
313: case 2: *nRanks = 9; break;
314: case 3: *nRanks = 27; break;
315: default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Get neighbors not implemented for dim = %D",dim);
316: }
317: *ranks = stag->neighbors;
318: return(0);
319: }
321: static PetscErrorCode DMView_Stag(DM dm,PetscViewer viewer)
322: {
323: PetscErrorCode ierr;
324: DM_Stag * const stag = (DM_Stag*)dm->data;
325: PetscBool isascii,viewAllRanks;
326: PetscMPIInt rank,size;
327: PetscInt dim,maxRanksToView,i;
330: MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);
331: MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
332: DMGetDimension(dm,&dim);
333: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
334: if (isascii) {
335: PetscViewerASCIIPrintf(viewer,"Dimension: %D\n",dim);
336: switch (dim) {
337: case 1:
338: PetscViewerASCIIPrintf(viewer,"Global size: %D\n",stag->N[0]);
339: break;
340: case 2:
341: PetscViewerASCIIPrintf(viewer,"Global sizes: %D x %D\n",stag->N[0],stag->N[1]);
342: PetscViewerASCIIPrintf(viewer,"Parallel decomposition: %D x %D ranks\n",stag->nRanks[0],stag->nRanks[1]);
343: break;
344: case 3:
345: PetscViewerASCIIPrintf(viewer,"Global sizes: %D x %D x %D\n",stag->N[0],stag->N[1],stag->N[2]);
346: PetscViewerASCIIPrintf(viewer,"Parallel decomposition: %D x %D x %D ranks\n",stag->nRanks[0],stag->nRanks[1],stag->nRanks[2]);
347: break;
348: default: SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"not implemented for dim==%D",dim);
349: }
350: PetscViewerASCIIPrintf(viewer,"Boundary ghosting:");
351: for (i=0; i<dim; ++i) {
352: PetscViewerASCIIPrintf(viewer," %s",DMBoundaryTypes[stag->boundaryType[i]]);
353: }
354: PetscViewerASCIIPrintf(viewer,"\n");
355: PetscViewerASCIIPrintf(viewer,"Elementwise ghost stencil: %s, width %D\n",DMStagStencilTypes[stag->stencilType],stag->stencilWidth);
356: PetscViewerASCIIPrintf(viewer,"Stratum dof:");
357: for (i=0; i<dim+1; ++i) {
358: PetscViewerASCIIPrintf(viewer," %D:%D",i,stag->dof[i]);
359: }
360: PetscViewerASCIIPrintf(viewer,"\n");
361: if(dm->coordinateDM) {
362: PetscViewerASCIIPrintf(viewer,"Has coordinate DM\n");
363: }
364: maxRanksToView = 16;
365: viewAllRanks = (PetscBool)(size <= maxRanksToView);
366: if (viewAllRanks) {
367: PetscViewerASCIIPushSynchronized(viewer);
368: switch (dim) {
369: case 1:
370: PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Local elements : %D (%D with ghosts)\n",rank,stag->n[0],stag->nGhost[0]);
371: break;
372: case 2:
373: PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Rank coordinates (%d,%d)\n",rank,stag->rank[0],stag->rank[1]);
374: 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]);
375: break;
376: case 3:
377: PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Rank coordinates (%d,%d,%d)\n",rank,stag->rank[0],stag->rank[1],stag->rank[2]);
378: 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]);
379: break;
380: default: SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"not implemented for dim==%D",dim);
381: }
382: PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Local native entries: %d\n",rank,stag->entries );
383: PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Local entries total : %d\n",rank,stag->entriesGhost);
384: PetscViewerFlush(viewer);
385: PetscViewerASCIIPopSynchronized(viewer);
386: } else {
387: PetscViewerASCIIPrintf(viewer,"(Per-rank information omitted since >%D ranks used)\n",maxRanksToView);
388: }
389: }
390: return(0);
391: }
393: static PetscErrorCode DMSetFromOptions_Stag(PetscOptionItems *PetscOptionsObject,DM dm)
394: {
395: PetscErrorCode ierr;
396: DM_Stag * const stag = (DM_Stag*)dm->data;
397: PetscInt dim;
400: DMGetDimension(dm,&dim);
401: PetscOptionsHead(PetscOptionsObject,"DMStag Options");
402: PetscOptionsInt("-stag_grid_x","Number of grid points in x direction","DMStagSetGlobalSizes",stag->N[0],&stag->N[0],NULL);
403: if (dim > 1) { PetscOptionsInt("-stag_grid_y","Number of grid points in y direction","DMStagSetGlobalSizes",stag->N[1],&stag->N[1],NULL); }
404: if (dim > 2) { PetscOptionsInt("-stag_grid_z","Number of grid points in z direction","DMStagSetGlobalSizes",stag->N[2],&stag->N[2],NULL); }
405: PetscOptionsInt("-stag_ranks_x","Number of ranks in x direction","DMStagSetNumRanks",stag->nRanks[0],&stag->nRanks[0],NULL);
406: if (dim > 1) { PetscOptionsInt("-stag_ranks_y","Number of ranks in y direction","DMStagSetNumRanks",stag->nRanks[1],&stag->nRanks[1],NULL); }
407: if (dim > 2) { PetscOptionsInt("-stag_ranks_z","Number of ranks in z direction","DMStagSetNumRanks",stag->nRanks[2],&stag->nRanks[2],NULL); }
408: PetscOptionsInt("-stag_stencil_width","Elementwise stencil width","DMStagSetStencilWidth",stag->stencilWidth,&stag->stencilWidth,NULL);
409: PetscOptionsEnum("-stag_stencil_type","Elementwise stencil stype","DMStagSetStencilType",DMStagStencilTypes,(PetscEnum)stag->stencilType,(PetscEnum*)&stag->stencilType,NULL);
410: PetscOptionsEnum("-stag_boundary_type_x","Treatment of (physical) boundaries in x direction","DMStagSetBoundaryTypes",DMBoundaryTypes,(PetscEnum)stag->boundaryType[0],(PetscEnum*)&stag->boundaryType[0],NULL);
411: PetscOptionsEnum("-stag_boundary_type_y","Treatment of (physical) boundaries in y direction","DMStagSetBoundaryTypes",DMBoundaryTypes,(PetscEnum)stag->boundaryType[1],(PetscEnum*)&stag->boundaryType[1],NULL);
412: PetscOptionsEnum("-stag_boundary_type_z","Treatment of (physical) boundaries in z direction","DMStagSetBoundaryTypes",DMBoundaryTypes,(PetscEnum)stag->boundaryType[2],(PetscEnum*)&stag->boundaryType[2],NULL);
413: PetscOptionsInt("-stag_dof_0","Number of dof per 0-cell (vertex/corner)","DMStagSetDOF",stag->dof[0],&stag->dof[0],NULL);
414: PetscOptionsInt("-stag_dof_1","Number of dof per 1-cell (edge)", "DMStagSetDOF",stag->dof[1],&stag->dof[1],NULL);
415: PetscOptionsInt("-stag_dof_2","Number of dof per 2-cell (face)", "DMStagSetDOF",stag->dof[2],&stag->dof[2],NULL);
416: PetscOptionsInt("-stag_dof_3","Number of dof per 3-cell (hexahedron)", "DMStagSetDOF",stag->dof[3],&stag->dof[3],NULL);
417: PetscOptionsTail();
418: return(0);
419: }
421: /*MC
422: DMSTAG = "stag" - A DM object, similar to DMDA, representing a "staggered grid" or a structured cell complex.
424: Level: beginner
426: .seealso: DM, DMPRODUCT, DMDA, DMPLEX, DMStagCreate1d(), DMStagCreate2d(), DMStagCreate3d()
427: M*/
429: PETSC_EXTERN PetscErrorCode DMCreate_Stag(DM dm)
430: {
432: DM_Stag *stag;
433: PetscInt i,dim;
437: PetscNewLog(dm,&stag);
438: dm->data = stag;
439: PetscObjectChangeTypeName((PetscObject)dm,DMSTAG);
441: stag->gton = NULL;
442: stag->gtol = NULL;
443: for (i=0; i<DMSTAG_MAX_STRATA; ++i) stag->dof[i] = 0;
444: for (i=0; i<DMSTAG_MAX_DIM; ++i) stag->l[i] = NULL;
445: stag->stencilType = DMSTAG_STENCIL_NONE;
446: stag->stencilWidth = 0;
447: for (i=0; i<DMSTAG_MAX_DIM; ++i) stag->nRanks[i] = -1;
448: stag->coordinateDMType = NULL;
450: DMGetDimension(dm,&dim);
452: PetscMemzero(dm->ops,sizeof(*(dm->ops)));
453: dm->ops->createcoordinatedm = DMCreateCoordinateDM_Stag;
454: dm->ops->createglobalvector = DMCreateGlobalVector_Stag;
455: dm->ops->createinterpolation = NULL;
456: dm->ops->createlocalvector = DMCreateLocalVector_Stag;
457: dm->ops->creatematrix = DMCreateMatrix_Stag;
458: dm->ops->destroy = DMDestroy_Stag;
459: dm->ops->getneighbors = DMGetNeighbors_Stag;
460: dm->ops->globaltolocalbegin = DMGlobalToLocalBegin_Stag;
461: dm->ops->globaltolocalend = DMGlobalToLocalEnd_Stag;
462: dm->ops->localtoglobalbegin = DMLocalToGlobalBegin_Stag;
463: dm->ops->localtoglobalend = DMLocalToGlobalEnd_Stag;
464: dm->ops->setfromoptions = DMSetFromOptions_Stag;
465: switch (dim) {
466: case 1: dm->ops->setup = DMSetUp_Stag_1d; break;
467: case 2: dm->ops->setup = DMSetUp_Stag_2d; break;
468: case 3: dm->ops->setup = DMSetUp_Stag_3d; break;
469: default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported dimension %d",dim);
470: }
471: dm->ops->view = DMView_Stag;
472: dm->ops->getcompatibility = DMGetCompatibility_Stag;
473: return(0);
474: }