[segyio] 78/376: Trace.raw mode for eager reading of traces
Jørgen Kvalsvik
jokva-guest at moszumanska.debian.org
Wed Sep 20 08:04:10 UTC 2017
This is an automated email from the git hooks/post-receive script.
jokva-guest pushed a commit to branch debian
in repository segyio.
commit d2315e3c7f643eb500a60653f425ce756f605b6c
Author: Jørgen Kvalsvik <jokva at statoil.com>
Date: Thu Oct 27 12:14:47 2016 +0200
Trace.raw mode for eager reading of traces
Adds support for the raw trace sub mode that does eager reading of
traces into an MxN numpy array - a useful feature for segyview and other
visualisation tools when it is known beforehand that the file will fit
in memory.
---
python/segyio/CMakeLists.txt | 1 +
python/segyio/_raw_trace.py | 19 +++++++++++++++++++
python/segyio/_segyio.c | 44 +++++++++++++++++++++++++++++++++++++++-----
python/segyio/_trace.py | 14 ++++++++------
python/segyio/segy.py | 15 +++++++++++++++
tests/test_segy.py | 22 ++++++++++++++++++++++
tests/test_segyio_c.py | 4 ++--
7 files changed, 106 insertions(+), 13 deletions(-)
diff --git a/python/segyio/CMakeLists.txt b/python/segyio/CMakeLists.txt
index 03cdafd..a75737f 100644
--- a/python/segyio/CMakeLists.txt
+++ b/python/segyio/CMakeLists.txt
@@ -4,6 +4,7 @@ set(PYTHON_SOURCES
_line.py
_field.py
_trace.py
+ _raw_trace.py
segy.py
tracefield.py
binfield.py
diff --git a/python/segyio/_raw_trace.py b/python/segyio/_raw_trace.py
new file mode 100644
index 0000000..b93503c
--- /dev/null
+++ b/python/segyio/_raw_trace.py
@@ -0,0 +1,19 @@
+import numpy as np
+import segyio
+
+class RawTrace(object):
+ def __init__(self, trace):
+ self.trace = trace
+
+ def __getitem__(self, index):
+ """ :rtype: numpy.ndarray """
+ buf = None
+ if isinstance(index, slice):
+ f = self.trace._file
+ start, stop, step = index.indices(f.tracecount)
+ mstart, mstop = min(start, stop), max(start, stop)
+ length = max(0, (mstop - mstart + (step - (1 if step > 0 else -1))))
+ buf = np.zeros(shape = (length, f.samples), dtype = np.single)
+
+ return self.trace._readtr(index, buf)
+
diff --git a/python/segyio/_segyio.c b/python/segyio/_segyio.c
index 9a0834f..e787b1f 100644
--- a/python/segyio/_segyio.c
+++ b/python/segyio/_segyio.c
@@ -705,19 +705,30 @@ static PyObject *py_fread_trace0(PyObject *self, PyObject *args) {
static PyObject *py_read_trace(PyObject *self, PyObject *args) {
errno = 0;
PyObject *file_capsule = NULL;
- unsigned int trace_no;
+ PyObject *trace_no;
PyObject *buffer_out;
+ int trace_count;
long trace0;
unsigned int trace_bsize;
int format;
unsigned int samples;
- PyArg_ParseTuple(args, "OIOlIiI", &file_capsule, &trace_no, &buffer_out, &trace0, &trace_bsize, &format, &samples);
+ PyArg_ParseTuple(args, "OOiOlIiI", &file_capsule, &trace_no, &trace_count, &buffer_out, &trace0, &trace_bsize, &format, &samples);
FILE *p_FILE = get_FILE_pointer_from_capsule(file_capsule);
if (PyErr_Occurred()) { return NULL; }
+ if( !trace_no || trace_no == Py_None ) {
+ PyErr_SetString(PyExc_TypeError, "Trace number must be int or slice." );
+ return NULL;
+ }
+
+ if( !PyInt_Check( trace_no ) && !PySlice_Check( trace_no ) ) {
+ PyErr_SetString(PyExc_TypeError, "Trace number must be int or slice." );
+ return NULL;
+ }
+
if (!PyObject_CheckBuffer(buffer_out)) {
PyErr_SetString(PyExc_TypeError, "The destination buffer is not of the correct type.");
return NULL;
@@ -725,13 +736,36 @@ static PyObject *py_read_trace(PyObject *self, PyObject *args) {
Py_buffer buffer;
PyObject_GetBuffer(buffer_out, &buffer, PyBUF_FORMAT | PyBUF_C_CONTIGUOUS | PyBUF_WRITEABLE);
- int error = segy_readtrace(p_FILE, trace_no, buffer.buf, trace0, trace_bsize);
+ Py_ssize_t start, stop, step, length;
+ if( PySlice_Check( trace_no ) ) {
+ int err = PySlice_GetIndicesEx( (PySliceObject*)trace_no,
+ trace_count,
+ &start, &stop, &step,
+ &length );
+ if( err != 0 ) return NULL;
+
+ }
+ else {
+ start = PyInt_AsSsize_t( trace_no );
+ if( start < 0 ) start += trace_count;
+ step = 1;
+ stop = start + step;
+ length = 1;
+ }
+
+ int error = 0;
+ char* buf = buffer.buf;
+ Py_ssize_t i;
+
+ for( i = 0; error == 0 && i < length; ++i, buf += trace_bsize ) {
+ error = segy_readtrace(p_FILE, start + (i * step), (float*)buf, trace0, trace_bsize);
+ }
if (error != 0) {
- return py_handle_segy_error_with_index_and_name(error, errno, trace_no, "Trace");
+ return py_handle_segy_error_with_index_and_name(error, errno, start + (i * step), "Trace");
}
- error = segy_to_native(format, samples, buffer.buf);
+ error = segy_to_native(format, length * samples, buffer.buf);
if (error != 0) {
PyErr_SetString(PyExc_TypeError, "Unable to convert buffer to native format.");
diff --git a/python/segyio/_trace.py b/python/segyio/_trace.py
index 063fb68..a4a35a2 100644
--- a/python/segyio/_trace.py
+++ b/python/segyio/_trace.py
@@ -1,5 +1,6 @@
import numpy as np
import segyio
+from segyio._raw_trace import RawTrace
class Trace:
@@ -70,22 +71,18 @@ class Trace:
raise TypeError("Buffer must be None or numpy.ndarray")
elif buf.dtype != np.single:
buf = np.empty(shape=samples, dtype=np.single)
- elif buf.shape != samples:
- buf.reshape(samples)
return buf
def _readtr(self, traceno, buf=None):
- if traceno < 0:
- traceno += self._file.tracecount
-
buf = self._trace_buffer(buf)
+ tracecount = self._file.tracecount
trace0 = self._file._tr0
bsz = self._file._bsz
fmt = self._file._fmt
samples = self._file.samples
- return segyio._segyio.read_trace(self._file.xfd, traceno, buf, trace0, bsz, fmt, samples)
+ return segyio._segyio.read_trace(self._file.xfd, traceno, tracecount, buf, trace0, bsz, fmt, samples)
def _writetr(self, traceno, buf):
self.write_trace(traceno, buf, self._file)
@@ -99,3 +96,8 @@ class Trace:
"""
segyio._segyio.write_trace(segy.xfd, traceno, buf, segy._tr0, segy._bsz, segy._fmt, segy.samples)
+
+ @property
+ def raw(self):
+ """ :rtype: segyio.RawTrace """
+ return RawTrace(self)
diff --git a/python/segyio/segy.py b/python/segyio/segy.py
index d732147..a16ea63 100644
--- a/python/segyio/segy.py
+++ b/python/segyio/segy.py
@@ -302,6 +302,21 @@ class SegyFile(object):
Fill the file with one trace (filled with zeros)::
>>> tr = np.zeros(f.samples)
>>> f.trace = itertools.repeat(tr)
+
+ For advanced users: sometimes you want to load the entire segy file
+ to memory and apply your own structural manipulations or operations
+ on it. Some segy files are very large and may not fit, in which
+ case this feature will break down. This is an optimisation feature;
+ using it should generally be driven by measurements.
+
+ Read the first 10 traces::
+ >>> f.trace.raw[0:10]
+
+ Read *all* traces to memory::
+ >>> f.trace.raw[:]
+
+ Read every other trace to memory::
+ >>> f.trace.raw[::2]
"""
return Trace(self)
diff --git a/tests/test_segy.py b/tests/test_segy.py
index 636cbb5..cd8a5c1 100644
--- a/tests/test_segy.py
+++ b/tests/test_segy.py
@@ -187,6 +187,28 @@ class TestSegy(TestCase):
for line in f.xline:
pass
+ def test_traces_raw(self):
+ with segyio.open(self.filename, "r") as f:
+ gen_traces = np.array(map( np.copy, f.trace ), dtype = np.single)
+
+ raw_traces = f.trace.raw[:]
+ self.assertTrue(np.array_equal(gen_traces, raw_traces))
+
+ self.assertEqual(len(gen_traces), f.tracecount)
+ self.assertEqual(len(raw_traces), f.tracecount)
+
+ self.assertEqual(gen_traces[0][49], raw_traces[0][49])
+ self.assertEqual(gen_traces[1][49], f.trace.raw[1][49])
+ self.assertEqual(gen_traces[2][49], raw_traces[2][49])
+
+ self.assertTrue(np.array_equal(f.trace[10], f.trace.raw[10]))
+
+ for raw, gen in itertools.izip(f.trace.raw[::2], f.trace[::2]):
+ self.assertTrue(np.array_equal(raw, gen))
+
+ for raw, gen in itertools.izip(f.trace.raw[::-1], f.trace[::-1]):
+ self.assertTrue(np.array_equal(raw, gen))
+
def test_read_header(self):
with segyio.open(self.filename, "r") as f:
self.assertEqual(1, f.header[0][189])
diff --git a/tests/test_segyio_c.py b/tests/test_segyio_c.py
index f71aa23..7bf006d 100644
--- a/tests/test_segyio_c.py
+++ b/tests/test_segyio_c.py
@@ -379,12 +379,12 @@ class _segyioTests(TestCase):
buf = numpy.zeros(25, dtype=numpy.single)
- _segyio.read_trace(f, 0, buf, 0, 100, 1, 25)
+ _segyio.read_trace(f, 0, 25, buf, 0, 100, 1, 25)
self.assertAlmostEqual(buf[10], 1.0, places=4)
self.assertAlmostEqual(buf[11], 3.1415, places=4)
- _segyio.read_trace(f, 1, buf, 0, 100, 1, 25)
+ _segyio.read_trace(f, 1, 25, buf, 0, 100, 1, 25)
self.assertAlmostEqual(sum(buf), 42.0 * 25, places=4)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/segyio.git
More information about the debian-science-commits
mailing list