Actual source code: plexglvis.c

  1: #include <petsc/private/glvisviewerimpl.h>
  2: #include <petsc/private/petscimpl.h>
  3: #include <petsc/private/dmpleximpl.h>
  4: #include <petscbt.h>
  5: #include <petscdmplex.h>
  6: #include <petscsf.h>
  7: #include <petscds.h>

  9: typedef struct {
 10:   PetscInt   nf;
 11:   VecScatter *scctx;
 12: } GLVisViewerCtx;

 14: static PetscErrorCode DestroyGLVisViewerCtx_Private(void *vctx)
 15: {
 16:   GLVisViewerCtx *ctx = (GLVisViewerCtx*)vctx;
 17:   PetscInt       i;

 19:   for (i=0;i<ctx->nf;i++) {
 20:     VecScatterDestroy(&ctx->scctx[i]);
 21:   }
 22:   PetscFree(ctx->scctx);
 23:   PetscFree(vctx);
 24:   return 0;
 25: }

 27: static PetscErrorCode DMPlexSampleGLVisFields_Private(PetscObject oX, PetscInt nf, PetscObject oXfield[], void *vctx)
 28: {
 29:   GLVisViewerCtx *ctx = (GLVisViewerCtx*)vctx;
 30:   PetscInt       f;

 32:   for (f=0;f<nf;f++) {
 33:     VecScatterBegin(ctx->scctx[f],(Vec)oX,(Vec)oXfield[f],INSERT_VALUES,SCATTER_FORWARD);
 34:     VecScatterEnd(ctx->scctx[f],(Vec)oX,(Vec)oXfield[f],INSERT_VALUES,SCATTER_FORWARD);
 35:   }
 36:   return 0;
 37: }

 39: /* for FEM, it works for H1 fields only and extracts dofs at cell vertices, discarding any other dof */
 40: PetscErrorCode DMSetUpGLVisViewer_Plex(PetscObject odm, PetscViewer viewer)
 41: {
 42:   DM             dm = (DM)odm;
 43:   Vec            xlocal,xfield,*Ufield;
 44:   PetscDS        ds;
 45:   IS             globalNum,isfield;
 46:   PetscBT        vown;
 47:   char           **fieldname = NULL,**fec_type = NULL;
 48:   const PetscInt *gNum;
 49:   PetscInt       *nlocal,*bs,*idxs,*dims;
 50:   PetscInt       f,maxfields,nfields,c,totc,totdofs,Nv,cum,i;
 51:   PetscInt       dim,cStart,cEnd,vStart,vEnd;
 52:   GLVisViewerCtx *ctx;
 53:   PetscSection   s;

 55:   DMGetDimension(dm,&dim);
 56:   DMPlexGetDepthStratum(dm,0,&vStart,&vEnd);
 57:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
 58:   PetscObjectQuery((PetscObject)dm,"_glvis_plex_gnum",(PetscObject*)&globalNum);
 59:   if (!globalNum) {
 60:     DMPlexCreateCellNumbering_Internal(dm,PETSC_TRUE,&globalNum);
 61:     PetscObjectCompose((PetscObject)dm,"_glvis_plex_gnum",(PetscObject)globalNum);
 62:     PetscObjectDereference((PetscObject)globalNum);
 63:   }
 64:   ISGetIndices(globalNum,&gNum);
 65:   PetscBTCreate(vEnd-vStart,&vown);
 66:   for (c = cStart, totc = 0; c < cEnd; c++) {
 67:     if (gNum[c-cStart] >= 0) {
 68:       PetscInt i,numPoints,*points = NULL;

 70:       totc++;
 71:       DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&numPoints,&points);
 72:       for (i=0;i<numPoints*2;i+= 2) {
 73:         if ((points[i] >= vStart) && (points[i] < vEnd)) {
 74:           PetscBTSet(vown,points[i]-vStart);
 75:         }
 76:       }
 77:       DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&numPoints,&points);
 78:     }
 79:   }
 80:   for (f=0,Nv=0;f<vEnd-vStart;f++) if (PetscLikely(PetscBTLookup(vown,f))) Nv++;

 82:   DMCreateLocalVector(dm,&xlocal);
 83:   VecGetLocalSize(xlocal,&totdofs);
 84:   DMGetLocalSection(dm,&s);
 85:   PetscSectionGetNumFields(s,&nfields);
 86:   for (f=0,maxfields=0;f<nfields;f++) {
 87:     PetscInt bs;

 89:     PetscSectionGetFieldComponents(s,f,&bs);
 90:     maxfields += bs;
 91:   }
 92:   PetscCalloc7(maxfields,&fieldname,maxfields,&nlocal,maxfields,&bs,maxfields,&dims,maxfields,&fec_type,totdofs,&idxs,maxfields,&Ufield);
 93:   PetscNew(&ctx);
 94:   PetscCalloc1(maxfields,&ctx->scctx);
 95:   DMGetDS(dm,&ds);
 96:   if (ds) {
 97:     for (f=0;f<nfields;f++) {
 98:       const char* fname;
 99:       char        name[256];
100:       PetscObject disc;
101:       size_t      len;

103:       PetscSectionGetFieldName(s,f,&fname);
104:       PetscStrlen(fname,&len);
105:       if (len) {
106:         PetscStrcpy(name,fname);
107:       } else {
108:         PetscSNPrintf(name,256,"Field%D",f);
109:       }
110:       PetscDSGetDiscretization(ds,f,&disc);
111:       if (disc) {
112:         PetscClassId id;
113:         PetscInt     Nc;
114:         char         fec[64];

116:         PetscObjectGetClassId(disc, &id);
117:         if (id == PETSCFE_CLASSID) {
118:           PetscFE            fem = (PetscFE)disc;
119:           PetscDualSpace     sp;
120:           PetscDualSpaceType spname;
121:           PetscInt           order;
122:           PetscBool          islag,continuous,H1 = PETSC_TRUE;

124:           PetscFEGetNumComponents(fem,&Nc);
125:           PetscFEGetDualSpace(fem,&sp);
126:           PetscDualSpaceGetType(sp,&spname);
127:           PetscStrcmp(spname,PETSCDUALSPACELAGRANGE,&islag);
129:           PetscDualSpaceLagrangeGetContinuity(sp,&continuous);
130:           PetscDualSpaceGetOrder(sp,&order);
131:           if (continuous && order > 0) { /* no support for high-order viz, still have to figure out the numbering */
132:             PetscSNPrintf(fec,64,"FiniteElementCollection: H1_%DD_P1",dim);
133:           } else {
135:             H1   = PETSC_FALSE;
136:             PetscSNPrintf(fec,64,"FiniteElementCollection: L2_%DD_P%D",dim,order);
137:           }
138:           PetscStrallocpy(name,&fieldname[ctx->nf]);
139:           bs[ctx->nf]   = Nc;
140:           dims[ctx->nf] = dim;
141:           if (H1) {
142:             nlocal[ctx->nf] = Nc * Nv;
143:             PetscStrallocpy(fec,&fec_type[ctx->nf]);
144:             VecCreateSeq(PETSC_COMM_SELF,Nv*Nc,&xfield);
145:             for (i=0,cum=0;i<vEnd-vStart;i++) {
146:               PetscInt j,off;

148:               if (PetscUnlikely(!PetscBTLookup(vown,i))) continue;
149:               PetscSectionGetFieldOffset(s,i+vStart,f,&off);
150:               for (j=0;j<Nc;j++) idxs[cum++] = off + j;
151:             }
152:             ISCreateGeneral(PetscObjectComm((PetscObject)xlocal),Nv*Nc,idxs,PETSC_USE_POINTER,&isfield);
153:           } else {
154:             nlocal[ctx->nf] = Nc * totc;
155:             PetscStrallocpy(fec,&fec_type[ctx->nf]);
156:             VecCreateSeq(PETSC_COMM_SELF,Nc*totc,&xfield);
157:             for (i=0,cum=0;i<cEnd-cStart;i++) {
158:               PetscInt j,off;

160:               if (PetscUnlikely(gNum[i] < 0)) continue;
161:               PetscSectionGetFieldOffset(s,i+cStart,f,&off);
162:               for (j=0;j<Nc;j++) idxs[cum++] = off + j;
163:             }
164:             ISCreateGeneral(PetscObjectComm((PetscObject)xlocal),totc*Nc,idxs,PETSC_USE_POINTER,&isfield);
165:           }
166:           VecScatterCreate(xlocal,isfield,xfield,NULL,&ctx->scctx[ctx->nf]);
167:           VecDestroy(&xfield);
168:           ISDestroy(&isfield);
169:           ctx->nf++;
170:         } else if (id == PETSCFV_CLASSID) {
171:           PetscInt c;

173:           PetscFVGetNumComponents((PetscFV)disc,&Nc);
174:           PetscSNPrintf(fec,64,"FiniteElementCollection: L2_%DD_P0",dim);
175:           for (c = 0; c < Nc; c++) {
176:             char comp[256];
177:             PetscSNPrintf(comp,256,"%s-Comp%D",name,c);
178:             PetscStrallocpy(comp,&fieldname[ctx->nf]);
179:             bs[ctx->nf] = 1; /* Does PetscFV support components with different block size? */
180:             nlocal[ctx->nf] = totc;
181:             dims[ctx->nf] = dim;
182:             PetscStrallocpy(fec,&fec_type[ctx->nf]);
183:             VecCreateSeq(PETSC_COMM_SELF,totc,&xfield);
184:             for (i=0,cum=0;i<cEnd-cStart;i++) {
185:               PetscInt off;

187:               if (PetscUnlikely(gNum[i])<0) continue;
188:               PetscSectionGetFieldOffset(s,i+cStart,f,&off);
189:               idxs[cum++] = off + c;
190:             }
191:             ISCreateGeneral(PetscObjectComm((PetscObject)xlocal),totc,idxs,PETSC_USE_POINTER,&isfield);
192:             VecScatterCreate(xlocal,isfield,xfield,NULL,&ctx->scctx[ctx->nf]);
193:             VecDestroy(&xfield);
194:             ISDestroy(&isfield);
195:             ctx->nf++;
196:           }
197:         } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",f);
198:       } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing discretization for field %D",f);
199:     }
200:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Needs a DS attached to the DM");
201:   PetscBTDestroy(&vown);
202:   VecDestroy(&xlocal);
203:   ISRestoreIndices(globalNum,&gNum);

205:   /* create work vectors */
206:   for (f=0;f<ctx->nf;f++) {
207:     VecCreateMPI(PetscObjectComm((PetscObject)dm),nlocal[f],PETSC_DECIDE,&Ufield[f]);
208:     PetscObjectSetName((PetscObject)Ufield[f],fieldname[f]);
209:     VecSetBlockSize(Ufield[f],bs[f]);
210:     VecSetDM(Ufield[f],dm);
211:   }

213:   /* customize the viewer */
214:   PetscViewerGLVisSetFields(viewer,ctx->nf,(const char**)fec_type,dims,DMPlexSampleGLVisFields_Private,(PetscObject*)Ufield,ctx,DestroyGLVisViewerCtx_Private);
215:   for (f=0;f<ctx->nf;f++) {
216:     PetscFree(fieldname[f]);
217:     PetscFree(fec_type[f]);
218:     VecDestroy(&Ufield[f]);
219:   }
220:   PetscFree7(fieldname,nlocal,bs,dims,fec_type,idxs,Ufield);
221:   return 0;
222: }

