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 ADDED
@@ -0,0 +1,101 @@
1
+ """segyio
2
+
3
+ Welcome to segyio. For help, examples and reference, type ``help(function)`` in
4
+ your favourite python interpreter, or ``pydoc function`` in the unix console.
5
+
6
+ The segyio library attempts to be easy to use efficently for prototyping and
7
+ interaction with possibly large segy files. File reading and writing is
8
+ streaming, with large file support out of the box and without hassle. For a
9
+ quick start on reading files, type ``help(segyio.open)``.
10
+
11
+ An open segy file is interacted with in modes. For a reference with examples,
12
+ please type ``help(segyio.segy)``, look at the online documentation at
13
+ segyio.readthedocs.io, or run ``help()`` on the object returned by
14
+ ``segyio.open``.. For documentation on individual modes, please
15
+ refer to the individual modes with ``help(f.[mode])``, where ``f`` is an open
16
+ file handle.
17
+
18
+ The available modes are:
19
+ * text, for textual headers including extended headers
20
+ * bin, for the binary header
21
+ * header, for the trace headers
22
+ * trace, for trace data
23
+ * iline, for inline biased operations
24
+ * xline, for crossline biased operations
25
+ * depth_slice, for depth biased operations
26
+ * gather, for gather/intersaction biased operations
27
+
28
+ The primary data type is the numpy.ndarray. All examples use ``np`` for the
29
+ numpy namespace. That means that any function that returns a trace, a set of
30
+ samples or even full lines, returns a numpy.ndarray. This enables quick and
31
+ easy mathematical operations on the data you care about.
32
+
33
+ Segyio is designed to blend into regular python code, so python concepts that
34
+ map to segy operations are written to behave similarly. That means that
35
+ sequences of data support list lookup, slicing (``f.trace[0:10:2]``), ``for x
36
+ in`` etc. Please refer to the individual modes' documentation for a more
37
+ extensive set of examples.
38
+
39
+ For all slicing operations that segyio provides the underlying buffer is
40
+ reused, so if you want to keep the data between iterations it is necessary to
41
+ manually copy the data, e.g. ``numpy.copy()``. Please refer to the examples.
42
+ """
43
+
44
+
45
+ class Enum(object):
46
+ def __init__(self, enum_value):
47
+ super(Enum, self).__init__()
48
+ self._value = int(enum_value)
49
+
50
+ def __int__(self):
51
+ return int(self._value)
52
+
53
+ def __str__(self):
54
+ for k, v in self.__class__.__dict__.items():
55
+ if isinstance(v, int) and self._value == v:
56
+ return k
57
+ return "Unknown Enum"
58
+
59
+ def __repr__(self):
60
+ return str(self)
61
+
62
+ def __hash__(self):
63
+ return hash(self._value)
64
+
65
+ def __eq__(self, other):
66
+ if other is None:
67
+ return False
68
+ try:
69
+ o = int(other)
70
+ except ValueError:
71
+ return super(Enum, self).__eq__(other)
72
+ else:
73
+ return self._value == o
74
+
75
+ def __ne__(self, other):
76
+ return not self == other
77
+
78
+ @classmethod
79
+ def enums(cls):
80
+ result = []
81
+ for k, v in cls.__dict__.items():
82
+ if isinstance(v, int) and not str.startswith(k, "_"):
83
+ result.append(cls(v))
84
+
85
+ return sorted(result, key=int)
86
+
87
+
88
+ from .binfield import BinField
89
+ from .segysampleformat import SegySampleFormat
90
+ from .tracesortingformat import TraceSortingFormat
91
+ from .tracefield import TraceField
92
+ from . import su
93
+ from .open import open, open_with, open_from_memory
94
+ from .create import create, create_with
95
+ from .segy import SegyFile, spec
96
+ from .tools import dt, sample_indexes, create_text_header, native
97
+ from .tools import collect, cube
98
+
99
+ __copyright__ = 'Copyright 2016, Statoil ASA'
100
+ __license__ = 'GNU Lesser General Public License version 3'
101
+ __status__ = 'Production'
Binary file
Binary file
Binary file
segyio/binfield.py ADDED
@@ -0,0 +1,153 @@
1
+ import warnings
2
+ from . import Enum
3
+
4
+ class TracesWrapper:
5
+ def __get__(self, instance, owner):
6
+ warnings.warn(
7
+ "Traces is deprecated and will be removed in a future version."
8
+ "Please use EnsembleTraces instead.",
9
+ DeprecationWarning,
10
+ stacklevel=2
11
+ )
12
+ return 3213
13
+
14
+ class AuxTracesWrapper:
15
+ def __get__(self, instance, owner):
16
+ warnings.warn(
17
+ "AuxTraces is deprecated and will be removed in a future version."
18
+ "Please use AuxEnsembleTraces instead.",
19
+ DeprecationWarning,
20
+ stacklevel=2
21
+ )
22
+ return 3215
23
+
24
+ class ExtTracesWrapper:
25
+ def __get__(self, instance, owner):
26
+ warnings.warn(
27
+ "ExtTraces is deprecated and will be removed in a future version."
28
+ "Please use ExtEnsembleTraces instead.",
29
+ DeprecationWarning,
30
+ stacklevel=2
31
+ )
32
+ return 3261
33
+
34
+ class ExtAuxTracesWrapper:
35
+ def __get__(self, instance, owner):
36
+ warnings.warn(
37
+ "ExtAuxTraces is deprecated and will be removed in a future version."
38
+ "Please use ExtAuxEnsembleTraces instead.",
39
+ DeprecationWarning,
40
+ stacklevel=2
41
+ )
42
+ return 3265
43
+
44
+
45
+ class BinField(Enum):
46
+ """Trace header field enumerator
47
+
48
+ See also
49
+ -------
50
+ segyio.su : Seismic unix aliases for header fields
51
+ """
52
+
53
+ JobID = 3201
54
+ LineNumber = 3205
55
+ ReelNumber = 3209
56
+ Traces = TracesWrapper() # Deprecated, use EnsembleTraces
57
+ EnsembleTraces = 3213
58
+ AuxTraces = AuxTracesWrapper() # Deprecated, use AuxEnsembleTraces
59
+ AuxEnsembleTraces = 3215
60
+ Interval = 3217
61
+ IntervalOriginal = 3219
62
+ Samples = 3221
63
+ SamplesOriginal = 3223
64
+ Format = 3225
65
+ EnsembleFold = 3227
66
+ SortingCode = 3229
67
+ VerticalSum = 3231
68
+ SweepFrequencyStart = 3233
69
+ SweepFrequencyEnd = 3235
70
+ SweepLength = 3237
71
+ Sweep = 3239
72
+ SweepChannel = 3241
73
+ SweepTaperStart = 3243
74
+ SweepTaperEnd = 3245
75
+ Taper = 3247
76
+ CorrelatedTraces = 3249
77
+ BinaryGainRecovery = 3251
78
+ AmplitudeRecovery = 3253
79
+ MeasurementSystem = 3255
80
+ ImpulseSignalPolarity = 3257
81
+ VibratoryPolarity = 3259
82
+ ExtTraces = ExtTracesWrapper() # Deprecated, use ExtEnsembleTraces
83
+ ExtEnsembleTraces = 3261
84
+ ExtAuxTraces = ExtAuxTracesWrapper() # Deprecated, use ExtAuxEnsembleTraces
85
+ ExtAuxEnsembleTraces = 3265
86
+ ExtSamples = 3269
87
+ ExtInterval = 3273
88
+ ExtIntervalOriginal = 3281
89
+ ExtSamplesOriginal = 3289
90
+ ExtEnsembleFold = 3293
91
+ IntConstant = 3297
92
+ Unassigned1 = 3301
93
+ SEGYRevision = 3501
94
+ SEGYRevisionMinor = 3502
95
+ TraceFlag = 3503
96
+ ExtendedHeaders = 3505
97
+ MaxAdditionalTraceHeaders = 3507
98
+ SurveyType = 3509
99
+ TimeBasisCode = 3511
100
+ NrTracesInStream = 3513
101
+ FirstTraceOffset = 3521
102
+ NrTrailerRecords = 3529
103
+ Unassigned2 = 3533
104
+
105
+ keys = {
106
+ 'JobID' : 3201,
107
+ 'LineNumber' : 3205,
108
+ 'ReelNumber' : 3209,
109
+ 'EnsembleTraces' : 3213,
110
+ 'AuxEnsembleTraces' : 3215,
111
+ 'Interval' : 3217,
112
+ 'IntervalOriginal' : 3219,
113
+ 'Samples' : 3221,
114
+ 'SamplesOriginal' : 3223,
115
+ 'Format' : 3225,
116
+ 'EnsembleFold' : 3227,
117
+ 'SortingCode' : 3229,
118
+ 'VerticalSum' : 3231,
119
+ 'SweepFrequencyStart' : 3233,
120
+ 'SweepFrequencyEnd' : 3235,
121
+ 'SweepLength' : 3237,
122
+ 'Sweep' : 3239,
123
+ 'SweepChannel' : 3241,
124
+ 'SweepTaperStart' : 3243,
125
+ 'SweepTaperEnd' : 3245,
126
+ 'Taper' : 3247,
127
+ 'CorrelatedTraces' : 3249,
128
+ 'BinaryGainRecovery' : 3251,
129
+ 'AmplitudeRecovery' : 3253,
130
+ 'MeasurementSystem' : 3255,
131
+ 'ImpulseSignalPolarity' : 3257,
132
+ 'VibratoryPolarity' : 3259,
133
+ 'ExtEnsembleTraces' : 3261,
134
+ 'ExtAuxEnsembleTraces' : 3265,
135
+ 'ExtSamples' : 3269,
136
+ 'ExtInterval' : 3273,
137
+ 'ExtIntervalOriginal' : 3281,
138
+ 'ExtSamplesOriginal' : 3289,
139
+ 'ExtEnsembleFold' : 3293,
140
+ 'IntConstant' : 3297,
141
+ 'Unassigned1' : 3301,
142
+ 'SEGYRevision' : 3501,
143
+ 'SEGYRevisionMinor' : 3502,
144
+ 'TraceFlag' : 3503,
145
+ 'ExtendedHeaders' : 3505,
146
+ 'MaxAdditionalTraceHeaders' : 3507,
147
+ 'SurveyType' : 3509,
148
+ 'TimeBasisCode' : 3511,
149
+ 'NrTracesInStream' : 3513,
150
+ 'FirstTraceOffset' : 3521,
151
+ 'NrTrailerRecords' : 3529,
152
+ 'Unassigned2' : 3533,
153
+ }
segyio/create.py ADDED
@@ -0,0 +1,314 @@
1
+ import datetime
2
+ import numpy
3
+ import segyio
4
+
5
+ from . import TraceSortingFormat
6
+ from .utils import (
7
+ FileDatasourceDescriptor,
8
+ StreamDatasourceDescriptor,
9
+ to_c_endianness,
10
+ to_c_encoding
11
+ )
12
+
13
+ def default_text_header(iline, xline, offset):
14
+ lines = {
15
+ 1: "DATE %s" % datetime.date.today().isoformat(),
16
+ 2: "AN INCREASE IN AMPLITUDE EQUALS AN INCREASE IN ACOUSTIC IMPEDANCE",
17
+ 3: "Written by libsegyio (python)",
18
+ 11: "TRACE HEADER POSITION:",
19
+ 12: " INLINE BYTES %03d-%03d | OFFSET BYTES %03d-%03d" % (iline, iline + 4, int(offset), int(offset) + 4),
20
+ 13: " CROSSLINE BYTES %03d-%03d |" % (xline, xline + 4),
21
+ 15: "END EBCDIC HEADER",
22
+ }
23
+ rows = segyio.create_text_header(lines)
24
+ rows = bytearray(rows, 'ascii') # mutable array of bytes
25
+ rows[-1] = 128 # \x80 -- Unsure if this is really required...
26
+ return bytes(rows) # immutable array of bytes that is compatible with strings
27
+
28
+
29
+ def structured(spec):
30
+ if not hasattr(spec, 'ilines' ): return False
31
+ if not hasattr(spec, 'xlines' ): return False
32
+ if not hasattr(spec, 'offsets'): return False
33
+
34
+ if spec.ilines is None: return False
35
+ if spec.xlines is None: return False
36
+ if spec.offsets is None: return False
37
+
38
+ if not list(spec.ilines): return False
39
+ if not list(spec.xlines): return False
40
+ if not list(spec.offsets): return False
41
+
42
+ return True
43
+
44
+ def create(filename, spec, layout_xml = None):
45
+ """Create a new segy file.
46
+
47
+ Create a new segy file with the geometry and properties given by `spec`.
48
+ This enables creating SEGY files from your data. The created file supports
49
+ all segyio modes, but has an emphasis on writing. The spec must be
50
+ complete, otherwise an exception will be raised. A default, empty spec can
51
+ be created with ``segyio.spec()``.
52
+
53
+ Very little data is written to the file, so just calling create is not
54
+ sufficient to re-read the file with segyio. Rather, every trace header and
55
+ trace must be written to the file to be considered complete.
56
+
57
+ Create should be used together with python's ``with`` statement. This ensure
58
+ the data is written. Please refer to the examples.
59
+
60
+ The ``segyio.spec()`` function will default sorting, offsets and everything
61
+ in the mandatory group, except format and samples, and requires the caller
62
+ to fill in *all* the fields in either of the exclusive groups.
63
+
64
+ If any field is missing from the first exclusive group, and the tracecount
65
+ is set, the resulting file will be considered unstructured. If the
66
+ tracecount is set, and all fields of the first exclusive group are
67
+ specified, the file is considered structured and the tracecount is inferred
68
+ from the xlines/ilines/offsets. The offsets are defaulted to ``[1]`` by
69
+ ``segyio.spec()``.
70
+
71
+ Parameters
72
+ ----------
73
+ filename : str
74
+ Path to file to create
75
+ spec : segyio.spec
76
+ Structure of the segy file
77
+ layout_xml: bytearray
78
+ SEG-Y revision 2.1 D8 xml layout. Note that this layout is used only
79
+ during file creation and is not stored in the file.
80
+
81
+ Returns
82
+ -------
83
+ file : segyio.SegyFile
84
+ An open segyio file handle, similar to that returned by `segyio.open`
85
+
86
+ See also
87
+ --------
88
+ segyio.spec : template for the `spec` argument
89
+
90
+
91
+ Notes
92
+ -----
93
+
94
+ .. versionadded:: 1.1
95
+
96
+ .. versionchanged:: 1.4
97
+ Support for creating unstructured files
98
+
99
+ .. versionchanged:: 1.8
100
+ Support for creating lsb files
101
+
102
+ .. versionchanged:: 2.0
103
+ Support for SEG-Y revision 2.1
104
+
105
+ The ``spec`` is any object that has the following attributes
106
+
107
+ Mandatory::
108
+
109
+ iline : int or segyio.BinField
110
+ xline : int or segyio.BinField
111
+ samples : array of int
112
+ format : { 1, 5 }
113
+ 1 = IBM float, 5 = IEEE float
114
+
115
+ Exclusive::
116
+
117
+ ilines : array_like of int
118
+ xlines : array_like of int
119
+ offsets : array_like of int
120
+ sorting : int or segyio.TraceSortingFormat
121
+
122
+ OR
123
+
124
+ tracecount : int
125
+
126
+ Optional::
127
+
128
+ ext_headers : int
129
+ endian : str { 'big', 'msb', 'little', 'lsb' }
130
+ defaults to 'big'
131
+ encoding : {'ebcdic', 'ascii'}
132
+ defaults to 'ebcdic'.
133
+
134
+
135
+ Examples
136
+ --------
137
+
138
+ Create a file:
139
+
140
+ >>> spec = segyio.spec()
141
+ >>> spec.ilines = [1, 2, 3, 4]
142
+ >>> spec.xlines = [11, 12, 13]
143
+ >>> spec.samples = list(range(50))
144
+ >>> spec.sorting = 2
145
+ >>> spec.format = 1
146
+ >>> with segyio.create(path, spec) as f:
147
+ ... ## fill the file with data
148
+ ... pass
149
+ ...
150
+
151
+ Copy a file, but shorten all traces by 50 samples:
152
+
153
+ >>> with segyio.open(srcpath) as src:
154
+ ... spec = segyio.spec()
155
+ ... spec.sorting = src.sorting
156
+ ... spec.format = src.format
157
+ ... spec.samples = src.samples[:len(src.samples) - 50]
158
+ ... spec.ilines = src.ilines
159
+ ... spec.xline = src.xlines
160
+ ... with segyio.create(dstpath, spec) as dst:
161
+ ... dst.text[0] = src.text[0]
162
+ ... dst.bin = src.bin
163
+ ... # this is writing a sparse file, which might be slow on some
164
+ ... # systems
165
+ ... dst.header = src.header
166
+ ... dst.trace = src.trace
167
+
168
+ Copy a file, but shift samples time by 50:
169
+
170
+ >>> with segyio.open(srcpath) as src:
171
+ ... delrt = 50
172
+ ... spec = segyio.spec()
173
+ ... spec.samples = src.samples + delrt
174
+ ... spec.ilines = src.ilines
175
+ ... spec.xline = src.xlines
176
+ ... with segyio.create(dstpath, spec) as dst:
177
+ ... dst.text[0] = src.text[0]
178
+ ... dst.bin = src.bin
179
+ ... dst.header = src.header
180
+ ... dst.header = { TraceField.DelayRecordingTime: delrt }
181
+ ... dst.trace = src.trace
182
+
183
+ Copy a file, but shorten all traces by 50 samples (since v1.4):
184
+
185
+ >>> with segyio.open(srcpath) as src:
186
+ ... spec = segyio.tools.metadata(src)
187
+ ... spec.samples = spec.samples[:len(spec.samples) - 50]
188
+ ... with segyio.create(dstpath, spec) as dst:
189
+ ... dst.text[0] = src.text[0]
190
+ ... dst.bin = src.bin
191
+ ... dst.header = src.header
192
+ ... dst.trace = src.trace
193
+ """
194
+ return _create(FileDatasourceDescriptor(filename, "w+"), spec, layout_xml)
195
+
196
+
197
+ def create_with(stream, spec, minimize_requests_number=True, layout_xml = None):
198
+ """
199
+ Creates a segy file on stream.
200
+
201
+ Function behaves the same as `segyio.create`, but outputs data to a
202
+ finite stream instead of a file. Stream's close() will be called when
203
+ SegyFile is closed.
204
+
205
+ Note that `segyio.create_with` can be very slow. `segyio.create` is
206
+ generally a preferred option when speed matters.
207
+
208
+ Parameters
209
+ ----------
210
+
211
+ stream : file-like object
212
+ Data destination. It is up to the user to assure stream is opened in w+b mode.
213
+ spec : segyio.spec
214
+ Structure of the segy file
215
+ minimize_requests_number : bool
216
+ Configuration for some internal algorithms. True to minimize number of
217
+ requests to the stream at the cost of higher memory usage. False to
218
+ minimize memory usage at the cost of more requests to the stream.
219
+ layout_xml: bytearray
220
+ SEG-Y revision 2.1 D8 xml layout. Note that this layout is used only
221
+ during file creation and is not stored in the file.
222
+ """
223
+ return _create(
224
+ StreamDatasourceDescriptor(
225
+ stream,
226
+ minimize_requests_number
227
+ ),
228
+ spec,
229
+ layout_xml
230
+ )
231
+
232
+
233
+ def _create(datasource_descriptor, spec, layout_xml):
234
+ if not structured(spec):
235
+ tracecount = spec.tracecount
236
+ else:
237
+ tracecount = len(spec.ilines) * len(spec.xlines) * len(spec.offsets)
238
+
239
+ ext_headers = spec.ext_headers if hasattr(spec, 'ext_headers') else 0
240
+ samples = numpy.asarray(spec.samples)
241
+
242
+ traceheader_count = spec.traceheader_count if hasattr(spec, 'traceheader_count') else 1
243
+
244
+ endian = spec.endian if hasattr(spec, 'endian') else 'big'
245
+ if endian is None:
246
+ endian = 'big'
247
+
248
+ encoding = spec.encoding if hasattr(spec, 'encoding') else 'ebcdic'
249
+ if encoding is None:
250
+ encoding = 'ebcdic'
251
+
252
+ fd = datasource_descriptor.make_segyfile_descriptor()
253
+ fd.segymake(
254
+ samples = len(samples),
255
+ tracecount = tracecount,
256
+ endianness=to_c_endianness(endian),
257
+ encoding=to_c_encoding(encoding),
258
+ format = int(spec.format),
259
+ ext_headers = int(ext_headers),
260
+ traceheader_count = traceheader_count,
261
+ layout_xml = layout_xml
262
+ )
263
+
264
+ # note: even if iline/xline are overridden, file is already created with
265
+ # standard iline/xline position, so those can mismatch
266
+
267
+ f = segyio.SegyFile(fd,
268
+ datasource_descriptor,
269
+ endian = endian,
270
+ )
271
+
272
+ f._samples = samples
273
+
274
+ if structured(spec):
275
+ sorting = spec.sorting if hasattr(spec, 'sorting') else None
276
+ if sorting is None:
277
+ sorting = TraceSortingFormat.INLINE_SORTING
278
+ f.interpret(spec.ilines, spec.xlines, spec.offsets, sorting)
279
+
280
+ f.text[0] = default_text_header(f._il, f._xl, segyio.TraceField.offset)
281
+
282
+ if len(samples) == 1:
283
+ interval = int(samples[0] * 1000)
284
+ else:
285
+ interval = int((samples[1] - samples[0]) * 1000)
286
+
287
+ binary_header = {}
288
+ binary_header.update(
289
+ ntrpr = 1,
290
+ hdt = interval,
291
+ dto = interval,
292
+ format = int(spec.format),
293
+ fold = 1,
294
+ tsort = 4,
295
+ exth = ext_headers,
296
+ )
297
+
298
+ if len(samples) > 2**16 - 1:
299
+ # when using the ext-samples field, also set rev2, even though it's a
300
+ # soft lie and files aren't really compliant
301
+ binary_header.update(
302
+ exthns = len(samples),
303
+ extnso = len(samples),
304
+ rev = 2
305
+ )
306
+ else:
307
+ binary_header.update(
308
+ hns = len(samples),
309
+ nso = len(samples),
310
+ )
311
+
312
+ f.bin.update(**binary_header)
313
+
314
+ return f