Skip to content

Quickstart

From SEG-Y files to shot gathers

Scan the trace headers once, organise the traces as gathers, and read them back by number:

from sweep_io.segy_index import build_segy_index
from sweep_io.seismic_plan import PlanReader, SeismicPlan

index = build_segy_index(["line_001.sgy", "line_002.sgy"])    # headers only, in parallel
plan = index.to_seismic_plan(grouping="csg", offset_min_m=200.0)
plan.save("plan.npz")                                         # later runs: SeismicPlan.load

reader = PlanReader(plan)
gather = reader.read_group(0)                                 # (n_traces, n_samples) float32
print(plan.n_groups, gather.shape, reader.dt_s)

grouping="csg" gives one group per shot; grouping="crg" gives one group per receiver position, binning receivers onto a receiver_quantize_m grid, which is what node (OBN) data wants. The plan stores, for every trace, which file it is in and at which byte offset, so read_group seeks straight to the traces and merges adjacent reads.

examples/segy_to_plan.py runs this on a synthetic file it writes first, so you can try it without data.

Read ahead while the GPU works

Wrap any iterator in a Prefetcher and the next item is read in a background thread while the loop body runs:

from sweep_io.prefetch import Prefetcher

gathers = (reader.read_group(g) for g in range(plan.n_groups))
with Prefetcher(gathers, queue_depth=2) as pf:
    for obs in pf:
        pred = solver(wavelet, sources, receivers, models=[vp])    # your FWI step
        loss = misfit(pred, obs)
        loss.backward()

ThreadPoolPrefetcher reads several items in parallel, for wide-striped or many-file storage; CUDAPrefetcher also copies each item to the GPU on a side stream.

Pick the data and the model window

DataPlan selects shots, receivers, offsets and a time window; ModelPlan crops the model and rebases the geometry onto it. Both work on a PhysicalGeometry (positions in metres) and the observed data:

from sweep_io.plan import DataPlan, ModelPlan, apply_data_plan, apply_model_plan

data_plan = DataPlan(shot_stride=5, offset_max_m=2000.0, dt_target_s=0.008)
geom_m, obs, receiver_mask = apply_data_plan(data_plan, geom_m, obs)

vp, geom_m, shot_mask = apply_model_plan(ModelPlan(x_window_m=(5000.0, 22000.0)),
                                         vp, dh=(12.5, 12.5), geom=geom_m)

PhysicalGeometry.to_grid(dh) then snaps the positions onto the grid of an FWI stage, dropping receivers that land on the same cell.

Velocity models and geometry files

import numpy as np
from sweep_io.geometry import Geometry
from sweep_io.models import load_velocity, save_velocity

save_velocity("vp.npy", vp)                 # .npy, .npz, .h5 or raw binary, by extension
vp = load_velocity("vp.npy")

geom = Geometry(sources=sources, receivers=receivers, dt=0.001, nt=4000, dh=(10.0, 10.0))
geom.save("acq.json")                       # grid indices, dt, nt, dh and metadata
geom = Geometry.load("acq.json")