VTKio 0.1.0.dev8__tar.gz → 0.1.0.dev9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/PKG-INFO +1 -1
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/ImageData.py +1 -1
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/PolyData.py +12 -27
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/RectilinearData.py +1 -1
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/StructuredGrid.py +1 -1
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/UnstructuredGrid.py +1 -1
- vtkio-0.1.0.dev9/examples/new_reader_testing.py +40 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/pyproject.toml +0 -8
- vtkio-0.1.0.dev9/src/vtkio/config.py +374 -0
- vtkio-0.1.0.dev9/src/vtkio/reader/api.py +427 -0
- vtkio-0.1.0.dev9/src/vtkio/reader/base_reader.py +717 -0
- vtkio-0.1.0.dev9/src/vtkio/reader/compression.py +326 -0
- vtkio-0.1.0.dev9/src/vtkio/reader/data_processors.py +384 -0
- vtkio-0.1.0.dev9/src/vtkio/reader/exceptions.py +39 -0
- vtkio-0.1.0.dev9/src/vtkio/reader/readers.py +735 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/utilities.py +1 -1
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/version.py +1 -2
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/writer/__init__.py +1 -1
- vtkio-0.1.0.dev9/src/vtkio/writer/vtkhdf.py +1256 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/writer/writers.py +14 -42
- vtkio-0.1.0.dev9/src/vtkio/writer/xml_writer.py +1598 -0
- vtkio-0.1.0.dev9/tests/conftest.py +152 -0
- vtkio-0.1.0.dev9/tests/test_api.py +86 -0
- vtkio-0.1.0.dev9/tests/test_base_reader.py +66 -0
- vtkio-0.1.0.dev9/tests/test_concrete_readers.py +100 -0
- vtkio-0.1.0.dev9/tests/test_config.py +39 -0
- vtkio-0.1.0.dev9/tests/test_data_processors.py +68 -0
- vtkio-0.1.0.dev9/tests/test_exceptions.py +22 -0
- vtkio-0.1.0.dev9/tests/test_integration.py +98 -0
- vtkio-0.1.0.dev8/src/vtkio/writer/base_writer.py +0 -245
- vtkio-0.1.0.dev8/src/vtkio/writer/validation.py +0 -248
- vtkio-0.1.0.dev8/src/vtkio/writer/vtkhdf.py +0 -553
- vtkio-0.1.0.dev8/src/vtkio/writer/xml.py +0 -1421
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/.gitignore +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/CITATION.cff +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/LICENSE +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/README.md +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/benchmarking.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/new_vtkhdf_test.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/read_vtk_files.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/__init__.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/helpers.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/reader/__init__.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/reader/hdf5.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/reader/xml.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/simplified.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/vtk_cell_types.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/vtk_structures.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/writer/pvd_writer.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/__init__.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_vtkhdf_vti.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vti.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vtp.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vtr.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vts.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vtu.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_vtkhdf_writer.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_vtkhdf_vts.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vti.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vtp.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vtr.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vts.py +0 -0
- {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vtu.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: VTKio
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev9
|
|
4
4
|
Summary: A simple package for converting data between VTK files (XML and HDF5) and NumPy arrays.
|
|
5
5
|
Project-URL: Homepage, https://jpmorr.gitlab.io/vtkio
|
|
6
6
|
Project-URL: Documentation, https://jpmorr.gitlab.io/vtkio
|
|
@@ -76,7 +76,7 @@ field_data = {'TimeValue': 0.122654987}
|
|
|
76
76
|
|
|
77
77
|
## new version
|
|
78
78
|
# --8<-- [start:write_imagedata_writer_ascii]
|
|
79
|
-
from vtkio.writer.
|
|
79
|
+
from vtkio.writer.xml_writer import XMLImageDataWriter
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
file = XMLImageDataWriter('test_uniform_image_data.vti',
|
|
@@ -83,7 +83,7 @@ offsets = np.arange(start=1, stop=npoints + 1, dtype="int32") # index of last n
|
|
|
83
83
|
|
|
84
84
|
#%% write with xml base writer
|
|
85
85
|
# --8<-- [start:write_points_data_ascii]
|
|
86
|
-
from vtkio.writer.
|
|
86
|
+
from vtkio.writer.xml_writer import XMLPolyDataWriter
|
|
87
87
|
|
|
88
88
|
# Write the file using the xml writer class
|
|
89
89
|
file = XMLPolyDataWriter('test_points_polydata.vtp',
|
|
@@ -212,8 +212,6 @@ poly_verts_data = read_vtkxml_data('../TestData/vtp/polytest.vtp')
|
|
|
212
212
|
lines_data = read_vtkxml_data('../TestData/vtp/ibm_with_data.vtp')
|
|
213
213
|
cow_data = read_vtkxml_data('../TestData/vtp/cow.vtp')
|
|
214
214
|
|
|
215
|
-
map_data_base_64 = read_vtkxml_data('map_base64_ref.vtp')
|
|
216
|
-
|
|
217
215
|
write_vtp('plate_vectors', points=plate_data.points,
|
|
218
216
|
polys=(plate_data.polys.connectivity, plate_data.polys.offsets),
|
|
219
217
|
point_data={"vectors": plate_data.point_data}, field_data=fielddata)
|
|
@@ -225,17 +223,7 @@ write_vtp('cow2', points=cow_data.points,
|
|
|
225
223
|
write_vtp('map', points=map_data.points,
|
|
226
224
|
lines=(map_data.lines.connectivity, map_data.lines.offsets),
|
|
227
225
|
cell_data={"vectors": map_data.cell_data},
|
|
228
|
-
field_data=fielddata
|
|
229
|
-
|
|
230
|
-
write_vtp('map_base64', points=map_data.points,
|
|
231
|
-
lines=(map_data.lines.connectivity, map_data.lines.offsets),
|
|
232
|
-
cell_data={"vectors": map_data.cell_data},
|
|
233
|
-
field_data=fielddata, encoding='binary')
|
|
234
|
-
|
|
235
|
-
write_vtp('map_appended', points=map_data.points,
|
|
236
|
-
lines=(map_data.lines.connectivity, map_data.lines.offsets),
|
|
237
|
-
cell_data={"vectors": map_data.cell_data},
|
|
238
|
-
field_data=fielddata, encoding='appended')
|
|
226
|
+
field_data=fielddata)
|
|
239
227
|
|
|
240
228
|
write_vtp('polytest', points=poly_verts_data.points,
|
|
241
229
|
verts=(poly_verts_data.verts.connectivity, poly_verts_data.verts.offsets),
|
|
@@ -287,14 +275,11 @@ points[9, :] = 2.0, 0.0, 3.0
|
|
|
287
275
|
# Some point variables
|
|
288
276
|
pressure = np.random.rand(npoints)
|
|
289
277
|
temp = np.random.rand(npoints)
|
|
290
|
-
scales = np.random.rand(5)
|
|
291
|
-
point_scales = np.array([scales,scales]).T.flatten()
|
|
292
278
|
|
|
293
279
|
# some line variables (cell data)
|
|
294
280
|
vel = np.arange(5) + 1
|
|
295
281
|
|
|
296
|
-
point_data = {"temp": temp, "pressure": pressure
|
|
297
|
-
cell_data = {"velocity": vel, "cell_scales": scales}
|
|
282
|
+
point_data = {"temp": temp, "pressure": pressure}
|
|
298
283
|
|
|
299
284
|
# --8<-- [end:create_lines_dataset]
|
|
300
285
|
|
|
@@ -311,7 +296,7 @@ offsets = (np.arange(num_lines) + 1) * 2
|
|
|
311
296
|
write_vtp('test_lines_polydata_appended_encoded',
|
|
312
297
|
points=points, lines=(connectivity, offsets),
|
|
313
298
|
point_data=point_data,
|
|
314
|
-
cell_data=
|
|
299
|
+
cell_data={'velocity': vel},
|
|
315
300
|
field_data=None,
|
|
316
301
|
encoding='appended')
|
|
317
302
|
|
|
@@ -322,15 +307,15 @@ write_vtp('test_lines_polydata_appended_encoded',
|
|
|
322
307
|
from vtkio.simplified import lines_to_poly
|
|
323
308
|
|
|
324
309
|
lines_to_poly('line_test', points,
|
|
325
|
-
point_data=
|
|
326
|
-
cell_data=
|
|
310
|
+
point_data={"1_temp": temp, "2_pressure": pressure},
|
|
311
|
+
cell_data={'velocity': vel},
|
|
327
312
|
fieldData=None, encoding='ascii')
|
|
328
313
|
|
|
329
|
-
lines_to_poly('line_test_binary', points, point_data=
|
|
330
|
-
cell_data=
|
|
314
|
+
lines_to_poly('line_test_binary', points, point_data={"1_temp": temp, "2_pressure": pressure},
|
|
315
|
+
cell_data={'velocity': vel}, fieldData=None, encoding='binary')
|
|
331
316
|
|
|
332
|
-
lines_to_poly('line_test_base64', points, point_data=
|
|
333
|
-
cell_data=
|
|
317
|
+
lines_to_poly('line_test_base64', points, point_data={"1_temp": temp, "2_pressure": pressure},
|
|
318
|
+
cell_data={'velocity': vel}, fieldData=None, encoding='appended')
|
|
334
319
|
|
|
335
320
|
# --8<-- [end:write_lines_dataset_hl]
|
|
336
321
|
|
|
@@ -410,7 +395,7 @@ polylines_to_poly('polyline_test_base64', points, pointsPerLine,
|
|
|
410
395
|
#%% test writing multiblock files
|
|
411
396
|
|
|
412
397
|
# --8<-- [start:write_poly_multiblock_xml]
|
|
413
|
-
from vtkio.writer.
|
|
398
|
+
from vtkio.writer.xml_writer import xml_multiblock_writer
|
|
414
399
|
|
|
415
400
|
xml_multiblock_writer('new_vtk_multiblock_file', {
|
|
416
401
|
'Base': {'files': ['edem_cube_base_t_0.vtp']},
|
|
@@ -426,7 +411,7 @@ xml_multiblock_writer('new_vtk_multiblock_file', {
|
|
|
426
411
|
# --8<-- [start:write_poly_multiblock_vtkhdf]
|
|
427
412
|
from vtkio.writer.vtkhdf import VTKHDFMultiBlockWriter
|
|
428
413
|
|
|
429
|
-
blocks = {'block1': plate_data, '
|
|
414
|
+
blocks = {'block1': plate_data, 'block3': cow_data, 'block4': lines_data}
|
|
430
415
|
writer = VTKHDFMultiBlockWriter('hdf_multiblock_test', blocks)
|
|
431
416
|
writer.write_vtkhdf_file()
|
|
432
417
|
|
|
@@ -81,7 +81,7 @@ field_data = {'TimeValue': 0.122654987}
|
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
# --8<-- [start:write_rectilineargriddata_writer_ascii]
|
|
84
|
-
from vtkio.writer.
|
|
84
|
+
from vtkio.writer.xml_writer import XMLRectilinearGridWriter
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
file = XMLRectilinearGridWriter('test_rectilinear_grid_data.vtr',
|
|
@@ -105,7 +105,7 @@ field_data = {'TimeValue': 0.122654987}
|
|
|
105
105
|
# --8<-- [end:create_grid_data]
|
|
106
106
|
|
|
107
107
|
# --8<-- [start:write_structuredgrid_data_writer_ascii]
|
|
108
|
-
from vtkio.writer.
|
|
108
|
+
from vtkio.writer.xml_writer import XMLStructuredGridWriter
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
file = XMLStructuredGridWriter('test_distorted_grid',
|
|
@@ -103,7 +103,7 @@ offsets = np.cumsum(num_cell_nodes)
|
|
|
103
103
|
|
|
104
104
|
# --8<-- [start:write_multicell_vtu]
|
|
105
105
|
# Write the unstructured grid to a vtu file with multiple cell types
|
|
106
|
-
from vtkio.writer.
|
|
106
|
+
from vtkio.writer.xml_writer import XMLUnstructuredGridWriter
|
|
107
107
|
|
|
108
108
|
# Write the file using the xml writer class
|
|
109
109
|
file = XMLUnstructuredGridWriter('multi_cell_type_example',
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Module documentation goes here.
|
|
4
|
+
|
|
5
|
+
Created at 20:22, 26 Apr, 2022
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__author__ = 'J.P. Morrissey'
|
|
9
|
+
__copyright__ = 'Copyright 2022-2025'
|
|
10
|
+
__maintainer__ = 'J.P. Morrissey'
|
|
11
|
+
__email__ = 'morrissey.jp@gmail.com'
|
|
12
|
+
__status__ = 'Development'
|
|
13
|
+
|
|
14
|
+
# Standard Library
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Imports
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
# Local Sources
|
|
21
|
+
from vtkio.reader import read_vtkxml_data
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
from ..src.vtkio.reader.readers import UnifiedXMLReader, UnifiedHDF5Reader
|
|
25
|
+
|
|
26
|
+
#%% test xml polydata reading
|
|
27
|
+
plate_data = read_vtkxml_data('../TestData/vtp/plate_vectors.vtp')
|
|
28
|
+
map_data = read_vtkxml_data('../TestData/vtp/map.vtp')
|
|
29
|
+
poly_verts_data = read_vtkxml_data('../TestData/vtp/polytest.vtp')
|
|
30
|
+
lines_data = read_vtkxml_data('../TestData/vtp/ibm_with_data.vtp')
|
|
31
|
+
cow_data = read_vtkxml_data('../TestData/vtp/cow.vtp')
|
|
32
|
+
|
|
33
|
+
#%%text new xml polydata reader
|
|
34
|
+
xml_reader = UnifiedXMLReader('../TestData/vtp/plate_vectors.vtp')
|
|
35
|
+
xml_reader.read()
|
|
36
|
+
print(xml_reader)
|
|
37
|
+
print(xml_reader.data)
|
|
38
|
+
print(xml_reader.data.point_data.keys())
|
|
39
|
+
print(xml_reader.data.cell_data.keys())
|
|
40
|
+
print(xml_reader.data.field_data.keys())
|
|
@@ -101,14 +101,6 @@ include = [
|
|
|
101
101
|
]
|
|
102
102
|
exclude = [
|
|
103
103
|
"/examples/example_data",
|
|
104
|
-
"/examples/*.vti",
|
|
105
|
-
"/examples/*.vtp",
|
|
106
|
-
"/examples/*.vtu",
|
|
107
|
-
"/examples/*.vtr",
|
|
108
|
-
"/examples/*.vts",
|
|
109
|
-
"/examples/*.vtm",
|
|
110
|
-
"/examples/*.vtkhdf",
|
|
111
|
-
"/examples/*.pvd",
|
|
112
104
|
"/TestData"
|
|
113
105
|
]
|
|
114
106
|
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Configuration settings for the VTKio package.
|
|
4
|
+
|
|
5
|
+
This centralises all magic strings, type mappings, and configuration
|
|
6
|
+
to make the system more maintainable.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__author__ = 'J.P. Morrissey'
|
|
10
|
+
__copyright__ = 'Copyright 2022-2025'
|
|
11
|
+
__maintainer__ = 'J.P. Morrissey'
|
|
12
|
+
__email__ = 'morrissey.jp@gmail.com'
|
|
13
|
+
__status__ = 'Development'
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
from typing import Dict, Set, Any
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
import logging
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class VTKConfig:
|
|
22
|
+
"""Central configuration for VTK readers."""
|
|
23
|
+
|
|
24
|
+
# File format support
|
|
25
|
+
SUPPORTED_XML_EXTENSIONS: Set[str] = {'.vti', '.vtr', '.vts', '.vtu', '.vtp'}
|
|
26
|
+
SUPPORTED_HDF5_EXTENSIONS: Set[str] = {'.h5', '.hdf5', 'vtkhdf', '.hdf'}
|
|
27
|
+
|
|
28
|
+
# VTK data types
|
|
29
|
+
SUPPORTED_VTK_TYPES: Set[str] = {
|
|
30
|
+
'ImageData', 'PolyData', 'UnstructuredGrid',
|
|
31
|
+
'StructuredGrid', 'RectilinearGrid'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# File format defaults
|
|
35
|
+
DEFAULT_ENCODING: str = 'utf-8'
|
|
36
|
+
DEFAULT_BYTE_ORDER: str = 'little_endian'
|
|
37
|
+
|
|
38
|
+
# Data type mappings for XML parsing
|
|
39
|
+
XML_TYPE_MAPPING: Dict[str, Any] = {
|
|
40
|
+
'int': np.int64,
|
|
41
|
+
'float': np.float32,
|
|
42
|
+
'double': np.float64,
|
|
43
|
+
'float16': np.float16,
|
|
44
|
+
'float32': np.float32,
|
|
45
|
+
'float64': np.float64,
|
|
46
|
+
'int8': np.int8,
|
|
47
|
+
'int16': np.int16,
|
|
48
|
+
'int32': np.int32,
|
|
49
|
+
'int64': np.int64,
|
|
50
|
+
'uint8': np.uint8,
|
|
51
|
+
'uint16': np.uint16,
|
|
52
|
+
'uint32': np.uint32,
|
|
53
|
+
'uint64': np.uint64,
|
|
54
|
+
'string': 's'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Required data sections for each VTK type
|
|
58
|
+
REQUIRED_DATA_SECTIONS: Dict[str, Set[str]] = {
|
|
59
|
+
'UnstructuredGrid': {'Points', 'Cells'},
|
|
60
|
+
'PolyData': {'Points'},
|
|
61
|
+
'ImageData': set(), # Grid info comes from attributes
|
|
62
|
+
'StructuredGrid': {'Points'},
|
|
63
|
+
'RectilinearGrid': {'Coordinates'}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Optional data sections (always try to read these)
|
|
67
|
+
OPTIONAL_DATA_SECTIONS: Set[str] = {'PointData', 'CellData', 'FieldData'}
|
|
68
|
+
|
|
69
|
+
# XML specific constants
|
|
70
|
+
XML_ARRAY_KEYS: Set[str] = {'DataArray', 'Array'}
|
|
71
|
+
XML_DATA_FORMATS: Set[str] = {'ascii', 'binary', 'appended'}
|
|
72
|
+
|
|
73
|
+
# HDF5 specific constants
|
|
74
|
+
HDF5_VTKHDF_GROUP: str = 'VTKHDF'
|
|
75
|
+
HDF5_REQUIRED_ATTRIBUTES: Set[str] = {'Type'}
|
|
76
|
+
|
|
77
|
+
# Polydata topology sections
|
|
78
|
+
POLYDATA_TOPOLOGY_SECTIONS: Dict[str, str] = {
|
|
79
|
+
'Vertices': 'verts',
|
|
80
|
+
'Lines': 'lines',
|
|
81
|
+
'Strips': 'strips',
|
|
82
|
+
'Polygons': 'polys',
|
|
83
|
+
'Polys': 'polys' # Handle both naming conventions
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Grid attributes for ImageData
|
|
87
|
+
IMAGE_DATA_ATTRIBUTES: Set[str] = {
|
|
88
|
+
'WholeExtent', 'Origin', 'Spacing', 'Direction'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# Coordinate names for RectilinearGrid
|
|
92
|
+
RECTILINEAR_COORDINATES: Set[str] = {'XCoordinates', 'YCoordinates', 'ZCoordinates'}
|
|
93
|
+
|
|
94
|
+
# Point array common names (in order of preference)
|
|
95
|
+
POINT_ARRAY_NAMES: list = ['Points', 'Coordinates', 'points', 'coordinates']
|
|
96
|
+
|
|
97
|
+
# Connectivity array names
|
|
98
|
+
CONNECTIVITY_ARRAY_NAMES: Dict[str, str] = {
|
|
99
|
+
'connectivity': 'connectivity',
|
|
100
|
+
'offsets': 'offsets',
|
|
101
|
+
'types': 'types'
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Compression type mapping - centralizes compression constants
|
|
105
|
+
SUPPORTED_COMPRESSION_TYPES = {
|
|
106
|
+
'none': 'none',
|
|
107
|
+
'zlib': 'zlib',
|
|
108
|
+
'gzip': 'zlib', # HDF5 gzip maps to zlib
|
|
109
|
+
'lzma': 'lzma',
|
|
110
|
+
'xz': 'lzma', # XZ maps to lzma
|
|
111
|
+
'lz4': 'lz4'
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Default compression settings
|
|
115
|
+
DEFAULT_COMPRESSION_TYPE = 'zlib'
|
|
116
|
+
MAX_DECOMPRESSION_MEMORY_MB = 1024 # 1GB default limit
|
|
117
|
+
|
|
118
|
+
# VTK-specific compression block size (typical default)
|
|
119
|
+
DEFAULT_COMPRESSION_BLOCK_SIZE = 32768
|
|
120
|
+
|
|
121
|
+
# Logging configuration
|
|
122
|
+
DEFAULT_LOG_LEVEL: int = logging.INFO
|
|
123
|
+
LOG_FORMAT: str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
124
|
+
|
|
125
|
+
# Performance settings
|
|
126
|
+
CHUNK_SIZE: int = 8192 # For reading large files in chunks
|
|
127
|
+
MAX_MEMORY_USAGE_MB: int = 1024 # Maximum memory usage before warnings
|
|
128
|
+
|
|
129
|
+
# Validation settings
|
|
130
|
+
VALIDATE_TOPOLOGY: bool = True
|
|
131
|
+
VALIDATE_DATA_CONSISTENCY: bool = True
|
|
132
|
+
|
|
133
|
+
# Error handling settings
|
|
134
|
+
STRICT_VALIDATION: bool = False # If True, fail on any validation errors
|
|
135
|
+
CONTINUE_ON_DATA_ERRORS: bool = True # Continue reading even if some data arrays fail
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def get_reader_class_for_extension(cls, file_path: Path) -> str:
|
|
139
|
+
"""
|
|
140
|
+
Get the appropriate reader class name for a file extension.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
file_path : Path
|
|
145
|
+
Path to the file
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
str
|
|
150
|
+
Name of the reader class to use
|
|
151
|
+
|
|
152
|
+
Raises
|
|
153
|
+
------
|
|
154
|
+
ValueError
|
|
155
|
+
If file extension is not supported
|
|
156
|
+
"""
|
|
157
|
+
suffix = file_path.suffix.lower()
|
|
158
|
+
|
|
159
|
+
if suffix in cls.SUPPORTED_XML_EXTENSIONS:
|
|
160
|
+
return 'UnifiedXMLReader'
|
|
161
|
+
elif suffix in cls.SUPPORTED_HDF5_EXTENSIONS:
|
|
162
|
+
return 'UnifiedHDF5Reader'
|
|
163
|
+
else:
|
|
164
|
+
raise ValueError(f"Unsupported file extension: {suffix}")
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def get_vtk_type_from_extension(cls, file_path: Path) -> str:
|
|
168
|
+
"""
|
|
169
|
+
Guess VTK type from file extension.
|
|
170
|
+
|
|
171
|
+
This is a fallback when type cannot be read from file.
|
|
172
|
+
"""
|
|
173
|
+
extension_to_type = {
|
|
174
|
+
'.vti': 'ImageData',
|
|
175
|
+
'.vtr': 'RectilinearGrid',
|
|
176
|
+
'.vts': 'StructuredGrid',
|
|
177
|
+
'.vtu': 'UnstructuredGrid',
|
|
178
|
+
'.vtp': 'PolyData'
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return extension_to_type.get(file_path.suffix.lower(), 'Unknown')
|
|
182
|
+
|
|
183
|
+
@classmethod
|
|
184
|
+
def validate_vtk_type(cls, vtk_type: str) -> bool:
|
|
185
|
+
"""Check if VTK type is supported."""
|
|
186
|
+
return vtk_type in cls.SUPPORTED_VTK_TYPES
|
|
187
|
+
|
|
188
|
+
@classmethod
|
|
189
|
+
def get_numpy_dtype(cls, xml_type_string: str) -> Any:
|
|
190
|
+
"""Convert XML type string to numpy dtype."""
|
|
191
|
+
return cls.XML_TYPE_MAPPING.get(xml_type_string.lower(), None)
|
|
192
|
+
|
|
193
|
+
@classmethod
|
|
194
|
+
def validate_compression_type(cls, compression_type: str) -> bool:
|
|
195
|
+
"""Validate if compression type is supported."""
|
|
196
|
+
return compression_type.lower() in cls.SUPPORTED_COMPRESSION_TYPES
|
|
197
|
+
|
|
198
|
+
@classmethod
|
|
199
|
+
def normalize_compression_type(cls, compression_type: str) -> str:
|
|
200
|
+
"""Normalize compression type name to standard form."""
|
|
201
|
+
normalized = compression_type.lower()
|
|
202
|
+
return cls.SUPPORTED_COMPRESSION_TYPES.get(normalized, 'none')
|
|
203
|
+
|
|
204
|
+
@classmethod
|
|
205
|
+
def get_supported_extensions_for_compression(cls) -> set:
|
|
206
|
+
"""Get all file extensions that may contain compressed data."""
|
|
207
|
+
return cls.SUPPORTED_HDF5_EXTENSIONS | cls.SUPPORTED_XML_EXTENSIONS
|
|
208
|
+
|
|
209
|
+
@classmethod
|
|
210
|
+
def setup_logging(cls, level: int = None, format_str: str = None) -> logging.Logger:
|
|
211
|
+
"""Set up logging with standard configuration."""
|
|
212
|
+
level = level or cls.DEFAULT_LOG_LEVEL
|
|
213
|
+
format_str = format_str or cls.LOG_FORMAT
|
|
214
|
+
|
|
215
|
+
logging.basicConfig(level=level, format=format_str)
|
|
216
|
+
logger = logging.getLogger('vtk_reader')
|
|
217
|
+
return logger
|
|
218
|
+
|
|
219
|
+
@classmethod
|
|
220
|
+
def get_supported_data_types(cls) -> Dict[str, Dict[str, Any]]:
|
|
221
|
+
"""
|
|
222
|
+
Get supported VTK data types with their parser information.
|
|
223
|
+
|
|
224
|
+
Returns
|
|
225
|
+
-------
|
|
226
|
+
Dict[str, Dict[str, Any]]
|
|
227
|
+
Dictionary mapping VTK type names to parser information
|
|
228
|
+
"""
|
|
229
|
+
return {
|
|
230
|
+
'UnstructuredGrid': {
|
|
231
|
+
'required_sections': cls.REQUIRED_DATA_SECTIONS['UnstructuredGrid'],
|
|
232
|
+
'parser_method': '_parse_unstructured_grid',
|
|
233
|
+
'description': 'Unstructured grid with arbitrary connectivity'
|
|
234
|
+
},
|
|
235
|
+
'PolyData': {
|
|
236
|
+
'required_sections': cls.REQUIRED_DATA_SECTIONS['PolyData'],
|
|
237
|
+
'parser_method': '_parse_polydata',
|
|
238
|
+
'description': 'Polygonal data (vertices, lines, polygons, triangle strips)'
|
|
239
|
+
},
|
|
240
|
+
'ImageData': {
|
|
241
|
+
'required_sections': cls.REQUIRED_DATA_SECTIONS['ImageData'],
|
|
242
|
+
'parser_method': '_parse_image_data',
|
|
243
|
+
'description': 'Regular grid with uniform spacing'
|
|
244
|
+
},
|
|
245
|
+
'StructuredGrid': {
|
|
246
|
+
'required_sections': cls.REQUIRED_DATA_SECTIONS['StructuredGrid'],
|
|
247
|
+
'parser_method': '_parse_structured_grid',
|
|
248
|
+
'description': 'Structured grid with arbitrary point positions'
|
|
249
|
+
},
|
|
250
|
+
'RectilinearGrid': {
|
|
251
|
+
'required_sections': cls.REQUIRED_DATA_SECTIONS['RectilinearGrid'],
|
|
252
|
+
'parser_method': '_parse_rectilinear_grid',
|
|
253
|
+
'description': 'Grid with separate coordinate arrays'
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
@classmethod
|
|
258
|
+
def get_required_sections_for_type(cls, vtk_type: str) -> Set[str]:
|
|
259
|
+
"""
|
|
260
|
+
Get required data sections for a specific VTK type.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
vtk_type : str
|
|
265
|
+
VTK data type name
|
|
266
|
+
|
|
267
|
+
Returns
|
|
268
|
+
-------
|
|
269
|
+
Set[str]
|
|
270
|
+
Set of required section names
|
|
271
|
+
"""
|
|
272
|
+
return cls.REQUIRED_DATA_SECTIONS.get(vtk_type, set())
|
|
273
|
+
|
|
274
|
+
@classmethod
|
|
275
|
+
def get_parser_method_for_type(cls, vtk_type: str) -> str:
|
|
276
|
+
"""
|
|
277
|
+
Get the parser method name for a VTK type.
|
|
278
|
+
|
|
279
|
+
Parameters
|
|
280
|
+
----------
|
|
281
|
+
vtk_type : str
|
|
282
|
+
VTK data type name
|
|
283
|
+
|
|
284
|
+
Returns
|
|
285
|
+
-------
|
|
286
|
+
str
|
|
287
|
+
Name of the parser method
|
|
288
|
+
|
|
289
|
+
Raises
|
|
290
|
+
------
|
|
291
|
+
ValueError
|
|
292
|
+
If VTK type is not supported
|
|
293
|
+
"""
|
|
294
|
+
supported_types = cls.get_supported_data_types()
|
|
295
|
+
if vtk_type not in supported_types:
|
|
296
|
+
raise ValueError(f"Unsupported VTK type: {vtk_type}")
|
|
297
|
+
|
|
298
|
+
return supported_types[vtk_type]['parser_method']
|
|
299
|
+
|
|
300
|
+
@classmethod
|
|
301
|
+
def is_xml_extension(cls, extension: str) -> bool:
|
|
302
|
+
"""Check if extension is a supported XML format."""
|
|
303
|
+
return extension.lower() in cls.SUPPORTED_XML_EXTENSIONS
|
|
304
|
+
|
|
305
|
+
@classmethod
|
|
306
|
+
def is_hdf5_extension(cls, extension: str) -> bool:
|
|
307
|
+
"""Check if extension is a supported HDF5 format."""
|
|
308
|
+
return extension.lower() in cls.SUPPORTED_HDF5_EXTENSIONS
|
|
309
|
+
|
|
310
|
+
@classmethod
|
|
311
|
+
def get_all_supported_extensions(cls) -> Set[str]:
|
|
312
|
+
"""Get all supported file extensions."""
|
|
313
|
+
return cls.SUPPORTED_XML_EXTENSIONS | cls.SUPPORTED_HDF5_EXTENSIONS
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
class ReaderSettings:
|
|
317
|
+
"""Runtime settings for VTK readers that can be customized per read operation."""
|
|
318
|
+
|
|
319
|
+
def __init__(self,
|
|
320
|
+
validate_topology: bool = None,
|
|
321
|
+
validate_data_consistency: bool = None,
|
|
322
|
+
strict_validation: bool = None,
|
|
323
|
+
continue_on_data_errors: bool = None,
|
|
324
|
+
max_memory_usage_mb: int = None,
|
|
325
|
+
chunk_size: int = None):
|
|
326
|
+
"""
|
|
327
|
+
Initialize reader settings.
|
|
328
|
+
|
|
329
|
+
Parameters that are None will use the defaults from VTKConfig.
|
|
330
|
+
"""
|
|
331
|
+
self.validate_topology = validate_topology if validate_topology is not None else VTKConfig.VALIDATE_TOPOLOGY
|
|
332
|
+
self.validate_data_consistency = validate_data_consistency if validate_data_consistency is not None else VTKConfig.VALIDATE_DATA_CONSISTENCY
|
|
333
|
+
self.strict_validation = strict_validation if strict_validation is not None else VTKConfig.STRICT_VALIDATION
|
|
334
|
+
self.continue_on_data_errors = continue_on_data_errors if continue_on_data_errors is not None else VTKConfig.CONTINUE_ON_DATA_ERRORS
|
|
335
|
+
self.max_memory_usage_mb = max_memory_usage_mb if max_memory_usage_mb is not None else VTKConfig.MAX_MEMORY_USAGE_MB
|
|
336
|
+
self.chunk_size = chunk_size if chunk_size is not None else VTKConfig.CHUNK_SIZE
|
|
337
|
+
|
|
338
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
339
|
+
"""Convert settings to dictionary for logging/debugging."""
|
|
340
|
+
return {
|
|
341
|
+
'validate_topology': self.validate_topology,
|
|
342
|
+
'validate_data_consistency': self.validate_data_consistency,
|
|
343
|
+
'strict_validation': self.strict_validation,
|
|
344
|
+
'continue_on_data_errors': self.continue_on_data_errors,
|
|
345
|
+
'max_memory_usage_mb': self.max_memory_usage_mb,
|
|
346
|
+
'chunk_size': self.chunk_size
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# Convenience functions for common configurations
|
|
351
|
+
def create_performance_settings() -> ReaderSettings:
|
|
352
|
+
"""Create settings optimised for performance (less validation)."""
|
|
353
|
+
return ReaderSettings(
|
|
354
|
+
validate_topology=False,
|
|
355
|
+
validate_data_consistency=False,
|
|
356
|
+
strict_validation=False,
|
|
357
|
+
continue_on_data_errors=True,
|
|
358
|
+
chunk_size=16384 # Larger chunks
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def create_strict_settings() -> ReaderSettings:
|
|
363
|
+
"""Create settings optimised for data integrity (more validation)."""
|
|
364
|
+
return ReaderSettings(
|
|
365
|
+
validate_topology=True,
|
|
366
|
+
validate_data_consistency=True,
|
|
367
|
+
strict_validation=True,
|
|
368
|
+
continue_on_data_errors=False
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def create_default_settings() -> ReaderSettings:
|
|
373
|
+
"""Create default balanced settings."""
|
|
374
|
+
return ReaderSettings() # Uses all defaults from VTKConfig
|