224: typedef enum {MFEM_POINT=0,MFEM_SEGMENT,MFEM_TRIANGLE,MFEM_SQUARE,MFEM_TETRAHEDRON,MFEM_CUBE,MFEM_PRISM,MFEM_UNDEF} MFEM_cid;

226: MFEM_cid mfem_table_cid[4][7]       = { {MFEM_POINT,MFEM_UNDEF,MFEM_UNDEF  ,MFEM_UNDEF   ,MFEM_UNDEF      ,MFEM_UNDEF,MFEM_UNDEF},
227:                                         {MFEM_POINT,MFEM_UNDEF,MFEM_SEGMENT,MFEM_UNDEF   ,MFEM_UNDEF      ,MFEM_UNDEF,MFEM_UNDEF},
228:                                         {MFEM_POINT,MFEM_UNDEF,MFEM_SEGMENT,MFEM_TRIANGLE,MFEM_SQUARE     ,MFEM_UNDEF,MFEM_UNDEF},
229:                                         {MFEM_POINT,MFEM_UNDEF,MFEM_SEGMENT,MFEM_UNDEF   ,MFEM_TETRAHEDRON,MFEM_PRISM,MFEM_CUBE } };

231: MFEM_cid mfem_table_cid_unint[4][9] = { {MFEM_POINT,MFEM_UNDEF,MFEM_UNDEF  ,MFEM_UNDEF   ,MFEM_UNDEF      ,MFEM_UNDEF,MFEM_PRISM,MFEM_UNDEF,MFEM_UNDEF},
232:                                         {MFEM_POINT,MFEM_UNDEF,MFEM_SEGMENT,MFEM_UNDEF   ,MFEM_UNDEF      ,MFEM_UNDEF,MFEM_PRISM,MFEM_UNDEF,MFEM_UNDEF},
233:                                         {MFEM_POINT,MFEM_UNDEF,MFEM_SEGMENT,MFEM_TRIANGLE,MFEM_SQUARE     ,MFEM_UNDEF,MFEM_PRISM,MFEM_UNDEF,MFEM_UNDEF},
234:                                         {MFEM_POINT,MFEM_UNDEF,MFEM_SEGMENT,MFEM_UNDEF   ,MFEM_TETRAHEDRON,MFEM_UNDEF,MFEM_PRISM,MFEM_UNDEF,MFEM_CUBE } };

