or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-access.mdfile-operations.mdheader-access.mdindex.mdseismic-unix.mdutilities.md

data-access.mddocs/

0

# Data Access

1

2

Multiple specialized interfaces for accessing seismic data organized by traces, inlines, crosslines, depth slices, and gathers. Each access mode provides a different view of the same underlying data optimized for specific workflows.

3

4

## Capabilities

5

6

### Individual Trace Access

7

8

Direct access to individual seismic traces by trace index. Most fundamental access pattern.

9

10

```python { .api }

11

# Trace access mode (available as f.trace)

12

f.trace[index] # Read trace by index (returns numpy.ndarray)

13

f.trace[start:end] # Read multiple traces (returns numpy.ndarray)

14

f.trace[start:end:step] # Read traces with step (returns numpy.ndarray)

15

f.trace[index] = data # Write trace data (if file writable)

16

```

17

18

**Usage Example:**

19

20

```python

21

with segyio.open('data.sgy') as f:

22

# Read single trace

23

first_trace = f.trace[0]

24

print(f"Trace shape: {first_trace.shape}")

25

print(f"Trace dtype: {first_trace.dtype}")

26

27

# Read multiple traces

28

traces_10_to_19 = f.trace[10:20]

29

print(f"Multiple traces shape: {traces_10_to_19.shape}")

30

31

# Read every 10th trace

32

sampled_traces = f.trace[::10]

33

34

# Iterate over all traces

35

for i, trace in enumerate(f.trace):

36

# Process each trace

37

amplitude = trace.max()

38

print(f"Trace {i} max amplitude: {amplitude}")

39

40

if i >= 100: # Limit for example

41

break

42

43

# Writing traces

44

with segyio.open('data.sgy', 'r+') as f:

45

# Modify a trace

46

modified_trace = f.trace[0] * 2.0 # Double amplitudes

47

f.trace[0] = modified_trace

48

49

# Write synthetic data

50

synthetic = np.sin(np.linspace(0, 10*np.pi, len(f.samples)))

51

f.trace[0] = synthetic

52

```

53

54

### Inline Access

55

56

Access seismic data organized by inline number (3D structured files only). Each inline represents a 2D vertical slice parallel to the acquisition direction.

57

58

```python { .api }

59

# Inline access mode (available as f.iline)

60

f.iline[inline_number] # Read inline slice (returns 2D numpy.ndarray)

61

f.iline[inline_number, crosslines] # Read subset of crosslines

62

f.iline[inline_number] = data # Write inline data (if file writable)

63

```

64

65

**Usage Example:**

66

67

```python

68

with segyio.open('3d_volume.sgy') as f:

69

print(f"Available inlines: {f.ilines}")

70

71

# Read complete inline

72

inline_100 = f.iline[100]

73

print(f"Inline shape: {inline_100.shape}") # (n_crosslines, n_samples)

74

75

# Read subset of crosslines for an inline

76

partial_inline = f.iline[100, 200:250] # Crosslines 200-249

77

78

# Iterate over all inlines

79

for il in f.ilines:

80

inline_data = f.iline[il]

81

avg_amplitude = inline_data.mean()

82

print(f"Inline {il} average amplitude: {avg_amplitude}")

83

84

# Process inline with numpy operations

85

inline_data = f.iline[150]

86

87

# Apply gain correction

88

gained = inline_data * 1.5

89

90

# Apply AGC (Automatic Gain Control)

91

window_size = 50

92

agc_data = np.zeros_like(inline_data)

93

for i, trace in enumerate(inline_data.T):

94

for j in range(len(trace)):

95

start = max(0, j - window_size//2)

96

end = min(len(trace), j + window_size//2)

97

window_rms = np.sqrt(np.mean(trace[start:end]**2))

98

if window_rms > 0:

99

agc_data[i, j] = trace[j] / window_rms

100

```

101

102

### Crossline Access

103

104

Access seismic data organized by crossline number (3D structured files only). Each crossline represents a 2D vertical slice perpendicular to the acquisition direction.

105

106

```python { .api }

107

# Crossline access mode (available as f.xline)

108

f.xline[crossline_number] # Read crossline slice (returns 2D numpy.ndarray)

109

f.xline[crossline_number, inlines] # Read subset of inlines

110

f.xline[crossline_number] = data # Write crossline data (if file writable)

111

```

112

113

**Usage Example:**

114

115

