Skip to content

Commit 686a28a

Browse files
authored
Merge pull request #650 from achaikou/field_mappings_open
Open file with shifted layout
2 parents 521bbb7 + 69a9101 commit 686a28a

15 files changed

Lines changed: 537 additions & 235 deletions

File tree

lib/include/segyio/segy.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ int segy_field_forall( segy_datasource*,
550550
int start,
551551
int stop,
552552
int step,
553-
int* buf,
553+
void* buf,
554554
long trace0,
555555
int trace_bsize );
556556

@@ -821,7 +821,7 @@ int segy_inline_indices( segy_datasource*,
821821
int inline_count,
822822
int crossline_count,
823823
int offsets,
824-
int* buf,
824+
void* buf,
825825
long trace0,
826826
int trace_bsize );
827827

@@ -831,7 +831,7 @@ int segy_crossline_indices( segy_datasource*,
831831
int inline_count,
832832
int crossline_count,
833833
int offsets,
834-
int* buf,
834+
void* buf,
835835
long trace0,
836836
int trace_bsize );
837837

lib/src/segy.c

Lines changed: 91 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,68 +1377,116 @@ static int slicelength( int start, int stop, int step ) {
13771377
return (stop - start - 1) / step + 1;
13781378
}
13791379

1380-
static int32_t bswap_header_word(int32_t f, int word_size) {
1381-
if (word_size == 4)
1382-
return bswap32(f);
1380+
static int bswap_header_word( segy_field_data* fd ) {
1381+
uint8_t datatype = entry_type_to_datatype_map[fd->entry_type];
1382+
switch( datatype ) {
1383+
case SEGY_SIGNED_INTEGER_8_BYTE:
1384+
fd->value.i64 = bswap64( fd->value.i64 );
1385+
return SEGY_OK;
13831386

1384-
/*
1385-
* The casts are here are necessary
1386-
*
1387-
* First, it must be converted to a *signed* short (to preserve negative
1388-
* numbers). The narrowing is safe because the source is 2 bytes anyway.
1389-
*
1390-
* The behaviour when this is implicitly wrong was discovered in [1].
1391-
*
1392-
* Then, it must be byteswapped with bswap16. When using the shifts is
1393-
* probably fine as the types are also cast in the macro and are
1394-
* compatible, but the builtins have this signature [2]:
1395-
*
1396-
* uint16_t __builtin_bswap16 (uint16_t x)
1397-
*
1398-
* which means that if the value is *negative* it will be interpreted as
1399-
* unsigned and very much positive. When it is then implicitly converted
1400-
* in the return type it is widened, and int32 can fit uint16 maximum just
1401-
* fine.
1402-
*
1403-
* [1] https://github.com/equinor/segyio/issues/368
1404-
* [2] http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
1405-
*/
1406-
return (int16_t) bswap16((int16_t) f);
1387+
case SEGY_SIGNED_INTEGER_4_BYTE:
1388+
fd->value.i32 = bswap32( fd->value.i32 );
1389+
return SEGY_OK;
1390+
1391+
case SEGY_SIGNED_SHORT_2_BYTE:
1392+
fd->value.i16 = bswap16( fd->value.i16 );
1393+
return SEGY_OK;
1394+
1395+
case SEGY_UNSIGNED_INTEGER_8_BYTE:
1396+
fd->value.u64 = bswap64( fd->value.u64 );
1397+
return SEGY_OK;
1398+
1399+
case SEGY_UNSIGNED_INTEGER_4_BYTE:
1400+
fd->value.u32 = bswap32( fd->value.u32 );
1401+
return SEGY_OK;
1402+
1403+
case SEGY_UNSIGNED_SHORT_2_BYTE:
1404+
fd->value.u16 = bswap16( fd->value.u16 );
1405+
return SEGY_OK;
1406+
1407+
case SEGY_UNSIGNED_CHAR_1_BYTE:
1408+
case SEGY_SIGNED_CHAR_1_BYTE:
1409+
return SEGY_OK;
1410+
default:
1411+
return SEGY_INVALID_FIELD_DATATYPE;
1412+
}
14071413
}
14081414

14091415
int segy_field_forall( segy_datasource* ds,
14101416
int field,
14111417
int start,
14121418
int stop,
14131419
int step,
1414-
int* buf,
1420+
void* buffer,
14151421
long trace0,
14161422
int trace_bsize ) {
14171423
int err;
1424+
char* buf = (char*)buffer;
1425+
14181426
// do a dummy-read of a zero-init'd buffer to check args
1419-
int32_t f;
1420-
char header[ SEGY_TRACE_HEADER_SIZE ] = { 0 };
1421-
err = segy_get_tracefield_int( header, field, &f );
1427+
segy_field_data fd;
1428+
char header[SEGY_TRACE_HEADER_SIZE] = { 0 };
1429+
1430+
const segy_entry_definition* offset_map =
1431+
ds->traceheader_mapping_standard.offset_to_entry_definition;
1432+
err = segy_get_tracefield( header, offset_map, field, &fd );
14221433
if( err != SEGY_OK ) return SEGY_INVALID_ARGS;
14231434

14241435
int slicelen = slicelength( start, stop, step );
1436+
int elemsize = segy_formatsize( entry_type_to_datatype_map[fd.entry_type] );
14251437

14261438
const int zfield = field - 1;
1427-
for( int i = start; slicelen > 0; i += step, ++buf, --slicelen ) {
1428-
err = segy_seek( ds, i, trace0 + zfield, trace_bsize );
1439+
for( int i = start; slicelen > 0; i += step, buf += elemsize, --slicelen ) {
1440+
int offset = trace0 + zfield;
1441+
err = segy_seek( ds, i, offset, trace_bsize );
14291442
if( err != SEGY_OK ) return err;
1430-
err = ds->read( ds, header + zfield, sizeof( uint32_t ) );
1443+
err = ds->read( ds, header + zfield, elemsize );
14311444
if( err != 0 ) return SEGY_DS_READ_ERROR;
14321445

1433-
// note: for the moment function still works only on ints
1434-
err = segy_get_tracefield_int( header, field, &f );
1446+
err = segy_get_tracefield( header, offset_map, field, &fd );
14351447
if( err != 0 ) return err;
1436-
const uint8_t entry_type = traceheader_default_map[zfield].entry_type;
1437-
const uint8_t datatype = entry_type_to_datatype_map[entry_type];
1438-
if( ds->metadata.endianness == SEGY_LSB) {
1439-
f = bswap_header_word( f, segy_formatsize( datatype ) );
1448+
1449+
if( ds->metadata.endianness == SEGY_LSB ) {
1450+
err = bswap_header_word( &fd );
1451+
if( err != SEGY_OK ) return err;
1452+
}
1453+
1454+
switch( entry_type_to_datatype_map[fd.entry_type] ) {
1455+
case SEGY_SIGNED_INTEGER_8_BYTE:
1456+
memcpy( buf, &fd.value.i64, elemsize );
1457+
break;
1458+
1459+
case SEGY_SIGNED_INTEGER_4_BYTE:
1460+
memcpy( buf, &fd.value.i32, elemsize );
1461+
break;
1462+
1463+
case SEGY_SIGNED_SHORT_2_BYTE:
1464+
memcpy( buf, &fd.value.i16, elemsize );
1465+
break;
1466+
1467+
case SEGY_SIGNED_CHAR_1_BYTE:
1468+
memcpy( buf, &fd.value.i8, elemsize );
1469+
break;
1470+
1471+
case SEGY_UNSIGNED_INTEGER_8_BYTE:
1472+
memcpy( buf, &fd.value.u64, elemsize );
1473+
break;
1474+
1475+
case SEGY_UNSIGNED_INTEGER_4_BYTE:
1476+
memcpy( buf, &fd.value.u32, elemsize );
1477+
break;
1478+
1479+
case SEGY_UNSIGNED_SHORT_2_BYTE:
1480+
memcpy( buf, &fd.value.u16, elemsize );
1481+
break;
1482+
1483+
case SEGY_UNSIGNED_CHAR_1_BYTE:
1484+
memcpy( buf, &fd.value.u8, elemsize );
1485+
break;
1486+
1487+
default:
1488+
return SEGY_INVALID_FIELD_DATATYPE;
14401489
}
1441-
*buf = f;
14421490
}
14431491

14441492
return SEGY_OK;
@@ -2117,7 +2165,7 @@ static int segy_line_indices( segy_datasource* ds,
21172165
int traceno,
21182166
int stride,
21192167
int num_indices,
2120-
int* buf,
2168+
void* buf,
21212169
long trace0,
21222170
int trace_bsize ) {
21232171
return segy_field_forall( ds,
@@ -2281,7 +2329,7 @@ int segy_inline_indices( segy_datasource* ds,
22812329
int inline_count,
22822330
int crossline_count,
22832331
int offsets,
2284-
int* buf,
2332+
void* buf,
22852333
long trace0,
22862334
int trace_bsize) {
22872335

@@ -2303,7 +2351,7 @@ int segy_crossline_indices( segy_datasource* ds,
23032351
int inline_count,
23042352
int crossline_count,
23052353
int offsets,
2306-
int* buf,
2354+
void* buf,
23072355
long trace0,
23082356
int trace_bsize ) {
23092357

python/segyio/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ def __hash__(self):
6363
return hash(self._value)
6464

6565
def __eq__(self, other):
66+
if other is None:
67+
return False
6668
try:
6769
o = int(other)
6870
except ValueError:

python/segyio/create.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,11 @@ def _create(datasource_descriptor, spec):
247247
ext_headers = int(ext_headers),
248248
)
249249

250+
# note: even if iline/xline are overridden, file is already created with
251+
# standard iline/xline position, so those can mismatch
252+
250253
f = segyio.SegyFile(fd,
251254
datasource_descriptor,
252-
iline = int(spec.iline),
253-
xline = int(spec.xline),
254255
endian = endian,
255256
)
256257

python/segyio/open.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ def infer_geometry(f, metrics, strict):
3838
return f
3939

4040

41-
def open(filename, mode="r", iline = 189,
42-
xline = 193,
41+
def open(filename, mode="r", iline = None,
42+
xline = None,
4343
strict = True,
4444
ignore_geometry = False,
4545
endian = None,
@@ -82,12 +82,16 @@ def open(filename, mode="r", iline = 189,
8282
File access mode, read-only ('r', default) or read-write ('r+')
8383
8484
iline : int or segyio.TraceField
85-
Inline number field in the trace headers. Defaults to 189 as per the
86-
SEG-Y rev1 specification
85+
Overrides inline field offset in the trace headers. If no value is set,
86+
value defined in xml mapping is used and if this one is absent the
87+
standard-defined value 189 is used. By setting this value user takes
88+
over responsibility of assuring parsing can be done correctly.
8789
8890
xline : int or segyio.TraceField
89-
Crossline number field in the trace headers. Defaults to 193 as per the
90-
SEG-Y rev1 specification
91+
Overrides crossline field offset in the trace headers. If no value is
92+
set, value defined in xml mapping is used and if this one is absent the
93+
standard-defined value 193 is used. By setting this value user takes
94+
over responsibility of assuring parsing can be done correctly.
9195
9296
strict : bool, optional
9397
Abort if a geometry cannot be inferred. Defaults to True.
@@ -169,8 +173,8 @@ def open(filename, mode="r", iline = 189,
169173

170174

171175
def open_with(stream,
172-
iline=189,
173-
xline=193,
176+
iline=None,
177+
xline=None,
174178
strict=True,
175179
ignore_geometry=False,
176180
endian=None,
@@ -210,8 +214,8 @@ def open_with(stream,
210214

211215

212216
def open_from_memory(memory_buffer,
213-
iline=189,
214-
xline=193,
217+
iline=None,
218+
xline=None,
215219
strict=True,
216220
ignore_geometry=False,
217221
endian=None,
@@ -242,27 +246,31 @@ def open_from_memory(memory_buffer,
242246

243247

244248
def _open(datasource_descriptor,
245-
iline=189,
246-
xline=193,
249+
iline=None,
250+
xline=None,
247251
strict=True,
248252
ignore_geometry=False,
249253
endian=None,
250254
encoding=None,
251255
):
252256

253257
fd = datasource_descriptor.make_segyfile_descriptor()
258+
259+
if iline != None:
260+
iline = int(iline)
261+
if xline != None:
262+
xline = int(xline)
263+
254264
fd.segyopen(
255265
endianness=to_c_endianness(endian),
256266
encoding=to_c_encoding(encoding),
257-
iline=int(iline),
258-
xline=int(xline)
267+
iline=iline,
268+
xline=xline
259269
)
260270
metrics = fd.metrics()
261271

262272
f = segyio.SegyFile(fd,
263273
datasource_descriptor,
264-
iline = int(iline),
265-
xline = int(xline),
266274
endian = endian,
267275
)
268276

python/segyio/segy.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@ def __init__(
2727
self,
2828
fd,
2929
datasource_descriptor,
30-
iline=189,
31-
xline=193,
3230
endian='big'
3331
):
3432

3533
self._datasource_descriptor = datasource_descriptor
36-
self._il = iline
37-
self._xl = xline
34+
35+
self._traceheader_layouts = fd.traceheader_layouts()
36+
standard_header_layout = self._traceheader_layouts["SEG00000"]
37+
self._il = standard_header_layout.entry_by_name("iline").byte
38+
self._xl = standard_header_layout.entry_by_name("xline").byte
3839

3940
# property value holders
4041
self._ilines = None
@@ -415,7 +416,8 @@ def attributes(self, field):
415416
.. versionadded:: 1.1
416417
417418
"""
418-
return Attributes(field, self.segyfd, self.tracecount)
419+
traceheader_layout = self._traceheader_layouts["SEG00000"]
420+
return Attributes(field, self.segyfd, traceheader_layout, self.tracecount)
419421

420422
@property
421423
def trace(self):

0 commit comments

Comments
 (0)