236: static PetscErrorCode DMPlexGetPointMFEMCellID_Internal(DM dm, DMLabel label, PetscInt minl, PetscInt p, PetscInt *mid, PetscInt *cid)
237: {
238:   DMLabel        dlabel;
239:   PetscInt       depth,csize,pdepth,dim;

241:   DMPlexGetDepthLabel(dm,&dlabel);
242:   DMLabelGetValue(dlabel,p,&pdepth);
243:   DMPlexGetConeSize(dm,p,&csize);
244:   DMPlexGetDepth(dm,&depth);
245:   DMGetDimension(dm,&dim);
246:   if (label) {
247:     DMLabelGetValue(label,p,mid);
248:     *mid = *mid - minl + 1; /* MFEM does not like negative markers */
249:   } else *mid = 1;
250:   if (depth >=0 && dim != depth) { /* not interpolated, it assumes cell-vertex mesh */
254:     *cid = mfem_table_cid_unint[dim][csize];
255:   } else {
258:     *cid = mfem_table_cid[pdepth][csize];
259:   }
260:   return 0;
261: }

263: static PetscErrorCode DMPlexGetPointMFEMVertexIDs_Internal(DM dm, PetscInt p, PetscSection csec, PetscInt *nv, PetscInt vids[])
264: {
265:   PetscInt       dim,sdim,dof = 0,off = 0,i,q,vStart,vEnd,numPoints,*points = NULL;

267:   DMPlexGetDepthStratum(dm,0,&vStart,&vEnd);
268:   DMGetDimension(dm,&dim);
269:   sdim = dim;
270:   if (csec) {
271:     PetscInt sStart,sEnd;

273:     DMGetCoordinateDim(dm,&sdim);
274:     PetscSectionGetChart(csec,&sStart,&sEnd);
275:     PetscSectionGetOffset(csec,vStart,&off);
276:     off  = off/sdim;
277:     if (p >= sStart && p < sEnd) {
278:       PetscSectionGetDof(csec,p,&dof);
279:     }
280:   }
281:   if (!dof) {
282:     DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&numPoints,&points);
283:     for (i=0,q=0;i<numPoints*2;i+= 2)
284:       if ((points[i] >= vStart) && (points[i] < vEnd))
285:         vids[q++] = points[i]-vStart+off;
286:     DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&numPoints,&points);
287:   } else {
288:     PetscSectionGetOffset(csec,p,&off);
289:     PetscSectionGetDof(csec,p,&dof);
290:     for (q=0;q<dof/sdim;q++) vids[q] = off/sdim + q;
291:   }
292:   *nv = q;
293:   return 0;
294: }

296: static PetscErrorCode GLVisCreateFE(PetscFE femIn,char name[32],PetscFE *fem)
297: {
298:   DM              K;
299:   PetscSpace      P;
300:   PetscDualSpace  Q;
301:   PetscQuadrature q,fq;
302:   PetscInt        dim,deg,dof;
303:   DMPolytopeType  ptype;
304:   PetscBool       isSimplex,isTensor;
305:   PetscBool       continuity = PETSC_FALSE;
306:   PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
307:   PetscBool       endpoint   = PETSC_TRUE;
308:   MPI_Comm        comm;

310:   PetscObjectGetComm((PetscObject)femIn, &comm);
311:   PetscFEGetBasisSpace(femIn,&P);
312:   PetscFEGetDualSpace(femIn,&Q);
313:   PetscDualSpaceGetDM(Q,&K);
314:   DMGetDimension(K,&dim);
315:   PetscSpaceGetDegree(P,&deg,NULL);
316:   PetscSpaceGetNumComponents(P,&dof);
317:   DMPlexGetCellType(K,0,&ptype);
318:   switch (ptype) {
319:   case DM_POLYTOPE_QUADRILATERAL:
320:   case DM_POLYTOPE_HEXAHEDRON:
321:     isSimplex = PETSC_FALSE; break;
322:   default:
323:     isSimplex = PETSC_TRUE; break;
324:   }
325:   isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
326:   /* Create space */
327:   PetscSpaceCreate(comm,&P);
328:   PetscSpaceSetType(P,PETSCSPACEPOLYNOMIAL);
329:   PetscSpacePolynomialSetTensor(P,isTensor);
330:   PetscSpaceSetNumComponents(P,dof);
331:   PetscSpaceSetNumVariables(P,dim);
332:   PetscSpaceSetDegree(P,deg,PETSC_DETERMINE);
333:   PetscSpaceSetUp(P);
334:   /* Create dual space */
335:   PetscDualSpaceCreate(comm,&Q);
336:   PetscDualSpaceSetType(Q,PETSCDUALSPACELAGRANGE);
337:   PetscDualSpaceLagrangeSetTensor(Q,isTensor);
338:   PetscDualSpaceLagrangeSetContinuity(Q,continuity);
339:   PetscDualSpaceLagrangeSetNodeType(Q,nodeType,endpoint,0);
340:   PetscDualSpaceSetNumComponents(Q,dof);
341:   PetscDualSpaceSetOrder(Q,deg);
342:   DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K);
343:   PetscDualSpaceSetDM(Q,K);
344:   DMDestroy(&K);
345:   PetscDualSpaceSetUp(Q);
346:   /* Create quadrature */
347:   if (isSimplex) {
348:     PetscDTStroudConicalQuadrature(dim,  1,deg+1,-1,+1,&q);
349:     PetscDTStroudConicalQuadrature(dim-1,1,deg+1,-1,+1,&fq);
350:   } else {
351:     PetscDTGaussTensorQuadrature(dim,  1,deg+1,-1,+1,&q);
352:     PetscDTGaussTensorQuadrature(dim-1,1,deg+1,-1,+1,&fq);
353:   }
354:   /* Create finite element */
355:   PetscFECreate(comm,fem);
356:   PetscSNPrintf(name,32,"L2_T1_%DD_P%D",dim,deg);
357:   PetscObjectSetName((PetscObject)*fem,name);
358:   PetscFESetType(*fem,PETSCFEBASIC);
359:   PetscFESetNumComponents(*fem,dof);
360:   PetscFESetBasisSpace(*fem,P);
361:   PetscFESetDualSpace(*fem,Q);
362:   PetscFESetQuadrature(*fem,q);
363:   PetscFESetFaceQuadrature(*fem,fq);
364:   PetscFESetUp(*fem);
365:   /* Cleanup */
366:   PetscSpaceDestroy(&P);
367:   PetscDualSpaceDestroy(&Q);
368:   PetscQuadratureDestroy(&q);
369:   PetscQuadratureDestroy(&fq);
370:   return 0;
371: }

