diff --git a/IO/Geometry/vtkOpenFOAMReader.cxx b/IO/Geometry/vtkOpenFOAMReader.cxx index b73fe246522262ce575392dff277ad3333b25108..a78e1be0e1b1b3fffb6596a2d8c5026c8a95ef29 100644 --- a/IO/Geometry/vtkOpenFOAMReader.cxx +++ b/IO/Geometry/vtkOpenFOAMReader.cxx @@ -6710,6 +6710,9 @@ bool vtkOpenFOAMReaderPrivate::ReadOwnerNeighbourFiles(const std::string& timeRe } const bool use64BitLabels = io.IsLabel64(); + // Count cells by tracking the max cell id seen + vtkTypeInt64 nCells = -1; + { vtkFoamEntryValue ownerDict(nullptr); ownerDict.SetStreamOption(io); @@ -6738,8 +6741,7 @@ bool vtkOpenFOAMReaderPrivate::ReadOwnerNeighbourFiles(const std::string& timeRe this->FaceOwner = ownerDict.ReleasePtr<vtkDataArray>(); const vtkIdType nFaces = this->FaceOwner->GetNumberOfTuples(); - // Count cells, check validity - vtkTypeInt64 nCells = -1; + // Check for max cell, check validity for (vtkIdType facei = 0; facei < nFaces; ++facei) { const vtkTypeInt64 celli = GetLabelValue(this->FaceOwner, facei, use64BitLabels); @@ -6753,8 +6755,6 @@ bool vtkOpenFOAMReaderPrivate::ReadOwnerNeighbourFiles(const std::string& timeRe nCells = celli; // <- max(nCells, celli) } } - - this->NumCells = static_cast<vtkIdType>(++nCells); } // Read polyMesh/neighbour @@ -6816,23 +6816,27 @@ bool vtkOpenFOAMReaderPrivate::ReadOwnerNeighbourFiles(const std::string& timeRe } this->FaceNeigh->Resize(nInternalFaces); } - else - { - // Check validity - const vtkIdType nInternalFaces = this->FaceNeigh->GetNumberOfTuples(); - for (vtkIdType facei = 0; facei < nInternalFaces; ++facei) + const vtkIdType nInternalFaces = this->FaceNeigh->GetNumberOfTuples(); + + // Check for max cell, check validity + for (vtkIdType facei = 0; facei < nInternalFaces; ++facei) + { + const vtkTypeInt64 celli = GetLabelValue(this->FaceNeigh, facei, use64BitLabels); + if (celli < 0) { - const vtkTypeInt64 celli = GetLabelValue(this->FaceNeigh, facei, use64BitLabels); - if (celli < 0) - { - vtkErrorMacro(<< "Illegal cell label in neighbour addressing. Face " << facei); - return false; - } + vtkErrorMacro(<< "Illegal cell label in neighbour addressing. Face " << facei); + return false; + } + if (nCells < celli) + { + nCells = celli; // <- max(nCells, celli) } } } + this->NumCells = static_cast<vtkIdType>(++nCells); + // Size checks if (this->NumCells == 0) { @@ -6906,6 +6910,14 @@ std::unique_ptr<vtkFoamLabelListList> vtkOpenFOAMReaderPrivate::CreateCellFaces( nCells = celli; // <- max(nCells, celli) } } + for (vtkIdType facei = 0; facei < nInternalFaces; ++facei) + { + const vtkTypeInt64 celli = GetLabelValue(&faceNeigh, facei, use64BitLabels); + if (nCells < celli) + { + nCells = celli; // <- max(nCells, celli) + } + } // Set the number of cells this->NumCells = static_cast<vtkIdType>(++nCells); @@ -7168,6 +7180,9 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( // Jordan, with lots of improvements. Not as elegant as the one in // OpenFOAM but it's simple and works reasonably fast. + // Note: faces are flipped around their 0 point (as per OpenFOAM) + // to keep predicable face point ordering + // OpenFOAM "hex" | vtkHexahedron if (cellType == VTK_HEXAHEDRON) { @@ -7180,16 +7195,17 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( meshFaces.GetCell(cellFacei, facePoints); // Add face0 to cell points - flip owner to point inwards + cellPoints[nCellPoints++] = facePoints[0]; if (isOwner) { - for (int fp = 3; fp >= 0; --fp) + for (int fp = 3; fp > 0; --fp) { cellPoints[nCellPoints++] = facePoints[fp]; } } else { - for (int fp = 0; fp < 4; ++fp) + for (int fp = 1; fp < 4; ++fp) { cellPoints[nCellPoints++] = facePoints[fp]; } @@ -7346,16 +7362,17 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( // Add face0 to cell points - flip neighbour to point outwards // - OpenFOAM face0 points inwards // - VTK face0 points outwards + cellPoints[nCellPoints++] = facePoints[0]; if (isOwner) { - for (int fp = 0; fp < 3; ++fp) + for (int fp = 1; fp < 3; ++fp) { cellPoints[nCellPoints++] = facePoints[fp]; } } else { - for (int fp = 2; fp >= 0; --fp) + for (int fp = 2; fp > 0; --fp) { cellPoints[nCellPoints++] = facePoints[fp]; } @@ -7508,8 +7525,7 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( // OpenFOAM "pyr" | vtkPyramid || OpenFOAM "tet" | vtkTetrahedron else if (cellType == VTK_PYRAMID || cellType == VTK_TETRA) { - const vtkIdType nCellPoints = (cellType == VTK_PYRAMID ? 5 : 4); - + int nCellPoints = 0; int baseFaceId = 0; if (cellType == VTK_PYRAMID) { @@ -7531,18 +7547,19 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( meshFaces.GetCell(cellFacei, facePoints); const size_t nFacePoints = facePoints.size(); + cellPoints[nCellPoints++] = facePoints[0]; if (isOwner) { - for (size_t fp = 0, endp = nFacePoints - 1; fp < nFacePoints; ++fp, --endp) + for (size_t fp = nFacePoints - 1; fp > 0; --fp) { - cellPoints[fp] = facePoints[endp]; + cellPoints[nCellPoints++] = facePoints[fp]; } } else { - for (size_t fp = 0; fp < nFacePoints; ++fp) + for (size_t fp = 1; fp < nFacePoints; ++fp) { - cellPoints[fp] = facePoints[fp]; + cellPoints[nCellPoints++] = facePoints[fp]; } } } @@ -7570,7 +7587,7 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( } // ... and add the apex-point - cellPoints[nCellPoints - 1] = apexMeshPointi; + cellPoints[nCellPoints++] = apexMeshPointi; // Add tetra or pyramid to the mesh internalMesh->InsertNextCell(cellType, nCellPoints, cellPoints.data()); @@ -7653,9 +7670,12 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( pointArray->InsertNextTuple(centroid); // polyhedron decomposition. - // a tweaked algorithm based on applications/utilities/postProcessing/ - // graphics/PVFoamReader/vtkFoam/vtkFoamAddInternalMesh.C - bool insertDecomposedCell = true; + // a tweaked algorithm based on OpenFOAM + // src/fileFormats/vtk/part/foamVtuSizingTemplates.C + + // TODO: improve consistency of face point ordering. + // - currently just flips the faces without preserving the face point 0 order. + bool firstCell = true; int nAdditionalCells = 0; for (size_t facei = 0; facei < cellFaces.size(); ++facei) { @@ -7699,10 +7719,9 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( cellPoints[0] = facePoints[(vertI == 2) ? static_cast<vtkIdType>(0) : static_cast<vtkIdType>(nFacePoints - 1)]; - cellPoints[4] = static_cast<vtkIdType>(this->NumPoints + nAdditionalPoints); + cellPoints[4] = static_cast<vtkIdType>(this->NumPoints + nAdditionalPoints); // apex - // decompose a face into quads in order (flipping the - // decomposed face if owner) + // Decompose a face into quads in order (flipping decomposed face if owner) const size_t nQuadVerts = nFacePoints - 1 - nTris; for (; vertI < nQuadVerts; vertI += 2) { @@ -7710,13 +7729,12 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( cellPoints[2] = facePoints[vertI]; cellPoints[3] = facePoints[vertI + flipNeighbor]; - // if the decomposed cell is the first one insert it to - // the original position; or append to the decomposed cell - // list otherwise - if (insertDecomposedCell) + // Insert first decomposed cell into the original position, + // subsequent ones are appended to the decomposed cell list + if (firstCell) { + firstCell = false; internalMesh->InsertNextCell(VTK_PYRAMID, 5, cellPoints.data()); - insertDecomposedCell = false; } else { @@ -7728,7 +7746,7 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( // if the number of vertices is odd there's a triangle if (nTris) { - if (flipNeighbor == -1) + if (flipNeighbor == -1) // isOwner { cellPoints[1] = facePoints[vertI]; cellPoints[2] = facePoints[vertI - 1]; @@ -7740,10 +7758,12 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( } cellPoints[3] = static_cast<vtkIdType>(this->NumPoints + nAdditionalPoints); - if (insertDecomposedCell) + // Insert first decomposed cell into the original position, + // subsequent ones are appended to the decomposed cell list + if (firstCell) { + firstCell = false; internalMesh->InsertNextCell(VTK_TETRA, 4, cellPoints.data()); - insertDecomposedCell = false; } else { @@ -7770,8 +7790,10 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( // - use nPolyPoints to estimate unique cell points // (assume a point connects at least three faces) - cellPoints.fast_reserve(nPolyPoints / 3); - polyPoints.fast_reserve(nPolyPoints + cellFaces.size()); + cellPoints.copy_resize(0); + polyPoints.copy_resize(0); + cellPoints.copy_reserve(nPolyPoints / 3); + polyPoints.copy_reserve(nPolyPoints + cellFaces.size()); size_t nCellPoints = 0; nPolyPoints = 0; // Reset @@ -7783,46 +7805,51 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( (cellId == GetLabelValue(this->FaceOwner, cellFacei, faceOwner64Bit)); meshFaces.GetCell(cellFacei, facePoints); const size_t nFacePoints = facePoints.size(); + size_t nUnique = 0; + + // Pass 1: add face points, and mark up duplicates on the way - // Local face point indexing - must be signed - // Flip direction for neighbour face - int facePointi = (isOwner ? 0 : static_cast<int>(nFacePoints) - 1); - const int faceDirn = (isOwner ? 1 : -1); + polyPoints.copy_resize(nPolyPoints + nFacePoints + 1); + polyPoints[nPolyPoints++] = static_cast<vtkIdType>(nFacePoints); - if (!nCellPoints && !nPolyPoints) + if (!nFacePoints) { - // First face - add directly (no duplicate points) - cellPoints.copy_resize(nCellPoints + nFacePoints); - polyPoints.copy_resize(nPolyPoints + nFacePoints + 1); + continue; + } - // Add face to cell points, and to polyPoints - polyPoints[nPolyPoints++] = static_cast<vtkIdType>(nFacePoints); - for (size_t fp = 0; fp < nFacePoints; ++fp, facePointi += faceDirn) + // Add face point 0 + { + const auto meshPointi = static_cast<vtkIdType>(facePoints[0]); + polyPoints[nPolyPoints++] = meshPointi; + bool isUnique = true; + for (size_t cp = 0; isUnique && cp < nCellPoints; ++cp) { - const auto meshPointi = static_cast<vtkIdType>(facePoints[facePointi]); - cellPoints[nCellPoints++] = meshPointi; - polyPoints[nPolyPoints++] = meshPointi; + isUnique = (meshPointi != cellPoints[cp]); + } + if (isUnique) + { + ++nUnique; + } + else + { + facePoints[0] = -1; // Duplicate } } - else - { - // Subsequent faces - avoid duplicate points - // Pass 1: add face points, and mark up any duplicates too - // Grow if needed, preserve content - polyPoints.copy_resize(nPolyPoints + nFacePoints + 1); + // Add other face points + { + // Local face point indexing - must be signed + const int faceDirn = (isOwner ? 1 : -1); // Flip direction for neighbour face + int facePointi = (isOwner ? 1 : static_cast<int>(nFacePoints) - 1); - // Add face to poly (face) points - polyPoints[nPolyPoints++] = static_cast<vtkIdType>(nFacePoints); - size_t nUnique = 0; - for (size_t fp = 0; fp < nFacePoints; ++fp, facePointi += faceDirn) + for (size_t fp = 1; fp < nFacePoints; ++fp, facePointi += faceDirn) { const auto meshPointi = static_cast<vtkIdType>(facePoints[facePointi]); polyPoints[nPolyPoints++] = meshPointi; bool isUnique = true; for (size_t cp = 0; isUnique && cp < nCellPoints; ++cp) { - isUnique = (cellPoints[cp] != meshPointi); + isUnique = (meshPointi != cellPoints[cp]); } if (isUnique) { @@ -7833,18 +7860,17 @@ void vtkOpenFOAMReaderPrivate::InsertCellsToGrid( facePoints[facePointi] = -1; // Duplicate } } + } - // Grow if needed, preserve content - cellPoints.copy_resize(nCellPoints + nUnique); + cellPoints.copy_resize(nCellPoints + nUnique); - // Pass 2: add unique cell points - order is arbitrary - for (size_t fp = 0; fp < nFacePoints; ++fp) + // Pass 2: add unique cell points - order is arbitrary + for (size_t fp = 0; fp < nFacePoints; ++fp) + { + const auto meshPointi = static_cast<vtkIdType>(facePoints[fp]); + if (meshPointi != -1) // isUnique { - const auto meshPointi = static_cast<vtkIdType>(facePoints[fp]); - if (meshPointi != -1) // isUnique - { - cellPoints[nCellPoints++] = meshPointi; - } + cellPoints[nCellPoints++] = meshPointi; } } } @@ -8550,7 +8576,7 @@ vtkSmartPointer<vtkFloatArray> vtkOpenFOAMReaderPrivate::FillField(vtkFoamEntry& } else { - vtkErrorMacro(<< "Wrong list type for uniform field"); + vtkErrorMacro(<< "Wrong list type for uniform field: " << io.GetObjectName()); return nullptr; } @@ -8567,7 +8593,7 @@ vtkSmartPointer<vtkFloatArray> vtkOpenFOAMReaderPrivate::FillField(vtkFoamEntry& } else { - vtkErrorMacro(<< "Number of components and field class doesn't match " + vtkErrorMacro(<< "Number of components and field class do not match " << "for " << io.GetFileName() << ". class = " << className << ", nComponents = " << nComponents); return nullptr; @@ -8584,8 +8610,9 @@ vtkSmartPointer<vtkFloatArray> vtkOpenFOAMReaderPrivate::FillField(vtkFoamEntry& const vtkIdType nTuples = entry.ScalarList().GetNumberOfTuples(); if (nTuples != nElements) { - vtkErrorMacro(<< "Number of cells/points in mesh and field don't match: " - << "mesh = " << nElements << ", field = " << nTuples); + vtkErrorMacro(<< "Number of cells/points in mesh and field do not match: " + << "mesh = " << nElements << ", field = " << nTuples << " in " + << io.GetObjectName()); return nullptr; }