```python

116

with segyio.open('3d_volume.sgy') as f:

117

print(f"Available crosslines: {f.xlines}")

118

119

# Read complete crossline

120

crossline_300 = f.xline[300]

121

print(f"Crossline shape: {crossline_300.shape}") # (n_inlines, n_samples)

122

123

# Compare inline vs crossline

124

il_data = f.iline[100]

125

xl_data = f.xline[300]

126

127

print(f"Inline 100 dimensions: {il_data.shape}")

128

print(f"Crossline 300 dimensions: {xl_data.shape}")

129

130

# Find intersection point

131

intersection = f.trace[f.index(inline=100, crossline=300)]

132

133

# Extract same trace from both slices

134

# Find position of crossline 300 in inline 100

135

xl_pos = list(f.xlines).index(300)

136

trace_from_inline = il_data[xl_pos, :]

137

138

# Find position of inline 100 in crossline 300

139

il_pos = list(f.ilines).index(100)

140

trace_from_crossline = xl_data[il_pos, :]

141

142

# These should be identical

143

assert np.allclose(trace_from_inline, trace_from_crossline)

144

```

145

146

### Fast and Slow Dimension Access

147

148

Access data along the fast and slow dimensions based on file sorting. Provides consistent access regardless of whether file is inline-sorted or crossline-sorted.

149

150

```python { .api }

151

# Fast/slow dimension access (available as f.fast and f.slow)

152

f.fast[index] # Read along fast dimension

153

f.slow[index] # Read along slow dimension

154

```

155

156

**Usage Example:**

157

158

```python

159

with segyio.open('data.sgy') as f:

160

print(f"File sorting: {f.sorting}")

161

162

if f.sorting == segyio.TraceSortingFormat.INLINE_SORTING:

163

print("Fast=inline, Slow=crossline")

164

assert f.fast == f.iline

165

assert f.slow == f.xline

166

elif f.sorting == segyio.TraceSortingFormat.CROSSLINE_SORTING:

167

print("Fast=crossline, Slow=inline")

168

assert f.fast == f.xline

169

assert f.slow == f.iline

170

171

# Access first line along fast dimension

172

fast_line = f.fast[f.fast.indices[0]]

173

174

# Access first line along slow dimension

175

slow_line = f.slow[f.slow.indices[0]]

176

```

177

178

### Depth Slice Access

179

180

Access horizontal slices at specific sample indices (time/depth slices). Useful for horizon mapping and amplitude analysis.

181

182

```python { .api }

183

# Depth slice access mode (available as f.depth_slice)

184

f.depth_slice[sample_index] # Read horizontal slice at sample index

185

f.depth_slice[sample_index] = data # Write depth slice (if file writable)

186

```

187

188

**Usage Example:**

189

190

```python

191

with segyio.open('3d_volume.sgy') as f:

192

print(f"Sample range: {f.samples}")

193

194

# Read depth slice at 500ms (sample index 125 for 4ms sampling)

195

sample_index = 125

196

depth_slice = f.depth_slice[sample_index]

197

print(f"Depth slice shape: {depth_slice.shape}") # (n_inlines, n_crosslines)

198

199

# Create amplitude map for interpretation

200

import matplotlib.pyplot as plt

201

202

plt.figure(figsize=(10, 8))

203

plt.imshow(depth_slice, cmap='seismic', aspect='auto')

204

plt.title(f'Amplitude at {f.samples[sample_index]}ms')

205

plt.xlabel('Crossline')

206

plt.ylabel('Inline')

207

plt.colorbar(label='Amplitude')

208

209

# Find maximum amplitude location

210

max_pos = np.unravel_index(np.argmax(np.abs(depth_slice)), depth_slice.shape)

211

max_inline = f.ilines[max_pos[0]]

212

max_crossline = f.xlines[max_pos[1]]

213

print(f"Maximum amplitude at IL={max_inline}, XL={max_crossline}")

214

215

# Extract amplitude attributes along a horizon

216

horizon_samples = np.full(depth_slice.shape, sample_index) # Flat horizon

217

218

# For variable horizon, load from interpretation

219

# horizon_samples = load_horizon_picks('horizon.dat')

220

221

# Extract attributes along horizon

222

horizon_amplitudes = np.zeros(depth_slice.shape)

223

for i, il in enumerate(f.ilines):

224

for j, xl in enumerate(f.xlines):

225

sample_idx = int(horizon_samples[i, j])

226

if 0 <= sample_idx < len(f.samples):

227

horizon_amplitudes[i, j] = f.depth_slice[sample_idx][i, j]

228

```

229

230

### Gather Access

231

232

Access pre-stack gathers organized by Common Depth Point (CDP) or other grouping criteria. Essential for velocity analysis and pre-stack processing.

233

234

```python { .api }

235

# Gather access mode (available as f.gather)

236

f.gather[cdp_number] # Read gather by CDP number

237

f.gather[cdp_number, offsets] # Read subset of offsets

238

```

239

240

**Usage Example:**

241

242