373: /*
374:    ASCII visualization/dump: full support for simplices and tensor product cells. It supports AMR
375:    Higher order meshes are also supported
376: */
377: static PetscErrorCode DMPlexView_GLVis_ASCII(DM dm, PetscViewer viewer)
378: {
379:   DMLabel              label;
380:   PetscSection         coordSection,parentSection;
381:   Vec                  coordinates,hovec;
382:   const PetscScalar    *array;
383:   PetscInt             bf,p,sdim,dim,depth,novl,minl;
384:   PetscInt             cStart,cEnd,vStart,vEnd,nvert;
385:   PetscMPIInt          size;
386:   PetscBool            localized,isascii;
387:   PetscBool            enable_mfem,enable_boundary,enable_ncmesh,view_ovl = PETSC_FALSE;
388:   PetscBT              pown,vown;
389:   PetscErrorCode       ierr;
390:   PetscContainer       glvis_container;
391:   PetscBool            cellvertex = PETSC_FALSE, periodic, enabled = PETSC_TRUE;
392:   PetscBool            enable_emark,enable_bmark;
393:   const char           *fmt;
394:   char                 emark[64] = "",bmark[64] = "";

398:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
400:   MPI_Comm_size(PetscObjectComm((PetscObject)viewer),&size);
402:   DMGetDimension(dm,&dim);

404:   /* get container: determines if a process visualizes is portion of the data or not */
405:   PetscObjectQuery((PetscObject)viewer,"_glvis_info_container",(PetscObject*)&glvis_container);
407:   {
408:     PetscViewerGLVisInfo glvis_info;
409:     PetscContainerGetPointer(glvis_container,(void**)&glvis_info);
410:     enabled = glvis_info->enabled;
411:     fmt     = glvis_info->fmt;
412:   }

414:   /* Users can attach a coordinate vector to the DM in case they have a higher-order mesh
415:      DMPlex does not currently support HO meshes, so there's no API for this */
416:   PetscObjectQuery((PetscObject)dm,"_glvis_mesh_coords",(PetscObject*)&hovec);
417:   PetscObjectReference((PetscObject)hovec);
418:   if (!hovec) {
419:     DM           cdm;
420:     PetscFE      disc;
421:     PetscClassId classid;

423:     DMGetCoordinateDM(dm,&cdm);
424:     DMGetField(cdm,0,NULL,(PetscObject*)&disc);
425:     PetscObjectGetClassId((PetscObject)disc,&classid);
426:     if (classid == PETSCFE_CLASSID) {
427:       DM      hocdm;
428:       PetscFE hodisc;
429:       Vec     vec;
430:       Mat     mat;
431:       char    name[32],fec_type[64];

433:       GLVisCreateFE(disc,name,&hodisc);
434:       DMClone(cdm,&hocdm);
435:       DMSetField(hocdm,0,NULL,(PetscObject)hodisc);
436:       PetscFEDestroy(&hodisc);
437:       DMCreateDS(hocdm);

439:       DMGetCoordinates(dm,&vec);
440:       DMCreateGlobalVector(hocdm,&hovec);
441:       DMCreateInterpolation(cdm,hocdm,&mat,NULL);
442:       MatInterpolate(mat,vec,hovec);
443:       MatDestroy(&mat);
444:       DMDestroy(&hocdm);

446:       PetscSNPrintf(fec_type,sizeof(fec_type),"FiniteElementCollection: %s", name);
447:       PetscObjectSetName((PetscObject)hovec,fec_type);
448:     }
449:   }

451:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
452:   DMPlexGetGhostCellStratum(dm,&p,NULL);
453:   if (p >= 0) cEnd = p;
454:   DMPlexGetDepthStratum(dm,0,&vStart,&vEnd);
455:   DMGetPeriodicity(dm,&periodic,NULL,NULL,NULL);
456:   DMGetCoordinatesLocalized(dm,&localized);
458:   DMGetCoordinateSection(dm,&coordSection);
459:   DMGetCoordinateDim(dm,&sdim);
460:   DMGetCoordinatesLocal(dm,&coordinates);

463:   /*
464:      a couple of sections of the mesh specification are disabled
465:        - boundary: the boundary is not needed for proper mesh visualization unless we want to visualize boundary attributes or we have high-order coordinates in 3D (topologically)
466:        - vertex_parents: used for non-conforming meshes only when we want to use MFEM as a discretization package
467:                          and be able to derefine the mesh (MFEM does not currently have to ability to read ncmeshes in parallel)
468:   */
469:   enable_boundary = PETSC_FALSE;
470:   enable_ncmesh   = PETSC_FALSE;
471:   enable_mfem     = PETSC_FALSE;
472:   enable_emark    = PETSC_FALSE;
473:   enable_bmark    = PETSC_FALSE;
474:   /* I'm tired of problems with negative values in the markers, disable them */
475:   PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"GLVis PetscViewer DMPlex Options","PetscViewer");
476:   PetscOptionsBool("-viewer_glvis_dm_plex_enable_boundary","Enable boundary section in mesh representation",NULL,enable_boundary,&enable_boundary,NULL);
477:   PetscOptionsBool("-viewer_glvis_dm_plex_enable_ncmesh","Enable vertex_parents section in mesh representation (allows derefinement)",NULL,enable_ncmesh,&enable_ncmesh,NULL);
478:   PetscOptionsBool("-viewer_glvis_dm_plex_enable_mfem","Dump a mesh that can be used with MFEM's FiniteElementSpaces",NULL,enable_mfem,&enable_mfem,NULL);
479:   PetscOptionsBool("-viewer_glvis_dm_plex_overlap","Include overlap region in local meshes",NULL,view_ovl,&view_ovl,NULL);
480:   PetscOptionsString("-viewer_glvis_dm_plex_emarker","String for the material id label",NULL,emark,emark,sizeof(emark),&enable_emark);
481:   PetscOptionsString("-viewer_glvis_dm_plex_bmarker","String for the boundary id label",NULL,bmark,bmark,sizeof(bmark),&enable_bmark);
482:   PetscOptionsEnd();
483:   if (enable_bmark) enable_boundary = PETSC_TRUE;

485:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
487:   DMPlexGetDepth(dm,&depth);
489:                                                              "Alternatively, run with -viewer_glvis_dm_plex_enable_boundary 0");
491:                                                            "Alternatively, run with -viewer_glvis_dm_plex_enable_ncmesh 0");
492:   if (depth >=0 && dim != depth) { /* not interpolated, it assumes cell-vertex mesh */
494:     cellvertex = PETSC_TRUE;
495:   }

