segyio 2.0.0a1__cp312-cp312-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- segyio/__init__.py +101 -0
- segyio/_segyio.cp310-win_amd64.pyd +0 -0
- segyio/_segyio.cp311-win_amd64.pyd +0 -0
- segyio/_segyio.cp312-win_amd64.pyd +0 -0
- segyio/binfield.py +153 -0
- segyio/create.py +314 -0
- segyio/depth.py +180 -0
- segyio/field.py +657 -0
- segyio/gather.py +444 -0
- segyio/line.py +498 -0
- segyio/open.py +306 -0
- segyio/segy.py +1182 -0
- segyio/segyio.cpp +3281 -0
- segyio/segysampleformat.py +19 -0
- segyio/su/__init__.py +2 -0
- segyio/su/file.py +120 -0
- segyio/su/words.py +286 -0
- segyio/tools.py +731 -0
- segyio/trace.py +1624 -0
- segyio/tracefield.py +204 -0
- segyio/tracesortingformat.py +6 -0
- segyio/utils.py +199 -0
- segyio-2.0.0a1.dist-info/METADATA +67 -0
- segyio-2.0.0a1.dist-info/RECORD +25 -0
- segyio-2.0.0a1.dist-info/WHEEL +5 -0
segyio/trace.py
ADDED
|
@@ -0,0 +1,1624 @@
|
|
|
1
|
+
try:
|
|
2
|
+
from collections.abc import Sequence # noqa
|
|
3
|
+
except ImportError:
|
|
4
|
+
from collections import Sequence # noqa
|
|
5
|
+
|
|
6
|
+
import contextlib
|
|
7
|
+
import itertools
|
|
8
|
+
import warnings
|
|
9
|
+
import sys
|
|
10
|
+
try: from future_builtins import zip
|
|
11
|
+
except ImportError: pass
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
from .line import HeaderLine
|
|
16
|
+
from .field import Field, HeaderFieldAccessor
|
|
17
|
+
from .utils import castarray
|
|
18
|
+
|
|
19
|
+
class Sequence(Sequence):
|
|
20
|
+
|
|
21
|
+
# unify the common optimisations and boilerplate of Trace, RawTrace, and
|
|
22
|
+
# Header, which all obey the same index-oriented interface, and all share
|
|
23
|
+
# length and wrap-around properties.
|
|
24
|
+
#
|
|
25
|
+
# It provides a useful negative-wrap index method which deals
|
|
26
|
+
# appropriately with IndexError and python2-3 differences.
|
|
27
|
+
|
|
28
|
+
def __init__(self, length):
|
|
29
|
+
self.length = length
|
|
30
|
+
|
|
31
|
+
def __len__(self):
|
|
32
|
+
"""x.__len__() <==> len(x)"""
|
|
33
|
+
return self.length
|
|
34
|
+
|
|
35
|
+
def __iter__(self):
|
|
36
|
+
"""x.__iter__() <==> iter(x)"""
|
|
37
|
+
# __iter__ has a reasonable default implementation from Sequence. It's
|
|
38
|
+
# essentially this loop:
|
|
39
|
+
# for i in range(len(self)): yield self[i]
|
|
40
|
+
# However, in segyio that means the double-buffering, buffer reuse does
|
|
41
|
+
# not happen, which is *much* slower (the allocation of otherwised
|
|
42
|
+
# reused numpy objects takes about half the execution time), so
|
|
43
|
+
# explicitly implement it as [:]
|
|
44
|
+
return self[:]
|
|
45
|
+
|
|
46
|
+
def wrapindex(self, i):
|
|
47
|
+
if i < 0:
|
|
48
|
+
i += len(self)
|
|
49
|
+
|
|
50
|
+
if not 0 <= i < len(self):
|
|
51
|
+
# in python2, int-slice comparison does not raise a type error,
|
|
52
|
+
# (but returns False), so force a type-error if this still isn't an
|
|
53
|
+
# int-like.
|
|
54
|
+
_ = i + 0
|
|
55
|
+
raise IndexError('trace index out of range')
|
|
56
|
+
|
|
57
|
+
return i
|
|
58
|
+
|
|
59
|
+
class Trace(Sequence):
|
|
60
|
+
"""
|
|
61
|
+
The Trace implements the array interface, where every array element, the
|
|
62
|
+
data trace, is a numpy.ndarray. As all arrays, it can be random accessed,
|
|
63
|
+
iterated over, and read strided. Data is read lazily from disk, so
|
|
64
|
+
iteration does not consume much memory. If you want eager reading, use
|
|
65
|
+
Trace.raw.
|
|
66
|
+
|
|
67
|
+
This mode gives access to reading and writing functionality for traces.
|
|
68
|
+
The primary data type is ``numpy.ndarray``. Traces can be accessed
|
|
69
|
+
individually or with python slices, and writing is done via assignment.
|
|
70
|
+
|
|
71
|
+
Notes
|
|
72
|
+
-----
|
|
73
|
+
.. versionadded:: 1.1
|
|
74
|
+
|
|
75
|
+
.. versionchanged:: 1.6
|
|
76
|
+
common list operations (Sequence)
|
|
77
|
+
|
|
78
|
+
Examples
|
|
79
|
+
--------
|
|
80
|
+
Read all traces in file f and store in a list:
|
|
81
|
+
|
|
82
|
+
>>> l = [numpy.copy(tr) for tr in trace[:]]
|
|
83
|
+
|
|
84
|
+
Do numpy operations on a trace:
|
|
85
|
+
|
|
86
|
+
>>> tr = trace[10]
|
|
87
|
+
>>> tr = tr * 2
|
|
88
|
+
>>> tr = tr - 100
|
|
89
|
+
>>> avg = numpy.average(tr)
|
|
90
|
+
|
|
91
|
+
Perform some seismic processing on a trace. E.g resample from 2ms spacing
|
|
92
|
+
to 4ms spacing (note there is no anti-alias filtering in this example):
|
|
93
|
+
|
|
94
|
+
>>> tr = scipy.signal.resample(tr, len(tr)/2)
|
|
95
|
+
|
|
96
|
+
Double every trace value and write to disk. Since accessing a trace
|
|
97
|
+
gives a numpy value, to write to the respective trace we need its index:
|
|
98
|
+
|
|
99
|
+
>>> for i, tr in enumerate(trace):
|
|
100
|
+
... tr = tr * 2
|
|
101
|
+
... trace[i] = tr
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
def __init__(self, segyfd, dtype, tracecount, samples, readonly):
|
|
106
|
+
super(Trace, self).__init__(tracecount)
|
|
107
|
+
self.segyfd = segyfd
|
|
108
|
+
self.dtype = dtype
|
|
109
|
+
self.shape = samples
|
|
110
|
+
self.readonly = readonly
|
|
111
|
+
|
|
112
|
+
def __getitem__(self, i):
|
|
113
|
+
"""trace[i] or trace[i, j]
|
|
114
|
+
|
|
115
|
+
ith trace of the file, starting at 0. trace[i] returns a numpy array,
|
|
116
|
+
and changes to this array will *not* be reflected on disk.
|
|
117
|
+
|
|
118
|
+
When i is a tuple, the second index j (int or slice) is the depth index
|
|
119
|
+
or interval, respectively. j starts at 0.
|
|
120
|
+
|
|
121
|
+
When i is a slice, a generator of numpy arrays is returned.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
i : int or slice
|
|
126
|
+
j : int or slice
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
trace : numpy.ndarray of dtype or generator of numpy.ndarray of dtype
|
|
131
|
+
|
|
132
|
+
Notes
|
|
133
|
+
-----
|
|
134
|
+
.. versionadded:: 1.1
|
|
135
|
+
|
|
136
|
+
Behaves like [] for lists.
|
|
137
|
+
|
|
138
|
+
.. note::
|
|
139
|
+
|
|
140
|
+
This operator reads lazily from the file, meaning the file is read
|
|
141
|
+
on ``next()``, and only one trace is fixed in memory. This means
|
|
142
|
+
segyio can run through arbitrarily large files without consuming
|
|
143
|
+
much memory, but it is potentially slow if the goal is to read the
|
|
144
|
+
entire file into memory. If that is the case, consider using
|
|
145
|
+
`trace.raw`, which reads eagerly.
|
|
146
|
+
|
|
147
|
+
Examples
|
|
148
|
+
--------
|
|
149
|
+
Read every other trace:
|
|
150
|
+
|
|
151
|
+
>>> for tr in trace[::2]:
|
|
152
|
+
... print(tr)
|
|
153
|
+
|
|
154
|
+
Read all traces, last-to-first:
|
|
155
|
+
|
|
156
|
+
>>> for tr in trace[::-1]:
|
|
157
|
+
... tr.mean()
|
|
158
|
+
|
|
159
|
+
Read a single value. The second [] is regular numpy array indexing, and
|
|
160
|
+
supports all numpy operations, including negative indexing and slicing:
|
|
161
|
+
|
|
162
|
+
>>> trace[0][0]
|
|
163
|
+
1490.2
|
|
164
|
+
>>> trace[0][1]
|
|
165
|
+
1490.8
|
|
166
|
+
>>> trace[0][-1]
|
|
167
|
+
1871.3
|
|
168
|
+
>>> trace[-1][100]
|
|
169
|
+
1562.0
|
|
170
|
+
|
|
171
|
+
Read only an interval in a trace:
|
|
172
|
+
>>> trace[0, 5:10]
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
# optimize for the default case when i is a single trace index
|
|
177
|
+
i = self.wrapindex(i)
|
|
178
|
+
buf = np.zeros(self.shape, dtype = self.dtype)
|
|
179
|
+
return self.segyfd.gettr(buf, i, 1, 1, 0, self.shape, 1, self.shape)
|
|
180
|
+
except TypeError:
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
i, j = i
|
|
185
|
+
except TypeError:
|
|
186
|
+
# index is not a tuple. Set j to be a slice that causes the entire
|
|
187
|
+
# trace to be loaded.
|
|
188
|
+
j = slice(0, self.shape, 1)
|
|
189
|
+
|
|
190
|
+
single = False
|
|
191
|
+
try:
|
|
192
|
+
start, stop, step = j.indices(self.shape)
|
|
193
|
+
except AttributeError:
|
|
194
|
+
# j is not a slice, set start stop and step so that a single sample
|
|
195
|
+
# at position j is loaded.
|
|
196
|
+
start = int(j) % self.shape
|
|
197
|
+
stop = start + 1
|
|
198
|
+
step = 1
|
|
199
|
+
single = True
|
|
200
|
+
|
|
201
|
+
n_elements = len(range(start, stop, step))
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
i = self.wrapindex(i)
|
|
205
|
+
buf = np.zeros(n_elements, dtype = self.dtype)
|
|
206
|
+
tr = self.segyfd.gettr(buf, i, 1, 1, start, stop, step, n_elements)
|
|
207
|
+
return tr[0] if single else tr
|
|
208
|
+
except TypeError:
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
indices = i.indices(len(self))
|
|
213
|
+
def gen():
|
|
214
|
+
# double-buffer the trace. when iterating over a range, we want
|
|
215
|
+
# to make sure the visible change happens as late as possible,
|
|
216
|
+
# and that in the case of exception the last valid trace was
|
|
217
|
+
# untouched. this allows for some fancy control flow, and more
|
|
218
|
+
# importantly helps debugging because you can fully inspect and
|
|
219
|
+
# interact with the last good value.
|
|
220
|
+
x = np.zeros(n_elements, dtype=self.dtype)
|
|
221
|
+
y = np.zeros(n_elements, dtype=self.dtype)
|
|
222
|
+
|
|
223
|
+
for k in range(*indices):
|
|
224
|
+
self.segyfd.gettr(x, k, 1, 1, start, stop, step, n_elements)
|
|
225
|
+
x, y = y, x
|
|
226
|
+
yield y
|
|
227
|
+
|
|
228
|
+
return gen()
|
|
229
|
+
except AttributeError:
|
|
230
|
+
# At this point we have tried to unpack index as a single int, a
|
|
231
|
+
# slice and a pair with either element being an int or slice.
|
|
232
|
+
msg = 'trace indices must be integers or slices, not {}'
|
|
233
|
+
raise TypeError(msg.format(type(i).__name__))
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def __setitem__(self, i, val):
|
|
237
|
+
"""trace[i] = val
|
|
238
|
+
|
|
239
|
+
Write the ith trace of the file, starting at 0. It accepts any
|
|
240
|
+
array_like, but val must be at least as big as the underlying data
|
|
241
|
+
trace.
|
|
242
|
+
|
|
243
|
+
If val is longer than the underlying trace, it is essentially
|
|
244
|
+
truncated.
|
|
245
|
+
|
|
246
|
+
For the best performance, val should be a numpy.ndarray of sufficient
|
|
247
|
+
size and same dtype as the file. segyio will warn on mismatched types,
|
|
248
|
+
and attempt a conversion for you.
|
|
249
|
+
|
|
250
|
+
Data is written immediately to disk. If writing multiple traces at
|
|
251
|
+
once, and a write fails partway through, the resulting file is left in
|
|
252
|
+
an unspecified state.
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
i : int or slice
|
|
257
|
+
val : array_like
|
|
258
|
+
|
|
259
|
+
Notes
|
|
260
|
+
-----
|
|
261
|
+
.. versionadded:: 1.1
|
|
262
|
+
|
|
263
|
+
Behaves like [] for lists.
|
|
264
|
+
|
|
265
|
+
Examples
|
|
266
|
+
--------
|
|
267
|
+
Write a single trace:
|
|
268
|
+
|
|
269
|
+
>>> trace[10] = list(range(1000))
|
|
270
|
+
|
|
271
|
+
Write multiple traces:
|
|
272
|
+
|
|
273
|
+
>>> trace[10:15] = np.array([cube[i] for i in range(5)])
|
|
274
|
+
|
|
275
|
+
Write multiple traces with stride:
|
|
276
|
+
|
|
277
|
+
>>> trace[10:20:2] = np.array([cube[i] for i in range(5)])
|
|
278
|
+
|
|
279
|
+
"""
|
|
280
|
+
if isinstance(i, slice):
|
|
281
|
+
for j, x in zip(range(*i.indices(len(self))), val):
|
|
282
|
+
self[j] = x
|
|
283
|
+
|
|
284
|
+
return
|
|
285
|
+
|
|
286
|
+
xs = castarray(val, self.dtype)
|
|
287
|
+
|
|
288
|
+
# TODO: check if len(xs) > shape, and optionally warn on truncating
|
|
289
|
+
# writes
|
|
290
|
+
self.segyfd.puttr(self.wrapindex(i), xs)
|
|
291
|
+
|
|
292
|
+
def __repr__(self):
|
|
293
|
+
return "Trace(traces = {}, samples = {})".format(len(self), self.shape)
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def raw(self):
|
|
297
|
+
"""
|
|
298
|
+
An eager version of Trace
|
|
299
|
+
|
|
300
|
+
Returns
|
|
301
|
+
-------
|
|
302
|
+
raw : RawTrace
|
|
303
|
+
"""
|
|
304
|
+
return RawTrace(self.segyfd,
|
|
305
|
+
self.dtype,
|
|
306
|
+
len(self),
|
|
307
|
+
self.shape,
|
|
308
|
+
self.readonly,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
@property
|
|
312
|
+
@contextlib.contextmanager
|
|
313
|
+
def ref(self):
|
|
314
|
+
"""
|
|
315
|
+
A write-back version of Trace
|
|
316
|
+
|
|
317
|
+
Returns
|
|
318
|
+
-------
|
|
319
|
+
ref : RefTrace
|
|
320
|
+
`ref` is returned in a context manager, and must be in a ``with``
|
|
321
|
+
statement
|
|
322
|
+
|
|
323
|
+
Notes
|
|
324
|
+
-----
|
|
325
|
+
.. versionadded:: 1.6
|
|
326
|
+
|
|
327
|
+
Examples
|
|
328
|
+
--------
|
|
329
|
+
>>> with trace.ref as ref:
|
|
330
|
+
... ref[10] += 1.617
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
x = RefTrace(self.segyfd,
|
|
334
|
+
self.dtype,
|
|
335
|
+
len(self),
|
|
336
|
+
self.shape,
|
|
337
|
+
self.readonly,
|
|
338
|
+
)
|
|
339
|
+
yield x
|
|
340
|
+
x.flush()
|
|
341
|
+
|
|
342
|
+
class RawTrace(Trace):
|
|
343
|
+
"""
|
|
344
|
+
Behaves exactly like trace, except reads are done eagerly and returned as
|
|
345
|
+
numpy.ndarray, instead of generators of numpy.ndarray.
|
|
346
|
+
"""
|
|
347
|
+
def __init__(self, *args):
|
|
348
|
+
super(RawTrace, self).__init__(*args)
|
|
349
|
+
|
|
350
|
+
def __getitem__(self, i):
|
|
351
|
+
"""trace[i]
|
|
352
|
+
|
|
353
|
+
Eagerly read the ith trace of the file, starting at 0. trace[i] returns
|
|
354
|
+
a numpy array, and changes to this array will *not* be reflected on
|
|
355
|
+
disk.
|
|
356
|
+
|
|
357
|
+
When i is a slice, this returns a 2-dimensional numpy.ndarray .
|
|
358
|
+
|
|
359
|
+
Parameters
|
|
360
|
+
----------
|
|
361
|
+
i : int or slice
|
|
362
|
+
|
|
363
|
+
Returns
|
|
364
|
+
-------
|
|
365
|
+
trace : numpy.ndarray of dtype
|
|
366
|
+
|
|
367
|
+
Notes
|
|
368
|
+
-----
|
|
369
|
+
.. versionadded:: 1.1
|
|
370
|
+
|
|
371
|
+
Behaves like [] for lists.
|
|
372
|
+
|
|
373
|
+
.. note::
|
|
374
|
+
|
|
375
|
+
Reading this way is more efficient if you know you can afford the
|
|
376
|
+
extra memory usage. It reads the requested traces immediately to
|
|
377
|
+
memory.
|
|
378
|
+
|
|
379
|
+
"""
|
|
380
|
+
try:
|
|
381
|
+
i = self.wrapindex(i)
|
|
382
|
+
buf = np.zeros(self.shape, dtype = self.dtype)
|
|
383
|
+
return self.segyfd.gettr(buf, i, 1, 1, 0, self.shape, 1, self.shape)
|
|
384
|
+
except TypeError:
|
|
385
|
+
try:
|
|
386
|
+
indices = i.indices(len(self))
|
|
387
|
+
except AttributeError:
|
|
388
|
+
msg = 'trace indices must be integers or slices, not {}'
|
|
389
|
+
raise TypeError(msg.format(type(i).__name__))
|
|
390
|
+
start, _, step = indices
|
|
391
|
+
length = len(range(*indices))
|
|
392
|
+
buf = np.empty((length, self.shape), dtype = self.dtype)
|
|
393
|
+
return self.segyfd.gettr(buf, start, step, length, 0, self.shape, 1, self.shape)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def fingerprint(x):
|
|
397
|
+
return hash(bytes(x.data))
|
|
398
|
+
|
|
399
|
+
class RefTrace(Trace):
|
|
400
|
+
"""
|
|
401
|
+
Behaves like trace, except changes to the returned numpy arrays *are*
|
|
402
|
+
reflected on disk. Operations have to be in-place on the numpy array, so
|
|
403
|
+
assignment on a trace will not work.
|
|
404
|
+
|
|
405
|
+
This feature exists to support code like::
|
|
406
|
+
|
|
407
|
+
>>> with ref as r:
|
|
408
|
+
... for x, y in zip(r, src):
|
|
409
|
+
... numpy.copyto(x, y + 10)
|
|
410
|
+
|
|
411
|
+
This class is not meant to be instantiated directly, but returned by
|
|
412
|
+
:attr:`Trace.ref`. This feature requires a context manager, to guarantee
|
|
413
|
+
modifications are written back to disk.
|
|
414
|
+
"""
|
|
415
|
+
def __init__(self, *args):
|
|
416
|
+
super(RefTrace, self).__init__(*args)
|
|
417
|
+
self.refs = {}
|
|
418
|
+
|
|
419
|
+
def flush(self):
|
|
420
|
+
"""
|
|
421
|
+
Commit cached writes to the file handle. Does not flush libc buffers or
|
|
422
|
+
notifies the kernel, so these changes may not immediately be visible to
|
|
423
|
+
other processes.
|
|
424
|
+
|
|
425
|
+
Updates the fingerprints whena writes happen, so successive ``flush()``
|
|
426
|
+
invocations are no-ops.
|
|
427
|
+
|
|
428
|
+
It is not necessary to call this method in user code.
|
|
429
|
+
|
|
430
|
+
Notes
|
|
431
|
+
-----
|
|
432
|
+
.. versionadded:: 1.6
|
|
433
|
+
|
|
434
|
+
This method is not intended as user-oriented functionality, but might
|
|
435
|
+
be useful in certain contexts to provide stronger guarantees.
|
|
436
|
+
"""
|
|
437
|
+
garbage = []
|
|
438
|
+
# If there are no external references to the data (so only internal
|
|
439
|
+
# references remain), the reference count is
|
|
440
|
+
# - 2 (Python >= 3.14)
|
|
441
|
+
# - 3 (Python < 3.14)
|
|
442
|
+
garbage_threshold = 3 if sys.version_info < (3, 14) else 2
|
|
443
|
+
|
|
444
|
+
for i, (x, signature) in self.refs.items():
|
|
445
|
+
if sys.getrefcount(x) == garbage_threshold:
|
|
446
|
+
garbage.append(i)
|
|
447
|
+
|
|
448
|
+
if fingerprint(x) == signature: continue
|
|
449
|
+
|
|
450
|
+
self.segyfd.puttr(i, x)
|
|
451
|
+
signature = fingerprint(x)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
# to avoid too many resource leaks, when this dict is the only one
|
|
455
|
+
# holding references to already-produced traces, clear them
|
|
456
|
+
for i in garbage:
|
|
457
|
+
del self.refs[i]
|
|
458
|
+
|
|
459
|
+
def fetch(self, i, buf = None):
|
|
460
|
+
if buf is None:
|
|
461
|
+
buf = np.zeros(self.shape, dtype = self.dtype)
|
|
462
|
+
|
|
463
|
+
try:
|
|
464
|
+
self.segyfd.gettr(buf, i, 1, 1, 0, self.shape, 1, self.shape)
|
|
465
|
+
except IOError:
|
|
466
|
+
if not self.readonly:
|
|
467
|
+
# if the file is opened read-only and this happens, there's no
|
|
468
|
+
# way to actually write and the error is an actual error
|
|
469
|
+
buf.fill(0)
|
|
470
|
+
else: raise
|
|
471
|
+
|
|
472
|
+
return buf
|
|
473
|
+
|
|
474
|
+
def __getitem__(self, i):
|
|
475
|
+
"""trace[i]
|
|
476
|
+
|
|
477
|
+
Read the ith trace of the file, starting at 0. trace[i] returns a numpy
|
|
478
|
+
array, but unlike Trace, changes to this array *will* be reflected on
|
|
479
|
+
disk. The modifications must happen to the actual array (views are ok),
|
|
480
|
+
so in-place operations work, but assignments will not::
|
|
481
|
+
|
|
482
|
+
>>> with ref as ref:
|
|
483
|
+
... x = ref[10]
|
|
484
|
+
... x += 1.617 # in-place, works
|
|
485
|
+
... numpy.copyto(x, x + 10) # works
|
|
486
|
+
... x = x + 10 # re-assignment, won't change the original x
|
|
487
|
+
|
|
488
|
+
Works on newly created files that has yet to have any traces written,
|
|
489
|
+
which opens up a natural way of filling newly created files with data.
|
|
490
|
+
When getting unwritten traces, a trace filled with zeros is returned.
|
|
491
|
+
|
|
492
|
+
Parameters
|
|
493
|
+
----------
|
|
494
|
+
i : int or slice
|
|
495
|
+
|
|
496
|
+
Returns
|
|
497
|
+
-------
|
|
498
|
+
trace : numpy.ndarray of dtype
|
|
499
|
+
|
|
500
|
+
Notes
|
|
501
|
+
-----
|
|
502
|
+
.. versionadded:: 1.6
|
|
503
|
+
|
|
504
|
+
Behaves like [] for lists.
|
|
505
|
+
|
|
506
|
+
Examples
|
|
507
|
+
--------
|
|
508
|
+
Merge two files with a binary operation. Relies on python3 iterator
|
|
509
|
+
zip:
|
|
510
|
+
|
|
511
|
+
>>> with ref as ref:
|
|
512
|
+
... for x, lhs, rhs in zip(ref, L, R):
|
|
513
|
+
... numpy.copyto(x, lhs + rhs)
|
|
514
|
+
|
|
515
|
+
Create a file and fill with data (the repeated trace index):
|
|
516
|
+
|
|
517
|
+
>>> f = create()
|
|
518
|
+
>>> with f.trace.ref as ref:
|
|
519
|
+
... for i, x in enumerate(ref):
|
|
520
|
+
... x.fill(i)
|
|
521
|
+
"""
|
|
522
|
+
try:
|
|
523
|
+
i = self.wrapindex(i)
|
|
524
|
+
|
|
525
|
+
# we know this class is only used in context managers, so we know
|
|
526
|
+
# refs don't escape (with expectation of being written), so
|
|
527
|
+
# preserve all refs yielded with getitem(int)
|
|
528
|
+
#
|
|
529
|
+
# using ref[int] is problematic and pointless, we need to handle
|
|
530
|
+
# this scenario gracefully:
|
|
531
|
+
# with f.trace.ref as ref:
|
|
532
|
+
# x = ref[10]
|
|
533
|
+
# x[5] = 0
|
|
534
|
+
# # invalidate other refs
|
|
535
|
+
# y = ref[11]
|
|
536
|
+
# y[6] = 1.6721
|
|
537
|
+
#
|
|
538
|
+
# # if we don't preserve returned individual getitems, this
|
|
539
|
+
# # write is lost
|
|
540
|
+
# x[5] = 52
|
|
541
|
+
#
|
|
542
|
+
# for slices, we know that references terminate with every
|
|
543
|
+
# iteration anyway, multiple live references cannot happen
|
|
544
|
+
|
|
545
|
+
if i in self.refs:
|
|
546
|
+
return self.refs[i][0]
|
|
547
|
+
|
|
548
|
+
x = self.fetch(i)
|
|
549
|
+
self.refs[i] = (x, fingerprint(x))
|
|
550
|
+
return x
|
|
551
|
+
|
|
552
|
+
except TypeError:
|
|
553
|
+
try:
|
|
554
|
+
indices = i.indices(len(self))
|
|
555
|
+
except AttributeError:
|
|
556
|
+
msg = 'trace indices must be integers or slices, not {}'
|
|
557
|
+
raise TypeError(msg.format(type(i).__name__))
|
|
558
|
+
|
|
559
|
+
def gen():
|
|
560
|
+
x = np.zeros(self.shape, dtype = self.dtype)
|
|
561
|
+
try:
|
|
562
|
+
for j in range(*indices):
|
|
563
|
+
x = self.fetch(j, x)
|
|
564
|
+
y = fingerprint(x)
|
|
565
|
+
|
|
566
|
+
yield x
|
|
567
|
+
|
|
568
|
+
if not fingerprint(x) == y:
|
|
569
|
+
self.segyfd.puttr(j, x)
|
|
570
|
+
|
|
571
|
+
finally:
|
|
572
|
+
# the last yielded item is available after the loop, so
|
|
573
|
+
# preserve it and check if it's been updated on exit
|
|
574
|
+
self.refs[j] = (x, y)
|
|
575
|
+
|
|
576
|
+
return gen()
|
|
577
|
+
|
|
578
|
+
class Header(Sequence):
|
|
579
|
+
"""Interact with segy in header mode
|
|
580
|
+
|
|
581
|
+
This mode gives access to reading and writing functionality of headers,
|
|
582
|
+
both in individual (trace) mode and line mode. The returned header
|
|
583
|
+
implements a dict_like object with a fixed set of keys, given by the SEG-Y
|
|
584
|
+
standard.
|
|
585
|
+
|
|
586
|
+
The Header implements the array interface, where every array element, the
|
|
587
|
+
data trace, is a numpy.ndarray. As all arrays, it can be random accessed,
|
|
588
|
+
iterated over, and read strided. Data is read lazily from disk, so
|
|
589
|
+
iteration does not consume much memory.
|
|
590
|
+
|
|
591
|
+
Notes
|
|
592
|
+
-----
|
|
593
|
+
.. versionadded:: 1.1
|
|
594
|
+
|
|
595
|
+
.. versionchanged:: 1.6
|
|
596
|
+
common list operations (Sequence)
|
|
597
|
+
|
|
598
|
+
"""
|
|
599
|
+
def __init__(self, segyfile):
|
|
600
|
+
self.segyfile = segyfile
|
|
601
|
+
super(Header, self).__init__(segyfile.tracecount)
|
|
602
|
+
|
|
603
|
+
def __getitem__(self, i):
|
|
604
|
+
"""header[i]
|
|
605
|
+
|
|
606
|
+
ith header of the file, starting at 0.
|
|
607
|
+
|
|
608
|
+
Parameters
|
|
609
|
+
----------
|
|
610
|
+
i : int or slice
|
|
611
|
+
|
|
612
|
+
Returns
|
|
613
|
+
-------
|
|
614
|
+
field : Field
|
|
615
|
+
dict_like header
|
|
616
|
+
|
|
617
|
+
Notes
|
|
618
|
+
-----
|
|
619
|
+
.. versionadded:: 1.1
|
|
620
|
+
|
|
621
|
+
Behaves like [] for lists.
|
|
622
|
+
|
|
623
|
+
Examples
|
|
624
|
+
--------
|
|
625
|
+
Reading a header:
|
|
626
|
+
|
|
627
|
+
>>> header[10]
|
|
628
|
+
|
|
629
|
+
Read a field in the first 5 headers:
|
|
630
|
+
|
|
631
|
+
>>> [x[25] for x in header[:5]]
|
|
632
|
+
[1, 2, 3, 4, 5]
|
|
633
|
+
|
|
634
|
+
Read a field in every other header:
|
|
635
|
+
|
|
636
|
+
>>> [x[37] for x in header[::2]]
|
|
637
|
+
[1, 3, 1, 3, 1, 3]
|
|
638
|
+
"""
|
|
639
|
+
try:
|
|
640
|
+
i = self.wrapindex(i)
|
|
641
|
+
return Field.trace(traceno = i, traceheader_index = 0, segyfile = self.segyfile)
|
|
642
|
+
|
|
643
|
+
except TypeError:
|
|
644
|
+
try:
|
|
645
|
+
indices = i.indices(len(self))
|
|
646
|
+
except AttributeError:
|
|
647
|
+
msg = 'trace indices must be integers or slices, not {}'
|
|
648
|
+
raise TypeError(msg.format(type(i).__name__))
|
|
649
|
+
|
|
650
|
+
def gen():
|
|
651
|
+
# double-buffer the header. when iterating over a range, we
|
|
652
|
+
# want to make sure the visible change happens as late as
|
|
653
|
+
# possible, and that in the case of exception the last valid
|
|
654
|
+
# header was untouched. this allows for some fancy control
|
|
655
|
+
# flow, and more importantly helps debugging because you can
|
|
656
|
+
# fully inspect and interact with the last good value.
|
|
657
|
+
x = Field.trace(traceno = None, traceheader_index = 0, segyfile = self.segyfile)
|
|
658
|
+
buf = bytearray(x.buf)
|
|
659
|
+
for j in range(*indices):
|
|
660
|
+
# skip re-invoking __getitem__, just update the buffer
|
|
661
|
+
# directly with fetch, and save some initialisation work
|
|
662
|
+
buf = x.fetch(buf, j)
|
|
663
|
+
x.buf[:] = buf
|
|
664
|
+
x.traceno = j
|
|
665
|
+
yield x
|
|
666
|
+
|
|
667
|
+
return gen()
|
|
668
|
+
|
|
669
|
+
def __setitem__(self, i, val):
|
|
670
|
+
"""header[i] = val
|
|
671
|
+
|
|
672
|
+
Write the ith header of the file, starting at 0. Unlike data traces
|
|
673
|
+
(which return numpy.ndarrays), changes to returned headers being
|
|
674
|
+
iterated over *will* be reflected on disk.
|
|
675
|
+
|
|
676
|
+
Parameters
|
|
677
|
+
----------
|
|
678
|
+
i : int or slice
|
|
679
|
+
val : Field or array_like of dict_like
|
|
680
|
+
|
|
681
|
+
Notes
|
|
682
|
+
-----
|
|
683
|
+
.. versionadded:: 1.1
|
|
684
|
+
|
|
685
|
+
Behaves like [] for lists
|
|
686
|
+
|
|
687
|
+
Examples
|
|
688
|
+
--------
|
|
689
|
+
Copy a header to a different trace:
|
|
690
|
+
|
|
691
|
+
>>> header[28] = header[29]
|
|
692
|
+
|
|
693
|
+
Write multiple fields in a trace:
|
|
694
|
+
|
|
695
|
+
>>> header[10] = { 37: 5, TraceField.INLINE_3D: 2484 }
|
|
696
|
+
|
|
697
|
+
Set a fixed set of values in all headers:
|
|
698
|
+
|
|
699
|
+
>>> for x in header[:]:
|
|
700
|
+
... x[37] = 1
|
|
701
|
+
... x.update({ TraceField.offset: 1, 2484: 10 })
|
|
702
|
+
|
|
703
|
+
Write a field in multiple headers
|
|
704
|
+
|
|
705
|
+
>>> for x in header[:10]:
|
|
706
|
+
... x.update({ TraceField.offset : 2 })
|
|
707
|
+
|
|
708
|
+
Write a field in every other header:
|
|
709
|
+
|
|
710
|
+
>>> for x in header[::2]:
|
|
711
|
+
... x.update({ TraceField.offset : 2 })
|
|
712
|
+
"""
|
|
713
|
+
|
|
714
|
+
x = self[i]
|
|
715
|
+
|
|
716
|
+
try:
|
|
717
|
+
x.update(val)
|
|
718
|
+
except AttributeError:
|
|
719
|
+
if isinstance(val, Field) or isinstance(val, dict):
|
|
720
|
+
val = itertools.repeat(val)
|
|
721
|
+
|
|
722
|
+
for h, v in zip(x, val):
|
|
723
|
+
h.update(v)
|
|
724
|
+
|
|
725
|
+
@property
|
|
726
|
+
def iline(self):
|
|
727
|
+
"""
|
|
728
|
+
Headers, accessed by inline
|
|
729
|
+
|
|
730
|
+
Returns
|
|
731
|
+
-------
|
|
732
|
+
line : HeaderLine
|
|
733
|
+
"""
|
|
734
|
+
return HeaderLine(self, self.segyfile.iline, 'inline')
|
|
735
|
+
|
|
736
|
+
@iline.setter
|
|
737
|
+
def iline(self, value):
|
|
738
|
+
"""Write iterables to lines
|
|
739
|
+
|
|
740
|
+
Examples:
|
|
741
|
+
Supports writing to *all* crosslines via assignment, regardless of
|
|
742
|
+
data source and format. Will respect the sample size and structure
|
|
743
|
+
of the file being assigned to, so if the argument traces are longer
|
|
744
|
+
than that of the file being written to the surplus data will be
|
|
745
|
+
ignored. Uses same rules for writing as `f.iline[i] = x`.
|
|
746
|
+
"""
|
|
747
|
+
for i, src in zip(self.segyfile.ilines, value):
|
|
748
|
+
self.iline[i] = src
|
|
749
|
+
|
|
750
|
+
@property
|
|
751
|
+
def xline(self):
|
|
752
|
+
"""
|
|
753
|
+
Headers, accessed by crossline
|
|
754
|
+
|
|
755
|
+
Returns
|
|
756
|
+
-------
|
|
757
|
+
line : HeaderLine
|
|
758
|
+
"""
|
|
759
|
+
return HeaderLine(self, self.segyfile.xline, 'crossline')
|
|
760
|
+
|
|
761
|
+
@xline.setter
|
|
762
|
+
def xline(self, value):
|
|
763
|
+
"""Write iterables to lines
|
|
764
|
+
|
|
765
|
+
Examples:
|
|
766
|
+
Supports writing to *all* crosslines via assignment, regardless of
|
|
767
|
+
data source and format. Will respect the sample size and structure
|
|
768
|
+
of the file being assigned to, so if the argument traces are longer
|
|
769
|
+
than that of the file being written to the surplus data will be
|
|
770
|
+
ignored. Uses same rules for writing as `f.xline[i] = x`.
|
|
771
|
+
"""
|
|
772
|
+
|
|
773
|
+
for i, src in zip(self.segyfile.xlines, value):
|
|
774
|
+
self.xline[i] = src
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
class FileFieldAccessor(Sequence):
|
|
778
|
+
"""
|
|
779
|
+
Sequence of rows of trace headers in a SEG-Y file.
|
|
780
|
+
|
|
781
|
+
Provides access to all trace headers defined in the SEG-Y file.
|
|
782
|
+
|
|
783
|
+
Notes
|
|
784
|
+
-----
|
|
785
|
+
.. versionadded:: 2.0
|
|
786
|
+
|
|
787
|
+
"""
|
|
788
|
+
|
|
789
|
+
def __init__(self, segyfile):
|
|
790
|
+
self.segyfile = segyfile
|
|
791
|
+
super().__init__(segyfile.tracecount)
|
|
792
|
+
|
|
793
|
+
def __getitem__(self, i):
|
|
794
|
+
"""traceheader[i]
|
|
795
|
+
|
|
796
|
+
All headers belonging to ith trace, starting at 0.
|
|
797
|
+
|
|
798
|
+
Parameters
|
|
799
|
+
----------
|
|
800
|
+
i : int or slice
|
|
801
|
+
|
|
802
|
+
Returns
|
|
803
|
+
-------
|
|
804
|
+
traceheaders : RowFieldAccessor
|
|
805
|
+
|
|
806
|
+
Examples
|
|
807
|
+
--------
|
|
808
|
+
Accessing headers in trace 10 (11th in the file):
|
|
809
|
+
|
|
810
|
+
>>> traceheader[10]
|
|
811
|
+
"""
|
|
812
|
+
try:
|
|
813
|
+
trace_index = self.wrapindex(i)
|
|
814
|
+
return RowFieldAccessor(segyfile=self.segyfile, trace_index=trace_index)
|
|
815
|
+
|
|
816
|
+
except TypeError:
|
|
817
|
+
try:
|
|
818
|
+
trace_indices = i.indices(len(self))
|
|
819
|
+
except AttributeError:
|
|
820
|
+
msg = 'trace indices must be integers or slices, not {}'
|
|
821
|
+
raise TypeError(msg.format(type(i).__name__))
|
|
822
|
+
|
|
823
|
+
def gen():
|
|
824
|
+
for trace_index in range(*trace_indices):
|
|
825
|
+
yield RowFieldAccessor(segyfile=self.segyfile, trace_index=trace_index)
|
|
826
|
+
|
|
827
|
+
return gen()
|
|
828
|
+
|
|
829
|
+
def __setitem__(self, i, val):
|
|
830
|
+
"""traceheader[i] = val
|
|
831
|
+
|
|
832
|
+
Write the ith header of the file, starting at 0.
|
|
833
|
+
|
|
834
|
+
Parameters
|
|
835
|
+
----------
|
|
836
|
+
i : int or slice
|
|
837
|
+
val : another FileFieldAccessor or array like
|
|
838
|
+
|
|
839
|
+
Examples
|
|
840
|
+
--------
|
|
841
|
+
Copy all trace's headers to a different trace:
|
|
842
|
+
|
|
843
|
+
>>> traceheader[28] = traceheader[29]
|
|
844
|
+
"""
|
|
845
|
+
if not isinstance(i, slice):
|
|
846
|
+
trace_index = self.wrapindex(i)
|
|
847
|
+
if not isinstance(val, RowFieldAccessor):
|
|
848
|
+
raise TypeError(
|
|
849
|
+
"Unassignable type. f.traceheader[i] can only be assigned f.traceheader[j]")
|
|
850
|
+
self[trace_index][:] = val
|
|
851
|
+
return
|
|
852
|
+
|
|
853
|
+
trace_indices = range(*i.indices(len(self)))
|
|
854
|
+
for trace_index, value in zip(trace_indices, val):
|
|
855
|
+
self[trace_index] = value
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
class RowFieldAccessor(Sequence):
|
|
859
|
+
"""
|
|
860
|
+
Sequence of trace headers in a single trace (row).
|
|
861
|
+
|
|
862
|
+
Provides access to all trace headers defined in the trace.
|
|
863
|
+
|
|
864
|
+
Notes
|
|
865
|
+
-----
|
|
866
|
+
.. versionadded:: 2.0
|
|
867
|
+
|
|
868
|
+
"""
|
|
869
|
+
|
|
870
|
+
def __init__(self, segyfile, trace_index):
|
|
871
|
+
self.segyfile = segyfile
|
|
872
|
+
self.trace_index = trace_index
|
|
873
|
+
super().__init__(segyfile.traceheader_count)
|
|
874
|
+
|
|
875
|
+
def __getitem__(self, i):
|
|
876
|
+
"""traceheader[i]
|
|
877
|
+
|
|
878
|
+
ith header of the trace, starting at 0.
|
|
879
|
+
|
|
880
|
+
Note that this function loads trace header into memory, so if you wish
|
|
881
|
+
to access multiple fields, caching the result of this function is more
|
|
882
|
+
efficient than calling it anew with each of the fields.
|
|
883
|
+
|
|
884
|
+
Parameters
|
|
885
|
+
----------
|
|
886
|
+
i : int or slice
|
|
887
|
+
|
|
888
|
+
Returns
|
|
889
|
+
-------
|
|
890
|
+
field : Field
|
|
891
|
+
dict_like header
|
|
892
|
+
|
|
893
|
+
Examples
|
|
894
|
+
--------
|
|
895
|
+
Reading a header:
|
|
896
|
+
|
|
897
|
+
>>> traceheader[10]
|
|
898
|
+
|
|
899
|
+
Read a field in the first 5 headers:
|
|
900
|
+
|
|
901
|
+
>>> [x[25] for x in traceheader[:5]]
|
|
902
|
+
[1, 2, 3, 4, 5]
|
|
903
|
+
"""
|
|
904
|
+
try:
|
|
905
|
+
return HeaderFieldAccessor.trace(
|
|
906
|
+
traceno=self.trace_index, traceheader_index=self.wrapindex(i), segyfile=self.segyfile
|
|
907
|
+
)
|
|
908
|
+
|
|
909
|
+
except TypeError:
|
|
910
|
+
try:
|
|
911
|
+
traceheader_indices = i.indices(len(self))
|
|
912
|
+
except AttributeError:
|
|
913
|
+
msg = 'trace header indices must be integers or slices, not {}'
|
|
914
|
+
raise TypeError(msg.format(type(i).__name__))
|
|
915
|
+
|
|
916
|
+
def gen():
|
|
917
|
+
# see Header.__getitem__ for logic explanation
|
|
918
|
+
x = HeaderFieldAccessor.trace(
|
|
919
|
+
traceno=self.trace_index, traceheader_index=None, segyfile=self.segyfile
|
|
920
|
+
)
|
|
921
|
+
buf = bytearray(x.buf)
|
|
922
|
+
for traceheader_index in range(*traceheader_indices):
|
|
923
|
+
buf = x.fetch(buf, self.trace_index, traceheader_index)
|
|
924
|
+
x.buf[:] = buf
|
|
925
|
+
x.traceheader_index = traceheader_index
|
|
926
|
+
traceheader_layout = x.segyfile.tracefield[traceheader_index]
|
|
927
|
+
x._keys = [field.offset() for field in traceheader_layout]
|
|
928
|
+
yield x
|
|
929
|
+
|
|
930
|
+
return gen()
|
|
931
|
+
|
|
932
|
+
def __getattr__(self, name):
|
|
933
|
+
"""traceheaders.name
|
|
934
|
+
|
|
935
|
+
Header of the trace by name `name`. `name` must be a name defined by
|
|
936
|
+
the file layouts.
|
|
937
|
+
|
|
938
|
+
Wrapper around :meth:`.__getitem__`, so refer to it for more
|
|
939
|
+
information.
|
|
940
|
+
|
|
941
|
+
Parameters
|
|
942
|
+
----------
|
|
943
|
+
name : str
|
|
944
|
+
|
|
945
|
+
Returns
|
|
946
|
+
-------
|
|
947
|
+
field : Field
|
|
948
|
+
dict_like header
|
|
949
|
+
|
|
950
|
+
Examples
|
|
951
|
+
--------
|
|
952
|
+
Reading a header:
|
|
953
|
+
|
|
954
|
+
>>> traceheaders.SEG00001
|
|
955
|
+
"""
|
|
956
|
+
index = self.segyfile._traceheader_names.index(name)
|
|
957
|
+
return self[index]
|
|
958
|
+
|
|
959
|
+
def __setitem__(self, i, val):
|
|
960
|
+
"""traceheader[i] = val
|
|
961
|
+
|
|
962
|
+
Write the ith header of the trace, starting at 0.
|
|
963
|
+
|
|
964
|
+
Parameters
|
|
965
|
+
----------
|
|
966
|
+
i : int or slice
|
|
967
|
+
val : Field or array_like of dict_like
|
|
968
|
+
|
|
969
|
+
Examples
|
|
970
|
+
--------
|
|
971
|
+
Copy standard header to a different trace:
|
|
972
|
+
|
|
973
|
+
>>> f.traceheader[0][0] = f.traceheader[1][0]
|
|
974
|
+
|
|
975
|
+
Writing fields via `traceheader[trace_index][traceheader_index] =
|
|
976
|
+
{(offset: value)}` is not supported. Use :class:`segyio.field.Field`
|
|
977
|
+
interface instead:
|
|
978
|
+
|
|
979
|
+
>>> f.traceheader[0][0].update({ 37: 5, 1: 2484 })
|
|
980
|
+
|
|
981
|
+
"""
|
|
982
|
+
if not isinstance(i, slice):
|
|
983
|
+
traceheader_index = self.wrapindex(i)
|
|
984
|
+
field_sequence = self[traceheader_index]
|
|
985
|
+
if isinstance(val, Field):
|
|
986
|
+
field_sequence.update(val)
|
|
987
|
+
return
|
|
988
|
+
raise TypeError(
|
|
989
|
+
"Unassignable type. f.traceheader[i][j] can only be assigned another Field.")
|
|
990
|
+
|
|
991
|
+
traceheader_indices = range(*i.indices(len(self)))
|
|
992
|
+
|
|
993
|
+
for traceheader_index, value in zip(traceheader_indices, val):
|
|
994
|
+
self[traceheader_index] = value
|
|
995
|
+
|
|
996
|
+
def __setattr__(self, name, value):
|
|
997
|
+
"""traceheaders.name = value
|
|
998
|
+
|
|
999
|
+
Write header of the trace by name `name`. `name` must be a name defined by
|
|
1000
|
+
the file layouts.
|
|
1001
|
+
|
|
1002
|
+
Wrapper around :meth:`.__setitem__`, so refer to it for more
|
|
1003
|
+
information.
|
|
1004
|
+
|
|
1005
|
+
Parameters
|
|
1006
|
+
----------
|
|
1007
|
+
name : str
|
|
1008
|
+
|
|
1009
|
+
Examples
|
|
1010
|
+
--------
|
|
1011
|
+
Copying a header:
|
|
1012
|
+
|
|
1013
|
+
>>> f.traceheader[0].SEG00001 = f.traceheader[1].SEG00001
|
|
1014
|
+
"""
|
|
1015
|
+
if name == "segyfile":
|
|
1016
|
+
super().__setattr__(name, value)
|
|
1017
|
+
return
|
|
1018
|
+
|
|
1019
|
+
try:
|
|
1020
|
+
index = self.segyfile._traceheader_names.index(name)
|
|
1021
|
+
self[index] = value
|
|
1022
|
+
except ValueError:
|
|
1023
|
+
super().__setattr__(name, value)
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
class Attributes(Sequence):
|
|
1027
|
+
"""File-wide attribute (header word) reading
|
|
1028
|
+
|
|
1029
|
+
Lazily read a single header word for every trace in the file. The
|
|
1030
|
+
Attributes implement the array interface, and will behave as expected when
|
|
1031
|
+
indexed and sliced.
|
|
1032
|
+
|
|
1033
|
+
Notes
|
|
1034
|
+
-----
|
|
1035
|
+
.. versionadded:: 1.1
|
|
1036
|
+
"""
|
|
1037
|
+
|
|
1038
|
+
ENTRY_TYPE_TO_NUMPY = {
|
|
1039
|
+
"int2": np.int16,
|
|
1040
|
+
"int4": np.int32,
|
|
1041
|
+
"int8": np.int64,
|
|
1042
|
+
"uint2": np.uint16,
|
|
1043
|
+
"uint4": np.uint32,
|
|
1044
|
+
"uint8": np.uint64,
|
|
1045
|
+
"ibmfp": np.float32,
|
|
1046
|
+
"ieee32": np.float32,
|
|
1047
|
+
"ieee64": np.float64,
|
|
1048
|
+
"linetrc": np.uint32,
|
|
1049
|
+
"reeltrc": np.uint32,
|
|
1050
|
+
"linetrc8": np.uint64,
|
|
1051
|
+
"reeltrc8": np.uint64,
|
|
1052
|
+
"coor4": np.int32,
|
|
1053
|
+
"elev4": np.int32,
|
|
1054
|
+
"time2": np.int16,
|
|
1055
|
+
"spnum4": np.int32,
|
|
1056
|
+
# "scale6" unspported, unclear what to do yet
|
|
1057
|
+
"string8": np.dtype('S8'),
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
def __init__(self, segyfile, field, traceheader_index):
|
|
1061
|
+
super(Attributes, self).__init__(segyfile.tracecount)
|
|
1062
|
+
self.field = field
|
|
1063
|
+
self.traceheader_index = traceheader_index
|
|
1064
|
+
self.segyfd = segyfile.segyfd
|
|
1065
|
+
self.tracecount = segyfile.tracecount
|
|
1066
|
+
|
|
1067
|
+
traceheader_layout = list(segyfile._traceheader_layouts.values())[traceheader_index]
|
|
1068
|
+
entry = traceheader_layout.entry_by_byte(field)
|
|
1069
|
+
self.dtype = Attributes.ENTRY_TYPE_TO_NUMPY[entry.type]
|
|
1070
|
+
|
|
1071
|
+
def __iter__(self):
|
|
1072
|
+
# attributes requires a custom iter, because self[:] returns a numpy
|
|
1073
|
+
# array, which in itself is iterable, but not an iterator
|
|
1074
|
+
return iter(self[:])
|
|
1075
|
+
|
|
1076
|
+
def __getitem__(self, i):
|
|
1077
|
+
"""attributes[:]
|
|
1078
|
+
|
|
1079
|
+
Parameters
|
|
1080
|
+
----------
|
|
1081
|
+
i : int or slice or array_like
|
|
1082
|
+
|
|
1083
|
+
Returns
|
|
1084
|
+
-------
|
|
1085
|
+
attributes : array_like of dtype
|
|
1086
|
+
|
|
1087
|
+
Examples
|
|
1088
|
+
--------
|
|
1089
|
+
Assuming file with default layout mapping, read all unique sweep
|
|
1090
|
+
frequency end:
|
|
1091
|
+
|
|
1092
|
+
>>> end = segyio.TraceField.SweepFrequencyEnd
|
|
1093
|
+
>>> sfe = np.unique(f.attributes( end )[:])
|
|
1094
|
+
|
|
1095
|
+
Discover the first traces of each unique sweep frequency end:
|
|
1096
|
+
|
|
1097
|
+
>>> end = segyio.TraceField.SweepFrequencyEnd
|
|
1098
|
+
>>> attrs = f.attributes(end)
|
|
1099
|
+
>>> sfe, tracenos = np.unique(attrs[:], return_index = True)
|
|
1100
|
+
|
|
1101
|
+
Scatter plot group x/y-coordinates with SFEs (using matplotlib):
|
|
1102
|
+
|
|
1103
|
+
>>> end = segyio.TraceField.SweepFrequencyEnd
|
|
1104
|
+
>>> attrs = f.attributes(end)
|
|
1105
|
+
>>> _, tracenos = np.unique(attrs[:], return_index = True)
|
|
1106
|
+
>>> gx = f.attributes(segyio.TraceField.GroupX)[tracenos]
|
|
1107
|
+
>>> gy = f.attributes(segyio.TraceField.GroupY)[tracenos]
|
|
1108
|
+
>>> scatter(gx, gy)
|
|
1109
|
+
"""
|
|
1110
|
+
try:
|
|
1111
|
+
xs = np.asarray(i, dtype=np.int32)
|
|
1112
|
+
xs = xs.astype(dtype=np.int32, order='C', copy=False)
|
|
1113
|
+
attrs = np.empty(len(xs), dtype = self.dtype)
|
|
1114
|
+
return self.segyfd.field_foreach(attrs, self.traceheader_index, xs, self.field)
|
|
1115
|
+
|
|
1116
|
+
except TypeError:
|
|
1117
|
+
try:
|
|
1118
|
+
i = slice(i, i + 1, 1)
|
|
1119
|
+
except TypeError:
|
|
1120
|
+
pass
|
|
1121
|
+
|
|
1122
|
+
traces = self.tracecount
|
|
1123
|
+
segyfd = self.segyfd
|
|
1124
|
+
field = self.field
|
|
1125
|
+
|
|
1126
|
+
start, stop, step = i.indices(traces)
|
|
1127
|
+
indices = range(start, stop, step)
|
|
1128
|
+
attrs = np.empty(len(indices), dtype = self.dtype)
|
|
1129
|
+
return segyfd.field_forall(attrs, self.traceheader_index, start, stop, step, field)
|
|
1130
|
+
|
|
1131
|
+
class Text(Sequence):
|
|
1132
|
+
"""Interact with segy in text mode
|
|
1133
|
+
|
|
1134
|
+
This mode gives access to reading and writing functionality for textual
|
|
1135
|
+
headers.
|
|
1136
|
+
|
|
1137
|
+
The primary data type is the python string. Reading textual headers is done
|
|
1138
|
+
with [], and writing is done via assignment. No additional structure is
|
|
1139
|
+
built around the textual header, so everything is treated as one long
|
|
1140
|
+
string without line breaks.
|
|
1141
|
+
|
|
1142
|
+
Notes
|
|
1143
|
+
-----
|
|
1144
|
+
.. versionchanged:: 1.7
|
|
1145
|
+
common list operations (Sequence)
|
|
1146
|
+
|
|
1147
|
+
"""
|
|
1148
|
+
|
|
1149
|
+
def __init__(self, segyfd, textcount):
|
|
1150
|
+
super(Text, self).__init__(textcount)
|
|
1151
|
+
self.segyfd = segyfd
|
|
1152
|
+
|
|
1153
|
+
def __getitem__(self, i):
|
|
1154
|
+
"""text[i]
|
|
1155
|
+
|
|
1156
|
+
Read the text header at i. 0 is the mandatory, main
|
|
1157
|
+
|
|
1158
|
+
Examples
|
|
1159
|
+
--------
|
|
1160
|
+
Print the textual header:
|
|
1161
|
+
|
|
1162
|
+
>>> print(f.text[0])
|
|
1163
|
+
|
|
1164
|
+
Print the first extended textual header:
|
|
1165
|
+
|
|
1166
|
+
>>> print(f.text[1])
|
|
1167
|
+
|
|
1168
|
+
Print a textual header line-by-line:
|
|
1169
|
+
|
|
1170
|
+
>>> # using zip, from the zip documentation
|
|
1171
|
+
>>> text = f.text[0].decode('ascii', errors='replace')
|
|
1172
|
+
>>> lines = map(''.join, zip( *[iter(text)] * 80))
|
|
1173
|
+
>>> for line in lines:
|
|
1174
|
+
... print(line)
|
|
1175
|
+
...
|
|
1176
|
+
|
|
1177
|
+
Or use segyio.tools.wrap:
|
|
1178
|
+
>>> text = segyio.tools.wrap(f.text[0].decode('latin-1'))
|
|
1179
|
+
"""
|
|
1180
|
+
try:
|
|
1181
|
+
i = self.wrapindex(i)
|
|
1182
|
+
return self.segyfd.gettext(i)
|
|
1183
|
+
|
|
1184
|
+
except TypeError:
|
|
1185
|
+
try:
|
|
1186
|
+
indices = i.indices(len(self))
|
|
1187
|
+
except AttributeError:
|
|
1188
|
+
msg = 'trace indices must be integers or slices, not {}'
|
|
1189
|
+
raise TypeError(msg.format(type(i).__name__))
|
|
1190
|
+
|
|
1191
|
+
def gen():
|
|
1192
|
+
for j in range(*indices):
|
|
1193
|
+
yield self.segyfd.gettext(j)
|
|
1194
|
+
return gen()
|
|
1195
|
+
|
|
1196
|
+
def __setitem__(self, i, val):
|
|
1197
|
+
"""text[i] = val
|
|
1198
|
+
|
|
1199
|
+
Write the ith text header of the file, starting at 0.
|
|
1200
|
+
If val is instance of Text or iterable of Text,
|
|
1201
|
+
value is set to be the first element of every Text
|
|
1202
|
+
|
|
1203
|
+
Parameters
|
|
1204
|
+
----------
|
|
1205
|
+
i : int or slice
|
|
1206
|
+
val : str, Text or iterable if i is slice
|
|
1207
|
+
|
|
1208
|
+
Examples
|
|
1209
|
+
--------
|
|
1210
|
+
Write a new textual header:
|
|
1211
|
+
|
|
1212
|
+
>>> f.text[0] = make_new_header()
|
|
1213
|
+
>>> f.text[1:3] = ["new_header1", "new_header_2"]
|
|
1214
|
+
|
|
1215
|
+
Copy a textual header:
|
|
1216
|
+
|
|
1217
|
+
>>> f.text[1] = g.text[0]
|
|
1218
|
+
|
|
1219
|
+
Write a textual header based on Text:
|
|
1220
|
+
|
|
1221
|
+
>>> f.text[1] = g.text
|
|
1222
|
+
>>> assert f.text[1] == g.text[0]
|
|
1223
|
+
|
|
1224
|
+
>>> f.text[1:3] = [g1.text, g2.text]
|
|
1225
|
+
>>> assert f.text[1] == g1.text[0]
|
|
1226
|
+
>>> assert f.text[2] == g2.text[0]
|
|
1227
|
+
|
|
1228
|
+
"""
|
|
1229
|
+
if isinstance(val, Text):
|
|
1230
|
+
self[i] = val[0]
|
|
1231
|
+
return
|
|
1232
|
+
|
|
1233
|
+
try:
|
|
1234
|
+
i = self.wrapindex(i)
|
|
1235
|
+
self.segyfd.puttext(i, val)
|
|
1236
|
+
|
|
1237
|
+
except TypeError:
|
|
1238
|
+
try:
|
|
1239
|
+
indices = i.indices(len(self))
|
|
1240
|
+
except AttributeError:
|
|
1241
|
+
msg = 'trace indices must be integers or slices, not {}'
|
|
1242
|
+
raise TypeError(msg.format(type(i).__name__))
|
|
1243
|
+
|
|
1244
|
+
for i, text in zip(range(*indices), val):
|
|
1245
|
+
if isinstance(text, Text):
|
|
1246
|
+
text = text[0]
|
|
1247
|
+
self.segyfd.puttext(i, text)
|
|
1248
|
+
|
|
1249
|
+
|
|
1250
|
+
class Stanza(Sequence):
|
|
1251
|
+
"""Access stanza data from extended textual headers.
|
|
1252
|
+
|
|
1253
|
+
Reading stanzas is done with []. Keys are stanza indices, values are raw
|
|
1254
|
+
stanza data as bytes. Stanza name (stanza header) is not included in the
|
|
1255
|
+
return bytes.
|
|
1256
|
+
|
|
1257
|
+
Writing stanzas is not supported.
|
|
1258
|
+
|
|
1259
|
+
Notes
|
|
1260
|
+
-----
|
|
1261
|
+
.. versionadded:: 2.0
|
|
1262
|
+
|
|
1263
|
+
Examples
|
|
1264
|
+
--------
|
|
1265
|
+
Get all stanza names:
|
|
1266
|
+
|
|
1267
|
+
>>> names = f.stanza.names()
|
|
1268
|
+
... ['OGP:P1/11:text/csv', 'SEG:catalog', 'TROIKA:IMAGEPNG:image/png:51929']
|
|
1269
|
+
|
|
1270
|
+
Access stanza data:
|
|
1271
|
+
|
|
1272
|
+
>>> data = f.stanza[2]
|
|
1273
|
+
"""
|
|
1274
|
+
|
|
1275
|
+
def __init__(self, segyfd):
|
|
1276
|
+
self.segyfd = segyfd
|
|
1277
|
+
self._names = self.segyfd.stanza_names()
|
|
1278
|
+
super(Stanza, self).__init__(len(self._names))
|
|
1279
|
+
|
|
1280
|
+
def names(self):
|
|
1281
|
+
"""Get all stanza names. Names are the same as they appear in the file.
|
|
1282
|
+
|
|
1283
|
+
Returns
|
|
1284
|
+
-------
|
|
1285
|
+
names : list of str
|
|
1286
|
+
List of all stanza names in the file in order of appearance
|
|
1287
|
+
"""
|
|
1288
|
+
return self._names
|
|
1289
|
+
|
|
1290
|
+
def __getitem__(self, key):
|
|
1291
|
+
"""Get stanza data by index.
|
|
1292
|
+
|
|
1293
|
+
Parameters
|
|
1294
|
+
----------
|
|
1295
|
+
key : int or slice
|
|
1296
|
+
Stanza index or indices
|
|
1297
|
+
|
|
1298
|
+
Returns
|
|
1299
|
+
-------
|
|
1300
|
+
data : bytes
|
|
1301
|
+
Stanza data for single stanza, or generator for slice
|
|
1302
|
+
|
|
1303
|
+
Examples
|
|
1304
|
+
--------
|
|
1305
|
+
Access by index:
|
|
1306
|
+
|
|
1307
|
+
>>> data = f.stanza[0]
|
|
1308
|
+
|
|
1309
|
+
Find stanza that fits name pattern:
|
|
1310
|
+
|
|
1311
|
+
>>> for i, name in enumerate(f.stanza.names()):
|
|
1312
|
+
>>> if name.upper().startswith("SEG:LAYOUT"):
|
|
1313
|
+
>>> layout_stanza_index = i
|
|
1314
|
+
>>> data = f.stanza[layout_stanza_index]
|
|
1315
|
+
"""
|
|
1316
|
+
try:
|
|
1317
|
+
index = self.wrapindex(key)
|
|
1318
|
+
return self.segyfd.getstanza(index)
|
|
1319
|
+
except TypeError:
|
|
1320
|
+
try:
|
|
1321
|
+
indices = key.indices(len(self))
|
|
1322
|
+
except AttributeError:
|
|
1323
|
+
msg = 'stanza indices must be integers, strings, or slices, not {}'
|
|
1324
|
+
raise TypeError(msg.format(type(key).__name__))
|
|
1325
|
+
|
|
1326
|
+
def gen():
|
|
1327
|
+
for j in range(*indices):
|
|
1328
|
+
yield self.segyfd.getstanza(j)
|
|
1329
|
+
return gen()
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
class RowLayoutEntries(Sequence):
|
|
1333
|
+
"""
|
|
1334
|
+
Sequence of trace header layouts in one trace (row).
|
|
1335
|
+
|
|
1336
|
+
Provides access to all trace header layouts defined in the SEG-Y file.
|
|
1337
|
+
|
|
1338
|
+
Notes
|
|
1339
|
+
-----
|
|
1340
|
+
.. versionadded:: 2.0
|
|
1341
|
+
"""
|
|
1342
|
+
|
|
1343
|
+
def __init__(self, segyfile):
|
|
1344
|
+
self.segyfile = segyfile
|
|
1345
|
+
self._layouts = segyfile._traceheader_layouts
|
|
1346
|
+
self._layout_names = list(self._layouts.keys())
|
|
1347
|
+
|
|
1348
|
+
super().__init__(segyfile.traceheader_count)
|
|
1349
|
+
|
|
1350
|
+
def __getitem__(self, key):
|
|
1351
|
+
"""
|
|
1352
|
+
Get a trace header fields layout by index or slice.
|
|
1353
|
+
|
|
1354
|
+
Parameters
|
|
1355
|
+
----------
|
|
1356
|
+
key : int or slice
|
|
1357
|
+
Index or range.
|
|
1358
|
+
|
|
1359
|
+
Returns
|
|
1360
|
+
-------
|
|
1361
|
+
HeaderLayoutEntries or generator of HeaderLayoutEntries
|
|
1362
|
+
|
|
1363
|
+
Examples
|
|
1364
|
+
--------
|
|
1365
|
+
Get the layout via [] notation:
|
|
1366
|
+
|
|
1367
|
+
>>> layout = traceheader_layouts[0]
|
|
1368
|
+
"""
|
|
1369
|
+
try:
|
|
1370
|
+
traceheader_index = self.wrapindex(key)
|
|
1371
|
+
name = self._layout_names[traceheader_index]
|
|
1372
|
+
layout = self._layouts[name]
|
|
1373
|
+
return HeaderLayoutEntries(self.segyfile, traceheader_index, layout)
|
|
1374
|
+
except TypeError:
|
|
1375
|
+
indices = key.indices(len(self))
|
|
1376
|
+
|
|
1377
|
+
def gen():
|
|
1378
|
+
for traceheader_index in range(*indices):
|
|
1379
|
+
name = self._layout_names[traceheader_index]
|
|
1380
|
+
layout = self._layouts[name]
|
|
1381
|
+
yield HeaderLayoutEntries(self.segyfile, traceheader_index, layout)
|
|
1382
|
+
return gen()
|
|
1383
|
+
|
|
1384
|
+
def __getattr__(self, name):
|
|
1385
|
+
"""
|
|
1386
|
+
Get trace header fields layout as an attribute.
|
|
1387
|
+
|
|
1388
|
+
Parameters
|
|
1389
|
+
----------
|
|
1390
|
+
name : str
|
|
1391
|
+
Name of the layout. Name is case-sensitive.
|
|
1392
|
+
|
|
1393
|
+
Returns
|
|
1394
|
+
-------
|
|
1395
|
+
HeaderLayoutEntries
|
|
1396
|
+
|
|
1397
|
+
Examples
|
|
1398
|
+
--------
|
|
1399
|
+
Get the field layout via . notation:
|
|
1400
|
+
|
|
1401
|
+
>>> layout = traceheader_layouts.SEG00000
|
|
1402
|
+
|
|
1403
|
+
Raises
|
|
1404
|
+
------
|
|
1405
|
+
AttributeError
|
|
1406
|
+
If the layout does not exist.
|
|
1407
|
+
"""
|
|
1408
|
+
if name in self._layouts:
|
|
1409
|
+
traceheader_index = self._layout_names.index(name)
|
|
1410
|
+
return HeaderLayoutEntries(self.segyfile, traceheader_index, self._layouts[name])
|
|
1411
|
+
raise AttributeError(f"No header with name: {name}")
|
|
1412
|
+
|
|
1413
|
+
def names(self):
|
|
1414
|
+
"""
|
|
1415
|
+
List all trace header names.
|
|
1416
|
+
|
|
1417
|
+
Returns
|
|
1418
|
+
-------
|
|
1419
|
+
list of str
|
|
1420
|
+
Names of all traceheaders.
|
|
1421
|
+
"""
|
|
1422
|
+
return self._layout_names
|
|
1423
|
+
|
|
1424
|
+
def __repr__(self):
|
|
1425
|
+
return f"RowLayoutEntries({self._layout_names})"
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
class HeaderLayoutEntries(Sequence):
|
|
1429
|
+
"""
|
|
1430
|
+
Sequence of field layout entries in a trace header.
|
|
1431
|
+
|
|
1432
|
+
Provides access to the individual fields (entries) within a trace header
|
|
1433
|
+
layout.
|
|
1434
|
+
|
|
1435
|
+
Notes
|
|
1436
|
+
-----
|
|
1437
|
+
.. versionadded:: 2.0
|
|
1438
|
+
"""
|
|
1439
|
+
|
|
1440
|
+
def __init__(self, segyfile, traceheader_index, layout):
|
|
1441
|
+
self.segyfile = segyfile
|
|
1442
|
+
self._layout = layout
|
|
1443
|
+
self.traceheader_index = traceheader_index
|
|
1444
|
+
|
|
1445
|
+
super().__init__(len(layout))
|
|
1446
|
+
|
|
1447
|
+
def __getitem__(self, key):
|
|
1448
|
+
"""
|
|
1449
|
+
Get field entries by index or slice.
|
|
1450
|
+
|
|
1451
|
+
Parameters
|
|
1452
|
+
----------
|
|
1453
|
+
key : int or slice
|
|
1454
|
+
Index or range.
|
|
1455
|
+
|
|
1456
|
+
Returns
|
|
1457
|
+
-------
|
|
1458
|
+
FieldLayoutEntry or generator of FieldLayoutEntry
|
|
1459
|
+
|
|
1460
|
+
Examples
|
|
1461
|
+
--------
|
|
1462
|
+
Get the entry via [] notation:
|
|
1463
|
+
|
|
1464
|
+
>>> entry = layout[3]
|
|
1465
|
+
"""
|
|
1466
|
+
try:
|
|
1467
|
+
entry_index = self.wrapindex(key)
|
|
1468
|
+
entry = self._layout.entries[entry_index]
|
|
1469
|
+
return FieldLayoutEntry(self.segyfile, entry, self.traceheader_index)
|
|
1470
|
+
|
|
1471
|
+
except TypeError:
|
|
1472
|
+
indices = key.indices(len(self))
|
|
1473
|
+
|
|
1474
|
+
def gen():
|
|
1475
|
+
for entry_index in range(*indices):
|
|
1476
|
+
entry = self._layout.entries[entry_index]
|
|
1477
|
+
yield FieldLayoutEntry(self.segyfile, entry, self.traceheader_index)
|
|
1478
|
+
return gen()
|
|
1479
|
+
|
|
1480
|
+
def __getattr__(self, name):
|
|
1481
|
+
"""
|
|
1482
|
+
Get field entry as an attribute.
|
|
1483
|
+
|
|
1484
|
+
Parameters
|
|
1485
|
+
----------
|
|
1486
|
+
name : str
|
|
1487
|
+
Name of the field. Name is case-sensitive.
|
|
1488
|
+
|
|
1489
|
+
Returns
|
|
1490
|
+
-------
|
|
1491
|
+
FieldLayoutEntry
|
|
1492
|
+
|
|
1493
|
+
Examples
|
|
1494
|
+
--------
|
|
1495
|
+
Get the entry via . notation:
|
|
1496
|
+
|
|
1497
|
+
>>> entry = layout.iline
|
|
1498
|
+
|
|
1499
|
+
Raises
|
|
1500
|
+
------
|
|
1501
|
+
AttributeError
|
|
1502
|
+
If the field by that name does not exist.
|
|
1503
|
+
"""
|
|
1504
|
+
entry = self._layout.entry_by_name(name)
|
|
1505
|
+
if entry is None:
|
|
1506
|
+
raise AttributeError(f"No field with name: {name}")
|
|
1507
|
+
return FieldLayoutEntry(self.segyfile, entry, self.traceheader_index)
|
|
1508
|
+
|
|
1509
|
+
def names(self):
|
|
1510
|
+
"""
|
|
1511
|
+
List all field names in this traceheader layout.
|
|
1512
|
+
|
|
1513
|
+
Returns
|
|
1514
|
+
-------
|
|
1515
|
+
list of str
|
|
1516
|
+
Names of all fields.
|
|
1517
|
+
"""
|
|
1518
|
+
return [entry.name for entry in self._layout]
|
|
1519
|
+
|
|
1520
|
+
def index(self):
|
|
1521
|
+
"""
|
|
1522
|
+
Get traceheader index of this layout.
|
|
1523
|
+
|
|
1524
|
+
Returns
|
|
1525
|
+
-------
|
|
1526
|
+
int
|
|
1527
|
+
Layout index.
|
|
1528
|
+
"""
|
|
1529
|
+
return self.traceheader_index
|
|
1530
|
+
|
|
1531
|
+
def __repr__(self):
|
|
1532
|
+
return f"HeaderLayoutEntries({self.names()})"
|
|
1533
|
+
|
|
1534
|
+
|
|
1535
|
+
class FieldLayoutEntry():
|
|
1536
|
+
"""
|
|
1537
|
+
Represents a single field entry in a trace header layout.
|
|
1538
|
+
|
|
1539
|
+
Notes
|
|
1540
|
+
-----
|
|
1541
|
+
.. versionadded:: 2.0
|
|
1542
|
+
"""
|
|
1543
|
+
|
|
1544
|
+
def __init__(self, segyfile, entry, traceheader_index):
|
|
1545
|
+
self.segyfile = segyfile
|
|
1546
|
+
self.entry = entry
|
|
1547
|
+
self.traceheader_index = traceheader_index
|
|
1548
|
+
|
|
1549
|
+
def name(self):
|
|
1550
|
+
"""
|
|
1551
|
+
Get the name of the field as is defined in the layout.
|
|
1552
|
+
|
|
1553
|
+
Returns
|
|
1554
|
+
-------
|
|
1555
|
+
str
|
|
1556
|
+
Name of the field.
|
|
1557
|
+
"""
|
|
1558
|
+
return self.entry.name
|
|
1559
|
+
|
|
1560
|
+
def offset(self):
|
|
1561
|
+
"""
|
|
1562
|
+
Get the byte offset of this field in the trace header.
|
|
1563
|
+
|
|
1564
|
+
Returns
|
|
1565
|
+
-------
|
|
1566
|
+
int
|
|
1567
|
+
Byte offset of the field.
|
|
1568
|
+
"""
|
|
1569
|
+
return self.entry.byte
|
|
1570
|
+
|
|
1571
|
+
def type(self):
|
|
1572
|
+
"""
|
|
1573
|
+
Get the data type of the field as defined in the layout.
|
|
1574
|
+
|
|
1575
|
+
Returns
|
|
1576
|
+
-------
|
|
1577
|
+
str
|
|
1578
|
+
Data type of the field.
|
|
1579
|
+
"""
|
|
1580
|
+
return self.entry.type
|
|
1581
|
+
|
|
1582
|
+
|
|
1583
|
+
def use_only_if_non_zero(self):
|
|
1584
|
+
"""
|
|
1585
|
+
Returns the field property 'if-non-zero' stating if this field could be
|
|
1586
|
+
used only when its value does not equal 0.
|
|
1587
|
+
|
|
1588
|
+
Returns
|
|
1589
|
+
-------
|
|
1590
|
+
bool
|
|
1591
|
+
True if requires non-zero value, False otherwise.
|
|
1592
|
+
"""
|
|
1593
|
+
return self.entry.requires_nonzero_value
|
|
1594
|
+
|
|
1595
|
+
def __str__(self):
|
|
1596
|
+
name = self.name()
|
|
1597
|
+
offset = self.offset()
|
|
1598
|
+
type = self.type()
|
|
1599
|
+
non_zero = self.use_only_if_non_zero()
|
|
1600
|
+
return f"{name} (offset={offset}, type={type}, use_only_if_non_zero={non_zero})"
|
|
1601
|
+
|
|
1602
|
+
def __getitem__(self, key):
|
|
1603
|
+
""" tracefield[key]
|
|
1604
|
+
|
|
1605
|
+
Returns values of traces provided in 'key'.
|
|
1606
|
+
Wrapper around :class:`.Attributes`, so refer to it for more
|
|
1607
|
+
information.
|
|
1608
|
+
|
|
1609
|
+
Parameters
|
|
1610
|
+
----------
|
|
1611
|
+
key : int or slice
|
|
1612
|
+
Index or slice.
|
|
1613
|
+
|
|
1614
|
+
Returns
|
|
1615
|
+
-------
|
|
1616
|
+
array of int, float or bytearray
|
|
1617
|
+
|
|
1618
|
+
Examples
|
|
1619
|
+
--------
|
|
1620
|
+
Get the cdp_x attribute from trace header extension 1 for first 10 traces:
|
|
1621
|
+
|
|
1622
|
+
>>> f.tracefield.SEG00001.cdp_x[0:10]
|
|
1623
|
+
"""
|
|
1624
|
+
return Attributes(self.segyfile, self.entry.byte, self.traceheader_index)[key]
|