```python

243

# Pre-stack data with multiple offsets

244

with segyio.open('prestack.sgy') as f:

245

print(f"Available offsets: {f.offsets}")

246

247

# Get first CDP number

248

first_cdp = f.header[0][segyio.TraceField.CDP]

249

250

# Read complete gather

251

gather = f.gather[first_cdp]

252

print(f"Gather shape: {gather.shape}") # (n_offsets, n_samples)

253

254

# Read subset of offsets

255

near_offsets = f.gather[first_cdp, f.offsets[:3]] # First 3 offsets

256

257

# Velocity analysis - compute semblance

258

def compute_semblance(gather, times, velocities):

259

"""Compute semblance for velocity analysis."""

260

semblance = np.zeros((len(times), len(velocities)))

261

262

for i, t in enumerate(times):

263

for j, v in enumerate(velocities):

264

# NMO correction

265

corrected = np.zeros_like(gather)

266

for k, offset in enumerate(f.offsets):

267

t_nmo = np.sqrt(t**2 + (offset/v)**2)

268

# Interpolate to corrected time

269

# (simplified - would use proper interpolation)

270

sample_idx = int(t_nmo * 1000 / 4) # 4ms sampling

271

if sample_idx < gather.shape[1]:

272

corrected[k, i] = gather[k, sample_idx]

273

274

# Compute semblance

275

stack = corrected.sum(axis=0)

276

energy_stack = (stack**2).sum()

277

energy_individual = (corrected**2).sum()

278

279

if energy_individual > 0:

280

semblance[i, j] = energy_stack / energy_individual

281

282

return semblance

283

284

# Example velocity analysis

285

times = np.arange(0, 2.0, 0.004) # 0-2 seconds

286

velocities = np.arange(1500, 4000, 50) # 1500-4000 m/s

287

288

semblance = compute_semblance(gather, times, velocities)

289

290

# Find maximum velocity at each time

291

optimal_velocities = velocities[np.argmax(semblance, axis=1)]

292

```

293

294

### Multi-dimensional Indexing

295

296

Combined indexing across multiple dimensions for precise data access.

297

298

```python

299

with segyio.open('3d_volume.sgy') as f:

300

# Get trace index from inline/crossline coordinates

301

trace_idx = f.index(inline=100, crossline=200)

302

trace = f.trace[trace_idx]

303

304

# Alternative: direct access via coordinates

305

trace = f.trace[f.index(100, 200)]

306

307

# Bulk operations on subsets

308

inline_subset = f.iline[100:110] # Multiple inlines

309

crossline_subset = f.xline[200:210] # Multiple crosslines

310

311

# Advanced slicing

312

subvolume = f.iline[100:110, 200:210] # Sub-cube extraction

313

```

314

315

## Data Processing Examples

316

317

### Amplitude Statistics

318

319

```python

320

def compute_amplitude_stats(filename):

321

"""Compute amplitude statistics for SEG-Y file."""

322

with segyio.open(filename) as f:

323

all_amplitudes = []

324

325

# Sample every 100th trace for efficiency

326

for i in range(0, f.tracecount, 100):

327

trace = f.trace[i]

328

all_amplitudes.extend(trace)

329

330

amplitudes = np.array(all_amplitudes)

331

332

return {

333

'min': amplitudes.min(),

334

'max': amplitudes.max(),

335

'mean': amplitudes.mean(),

336

'std': amplitudes.std(),

337

'rms': np.sqrt(np.mean(amplitudes**2))

338

}

339

```

340

341

### Data QC and Validation

342

343

```python

344

def qc_seismic_data(filename):

345

"""Perform basic QC on seismic data."""

346

issues = []

347

348

with segyio.open(filename) as f:

349

# Check for dead traces

350

dead_traces = []

351

for i in range(min(1000, f.tracecount)):

352

trace = f.trace[i]

353

if np.all(trace == 0) or np.all(np.isnan(trace)):

354

dead_traces.append(i)

355

356

if dead_traces:

357

issues.append(f"Dead traces found: {len(dead_traces)}")

358

359

# Check for clipped data

360

clipped_traces = []

361

for i in range(min(1000, f.tracecount)):

362

trace = f.trace[i]

363

if np.any(np.abs(trace) >= 32767): # Common clipping level

364

clipped_traces.append(i)

365

366

if clipped_traces:

367

issues.append(f"Clipped traces found: {len(clipped_traces)}")

368

369

# Check geometry consistency

370

if not f.unstructured:

371

expected_traces = len(f.ilines) * len(f.xlines) * len(f.offsets)

372

if f.tracecount != expected_traces:

373

issues.append(f"Trace count mismatch: {f.tracecount} vs {expected_traces}")

374

375

return issues

376

```