497:   /* Identify possible cells in the overlap */
498:   novl = 0;
499:   pown = NULL;
500:   if (size > 1) {
501:     IS             globalNum = NULL;
502:     const PetscInt *gNum;
503:     PetscBool      ovl  = PETSC_FALSE;

505:     PetscObjectQuery((PetscObject)dm,"_glvis_plex_gnum",(PetscObject*)&globalNum);
506:     if (!globalNum) {
507:       if (view_ovl) {
508:         ISCreateStride(PetscObjectComm((PetscObject)dm),cEnd-cStart,0,1,&globalNum);
509:       } else {
510:         DMPlexCreateCellNumbering_Internal(dm,PETSC_TRUE,&globalNum);
511:       }
512:       PetscObjectCompose((PetscObject)dm,"_glvis_plex_gnum",(PetscObject)globalNum);
513:       PetscObjectDereference((PetscObject)globalNum);
514:     }
515:     ISGetIndices(globalNum,&gNum);
516:     for (p=cStart; p<cEnd; p++) {
517:       if (gNum[p-cStart] < 0) {
518:         ovl = PETSC_TRUE;
519:         novl++;
520:       }
521:     }
522:     if (ovl) {
523:       /* it may happen that pown get not destroyed, if the user closes the window while this function is running.
524:          TODO: garbage collector? attach pown to dm?  */
525:       PetscBTCreate(cEnd-cStart,&pown);
526:       for (p=cStart; p<cEnd; p++) {
527:         if (gNum[p-cStart] < 0) continue;
528:         else {
529:           PetscBTSet(pown,p-cStart);
530:         }
531:       }
532:     }
533:     ISRestoreIndices(globalNum,&gNum);
534:   }

536:   /* vertex_parents (Non-conforming meshes) */
537:   parentSection  = NULL;
538:   if (enable_ncmesh) {
539:     DMPlexGetTree(dm,&parentSection,NULL,NULL,NULL,NULL);
540:     enable_ncmesh = (PetscBool)(enable_ncmesh && parentSection);
541:   }
542:   /* return if this process is disabled */
543:   if (!enabled) {
544:     PetscViewerASCIIPrintf(viewer,"MFEM mesh %s\n",enable_ncmesh ? "v1.1" : "v1.0");
545:     PetscViewerASCIIPrintf(viewer,"\ndimension\n");
546:     PetscViewerASCIIPrintf(viewer,"%D\n",dim);
547:     PetscViewerASCIIPrintf(viewer,"\nelements\n");
548:     PetscViewerASCIIPrintf(viewer,"%D\n",0);
549:     PetscViewerASCIIPrintf(viewer,"\nboundary\n");
550:     PetscViewerASCIIPrintf(viewer,"%D\n",0);
551:     PetscViewerASCIIPrintf(viewer,"\nvertices\n");
552:     PetscViewerASCIIPrintf(viewer,"%D\n",0);
553:     PetscViewerASCIIPrintf(viewer,"%D\n",sdim);
554:     PetscBTDestroy(&pown);
555:     VecDestroy(&hovec);
556:     return 0;
557:   }

559:   if (enable_mfem) {
560:     if (periodic && !hovec) { /* we need to generate a vector of L2 coordinates, as this is how MFEM handles periodic meshes */
561:       PetscInt    vpc = 0;
562:       char        fec[64];
563:       PetscInt    vids[8] = {0,1,2,3,4,5,6,7};
564:       PetscInt    hexv[8] = {0,1,3,2,4,5,7,6}, tetv[4] = {0,1,2,3};
565:       PetscInt    quadv[8] = {0,1,3,2}, triv[3] = {0,1,2};
566:       PetscInt    *dof = NULL;
567:       PetscScalar *array,*ptr;

569:       PetscSNPrintf(fec,sizeof(fec),"FiniteElementCollection: L2_T1_%DD_P1",dim);
570:       if (cEnd-cStart) {
571:         PetscInt fpc;

573:         DMPlexGetConeSize(dm,cStart,&fpc);
574:         switch(dim) {
575:           case 1:
576:             vpc = 2;
577:             dof = hexv;
578:             break;
579:           case 2:
580:             switch (fpc) {
581:               case 3:
582:                 vpc = 3;
583:                 dof = triv;
584:                 break;
585:               case 4:
586:                 vpc = 4;
587:                 dof = quadv;
588:                 break;
589:               default:
590:                 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unhandled case: faces per cell %D",fpc);
591:             }
592:             break;
593:           case 3:
594:             switch (fpc) {
595:               case 4: /* TODO: still need to understand L2 ordering for tets */
596:                 vpc = 4;
597:                 dof = tetv;
598:                 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unhandled tethraedral case");
599:               case 6:
601:                 vpc = 8;
602:                 dof = hexv;
603:                 break;
604:               case 8:
606:                 vpc = 8;
607:                 dof = hexv;
608:                 break;
609:               default:
610:                 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unhandled case: faces per cell %D",fpc);
611:             }
612:             break;
613:           default:
614:             SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unhandled dim");
615:         }
616:         DMPlexReorderCell(dm,cStart,vids);
617:       }
619:       VecCreateSeq(PETSC_COMM_SELF,(cEnd-cStart-novl)*vpc*sdim,&hovec);
620:       PetscObjectSetName((PetscObject)hovec,fec);
621:       VecGetArray(hovec,&array);
622:       ptr  = array;
623:       for (p=cStart;p<cEnd;p++) {
624:         PetscInt    csize,v,d;
625:         PetscScalar *vals = NULL;

627:         if (PetscUnlikely(pown && !PetscBTLookup(pown,p-cStart))) continue;
628:         DMPlexVecGetClosure(dm,coordSection,coordinates,p,&csize,&vals);
630:         for (v=0;v<vpc;v++) {
631:           for (d=0;d<sdim;d++) {
632:             ptr[sdim*dof[v]+d] = vals[sdim*vids[v]+d];
633:           }
634:         }
635:         ptr += vpc*sdim;
636:         DMPlexVecRestoreClosure(dm,coordSection,coordinates,p,&csize,&vals);
637:       }
638:       VecRestoreArray(hovec,&array);
639:     }
640:   }
641:   /* if we have high-order coordinates in 3D, we need to specify the boundary */
642:   if (hovec && dim == 3) enable_boundary = PETSC_TRUE;

644:   /* header */
645:   PetscViewerASCIIPrintf(viewer,"MFEM mesh %s\n",enable_ncmesh ? "v1.1" : "v1.0");

647:   /* topological dimension */
648:   PetscViewerASCIIPrintf(viewer,"\ndimension\n");
649:   PetscViewerASCIIPrintf(viewer,"%D\n",dim);

