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,°,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: }