1313from segy .config import SegyHeaderOverrides
1414from segy .standards .codes import MeasurementSystem as SegyMeasurementSystem
1515from segy .standards .fields import binary as binary_header_fields
16+ from zarr import open_group as zarr_open_group
1617
1718from mdio .api .io import _normalize_path
19+ from mdio .api .io import _normalize_storage_options
1820from mdio .api .io import to_mdio
1921from mdio .builder .schemas .chunk_grid import RegularChunkGrid
2022from mdio .builder .schemas .chunk_grid import RegularChunkShape
@@ -140,29 +142,38 @@ def _scan_for_headers(
140142 segy_file_info : SegyFileInfo ,
141143 template : AbstractDatasetTemplate ,
142144 grid_overrides : dict [str , Any ] | None = None ,
143- ) -> tuple [list [Dimension ], SegyHeaderArray ]:
145+ calculate_checksum : bool = False ,
146+ ) -> tuple [list [Dimension ], SegyHeaderArray , int | None ]:
144147 """Extract trace dimensions and index headers from the SEG-Y file.
145148
146149 This is an expensive operation.
147150 It scans the SEG-Y file in chunks by using ProcessPoolExecutor
151+ Optionally calculates CRC32C checksum for all trace data during scanning.
148152 """
149153 full_chunk_size = template .full_chunk_size
150- segy_dimensions , chunk_size , segy_headers = get_grid_plan (
154+ grid_plan_result = get_grid_plan (
151155 segy_file_kwargs = segy_file_kwargs ,
152156 segy_file_info = segy_file_info ,
153157 return_headers = True ,
154158 template = template ,
155159 chunksize = full_chunk_size ,
156160 grid_overrides = grid_overrides ,
161+ calculate_checksum = calculate_checksum ,
157162 )
163+
164+ if calculate_checksum :
165+ segy_dimensions , chunk_size , segy_headers , trace_data_crc32c = grid_plan_result
166+ else :
167+ segy_dimensions , chunk_size , segy_headers = grid_plan_result
168+ trace_data_crc32c = None
158169 if full_chunk_size != chunk_size :
159170 # TODO(Dmitriy): implement grid overrides
160171 # https://github.com/TGSAI/mdio-python/issues/585
161172 # The returned 'chunksize' is used only for grid_overrides. We will need to use it when full
162173 # support for grid overrides is implemented
163174 err = "Support for changing full_chunk_size in grid overrides is not yet implemented"
164175 raise NotImplementedError (err )
165- return segy_dimensions , segy_headers
176+ return segy_dimensions , segy_headers , trace_data_crc32c
166177
167178
168179def _build_and_check_grid (
@@ -518,11 +529,15 @@ def segy_to_mdio( # noqa PLR0913
518529 }
519530 segy_file_info = get_segy_file_info (segy_file_kwargs )
520531
521- segy_dimensions , segy_headers = _scan_for_headers (
532+ # Only calculate CRC32C when raw headers are enabled
533+ calculate_checksum = os .getenv ("MDIO__IMPORT__RAW_HEADERS" ) in ("1" , "true" , "yes" , "on" )
534+
535+ segy_dimensions , segy_headers , trace_data_crc32c = _scan_for_headers (
522536 segy_file_kwargs ,
523537 segy_file_info ,
524538 template = mdio_template ,
525539 grid_overrides = grid_overrides ,
540+ calculate_checksum = calculate_checksum ,
526541 )
527542 grid = _build_and_check_grid (segy_dimensions , segy_file_info , segy_headers )
528543
@@ -580,10 +595,27 @@ def segy_to_mdio( # noqa PLR0913
580595 default_variable_name = mdio_template .default_variable_name
581596 # This is an memory-expensive and time-consuming read-write operation
582597 # performed in chunks to save the memory
598+ # NOTE: trace_data_crc32c was already calculated during header scanning phase
583599 blocked_io .to_zarr (
584600 segy_file_kwargs = segy_file_kwargs ,
585601 output_path = output_path ,
586602 grid_map = grid .map ,
587603 dataset = xr_dataset ,
588604 data_variable_name = default_variable_name ,
589605 )
606+
607+ # Store the final CRC32C checksum in the Zarr store attributes only when calculated
608+ if trace_data_crc32c is not None :
609+ # The trace_data_crc32c is now the full file CRC32C from DistributedCRC32C
610+ final_crc32c = trace_data_crc32c
611+
612+ storage_options = _normalize_storage_options (output_path )
613+ zarr_group = zarr_open_group (output_path .as_posix (), mode = "a" , storage_options = storage_options )
614+ zarr_group .attrs .update (
615+ {
616+ "segy_input_crc32c" : final_crc32c , # Store as integer, not hex string
617+ "crc32c_algorithm" : "CRC32C" ,
618+ "checksum_scope" : "full_file" ,
619+ "checksum_library" : "google-crc32c" ,
620+ }
621+ )
0 commit comments