Skip to content

Commit 071df0b

Browse files
authored
Merge branch 'main' into numpy_ingestion
2 parents b1fe3d5 + 2e5c057 commit 071df0b

29 files changed

Lines changed: 2654 additions & 285 deletions
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Constraints for building source distributions
2+
# pytest-dependency uses a legacy setup.py incompatible with setuptools 81+
3+
# See: https://github.com/RKrahl/pytest-dependency/issues/91
4+
setuptools<81

.github/workflows/constraints.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
bump-my-version==1.2.4
1+
bump-my-version==1.2.6
22
nox==2025.11.12

.github/workflows/labeler.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
steps:
1313
- name: Check out the repository
14-
uses: actions/checkout@v5
14+
uses: actions/checkout@v6
1515

1616
- name: Run Labeler
1717
uses: crazy-max/ghaction-github-labeler@v5

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313
steps:
1414
- name: Check out the repository
15-
uses: actions/checkout@v5
15+
uses: actions/checkout@v6
1616
with:
1717
fetch-depth: 2
1818

.github/workflows/tests.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434

3535
steps:
3636
- name: Check out the repository
37-
uses: actions/checkout@v5
37+
uses: actions/checkout@v6
3838

3939
- name: Set up Python ${{ matrix.python }}
4040
uses: actions/setup-python@v6
@@ -69,7 +69,7 @@ jobs:
6969
print("result={}".format(result), file=open(os.environ['GITHUB_OUTPUT'], 'a'))
7070
7171
- name: Restore pre-commit cache
72-
uses: actions/cache@v4
72+
uses: actions/cache@v5
7373
if: matrix.session == 'pre-commit'
7474
with:
7575
path: ~/.cache/pre-commit
@@ -83,15 +83,15 @@ jobs:
8383
8484
- name: Upload coverage data
8585
if: always() && matrix.session == 'tests'
86-
uses: actions/upload-artifact@v5
86+
uses: actions/upload-artifact@v6
8787
with:
8888
name: coverage-data-${{ matrix.os }}-${{ matrix.python }}
8989
include-hidden-files: true
9090
path: ".coverage.*"
9191

9292
- name: Upload documentation
9393
if: matrix.session == 'docs-build'
94-
uses: actions/upload-artifact@v5
94+
uses: actions/upload-artifact@v6
9595
with:
9696
name: docs
9797
path: docs/_build
@@ -101,7 +101,7 @@ jobs:
101101
needs: tests
102102
steps:
103103
- name: Check out the repository
104-
uses: actions/checkout@v5
104+
uses: actions/checkout@v6
105105

106106
- name: Install the pinned version of uv
107107
uses: astral-sh/setup-uv@v7
@@ -115,7 +115,7 @@ jobs:
115115
nox --version
116116
117117
- name: Download coverage data
118-
uses: actions/download-artifact@v6
118+
uses: actions/download-artifact@v7
119119
with:
120120
pattern: coverage-data-*
121121
merge-multiple: true
@@ -129,6 +129,6 @@ jobs:
129129
nox --session=coverage -- xml
130130
131131
- name: Upload coverage report
132-
uses: codecov/codecov-action@v5.5.1
132+
uses: codecov/codecov-action@v5.5.2
133133
env:
134134
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

