vtkHDF: Add support for polyhedron cells

we converge with @MicK7 @Dieke and some others folks about what the spec could be.

AFAIK nothing more that what we talk in this discourse post has been made so the next step will be to write it in the spec directly, then we can see to support it in the vtkHDFReader/Writer. Unfortunately, I personally don’t have funding for this.

longBox.hdf (1.3 MB)
To contribute to the discussion, I have uploaded a VTKHDF file containing MultiBlockData. This file contains 13 Blocks with face data.
Each block contains the connectivity, offsets and types. Further cell1 and (where applicable) cell2 DataSets are provided denoting the cells a face contributes to (cell2 is in reverse order).

This file can be displayed in ParaView.

With the programmable source below, the corresponding polyhedrons can be created and displayed. There might be still room for improvement.

Maybe it is possible to implement something similar in the VTKHDFreader.

Greetings Dieke

import vtk
reader = vtk.vtkHDFReader()
reader.SetFileName('longBox.hdf')
reader.Update()  # Needed because of GetScalarRange
blocks =reader.GetOutput()


cells =  {}
for iBlock in range(blocks.GetNumberOfBlocks()):
   block = blocks.GetBlock(iBlock).GetBlock(0)

   # only blocks with cell1/2 DataSet are considered

   cell1 = block.GetCellData().GetArray('cell1')
   cell2 = block.GetCellData().GetArray('cell2')
   for i in range(cell1.GetNumberOfValues()):
      icell = cell1.GetValue(i)
      ids = block.GetCell(i).GetPointIds()
      c = []
      for p in range(ids.GetNumberOfIds()):
         c.append(block.GetCell(i).GetPointId(p))
      if not icell in cells: cells[icell] = []
      cells[icell].append(c)
      c = []
      if cell2:
        icell = cell2.GetValue(i)
        ids = block.GetCell(i).GetPointIds()
        c = []
        for p in range(ids.GetNumberOfIds(),0,-1):
          c.append(block.GetCell(i).GetPointId(p-1))
        if not icell in cells: cells[icell] = []
        cells[icell].append(c)

# create the unstructured grid with polyhedra

output = vtk.vtkUnstructuredGrid()
output.Initialize()
output.Allocate(len(cells))
points = blocks.GetBlock(0).GetBlock(0).GetPoints()
output.SetPoints(points)

for key in sorted(cells.keys()):

   faceIds = vtk.vtkIdList()
   cell = cells[key]
   print(key,len(cell))
   poly = vtk.vtkPolyhedron()
   poly.Initialize()
   faceIds.InsertNextId(len(cell))
   for c  in cell:
      faceIds.InsertNextId(len(c))
      for p in c:
         faceIds.InsertNextId(p)
   output.InsertNextCell(vtk.VTK_POLYHEDRON, faceIds)

Although VTK doesn’t currently support non-simple polygons/polyhedra (i.e. with holes/voids and concavities), is there any thought to the file format supporting them?

currently we have an issue with what the file format could be in VTK:

https://gitlab.kitware.com/vtk/vtk/-/issues/19228

Some improvement could be done later with compact storage version, see https://gitlab.kitware.com/vtk/vtk/-/issues/19228

Based on my previous post I have an proposal for a specification to implement polyhedral.

The main addition is the introduction of a CellAssembly group in to the vtkUnstructuredGrid connectivity. This group contains links to vtkUnstructuredGrids with polygons.

The polygon vtkUnstructuredGrids should have a CellData cell1 and may have a CellData cell2.

CellData cell1 denotes the owner cell of the faces. The owner cells are always in the same partition as the respective faces. A CellData cell2 denotes the neighbour cells. The faces must be used in reverse vertex order for the neighbour cells. The partition of a neighbour cell may differ from the face but can be easily determined by the cell number.

My recommendation would be to separate the faces having owner and neighbour (internal faces) from those having only an owner (in most cases boundary face) into different grids. It is also possible to mark missing neighbour in cell2 array by negative numbers.

For post processing purposes it might be advisable to use one grid per boundary condition.

The polyhedron grid and the polygon grids should refer to the same Points and PointData.

The polyhedron grid can by this definition hold only polyhedron cells. But this seem to me a small limitation. In return we get a space efficient file format with little overhead.

Below is a sketch of the proposed dependencies.
vtkhdf-polyhedron

1 Like

I have prepared an example file. The 2D Groups can be displayed in paraview.
boxHangingNodes.hdf (396.4 KB)

It will definitively be useful when someone will try to support it in the VTKHDF File Format and in the reader/writer.

Is it possible to add the output of the h5dump in a .txt ?

h5dfdump.txt (19.8 KB)
There you go!

1 Like

The specification you’ve linked does not have any support for non-simple polygons/polyhedra. That would require additional arrays, so that

  • a polyhedron is a collection of one or more oriented shells (one outer shell with its orientation chosen to produce outward-pointing normals and zero or more inner shells with their orientations chosen to produce inward-pointing normals).
  • each shell is a collection of facets, oriented so all the facets in the shell have the same normal direction (all inward or all outward).
  • each facet is a collection of one or more oriented edge-loops (one outer loop with its orientation chosen to produce a counter-clockwise (CCW) set of edges; and zero or more inner loops with their orientations chosen to produce clockwise (CW) edges).
  • each loop is a collection of one or more oriented wires chosen so that they form a closed loop of head-to-tail segments.
  • each wire is a collection of two or more vertices.

The data structure in the link above presumes that there is only one shell (the outer shell) and each polygonal facet has a single loop (the outer loop). Adding the concepts of multiple shells and loops would be required to handle non-simple polyhedra. You might plan for this in advance by renaming PolygonConnectivity to SimplePolygonConnectivity and PolyhedronToFaces to SimplePolyhedronFaces, respectively. That way, support can be added later to include shell and loop connectivity in additional (non-simple) arrays.

Also, I am unsure why both Connectivity and PolyhedronToFaces exist. It seems that the PolyhedronToFaces/PolyhedronOffsets arrays are enough to specify a collection of simple polyhedra (since PolygonConnectivity/PolygonOffsets provide vertex connectivity for each of the faces making up a single polyhedron).