Skip to content

Commit 1d3670a

Browse files
committed
Begin roughing out new templates
1 parent 3d01a6d commit 1d3670a

3 files changed

Lines changed: 242 additions & 0 deletions

File tree

src/mdio/builder/template_registry.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
from mdio.builder.templates.seismic_2d_streamer_shot import Seismic2DStreamerShotGathersTemplate
2626
from mdio.builder.templates.seismic_3d_cdp import Seismic3DCdpGathersTemplate
2727
from mdio.builder.templates.seismic_3d_coca import Seismic3DCocaGathersTemplate
28+
from mdio.builder.templates.seismic_3d_obn_receiver import Seismic3DObnReceiverGathersTemplate
29+
from mdio.builder.templates.seismic_3d_ovt import Seismic3DOffsetVectorTileTemplate
2830
from mdio.builder.templates.seismic_3d_poststack import Seismic3DPostStackTemplate
2931
from mdio.builder.templates.seismic_3d_streamer_field import Seismic3DStreamerFieldRecordsTemplate
3032
from mdio.builder.templates.seismic_3d_streamer_shot import Seismic3DStreamerShotGathersTemplate
@@ -133,6 +135,14 @@ def _register_default_templates(self) -> None:
133135
self.register(Seismic3DCocaGathersTemplate("time"))
134136
self.register(Seismic3DCocaGathersTemplate("depth"))
135137

