vtkHDF: Add support for polyhedron cells

The idea would be to add support for polyhedral cell in a partition of unstructured grid stored in vtkHDF

The partition sizing for polyhedral cells would required defining the following variables:

  • NumberOfFaces
  • NumberOfFaceConnectivityIds
  • NumberOfPolyhedronToFaceIds

We can then compute the size of partition i using the following formulas:

Size of partition i
Points NumberOfPoints[i] * 3 * sizeof(Points[0][0])
Connectivity NumberOfConnectivityIds[i] * sizeof(Connectivity[0])
Offsets (NumberOfCells[i] + 1) * sizeof(Offsets[0])
Types NumberOfCells[i] * sizeof(Types[i])
FaceConnectivity NumberOfFaceConnectivityIds[i] * sizeof(FaceConnectivity[i])
FaceOffsets (NumberOfFaces[i] + 1) * sizeof(FaceOffsets[i])
PolyhedronToFaces NumberOfPolyhedronToFaceIds[i] * sizeof(PolyhedronToFace[0])
PolyhedronOffsets (NumberOfCells[i] + 1) * sizeof(PolyhedronOffsets[0])
PointData NumberOfPoints[i] * sizeof(point_array_k[0])
CellData NumberOfCells[i] * sizeof(cell_array_k[0])

The issue is that PolyhedronToFaces and PolyhedronOffsets can easily be splitted in partition but it is less obvious for the PolygonOffsets (or FaceOffsets) and PolygonConnectivity (or FaceConnectivity).

@Louis_Gombert @Charles_Gueunet @lgivord @danlipsa @jfausty

Hello @MicK7

I think there is a type in the description at the end, regarding the PolyhedonFaces array as it is not mention in your diagram above.

I also have a question, what is the array PolyhedonOffsets here ? I am not sure why we need this entry.

Best,
Charles

1 Like

@Charles_Gueunet Yes it was a typo.
PolyhedronOffsets is an array that provide the position of a polyhedron start in the PolyhedronToFaces array as well as the number of face of a polyhedron.
It is sized following the number of unstructured cells meaning it stores useless information about non polyhedral cells (They have a zero size). Maybe it could be sized along a NumberOfPolyhedronCells to keep only relevant data and minimize disk space but then it will need a bit of computation on CPU side during write and load to build a mapping.
The behavor mimics the Connectivity + Offsets.

2 Likes

Indeed there is no way with the current vtkHDF File Format to store vtkPolyhedron and your proposal looks really great.

I assume that these new fields will be stored as DataSet (to facilitate future support of transient data for polyhedron).

Also I prefer using FaceOffsets/Connectivity than PolygonOffsets/Conenctivity for naming as it suits better based on the vtkPolyhedron API

wdyt?

1 Like

Yes the new field should be DataSet for transient data.
I don’t have a preference about the naming and it sounds good to use FaceOffsets/Connectivity like in the API.

I will update the proposal.

Concerning the field:
NumberOfFaces
NumberOfFaceConnectivityIds
NumberOfPolyhedronToFaceIds

Is it possible to have them optional, in case no polyhedron are present in the unstructured grid ? Or should they always be there with a zero value ?

Thanks @MicK7

Is it possible to have them optional?

In this context yes it could be optional (FYI we already have optional field (like NumberOfPart))

Have you any other question regarding the support of vtkPolyhedron in vtkHDF File Format?

Thanks with a delay for answering my doubts

1 Like

Hello,

I learned that the storing of polyhedron data is in the implementation phase. Maybe I am in time to suggest an additional space reducing format for polyhedra.
In our code we are storing the polyhedron topology information in two CSR array combinations.
The first array contains the offsets and the vertices of the faces, the second array stores the offsets and the reference to the faces in the first array.
In a simple example with two hexahedra it looks like this

  6 ---  5 ---  11
 / |     /       /|
/  |    /       / |
7 ---  4 --- 10   |
|  /2  | 1    |  / 9
| /    |      | / 
|/     |      |/
3 ---  0 --- 8

The face connectivity would look like the
0 3 2 1 #Face 0
0 1 5 4 #Face 1
1 2 6 5 #Face 2
2 3 7 6 #Face 3
0 4 7 3 #Face 5
4 5 6 7 # Face 6

8 0 1 9 #Face 7
8 9 11 10 #Face 8
9 1 5 11 #Face 9
0 8 10 4 # Face 10
10 11 5 4 #Face 11
The offsets would be
0,4,8,12 …
The faces of the polyhedra would be
0 1 2 3 4 5 6 # Hexahedron 1
7 8 9 -1 10 11 # Hexadron 2
The offsets would be
0 6 12