651:   /* elements */
652:   minl = 1;
653:   label = NULL;
654:   if (enable_emark) {
655:     PetscInt lminl = PETSC_MAX_INT;

657:     DMGetLabel(dm,emark,&label);
658:     if (label) {
659:       IS       vals;
660:       PetscInt ldef;

662:       DMLabelGetDefaultValue(label,&ldef);
663:       DMLabelGetValueIS(label,&vals);
664:       ISGetMinMax(vals,&lminl,NULL);
665:       ISDestroy(&vals);
666:       lminl = PetscMin(ldef,lminl);
667:     }
668:     MPIU_Allreduce(&lminl,&minl,1,MPIU_INT,MPI_MIN,PetscObjectComm((PetscObject)dm));
669:     if (minl == PETSC_MAX_INT) minl = 1;
670:   }
671:   PetscViewerASCIIPrintf(viewer,"\nelements\n");
672:   PetscViewerASCIIPrintf(viewer,"%D\n",cEnd-cStart-novl);
673:   for (p=cStart;p<cEnd;p++) {
674:     PetscInt       vids[8];
675:     PetscInt       i,nv = 0,cid = -1,mid = 1;

677:     if (PetscUnlikely(pown && !PetscBTLookup(pown,p-cStart))) continue;
678:     DMPlexGetPointMFEMCellID_Internal(dm,label,minl,p,&mid,&cid);
679:     DMPlexGetPointMFEMVertexIDs_Internal(dm,p,(localized && !hovec) ? coordSection : NULL,&nv,vids);
680:     DMPlexReorderCell(dm,p,vids);
681:     PetscViewerASCIIPrintf(viewer,"%D %D",mid,cid);
682:     for (i=0;i<nv;i++) {
683:       PetscViewerASCIIPrintf(viewer," %D",vids[i]);
684:     }
685:     PetscViewerASCIIPrintf(viewer,"\n");
686:   }

688:   /* boundary */
689:   PetscViewerASCIIPrintf(viewer,"\nboundary\n");
690:   if (!enable_boundary) {
691:     PetscViewerASCIIPrintf(viewer,"%D\n",0);
692:   } else {
693:     DMLabel  perLabel;
694:     PetscBT  bfaces;
695:     PetscInt fStart,fEnd,*fcells;

697:     DMPlexGetHeightStratum(dm,1,&fStart,&fEnd);
698:     PetscBTCreate(fEnd-fStart,&bfaces);
699:     DMPlexGetMaxSizes(dm,NULL,&p);
700:     PetscMalloc1(p,&fcells);
701:     DMGetLabel(dm,"glvis_periodic_cut",&perLabel);
702:     if (!perLabel && localized) { /* this periodic cut can be moved up to DMPlex setup */
703:       DMCreateLabel(dm,"glvis_periodic_cut");
704:       DMGetLabel(dm,"glvis_periodic_cut",&perLabel);
705:       DMLabelSetDefaultValue(perLabel,1);
706:       for (p=cStart;p<cEnd;p++) {
707:         DMPolytopeType cellType;
708:         PetscInt       dof;

710:         DMPlexGetCellType(dm,p,&cellType);
711:         PetscSectionGetDof(coordSection,p,&dof);
712:         if (dof) {
713:           PetscInt    uvpc, v,csize,cellClosureSize,*cellClosure = NULL,*vidxs = NULL;
714:           PetscScalar *vals = NULL;

716:           uvpc = DMPolytopeTypeGetNumVertices(cellType);
718:           DMPlexVecGetClosure(dm,coordSection,coordinates,p,&csize,&vals);
719:           DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&cellClosureSize,&cellClosure);
720:           for (v=0;v<cellClosureSize;v++)
721:             if (cellClosure[2*v] >= vStart && cellClosure[2*v] < vEnd) {
722:               vidxs = cellClosure + 2*v;
723:               break;
724:             }
726:           for (v=0;v<uvpc;v++) {
727:             PetscInt s;

729:             for (s=0;s<sdim;s++) {
730:               if (PetscAbsScalar(vals[v*sdim+s]-vals[v*sdim+s+uvpc*sdim])>PETSC_MACHINE_EPSILON) {
731:                 DMLabelSetValue(perLabel,vidxs[2*v],2);
732:               }
733:             }
734:           }
735:           DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&cellClosureSize,&cellClosure);
736:           DMPlexVecRestoreClosure(dm,coordSection,coordinates,p,&csize,&vals);
737:         }
738:       }
739:       if (dim > 1) {
740:         PetscInt eEnd,eStart;

742:         DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);
743:         for (p=eStart;p<eEnd;p++) {
744:           const PetscInt *cone;
745:           PetscInt       coneSize,i;
746:           PetscBool      ispe = PETSC_TRUE;

748:           DMPlexGetCone(dm,p,&cone);
749:           DMPlexGetConeSize(dm,p,&coneSize);
750:           for (i=0;i<coneSize;i++) {
751:             PetscInt v;

753:             DMLabelGetValue(perLabel,cone[i],&v);
754:             ispe = (PetscBool)(ispe && (v==2));
755:           }
756:           if (ispe && coneSize) {
757:             PetscInt       ch, numChildren;
758:             const PetscInt *children;

760:             DMLabelSetValue(perLabel,p,2);
761:             DMPlexGetTreeChildren(dm,p,&numChildren,&children);
762:             for (ch = 0; ch < numChildren; ch++) {
763:               DMLabelSetValue(perLabel,children[ch],2);
764:             }
765:           }
766:         }
767:         if (dim > 2) {
768:           for (p=fStart;p<fEnd;p++) {
769:             const PetscInt *cone;
770:             PetscInt       coneSize,i;
771:             PetscBool      ispe = PETSC_TRUE;

773:             DMPlexGetCone(dm,p,&cone);
774:             DMPlexGetConeSize(dm,p,&coneSize);
775:             for (i=0;i<coneSize;i++) {
776:               PetscInt v;

778:               DMLabelGetValue(perLabel,cone[i],&v);
779:               ispe = (PetscBool)(ispe && (v==2));
780:             }
781:             if (ispe && coneSize) {
782:               PetscInt       ch, numChildren;
783:               const PetscInt *children;

785:               DMLabelSetValue(perLabel,p,2);
786:               DMPlexGetTreeChildren(dm,p,&numChildren,&children);
787:               for (ch = 0; ch < numChildren; ch++) {
788:                 DMLabelSetValue(perLabel,children[ch],2);
789:               }
790:             }
791:           }
792:         }
793:       }
794:     }
795:     for (p=fStart;p<fEnd;p++) {
796:       const PetscInt *support;
797:       PetscInt       supportSize;
798:       PetscBool      isbf = PETSC_FALSE;

800:       DMPlexGetSupportSize(dm,p,&supportSize);
801:       if (pown) {
802:         PetscBool has_owned = PETSC_FALSE, has_ghost = PETSC_FALSE;
803:         PetscInt  i;

805:         DMPlexGetSupport(dm,p,&support);
806:         for (i=0;i<supportSize;i++) {
807:           if (PetscLikely(PetscBTLookup(pown,support[i]-cStart))) has_owned = PETSC_TRUE;
808:           else has_ghost = PETSC_TRUE;
809:         }
810:         isbf = (PetscBool)((supportSize == 1 && has_owned) || (supportSize > 1 && has_owned && has_ghost));
811:       } else {
812:         isbf = (PetscBool)(supportSize == 1);
813:       }
814:       if (!isbf && perLabel) {
815:         const PetscInt *cone;
816:         PetscInt       coneSize,i;

818:         DMPlexGetCone(dm,p,&cone);
819:         DMPlexGetConeSize(dm,p,&coneSize);
820:         isbf = PETSC_TRUE;
821:         for (i=0;i<coneSize;i++) {
822:           PetscInt v,d;

824:           DMLabelGetValue(perLabel,cone[i],&v);
825:           DMLabelGetDefaultValue(perLabel,&d);
826:           isbf = (PetscBool)(isbf && v != d);
827:         }
828:       }
829:       if (isbf) {
830:         PetscBTSet(bfaces,p-fStart);
831:       }
832:     }
833:     /* count boundary faces */
834:     for (p=fStart,bf=0;p<fEnd;p++) {
835:       if (PetscUnlikely(PetscBTLookup(bfaces,p-fStart))) {
836:         const PetscInt *support;
837:         PetscInt       supportSize,c;

839:         DMPlexGetSupportSize(dm,p,&supportSize);
840:         DMPlexGetSupport(dm,p,&support);
841:         for (c=0;c<supportSize;c++) {
842:           const    PetscInt *cone;
843:           PetscInt cell,cl,coneSize;

845:           cell = support[c];
846:           if (pown && PetscUnlikely(!PetscBTLookup(pown,cell-cStart))) continue;
847:           DMPlexGetCone(dm,cell,&cone);
848:           DMPlexGetConeSize(dm,cell,&coneSize);
849:           for (cl=0;cl<coneSize;cl++) {
850:             if (cone[cl] == p) {
851:               bf += 1;
852:               break;
853:             }
854:           }
855:         }
856:       }
857:     }
858:     minl = 1;
859:     label = NULL;
860:     if (enable_bmark) {
861:       PetscInt lminl = PETSC_MAX_INT;

863:       DMGetLabel(dm,bmark,&label);
864:       if (label) {
865:         IS       vals;
866:         PetscInt ldef;

868:         DMLabelGetDefaultValue(label,&ldef);
869:         DMLabelGetValueIS(label,&vals);
870:         ISGetMinMax(vals,&lminl,NULL);
871:         ISDestroy(&vals);
872:         lminl = PetscMin(ldef,lminl);
873:       }
874:       MPIU_Allreduce(&lminl,&minl,1,MPIU_INT,MPI_MIN,PetscObjectComm((PetscObject)dm));
875:       if (minl == PETSC_MAX_INT) minl = 1;
876:     }
877:     PetscViewerASCIIPrintf(viewer,"%D\n",bf);
878:     for (p=fStart;p<fEnd;p++) {
879:       if (PetscUnlikely(PetscBTLookup(bfaces,p-fStart))) {
880:         const PetscInt *support;
881:         PetscInt       supportSize,c,nc = 0;

883:         DMPlexGetSupportSize(dm,p,&supportSize);
884:         DMPlexGetSupport(dm,p,&support);
885:         if (pown) {
886:           for (c=0;c<supportSize;c++) {
887:             if (PetscLikely(PetscBTLookup(pown,support[c]-cStart))) {
888:               fcells[nc++] = support[c];
889:             }
890:           }
891:         } else for (c=0;c<supportSize;c++) fcells[nc++] = support[c];
892:         for (c=0;c<nc;c++) {
893:           const DMPolytopeType *faceTypes;
894:           DMPolytopeType       cellType;
895:           const PetscInt       *faceSizes,*cone;
896:           PetscInt             vids[8],*faces,st,i,coneSize,cell,cl,nv,cid = -1,mid = -1;

898:           cell = fcells[c];
899:           DMPlexGetCone(dm,cell,&cone);
900:           DMPlexGetConeSize(dm,cell,&coneSize);
901:           for (cl=0;cl<coneSize;cl++)
902:             if (cone[cl] == p)
903:               break;
904:           if (cl == coneSize) continue;

906:           /* face material id and type */
907:           DMPlexGetPointMFEMCellID_Internal(dm,label,minl,p,&mid,&cid);
908:           PetscViewerASCIIPrintf(viewer,"%D %D",mid,cid);
909:           /* vertex ids */
910:           DMPlexGetCellType(dm,cell,&cellType);
911:           DMPlexGetPointMFEMVertexIDs_Internal(dm,cell,(localized && !hovec) ? coordSection : NULL,&nv,vids);
912:           DMPlexGetRawFaces_Internal(dm,cellType,vids,NULL,&faceTypes,&faceSizes,(const PetscInt**)&faces);
913:           st = 0;
914:           for (i=0;i<cl;i++) st += faceSizes[i];
915:           DMPlexInvertCell(faceTypes[cl],faces + st);
916:           for (i=0;i<faceSizes[cl];i++) {
917:             PetscViewerASCIIPrintf(viewer," %d",faces[st+i]);
918:           }
919:           PetscViewerASCIIPrintf(viewer,"\n");
920:           DMPlexRestoreRawFaces_Internal(dm,cellType,vids,NULL,&faceTypes,&faceSizes,(const PetscInt**)&faces);
921:           bf -= 1;
922:         }
923:       }
924:     }
926:     PetscBTDestroy(&bfaces);
927:     PetscFree(fcells);
928:   }

