[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