Creating a New SEG-Y

Altay Sansal

May 07, 2024

2 min read

In this tutorial, we create a new SEG-Y file from spec.

Let’s start by importing some modules we will be using.

from segy.factory import SegyFactory
from segy.standards.rev1 import rev1_segy

We will take the default SEG-Y Revision 1 specification.

The SegyFactory takes the spec, number of samples, and sample interval as inputs. By using its creation functions, we can make the encoded (ready to write to disk) bytes for file headers (text header and binary header).

SAMPLE_INTERVAL = 4000  # in microseconds
SAMPLES_PER_TRACE = 101

factory = SegyFactory(
    rev1_segy, sample_interval=SAMPLE_INTERVAL, samples_per_trace=SAMPLES_PER_TRACE
)

txt = factory.create_textual_header()
bin_ = factory.create_binary_header()

Let’s create 15 traces and populate their values. Headers by default will be populated by sample rate and number of samples. We will set some fake headers. We will also fill in the trace samples with trace_no + sample_index.

TRACE_COUNT = 15

headers = factory.create_trace_header_template(size=TRACE_COUNT)
samples = factory.create_trace_sample_template(size=TRACE_COUNT)

for trace_idx in range(TRACE_COUNT):
    headers[trace_idx]["trace_seq_file"] = trace_idx + 1
    headers[trace_idx]["x_coordinate"] = 1_000
    headers[trace_idx]["y_coordinate"] = 10_000 + trace_idx * 50
    headers[trace_idx]["inline_no"] = 10
    headers[trace_idx]["crossline_no"] = 100 + trace_idx

    samples[trace_idx] = range(SAMPLES_PER_TRACE)  # sample index
    samples[trace_idx] += trace_idx  # trace no

Now we can create the encoded binary values for traces (ready to write).

traces = factory.create_traces(samples=samples, headers=headers)

We can now compose a binary SEG-Y file from pieces.

We create a new my_segy.sgy file and write the pieces we built.

from pathlib import Path

with Path("my_segy.sgy").open(mode="wb") as fp:
    fp.write(txt)
    fp.write(bin_)
    fp.write(traces)

Opening New SEG-Y

Now we can open it with SegyFile.

Note that our factory correctly populated the revision number in the header so the spec is automatically inferred!

from segy.file import SegyFile

file = SegyFile("my_segy.sgy")
print(file.text_header)
C01 File written by the open-source segy library.                               
C02                                                                             
C03 Website: https://segy.readthedocs.io                                        
C04 Source: https://github.com/TGSAI/segy                                       
C05                                                                             
C06                                                                             
C07                                                                             
C08                                                                             
C09                                                                             
C10                                                                             
C11                                                                             
C12                                                                             
C13                                                                             
C14                                                                             
C15                                                                             
C16                                                                             
C17                                                                             
C18                                                                             
C19                                                                             
C20                                                                             
C21                                                                             
C22                                                                             
C23                                                                             
C24                                                                             
C25                                                                             
C26                                                                             
C27                                                                             
C28                                                                             
C29                                                                             
C30                                                                             
C31                                                                             
C32                                                                             
C33                                                                             
C34                                                                             
C35                                                                             
C36                                                                             
C37                                                                             
C38                                                                             
C39                                                                             
C40 END TEXTUAL HEADER                                                          
file.binary_header.to_dataframe()
job_id line_no reel_no data_traces_ensemble aux_traces_ensemble sample_interval sample_interval_orig samples_per_trace samples_per_trace_orig data_sample_format ... correlated_traces binary_gain amp_recovery_method measurement_system impulse_signal_polarity vibratory_polarity seg_y_revision fixed_length_trace_flag extended_textual_headers additional_trace_headers
0 0 0 0 0 0 4000 4000 101 101 0 ... 0 0 0 0 0 0 256 0 0 0

1 rows × 31 columns

file.sample[:]
array([[  0.,   1.,   2., ...,  98.,  99., 100.],
       [  1.,   2.,   3., ...,  99., 100., 101.],
       [  2.,   3.,   4., ..., 100., 101., 102.],
       ...,
       [ 12.,  13.,  14., ..., 110., 111., 112.],
       [ 13.,  14.,  15., ..., 111., 112., 113.],
       [ 14.,  15.,  16., ..., 112., 113., 114.]], dtype=float32)
show_fields = [
    "trace_seq_file",
    "x_coordinate",
    "y_coordinate",
    "inline_no",
    "crossline_no",
]

file.header[:][show_fields].to_dataframe()
trace_seq_file x_coordinate y_coordinate inline_no crossline_no
0 1 1000 10000 10 100
1 2 1000 10050 10 101
2 3 1000 10100 10 102
3 4 1000 10150 10 103
4 5 1000 10200 10 104
5 6 1000 10250 10 105
6 7 1000 10300 10 106
7 8 1000 10350 10 107
8 9 1000 10400 10 108
9 10 1000 10450 10 109
10 11 1000 10500 10 110
11 12 1000 10550 10 111
12 13 1000 10600 10 112
13 14 1000 10650 10 113
14 15 1000 10700 10 114