930:   /* mark owned vertices */
931:   vown = NULL;
932:   if (pown) {
933:     PetscBTCreate(vEnd-vStart,&vown);
934:     for (p=cStart;p<cEnd;p++) {
935:       PetscInt i,closureSize,*closure = NULL;

937:       if (PetscUnlikely(!PetscBTLookup(pown,p-cStart))) continue;
938:       DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);
939:       for (i=0;i<closureSize;i++) {
940:         const PetscInt pp = closure[2*i];

942:         if (pp >= vStart && pp < vEnd) {
943:           PetscBTSet(vown,pp-vStart);
944:         }
945:       }
946:       DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);
947:     }
948:   }

950:   if (parentSection) {
951:     PetscInt vp,gvp;

953:     for (vp=0,p=vStart;p<vEnd;p++) {
954:       DMLabel  dlabel;
955:       PetscInt parent,depth;

957:       if (PetscUnlikely(vown && !PetscBTLookup(vown,p-vStart))) continue;
958:       DMPlexGetDepthLabel(dm,&dlabel);
959:       DMLabelGetValue(dlabel,p,&depth);
960:       DMPlexGetTreeParent(dm,p,&parent,NULL);
961:       if (parent != p) vp++;
962:     }
963:     MPIU_Allreduce(&vp,&gvp,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm));
964:     if (gvp) {
965:       PetscInt  maxsupp;
966:       PetscBool *skip = NULL;

968:       PetscViewerASCIIPrintf(viewer,"\nvertex_parents\n");
969:       PetscViewerASCIIPrintf(viewer,"%D\n",vp);
970:       DMPlexGetMaxSizes(dm,NULL,&maxsupp);
971:       PetscMalloc1(maxsupp,&skip);
972:       for (p=vStart;p<vEnd;p++) {
973:         DMLabel  dlabel;
974:         PetscInt parent;

976:         if (PetscUnlikely(vown && !PetscBTLookup(vown,p-vStart))) continue;
977:         DMPlexGetDepthLabel(dm,&dlabel);
978:         DMPlexGetTreeParent(dm,p,&parent,NULL);
979:         if (parent != p) {
980:           PetscInt       vids[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; /* silent overzealous clang static analyzer */
981:           PetscInt       i,nv,ssize,n,numChildren,depth = -1;
982:           const PetscInt *children;

984:           DMPlexGetConeSize(dm,parent,&ssize);
985:           switch (ssize) {
986:             case 2: /* edge */
987:               nv   = 0;
988:               DMPlexGetPointMFEMVertexIDs_Internal(dm,parent,localized ? coordSection : NULL,&nv,vids);
989:               PetscViewerASCIIPrintf(viewer,"%D",p-vStart);
990:               for (i=0;i<nv;i++) {
991:                 PetscViewerASCIIPrintf(viewer," %D",vids[i]);
992:               }
993:               PetscViewerASCIIPrintf(viewer,"\n");
994:               vp--;
995:               break;
996:             case 4: /* face */
997:               DMPlexGetTreeChildren(dm,parent,&numChildren,&children);
998:               for (n=0;n<numChildren;n++) {
999:                 DMLabelGetValue(dlabel,children[n],&depth);
1000:                 if (!depth) {
1001:                   const PetscInt *hvsupp,*hesupp,*cone;
1002:                   PetscInt       hvsuppSize,hesuppSize,coneSize;
1003:                   PetscInt       hv = children[n],he = -1,f;

1005:                   PetscArrayzero(skip,maxsupp);
1006:                   DMPlexGetSupportSize(dm,hv,&hvsuppSize);
1007:                   DMPlexGetSupport(dm,hv,&hvsupp);
1008:                   for (i=0;i<hvsuppSize;i++) {
1009:                     PetscInt ep;
1010:                     DMPlexGetTreeParent(dm,hvsupp[i],&ep,NULL);
1011:                     if (ep != hvsupp[i]) {
1012:                       he = hvsupp[i];
1013:                     } else {
1014:                       skip[i] = PETSC_TRUE;
1015:                     }
1016:                   }
1018:                   DMPlexGetCone(dm,he,&cone);
1019:                   vids[0] = (cone[0] == hv) ? cone[1] : cone[0];
1020:                   DMPlexGetSupportSize(dm,he,&hesuppSize);
1021:                   DMPlexGetSupport(dm,he,&hesupp);
1022:                   for (f=0;f<hesuppSize;f++) {
1023:                     PetscInt j;

1025:                     DMPlexGetCone(dm,hesupp[f],&cone);
1026:                     DMPlexGetConeSize(dm,hesupp[f],&coneSize);
1027:                     for (j=0;j<coneSize;j++) {
1028:                       PetscInt k;
1029:                       for (k=0;k<hvsuppSize;k++) {
1030:                         if (hvsupp[k] == cone[j]) {
1031:                           skip[k] = PETSC_TRUE;
1032:                           break;
1033:                         }
1034:                       }
1035:                     }
1036:                   }
1037:                   for (i=0;i<hvsuppSize;i++) {
1038:                     if (!skip[i]) {
1039:                       DMPlexGetCone(dm,hvsupp[i],&cone);
1040:                       vids[1] = (cone[0] == hv) ? cone[1] : cone[0];
1041:                     }
1042:                   }
1043:                   PetscViewerASCIIPrintf(viewer,"%D",hv-vStart);
1044:                   for (i=0;i<2;i++) {
1045:                     PetscViewerASCIIPrintf(viewer," %D",vids[i]-vStart);
1046:                   }
1047:                   PetscViewerASCIIPrintf(viewer,"\n");
1048:                   vp--;
1049:                 }
1050:               }
1051:               break;
1052:             default:
1053:               SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Don't know how to deal with support size %D",ssize);
1054:           }
1055:         }
1056:       }
1057:       PetscFree(skip);
1058:     }
1060:   }
1061:   PetscBTDestroy(&pown);
1062:   PetscBTDestroy(&vown);

