Skip to content

Commit

Permalink
Get tracecount from arg in create, not header
Browse files Browse the repository at this point in the history
The cheeky trick of passing the number of traceheaders in the binary
header when creating new files, in a field that is not dedicated to
number-of-traces-per-file, doesn't work because it's only 16 bits and
overflows very fast, and SEG-Y allows for 32-bits of traces (governed by
traceno).

Instead, pass the override-number-of-traces argument to the internal
filehandle constructor explicitly, and only consider that number if the
binary header is also passed.

This fixes the issue reported in
equinor#235
  • Loading branch information
jokva committed Mar 16, 2018
1 parent 162c155 commit 2019c1e
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 21 deletions.
8 changes: 4 additions & 4 deletions python/segyio/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,19 +135,19 @@ def create(filename, spec):
if not structured(spec):
tracecount = spec.tracecount
else:
tracecount = len(spec.ilines) * len(spec.xlines) * len(spec.offsets)
tracecount = len(spec.ilines) * len(spec.xlines) * len(spec.offsets)

ext_headers = spec.ext_headers if hasattr(spec, 'ext_headers') else 0
samples = numpy.asarray(spec.samples, dtype = numpy.single)

binary = bytearray(_segyio.binsize())
_segyio.putfield(binary, 3213, tracecount)
_segyio.putfield(binary, 3217, 4000)
_segyio.putfield(binary, 3221, len(samples))
_segyio.putfield(binary, 3225, int(spec.format))
_segyio.putfield(binary, 3505, int(ext_headers))

f = segyio.SegyFile(str(filename), "w+", binary = binary)
f = segyio.SegyFile(str(filename), "w+", tracecount = tracecount,
binary = binary)

f._il = int(spec.iline)
f._xl = int(spec.xline)
Expand All @@ -161,7 +161,7 @@ def create(filename, spec):
f._xlines = numpy.copy(numpy.asarray(spec.xlines, dtype=numpy.intc))

line_metrics = _segyio.line_metrics(f.sorting,
f.tracecount,
tracecount,
len(f.ilines),
len(f.xlines),
len(f.offsets))
Expand Down
4 changes: 2 additions & 2 deletions python/segyio/segy.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class SegyFile(object):

_unstructured_errmsg = "File opened in unstructured mode."

def __init__(self, filename, mode, iline=189, xline=193, binary=None):
def __init__(self, filename, mode, iline=189, xline=193, tracecount=0, binary=None):
"""
Constructor, internal.
"""
Expand Down Expand Up @@ -64,7 +64,7 @@ def __init__(self, filename, mode, iline=189, xline=193, binary=None):
self._xline = None
self._gather = None

self.xfd = _segyio.segyiofd(filename, mode, binary)
self.xfd = _segyio.segyiofd(filename, mode, tracecount, binary)
metrics = self.xfd.metrics()
self._fmt = metrics['format']
self._tracecount = metrics['tracecount']
Expand Down
14 changes: 5 additions & 9 deletions python/segyio/segyio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,13 @@ namespace fd {
int init( segyiofd* self, PyObject* args, PyObject* ) {
char* filename = NULL;
char* mode = NULL;
int tracecount = 0;
buffer_guard buffer;

if( !PyArg_ParseTuple( args, "ss|z*", &filename, &mode, &buffer ) )
if( !PyArg_ParseTuple( args, "ss|iz*", &filename,
&mode,
&tracecount,
&buffer ) )
return -1;

const char* binary = buffer.buf< const char >();
Expand Down Expand Up @@ -261,7 +265,6 @@ int init( segyiofd* self, PyObject* args, PyObject* ) {
return -1;
}

int tracecount = 0;
char bin[ SEGY_BINARY_HEADER_SIZE ] = {};

if( !binary ) {
Expand All @@ -273,13 +276,6 @@ int init( segyiofd* self, PyObject* args, PyObject* ) {
}

binary = bin;
} else {
/*
* usually we wouldn't trust the bin-traces in the binary header, but
* this code path is only taken with create() (or similarly
* pre-verified header), in which case we can just read the tracecount.
*/
segy_get_bfield( binary, SEGY_BIN_TRACES, &tracecount );
}

const long trace0 = segy_trace0( binary );
Expand Down
23 changes: 22 additions & 1 deletion python/test/segy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1065,4 +1065,25 @@ def value(x, y):
for index, depth_slice in enumerate(f.depth_slice):
assert np.allclose(depth_slice, buf * index)


def test_no_16bit_overflow_tracecount(tmpdir):
spec = segyio.spec()
spec.format = 1
spec.sorting = 2
spec.samples = np.arange(501)
spec.ilines = np.arange(345)
spec.xlines = np.arange(250)

# build a file with more than 65k traces, which would cause a 16bit int to
# overflow.
# see https://github.com/Statoil/segyio/issues/235
ones = np.ones(len(spec.samples), dtype = np.single)
with segyio.create(tmpdir / 'foo.sgy', spec) as f:
assert f.tracecount > 0
assert f.tracecount > 2**16 - 1
for i in range(f.tracecount):
f.trace[i] = ones
f.header[i] = {
segyio.TraceField.INLINE_3D: i,
segyio.TraceField.CROSSLINE_3D: i,
segyio.TraceField.offset: 1,
}
16 changes: 11 additions & 5 deletions python/test/segyio_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ def write_text_header(f, mmap):
f.close()


def get_instance_segyiofd(tmpdir, file_name="small.sgy", mode="r+", binary=None):
def get_instance_segyiofd(tmpdir,
file_name="small.sgy",
mode="r+",
tracecount=0,
binary=None):
path = str(tmpdir)
f = os.path.join(path, file_name)
if binary is not None:
Expand Down Expand Up @@ -424,18 +428,20 @@ def mkempty():
@tmpfiles("test-data/small.sgy")
def test_read_and_write_trace_mmap(tmpdir):
binary = bytearray(_segyio.binsize())
_segyio.putfield(binary, 3213, 100)
_segyio.putfield(binary, 3221, 25)
f = get_instance_segyiofd(tmpdir, "trace-wrt.sgy", "w+", binary)
f = get_instance_segyiofd(tmpdir, "trace-wrt.sgy", "w+",
tracecount=100,
binary=binary)
read_and_write_trace(f, True)


@tmpfiles("test-data/small.sgy")
def test_read_and_write_trace(tmpdir):
binary = bytearray(_segyio.binsize())
_segyio.putfield(binary, 3213, 100)
_segyio.putfield(binary, 3221, 25)
f = get_instance_segyiofd(tmpdir, "trace-wrt.sgy", "w+", binary)
f = get_instance_segyiofd(tmpdir, "trace-wrt.sgy", "w+",
tracecount=100,
binary=binary)
read_and_write_trace(f, False)


Expand Down

0 comments on commit 2019c1e

Please sign in to comment.