138+
# OBN/OBC Receiver Gathers
139+
self.register(Seismic3DObnReceiverGathersTemplate("time"))
140+
self.register(Seismic3DObnReceiverGathersTemplate("depth"))
141+
142+
# Offset Vector Tile (OVT) Gathers
143+
self.register(Seismic3DOffsetVectorTileTemplate("time"))
144+
self.register(Seismic3DOffsetVectorTileTemplate("depth"))
145+
136146
# Field (shot) data
137147
self.register(Seismic2DStreamerShotGathersTemplate())
138148
self.register(Seismic3DStreamerShotGathersTemplate())
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
"""Seismic3DObnReceiverGathersTemplate MDIO v1 dataset templates."""
2+
3+
from typing import Any
4+
5+
from mdio.builder.schemas import compressors
6+
from mdio.builder.schemas.dtype import ScalarType
7+
from mdio.builder.schemas.v1.variable import CoordinateMetadata
8+
from mdio.builder.templates.base import AbstractDatasetTemplate
9+
from mdio.builder.templates.types import SeismicDataDomain
10+
11+
12+
class Seismic3DObnReceiverGathersTemplate(AbstractDatasetTemplate):
13+
"""Seismic OBN/OBC receiver-domain pre-stack 3D Dataset template.
14+
15+
A template for Ocean Bottom Node (OBN) or Ocean Bottom Cable (OBC) surveys where
16+
receivers are deployed at fixed positions and shots are organized by shot lines.
17+
Data is indexed by receiver position, enabling efficient receiver-side processing.
18+
19+
Dimensions:
20+
- receiver: Index of the receiver node/station
21+
- shot_line: Shot line or swath identifier
22+
- shot_point: Shot point within the line
23+
- time/depth: Sample dimension
24+
25+
This organization is optimal for:
26+
- Receiver-side wavefield separation (up/down)
27+
- Receiver-consistent deconvolution
28+
- Multi-component processing
29+
30+
Args:
31+
data_domain: The domain of the dataset ('time' or 'depth').
32+
"""
33+
34+
def __init__(self, data_domain: SeismicDataDomain = "time"):
35+
super().__init__(data_domain=data_domain)
36+
37+
self._dim_names = ("receiver", "shot_line", "shot_point", self._data_domain)
38+
self._physical_coord_names = (
39+
"receiver_x",
40+
"receiver_y",
41+
"source_coord_x",
42+
"source_coord_y",
43+
)
44+
self._logical_coord_names = ("receiver_depth",)
45+
self._var_chunk_shape = (1, 1, 512, 4096)
46+
47+
@property
48+
def _name(self) -> str:
49+
return f"ObnReceiverGathers3D{self._data_domain.capitalize()}"
50+
51+
def _load_dataset_attributes(self) -> dict[str, Any]:
52+
return {"surveyType": "3D", "gatherType": "common_receiver", "acquisitionType": "obn"}
53+
54+
def _add_coordinates(self) -> None:
55+
# Add dimension coordinates
56+
self._builder.add_coordinate(
57+
"receiver",
58+
dimensions=("receiver",),
59+
data_type=ScalarType.UINT32,
60+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("receiver")),
61+
)
62+
self._builder.add_coordinate(
63+
"shot_line",
64+
dimensions=("shot_line",),
65+
data_type=ScalarType.UINT32,
66+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("shot_line")),
67+
)
68+
self._builder.add_coordinate(
69+
"shot_point",
70+
dimensions=("shot_point",),
71+
data_type=ScalarType.UINT32,
72+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("shot_point")),
73+
)
74+
self._builder.add_coordinate(
75+
self.trace_domain,
76+
dimensions=(self.trace_domain,),
77+
data_type=ScalarType.INT32,
78+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key(self.trace_domain)),
79+
)
80+
81+
# Add non-dimension coordinates
82+
compressor = compressors.Blosc(cname=compressors.BloscCname.zstd)
83+
84+
# Receiver coordinates (fixed per receiver)
85+
self._builder.add_coordinate(
86+
"receiver_x",
87+
dimensions=("receiver",),
88+
data_type=ScalarType.FLOAT64,
89+
compressor=compressor,
90+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("receiver_x")),
91+
)
92+
self._builder.add_coordinate(
93+
"receiver_y",
94+
dimensions=("receiver",),
95+
data_type=ScalarType.FLOAT64,
96+
compressor=compressor,
97+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("receiver_y")),
98+
)
99+
self._builder.add_coordinate(
100+
"receiver_depth",
101+
dimensions=("receiver",),
102+
data_type=ScalarType.FLOAT32,
103+
compressor=compressor,
104+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("receiver_depth")),
105+
)
106+
107+
# Source coordinates (vary by shot_line and shot_point)
108+
self._builder.add_coordinate(
109+
"source_coord_x",
110+
dimensions=("shot_line", "shot_point"),
111+
data_type=ScalarType.FLOAT64,
112+
compressor=compressor,
113+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("source_coord_x")),
114+
)
115+
self._builder.add_coordinate(
116+
"source_coord_y",
117+
dimensions=("shot_line", "shot_point"),
118+
data_type=ScalarType.FLOAT64,
119+
compressor=compressor,
120+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("source_coord_y")),
121+
)
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"""Seismic3DOffsetVectorTileTemplate MDIO v1 dataset templates."""
2+
3+
from typing import Any
4+
5+
from mdio.builder.schemas import compressors
6+
from mdio.builder.schemas.dtype import ScalarType
7+
from mdio.builder.schemas.v1.variable import CoordinateMetadata
8+
from mdio.builder.templates.base import AbstractDatasetTemplate
9+
from mdio.builder.templates.types import SeismicDataDomain
10+
11+
12+
class Seismic3DOffsetVectorTileTemplate(AbstractDatasetTemplate):
13+
"""Seismic Offset Vector Tile (OVT) pre-stack 3D Dataset template.
14+
15+
A 5D template for wide-azimuth seismic data organized by offset vector tiles.
16+
Data is binned by CDP location (inline, crossline) with offset vector
17+
decomposition into inline and crossline offset tile components.
18+
19+
Dimensions:
20+
- inline: Inline bin position
21+
- crossline: Crossline bin position
22+
- inline_offset_tile: Inline component of the offset vector tile
23+
- crossline_offset_tile: Crossline component of the offset vector tile
24+
- time/depth: Sample dimension
25+
26+
This organization is optimal for:
27+
- Wide-azimuth data preservation
28+
- 5D interpolation and regularization
29+
- Azimuthal analysis and processing
30+
- Offset vector filtering
31+
32+
The offset vector tiles partition the offset-azimuth space into a regular grid,
33+
preserving both offset magnitude and azimuth information in a format suitable
34+
for modern wide-azimuth processing workflows.
35+
36+
Args:
37+
data_domain: The domain of the dataset ('time' or 'depth').
38+
"""
39+
40+
def __init__(self, data_domain: SeismicDataDomain = "time"):
41+
super().__init__(data_domain=data_domain)
42+
43+
self._dim_names = (
44+
"inline",
45+
"crossline",
46+
"inline_offset_tile",
47+
"crossline_offset_tile",
48+
self._data_domain,
49+
)
50+
self._physical_coord_names = ("cdp_x", "cdp_y")
51+
self._logical_coord_names = ()
52+
self._var_chunk_shape = (4, 4, 6, 6, 4096)
53+
54+
@property
55+
def _name(self) -> str:
56+
return f"OffsetVectorTileGathers3D{self._data_domain.capitalize()}"
57+
58+
def _load_dataset_attributes(self) -> dict[str, Any]:
59+
return {"surveyType": "3D", "gatherType": "offset_vector_tile"}
60+
61+
def _add_coordinates(self) -> None:
62+
# Add dimension coordinates
63+
self._builder.add_coordinate(
64+
"inline",
65+
dimensions=("inline",),
66+
data_type=ScalarType.INT32,
67+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("inline")),
68+
)
69+
self._builder.add_coordinate(
70+
"crossline",
71+
dimensions=("crossline",),
72+
data_type=ScalarType.INT32,
73+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("crossline")),
74+
)
75+
self._builder.add_coordinate(
76+
"inline_offset_tile",
77+
dimensions=("inline_offset_tile",),
78+
data_type=ScalarType.INT16,
79+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("inline_offset_tile")),
80+
)
81+
self._builder.add_coordinate(
82+
"crossline_offset_tile",
83+
dimensions=("crossline_offset_tile",),
84+
data_type=ScalarType.INT16,
85+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("crossline_offset_tile")),
86+
)
87+
self._builder.add_coordinate(
88+
self.trace_domain,
89+
dimensions=(self.trace_domain,),
90+
data_type=ScalarType.INT32,
91+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key(self.trace_domain)),
92+
)
93+
94+
# Add non-dimension coordinates
95+
compressor = compressors.Blosc(cname=compressors.BloscCname.zstd)
96+
97+
# CDP coordinates (vary by inline, crossline)
98+
self._builder.add_coordinate(
99+
"cdp_x",
100+
dimensions=("inline", "crossline"),
101+
data_type=ScalarType.FLOAT64,
102+
compressor=compressor,
103+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("cdp_x")),
104+
)
105+
self._builder.add_coordinate(
106+
"cdp_y",
107+
dimensions=("inline", "crossline"),
108+
data_type=ScalarType.FLOAT64,
109+
compressor=compressor,
110+
metadata=CoordinateMetadata(units_v1=self.get_unit_by_key("cdp_y")),
111+
)

0 commit comments

Comments
 (0)