[segyio] 212/376: segy.attributes - file-wide header read

Jørgen Kvalsvik jokva-guest at moszumanska.debian.org
Wed Sep 20 08:04:35 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 a72e77bca0e70eb62d7003d917a343aaff1a3f70
Author: Jørgen Kvalsvik <jokva at statoil.com>
Date:   Fri Feb 24 15:45:33 2017 +0100

    segy.attributes - file-wide header read
    
    The new function segy.attribute leverages the segy_field_forall function
    to support reading some field across the full file or parts of the file.
    Uses cases include learning things about a new file, make assumptions on
    structure and plot ensembles, CDP etc.
    
    The interface is designed to quickly give control to numpy or other
    third-party libs, and the return value is always an array or a simple
    value. Supports looking up attributes for a single trace, a range (via
    slice operations [start:stop:step]) or lists of indices.
---
 python/segyio/_segyio.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++
 python/segyio/segy.py   |  53 +++++++++++++++++++++
 python/test/segy.py     |  41 ++++++++++++++++
 3 files changed, 216 insertions(+)

diff --git a/python/segyio/_segyio.c b/python/segyio/_segyio.c
index 2cc1ccc..73c904c 100644
--- a/python/segyio/_segyio.c
+++ b/python/segyio/_segyio.c
@@ -480,6 +480,126 @@ static PyObject *py_write_trace_header(PyObject *self, PyObject *args) {
     }
 }
 