A negative face index indicate a face in negative orientation. The advantage is that connecting faces are stored only once.
Is it possible to consider this type of storage (or something similar) in VTKHDF?

Thanks for your great work!

Dieke

Hello @Dieke,

We converged to the design proposed by @MicK7 but AFAIK nobody currently implement it, so design suggestions/improvements are always welcome :slightly_smiling_face:

IMO there is no limitation in your use case for VTKHDF, regarding polyhedron itself I’m not an expert on such cell type, but @Charles_Gueunet and/or @MicK7 may have some inputs.

Best

@Dieke Thanks for your suggestion.
Your proposal make a lot of sense and cleverly optimize disk space.

In vtk case we start the numbering of faces at 0 for the polyhedron.
This mean that face 0 can have only one orientation according
to your scheme and the orientation is undefined.
This could be solved by managing a 1 offset after/before (un)signing the face during reading/writing.

For the writing, the issue is that we will need to compute the connected faces and sort them out before storing the data. This could be costly for huge simulation as vtk does not have the connection information already. Or it is well hidden…

@Charles_Gueunet any idea how vtk can handle shared or connected faces ?

Thanks for the quick answer and considering my idea. We are using a 1-based scheme so negative numbers are no problem. My mistake to translate in a 0-based world :wink:

Best regards,
Dieke

I like the idea of using the sign to handle the orientation of the face. It make a clever use of the full range of value available. We do really need to clearly document that though, because for people inspecting files with an external tool, the shift between 0 and 1 numbering only for polyhedron may be confusing.

For the writing, the issue is that we will need to compute the connected faces and sort them out before storing the data. This could be costly for huge simulation as vtk does not have the connection information already. Or it is well hidden…

VTK does not store this information indeed. We can compute this information using a costly call to GetCellNeighbors.
I do not see this as a blocking point. We can use this syntax even if the VTK provided writer create duplicates faces at first. Simulation will still be able to benefits from lighter files as the most important part here is the reader. Ideally, the writer may have an advanced parameter to enable this optimization during write.

Dear VTK-Team,

I am still enthusiastic about your prompt and positive reply. I expect that our (ParaView-) users would benefit a lot from a new unstructured grid format.
As in many finite volume codes we are storing data in the cell centers and the centers of the internal (those with a positive and negative number in my example) and the external(boundary) faces.
Thus the boundary data will need less storage than the data on the internal faces.
This could be reflecte by using something like face sections.
My idea would be something like :

/VTKHDF (Attribute Type UnstructuredGrid, Version )
   /NumberOfCells
   /NumberOfCellSides
   /NumberOfPoints
   /NumberOfFaces
   /NumberOfFaceVertices
   /NumberOfFaceSections
   /Connectivity
       /Faces
          /Vertices
          /Offsets
       /Cells
          /OneBasedFaceIDs
          /Offsets
       /FaceSection attribute  name = "family1" attribute boundaryCondition = "bc1"
      either /SectionRange  Start,End
      or     /FaceList  list of face indicators
       /FaceSection attribute name = "family2" 
      either /SectionRange  Start,End
      or     /FaceList  list of face indicators attribute boundaryCondition = "bc1"
   /Points
   /CellData
   /PointData
   /FaceData
   /FaceSectionData name="family1" 
   /FaceSectionData name="family2" 
 

In this way, the all the data would be stored in a very compact way. Ideally, the /Cells /Faces and /FaceSection sections would be selectable similar to the “Extract Block” filter in ParaView.

If the 1 based faceIds are posing a problem, it would be possible to put the boundary faces in the beginning of the face list since their orientation would be always positive. A dummy face would do the trick as well.

1 Like

Another idea to have a compact storage would be to add a “Parent” 2d array that for each face will store at first the cell owner and at second the cell neighbor. For the cell owner the face will be correctly oriented while for the neighbor it will be needed to flip it.
If a Face is a boundary it will not have a neighbor (thus value will be -1 for neighbor).
This is like a FaceToCell relationship reverse to the current CellToFace storage.
This is done by solvers like openfoam to store polyMesh.

I agree with Mickael that this is also a good and very disk space aware of storing the data. If we store the internal faces and the (external) boundaries in separate sections for each family we could also leave out the neighbor cell information for the boundaries. This would save even more space.
When designing the output file please make the field and the separate boundary families accessible by using a multi-block like approach. This would make ParaView even more usable for out team.

1 Like