22
33from __future__ import annotations
44
5+ import math
6+ from turtle import speed
57from typing import TYPE_CHECKING
68
79import numpy as np
810import pytest
911from segy .standards import get_segy_standard
1012
13+ from mdio .builder .schemas .v1 .units import LengthUnitEnum , LengthUnitModel , SpeedUnitEnum , SpeedUnitModel , TimeUnitEnum , TimeUnitModel
14+
1115if TYPE_CHECKING :
1216 from pathlib import Path
1317
1418 from xarray import Dataset as xr_Dataset
1519
20+ from mdio .builder .schemas .v1 .stats import CenteredBinHistogram , SummaryStatistics
21+ from tests .integration .test_segy_roundtrip_teapot import text_header_teapot_dome
1622from tests .integration .testing_helpers import get_values
1723from tests .integration .testing_helpers import validate_variable
1824
1925from mdio import __version__
20- from mdio .api .io import open_mdio
26+ from mdio .api .io import open_mdio , to_mdio
2127from mdio .core import Dimension
22- from mdio .creators .mdio import create_empty_mdio
28+ from mdio .creators .mdio import create_empty
2329
2430
2531class TestCreateEmptyPostStack3DTimeMdio :
@@ -51,7 +57,7 @@ def _validate_empty_mdio_dataset(cls, ds: xr_Dataset, has_headers: bool) -> None
5157 # Validate the trace mask (should be all True for empty dataset)
5258 validate_variable (ds , "trace_mask" , (200 , 300 ), ("inline" , "crossline" ), np .bool_ , None , None )
5359 trace_mask = ds ["trace_mask" ].values
54- assert np .all (trace_mask ), "All traces should be marked as live in empty dataset"
60+ assert not np .any (trace_mask ), "All traces should be marked as dead in empty dataset"
5561
5662 # Validate the amplitude data (should be empty)
5763 validate_variable (ds , "amplitude" , (200 , 300 , 750 ), ("inline" , "crossline" , "time" ), np .float32 , None , None )
@@ -67,7 +73,7 @@ def _create_empty_mdio(cls, create_headers: bool, output_path: Path, overwrite:
6773 ]
6874
6975 # Call create_empty_mdio
70- create_empty_mdio (
76+ create_empty (
7177 mdio_template_name = "PostStack3DTime" ,
7278 dimensions = dims ,
7379 output_path = output_path ,
@@ -166,3 +172,73 @@ def test_overwrite_behavior(self, empty_mdio_dir: Path) -> None:
166172 # Verify the garbage data was overwritten (should not exist)
167173 assert not garbage_file .exists (), "Garbage file should have been overwritten"
168174 assert not garbage_dir .exists (), "Garbage directory should have been overwritten"
175+
176+
177+ def test_populate_empty_dataset (self , mdio_with_headers : Path ) -> None :
178+ """Test showing how to populate empty dataset."""
179+
180+ # Open an empty PostStack3DTime dataset with SEG-Y 1.0 headers
181+ # NOTES:
182+ # When this empty dataset was created from the 'PostStack3DTime' template and dimensions,
183+ # * 'inline', 'crossline', and 'time' dimension coordinate variables were created and pre-populated
184+ # * 'cdp_x', 'cdp_y' non-dimensional coordinate variables were created
185+ # * 'amplitude' variable was created (the name of this variable is specified in the template)
186+ # HACK: in this example, we will use this variable to store the velocity data
187+ # * 'trace_mask' variable was created and pre-populated with 'False' fill values
188+ # (all traces are marked as dead)
189+ # * 'headers' segy trace headers variable was created (if the dataset was created with create_headers=true)
190+ # * dataset attribute called 'attributes' was created
191+ ds = open_mdio (mdio_with_headers )
192+
193+ # 1.A) Populate dataset's velocity
194+ var_name = ds .attrs ["attributes" ]["defaultVariableName" ]
195+ velocity = ds [var_name ]
196+ velocity [:5 ,:,:] = 1
197+ velocity [5 :10 ,:,:] = 2
198+ velocity [50 :100 ,:,:] = 3
199+ velocity [150 :175 ,:,:] = - 1
200+
201+ # 1.B) Populate dataset's velocity statistics (optional)
202+ nonzero_samples = np .ma .masked_invalid (velocity , copy = False )
203+ stats = SummaryStatistics (
204+ count = nonzero_samples .count (),
205+ min = nonzero_samples .min (),
206+ max = nonzero_samples .max (),
207+ sum = nonzero_samples .sum (dtype = "float64" ),
208+ sum_squares = (np .ma .power (nonzero_samples , 2 ).sum (dtype = "float64" )),
209+ histogram = CenteredBinHistogram (bin_centers = [], counts = []),
210+ )
211+ velocity .attrs ["statsV1" ] = stats .model_dump_json ()
212+
213+ # 1.C) Set coordinate and data variable units (optional)
214+ ds .time ["unitsV1" ] = TimeUnitModel (time = TimeUnitEnum .MILLISECOND ).model_dump_json ()
215+
216+ ds .cdp_x .attrs ["unitsV1" ] = LengthUnitModel (length = LengthUnitEnum .FOOT ).model_dump_json ()
217+ ds .cdp_x .attrs ["unitsV1" ] = LengthUnitModel (length = LengthUnitEnum .FOOT ).model_dump_json ()
218+
219+ velocity .attrs ["unitsV1" ] = SpeedUnitModel (speed = SpeedUnitEnum .FEET_PER_SECOND ).model_dump_json ()
220+
221+ # 3) Populate the non-dimensional coordinate variables 'cdp_x' and 'cdp_y' (optional)
222+ origin = [270000 , 3290000 ] # survey x, y origin
223+ inline_azimuth_rad = 0.523599 # survey orientation, in radians, from the north to the east (30 degrees)
224+ spacing = [50 , 50 ] # survey inline, crossline spacing
225+ inline_grid , xline_grid = np .meshgrid (ds .inline .values , ds .crossline .values , indexing = 'ij' )
226+ sin_azimuth = math .sin (inline_azimuth_rad )
227+ cos_azimuth = math .cos (inline_azimuth_rad )
228+ ds .cdp_x [:] = origin [0 ] + inline_grid * spacing [0 ] * sin_azimuth + xline_grid * spacing [1 ] * cos_azimuth
229+ ds .cdp_y [:] = origin [1 ] + inline_grid * spacing [0 ] * cos_azimuth - xline_grid * spacing [1 ] * sin_azimuth
230+
231+ # 4) Populate dataset's trace mask (optional)
232+ ds .trace_mask [:] = ~ np .isnan (velocity [:,:,0 ])
233+
234+ # 5) Populate dataset's segy trace headers, if those were created (optional)
235+ if "headers" in ds .variables :
236+ ds .headers ["cdp_x" ][:] = ds .cdp_x
237+ ds .headers ["cdp_y" ][:] = ds .cdp_y
238+
239+ # 5) Create dataset's custom attributes (optional)
240+ ds .attrs ["attributes" ]["createdBy" ] = "John Doe"
241+
242+ output_path = mdio_with_headers .parent / "populated_empty.mdio"
243+ to_mdio (ds , output_path = output_path , mode = "w" , compute = True )
244+
0 commit comments