Actual source code: plexvtu.c
petsc-3.9.4 2018-09-11
1: #include <petsc/private/dmpleximpl.h>
2: #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h>
4: typedef struct {
5: PetscInt nvertices;
6: PetscInt ncells;
7: PetscInt nconn; /* number of entries in cell->vertex connectivity array */
8: } PieceInfo;
10: #if defined(PETSC_USE_REAL_SINGLE)
11: static const char precision[] = "Float32";
12: #elif defined(PETSC_USE_REAL_DOUBLE)
13: static const char precision[] = "Float64";
14: #else
15: static const char precision[] = "UnknownPrecision";
16: #endif
18: static PetscErrorCode TransferWrite(PetscViewer viewer,FILE *fp,PetscMPIInt srank,PetscMPIInt root,const void *send,void *recv,PetscMPIInt count,MPI_Datatype mpidatatype,PetscMPIInt tag)
19: {
20: PetscMPIInt rank;
22: MPI_Comm comm;
25: PetscObjectGetComm((PetscObject)viewer,&comm);
26: MPI_Comm_rank(comm,&rank);
28: if (rank == srank && rank != root) {
29: MPI_Send((void*)send,count,mpidatatype,root,tag,comm);
30: } else if (rank == root) {
31: const void *buffer;
32: if (root == srank) { /* self */
33: buffer = send;
34: } else {
35: MPI_Status status;
36: PetscMPIInt nrecv;
37: MPI_Recv(recv,count,mpidatatype,srank,tag,comm,&status);
38: MPI_Get_count(&status,mpidatatype,&nrecv);
39: if (count != nrecv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Array size mismatch");
40: buffer = recv;
41: }
42: PetscViewerVTKFWrite(viewer,fp,buffer,count,mpidatatype);
43: }
44: return(0);
45: }
47: static PetscErrorCode DMPlexGetVTKConnectivity(DM dm, PetscBool localized, PieceInfo *piece,PetscVTKInt **oconn,PetscVTKInt **ooffsets,PetscVTKType **otypes)
48: {
50: PetscSection coordSection;
51: PetscVTKInt *conn,*offsets;
52: PetscVTKType *types;
53: PetscInt dim,vStart,vEnd,cStart,cEnd,pStart,pEnd,cellHeight,cMax,numLabelCells,hasLabel,c,v,countcell,countconn;
56: PetscMalloc3(piece->nconn,&conn,piece->ncells,&offsets,piece->ncells,&types);
57: DMGetCoordinateSection(dm, &coordSection);
58: DMGetDimension(dm,&dim);
59: DMPlexGetChart(dm,&pStart,&pEnd);
60: DMPlexGetVTKCellHeight(dm, &cellHeight);
61: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
62: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
63: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
64: if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
65: DMGetStratumSize(dm, "vtk", 1, &numLabelCells);
66: hasLabel = numLabelCells > 0 ? PETSC_TRUE : PETSC_FALSE;
68: countcell = 0;
69: countconn = 0;
70: for (c = cStart; c < cEnd; ++c) {
71: PetscInt nverts,dof = 0,celltype,startoffset,nC=0;
73: if (hasLabel) {
74: PetscInt value;
76: DMGetLabelValue(dm, "vtk", c, &value);
77: if (value != 1) continue;
78: }
79: startoffset = countconn;
80: if (localized) {
81: PetscSectionGetDof(coordSection, c, &dof);
82: }
83: if (!dof) {
84: PetscInt *closure = NULL;
85: PetscInt closureSize;
87: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
88: for (v = 0; v < closureSize*2; v += 2) {
89: if ((closure[v] >= vStart) && (closure[v] < vEnd)) {
90: if (!localized) conn[countconn++] = closure[v] - vStart;
91: else conn[countconn++] = startoffset + nC;
92: ++nC;
93: }
94: }
95: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
96: } else {
97: for (nC = 0; nC < dof/dim; nC++) conn[countconn++] = startoffset + nC;
98: }
99: DMPlexInvertCell(dim, nC, &conn[countconn-nC]);
101: offsets[countcell] = countconn;
103: nverts = countconn - startoffset;
104: DMPlexVTKGetCellType_Internal(dm,dim,nverts,&celltype);
106: types[countcell] = celltype;
107: countcell++;
108: }
109: if (countcell != piece->ncells) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent cell count");
110: if (countconn != piece->nconn) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Inconsistent connectivity count");
111: *oconn = conn;
112: *ooffsets = offsets;
113: *otypes = types;
114: return(0);
115: }
117: /*
118: Write all fields that have been provided to the viewer
119: Multi-block XML format with binary appended data.
120: */
121: PetscErrorCode DMPlexVTKWriteAll_VTU(DM dm,PetscViewer viewer)
122: {
123: MPI_Comm comm;
124: PetscSection coordSection;
125: PetscViewer_VTK *vtk = (PetscViewer_VTK*)viewer->data;
126: PetscViewerVTKObjectLink link;
127: FILE *fp;
128: PetscMPIInt rank,size,tag;
129: PetscErrorCode ierr;
130: PetscInt dimEmbed,cellHeight,cStart,cEnd,vStart,vEnd,cMax,numLabelCells,hasLabel,c,v,r,i;
131: PetscBool localized;
132: PieceInfo piece,*gpiece = NULL;
133: void *buffer = NULL;
136: PetscObjectGetComm((PetscObject)dm,&comm);
137: #if defined(PETSC_USE_COMPLEX)
138: SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Complex values not supported");
139: #endif
140: MPI_Comm_size(comm,&size);
141: MPI_Comm_rank(comm,&rank);
142: tag = ((PetscObject)viewer)->tag;
144: PetscFOpen(comm,vtk->filename,"wb",&fp);
145: PetscFPrintf(comm,fp,"<?xml version=\"1.0\"?>\n");
146: #if defined(PETSC_WORDS_BIGENDIAN)
147: PetscFPrintf(comm,fp,"<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"BigEndian\">\n");
148: #else
149: PetscFPrintf(comm,fp,"<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n");
150: #endif
151: PetscFPrintf(comm,fp," <UnstructuredGrid>\n");
153: DMGetCoordinateDim(dm, &dimEmbed);
154: DMPlexGetVTKCellHeight(dm, &cellHeight);
155: DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
156: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
157: DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
158: if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
159: DMGetStratumSize(dm, "vtk", 1, &numLabelCells);
160: DMGetCoordinatesLocalized(dm, &localized);
161: DMGetCoordinateSection(dm, &coordSection);
163: hasLabel = numLabelCells > 0 ? PETSC_TRUE : PETSC_FALSE;
164: piece.nvertices = 0;
165: piece.ncells = 0;
166: piece.nconn = 0;
167: if (!localized) piece.nvertices = vEnd - vStart;
168: for (c = cStart; c < cEnd; ++c) {
169: PetscInt dof = 0;
170: if (hasLabel) {
171: PetscInt value;
173: DMGetLabelValue(dm, "vtk", c, &value);
174: if (value != 1) continue;
175: }
176: if (localized) {
177: PetscSectionGetDof(coordSection, c, &dof);
178: }
179: if (!dof) {
180: PetscInt *closure = NULL;
181: PetscInt closureSize;
183: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
184: for (v = 0; v < closureSize*2; v += 2) {
185: if ((closure[v] >= vStart) && (closure[v] < vEnd)) {
186: piece.nconn++;
187: if (localized) piece.nvertices++;
188: }
189: }
190: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
191: } else {
192: piece.nvertices += dof/dimEmbed;
193: piece.nconn += dof/dimEmbed;
194: }
195: piece.ncells++;
196: }
197: if (!rank) {PetscMalloc1(size,&gpiece);}
198: MPI_Gather((PetscInt*)&piece,sizeof(piece)/sizeof(PetscInt),MPIU_INT,(PetscInt*)gpiece,sizeof(piece)/sizeof(PetscInt),MPIU_INT,0,comm);
200: /*
201: * Write file header
202: */
203: if (!rank) {
204: PetscInt boffset = 0;
206: for (r=0; r<size; r++) {
207: PetscFPrintf(PETSC_COMM_SELF,fp," <Piece NumberOfPoints=\"%D\" NumberOfCells=\"%D\">\n",gpiece[r].nvertices,gpiece[r].ncells);
208: /* Coordinate positions */
209: PetscFPrintf(PETSC_COMM_SELF,fp," <Points>\n");
210: PetscFPrintf(PETSC_COMM_SELF,fp," <DataArray type=\"%s\" Name=\"Position\" NumberOfComponents=\"3\" format=\"appended\" offset=\"%D\" />\n",precision,boffset);
211: boffset += gpiece[r].nvertices*3*sizeof(PetscScalar) + sizeof(int);
212: PetscFPrintf(PETSC_COMM_SELF,fp," </Points>\n");
213: /* Cell connectivity */
214: PetscFPrintf(PETSC_COMM_SELF,fp," <Cells>\n");
215: PetscFPrintf(PETSC_COMM_SELF,fp," <DataArray type=\"Int32\" Name=\"connectivity\" NumberOfComponents=\"1\" format=\"appended\" offset=\"%D\" />\n",boffset);
216: boffset += gpiece[r].nconn*sizeof(PetscInt) + sizeof(int);
217: PetscFPrintf(PETSC_COMM_SELF,fp," <DataArray type=\"Int32\" Name=\"offsets\" NumberOfComponents=\"1\" format=\"appended\" offset=\"%D\" />\n",boffset);
218: boffset += gpiece[r].ncells*sizeof(PetscInt) + sizeof(int);
219: PetscFPrintf(PETSC_COMM_SELF,fp," <DataArray type=\"UInt8\" Name=\"types\" NumberOfComponents=\"1\" format=\"appended\" offset=\"%D\" />\n",boffset);
220: boffset += gpiece[r].ncells*sizeof(unsigned char) + sizeof(int);
221: PetscFPrintf(PETSC_COMM_SELF,fp," </Cells>\n");
223: /*
224: * Cell Data headers
225: */
226: PetscFPrintf(PETSC_COMM_SELF,fp," <CellData>\n");
227: PetscFPrintf(PETSC_COMM_SELF,fp," <DataArray type=\"Int32\" Name=\"Rank\" NumberOfComponents=\"1\" format=\"appended\" offset=\"%D\" />\n",boffset);
228: boffset += gpiece[r].ncells*sizeof(int) + sizeof(int);
229: /* all the vectors */
230: for (link=vtk->link; link; link=link->next) {
231: Vec X = (Vec)link->vec;
232: PetscInt bs,nfields,field;
233: const char *vecname = "";
234: if ((link->ft != PETSC_VTK_CELL_FIELD) && (link->ft != PETSC_VTK_CELL_VECTOR_FIELD)) continue;
235: if (((PetscObject)X)->name || link != vtk->link) { /* If the object is already named, use it. If it is past the first link, name it to disambiguate. */
236: PetscObjectGetName((PetscObject)X,&vecname);
237: }
238: PetscSectionGetDof(dm->defaultSection,cStart,&bs);
239: PetscSectionGetNumFields(dm->defaultSection,&nfields);
240: for (field=0,i=0; field<(nfields?nfields:1); field++) {
241: PetscInt fbs,j;
242: PetscFV fv = NULL;
243: PetscObject f;
244: PetscClassId fClass;
245: const char *fieldname = NULL;
246: char buf[256];
247: if (nfields) { /* We have user-defined fields/components */
248: PetscSectionGetFieldDof(dm->defaultSection,cStart,field,&fbs);
249: PetscSectionGetFieldName(dm->defaultSection,field,&fieldname);
250: } else fbs = bs; /* Say we have one field with 'bs' components */
251: DMGetField(dm,field,&f);
252: PetscObjectGetClassId(f,&fClass);
253: if (fClass == PETSCFV_CLASSID) {
254: fv = (PetscFV) f;
255: }
256: if (!fieldname) {
257: PetscSNPrintf(buf,sizeof(buf),"CellField%D",field);
258: fieldname = buf;
259: }
260: for (j=0; j<fbs; j++) {
261: const char *compName = NULL;
262: if (fv) {
263: PetscFVGetComponentName(fv,j,&compName);
264: }
265: if (compName) {
266: PetscFPrintf(comm,fp," <DataArray type=\"%s\" Name=\"%s%s.%s\" NumberOfComponents=\"1\" format=\"appended\" offset=\"%D\" />\n",precision,vecname,fieldname,compName,boffset);
267: }
268: else {
269: PetscFPrintf(comm,fp," <DataArray type=\"%s\" Name=\"%s%s.%D\" NumberOfComponents=\"1\" format=\"appended\" offset=\"%D\" />\n",precision,vecname,fieldname,j,boffset);
270: }
271: boffset += gpiece[r].ncells*sizeof(PetscScalar) + sizeof(int);
272: i++;
273: }
274: }
275: if (i != bs) SETERRQ2(comm,PETSC_ERR_PLIB,"Total number of field components %D != block size %D",i,bs);
276: }
277: PetscFPrintf(PETSC_COMM_SELF,fp," </CellData>\n");
279: /*
280: * Point Data headers
281: */
282: PetscFPrintf(PETSC_COMM_SELF,fp," <PointData>\n");
283: for (link=vtk->link; link; link=link->next) {
284: Vec X = (Vec)link->vec;
285: PetscInt bs,nfields,field;
286: const char *vecname = "";
287: if ((link->ft != PETSC_VTK_POINT_FIELD) && (link->ft != PETSC_VTK_POINT_VECTOR_FIELD)) continue;
288: if (((PetscObject)X)->name || link != vtk->link) { /* If the object is already named, use it. If it is past the first link, name it to disambiguate. */
289: PetscObjectGetName((PetscObject)X,&vecname);
290: }
291: PetscSectionGetDof(dm->defaultSection,vStart,&bs);
292: PetscSectionGetNumFields(dm->defaultSection,&nfields);
293: for (field=0,i=0; field<(nfields?nfields:1); field++) {
294: PetscInt fbs,j;
295: const char *fieldname = NULL;
296: char buf[256];
297: if (nfields) { /* We have user-defined fields/components */
298: PetscSectionGetFieldDof(dm->defaultSection,vStart,field,&fbs);
299: PetscSectionGetFieldName(dm->defaultSection,field,&fieldname);
300: } else fbs = bs; /* Say we have one field with 'bs' components */
301: if (!fieldname) {
302: PetscSNPrintf(buf,sizeof(buf),"PointField%D",field);
303: fieldname = buf;
304: }
305: for (j=0; j<fbs; j++) {
306: PetscFPrintf(comm,fp," <DataArray type=\"%s\" Name=\"%s%s.%D\" NumberOfComponents=\"1\" format=\"appended\" offset=\"%D\" />\n",precision,vecname,fieldname,j,boffset);
307: boffset += gpiece[r].nvertices*sizeof(PetscScalar) + sizeof(int);
308: }
309: }
310: }
311: PetscFPrintf(PETSC_COMM_SELF,fp," </PointData>\n");
313: PetscFPrintf(PETSC_COMM_SELF,fp," </Piece>\n");
314: }
315: }
317: PetscFPrintf(comm,fp," </UnstructuredGrid>\n");
318: PetscFPrintf(comm,fp," <AppendedData encoding=\"raw\">\n");
319: PetscFPrintf(comm,fp,"_");
321: if (!rank) {
322: PetscInt maxsize = 0;
323: for (r=0; r<size; r++) {
324: maxsize = PetscMax(maxsize, (PetscInt) (gpiece[r].nvertices*3*sizeof(PetscScalar)));
325: maxsize = PetscMax(maxsize, (PetscInt) (gpiece[r].ncells*sizeof(PetscScalar)));
326: maxsize = PetscMax(maxsize, (PetscInt) (gpiece[r].nconn*sizeof(PetscVTKInt)));
327: }
328: PetscMalloc(maxsize,&buffer);
329: }
330: for (r=0; r<size; r++) {
331: if (r == rank) {
332: PetscInt nsend;
333: { /* Position */
334: const PetscScalar *x;
335: PetscScalar *y = NULL;
336: Vec coords;
338: DMGetCoordinatesLocal(dm,&coords);
339: VecGetArrayRead(coords,&x);
340: if (dimEmbed != 3 || localized) {
341: PetscMalloc1(piece.nvertices*3,&y);
342: if (localized) {
343: PetscInt cnt;
344: for (c=cStart,cnt=0; c<cEnd; c++) {
345: PetscInt off, dof;
347: PetscSectionGetDof(coordSection, c, &dof);
348: if (!dof) {
349: PetscInt *closure = NULL;
350: PetscInt closureSize;
352: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
353: for (v = 0; v < closureSize*2; v += 2) {
354: if ((closure[v] >= vStart) && (closure[v] < vEnd)) {
355: PetscSectionGetOffset(coordSection, closure[v], &off);
356: if (dimEmbed != 3) {
357: y[cnt*3+0] = x[off+0];
358: y[cnt*3+1] = (dimEmbed > 1) ? x[off+1] : 0.0;
359: y[cnt*3+2] = 0.0;
360: } else {
361: y[cnt*3+0] = x[off+0];
362: y[cnt*3+1] = x[off+1];
363: y[cnt*3+2] = x[off+2];
364: }
365: cnt++;
366: }
367: }
368: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
369: } else {
370: PetscSectionGetOffset(coordSection, c, &off);
371: if (dimEmbed != 3) {
372: for (i=0; i<dof/dimEmbed; i++) {
373: y[cnt*3+0] = x[off + i*dimEmbed + 0];
374: y[cnt*3+1] = (dimEmbed > 1) ? x[off + i*dimEmbed + 1] : 0.0;
375: y[cnt*3+2] = 0.0;
376: cnt++;
377: }
378: } else {
379: for (i=0; i<dof; i ++) {
380: y[cnt*3+i] = x[off + i];
381: }
382: cnt += dof/dimEmbed;
383: }
384: }
385: }
386: if (cnt != piece.nvertices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Count does not match");
387: } else {
388: for (i=0; i<piece.nvertices; i++) {
389: y[i*3+0] = x[i*dimEmbed+0];
390: y[i*3+1] = (dimEmbed > 1) ? x[i*dimEmbed+1] : 0;
391: y[i*3+2] = 0.0;
392: }
393: }
394: }
395: nsend = piece.nvertices*3;
396: TransferWrite(viewer,fp,r,0,y ? y : x,buffer,nsend,MPIU_SCALAR,tag);
397: PetscFree(y);
398: VecRestoreArrayRead(coords,&x);
399: }
400: { /* Connectivity, offsets, types */
401: PetscVTKInt *connectivity = NULL, *offsets = NULL;
402: PetscVTKType *types = NULL;
403: DMPlexGetVTKConnectivity(dm,localized,&piece,&connectivity,&offsets,&types);
404: TransferWrite(viewer,fp,r,0,connectivity,buffer,piece.nconn,MPI_INT,tag);
405: TransferWrite(viewer,fp,r,0,offsets,buffer,piece.ncells,MPI_INT,tag);
406: TransferWrite(viewer,fp,r,0,types,buffer,piece.ncells,MPI_CHAR,tag);
407: PetscFree3(connectivity,offsets,types);
408: }
409: { /* Owners (cell data) */
410: PetscVTKInt *owners;
411: PetscMalloc1(piece.ncells,&owners);
412: for (i=0; i<piece.ncells; i++) owners[i] = rank;
413: TransferWrite(viewer,fp,r,0,owners,buffer,piece.ncells,MPI_INT,tag);
414: PetscFree(owners);
415: }
416: /* Cell data */
417: for (link=vtk->link; link; link=link->next) {
418: Vec X = (Vec)link->vec;
419: const PetscScalar *x;
420: PetscScalar *y;
421: PetscInt bs;
422: if ((link->ft != PETSC_VTK_CELL_FIELD) && (link->ft != PETSC_VTK_CELL_VECTOR_FIELD)) continue;
423: PetscSectionGetDof(dm->defaultSection,cStart,&bs);
424: VecGetArrayRead(X,&x);
425: PetscMalloc1(piece.ncells,&y);
426: for (i=0; i<bs; i++) {
427: PetscInt cnt;
428: for (c=cStart,cnt=0; c<cEnd; c++) {
429: PetscScalar *xpoint;
430: if (hasLabel) { /* Ignore some cells */
431: PetscInt value;
432: DMGetLabelValue(dm, "vtk", c, &value);
433: if (value != 1) continue;
434: }
435: DMPlexPointLocalRead(dm,c,x,&xpoint);
436: y[cnt++] = xpoint[i];
437: }
438: if (cnt != piece.ncells) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Count does not match");
439: TransferWrite(viewer,fp,r,0,y,buffer,piece.ncells,MPIU_SCALAR,tag);
440: }
441: PetscFree(y);
442: VecRestoreArrayRead(X,&x);
443: }
445: for (link=vtk->link; link; link=link->next) {
446: Vec X = (Vec)link->vec;
447: const PetscScalar *x;
448: PetscScalar *y;
449: PetscInt bs;
450: if ((link->ft != PETSC_VTK_POINT_FIELD) && (link->ft != PETSC_VTK_POINT_VECTOR_FIELD)) continue;
451: PetscSectionGetDof(dm->defaultSection,vStart,&bs);
452: VecGetArrayRead(X,&x);
453: PetscMalloc1(piece.nvertices,&y);
454: for (i=0; i<bs; i++) {
455: PetscInt cnt;
456: if (!localized) {
457: for (v=vStart,cnt=0; v<vEnd; v++) {
458: PetscScalar *xpoint;
459: DMPlexPointLocalRead(dm,v,x,&xpoint);
460: y[cnt++] = xpoint[i];
461: }
462: } else {
463: for (c=cStart,cnt=0; c<cEnd; c++) {
464: PetscInt *closure = NULL;
465: PetscInt closureSize, off;
467: DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
468: for (v = 0, off = 0; v < closureSize*2; v += 2) {
469: if ((closure[v] >= vStart) && (closure[v] < vEnd)) {
470: PetscScalar *xpoint;
472: DMPlexPointLocalRead(dm,v,x,&xpoint);
473: y[cnt + off++] = xpoint[i];
474: }
475: }
476: DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
477: }
478: }
479: if (cnt != piece.nvertices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Count does not match");
480: TransferWrite(viewer,fp,r,0,y,buffer,piece.nvertices,MPIU_SCALAR,tag);
481: }
482: PetscFree(y);
483: VecRestoreArrayRead(X,&x);
484: }
485: } else if (!rank) {
486: TransferWrite(viewer,fp,r,0,NULL,buffer,gpiece[r].nvertices*3,MPIU_SCALAR,tag); /* positions */
487: TransferWrite(viewer,fp,r,0,NULL,buffer,gpiece[r].nconn,MPI_INT,tag); /* connectivity */
488: TransferWrite(viewer,fp,r,0,NULL,buffer,gpiece[r].ncells,MPI_INT,tag); /* offsets */
489: TransferWrite(viewer,fp,r,0,NULL,buffer,gpiece[r].ncells,MPI_CHAR,tag); /* types */
490: TransferWrite(viewer,fp,r,0,NULL,buffer,gpiece[r].ncells,MPI_INT,tag); /* owner rank (cells) */
491: /* all cell data */
492: for (link=vtk->link; link; link=link->next) {
493: PetscInt bs;
494: if ((link->ft != PETSC_VTK_CELL_FIELD) && (link->ft != PETSC_VTK_CELL_VECTOR_FIELD)) continue;
495: PetscSectionGetDof(dm->defaultSection,cStart,&bs);
496: for (i=0; i<bs; i++) {
497: TransferWrite(viewer,fp,r,0,NULL,buffer,gpiece[r].ncells,MPIU_SCALAR,tag);
498: }
499: }
500: /* all point data */
501: for (link=vtk->link; link; link=link->next) {
502: PetscInt bs;
503: if ((link->ft != PETSC_VTK_POINT_FIELD) && (link->ft != PETSC_VTK_POINT_VECTOR_FIELD)) continue;
504: PetscSectionGetDof(dm->defaultSection,vStart,&bs);
505: for (i=0; i<bs; i++) {
506: TransferWrite(viewer,fp,r,0,NULL,buffer,gpiece[r].nvertices,MPIU_SCALAR,tag);
507: }
508: }
509: }
510: }
511: PetscFree(gpiece);
512: PetscFree(buffer);
513: PetscFPrintf(comm,fp,"\n </AppendedData>\n");
514: PetscFPrintf(comm,fp,"</VTKFile>\n");
515: PetscFClose(comm,fp);
516: return(0);
517: }