Actual source code: stag.c

petsc-master 2019-07-16
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: /*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,&ltogmap);
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;

440:   stag->gton                                          = NULL;
441:   stag->gtol                                          = NULL;
442:   for (i=0; i<DMSTAG_MAX_STRATA; ++i) stag->dof[i]    = 0;
443:   for (i=0; i<DMSTAG_MAX_DIM;    ++i) stag->l[i]      = NULL;
444:   stag->stencilType                                   = DMSTAG_STENCIL_NONE;
445:   stag->stencilWidth                                  = 0;
446:   for (i=0; i<DMSTAG_MAX_DIM;    ++i) stag->nRanks[i] = -1;
447:   stag->coordinateDMType                              = NULL;

449:   DMGetDimension(dm,&dim);

451:   PetscMemzero(dm->ops,sizeof(*(dm->ops)));
452:   dm->ops->createcoordinatedm  = DMCreateCoordinateDM_Stag;
453:   dm->ops->createglobalvector  = DMCreateGlobalVector_Stag;
454:   dm->ops->createinterpolation = NULL;
455:   dm->ops->createlocalvector   = DMCreateLocalVector_Stag;
456:   dm->ops->creatematrix        = DMCreateMatrix_Stag;
457:   dm->ops->destroy             = DMDestroy_Stag;
458:   dm->ops->getneighbors        = DMGetNeighbors_Stag;
459:   dm->ops->globaltolocalbegin  = DMGlobalToLocalBegin_Stag;
460:   dm->ops->globaltolocalend    = DMGlobalToLocalEnd_Stag;
461:   dm->ops->localtoglobalbegin  = DMLocalToGlobalBegin_Stag;
462:   dm->ops->localtoglobalend    = DMLocalToGlobalEnd_Stag;
463:   dm->ops->setfromoptions      = DMSetFromOptions_Stag;
464:   switch (dim) {
465:     case 1: dm->ops->setup     = DMSetUp_Stag_1d; break;
466:     case 2: dm->ops->setup     = DMSetUp_Stag_2d; break;
467:     case 3: dm->ops->setup     = DMSetUp_Stag_3d; break;
468:     default : SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported dimension %d",dim);
469:   }
470:   dm->ops->view                = DMView_Stag;
471:   dm->ops->getcompatibility    = DMGetCompatibility_Stag;
472:   return(0);
473: }