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.
Files changed (63) hide show
  1. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/PKG-INFO +1 -1
  2. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/ImageData.py +1 -1
  3. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/PolyData.py +12 -27
  4. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/RectilinearData.py +1 -1
  5. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/StructuredGrid.py +1 -1
  6. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/UnstructuredGrid.py +1 -1
  7. vtkio-0.1.0.dev9/examples/new_reader_testing.py +40 -0
  8. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/pyproject.toml +0 -8
  9. vtkio-0.1.0.dev9/src/vtkio/config.py +374 -0
  10. vtkio-0.1.0.dev9/src/vtkio/reader/api.py +427 -0
  11. vtkio-0.1.0.dev9/src/vtkio/reader/base_reader.py +717 -0
  12. vtkio-0.1.0.dev9/src/vtkio/reader/compression.py +326 -0
  13. vtkio-0.1.0.dev9/src/vtkio/reader/data_processors.py +384 -0
  14. vtkio-0.1.0.dev9/src/vtkio/reader/exceptions.py +39 -0
  15. vtkio-0.1.0.dev9/src/vtkio/reader/readers.py +735 -0
  16. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/utilities.py +1 -1
  17. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/version.py +1 -2
  18. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/writer/__init__.py +1 -1
  19. vtkio-0.1.0.dev9/src/vtkio/writer/vtkhdf.py +1256 -0
  20. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/writer/writers.py +14 -42
  21. vtkio-0.1.0.dev9/src/vtkio/writer/xml_writer.py +1598 -0
  22. vtkio-0.1.0.dev9/tests/conftest.py +152 -0
  23. vtkio-0.1.0.dev9/tests/test_api.py +86 -0
  24. vtkio-0.1.0.dev9/tests/test_base_reader.py +66 -0
  25. vtkio-0.1.0.dev9/tests/test_concrete_readers.py +100 -0
  26. vtkio-0.1.0.dev9/tests/test_config.py +39 -0
  27. vtkio-0.1.0.dev9/tests/test_data_processors.py +68 -0
  28. vtkio-0.1.0.dev9/tests/test_exceptions.py +22 -0
  29. vtkio-0.1.0.dev9/tests/test_integration.py +98 -0
  30. vtkio-0.1.0.dev8/src/vtkio/writer/base_writer.py +0 -245
  31. vtkio-0.1.0.dev8/src/vtkio/writer/validation.py +0 -248
  32. vtkio-0.1.0.dev8/src/vtkio/writer/vtkhdf.py +0 -553
  33. vtkio-0.1.0.dev8/src/vtkio/writer/xml.py +0 -1421
  34. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/.gitignore +0 -0
  35. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/CITATION.cff +0 -0
  36. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/LICENSE +0 -0
  37. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/README.md +0 -0
  38. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/benchmarking.py +0 -0
  39. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/new_vtkhdf_test.py +0 -0
  40. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/examples/read_vtk_files.py +0 -0
  41. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/__init__.py +0 -0
  42. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/helpers.py +0 -0
  43. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/reader/__init__.py +0 -0
  44. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/reader/hdf5.py +0 -0
  45. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/reader/xml.py +0 -0
  46. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/simplified.py +0 -0
  47. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/vtk_cell_types.py +0 -0
  48. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/vtk_structures.py +0 -0
  49. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/src/vtkio/writer/pvd_writer.py +0 -0
  50. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/__init__.py +0 -0
  51. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_vtkhdf_vti.py +0 -0
  52. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vti.py +0 -0
  53. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vtp.py +0 -0
  54. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vtr.py +0 -0
  55. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vts.py +0 -0
  56. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_read_xml_vtu.py +0 -0
  57. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_vtkhdf_writer.py +0 -0
  58. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_vtkhdf_vts.py +0 -0
  59. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vti.py +0 -0
  60. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vtp.py +0 -0
  61. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vtr.py +0 -0
  62. {vtkio-0.1.0.dev8 → vtkio-0.1.0.dev9}/tests/test_write_xml_vts.py +0 -0
  63. {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.dev8
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.xml import XMLImageDataWriter
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.xml import XMLPolyDataWriter
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, encoding='ascii')
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, "point_scales": point_scales}
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=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=point_data,
326
- cell_data=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=point_data,
330
- cell_data=cell_data, fieldData=None, encoding='binary')
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=point_data,
333
- cell_data=cell_data, fieldData=None, encoding='appended')
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.xml import xml_multiblock_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, 'block2': map_data, 'block3': cow_data, 'block4': lines_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.xml import XMLRectilinearGridWriter
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.xml import XMLStructuredGridWriter
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.xml import XMLUnstructuredGridWriter
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