@@ -2444,7 +2444,8 @@ class UnstructuredMesh(MeshBase):
24442444 _UNSUPPORTED_ELEM = - 1
24452445 _LINEAR_TET = 0
24462446 _LINEAR_HEX = 1
2447- _VTK_TETRA = 10
2447+ _VTK_TET = 10
2448+ _VTK_HEX = 12
24482449
24492450 def __init__ (self , filename : PathLike , library : str , mesh_id : int | None = None ,
24502451 name : str = '' , length_multiplier : float = 1.0 ,
@@ -2814,29 +2815,33 @@ def append_dataset(dset, array):
28142815 dset .resize (origLen + array .shape [0 ], axis = 0 )
28152816 dset [origLen :] = array
28162817
2817- if self .library != "moab" :
2818- raise NotImplementedError ("VTKHDF output is only supported for MOAB meshes" )
2819-
2820- # the self.connectivity contains arrays of length 8 to support hex
2821- # elements as well, in the case of tetrahedra mesh elements, the
2822- # last 4 values are -1 and are removed
2823- trimmed_connectivity = []
2824- for cell in self .connectivity :
2825- # Find the index of the first -1 value, if any
2826- first_negative_index = np .where (cell == - 1 )[0 ]
2827- if first_negative_index .size > 0 :
2828- # Slice the array up to the first -1 value
2829- trimmed_connectivity .append (cell [: first_negative_index [0 ]])
2818+ # This writer supports linear tetrahedra and linear hexahedra elements
2819+ conn_list = [] # flattened connectivity ids
2820+ cell_sizes = [] # number of points per cell
2821+ vtk_types = [] # VTK cell types per cell (uint8)
2822+
2823+ for conn , etype in zip (self .connectivity , self .element_types ):
2824+ if etype == self ._LINEAR_TET :
2825+ ids = conn [:4 ]
2826+ vtk_types .append (self ._VTK_TETRA )
2827+ elif etype == self ._LINEAR_HEX :
2828+ ids = conn [:8 ]
2829+ vtk_types .append (self ._VTK_HEXAHEDRON )
28302830 else :
2831- # No -1 values, append the whole cell
2832- trimmed_connectivity .append (cell )
2833- trimmed_connectivity = np .array (trimmed_connectivity , dtype = "int32" ).flatten ()
2831+ raise RuntimeError (
2832+ f"Invalid element type { etype } found in mesh { self .id } "
2833+ )
2834+ conn_list .extend (ids .tolist ())
2835+ cell_sizes .append (len (ids ))
28342836
2835- # MOAB meshes supports tet elements only so we know it has 4 points per cell
2836- points_per_cell = 4
2837+ connectivity = np .asarray (conn_list , dtype = np .int64 )
28372838
2838- # offsets are the indices of the first point of each cell in the array of points
2839- offsets = np .arange (0 , self .n_elements * points_per_cell + 1 , points_per_cell )
2839+ # Offsets must be length (numCells + 1) with a leading 0 and
2840+ # cumulative end-indices thereafter, per VTK's layout
2841+ cell_sizes_arr = np .asarray (cell_sizes , dtype = np .int64 )
2842+ offsets = np .empty (cell_sizes_arr .size + 1 , dtype = np .int64 )
2843+ offsets [0 ] = 0
2844+ np .cumsum (cell_sizes_arr , out = offsets [1 :])
28402845
28412846 for name , data in datasets .items ():
28422847 if data .shape != self .dimension :
@@ -2858,30 +2863,19 @@ def append_dataset(dset, array):
28582863 dtype = h5py .string_dtype ("ascii" , len (ascii_type )),
28592864 )
28602865
2861- # create hdf5 file structure
2862- root .create_dataset ("NumberOfPoints" , (0 ,), maxshape = (None ,), dtype = "i8" )
2863- root .create_dataset ("Types" , (0 ,), maxshape = (None ,), dtype = "uint8" )
2864- root .create_dataset ("Points" , (0 , 3 ), maxshape = (None , 3 ), dtype = "f" )
2865- root .create_dataset (
2866- "NumberOfConnectivityIds" , (0 ,), maxshape = (None ,), dtype = "i8"
2867- )
2868- root .create_dataset ("NumberOfCells" , (0 ,), maxshape = (None ,), dtype = "i8" )
2869- root .create_dataset ("Offsets" , (0 ,), maxshape = (None ,), dtype = "i8" )
2870- root .create_dataset ("Connectivity" , (0 ,), maxshape = (None ,), dtype = "i8" )
2871-
2872- append_dataset (root ["NumberOfPoints" ], np .array ([len (self .vertices )]))
2873- append_dataset (root ["Points" ], self .vertices )
2874- append_dataset (
2875- root ["NumberOfConnectivityIds" ],
2876- np .array ([len (trimmed_connectivity )]),
2877- )
2878- append_dataset (root ["Connectivity" ], trimmed_connectivity )
2879- append_dataset (root ["NumberOfCells" ], np .array ([self .n_elements ]))
2880- append_dataset (root ["Offsets" ], offsets )
2881-
2882- append_dataset (
2883- root ["Types" ], np .full (self .n_elements , self ._VTK_TETRA , dtype = "uint8" )
2884- )
2866+ # Create HDF5 file structure compliant with VTKHDF UnstructuredGrid
2867+ n_points = int (len (self .vertices ))
2868+ n_cells = int (len (cell_sizes ))
2869+ n_conn_ids = int (len (connectivity ))
2870+
2871+ root .create_dataset ("NumberOfPoints" , data = (n_points ,), dtype = "i8" )
2872+ root .create_dataset ("NumberOfCells" , data = (n_cells ,), dtype = "i8" )
2873+ root .create_dataset ("NumberOfConnectivityIds" , data = (n_conn_ids ,), dtype = "i8" )
2874+ # VTK typically stores points as double precision
2875+ root .create_dataset ("Points" , data = self .vertices .astype (np .float64 , copy = False ), dtype = "f8" )
2876+ root .create_dataset ("Types" , data = np .asarray (vtk_types , dtype = np .uint8 ), dtype = "uint8" )
2877+ root .create_dataset ("Offsets" , data = offsets .astype ("i8" ), dtype = "i8" )
2878+ root .create_dataset ("Connectivity" , data = connectivity .astype ("i8" ), dtype = "i8" )
28852879
28862880 cell_data_group = root .create_group ("CellData" )
28872881
0 commit comments