Skip to content

Commit feaf07f

Browse files
committed
Add unit tests for MDIO compatibility with older versions
1 parent d7af95a commit feaf07f

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

tests/unit/test_compat.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
"""Test MDIO compatibility with older versions."""
2+
3+
from pathlib import Path
4+
5+
import numpy as np
6+
import pytest
7+
import zarr
8+
from segy import SegyFile
9+
from segy.factory import SegyFactory
10+
from segy.standards import get_segy_standard
11+
12+
from mdio import mdio_to_segy
13+
from mdio import segy_to_mdio
14+
15+
16+
MDIO_VERSIONS = ["0.7.4", "0.8.3"]
17+
SEGY_REVISIONS = [0.0, 0.1, 1.0, 1.1]
18+
INLINES = (10, 10, 11, 11)
19+
CROSSLINES = (100, 101, 100, 101)
20+
21+
22+
@pytest.mark.parametrize("mdio_version", MDIO_VERSIONS)
23+
@pytest.mark.parametrize("segy_revision", SEGY_REVISIONS)
24+
def test_revision_encode_decode(
25+
mdio_version: str, segy_revision: float, tmp_path: Path
26+
) -> None:
27+
"""Test binary header major/minor revision roundtrip.
28+
29+
After introducting TGSAI/segy, we changed the header names. Now we use
30+
aliasing and MDIO has a dummy schema. The handling is slightly different
31+
for SEG-Y revision major/minor numbers. Testing to ensure they're
32+
(de)serialized correctly.
33+
"""
34+
rev1_spec = get_segy_standard(1.0)
35+
36+
sgy_filename = tmp_path / "sgy"
37+
mdio_filename = tmp_path / "mdio"
38+
sgy_rt_filename = tmp_path / "{rt.sgy"
39+
40+
# Make a rev1 segy
41+
factory = SegyFactory(rev1_spec, sample_interval=1000, samples_per_trace=5)
42+
43+
# We will replace the values in revision fields with these
44+
minor, major = np.modf(segy_revision)
45+
minor = int(minor * 10)
46+
major = int(major)
47+
48+
# Make fake tiny 3D dataset
49+
txt_buffer = factory.create_textual_header()
50+
51+
header = factory.create_trace_header_template(len(INLINES))
52+
data = factory.create_trace_sample_template(len(INLINES))
53+
header["inline"] = INLINES
54+
header["crossline"] = CROSSLINES
55+
data[:] = np.arange(len(INLINES))[:, None]
56+
trace_buffer = factory.create_traces(header, data)
57+
58+
# Update revision during bin hdr creation
59+
revision_code = major << 8 | minor
60+
bin_hdr_buffer = factory.create_binary_header(
61+
update={"segy_revision": revision_code}
62+
)
63+
with open(sgy_filename, mode="wb") as fp:
64+
fp.write(txt_buffer)
65+
fp.write(bin_hdr_buffer)
66+
fp.write(trace_buffer)
67+
68+
# Convert
69+
segy_to_mdio(str(sgy_filename), str(mdio_filename), index_bytes=(189, 193))
70+
71+
# Modify MDIO to mimic +/- 0.8
72+
root = zarr.open_group(mdio_filename, mode="r+")
73+
root.attrs["api_version"] = mdio_version
74+
75+
if mdio_version == "0.7.4":
76+
# Update bin hdr revision keys
77+
bin_hdr = root.metadata.attrs["binary_header"]
78+
bin_hdr["SEGYRevision"] = bin_hdr.pop("segy_revision_major")
79+
bin_hdr["SEGYRevisionMinor"] = bin_hdr.pop("segy_revision_minor")
80+
root.metadata.attrs["binary_header"] = bin_hdr
81+
82+
# Remove trace headers past 232 (pre 0.8)
83+
orig_hdr = root.metadata.chunked_012_trace_headers
84+
new_dtype = np.dtype(orig_hdr.dtype.descr[:-1])
85+
new_hdr = zarr.zeros_like(orig_hdr, dtype=new_dtype)
86+
root.metadata.create_dataset(
87+
"chunked_012_trace_headers",
88+
data=new_hdr,
89+
overwrite=True,
90+
)
91+
zarr.consolidate_metadata(root.store)
92+
93+
# Back to SEG-Y
94+
mdio_to_segy(str(mdio_filename), str(sgy_rt_filename))
95+
96+
# Assert if binary headers match and revisions are correct
97+
orig = SegyFile(sgy_filename, spec=rev1_spec)
98+
rt = SegyFile(sgy_rt_filename, spec=rev1_spec)
99+
100+
assert orig.binary_header["segy_revision_major"] == major
101+
assert orig.binary_header["segy_revision_minor"] == minor
102+
assert orig.binary_header == rt.binary_header

0 commit comments

Comments
 (0)