1 #define PETSCDM_DLL 2 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 3 #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h> 4 5 PetscErrorCode DMPlexVTKGetCellType_Internal(DM dm, PetscInt dim, PetscInt corners, PetscInt *cellType) 6 { 7 PetscFunctionBegin; 8 *cellType = -1; 9 switch (dim) { 10 case 0: 11 switch (corners) { 12 case 1: 13 *cellType = 1; /* VTK_VERTEX */ 14 break; 15 default: 16 break; 17 } 18 break; 19 case 1: 20 switch (corners) { 21 case 2: 22 *cellType = 3; /* VTK_LINE */ 23 break; 24 case 3: 25 *cellType = 21; /* VTK_QUADRATIC_EDGE */ 26 break; 27 default: 28 break; 29 } 30 break; 31 case 2: 32 switch (corners) { 33 case 3: 34 *cellType = 5; /* VTK_TRIANGLE */ 35 break; 36 case 4: 37 *cellType = 9; /* VTK_QUAD */ 38 break; 39 case 6: 40 *cellType = 22; /* VTK_QUADRATIC_TRIANGLE */ 41 break; 42 case 9: 43 *cellType = 23; /* VTK_QUADRATIC_QUAD */ 44 break; 45 default: 46 break; 47 } 48 break; 49 case 3: 50 switch (corners) { 51 case 4: 52 *cellType = 10; /* VTK_TETRA */ 53 break; 54 case 5: 55 *cellType = 14; /* VTK_PYRAMID */ 56 break; 57 case 6: 58 *cellType = 13; /* VTK_WEDGE */ 59 break; 60 case 8: 61 *cellType = 12; /* VTK_HEXAHEDRON */ 62 break; 63 case 10: 64 *cellType = 24; /* VTK_QUADRATIC_TETRA */ 65 break; 66 case 27: 67 *cellType = 29; /* VTK_QUADRATIC_HEXAHEDRON */ 68 break; 69 default: 70 break; 71 } 72 } 73 PetscFunctionReturn(PETSC_SUCCESS); 74 } 75 76 static PetscErrorCode DMPlexVTKWriteCells_ASCII(DM dm, FILE *fp, PetscInt *totalCells) 77 { 78 MPI_Comm comm; 79 DMLabel label; 80 IS globalVertexNumbers = NULL; 81 const PetscInt *gvertex; 82 PetscInt dim; 83 PetscInt numCorners = 0, totCorners = 0, maxCorners, *corners; 84 PetscInt numCells = 0, totCells = 0, maxCells, cellHeight; 85 PetscInt numLabelCells, maxLabelCells, cStart, cEnd, c, vStart, vEnd, v; 86 PetscMPIInt size, rank, proc, tag; 87 88 PetscFunctionBegin; 89 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 90 PetscCall(PetscCommGetNewTag(comm, &tag)); 91 PetscCallMPI(MPI_Comm_size(comm, &size)); 92 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 93 PetscCall(DMGetDimension(dm, &dim)); 94 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 95 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 96 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 97 PetscCall(DMGetLabel(dm, "vtk", &label)); 98 PetscCall(DMGetStratumSize(dm, "vtk", 1, &numLabelCells)); 99 PetscCall(MPIU_Allreduce(&numLabelCells, &maxLabelCells, 1, MPIU_INT, MPI_MAX, comm)); 100 if (!maxLabelCells) label = NULL; 101 for (c = cStart; c < cEnd; ++c) { 102 PetscInt *closure = NULL; 103 PetscInt closureSize, value; 104 105 if (label) { 106 PetscCall(DMLabelGetValue(label, c, &value)); 107 if (value != 1) continue; 108 } 109 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 110 for (v = 0; v < closureSize * 2; v += 2) { 111 if ((closure[v] >= vStart) && (closure[v] < vEnd)) ++numCorners; 112 } 113 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 114 ++numCells; 115 } 116 maxCells = numCells; 117 PetscCallMPI(MPI_Reduce(&numCells, &totCells, 1, MPIU_INT, MPI_SUM, 0, comm)); 118 PetscCallMPI(MPI_Reduce(&numCells, &maxCells, 1, MPIU_INT, MPI_MAX, 0, comm)); 119 PetscCallMPI(MPI_Reduce(&numCorners, &totCorners, 1, MPIU_INT, MPI_SUM, 0, comm)); 120 PetscCallMPI(MPI_Reduce(&numCorners, &maxCorners, 1, MPIU_INT, MPI_MAX, 0, comm)); 121 PetscCall(DMPlexGetVertexNumbering(dm, &globalVertexNumbers)); 122 PetscCall(ISGetIndices(globalVertexNumbers, &gvertex)); 123 PetscCall(PetscMalloc1(maxCells, &corners)); 124 PetscCall(PetscFPrintf(comm, fp, "CELLS %" PetscInt_FMT " %" PetscInt_FMT "\n", totCells, totCorners + totCells)); 125 if (rank == 0) { 126 PetscInt *remoteVertices, *vertices; 127 128 PetscCall(PetscMalloc1(maxCorners, &vertices)); 129 for (c = cStart, numCells = 0; c < cEnd; ++c) { 130 PetscInt *closure = NULL; 131 PetscInt closureSize, value, nC = 0; 132 133 if (label) { 134 PetscCall(DMLabelGetValue(label, c, &value)); 135 if (value != 1) continue; 136 } 137 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 138 for (v = 0; v < closureSize * 2; v += 2) { 139 if ((closure[v] >= vStart) && (closure[v] < vEnd)) { 140 const PetscInt gv = gvertex[closure[v] - vStart]; 141 vertices[nC++] = gv < 0 ? -(gv + 1) : gv; 142 } 143 } 144 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 145 PetscCall(DMPlexReorderCell(dm, c, vertices)); 146 corners[numCells++] = nC; 147 PetscCall(PetscFPrintf(comm, fp, "%" PetscInt_FMT " ", nC)); 148 for (v = 0; v < nC; ++v) PetscCall(PetscFPrintf(comm, fp, " %" PetscInt_FMT, vertices[v])); 149 PetscCall(PetscFPrintf(comm, fp, "\n")); 150 } 151 if (size > 1) PetscCall(PetscMalloc1(maxCorners + maxCells, &remoteVertices)); 152 for (proc = 1; proc < size; ++proc) { 153 MPI_Status status; 154 155 PetscCallMPI(MPI_Recv(&numCorners, 1, MPIU_INT, proc, tag, comm, &status)); 156 PetscCallMPI(MPI_Recv(remoteVertices, numCorners, MPIU_INT, proc, tag, comm, &status)); 157 for (c = 0; c < numCorners;) { 158 PetscInt nC = remoteVertices[c++]; 159 160 for (v = 0; v < nC; ++v, ++c) vertices[v] = remoteVertices[c]; 161 PetscCall(PetscFPrintf(comm, fp, "%" PetscInt_FMT " ", nC)); 162 for (v = 0; v < nC; ++v) PetscCall(PetscFPrintf(comm, fp, " %" PetscInt_FMT, vertices[v])); 163 PetscCall(PetscFPrintf(comm, fp, "\n")); 164 } 165 } 166 if (size > 1) PetscCall(PetscFree(remoteVertices)); 167 PetscCall(PetscFree(vertices)); 168 } else { 169 PetscInt *localVertices, numSend = numCells + numCorners, k = 0; 170 171 PetscCall(PetscMalloc1(numSend, &localVertices)); 172 for (c = cStart, numCells = 0; c < cEnd; ++c) { 173 PetscInt *closure = NULL; 174 PetscInt closureSize, value, nC = 0; 175 176 if (label) { 177 PetscCall(DMLabelGetValue(label, c, &value)); 178 if (value != 1) continue; 179 } 180 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 181 for (v = 0; v < closureSize * 2; v += 2) { 182 if ((closure[v] >= vStart) && (closure[v] < vEnd)) { 183 const PetscInt gv = gvertex[closure[v] - vStart]; 184 closure[nC++] = gv < 0 ? -(gv + 1) : gv; 185 } 186 } 187 corners[numCells++] = nC; 188 localVertices[k++] = nC; 189 for (v = 0; v < nC; ++v, ++k) localVertices[k] = closure[v]; 190 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 191 PetscCall(DMPlexReorderCell(dm, c, localVertices + k - nC)); 192 } 193 PetscCheck(k == numSend, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of vertices to send %" PetscInt_FMT " should be %" PetscInt_FMT, k, numSend); 194 PetscCallMPI(MPI_Send(&numSend, 1, MPIU_INT, 0, tag, comm)); 195 PetscCallMPI(MPI_Send(localVertices, numSend, MPIU_INT, 0, tag, comm)); 196 PetscCall(PetscFree(localVertices)); 197 } 198 PetscCall(ISRestoreIndices(globalVertexNumbers, &gvertex)); 199 PetscCall(PetscFPrintf(comm, fp, "CELL_TYPES %" PetscInt_FMT "\n", totCells)); 200 if (rank == 0) { 201 PetscInt cellType; 202 203 for (c = 0; c < numCells; ++c) { 204 PetscCall(DMPlexVTKGetCellType_Internal(dm, dim, corners[c], &cellType)); 205 PetscCall(PetscFPrintf(comm, fp, "%" PetscInt_FMT "\n", cellType)); 206 } 207 for (proc = 1; proc < size; ++proc) { 208 MPI_Status status; 209 210 PetscCallMPI(MPI_Recv(&numCells, 1, MPIU_INT, proc, tag, comm, &status)); 211 PetscCallMPI(MPI_Recv(corners, numCells, MPIU_INT, proc, tag, comm, &status)); 212 for (c = 0; c < numCells; ++c) { 213 PetscCall(DMPlexVTKGetCellType_Internal(dm, dim, corners[c], &cellType)); 214 PetscCall(PetscFPrintf(comm, fp, "%" PetscInt_FMT "\n", cellType)); 215 } 216 } 217 } else { 218 PetscCallMPI(MPI_Send(&numCells, 1, MPIU_INT, 0, tag, comm)); 219 PetscCallMPI(MPI_Send(corners, numCells, MPIU_INT, 0, tag, comm)); 220 } 221 PetscCall(PetscFree(corners)); 222 *totalCells = totCells; 223 PetscFunctionReturn(PETSC_SUCCESS); 224 } 225 226 static PetscErrorCode DMPlexVTKWritePartition_ASCII(DM dm, FILE *fp) 227 { 228 MPI_Comm comm; 229 PetscInt numCells = 0, cellHeight; 230 PetscInt numLabelCells, cStart, cEnd, c; 231 PetscMPIInt size, rank, proc, tag; 232 PetscBool hasLabel; 233 234 PetscFunctionBegin; 235 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 236 PetscCall(PetscCommGetNewTag(comm, &tag)); 237 PetscCallMPI(MPI_Comm_size(comm, &size)); 238 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 239 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 240 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 241 PetscCall(DMGetStratumSize(dm, "vtk", 1, &numLabelCells)); 242 hasLabel = numLabelCells > 0 ? PETSC_TRUE : PETSC_FALSE; 243 for (c = cStart; c < cEnd; ++c) { 244 if (hasLabel) { 245 PetscInt value; 246 247 PetscCall(DMGetLabelValue(dm, "vtk", c, &value)); 248 if (value != 1) continue; 249 } 250 ++numCells; 251 } 252 if (rank == 0) { 253 for (c = 0; c < numCells; ++c) PetscCall(PetscFPrintf(comm, fp, "%d\n", rank)); 254 for (proc = 1; proc < size; ++proc) { 255 MPI_Status status; 256 257 PetscCallMPI(MPI_Recv(&numCells, 1, MPIU_INT, proc, tag, comm, &status)); 258 for (c = 0; c < numCells; ++c) PetscCall(PetscFPrintf(comm, fp, "%d\n", proc)); 259 } 260 } else { 261 PetscCallMPI(MPI_Send(&numCells, 1, MPIU_INT, 0, tag, comm)); 262 } 263 PetscFunctionReturn(PETSC_SUCCESS); 264 } 265 266 #if defined(PETSC_USE_REAL_DOUBLE) || defined(PETSC_USE_REAL___FLOAT128) 267 typedef double PetscVTKReal; 268 #elif defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL___FP16) 269 typedef float PetscVTKReal; 270 #else 271 typedef PetscReal PetscVTKReal; 272 #endif 273 274 static PetscErrorCode DMPlexVTKWriteSection_ASCII(DM dm, PetscSection section, PetscSection globalSection, Vec v, FILE *fp, PetscInt enforceDof, PetscInt precision, PetscReal scale, PetscInt imag) 275 { 276 MPI_Comm comm; 277 const MPI_Datatype mpiType = MPIU_SCALAR; 278 PetscScalar *array; 279 PetscInt numDof = 0, maxDof; 280 PetscInt numLabelCells, cellHeight, cStart, cEnd, numLabelVertices, vStart, vEnd, pStart, pEnd, p; 281 PetscMPIInt size, rank, proc, tag; 282 PetscBool hasLabel; 283 284 PetscFunctionBegin; 285 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 286 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 287 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 288 if (precision < 0) precision = 6; 289 PetscCall(PetscCommGetNewTag(comm, &tag)); 290 PetscCallMPI(MPI_Comm_size(comm, &size)); 291 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 292 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 293 /* VTK only wants the values at cells or vertices */ 294 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 295 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 296 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 297 pStart = PetscMax(PetscMin(cStart, vStart), pStart); 298 pEnd = PetscMin(PetscMax(cEnd, vEnd), pEnd); 299 PetscCall(DMGetStratumSize(dm, "vtk", 1, &numLabelCells)); 300 PetscCall(DMGetStratumSize(dm, "vtk", 2, &numLabelVertices)); 301 hasLabel = numLabelCells > 0 || numLabelVertices > 0 ? PETSC_TRUE : PETSC_FALSE; 302 for (p = pStart; p < pEnd; ++p) { 303 /* Reject points not either cells or vertices */ 304 if (((p < cStart) || (p >= cEnd)) && ((p < vStart) || (p >= vEnd))) continue; 305 if (hasLabel) { 306 PetscInt value; 307 308 if (((p >= cStart) && (p < cEnd) && numLabelCells) || ((p >= vStart) && (p < vEnd) && numLabelVertices)) { 309 PetscCall(DMGetLabelValue(dm, "vtk", p, &value)); 310 if (value != 1) continue; 311 } 312 } 313 PetscCall(PetscSectionGetDof(section, p, &numDof)); 314 if (numDof) break; 315 } 316 PetscCall(MPIU_Allreduce(&numDof, &maxDof, 1, MPIU_INT, MPI_MAX, comm)); 317 enforceDof = PetscMax(enforceDof, maxDof); 318 PetscCall(VecGetArray(v, &array)); 319 if (rank == 0) { 320 PetscVTKReal dval; 321 PetscScalar val; 322 char formatString[8]; 323 324 PetscCall(PetscSNPrintf(formatString, 8, "%%.%" PetscInt_FMT "e", precision)); 325 for (p = pStart; p < pEnd; ++p) { 326 /* Here we lose a way to filter points by keeping them out of the Numbering */ 327 PetscInt dof, off, goff, d; 328 329 /* Reject points not either cells or vertices */ 330 if (((p < cStart) || (p >= cEnd)) && ((p < vStart) || (p >= vEnd))) continue; 331 if (hasLabel) { 332 PetscInt value; 333 334 if (((p >= cStart) && (p < cEnd) && numLabelCells) || ((p >= vStart) && (p < vEnd) && numLabelVertices)) { 335 PetscCall(DMGetLabelValue(dm, "vtk", p, &value)); 336 if (value != 1) continue; 337 } 338 } 339 PetscCall(PetscSectionGetDof(section, p, &dof)); 340 PetscCall(PetscSectionGetOffset(section, p, &off)); 341 PetscCall(PetscSectionGetOffset(globalSection, p, &goff)); 342 if (dof && goff >= 0) { 343 for (d = 0; d < dof; d++) { 344 if (d > 0) PetscCall(PetscFPrintf(comm, fp, " ")); 345 val = array[off + d]; 346 dval = (PetscVTKReal)((imag ? PetscImaginaryPart(val) : PetscRealPart(val)) * scale); 347 PetscCall(PetscFPrintf(comm, fp, formatString, dval)); 348 } 349 for (d = dof; d < enforceDof; d++) PetscCall(PetscFPrintf(comm, fp, " 0.0")); 350 PetscCall(PetscFPrintf(comm, fp, "\n")); 351 } 352 } 353 for (proc = 1; proc < size; ++proc) { 354 PetscScalar *remoteValues; 355 PetscInt size = 0, d; 356 MPI_Status status; 357 358 PetscCallMPI(MPI_Recv(&size, 1, MPIU_INT, proc, tag, comm, &status)); 359 PetscCall(PetscMalloc1(size, &remoteValues)); 360 PetscCallMPI(MPI_Recv(remoteValues, size, mpiType, proc, tag, comm, &status)); 361 for (p = 0; p < size / maxDof; ++p) { 362 for (d = 0; d < maxDof; ++d) { 363 if (d > 0) PetscCall(PetscFPrintf(comm, fp, " ")); 364 val = remoteValues[p * maxDof + d]; 365 dval = (PetscVTKReal)((imag ? PetscImaginaryPart(val) : PetscRealPart(val)) * scale); 366 PetscCall(PetscFPrintf(comm, fp, formatString, dval)); 367 } 368 for (d = maxDof; d < enforceDof; ++d) PetscCall(PetscFPrintf(comm, fp, " 0.0")); 369 PetscCall(PetscFPrintf(comm, fp, "\n")); 370 } 371 PetscCall(PetscFree(remoteValues)); 372 } 373 } else { 374 PetscScalar *localValues; 375 PetscInt size, k = 0; 376 377 PetscCall(PetscSectionGetStorageSize(section, &size)); 378 PetscCall(PetscMalloc1(size, &localValues)); 379 for (p = pStart; p < pEnd; ++p) { 380 PetscInt dof, off, goff, d; 381 382 /* Reject points not either cells or vertices */ 383 if (((p < cStart) || (p >= cEnd)) && ((p < vStart) || (p >= vEnd))) continue; 384 if (hasLabel) { 385 PetscInt value; 386 387 if (((p >= cStart) && (p < cEnd) && numLabelCells) || ((p >= vStart) && (p < vEnd) && numLabelVertices)) { 388 PetscCall(DMGetLabelValue(dm, "vtk", p, &value)); 389 if (value != 1) continue; 390 } 391 } 392 PetscCall(PetscSectionGetDof(section, p, &dof)); 393 PetscCall(PetscSectionGetOffset(section, p, &off)); 394 PetscCall(PetscSectionGetOffset(globalSection, p, &goff)); 395 if (goff >= 0) { 396 for (d = 0; d < dof; ++d) localValues[k++] = array[off + d]; 397 } 398 } 399 PetscCallMPI(MPI_Send(&k, 1, MPIU_INT, 0, tag, comm)); 400 PetscCallMPI(MPI_Send(localValues, k, mpiType, 0, tag, comm)); 401 PetscCall(PetscFree(localValues)); 402 } 403 PetscCall(VecRestoreArray(v, &array)); 404 PetscFunctionReturn(PETSC_SUCCESS); 405 } 406 407 static PetscErrorCode DMPlexVTKWriteField_ASCII(DM dm, PetscSection section, PetscSection globalSection, Vec field, const char name[], FILE *fp, PetscInt enforceDof, PetscInt precision, PetscReal scale, PetscBool nameComplex, PetscInt imag) 408 { 409 MPI_Comm comm; 410 PetscInt numDof = 0, maxDof; 411 PetscInt pStart, pEnd, p; 412 413 PetscFunctionBegin; 414 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 415 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 416 for (p = pStart; p < pEnd; ++p) { 417 PetscCall(PetscSectionGetDof(section, p, &numDof)); 418 if (numDof) break; 419 } 420 numDof = PetscMax(numDof, enforceDof); 421 PetscCall(MPIU_Allreduce(&numDof, &maxDof, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 422 if (!name) name = "Unknown"; 423 if (maxDof == 3) { 424 if (nameComplex) { 425 PetscCall(PetscFPrintf(comm, fp, "VECTORS %s.%s double\n", name, imag ? "Im" : "Re")); 426 } else { 427 PetscCall(PetscFPrintf(comm, fp, "VECTORS %s double\n", name)); 428 } 429 } else { 430 if (nameComplex) { 431 PetscCall(PetscFPrintf(comm, fp, "SCALARS %s.%s double %" PetscInt_FMT "\n", name, imag ? "Im" : "Re", maxDof)); 432 } else { 433 PetscCall(PetscFPrintf(comm, fp, "SCALARS %s double %" PetscInt_FMT "\n", name, maxDof)); 434 } 435 PetscCall(PetscFPrintf(comm, fp, "LOOKUP_TABLE default\n")); 436 } 437 PetscCall(DMPlexVTKWriteSection_ASCII(dm, section, globalSection, field, fp, enforceDof, precision, scale, imag)); 438 PetscFunctionReturn(PETSC_SUCCESS); 439 } 440 441 static PetscErrorCode DMPlexVTKWriteAll_ASCII(DM dm, PetscViewer viewer) 442 { 443 MPI_Comm comm; 444 PetscViewer_VTK *vtk = (PetscViewer_VTK *)viewer->data; 445 FILE *fp; 446 PetscViewerVTKObjectLink link; 447 PetscInt totVertices, totCells = 0, loops_per_scalar, l; 448 PetscBool hasPoint = PETSC_FALSE, hasCell = PETSC_FALSE, writePartition = PETSC_FALSE, localized, writeComplex; 449 const char *dmname; 450 451 PetscFunctionBegin; 452 #if defined(PETSC_USE_COMPLEX) 453 loops_per_scalar = 2; 454 writeComplex = PETSC_TRUE; 455 #else 456 loops_per_scalar = 1; 457 writeComplex = PETSC_FALSE; 458 #endif 459 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 460 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 461 PetscCheck(!localized, comm, PETSC_ERR_SUP, "VTK output with localized coordinates not yet supported"); 462 PetscCall(PetscFOpen(comm, vtk->filename, "wb", &fp)); 463 PetscCall(PetscObjectGetName((PetscObject)dm, &dmname)); 464 PetscCall(PetscFPrintf(comm, fp, "# vtk DataFile Version 2.0\n")); 465 PetscCall(PetscFPrintf(comm, fp, "%s\n", dmname)); 466 PetscCall(PetscFPrintf(comm, fp, "ASCII\n")); 467 PetscCall(PetscFPrintf(comm, fp, "DATASET UNSTRUCTURED_GRID\n")); 468 /* Vertices */ 469 { 470 PetscSection section, coordSection, globalCoordSection; 471 Vec coordinates; 472 PetscReal lengthScale; 473 DMLabel label; 474 IS vStratumIS; 475 PetscLayout vLayout; 476 477 PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale)); 478 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 479 PetscCall(DMPlexGetDepthLabel(dm, &label)); 480 PetscCall(DMLabelGetStratumIS(label, 0, &vStratumIS)); 481 PetscCall(DMGetCoordinateSection(dm, §ion)); /* This section includes all points */ 482 PetscCall(PetscSectionCreateSubdomainSection(section, vStratumIS, &coordSection)); /* This one includes just vertices */ 483 PetscCall(PetscSectionCreateGlobalSection(coordSection, dm->sf, PETSC_FALSE, PETSC_FALSE, &globalCoordSection)); 484 PetscCall(PetscSectionGetPointLayout(comm, globalCoordSection, &vLayout)); 485 PetscCall(PetscLayoutGetSize(vLayout, &totVertices)); 486 PetscCall(PetscFPrintf(comm, fp, "POINTS %" PetscInt_FMT " double\n", totVertices)); 487 PetscCall(DMPlexVTKWriteSection_ASCII(dm, coordSection, globalCoordSection, coordinates, fp, 3, PETSC_DETERMINE, lengthScale, 0)); 488 PetscCall(ISDestroy(&vStratumIS)); 489 PetscCall(PetscLayoutDestroy(&vLayout)); 490 PetscCall(PetscSectionDestroy(&coordSection)); 491 PetscCall(PetscSectionDestroy(&globalCoordSection)); 492 } 493 /* Cells */ 494 PetscCall(DMPlexVTKWriteCells_ASCII(dm, fp, &totCells)); 495 /* Vertex fields */ 496 for (link = vtk->link; link; link = link->next) { 497 if ((link->ft == PETSC_VTK_POINT_FIELD) || (link->ft == PETSC_VTK_POINT_VECTOR_FIELD)) hasPoint = PETSC_TRUE; 498 if ((link->ft == PETSC_VTK_CELL_FIELD) || (link->ft == PETSC_VTK_CELL_VECTOR_FIELD)) hasCell = PETSC_TRUE; 499 } 500 if (hasPoint) { 501 PetscCall(PetscFPrintf(comm, fp, "POINT_DATA %" PetscInt_FMT "\n", totVertices)); 502 for (link = vtk->link; link; link = link->next) { 503 Vec X = (Vec)link->vec; 504 PetscSection section = NULL, globalSection, newSection = NULL; 505 char namebuf[256]; 506 const char *name; 507 PetscInt enforceDof = PETSC_DETERMINE; 508 509 if ((link->ft != PETSC_VTK_POINT_FIELD) && (link->ft != PETSC_VTK_POINT_VECTOR_FIELD)) continue; 510 if (link->ft == PETSC_VTK_POINT_VECTOR_FIELD) enforceDof = 3; 511 PetscCall(PetscObjectGetName(link->vec, &name)); 512 PetscCall(PetscObjectQuery(link->vec, "section", (PetscObject *)§ion)); 513 if (!section) { 514 DM dmX; 515 516 PetscCall(VecGetDM(X, &dmX)); 517 if (dmX) { 518 DMLabel subpointMap, subpointMapX; 519 PetscInt dim, dimX, pStart, pEnd, qStart, qEnd; 520 521 PetscCall(DMGetLocalSection(dmX, §ion)); 522 /* Here is where we check whether dmX is a submesh of dm */ 523 PetscCall(DMGetDimension(dm, &dim)); 524 PetscCall(DMGetDimension(dmX, &dimX)); 525 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 526 PetscCall(DMPlexGetChart(dmX, &qStart, &qEnd)); 527 PetscCall(DMPlexGetSubpointMap(dm, &subpointMap)); 528 PetscCall(DMPlexGetSubpointMap(dmX, &subpointMapX)); 529 if (((dim != dimX) || ((pEnd - pStart) < (qEnd - qStart))) && subpointMap && !subpointMapX) { 530 const PetscInt *ind = NULL; 531 IS subpointIS; 532 PetscInt n = 0, q; 533 534 PetscCall(PetscSectionGetChart(section, &qStart, &qEnd)); 535 PetscCall(DMPlexGetSubpointIS(dm, &subpointIS)); 536 if (subpointIS) { 537 PetscCall(ISGetLocalSize(subpointIS, &n)); 538 PetscCall(ISGetIndices(subpointIS, &ind)); 539 } 540 PetscCall(PetscSectionCreate(comm, &newSection)); 541 PetscCall(PetscSectionSetChart(newSection, pStart, pEnd)); 542 for (q = qStart; q < qEnd; ++q) { 543 PetscInt dof, off, p; 544 545 PetscCall(PetscSectionGetDof(section, q, &dof)); 546 if (dof) { 547 PetscCall(PetscFindInt(q, n, ind, &p)); 548 if (p >= pStart) { 549 PetscCall(PetscSectionSetDof(newSection, p, dof)); 550 PetscCall(PetscSectionGetOffset(section, q, &off)); 551 PetscCall(PetscSectionSetOffset(newSection, p, off)); 552 } 553 } 554 } 555 if (subpointIS) PetscCall(ISRestoreIndices(subpointIS, &ind)); 556 /* No need to setup section */ 557 section = newSection; 558 } 559 } 560 } 561 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Vector %s had no PetscSection composed with it and could not create one from VecGetDM()", name); 562 if (link->field >= 0) { 563 const char *fieldname; 564 565 PetscCall(PetscSectionGetFieldName(section, link->field, &fieldname)); 566 PetscCall(PetscSectionGetField(section, link->field, §ion)); 567 if (fieldname) { 568 PetscCall(PetscSNPrintf(namebuf, sizeof(namebuf), "%s%s", name, fieldname)); 569 } else { 570 PetscCall(PetscSNPrintf(namebuf, sizeof(namebuf), "%s%" PetscInt_FMT, name, link->field)); 571 } 572 } else { 573 PetscCall(PetscSNPrintf(namebuf, sizeof(namebuf), "%s", name)); 574 } 575 PetscCall(PetscViewerVTKSanitizeName_Internal(namebuf, sizeof(namebuf))); 576 PetscCall(PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 577 for (l = 0; l < loops_per_scalar; l++) PetscCall(DMPlexVTKWriteField_ASCII(dm, section, globalSection, X, namebuf, fp, enforceDof, PETSC_DETERMINE, 1.0, writeComplex, l)); 578 PetscCall(PetscSectionDestroy(&globalSection)); 579 if (newSection) PetscCall(PetscSectionDestroy(&newSection)); 580 } 581 } 582 /* Cell Fields */ 583 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_partition", &writePartition, NULL)); 584 if (hasCell || writePartition) { 585 PetscCall(PetscFPrintf(comm, fp, "CELL_DATA %" PetscInt_FMT "\n", totCells)); 586 for (link = vtk->link; link; link = link->next) { 587 Vec X = (Vec)link->vec; 588 PetscSection section = NULL, globalSection; 589 const char *name = ""; 590 char namebuf[256]; 591 PetscInt enforceDof = PETSC_DETERMINE; 592 593 if ((link->ft != PETSC_VTK_CELL_FIELD) && (link->ft != PETSC_VTK_CELL_VECTOR_FIELD)) continue; 594 if (link->ft == PETSC_VTK_CELL_VECTOR_FIELD) enforceDof = 3; 595 PetscCall(PetscObjectGetName(link->vec, &name)); 596 PetscCall(PetscObjectQuery(link->vec, "section", (PetscObject *)§ion)); 597 if (!section) { 598 DM dmX; 599 600 PetscCall(VecGetDM(X, &dmX)); 601 if (dmX) PetscCall(DMGetLocalSection(dmX, §ion)); 602 } 603 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Vector %s had no PetscSection composed with it and could not create one from VecGetDM()", name); 604 if (link->field >= 0) { 605 const char *fieldname; 606 607 PetscCall(PetscSectionGetFieldName(section, link->field, &fieldname)); 608 PetscCall(PetscSectionGetField(section, link->field, §ion)); 609 if (fieldname) { 610 PetscCall(PetscSNPrintf(namebuf, sizeof(namebuf), "%s%s", name, fieldname)); 611 } else { 612 PetscCall(PetscSNPrintf(namebuf, sizeof(namebuf), "%s%" PetscInt_FMT, name, link->field)); 613 } 614 } else { 615 PetscCall(PetscSNPrintf(namebuf, sizeof(namebuf), "%s", name)); 616 } 617 PetscCall(PetscViewerVTKSanitizeName_Internal(namebuf, sizeof(namebuf))); 618 PetscCall(PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 619 for (l = 0; l < loops_per_scalar; l++) PetscCall(DMPlexVTKWriteField_ASCII(dm, section, globalSection, X, namebuf, fp, enforceDof, PETSC_DETERMINE, 1.0, writeComplex, l)); 620 PetscCall(PetscSectionDestroy(&globalSection)); 621 } 622 if (writePartition) { 623 PetscCall(PetscFPrintf(comm, fp, "SCALARS partition int 1\n")); 624 PetscCall(PetscFPrintf(comm, fp, "LOOKUP_TABLE default\n")); 625 PetscCall(DMPlexVTKWritePartition_ASCII(dm, fp)); 626 } 627 } 628 /* Cleanup */ 629 PetscCall(PetscFClose(comm, fp)); 630 PetscFunctionReturn(PETSC_SUCCESS); 631 } 632 633 /*@C 634 DMPlexVTKWriteAll - Write a file containing all the fields that have been provided to the viewer 635 636 Collective 637 638 Input Parameters: 639 + odm - The `DMPLEX` specifying the mesh, passed as a `PetscObject` 640 - viewer - viewer of type `PETSCVIEWERVTK` 641 642 Level: developer 643 644 Note: 645 This function is a callback used by the VTK viewer to actually write the file. 646 The reason for this odd model is that the VTK file format does not provide any way to write one field at a time. 647 Instead, metadata for the entire file needs to be available up-front before you can start writing the file. 648 649 .seealso: [](chapter_unstructured), `DM`, `PETSCVIEWEREXODUSII`, `DMPLEX`, `PETSCVIEWERVTK` 650 @*/ 651 PetscErrorCode DMPlexVTKWriteAll(PetscObject odm, PetscViewer viewer) 652 { 653 DM dm = (DM)odm; 654 655 PetscFunctionBegin; 656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 657 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 2, PETSCVIEWERVTK); 658 switch (viewer->format) { 659 case PETSC_VIEWER_ASCII_VTK_DEPRECATED: 660 PetscCall(DMPlexVTKWriteAll_ASCII(dm, viewer)); 661 break; 662 case PETSC_VIEWER_VTK_VTU: 663 PetscCall(DMPlexVTKWriteAll_VTU(dm, viewer)); 664 break; 665 default: 666 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]); 667 } 668 PetscFunctionReturn(PETSC_SUCCESS); 669 } 670