0
# Utilities
1
2
Helper functions for format conversion, metadata extraction, array-to-SEG-Y conversion, and common seismic processing operations. These utilities simplify common workflows and provide high-level convenience functions.
3
4
## Capabilities
5
6
### Sample Rate and Timing
7
8
Functions for working with sample rates, timing information, and creating sample indices.
9
10
```python { .api }
11
def dt(f, fallback_dt=4000.0):
12
"""
13
Infer sample rate from SEG-Y file.
14
15
Parameters:
16
- f (SegyFile): Open SEG-Y file handle
17
- fallback_dt (float): Fallback sample rate in microseconds if cannot be determined
18
19
Returns:
20
float: Sample interval in microseconds
21
22
Raises:
23
ValueError: If sample rate cannot be determined and no fallback provided
24
"""
25
26
def sample_indexes(segyfile, t0=0.0, dt_override=None):
27
"""
28
Create sample index list at specified depth/time values.
29
30
Parameters:
31
- segyfile (SegyFile): Open SEG-Y file handle
32
- t0 (float): Start time in milliseconds, default 0.0
33
- dt_override (float): Override sample rate in milliseconds
34
35
Returns:
36
numpy.ndarray: Array of sample indices/times
37
"""
38
```
39
40
**Usage Example:**
41
42
```python
43
import segyio
44
import numpy as np
45
46
with segyio.open('data.sgy') as f:
47
# Get sample rate
48
sample_rate = segyio.dt(f)
49
print(f"Sample rate: {sample_rate} microseconds ({sample_rate/1000} ms)")
50
51
# Create time axis
52
times = segyio.sample_indexes(f, t0=0.0)
53
print(f"Time range: {times[0]} to {times[-1]} ms")
54
55
# Create custom time axis with different start time
56
delayed_times = segyio.sample_indexes(f, t0=100.0) # Start at 100ms
57
58
# Override sample rate
59
custom_times = segyio.sample_indexes(f, dt_override=2.0) # 2ms sampling
60
```
61
62
### Text Header Formatting
63
64
Utilities for creating and formatting SEG-Y textual headers.
65
66
```python { .api }
67
def create_text_header(lines):
68
"""
69
Format textual header from line dictionary.
70
71
Parameters:
72
- lines (dict): Line number to text mapping (1-40)
73
74
Returns:
75
str: Formatted EBCDIC header string (3200 bytes)
76
77
Raises:
78
ValueError: Invalid line numbers or content
79
"""
80
```
81
82
**Usage Example:**
83
84
```python
85
import segyio
86
87
# Create custom textual header
88
header_lines = {
89
1: "C 1 CLIENT: EXAMPLE SEISMIC COMPANY",
90
2: "C 2 DATA TYPE: MIGRATED 3D SEISMIC DATA",
91
3: "C 3 AREA: NORTH SEA BLOCK 123/45",
92
4: "C 4 ",
93
5: "C 5 PROCESSING SEQUENCE:",
94
6: "C 6 1. DEMULTIPLE",
95
7: "C 7 2. DECONVOLUTION",
96
8: "C 8 3. VELOCITY ANALYSIS",
97
9: "C 9 4. DMO CORRECTION",
98
10: "C10 5. POST-STACK TIME MIGRATION",
99
11: "C11 ",
100
12: "C12 DATUM: MEAN SEA LEVEL",
101
13: "C13 COORDINATE SYSTEM: UTM ZONE 31N",
102
14: "C14 SAMPLE RATE: 4 MS",
103
15: "C15 RECORD LENGTH: 2000 MS"
104
}
105
106
text_header = segyio.create_text_header(header_lines)
107
108
# Use in file creation
109
spec = segyio.spec()
110
# ... configure spec ...
111
112
with segyio.create('output.sgy', spec) as f:
113
f.text[0] = text_header
114
```
115
116
### Data Format Conversion
117
118
Functions for converting between different data formats and handling IBM floating point.
119
120
```python { .api }
121
def native(data, format=SegySampleFormat.IBM_FLOAT_4_BYTE, copy=True):
122
"""
123
Convert numpy array to native float format.
124
125
Parameters:
126
- data (numpy.ndarray): Input data array
127
- format (int or SegySampleFormat): Source data format
128
- copy (bool): Whether to copy data or modify in-place
129
130
Returns:
131
numpy.ndarray: Data converted to native float format
132
133
Raises:
134
ValueError: Unsupported format or invalid data
135
"""
136
```
137
138
**Usage Example:**
139
140
```python
141
import segyio
142
import numpy as np
143
144
with segyio.open('ibm_data.sgy') as f:
145
# Read trace with IBM float format
146
ibm_trace = f.trace[0]
147
148
# Convert to native IEEE float
149
ieee_trace = segyio.native(ibm_trace, segyio.SegySampleFormat.IBM_FLOAT_4_BYTE)
150
151
# Check format in binary header
152
format_code = f.bin[segyio.BinField.Format]
153
if format_code == segyio.SegySampleFormat.IBM_FLOAT_4_BYTE:
154
print("Converting from IBM to IEEE float")
155
converted = segyio.native(ibm_trace, format_code)
156
else:
157
converted = ibm_trace # Already in native format
158
```
159
160
### Data Collection and Aggregation
161
162
Functions for collecting and combining trace data into larger arrays.
163
164
```python { .api }
165
def collect(itr):
166
"""
167
Collect iterable of traces/lines into single ndarray.
168
169
Parameters:
170
- itr (iterable): Iterable of numpy.ndarray objects (traces, lines, etc.)
171
172
Returns:
173
numpy.ndarray: Combined array with additional dimension
174
175
Raises:
176
ValueError: Inconsistent array shapes
177
"""
178
179
def cube(f):
180
"""
181
Read full 3D cube from file into memory.
182
183
Parameters:
184
- f (str or SegyFile): File path or open file handle
185
186
Returns:
187
numpy.ndarray: 3D array (inlines, crosslines, samples)
188
189
Raises:
190
ValueError: File is not 3D structured
191
MemoryError: Insufficient memory for cube
192
"""
193
```
194
195
**Usage Example:**
196
197
```python
198
import segyio
199
import numpy as np
200
201
# Read and collect multiple inlines
202
with segyio.open('3d_data.sgy') as f:
203
# Collect first 10 inlines into 3D array
204
inline_list = [f.iline[il] for il in f.ilines[:10]]
205
collected_inlines = segyio.collect(inline_list)
206
print(f"Collected shape: {collected_inlines.shape}")
207
208
# Read full cube (memory intensive!)
209
full_cube = segyio.cube(f)
210
print(f"Full cube shape: {full_cube.shape}")
211
212
# Collect traces with processing
213
with segyio.open('data.sgy') as f:
214
def process_trace(trace):
215
# Apply some processing
216
return trace * 2.0 # Simple gain
217
218
processed_traces = segyio.collect(
219
process_trace(f.trace[i]) for i in range(min(100, f.tracecount))
220
)
221
```
222
223
### Survey Metadata Extraction
224
225
Functions for extracting survey metadata and geometry information.
226
227
```python { .api }
228
def rotation(f, line='fast'):
229
"""
230
Find rotation angle of survey.
231
232
Parameters:
233
- f (SegyFile): Open SEG-Y file handle
234
- line (str): 'fast' or 'slow' dimension
235
236
Returns:
237
tuple: (rotation_angle, cdpx_center, cdpy_center)
238
"""
239
240
def metadata(f):
241
"""
242
Extract survey metadata as spec object.
243
244
Parameters:
245
- f (str or SegyFile): File path or open file handle
246
247
Returns:
248
segyio.spec: Specification object containing file metadata
249
"""
250
```
251
252
**Usage Example:**
253
254
```python
255
import segyio
256
257
# Analyze survey rotation
258
with segyio.open('3d_survey.sgy') as f:
259
rotation_angle, center_x, center_y = segyio.rotation(f)
260
print(f"Survey rotation: {rotation_angle:.2f} degrees")
261
print(f"Survey center: ({center_x:.2f}, {center_y:.2f})")
262
263
# Extract complete metadata
264
survey_spec = segyio.metadata('survey.sgy')
265
print(f"Inline range: {survey_spec.ilines}")
266
print(f"Crossline range: {survey_spec.xlines}")
267
print(f"Sample count: {len(survey_spec.samples)}")
268
print(f"Data format: {survey_spec.format}")
269
```
270
271
### Array-to-SEG-Y Conversion
272
273
Functions for creating SEG-Y files from numpy arrays with various geometries.
274
275
```python { .api }
276
def from_array(filename, data, iline=189, xline=193, format=SegySampleFormat.IBM_FLOAT_4_BYTE, dt=4000, delrt=0):
277
"""
278
Create SEG-Y file from n-dimensional numpy array.
279
280
Parameters:
281
- filename (str): Output file path
282
- data (numpy.ndarray): Input data array
283
- iline (int): Inline header field number
284
- xline (int): Crossline header field number
285
- format (SegySampleFormat): Output data format
286
- dt (int): Sample interval in microseconds
287
- delrt (int): Delay recording time in milliseconds
288
289
Returns:
290
None: Creates file on disk
291
"""
292
293
def from_array2D(filename, data, format=SegySampleFormat.IBM_FLOAT_4_BYTE, dt=4000, delrt=0):
294
"""
295
Create SEG-Y file from 2D array (shot records).
296
297
Parameters:
298
- filename (str): Output file path
299
- data (numpy.ndarray): 2D array (traces, samples)
300
- format (SegySampleFormat): Output data format
301
- dt (int): Sample interval in microseconds
302
- delrt (int): Delay recording time in milliseconds
303
304
Returns:
305
None: Creates file from 2D geometry
306
"""
307
308
def from_array3D(filename, data, iline=189, xline=193, format=SegySampleFormat.IBM_FLOAT_4_BYTE, dt=4000, delrt=0):
309
"""
310
Create SEG-Y file from 3D array (post-stack volume).
311
312
Parameters:
313
- filename (str): Output file path
314
- data (numpy.ndarray): 3D array (inlines, crosslines, samples)
315
- iline (int): Inline header field number
316
- xline (int): Crossline header field number
317
- format (SegySampleFormat): Output data format
318
- dt (int): Sample interval in microseconds
319
- delrt (int): Delay recording time in milliseconds
320
321
Returns:
322
None: Creates file from 3D geometry
323
"""
324
325
def from_array4D(filename, data, iline=189, xline=193, format=SegySampleFormat.IBM_FLOAT_4_BYTE, dt=4000, delrt=0):
326
"""
327
Create SEG-Y file from 4D array (pre-stack volume).
328
329
Parameters:
330
- filename (str): Output file path
331
- data (numpy.ndarray): 4D array (inlines, crosslines, offsets, samples)
332
- iline (int): Inline header field number
333
- xline (int): Crossline header field number
334
- format (SegySampleFormat): Output data format
335
- dt (int): Sample interval in microseconds
336
- delrt (int): Delay recording time in milliseconds
337
338
Returns:
339
None: Creates file from 4D geometry
340
"""
341
```
342
343
**Usage Example:**
344
345
```python
346
import segyio
347
import numpy as np
348
349
# Create synthetic seismic data
350
ni, nx, nt = 50, 40, 500 # 50 inlines, 40 crosslines, 500 samples
351
synthetic_data = np.random.randn(ni, nx, nt).astype(np.float32)
352
353
# Add some realistic seismic features
354
for i in range(ni):
355
for j in range(nx):
356
# Add a reflector at 200ms
357
synthetic_data[i, j, 50:60] += 0.5 * np.sin(np.linspace(0, 4*np.pi, 10))
358
359
# Convert to SEG-Y
360
segyio.from_array3D(
361
'synthetic_3d.sgy',
362
synthetic_data,
363
format=segyio.SegySampleFormat.IEEE_FLOAT_4_BYTE,
364
dt=4000, # 4ms sampling
365
delrt=0 # Start at 0ms
366
)
367
368
# 2D seismic line (shot records)
369
shot_data = np.random.randn(120, 1000).astype(np.float32) # 120 traces, 1000 samples
370
segyio.from_array2D('shot_record.sgy', shot_data, dt=2000) # 2ms sampling
371
372
# 4D pre-stack data
373
prestack_data = np.random.randn(30, 25, 5, 750).astype(np.float32) # 5 offsets
374
segyio.from_array4D('prestack_4d.sgy', prestack_data, dt=4000)
375
```
376
377
### File Resampling
378
379
Destructive resampling operations for changing sample rates and timing.
380
381
```python { .api }
382
def resample(f, rate=None, delay=None, micro=False, trace=True, binary=True):
383
"""
384
Resample file traces (destructive operation).
385
386
Parameters:
387
- f (SegyFile): File handle (must be writable)
388
- rate (float): New sample rate
389
- delay (float): New delay time
390
- micro (bool): Whether rate/delay are in microseconds
391
- trace (bool): Update trace headers
392
- binary (bool): Update binary header
393
394
Returns:
395
SegyFile: Modified file handle
396
397
Raises:
398
ValueError: Invalid resampling parameters
399
RuntimeError: File not writable
400
"""
401
```
402
403
**Usage Example:**
404
405
```python
406
import segyio
407
408
# Resample file from 4ms to 2ms
409
with segyio.open('input_4ms.sgy', 'r+') as f:
410
print(f"Original sample rate: {segyio.dt(f)/1000} ms")
411
412
# Resample to 2ms (note: this is destructive!)
413
segyio.resample(f, rate=2.0, micro=False) # 2ms
414
415
print(f"New sample rate: {segyio.dt(f)/1000} ms")
416
417
# Update delay time to 100ms
418
segyio.resample(f, delay=100.0, micro=False)
419
```
420
421
## Processing Workflows
422
423
### Quality Control Pipeline
424
425
```python
426
def qc_workflow(input_file, output_report):
427
"""Complete QC workflow for SEG-Y files."""
428
report = {}
429
430
with segyio.open(input_file) as f:
431
# Basic file information
432
report['filename'] = input_file
433
report['traces'] = f.tracecount
434
report['samples'] = len(f.samples)
435
report['sample_rate'] = segyio.dt(f) / 1000 # ms
436
437
# Geometry analysis
438
if not f.unstructured:
439
report['inlines'] = len(f.ilines)
440
report['crosslines'] = len(f.xlines)
441
report['offsets'] = len(f.offsets)
442
443
# Survey rotation
444
rotation_angle, _, _ = segyio.rotation(f)
445
report['rotation'] = rotation_angle
446
447
# Amplitude analysis
448
sample_traces = [f.trace[i] for i in range(0, f.tracecount, max(1, f.tracecount//100))]
449
all_samples = np.concatenate(sample_traces)
450
451
report['amplitude_stats'] = {
452
'min': float(all_samples.min()),
453
'max': float(all_samples.max()),
454
'mean': float(all_samples.mean()),
455
'std': float(all_samples.std())
456
}
457
458
# Save report
459
import json
460
with open(output_report, 'w') as f:
461
json.dump(report, f, indent=2)
462
463
return report
464
```
465
466
### Data Conversion Pipeline
467
468
```python
469
def convert_to_ieee(input_file, output_file):
470
"""Convert IBM float SEG-Y to IEEE float format."""
471
with segyio.open(input_file) as src:
472
# Check current format
473
current_format = src.bin[segyio.BinField.Format]
474
475
if current_format != segyio.SegySampleFormat.IBM_FLOAT_4_BYTE:
476
print("File is not IBM float format")
477
return
478
479
# Create new file spec
480
spec = segyio.metadata(src)
481
spec.format = segyio.SegySampleFormat.IEEE_FLOAT_4_BYTE
482
483
with segyio.create(output_file, spec) as dst:
484
# Copy and convert data
485
for i in range(src.tracecount):
486
ibm_trace = src.trace[i]
487
ieee_trace = segyio.native(ibm_trace, current_format)
488
dst.trace[i] = ieee_trace
489
490
# Copy headers
491
dst.header[i] = src.header[i]
492
493
# Copy text headers
494
for i in range(src.ext_headers + 1):
495
dst.text[i] = src.text[i]
496
497
# Update binary header
498
for field in [segyio.BinField.Samples, segyio.BinField.Interval,
499
segyio.BinField.Traces, segyio.BinField.Format]:
500
dst.bin[field] = src.bin[field]
501
502
# Set new format
503
dst.bin[segyio.BinField.Format] = segyio.SegySampleFormat.IEEE_FLOAT_4_BYTE
504
```