Skip to content

Commit 9297d1f

Browse files
committed
Enhance metadata handling for dimension coordinates in dataset templates
- Introduced a new method `_dim_coord_metadata` in `AbstractDatasetTemplate` to streamline the retrieval of metadata for dimension coordinates, ensuring unitless coordinates do not receive placeholder values. - Updated coordinate metadata handling in `Seismic2DCdpGathersTemplate`, `Seismic3DCdpGathersTemplate`, `Seismic3DCocaGathersTemplate`, `Seismic3DReceiverGathersTemplate`, and others to utilize the new method, improving code clarity and consistency. - Refactored coordinate addition logic across multiple templates to reduce redundancy and enhance maintainability.
1 parent 2e67c08 commit 9297d1f

14 files changed

Lines changed: 77 additions & 138 deletions

src/mdio/builder/templates/base.py

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,26 @@ def get_unit_by_key(self, key: str) -> AllUnitModel | None:
269269
"""Get units by variable/dimension/coordinate name. Returns None if not found."""
270270
return self._units.get(key, None)
271271

272+
def _dim_coord_metadata(self, name: str) -> VariableMetadata | None:
273+
"""Build metadata for a dimension coordinate.
274+
275+
Dimension coordinates such as ``inline`` or ``crossline`` are integer survey
276+
indices and are inherently unitless. Returning ``None`` here keeps the
277+
``metadata`` field unset on those coordinates rather than wrapping a
278+
``units_v1=None`` placeholder.
279+
280+
Args:
281+
name: Coordinate name to look up units for.
282+
283+
Returns:
284+
A ``VariableMetadata`` carrying the registered unit, or ``None`` if no
285+
unit is registered for ``name``.
286+
"""
287+
unit = self.get_unit_by_key(name)
288+
if unit is None:
289+
return None
290+
return VariableMetadata(units_v1=unit)
291+
272292
def _add_dimensions(self) -> None:
273293
"""Add custom dimensions.
274294
@@ -290,20 +310,14 @@ def _add_coordinates(self) -> None:
290310
name,
291311
dimensions=(name,),
292312
data_type=ScalarType.INT32,
293-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(name)),
313+
metadata=self._dim_coord_metadata(name),
294314
)
295315

296-
# Add non-dimension coordinates with computed chunk sizes
297-
for name in self.coordinate_names:
298-
# Compute optimal chunk size for coordinates (spatial dimensions only)
299-
spatial_shape = self._dim_sizes[:-1] # Exclude vertical dimension
300-
coord_chunk_shape = get_constrained_chunksize(
301-
spatial_shape,
302-
ScalarType.FLOAT64,
303-
MAX_COORDINATES_BYTES,
304-
)
305-
chunk_grid = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape))
316+
spatial_shape = self._dim_sizes[:-1]
317+
coord_chunk_shape = get_constrained_chunksize(spatial_shape, ScalarType.FLOAT64, MAX_COORDINATES_BYTES)
318+
chunk_grid = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape))
306319

320+
for name in self.coordinate_names:
307321
self._builder.add_coordinate(
308322
name=name,
309323
dimensions=self.spatial_dimension_names,
@@ -313,14 +327,9 @@ def _add_coordinates(self) -> None:
313327
)
314328

315329
def _add_trace_mask(self) -> None:
316-
"""Add trace mask variables with computed chunk sizes."""
317-
# Compute optimal chunk size for trace mask (spatial dimensions only)
318-
spatial_shape = self._dim_sizes[:-1] # Exclude vertical dimension
319-
mask_chunk_shape = get_constrained_chunksize(
320-
spatial_shape,
321-
ScalarType.BOOL,
322-
MAX_SIZE_LIVE_MASK,
323-
)
330+
"""Add trace mask variable."""
331+
spatial_shape = self._dim_sizes[:-1]
332+
mask_chunk_shape = get_constrained_chunksize(spatial_shape, ScalarType.BOOL, MAX_SIZE_LIVE_MASK)
324333
chunk_grid = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=mask_chunk_shape))
325334

326335
self._builder.add_variable(
@@ -345,15 +354,7 @@ def _add_trace_headers(self, header_dtype: StructuredType) -> None:
345354
)
346355

347356
def _add_raw_headers(self) -> None:
348-
"""Add raw binary headers variable.
349-
350-
This variable stores the raw binary header bytes for each trace, which can be useful
351-
for preserving original SEG-Y header information. Only supported in Zarr v3 format.
352-
353-
The raw headers variable has:
354-
- Same spatial dimensions as trace headers (all dimensions except vertical)
355-
- No coordinates
356-
"""
357+
"""Add raw 240-byte trace header variable. Zarr v3 only."""
357358
chunk_grid = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=self.full_chunk_shape[:-1]))
358359
self._builder.add_variable(
359360
name="raw_headers",

src/mdio/builder/templates/seismic_2d_cdp.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,28 +53,21 @@ def _add_coordinates(self) -> None:
5353
"cdp",
5454
dimensions=("cdp",),
5555
data_type=ScalarType.INT32,
56-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("cdp")),
5756
)
5857
self._builder.add_coordinate(
5958
self._gather_domain,
6059
dimensions=(self._gather_domain,),
6160
data_type=ScalarType.INT32,
62-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self._gather_domain)),
61+
metadata=self._dim_coord_metadata(self._gather_domain),
6362
)
6463
self._builder.add_coordinate(
6564
self.trace_domain,
6665
dimensions=(self.trace_domain,),
6766
data_type=ScalarType.INT32,
68-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self.trace_domain)),
67+
metadata=self._dim_coord_metadata(self.trace_domain),
6968
)
7069

71-
# Add non-dimension coordinates
72-
coord_spatial_shape = (self._dim_sizes[0],) # cdp
73-
coord_chunk_shape = get_constrained_chunksize(
74-
coord_spatial_shape,
75-
ScalarType.FLOAT64,
76-
MAX_COORDINATES_BYTES,
77-
)
70+
coord_chunk_shape = get_constrained_chunksize(self._dim_sizes[:1], ScalarType.FLOAT64, MAX_COORDINATES_BYTES)
7871
chunk_grid = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape))
7972

8073
compressor = Blosc(cname=BloscCname.zstd)

src/mdio/builder/templates/seismic_2d_streamer_shot.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,20 @@ def _load_dataset_attributes(self) -> dict[str, Any]:
2727
return {"surveyType": "2D", "gatherType": "common_source"}
2828

2929
def _add_coordinates(self) -> None:
30-
# Add dimension coordinates
31-
for name in self._dim_names:
30+
# Add dimension coordinates. shot_point and channel are unitless integer
31+
# indices; only the trace (time/depth) domain carries a unit.
32+
for name in ("shot_point", "channel"):
3233
self._builder.add_coordinate(
3334
name,
3435
dimensions=(name,),
3536
data_type=ScalarType.INT32,
36-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(name)),
3737
)
38+
self._builder.add_coordinate(
39+
self._data_domain,
40+
dimensions=(self._data_domain,),
41+
data_type=ScalarType.INT32,
42+
metadata=self._dim_coord_metadata(self._data_domain),
43+
)
3844

3945
# Add non-dimension coordinates
4046
compressor = compressors.Blosc(cname=compressors.BloscCname.zstd)

src/mdio/builder/templates/seismic_3d_cdp.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,34 +53,26 @@ def _add_coordinates(self) -> None:
5353
"inline",
5454
dimensions=("inline",),
5555
data_type=ScalarType.INT32,
56-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("inline")),
5756
)
5857
self._builder.add_coordinate(
5958
"crossline",
6059
dimensions=("crossline",),
6160
data_type=ScalarType.INT32,
62-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("crossline")),
6361
)
6462
self._builder.add_coordinate(
6563
self._gather_domain,
6664
dimensions=(self._gather_domain,),
6765
data_type=ScalarType.INT32,
68-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self._gather_domain)),
66+
metadata=self._dim_coord_metadata(self._gather_domain),
6967
)
7068
self._builder.add_coordinate(
7169
self.trace_domain,
7270
dimensions=(self.trace_domain,),
7371
data_type=ScalarType.INT32,
74-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self.trace_domain)),
72+
metadata=self._dim_coord_metadata(self.trace_domain),
7573
)
7674

77-
# Add non-dimension coordinates
78-
coord_spatial_shape = (self._dim_sizes[0], self._dim_sizes[1]) # inline, crossline
79-
coord_chunk_shape = get_constrained_chunksize(
80-
coord_spatial_shape,
81-
ScalarType.FLOAT64,
82-
MAX_COORDINATES_BYTES,
83-
)
75+
coord_chunk_shape = get_constrained_chunksize(self._dim_sizes[:2], ScalarType.FLOAT64, MAX_COORDINATES_BYTES)
8476
chunk_grid = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape))
8577

8678
compressor = Blosc(cname=BloscCname.zstd)

src/mdio/builder/templates/seismic_3d_coca.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,40 +44,32 @@ def _add_coordinates(self) -> None:
4444
"inline",
4545
dimensions=("inline",),
4646
data_type=ScalarType.INT32,
47-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("inline")),
4847
)
4948
self._builder.add_coordinate(
5049
"crossline",
5150
dimensions=("crossline",),
5251
data_type=ScalarType.INT32,
53-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("crossline")),
5452
)
5553
self._builder.add_coordinate(
5654
"offset",
5755
dimensions=("offset",),
5856
data_type=ScalarType.INT32,
59-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("offset")), # same unit as X/Y
57+
metadata=self._dim_coord_metadata("offset"),
6058
)
6159
self._builder.add_coordinate(
6260
"azimuth",
6361
dimensions=("azimuth",),
6462
data_type=ScalarType.FLOAT32,
65-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("azimuth")),
63+
metadata=self._dim_coord_metadata("azimuth"),
6664
)
6765
self._builder.add_coordinate(
6866
self.trace_domain,
6967
dimensions=(self.trace_domain,),
7068
data_type=ScalarType.INT32,
71-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self.trace_domain)),
69+
metadata=self._dim_coord_metadata(self.trace_domain),
7270
)
7371

74-
# Add non-dimension coordinates
75-
coord_spatial_shape = (self._dim_sizes[0], self._dim_sizes[1]) # inline, crossline
76-
coord_chunk_shape = get_constrained_chunksize(
77-
coord_spatial_shape,
78-
ScalarType.FLOAT64,
79-
MAX_COORDINATES_BYTES,
80-
)
72+
coord_chunk_shape = get_constrained_chunksize(self._dim_sizes[:2], ScalarType.FLOAT64, MAX_COORDINATES_BYTES)
8173
chunk_grid = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape))
8274

8375
compressor = compressors.Blosc(cname=compressors.BloscCname.zstd)

src/mdio/builder/templates/seismic_3d_obn.py

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -97,31 +97,16 @@ def _add_coordinates(self) -> None:
9797
self._data_domain,
9898
dimensions=(self._data_domain,),
9999
data_type=ScalarType.INT32,
100-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self._data_domain)),
100+
metadata=self._dim_coord_metadata(self._data_domain),
101101
)
102102

103-
# Add non-dimension coordinates with computed chunk sizes
104-
# For 1D coordinates (over receiver)
105-
coord_spatial_shape_1d = (self._dim_sizes[1],) # receiver
106-
coord_chunk_shape_1d = get_constrained_chunksize(
107-
coord_spatial_shape_1d,
108-
ScalarType.FLOAT64,
109-
MAX_COORDINATES_BYTES,
103+
# Chunk grids for receiver-indexed (1D) and shot-indexed (3D) non-dim coordinates.
104+
receiver_chunk_shape = get_constrained_chunksize(
105+
self._dim_sizes[1:2], ScalarType.FLOAT64, MAX_COORDINATES_BYTES
110106
)
111-
chunk_grid_1d = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape_1d))
112-
113-
# For 3D coordinates (over shot_line, gun, shot_index)
114-
coord_spatial_shape_3d = (
115-
self._dim_sizes[2],
116-
self._dim_sizes[3],
117-
self._dim_sizes[4],
118-
) # shot_line, gun, shot_index
119-
coord_chunk_shape_3d = get_constrained_chunksize(
120-
coord_spatial_shape_3d,
121-
ScalarType.FLOAT64,
122-
MAX_COORDINATES_BYTES,
123-
)
124-
chunk_grid_3d = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape_3d))
107+
chunk_grid_1d = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=receiver_chunk_shape))
108+
shot_chunk_shape = get_constrained_chunksize(self._dim_sizes[2:5], ScalarType.FLOAT64, MAX_COORDINATES_BYTES)
109+
chunk_grid_3d = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=shot_chunk_shape))
125110

126111
compressor = Blosc(cname=BloscCname.zstd)
127112
self._builder.add_coordinate(

src/mdio/builder/templates/seismic_3d_offset_tiles.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,37 +39,31 @@ def _add_coordinates(self) -> None:
3939
"inline",
4040
dimensions=("inline",),
4141
data_type=ScalarType.INT32,
42-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("inline")),
4342
)
4443
self._builder.add_coordinate(
4544
"crossline",
4645
dimensions=("crossline",),
4746
data_type=ScalarType.INT32,
48-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("crossline")),
4947
)
5048
self._builder.add_coordinate(
5149
"inline_offset_tile",
5250
dimensions=("inline_offset_tile",),
5351
data_type=ScalarType.INT16,
54-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("inline_offset_tile")),
5552
)
5653
self._builder.add_coordinate(
5754
"crossline_offset_tile",
5855
dimensions=("crossline_offset_tile",),
5956
data_type=ScalarType.INT16,
60-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("crossline_offset_tile")),
6157
)
6258
self._builder.add_coordinate(
6359
self.trace_domain,
6460
dimensions=(self.trace_domain,),
6561
data_type=ScalarType.INT32,
66-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self.trace_domain)),
62+
metadata=self._dim_coord_metadata(self.trace_domain),
6763
)
6864

6965
# Add non-dimension coordinates
7066
compressor = compressors.Blosc(cname=compressors.BloscCname.zstd)
71-
72-
# CDP coordinates (vary by inline, crossline)
7367
self._builder.add_coordinate(
7468
"cdp_x",
7569
dimensions=("inline", "crossline"),

src/mdio/builder/templates/seismic_3d_receiver_gathers.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,17 @@ def _add_coordinates(self) -> None:
3939
"receiver",
4040
dimensions=("receiver",),
4141
data_type=ScalarType.UINT32,
42-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("receiver")),
4342
)
4443
self._builder.add_coordinate(
4544
"shot_line",
4645
dimensions=("shot_line",),
4746
data_type=ScalarType.UINT32,
48-
metadata=VariableMetadata(units_v1=self.get_unit_by_key("shot_line")),
4947
)
5048
self._builder.add_coordinate(
5149
self.trace_domain,
5250
dimensions=(self.trace_domain,),
5351
data_type=ScalarType.INT32,
54-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self.trace_domain)),
52+
metadata=self._dim_coord_metadata(self.trace_domain),
5553
)
5654

5755
# Add non-dimension coordinates

src/mdio/builder/templates/seismic_3d_shot_receiver_line.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def _add_coordinates(self) -> None:
5858
self._data_domain,
5959
dimensions=(self._data_domain,),
6060
data_type=ScalarType.INT32,
61-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self._data_domain)),
61+
metadata=self._dim_coord_metadata(self._data_domain),
6262
)
6363

6464
# Add non-dimension coordinates

src/mdio/builder/templates/seismic_3d_streamer_field.py

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -85,37 +85,16 @@ def _add_coordinates(self) -> None:
8585
self._data_domain,
8686
dimensions=(self._data_domain,),
8787
data_type=ScalarType.INT32,
88-
metadata=VariableMetadata(units_v1=self.get_unit_by_key(self._data_domain)),
88+
metadata=self._dim_coord_metadata(self._data_domain),
8989
)
9090

91-
# Add non-dimension coordinates with computed chunk sizes
92-
# For 3D coordinates (over sail_line, gun, shot_index)
93-
coord_spatial_shape_3d = (
94-
self._dim_sizes[0],
95-
self._dim_sizes[1],
96-
self._dim_sizes[2],
97-
) # sail_line, gun, shot_index
98-
coord_chunk_shape_3d = get_constrained_chunksize(
99-
coord_spatial_shape_3d,
100-
ScalarType.FLOAT64,
101-
MAX_COORDINATES_BYTES,
91+
# Chunk grids for shot-indexed (3D) and receiver-indexed (5D) non-dim coordinates.
92+
shot_chunk_shape = get_constrained_chunksize(self._dim_sizes[:3], ScalarType.FLOAT64, MAX_COORDINATES_BYTES)
93+
chunk_grid_3d = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=shot_chunk_shape))
94+
receiver_chunk_shape = get_constrained_chunksize(
95+
self._dim_sizes[:5], ScalarType.FLOAT64, MAX_COORDINATES_BYTES
10296
)
103-
chunk_grid_3d = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape_3d))
104-
105-
# For 5D coordinates (over sail_line, gun, shot_index, cable, channel)
106-
coord_spatial_shape_5d = (
107-
self._dim_sizes[0],
108-
self._dim_sizes[1],
109-
self._dim_sizes[2],
110-
self._dim_sizes[3],
111-
self._dim_sizes[4],
112-
) # sail_line, gun, shot_index, cable, channel
113-
coord_chunk_shape_5d = get_constrained_chunksize(
114-
coord_spatial_shape_5d,
115-
ScalarType.FLOAT64,
116-
MAX_COORDINATES_BYTES,
117-
)
118-
chunk_grid_5d = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=coord_chunk_shape_5d))
97+
chunk_grid_5d = RegularChunkGrid(configuration=RegularChunkShape(chunk_shape=receiver_chunk_shape))
11998

12099
compressor = Blosc(cname=BloscCname.zstd)
121100
self._builder.add_coordinate(

0 commit comments

Comments
 (0)