Skip to content

Commit 2e67c08

Browse files
committed
Refactor coordinate specification handling in dataset templates
- Simplified the `declare_coordinate_specs` method in `AbstractDatasetTemplate` to use list comprehensions for better readability and performance. - Updated coordinate specifications in `Seismic2DCdpGathersTemplate`, `Seismic3DCdpGathersTemplate`, `Seismic3DCocaGathersTemplate`, and `Seismic3DStreamerFieldRecordsTemplate` to remove redundant parameters. - Introduced a new experimental module for handling raw headers, including functions to determine inclusion and attach binary headers, enhancing the ingestion pipeline's flexibility. - Modified metadata handling in `metadata.py` to utilize the new raw headers functionality, streamlining the process of adding SEG-Y file headers.
1 parent ae00a8c commit 2e67c08

11 files changed

Lines changed: 133 additions & 234 deletions

src/mdio/builder/templates/base.py

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -72,30 +72,25 @@ def _repr_html_(self) -> str:
7272
return template_repr_html(self)
7373

7474
def declare_coordinate_specs(self) -> tuple[CoordinateSpec, ...]:
75-
"""Return per-coordinate (name, dims, dtype, source, header_key, chunk_policy)."""
75+
"""Return the non-dimension coordinate specs (name, dims, dtype) for this template."""
7676
from mdio.ingestion.schema_resolver import CoordinateSpec
7777

