Source code for segfast.trace_header_spec

""" Class to specify headers to load. """

import numpy as np
import segyio

[docs] class TraceHeaderSpec: """ Trace header class to store its name, byte position and dtype (including endianness). By default, byte position is defined by name according to SEG-Y specification. Parameters ---------- name : str Name of the header. start_byte : int, optional Byte position of the header, by default ``None``. If ``None``, default byte position from the spec will be used. dtype : int, str or dtype, optional dtype for header (e.g. ``'i2'``, ``'>f4'``, ``numpy.float32``) or its length in bytes (then is interpreted as integer type). byteorder : '>' or '<', optional Endianness to use, if it's not defined by ``dtype``. If ``None`` and dtype doesn't specify it, architecture default will be used. """ TRACE_HEADER_SIZE = 240 STANDARD_HEADER_TO_BYTE = segyio.tracefield.keys """ Mapping from standard header name to its start byte. :meta hide-value: """ STANDARD_BYTE_TO_HEADER = {v: k for k, v in STANDARD_HEADER_TO_BYTE.items()} """ Mapping from start byte to header name accordingly to standard. :meta hide-value: """ START_BYTES = sorted(STANDARD_HEADER_TO_BYTE.values()) """ List bytes positions for standard headers :meta hide-value: """ STANDARD_BYTE_TO_LEN = {start: end - start for start, end in zip(START_BYTES, START_BYTES[1:] + [TRACE_HEADER_SIZE + 1])} """ Mapping from start byte to length of header in bytes accordingly to standard. :meta hide-value: """ def __init__(self, name=None, start_byte=None, dtype=None, byteorder=None): self.name = name or self.STANDARD_BYTE_TO_HEADER[start_byte] self.start_byte = start_byte or self.STANDARD_HEADER_TO_BYTE[name] dtype = dtype or self.STANDARD_BYTE_TO_LEN[self.start_byte] if isinstance(dtype, int): dtype = 'i' + str(dtype) self.dtype = np.dtype(dtype) self.default_byteorder = byteorder self.has_explicit_byteorder = isinstance(dtype, str) and dtype[0] in {'>', '<'} if not self.has_explicit_byteorder and byteorder is not None: self.dtype = self.dtype.newbyteorder(byteorder) if self.start_byte + self.byte_len > self.TRACE_HEADER_SIZE + 1: raise ValueError(f'{self.name} header position is out of bounds') @property def byte_len(self): """ The number of bytes for a header. """ return self.dtype.itemsize @property def is_standard(self): """ Whether the header matches the specification. """ return self.name in self.STANDARD_BYTE_TO_HEADER and self.has_standard_location @property def has_standard_location(self): """ Whether the header matches the specification, except maybe the name. """ return self.start_byte in self.STANDARD_BYTE_TO_HEADER and \ self.byte_len == self.STANDARD_BYTE_TO_LEN[self.start_byte] and \ np.issubdtype(self.dtype, np.integer) @property def standard_name(self): """ The name from the specification for the header (if ``has_standard_location`` is ``True``). """ if not self.has_standard_location: raise ValueError("The header has non-standard start byte or dtype") return self.STANDARD_BYTE_TO_HEADER[self.start_byte] @property def has_default_byteorder(self): """ Whether default byteorder is defined. """ return self.default_byteorder is not None @property def has_byteorder(self): """ Whether byteorder is defined. """ return self.has_explicit_byteorder or self.has_default_byteorder @property def byteorder(self): """ Header byteorder (if defined). """ if not self.has_byteorder: return None return self.dtype.str[0] @property def _spec_params(self): dtype_str = self.dtype.str if not self.has_byteorder: dtype_str = dtype_str[1:] return self.name, self.start_byte, dtype_str def __eq__(self, other): return self._spec_params == other._spec_params def __hash__(self): return hash(self._spec_params)
[docs] def set_default_byteorder(self, byteorder): """ Set byteorder to use as a default, if not specified by ``dtype``. """ dtype = self.dtype.str if not self.has_explicit_byteorder: dtype = dtype[1:] return type(self)(name=self.name, start_byte=self.start_byte, dtype=dtype, byteorder=byteorder)
def __repr__(self): class_name = type(self).__name__ return f"{class_name}(name='{self.name}', start_byte={self.start_byte}, dtype='{self._spec_params[2]}')"
[docs] def to_tuple(self): """ Make a tuple of input params of the header. """ return self._spec_params
[docs] def to_dict(self): """ Make a dict of input params of the header. """ return dict(zip(['name', 'start_byte', 'dtype'], self._spec_params))