[segyio] 231/376: Do not throw on files without good geometry
Jørgen Kvalsvik
jokva-guest at moszumanska.debian.org
Wed Sep 20 08:04:38 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 fe01eb0b30109ae5f54b6b9d3f0bf6064461cb33
Author: jokva <jokva at statoil.com>
Date: Thu Mar 9 17:53:25 2017 +0100
Do not throw on files without good geometry
Support opening files without a reasonable geometry, or that are in some
other way unsorted. Opens up a use case where segyio is used to read
files not yet stacked, organised by lines, but still has useful
properties or interesting data.
The default behaviour is to assume a file is sorted, and raise an
exception if this cannot be figured out.
---
python/segyio/_segyio.c | 61 ++++++++++++++++++++++++++++++++--------------
python/segyio/open.py | 65 ++++++++++++++++++++++++++++++++++++-------------
python/segyio/segy.py | 32 +++++++++++++++++++++---
python/test/segy.py | 31 ++++++++++++++++++++++-
python/test/segyio_c.py | 49 +++++++++++++++++++++++++++----------
5 files changed, 185 insertions(+), 53 deletions(-)
diff --git a/python/segyio/_segyio.c b/python/segyio/_segyio.c
index fbec53a..53d3952 100644
--- a/python/segyio/_segyio.c
+++ b/python/segyio/_segyio.c
@@ -665,10 +665,8 @@ static PyObject *py_init_metrics(PyObject *self, PyObject *args) {
errno = 0;
PyObject *file_capsule = NULL;
PyObject *binary_header_capsule = NULL;
- int il_field;
- int xl_field;
- PyArg_ParseTuple(args, "OOii", &file_capsule, &binary_header_capsule, &il_field, &xl_field);
+ PyArg_ParseTuple(args, "OO", &file_capsule, &binary_header_capsule);
segy_file *p_FILE = get_FILE_pointer_from_capsule(file_capsule);
@@ -683,18 +681,49 @@ static PyObject *py_init_metrics(PyObject *self, PyObject *args) {
int format = segy_format(binary_header);
int trace_bsize = segy_trace_bsize(sample_count);
- int sorting;
- int error = segy_sorting(p_FILE, il_field, xl_field, &sorting, trace0, trace_bsize);
+ int trace_count;
+ int error = segy_traces(p_FILE, &trace_count, trace0, trace_bsize);
if (error != 0) {
- return py_handle_segy_error_with_fields(error, errno, il_field, xl_field, 2);
+ return py_handle_segy_error(error, errno);
}
+ PyObject *dict = PyDict_New();
+ PyDict_SetItemString(dict, "trace0", Py_BuildValue("l", trace0));
+ PyDict_SetItemString(dict, "sample_count", Py_BuildValue("i", sample_count));
+ PyDict_SetItemString(dict, "format", Py_BuildValue("i", format));
+ PyDict_SetItemString(dict, "trace_bsize", Py_BuildValue("i", trace_bsize));
+ PyDict_SetItemString(dict, "trace_count", Py_BuildValue("i", trace_count));
+
+ return Py_BuildValue("O", dict);
+}
+
+static PyObject *py_init_cube_metrics(PyObject *self, PyObject *args) {
+ errno = 0;
+
+ PyObject *file_capsule = NULL;
+ int il_field;
+ int xl_field;
int trace_count;
- error = segy_traces(p_FILE, &trace_count, trace0, trace_bsize);
+ long trace0;
+ int trace_bsize;
+
+ PyArg_ParseTuple(args, "Oiiili", &file_capsule,
+ &il_field,
+ &xl_field,
+ &trace_count,
+ &trace0,
+ &trace_bsize);
+
+ segy_file *p_FILE = get_FILE_pointer_from_capsule(file_capsule);
+
+ if (PyErr_Occurred()) { return NULL; }
+
+ int sorting;
+ int error = segy_sorting(p_FILE, il_field, xl_field, &sorting, trace0, trace_bsize);
if (error != 0) {
- return py_handle_segy_error(error, errno);
+ return py_handle_segy_error_with_fields(error, errno, il_field, xl_field, 2);
}
int offset_count;
@@ -733,18 +762,13 @@ static PyObject *py_init_metrics(PyObject *self, PyObject *args) {
}
PyObject *dict = PyDict_New();
- PyDict_SetItemString(dict, "iline_field", Py_BuildValue("i", il_field));
- PyDict_SetItemString(dict, "xline_field", Py_BuildValue("i", xl_field));
+ PyDict_SetItemString(dict, "sorting", Py_BuildValue("i", sorting));
+ PyDict_SetItemString(dict, "iline_field", Py_BuildValue("i", il_field));
+ PyDict_SetItemString(dict, "xline_field", Py_BuildValue("i", xl_field));
PyDict_SetItemString(dict, "offset_field", Py_BuildValue("i", 37));
- PyDict_SetItemString(dict, "trace0", Py_BuildValue("l", trace0));
- PyDict_SetItemString(dict, "sample_count", Py_BuildValue("i", sample_count));
- PyDict_SetItemString(dict, "format", Py_BuildValue("i", format));
- PyDict_SetItemString(dict, "trace_bsize", Py_BuildValue("i", trace_bsize));
- PyDict_SetItemString(dict, "sorting", Py_BuildValue("i", sorting));
- PyDict_SetItemString(dict, "trace_count", Py_BuildValue("i", trace_count));
PyDict_SetItemString(dict, "offset_count", Py_BuildValue("i", offset_count));
- PyDict_SetItemString(dict, "iline_count", Py_BuildValue("i", il_count));
- PyDict_SetItemString(dict, "xline_count", Py_BuildValue("i", xl_count));
+ PyDict_SetItemString(dict, "iline_count", Py_BuildValue("i", il_count));
+ PyDict_SetItemString(dict, "xline_count", Py_BuildValue("i", xl_count));
return Py_BuildValue("O", dict);
}
@@ -1183,6 +1207,7 @@ static PyMethodDef SegyMethods[] = {
{"set_field", (PyCFunction) py_set_field, METH_VARARGS, "Set a header field."},
{"init_line_metrics", (PyCFunction) py_init_line_metrics, METH_VARARGS, "Find the length and stride of inline and crossline."},
+ {"init_cube_metrics", (PyCFunction) py_init_cube_metrics, METH_VARARGS, "Find the cube properties sorting, number of ilines, crosslines and offsets."},
{"init_metrics", (PyCFunction) py_init_metrics, METH_VARARGS, "Find most metrics for a segy file."},
{"init_indices", (PyCFunction) py_init_indices, METH_VARARGS, "Find the indices for inline, crossline and offsets."},
{"fread_trace0", (PyCFunction) py_fread_trace0, METH_VARARGS, "Find trace0 of a line."},
diff --git a/python/segyio/open.py b/python/segyio/open.py
index 0871ce0..e340793 100644
--- a/python/segyio/open.py
+++ b/python/segyio/open.py
@@ -3,7 +3,7 @@ import numpy
import segyio
-def open(filename, mode="r", iline=189, xline=193):
+def open(filename, mode="r", iline=189, xline=193, strict = True):
"""Open a segy file.
Opens a segy file and tries to figure out its sorting, inline numbers,
@@ -20,6 +20,12 @@ def open(filename, mode="r", iline=189, xline=193):
automatically be closed when the routine completes or an exception is
raised.
+ By default, segyio tries to open in 'strict' mode. This means the file will
+ be assumed to represent a geometry with consistent inline, crosslines and
+ offsets. If strict is False, segyio will still try to establish a geometry,
+ but it won't abort if it fails. When in non-strict mode is opened,
+ geometry-dependent modes such as iline will raise an error.
+
Args:
filename (str): Path to file to open.
mode (str, optional): File access mode, defaults to "r".
@@ -27,6 +33,8 @@ def open(filename, mode="r", iline=189, xline=193):
to 189 as per the SEGY specification.
xline (TraceField): Crossline number field in the trace headers.
Defaults to 193 as per the SEGY specification.
+ strict (bool, optional): Abort if a geometry cannot be inferred.
+ Defaults to True.
Examples:
Open a file in read-only mode::
@@ -48,38 +56,61 @@ def open(filename, mode="r", iline=189, xline=193):
f = segyio.SegyFile(filename, mode, iline, xline)
try:
- header = f.bin.buf
- metrics = segyio._segyio.init_metrics(f.xfd, header, iline, xline)
+ metrics = segyio._segyio.init_metrics(f.xfd, f.bin.buf)
f._samples = metrics['sample_count']
f._tr0 = metrics['trace0']
f._fmt = metrics['format']
f._bsz = metrics['trace_bsize']
f._ext_headers = (f._tr0 - 3600) // 3200 # should probably be from C
-
f._tracecount = metrics['trace_count']
- f._sorting = metrics['sorting']
+ except:
+ f.close()
+ raise
+ try:
+ cube_metrics = segyio._segyio.init_cube_metrics(f.xfd,
+ iline,
+ xline,
+ f.tracecount,
+ f._tr0,
+ f._bsz)
+ f._sorting = cube_metrics['sorting']
+ iline_count = cube_metrics['iline_count']
+ xline_count = cube_metrics['xline_count']
+ offset_count = cube_metrics['offset_count']
+ metrics.update(cube_metrics)
+
+ line_metrics = segyio._segyio.init_line_metrics(f.sorting,
+ f.tracecount,
+ iline_count,
+ xline_count,
+ offset_count)
- iline_count, xline_count = metrics['iline_count'], metrics['xline_count']
- offset_count = metrics['offset_count']
+ f._iline_length = line_metrics['iline_length']
+ f._iline_stride = line_metrics['iline_stride']
- line_metrics = segyio._segyio.init_line_metrics(f.sorting, f.tracecount,
- iline_count, xline_count, offset_count)
+ f._xline_length = line_metrics['xline_length']
+ f._xline_stride = line_metrics['xline_stride']
- f._ilines = numpy.zeros(iline_count, dtype=numpy.intc)
- f._xlines = numpy.zeros(xline_count, dtype=numpy.intc)
+ f._ilines = numpy.zeros(iline_count, dtype = numpy.intc)
+ f._xlines = numpy.zeros(xline_count, dtype = numpy.intc)
f._offsets = numpy.zeros(offset_count, dtype = numpy.intc)
segyio._segyio.init_indices(f.xfd, metrics, f.ilines, f.xlines, f.offsets)
- f._iline_length = line_metrics['iline_length']
- f._iline_stride = line_metrics['iline_stride']
+ if numpy.unique(f.ilines).size != f.ilines.size:
+ raise ValueError( "Inlines inconsistent - expect all inlines to be unique")
- f._xline_length = line_metrics['xline_length']
- f._xline_stride = line_metrics['xline_stride']
+ if numpy.unique(f.xlines).size != f.xlines.size:
+ raise ValueError( "Crosslines inconsistent - expect all crosslines to be unique")
except:
- f.close()
- raise
+ if not strict:
+ f._ilines = None
+ f._xlines = None
+ f._offsets = None
+ else:
+ f.close()
+ raise
return f
diff --git a/python/segyio/segy.py b/python/segyio/segy.py
index 7bf4ddc..23ca5c6 100644
--- a/python/segyio/segy.py
+++ b/python/segyio/segy.py
@@ -36,6 +36,8 @@ else: range = xrange
class SegyFile(object):
+ _unstructured_errmsg = "File opened in unstructured mode."
+
def __init__(self, filename, mode, iline=189, xline=193):
"""
Constructor, internal.
@@ -70,16 +72,23 @@ class SegyFile(object):
def __str__(self):
f = "SegyFile {}:".format(self._filename)
- il = " inlines: {} [{}, {}]".format(len(self.ilines), self.ilines[0], self.ilines[-1])
- xl = " crosslines: {} [{}, {}]".format(len(self.xlines), self.xlines[0], self.xlines[-1])
+
+ if self.unstructured:
+ il = " inlines: None"
+ xl = " crosslines: None"
+ of = " offsets: None"
+ else:
+ il = " inlines: {} [{}, {}]".format(len(self.ilines), self.ilines[0], self.ilines[-1])
+ xl = " crosslines: {} [{}, {}]".format(len(self.xlines), self.xlines[0], self.xlines[-1])
+ of = " offsets: {} [{}, {}]".format(len(self.offsets), self.offsets[0], self.offsets[-1])
+
tr = " traces: {}".format(self.tracecount)
sm = " samples: {}".format(self.samples)
- of = " offsets: {} [{}, {}]".format(len(self.offsets), self.offsets[0], self.offsets[-1])
fmt = " float representation: {}".format(self.format)
props = [f, il, xl, tr, sm]
- if len(self.offsets) > 1:
+ if self.offsets is not None and len(self.offsets) > 1:
props.append(of)
props.append(fmt)
@@ -181,6 +190,9 @@ class SegyFile(object):
""" :rtype: int """
return self._ext_headers
+ @property
+ def unstructured(self):
+ return self.ilines is None
@property
def header(self):
@@ -582,6 +594,10 @@ class SegyFile(object):
Copy an iline from f to g at g's offset 200::
>>> g.iline[12, 200] = f.iline[21]
"""
+
+ if self.unstructured:
+ raise ValueError(self._unstructured_errmsg)
+
il_len, il_stride = self._iline_length, self._iline_stride
lines = self.ilines
other_lines = self.xlines
@@ -711,6 +727,10 @@ class SegyFile(object):
Copy an xline from f to g at g's offset 200::
>>> g.xline[12, 200] = f.xline[21]
"""
+
+ if self.unstructured:
+ raise ValueError(self._unstructured_errmsg)
+
xl_len, xl_stride = self._xline_length, self._xline_stride
lines = self.xlines
other_lines = self.ilines
@@ -832,6 +852,10 @@ class SegyFile(object):
Copy every other depth slices from a different file::
>>> f.depth_slice = g.depth_slice[::2]
"""
+
+ if self.unstructured:
+ raise ValueError(self._unstructured_errmsg)
+
indices = np.asarray(list(range(self.samples)), dtype=np.uintc)
other_indices = np.asarray([0], dtype=np.uintc)
buffn = self._depth_buffer
diff --git a/python/test/segy.py b/python/test/segy.py
index 88ae144..643ab2b 100644
--- a/python/test/segy.py
+++ b/python/test/segy.py
@@ -171,6 +171,10 @@ class TestSegy(TestCase):
self.assertEqual(len(f.trace), f.tracecount)
self.assertEqual(50, f.samples)
+ def test_open_nostrict(self):
+ with segyio.open(self.filename, strict = False):
+ pass
+
def test_traces_slicing(self):
with segyio.open(self.filename, "r") as f:
@@ -223,7 +227,7 @@ class TestSegy(TestCase):
f.header.iline[1,2] = { il: 11 }
f.header.iline[1,2] = { xl: 13 }
- with segyio.open("small-ps.sgy", "r") as f:
+ with segyio.open("small-ps.sgy", "r", strict = False) as f:
self.assertEqual(f.header[0][il], 1)
self.assertEqual(f.header[1][il], 11)
self.assertEqual(f.header[2][il], 1)
@@ -517,11 +521,17 @@ class TestSegy(TestCase):
with segyio.open(self.filename, "r", 2) as f:
pass
+ with segyio.open(self.filename, "r", 2, strict = False) as f:
+ pass
+
def test_open_wrong_crossline(self):
with self.assertRaises(IndexError):
with segyio.open(self.filename, "r", 189, 2) as f:
pass
+ with segyio.open(self.filename, "r", 189, 2, strict = False) as f:
+ pass
+
def test_wonky_dimensions(self):
with segyio.open(self.fileMx1) as f:
pass
@@ -532,6 +542,25 @@ class TestSegy(TestCase):
with segyio.open(self.file1x1) as f:
pass
+ def test_open_fails_unstructured(self):
+ with segyio.open(self.filename, "r", 37, strict = False) as f:
+ with self.assertRaises(ValueError):
+ f.iline[10]
+
+ with self.assertRaises(ValueError):
+ f.iline[:,:]
+
+ with self.assertRaises(ValueError):
+ f.xline[:,:]
+
+ with self.assertRaises(ValueError):
+ f.depth_slice[2]
+
+ # operations that don't rely on geometry still works
+ self.assertEqual(f.header[2][189], 1)
+ self.assertListEqual(list(f.attributes(189)[:]),
+ [(i // 5) + 1 for i in range(len(f.trace))])
+
def test_create_sgy(self):
with TestContext("create_sgy") as context:
context.copy_file(self.filename)
diff --git a/python/test/segyio_c.py b/python/test/segyio_c.py
index a573586..7bd8188 100644
--- a/python/test/segyio_c.py
+++ b/python/test/segyio_c.py
@@ -124,7 +124,11 @@ class _segyioTests(TestCase):
binary_header = _segyio.read_binaryheader(f)
ilb = 189
xlb = 193
- metrics = _segyio.init_metrics(f, binary_header, ilb, xlb)
+ metrics = _segyio.init_metrics(f, binary_header)
+ metrics.update(_segyio.init_cube_metrics(f, ilb, xlb,
+ metrics['trace_count'],
+ metrics['trace0'],
+ metrics['trace_bsize']))
_segyio.close(f)
sorting = metrics['sorting']
@@ -162,18 +166,24 @@ class _segyioTests(TestCase):
xlb = 193
with self.assertRaises(TypeError):
- metrics = _segyio.init_metrics("?", binary_header, ilb, xlb)
+ metrics = _segyio.init_metrics("?", binary_header)
with self.assertRaises(TypeError):
- metrics = _segyio.init_metrics(f, "?", ilb, xlb)
+ metrics = _segyio.init_metrics(f, "?")
with self.assertRaises(IndexError):
- metrics = _segyio.init_metrics(f, binary_header, ilb + 1, xlb)
+ metrics = _segyio.init_metrics(f, binary_header)
+ metrics.update(_segyio.init_cube_metrics(f, ilb + 1, xlb,
+ metrics['trace_count'],
+ metrics['trace0'],
+ metrics['trace_bsize']))
+
+ metrics = _segyio.init_metrics(f, binary_header)
+ metrics.update(_segyio.init_cube_metrics(f, ilb, xlb,
+ metrics['trace_count'],
+ metrics['trace0'],
+ metrics['trace_bsize']))
- metrics = _segyio.init_metrics(f, binary_header, ilb, xlb)
-
- self.assertEqual(metrics['iline_field'], ilb)
- self.assertEqual(metrics['xline_field'], xlb)
self.assertEqual(metrics['trace0'], _segyio.textheader_size() + _segyio.binheader_size())
self.assertEqual(metrics['sample_count'], 50)
self.assertEqual(metrics['format'], 1)
@@ -187,7 +197,7 @@ class _segyioTests(TestCase):
_segyio.close(f)
with self.assertRaises(IOError):
- metrics = _segyio.init_metrics(f, binary_header, ilb, xlb)
+ metrics = _segyio.init_metrics(f, binary_header)
def test_indices(self):
f = _segyio.open(self.filename, "r")
@@ -195,7 +205,7 @@ class _segyioTests(TestCase):
binary_header = _segyio.read_binaryheader(f)
ilb = 189
xlb = 193
- metrics = _segyio.init_metrics(f, binary_header, ilb, xlb)
+ metrics = _segyio.init_metrics(f, binary_header)
dmy = numpy.zeros(2, dtype=numpy.intc)
dummy_metrics = {'xline_count': 2,
@@ -233,6 +243,11 @@ class _segyioTests(TestCase):
with self.assertRaises(ValueError):
_segyio.init_indices(f, dummy_metrics, two, one, off)
+ metrics.update(_segyio.init_cube_metrics(f, ilb, xlb,
+ metrics['trace_count'],
+ metrics['trace0'],
+ metrics['trace_bsize']))
+
# Happy Path
iline_indexes = numpy.zeros(metrics['iline_count'], dtype=numpy.intc)
xline_indexes = numpy.zeros(metrics['xline_count'], dtype=numpy.intc)
@@ -252,7 +267,11 @@ class _segyioTests(TestCase):
ilb = 189
xlb = 193
- metrics = _segyio.init_metrics(f, binary_header, ilb, xlb)
+ metrics = _segyio.init_metrics(f, binary_header)
+ metrics.update(_segyio.init_cube_metrics(f, ilb, xlb,
+ metrics['trace_count'],
+ metrics['trace0'],
+ metrics['trace_bsize']))
sorting = metrics['sorting']
trace_count = metrics['trace_count']
@@ -318,7 +337,7 @@ class _segyioTests(TestCase):
binary_header = _segyio.read_binaryheader(f)
ilb = 189
xlb = 193
- metrics = _segyio.init_metrics(f, binary_header, ilb, xlb)
+ metrics = _segyio.init_metrics(f, binary_header)
empty = _segyio.empty_traceheader()
@@ -384,7 +403,11 @@ class _segyioTests(TestCase):
ilb = 189
xlb = 193
- metrics = _segyio.init_metrics(f, binary_header, ilb, xlb)
+ metrics = _segyio.init_metrics(f, binary_header)
+ metrics.update(_segyio.init_cube_metrics(f, ilb, xlb,
+ metrics['trace_count'],
+ metrics['trace0'],
+ metrics['trace_bsize']))
sorting = metrics['sorting']
trace_count = metrics['trace_count']
--
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