From 4a431ad7ef7c582495898c2476af34554194c0c4 Mon Sep 17 00:00:00 2001 From: Altay Sansal Date: Wed, 20 Nov 2024 14:45:17 -0600 Subject: [PATCH] Add SEG-Y Revision 2.1 to supported formats (#232) * Add support for SEG-Y Rev2.1 specification * Add support for SEG-Y Rev2.1 specification --------- Co-authored-by: Altay Sansal --- README.md | 6 ++++-- src/segy/standards/__init__.py | 2 ++ src/segy/standards/fields/binary.py | 10 ++++++++-- src/segy/standards/spec.py | 30 ++++++++++++++++++++++++----- tests/test_segy_file.py | 3 ++- 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 095d05c..12f5416 100644 --- a/README.md +++ b/README.md @@ -105,8 +105,10 @@ are still in progress and not all validation logic is implemented yet: - ✅ Rev 0 (1975) - ✅ Rev 1 (2002) -- ✅ Rev 2 (2017) -- 🔲 Rev 2.1 (2023) +- ✅ Rev 2 (2017)\*\* +- ✅ Rev 2.1 (2023)\*\* + +\*\* The XML stanzas and extended trace headers are not currently supported. ### Custom SEG-Y Standards diff --git a/src/segy/standards/__init__.py b/src/segy/standards/__init__.py index 39b028b..0dafdaa 100644 --- a/src/segy/standards/__init__.py +++ b/src/segy/standards/__init__.py @@ -6,10 +6,12 @@ from segy.standards.spec import REV0 from segy.standards.spec import REV1 from segy.standards.spec import REV2 +from segy.standards.spec import REV21 register_segy_standard(version_or_name=0.0, spec=REV0) register_segy_standard(version_or_name=1.0, spec=REV1) register_segy_standard(version_or_name=2.0, spec=REV2) +register_segy_standard(version_or_name=2.1, spec=REV21) __all__ = ["get_segy_standard", "SegyStandard"] diff --git a/src/segy/standards/fields/binary.py b/src/segy/standards/fields/binary.py index b8aeb66..8a64d5d 100644 --- a/src/segy/standards/fields/binary.py +++ b/src/segy/standards/fields/binary.py @@ -57,10 +57,16 @@ class Rev2(SegStandardEnum): BYTE_ORDER = (97, "int32") SEGY_REVISION_MAJOR = (301, "uint8") SEGY_REVISION_MINOR = (302, "uint8") - MAX_EXTENDED_TRACE_HEADERS = (307, "int16") - SURVEY_TYPE = (309, "int16") + MAX_EXTENDED_TRACE_HEADERS = (307, "int32") TIME_BASIS_CODE = (311, "int16") NUM_TRACES = (313, "uint64") BYTE_OFFSET_FIRST_TRACE = (321, "uint64") NUM_DATA_TRAILER_STANZAS = (329, "int32") + + +class Rev21(SegStandardEnum): + """Definition of SEG-Y Rev2 binary headers.""" + + MAX_EXTENDED_TRACE_HEADERS = (307, "int16") + SURVEY_TYPE = (309, "int16") # fmt:on diff --git a/src/segy/standards/spec.py b/src/segy/standards/spec.py index 3894606..ec7ffaf 100644 --- a/src/segy/standards/spec.py +++ b/src/segy/standards/spec.py @@ -1,6 +1,5 @@ """SEG-Y Revision 0 Specification.""" - from segy.schema.base import Endianness from segy.schema.format import ScalarType from segy.schema.format import TextHeaderEncoding @@ -15,16 +14,25 @@ from segy.standards.fields import trace BIN_HDR_FIELDS_REV0 = [field.model for field in binary.Rev0] +TRC_HDR_FIELDS_REV0 = [field.model for field in trace.Rev0] + BIN_HDR_FIELDS_REV1 = BIN_HDR_FIELDS_REV0 + [field.model for field in binary.Rev1] -BIN_HDR_FIELDS_REV2 = BIN_HDR_FIELDS_REV1 + [field.model for field in binary.Rev2] +TRC_HDR_FIELDS_REV1 = TRC_HDR_FIELDS_REV0 + [field.model for field in trace.Rev1] +# Rev2 removes segy_revision and splits it into major/minor revision fields +BIN_HDR_FIELDS_REV2 = BIN_HDR_FIELDS_REV1 + [field.model for field in binary.Rev2] BIN_HDR_FIELDS_REV2.remove(binary.Rev1.SEGY_REVISION.model) BIN_HDR_FIELDS_REV2 = sorted(BIN_HDR_FIELDS_REV2, key=lambda f: f.byte) - -TRC_HDR_FIELDS_REV0 = [field.model for field in trace.Rev0] -TRC_HDR_FIELDS_REV1 = TRC_HDR_FIELDS_REV0 + [field.model for field in trace.Rev1] TRC_HDR_FIELDS_REV2 = TRC_HDR_FIELDS_REV1 + [field.model for field in trace.Rev2] +# Rev2.1 splits maximum extended trace headers into two 16-bit. +# First reduces it from 32-bit to 16-bit +# Second gets new "survey type" field +BIN_HDR_FIELDS_REV21 = BIN_HDR_FIELDS_REV2 + [field.model for field in binary.Rev21] +BIN_HDR_FIELDS_REV21.remove(binary.Rev2.MAX_EXTENDED_TRACE_HEADERS.model) +BIN_HDR_FIELDS_REV21 = sorted(BIN_HDR_FIELDS_REV21, key=lambda f: f.byte) +TRC_HDR_FIELDS_REV21 = TRC_HDR_FIELDS_REV2 # no change + text_header_ebcdic = TextHeaderSpec( rows=40, @@ -68,3 +76,15 @@ header=HeaderSpec(fields=TRC_HDR_FIELDS_REV2, item_size=240), ), ) + +REV21 = SegySpec( + segy_standard=SegyStandard.REV21, + endianness=Endianness.BIG, + text_header=text_header_ebcdic, + binary_header=HeaderSpec(fields=BIN_HDR_FIELDS_REV21, item_size=400, offset=3200), + ext_text_header=ext_text_header_ebcdic_3200, + trace=TraceSpec( + data=TraceDataSpec(format=ScalarType.IBM32), + header=HeaderSpec(fields=TRC_HDR_FIELDS_REV21, item_size=240), + ), +) diff --git a/tests/test_segy_file.py b/tests/test_segy_file.py index 6ceb5e9..0bc7161 100644 --- a/tests/test_segy_file.py +++ b/tests/test_segy_file.py @@ -131,7 +131,8 @@ class TestSegyFile: """Test the usage of SegyFile class.""" @pytest.mark.parametrize( - "standard", [SegyStandard.REV0, SegyStandard.REV1, SegyStandard.REV2] + "standard", + [SegyStandard.REV0, SegyStandard.REV1, SegyStandard.REV2, SegyStandard.REV21], ) @pytest.mark.parametrize("endianness", [Endianness.BIG, Endianness.LITTLE]) @pytest.mark.parametrize("sample_format", [ScalarType.IBM32, ScalarType.FLOAT32])