78-
specs = []
79-
for coord_name in self.physical_coordinate_names:
80-
specs.append(
81-
CoordinateSpec(
82-
name=coord_name,
83-
dimensions=self.spatial_dimension_names,
84-
dtype=ScalarType.FLOAT64,
85-
source="header",
86-
header_key=coord_name,
87-
)
78+
specs = [
79+
CoordinateSpec(
80+
name=coord_name,
81+
dimensions=self.spatial_dimension_names,
82+
dtype=ScalarType.FLOAT64,
8883
)
89-
for coord_name in self.logical_coordinate_names:
90-
specs.append(
91-
CoordinateSpec(
92-
name=coord_name,
93-
dimensions=self.spatial_dimension_names,
94-
dtype=ScalarType.UINT8 if coord_name == "gun" else ScalarType.INT32,
95-
source="header",
96-
header_key=coord_name,
97-
)
84+
for coord_name in self.physical_coordinate_names
85+
]
86+
specs.extend(
87+
CoordinateSpec(
88+
name=coord_name,
89+
dimensions=self.spatial_dimension_names,
90+
dtype=ScalarType.UINT8 if coord_name == "gun" else ScalarType.INT32,
9891
)
92+
for coord_name in self.logical_coordinate_names
93+
)
9994
return tuple(specs)
10095

10196
def build_dataset(

src/mdio/builder/templates/seismic_2d_cdp.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,8 @@ def declare_coordinate_specs(self) -> tuple[Any, ...]:
4343
from mdio.ingestion.schema_resolver import CoordinateSpec
4444

4545
return (
46-
CoordinateSpec(
47-
name="cdp_x",
48-
dimensions=("cdp",),
49-
dtype=ScalarType.FLOAT64,
50-
source="header",
51-
header_key="cdp_x",
52-
),
53-
CoordinateSpec(
54-
name="cdp_y",
55-
dimensions=("cdp",),
56-
dtype=ScalarType.FLOAT64,
57-
source="header",
58-
header_key="cdp_y",
59-
),
46+
CoordinateSpec(name="cdp_x", dimensions=("cdp",), dtype=ScalarType.FLOAT64),
47+
CoordinateSpec(name="cdp_y", dimensions=("cdp",), dtype=ScalarType.FLOAT64),
6048
)
6149

6250
def _add_coordinates(self) -> None:

src/mdio/builder/templates/seismic_3d_cdp.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,8 @@ def declare_coordinate_specs(self) -> tuple[Any, ...]:
4343
from mdio.ingestion.schema_resolver import CoordinateSpec
4444

4545
return (
46-
CoordinateSpec(
47-
name="cdp_x",
48-
dimensions=("inline", "crossline"),
49-
dtype=ScalarType.FLOAT64,
50-
source="header",
51-
header_key="cdp_x",
52-
),
53-
CoordinateSpec(
54-
name="cdp_y",
55-
dimensions=("inline", "crossline"),
56-
dtype=ScalarType.FLOAT64,
57-
source="header",
58-
header_key="cdp_y",
59-
),
46+
CoordinateSpec(name="cdp_x", dimensions=("inline", "crossline"), dtype=ScalarType.FLOAT64),
47+
CoordinateSpec(name="cdp_y", dimensions=("inline", "crossline"), dtype=ScalarType.FLOAT64),
6048
)
6149

6250
def _add_coordinates(self) -> None:

src/mdio/builder/templates/seismic_3d_coca.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,8 @@ def declare_coordinate_specs(self) -> tuple[Any, ...]:
3434
from mdio.ingestion.schema_resolver import CoordinateSpec
3535

3636
return (
37-
CoordinateSpec(
38-
name="cdp_x",
39-
dimensions=("inline", "crossline"),
40-
dtype=ScalarType.FLOAT64,
41-
source="header",
42-
header_key="cdp_x",
43-
),
44-
CoordinateSpec(
45-
name="cdp_y",
46-
dimensions=("inline", "crossline"),
47-
dtype=ScalarType.FLOAT64,
48-
source="header",
49-
header_key="cdp_y",
50-
),
37+
CoordinateSpec(name="cdp_x", dimensions=("inline", "crossline"), dtype=ScalarType.FLOAT64),
38+
CoordinateSpec(name="cdp_y", dimensions=("inline", "crossline"), dtype=ScalarType.FLOAT64),
5139
)
5240

5341
def _add_coordinates(self) -> None:

src/mdio/builder/templates/seismic_3d_obn.py

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -59,49 +59,15 @@ def _load_dataset_attributes(self) -> dict[str, Any]:
5959
def declare_coordinate_specs(self) -> tuple[Any, ...]:
6060
from mdio.ingestion.schema_resolver import CoordinateSpec
6161

62+
receiver_dim = ("receiver",)
63+
shot_dims = ("shot_line", "gun", "shot_index")
6264
return (
63-
CoordinateSpec(
64-
name="group_coord_x",
65-
dimensions=("receiver",),
66-
dtype=ScalarType.FLOAT64,
67-
source="header",
68-
header_key="group_coord_x",
69-
),
70-
CoordinateSpec(
71-
name="group_coord_y",
72-
dimensions=("receiver",),
73-
dtype=ScalarType.FLOAT64,
74-
source="header",
75-
header_key="group_coord_y",
76-
),
77-
CoordinateSpec(
78-
name="shot_point",
79-
dimensions=("shot_line", "gun", "shot_index"),
80-
dtype=ScalarType.UINT32,
81-
source="header",
82-
header_key="shot_point",
83-
),
84-
CoordinateSpec(
85-
name="orig_field_record_num",
86-
dimensions=("shot_line", "gun", "shot_index"),
87-
dtype=ScalarType.UINT32,
88-
source="header",
89-
header_key="orig_field_record_num",
90-
),
91-
CoordinateSpec(
92-
name="source_coord_x",
93-
dimensions=("shot_line", "gun", "shot_index"),
94-
dtype=ScalarType.FLOAT64,
95-
source="header",
96-
header_key="source_coord_x",
97-
),
98-
CoordinateSpec(
99-
name="source_coord_y",
100-
dimensions=("shot_line", "gun", "shot_index"),
101-
dtype=ScalarType.FLOAT64,
102-
source="header",
103-
header_key="source_coord_y",
104-
),
65+
CoordinateSpec(name="group_coord_x", dimensions=receiver_dim, dtype=ScalarType.FLOAT64),
66+
CoordinateSpec(name="group_coord_y", dimensions=receiver_dim, dtype=ScalarType.FLOAT64),
67+
CoordinateSpec(name="shot_point", dimensions=shot_dims, dtype=ScalarType.UINT32),
68+
CoordinateSpec(name="orig_field_record_num", dimensions=shot_dims, dtype=ScalarType.UINT32),
69+
CoordinateSpec(name="source_coord_x", dimensions=shot_dims, dtype=ScalarType.FLOAT64),
70+
CoordinateSpec(name="source_coord_y", dimensions=shot_dims, dtype=ScalarType.FLOAT64),
10571
)
10672

10773
def _add_coordinates(self) -> None:

src/mdio/builder/templates/seismic_3d_streamer_field.py

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -47,49 +47,15 @@ def _load_dataset_attributes(self) -> dict[str, Any]:
4747
def declare_coordinate_specs(self) -> tuple[Any, ...]:
4848
from mdio.ingestion.schema_resolver import CoordinateSpec
4949

50+
shot_dims = ("sail_line", "gun", "shot_index")
51+
receiver_dims = ("sail_line", "gun", "shot_index", "cable", "channel")
5052
return (
51-
CoordinateSpec(
52-
name="orig_field_record_num",
53-
dimensions=("sail_line", "gun", "shot_index"),
54-
dtype=ScalarType.UINT32,
55-
source="header",
56-
header_key="orig_field_record_num",
57-
),
58-
CoordinateSpec(
59-
name="shot_point",
60-
dimensions=("sail_line", "gun", "shot_index"),
61-
dtype=ScalarType.UINT32,
62-
source="header",
63-
header_key="shot_point",
64-
),
65-
CoordinateSpec(
66-
name="source_coord_x",
67-
dimensions=("sail_line", "gun", "shot_index"),
68-
dtype=ScalarType.FLOAT64,
69-
source="header",
70-
header_key="source_coord_x",
71-
),
72-
CoordinateSpec(
73-
name="source_coord_y",
74-
dimensions=("sail_line", "gun", "shot_index"),
75-
dtype=ScalarType.FLOAT64,
76-
source="header",
77-
header_key="source_coord_y",
78-
),
79-
CoordinateSpec(
80-
name="group_coord_x",
81-
dimensions=("sail_line", "gun", "shot_index", "cable", "channel"),
82-
dtype=ScalarType.FLOAT64,
83-
source="header",
84-
header_key="group_coord_x",
85-
),
86-
CoordinateSpec(
87-
name="group_coord_y",
88-
dimensions=("sail_line", "gun", "shot_index", "cable", "channel"),
89-
dtype=ScalarType.FLOAT64,
90-
source="header",
91-
header_key="group_coord_y",
92-
),
53+
CoordinateSpec(name="orig_field_record_num", dimensions=shot_dims, dtype=ScalarType.UINT32),
54+
CoordinateSpec(name="shot_point", dimensions=shot_dims, dtype=ScalarType.UINT32),
55+
CoordinateSpec(name="source_coord_x", dimensions=shot_dims, dtype=ScalarType.FLOAT64),
56+
CoordinateSpec(name="source_coord_y", dimensions=shot_dims, dtype=ScalarType.FLOAT64),
57+
CoordinateSpec(name="group_coord_x", dimensions=receiver_dims, dtype=ScalarType.FLOAT64),
58+
CoordinateSpec(name="group_coord_y", dimensions=receiver_dims, dtype=ScalarType.FLOAT64),
9359
)
9460

9561
def _add_coordinates(self) -> None:
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""EXPERIMENTAL: gating for the ``MDIO__IMPORT__RAW_HEADERS`` feature.
2+
3+
This module concentrates all checks tied to the experimental raw-headers feature so
4+
that removing the feature is a single-file delete plus the (small) handful of call
5+
sites that import from here. The behaviour:
6+
7+
* ``should_include_raw_headers()`` decides whether the ``raw_headers`` variable
8+
should be added to the dataset for this run. Honours the env-driven
9+
:class:`mdio.core.config.MDIOSettings` and the active Zarr format.
10+
* ``attach_raw_binary_header()`` adds the base64-encoded binary file header to a
11+
segy_file_header attribute dict, if (and only if) the feature is enabled.
12+
13+
Removal plan
14+
------------
15+
Delete this module and:
16+
17+
#. Drop the call to :func:`should_include_raw_headers` in
18+
:mod:`mdio.ingestion.pipeline` (and the resulting ``include_raw_headers``
19+
kwarg threaded through :class:`~mdio.ingestion.dataset_factory.DatasetFactory`
20+
/ :meth:`AbstractDatasetTemplate.build_dataset` / ``_add_raw_headers``).
21+
#. Drop the call to :func:`attach_raw_binary_header` in
22+
:mod:`mdio.ingestion.metadata`.
23+
#. Drop ``MDIOSettings.raw_headers``.
24+
"""
25+
26+
from __future__ import annotations
27+
28+
import base64
29+
import logging
30+
from typing import TYPE_CHECKING
31+
32+
import zarr
33+
34+
from mdio.constants import ZarrFormat
35+
from mdio.core.config import MDIOSettings
36+
37+
if TYPE_CHECKING:
38+
from typing import Any
39+
40+
logger = logging.getLogger(__name__)
41+
42+
43+
def should_include_raw_headers() -> bool:
44+
"""True iff the experimental flag is set and the active Zarr format supports it."""
45+
if not MDIOSettings().raw_headers:
46+
return False
47+
if zarr.config.get("default_zarr_format") == ZarrFormat.V2:
48+
logger.warning("Raw headers are only supported for Zarr v3. Skipping raw headers.")
49+
return False
50+
logger.warning("MDIO__IMPORT__RAW_HEADERS is experimental and expected to change or be removed.")
51+
return True
52+
53+
54+
def attach_raw_binary_header(attrs: dict[str, Any], raw_binary_headers: bytes) -> None:
55+
"""Attach a base64-encoded raw binary header to ``attrs`` if the feature is enabled."""
56+
if not MDIOSettings().raw_headers:
57+
return
58+
attrs["rawBinaryHeader"] = base64.b64encode(raw_binary_headers).decode("ascii")

src/mdio/ingestion/metadata.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
"""Metadata utilities for MDIO ingestion.
2-
3-
This module contains functions for adding metadata to MDIO datasets
4-
during ingestion.
5-
"""
1+
"""Metadata utilities for MDIO ingestion."""
62

73
from __future__ import annotations
84

9-
import base64
105
from typing import TYPE_CHECKING
116
from typing import Any
127

138
from mdio.core.config import MDIOSettings
9+
from mdio.ingestion._raw_headers_experimental import attach_raw_binary_header
1410

1511
if TYPE_CHECKING:
1612
from xarray import Dataset as xr_Dataset
@@ -30,9 +26,7 @@ def add_grid_override_to_metadata(dataset: Dataset, grid_overrides: dict[str, An
3026

3127
def add_segy_file_headers(xr_dataset: xr_Dataset, segy_file_info: SegyFileInfo) -> xr_Dataset:
3228
"""Add SEG-Y file headers to the dataset as metadata."""
33-
settings = MDIOSettings()
34-
35-
if not settings.save_segy_file_header:
29+
if not MDIOSettings().save_segy_file_header:
3630
return xr_dataset
3731

3832
expected_rows = 40
@@ -50,14 +44,13 @@ def add_segy_file_headers(xr_dataset: xr_Dataset, segy_file_info: SegyFileInfo)
5044
raise ValueError(err)
5145

5246
xr_dataset["segy_file_header"] = ((), "")
53-
xr_dataset["segy_file_header"].attrs.update(
47+
file_header_attrs = xr_dataset["segy_file_header"].attrs
48+
file_header_attrs.update(
5449
{
5550
"textHeader": segy_file_info.text_header,
5651
"binaryHeader": segy_file_info.binary_header_dict,
5752
}
5853
)
59-
if settings.raw_headers:
60-
raw_binary_base64 = base64.b64encode(segy_file_info.raw_binary_headers).decode("ascii")
61-
xr_dataset["segy_file_header"].attrs.update({"rawBinaryHeader": raw_binary_base64})
54+
attach_raw_binary_header(file_header_attrs, segy_file_info.raw_binary_headers)
6255

6356
return xr_dataset

0 commit comments

Comments
 (0)