Actual source code: stag.c

petsc-master 2019-12-15
Report Typos and Errors
  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,&ltogmap);
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: }