docs/guides/grid_overrides.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Grid Overrides
2+
3+
```{warning}
4+
🚧👷🏻 We are actively working on updating the documentation and adding missing features to v1 release. Please check back later for more updates!
5+
```
6+
7+
Grid overrides are transformations applied during SEG-Y import that modify how trace headers are interpreted and indexed. They handle complex acquisition geometries that cannot be represented by simple header-to-dimension mappings.
8+
9+
## Overview
10+
11+
When importing SEG-Y data, MDIO maps trace header fields to dataset dimensions. However, real-world seismic data often has complexities that require additional processing. Grid overrides address these issues by transforming header values before indexing.
12+
13+
## CalculateShotIndex
14+
15+
Calculates a dense `shot_index` dimension from sparse or interleaved `shot_point` values. Required for the `ObnReceiverGathers3D` template.
16+
17+
**Supported Templates:** `ObnReceiverGathers3D`
18+
19+
**Required Headers:** `shot_line`, `gun`, `shot_point`
20+
21+
**How it works:**
22+
23+
In multi-gun OBN acquisition, shot points are often interleaved across guns:
24+
25+
```
26+
Before (interleaved shot_point):
27+
Gun 1: 1, 3, 5, 7, ...
28+
Gun 2: 2, 4, 6, 8, ...
29+
30+
After (dense shot_index):
31+
Gun 1: 0, 1, 2, 3, ...
32+
Gun 2: 0, 1, 2, 3, ...
33+
```
34+
35+
The override detects the geometry type and only applies the transformation when shot points are actually interleaved (Type B geometry). For non-interleaved data (Type A), shot points are used directly.
36+
37+
**Usage:**
38+
39+
```python
40+
segy_to_mdio(
41+
input_path="obn_data.sgy",
42+
output_path="obn_data.mdio",
43+
segy_spec=obn_spec,
44+
mdio_template=get_template("ObnReceiverGathers3D"),
45+
grid_overrides={"CalculateShotIndex": True},
46+
)
47+
```
48+
49+
```{note}
50+
See [OBN Data Import](obn_data_import.md) for a complete guide on importing OBN data.
51+
```
52+
53+
## Special Behaviors
54+
55+
Some templates have special behaviors that are applied automatically during import, independent of grid overrides.
56+
57+
### Component Synthesis (OBN)
58+
59+
When using the `ObnReceiverGathers3D` template, if the SEG-Y specification does not include a `component` field, MDIO automatically synthesizes it with value `1` for all traces. This allows single-component data (e.g., hydrophone-only) to use the same template without modification.
60+
61+
```{note}
62+
A warning is logged when component is synthesized:
63+
64+
> SEG-Y headers do not contain 'component' field required by template 'ObnReceiverGathers3D'.
65+
> Synthesizing 'component' dimension with constant value 1 for all traces.
66+
```
67+
68+
## Error Handling
69+
70+
Grid overrides validate their requirements and raise specific exceptions:
71+
72+
| Exception | Cause |
73+
| ----------------------------------- | ----------------------------------- |
74+
| `GridOverrideUnknownError` | Unknown override name passed |
75+
| `GridOverrideKeysError` | Required header fields missing |
76+
| `GridOverrideMissingParameterError` | Required parameters not provided |
77+
| `GridOverrideIncompatibleError` | Override incompatible with template |
78+
79+
**Example error message:**
80+
81+
```
82+
GridOverrideKeysError: Grid override 'CalculateShotIndex' requires keys: {'shot_line', 'gun', 'shot_point'}
83+
```
84+
85+
## See Also
86+
87+
- [OBN Data Import](obn_data_import.md) - Complete guide for OBN data
88+
- [Template Registry](../template_registry.md) - Available templates
89+
- [Tutorials](../tutorials/index.md) - Hands-on guides

docs/guides/index.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Guides
2+
3+
Welcome to the MDIO guides. This section provides in-depth documentation on advanced features and specialized workflows.
4+
5+
## Topics
6+
7+
```{toctree}
8+
:maxdepth: 1
9+
:titlesonly:
10+
11+
grid_overrides
12+
obn_data_import
13+
```
14+
15+
## Overview
16+
17+
### Grid Overrides
18+
19+
Grid overrides are transformations applied during SEG-Y import that modify how trace headers are interpreted and indexed. They handle complex acquisition geometries like multi-gun acquisition with interleaved shot points.
20+
21+
See [Grid Overrides](grid_overrides.md) for documentation.
22+
23+
### OBN Data Import
24+
25+
Ocean Bottom Node (OBN) data has unique characteristics requiring specialized handling. The OBN guide covers:
26+
27+
- The `ObnReceiverGathers3D` template
28+
- Required grid overrides for OBN
29+
- Component synthesis for single-component data
30+
31+
See [OBN Data Import](obn_data_import.md) for the complete guide.