1064:   /* vertices */
1065:   if (hovec) { /* higher-order meshes */
1066:     const char *fec;
1067:     PetscInt   i,n,s;

1069:     PetscViewerASCIIPrintf(viewer,"\nvertices\n");
1070:     PetscViewerASCIIPrintf(viewer,"%D\n",vEnd-vStart);
1071:     PetscViewerASCIIPrintf(viewer,"nodes\n");
1072:     PetscObjectGetName((PetscObject)hovec,&fec);
1073:     PetscViewerASCIIPrintf(viewer,"FiniteElementSpace\n");
1074:     PetscViewerASCIIPrintf(viewer,"%s\n",fec);
1075:     PetscViewerASCIIPrintf(viewer,"VDim: %D\n",sdim);
1076:     PetscViewerASCIIPrintf(viewer,"Ordering: 1\n\n"); /*Ordering::byVDIM*/
1077:     VecGetArrayRead(hovec,&array);
1078:     VecGetLocalSize(hovec,&n);
1080:     for (i=0;i<n/sdim;i++) {
1081:       for (s=0;s<sdim;s++) {
1082:         PetscViewerASCIIPrintf(viewer,fmt,(double) PetscRealPart(array[i*sdim+s]));
1083:       }
1084:       PetscViewerASCIIPrintf(viewer,"\n");
1085:     }
1086:     VecRestoreArrayRead(hovec,&array);
1087:   } else {
1088:     VecGetLocalSize(coordinates,&nvert);
1089:     PetscViewerASCIIPrintf(viewer,"\nvertices\n");
1090:     PetscViewerASCIIPrintf(viewer,"%D\n",nvert/sdim);
1091:     PetscViewerASCIIPrintf(viewer,"%D\n",sdim);
1092:     VecGetArrayRead(coordinates,&array);
1093:     for (p=0;p<nvert/sdim;p++) {
1094:       PetscInt s;
1095:       for (s=0;s<sdim;s++) {
1096:         PetscReal v = PetscRealPart(array[p*sdim+s]);

1098:         PetscViewerASCIIPrintf(viewer,fmt,PetscIsInfOrNanReal(v) ? 0.0 : (double) v);
1099:       }
1100:       PetscViewerASCIIPrintf(viewer,"\n");
1101:     }
1102:     VecRestoreArrayRead(coordinates,&array);
1103:   }
1104:   VecDestroy(&hovec);
1105:   return 0;
1106: }

1108: PetscErrorCode DMPlexView_GLVis(DM dm, PetscViewer viewer)
1109: {
1110:   DMView_GLVis(dm,viewer,DMPlexView_GLVis_ASCII);
1111:   return 0;
1112: }