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