docs/guides/obn_data_import.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# OBN Data Import
2+
3+
This guide covers the `ObnReceiverGathers3D` template for importing Ocean Bottom Node (OBN) seismic data into MDIO.
4+
5+
## Template Overview
6+
7+
The `ObnReceiverGathers3D` template organizes data with the following dimensions:
8+
9+
| Dimension | Description |
10+
| -------------- | ------------------------------------------------------------------------------------------ |
11+
| `component` | Sensor component (e.g., 1=X, 2=Y, 3=Z, 4=Hydrophone) |
12+
| `receiver` | Ocean bottom node receiver ID |
13+
| `shot_line` | Shot line identifier |
14+
| `gun` | Gun identifier for multi-gun sources |
15+
| `shot_index` | Calculated dense index for shots (see [Required Grid Overrides](#required-grid-overrides)) |
16+
| `time`/`depth` | Vertical sample axis |
17+
18+
### Coordinates
19+
20+
- **Logical coordinates**: `shot_point` (original values), `orig_field_record_num`
21+
- **Physical coordinates**: `group_coord_x`, `group_coord_y`, `source_coord_x`, `source_coord_y`
22+
23+
```{note}
24+
The `shot_index` dimension is calculated (0 to N-1) from `shot_point` values during ingestion. Original `shot_point` values are preserved as a coordinate indexed by `(shot_line, gun, shot_index)`.
25+
```
26+
27+
## Required Grid Overrides
28+
29+
### CalculateShotIndex (Required)
30+
31+
The `CalculateShotIndex` grid override is **required** for the `ObnReceiverGathers3D` template. It calculates the `shot_index` dimension from `shot_point` values. Without this override, the import will fail with an error:
32+
33+
> Required computed fields ['shot_index'] for template ObnReceiverGathers3D not found after grid overrides.
34+
35+
This override handles multi-gun acquisition where shot points are interleaved across guns, calculating a dense `shot_index` from sparse `shot_point` values:
36+
37+
```
38+
Before (interleaved shot_point):
39+
Gun 1: 1, 3, 5, 7, ...
40+
Gun 2: 2, 4, 6, 8, ...
41+
42+
After (dense shot_index):
43+
Gun 1: 0, 1, 2, 3, ...
44+
Gun 2: 0, 1, 2, 3, ...
45+
```
46+
47+
For `ObnReceiverGathers3D`, the override uses `shot_line` as the line field and requires `shot_line`, `gun`, and `shot_point` headers.
48+
49+
## Special Behaviors
50+
51+
### Component Synthesis
52+
53+
When the SEG-Y spec does not include a `component` field, MDIO automatically synthesizes it with value `1` for all traces. This allows single-component data (e.g., hydrophone-only) to use the same template without modification.
54+
55+
```{note}
56+
A warning is logged when component is synthesized:
57+
> SEG-Y headers do not contain 'component' field required by template 'ObnReceiverGathers3D'.
58+
> Synthesizing 'component' dimension with constant value 1 for all traces.
59+
```
60+
61+
## Usage
62+
63+
### Basic Import
64+
65+
```python
66+
from segy.schema import HeaderField
67+
from segy.standards import get_segy_standard
68+
69+
from mdio import segy_to_mdio
70+
from mdio.builder.template_registry import get_template
71+
72+
# Define SEG-Y header mapping
73+
obn_headers = [
74+
HeaderField(name="orig_field_record_num", byte=9, format="int32"),
75+
HeaderField(name="receiver", byte=13, format="int32"),
76+
HeaderField(name="shot_point", byte=17, format="int32"),
77+
HeaderField(name="shot_line", byte=133, format="int16"),
78+
HeaderField(name="gun", byte=171, format="int16"),
79+
HeaderField(name="component", byte=189, format="int16"),
80+
HeaderField(name="coordinate_scalar", byte=71, format="int16"),
81+
HeaderField(name="source_coord_x", byte=73, format="int32"),
82+
HeaderField(name="source_coord_y", byte=77, format="int32"),
83+
HeaderField(name="group_coord_x", byte=81, format="int32"),
84+
HeaderField(name="group_coord_y", byte=85, format="int32"),
85+
]
86+
87+
obn_spec = get_segy_standard(1.0).customize(trace_header_fields=obn_headers)
88+
89+
segy_to_mdio(
90+
input_path="obn_data.sgy",
91+
output_path="obn_data.mdio",
92+
segy_spec=obn_spec,
93+
mdio_template=get_template("ObnReceiverGathers3D"),
94+
grid_overrides={"CalculateShotIndex": True},
95+
overwrite=True,
96+
)
97+
```
98+
99+
### Single-Component Data
100+
101+
For data without a `component` header field, simply omit it from the spec:
102+
103+
```python
104+
# Same as above, but without the component field
105+
obn_headers = [
106+
HeaderField(name="orig_field_record_num", byte=9, format="int32"),
107+
HeaderField(name="receiver", byte=13, format="int32"),
108+
HeaderField(name="shot_point", byte=17, format="int32"),
109+
HeaderField(name="shot_line", byte=133, format="int16"),
110+
HeaderField(name="gun", byte=171, format="int16"),
111+
# component omitted - will be synthesized
112+
HeaderField(name="coordinate_scalar", byte=71, format="int16"),
113+
HeaderField(name="source_coord_x", byte=73, format="int32"),
114+
HeaderField(name="source_coord_y", byte=77, format="int32"),
115+
HeaderField(name="group_coord_x", byte=81, format="int32"),
116+
HeaderField(name="group_coord_y", byte=85, format="int32"),
117+
]
118+
```
119+
120+
### Exploring the Data
121+
122+
```python
123+
from mdio import open_mdio
124+
125+
ds = open_mdio("obn_data.mdio")
126+
127+
# View dimensions
128+
print(ds.sizes)
129+
# {'component': 4, 'receiver': 100, 'shot_line': 10, 'gun': 2, 'shot_index': 500, 'time': 2001}
130+
131+
# Access original shot_point values (preserved as coordinate)
132+
print(ds["shot_point"].dims) # ('shot_line', 'gun', 'shot_index')
133+
134+
# Select a receiver gather
135+
receiver_gather = ds.sel(receiver=150, component=4)
136+
receiver_gather["amplitude"].plot()
137+
```
138+
139+
## Required Header Fields
140+
141+
| Field | Required | Notes |
142+
| ----------------------- | -------- | ----------------------------------- |
143+
| `receiver` | Yes | |
144+
| `shot_line` | Yes | |
145+
| `gun` | Yes | |
146+
| `shot_point` | Yes | |
147+
| `component` | No | Synthesized with value 1 if missing |
148+
| `coordinate_scalar` | Yes | |
149+
| `source_coord_x` | Yes | |
150+
| `source_coord_y` | Yes | |
151+
| `group_coord_x` | Yes | |
152+
| `group_coord_y` | Yes | |
153+
| `orig_field_record_num` | Yes | |
154+
155+
## See Also
156+
157+
- [Grid Overrides](grid_overrides.md) - All available grid overrides
158+
- [Template Registry](../template_registry.md)
159+
- [Quickstart Tutorial](../tutorials/quickstart.ipynb)

docs/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ tutorials/index
2727
api_reference
2828
```
2929

30+
```{toctree}
31+
:hidden:
32+
:caption: Guides
33+
34+
guides/index
35+
```
36+
3037
```{toctree}
3138
:hidden:
3239
:caption: Core Concepts and Structures

0 commit comments

Comments
 (0)