+static PyObject *py_field_forall(PyObject *self, PyObject *args ) {
+    errno = 0;
+    PyObject *file_capsule = NULL;
+    PyObject *buffer_out;
+    int start, stop, step;
+    long trace0;
+    int trace_bsize;
+    int field;
+
+    PyArg_ParseTuple(args, "OOiiiili", &file_capsule,
+                                       &buffer_out,
+                                       &start,
+                                       &stop,
+                                       &step,
+                                       &field,
+                                       &trace0,
+                                       &trace_bsize );
+
+    segy_file* fp = get_FILE_pointer_from_capsule(file_capsule);
+
+    if (PyErr_Occurred()) { return NULL; }
+
+    if (!PyObject_CheckBuffer(buffer_out)) {
+        PyErr_SetString(PyExc_TypeError, "The destination buffer is not of the correct type.");
+        return NULL;
+    }
+
+    Py_buffer buffer;
+    PyObject_GetBuffer(buffer_out, &buffer, PyBUF_FORMAT | PyBUF_C_CONTIGUOUS | PyBUF_WRITEABLE);
+
+    int error = segy_field_forall( fp,
+                                   field,
+                                   start,
+                                   stop,
+                                   step,
+                                   buffer.buf,
+                                   trace0,
+                                   trace_bsize );
+
+    int errorno = errno;
+
+    PyBuffer_Release( &buffer );
+    if( error != SEGY_OK ) {
+        return py_handle_segy_error( error, errno );
+    }
+
+    Py_IncRef(buffer_out);
+    return buffer_out;
+}
+
+static PyObject *py_field_foreach(PyObject *self, PyObject *args ) {
+    errno = 0;
+    PyObject *file_capsule = NULL;
+    PyObject *buffer_out;
+    PyObject *indices;
+    int field;
+    long trace0;
+    int trace_bsize;
+
+    PyArg_ParseTuple(args, "OOOili", &file_capsule,
+                                     &buffer_out,
+                                     &indices,
+                                     &field,
+                                     &trace0,
+                                     &trace_bsize );
+
+    segy_file* fp = get_FILE_pointer_from_capsule(file_capsule);
+
+    if (PyErr_Occurred()) { return NULL; }
+
+    if (!PyObject_CheckBuffer(buffer_out)) {
+        PyErr_SetString(PyExc_TypeError, "The destination buffer is not of the correct type.");
+        return NULL;
+    }
+
+    if (!PyObject_CheckBuffer(indices)) {
+        PyErr_SetString(PyExc_TypeError, "The indices buffer is not of the correct type.");
+        return NULL;
+    }
+
+    Py_buffer bufout;
+    PyObject_GetBuffer(buffer_out, &bufout, PyBUF_FORMAT | PyBUF_C_CONTIGUOUS | PyBUF_WRITEABLE);
+
+    Py_buffer bufindices;
+    PyObject_GetBuffer(indices, &bufindices, PyBUF_FORMAT | PyBUF_C_CONTIGUOUS);
+
+    int len = bufindices.len / bufindices.itemsize;
+    if( bufout.len / bufout.itemsize != len ) {
+        PyErr_SetString(PyExc_ValueError, "Attributes array length != indices" );
+        PyBuffer_Release( &bufout );
+        PyBuffer_Release( &bufindices );
+        return NULL;
+    }
+
+    int err = 0;
+    const int* ind = bufindices.buf;
+    int* out = bufout.buf;
+    for( int i = 0; i < len; ++i ) {
+        err = segy_field_forall( fp, field,
+                                 ind[ i ],
+                                 ind[ i ] + 1,
+                                 1,
+                                 out + i,
+                                 trace0,
+                                 trace_bsize );
+
+        if( err != SEGY_OK ) {
+            PyBuffer_Release( &bufout );
+            PyBuffer_Release( &bufindices );
+            return py_handle_segy_error( err, errno );
+        }
+    }
+
+    PyBuffer_Release( &bufout );
+    PyBuffer_Release( &bufindices );
+
+    Py_IncRef(buffer_out);
+    return buffer_out;
+}
+
 static PyObject *py_trace_bsize(PyObject *self, PyObject *args) {
     errno = 0;
     int sample_count;
@@ -1031,6 +1151,8 @@ static PyMethodDef SegyMethods[] = {
         {"empty_traceheader",  (PyCFunction) py_empty_trace_header, METH_NOARGS,  "Create empty trace header for a segy file."},
         {"read_traceheader",   (PyCFunction) py_read_trace_header,  METH_VARARGS, "Read a trace header from a segy file."},
         {"write_traceheader",  (PyCFunction) py_write_trace_header, METH_VARARGS, "Write a trace header to a segy file."},
+        {"field_forall",       (PyCFunction) py_field_forall,       METH_VARARGS, "Read a single attribute from a set of headers."},
+        {"field_foreach",      (PyCFunction) py_field_foreach,      METH_VARARGS, "Read a single attribute from a set of headers, given by a list of indices."},
 
         {"trace_bsize",        (PyCFunction) py_trace_bsize,        METH_VARARGS, "Returns the number of bytes in a trace."},
         {"get_field",          (PyCFunction) py_get_field,          METH_VARARGS, "Get a header field."},
diff --git a/python/segyio/segy.py b/python/segyio/segy.py
index 5f42234..4ceebd2 100644
--- a/python/segyio/segy.py
+++ b/python/segyio/segy.py
@@ -290,6 +290,59 @@ class SegyFile(object):
         for i, v in zip(range(self.tracecount), val):
             h[i, buf] = v
 
+    def attributes(self, field):
+        """ File-wide attribute (header word) reading
+
+        A range-oriented function that reads some attribute for all the
+        specified headers file-wide. Supports index lookup, slices and
+        numpy-style list-of-indices.
+
+        Examples:
+            Read all unique sweep frequency end::
+                >>> end = segyio.TraceField.SweepFrequencyEnd
+                >>> sfe = np.unique(f.attributes( end )[:])
+
+            Discover the first traces of each unique sweep frequency end::
+                >>> end = segyio.TraceField.SweepFrequencyEnd
+                >>> attrs = f.attributes(end)
+                >>> sfe, tracenos = np.unique(attrs[:], return_index = True)
+
+            Scatter plot group x/y-coordinates with SFEs (using matplotlib)::
+                >>> end = segyio.TraceField.SweepFrequencyEnd
+                >>> attrs = f.attributes(end)
+                >>> _, tracenos = np.unique(attrs[:], return_index = True)
+                >>> gx = f.attributes(segyio.TraceField.GroupX)[tracenos]
+                >>> gy = f.attributes(segyio.TraceField.GroupY)[tracenos]
+                >>> scatter(gx, gy)
+        """
+        class attr:
+            def __getitem__(inner, rng):
+                try: iter(rng)
+                except TypeError: pass
+                else: return inner._getitem_list(rng)
+
+                if not isinstance(rng, slice):
+                    rng = slice(rng, rng + 1, 1)
+
+                traces = self.tracecount
+                start, stop, step = rng.indices(traces)
+                attrs = np.empty(len(range(*rng.indices(traces))), dtype = np.intc)
+                return _segyio.field_forall(self.xfd, attrs,
+                                            start, stop, step, field,
+                                            self._tr0, self._bsz)
+
+            def _getitem_list(inner, xs):
+                if not isinstance(xs, np.ndarray):
+                    xs = np.asarray(xs, dtype = np.intc)
+
+                xs = xs.astype(dtype = np.intc, order = 'C', copy = False)
+                attrs = np.empty(len(xs), dtype = np.intc)
+                return _segyio.field_foreach(self.xfd, attrs, xs, field,
+                                          self._tr0, self._bsz)
+
+        return attr()
+
+
     @property
     def trace(self):
         """ Interact with segy in trace mode.
diff --git a/python/test/segy.py b/python/test/segy.py
index 439caf3..88ae144 100644
--- a/python/test/segy.py
+++ b/python/test/segy.py
@@ -232,6 +232,47 @@ class TestSegy(TestCase):
                 self.assertEqual(f.header[1][xl], 13)
                 self.assertEqual(f.header[2][xl], 2)
 
+    def test_attributes(self):
+        with segyio.open(self.filename) as f:
+            il = TraceField.INLINE_3D
+            xl = TraceField.CROSSLINE_3D
+
+            self.assertEqual(1,  f.attributes(il)[0])
+            self.assertEqual(20, f.attributes(xl)[0])
+
+            ils = [(i // 5) + 1 for i in range(25)]
+            attrils = list(map(int, f.attributes(il)[:]))
+            self.assertListEqual(ils, attrils)
+
+            xls = [(i % 5) + 20 for i in range(25)]
+            attrxls = list(map(int, f.attributes(xl)[:]))
+            self.assertListEqual(xls, attrxls)
+
+            ils = [(i // 5) + 1 for i in range(25)][::-1]
+            attrils = list(map(int, f.attributes(il)[::-1]))
+            self.assertListEqual(ils, attrils)
+
+            xls = [(i % 5) + 20 for i in range(25)][::-1]
+            attrxls = list(map(int, f.attributes(xl)[::-1]))
+            self.assertListEqual(xls, attrxls)
+
+            ils = [(i // 5) + 1 for i in range(25)][1:21:3]
+            attrils = list(map(int, f.attributes(il)[1:21:3]))
+            self.assertListEqual(ils, attrils)
+
+            xls = [(i % 5) + 20 for i in range(25)][2:17:5]
+            attrxls = list(map(int, f.attributes(xl)[2:17:5]))
+            self.assertListEqual(xls, attrxls)
+
+            ils = [1, 2, 3, 4, 5]
+            attrils = list(map(int, f.attributes(il)[[0, 5, 11, 17, 23]]))
+            self.assertListEqual(ils, attrils)
+
+            ils = [1, 2, 3, 4, 5]
+            indices = np.asarray([0, 5, 11, 17, 23])
+            attrils = list(map(int, f.attributes(il)[indices]))
+            self.assertListEqual(ils, attrils)
+
     def test_iline_offset(self):
         with segyio.open(self.prestack, "r") as f:
 

-- 
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