def trace_indexes(self): if self._trace_index_catalog is None: trace_index_catalog_builder = CatalogBuilder() trace_index = 0 dataset = self._array_dataset samples = dataset._samples for inline_index in range(0, samples.shape[0]): for xline_index in range(0, samples.shape[1]): trace_samples = samples[inline_index, xline_index, :] if dataset._trace_has_samples(trace_samples): trace_index_catalog_builder.add(trace_index, (inline_index, xline_index)) self._trace_index_catalog = trace_index_catalog_builder.create() return self._trace_index_catalog.keys()
def trace_indexes(self): if self._trace_index_catalog is None: trace_index_catalog_builder = CatalogBuilder() trace_index = 0 dataset = self._array_dataset samples = dataset._samples for inline_index in range(0, samples.shape[0]): for xline_index in range(0, samples.shape[1]): trace_samples = samples[inline_index, xline_index, :] if dataset._trace_has_samples(trace_samples): trace_index_catalog_builder.add( trace_index, (inline_index, xline_index)) self._trace_index_catalog = trace_index_catalog_builder.create() return self._trace_index_catalog.keys()
def catalog_traces(fh, bps, trace_header_format=TraceHeaderRev1, endian='>', progress=None): """Build catalogs to facilitate random access to trace_samples data. Note: This function can take significant time to run, proportional to the number of traces in the SEG Y file. Four catalogs will be build: 1. A catalog mapping trace_samples index (0-based) to the position of that trace_samples header in the file. 2. A catalog mapping trace_samples index (0-based) to the number of samples in that trace_samples. 3. A catalog mapping CDP number to the trace_samples index. 4. A catalog mapping an (inline, crossline) number 2-tuple to trace_samples index. Args: fh: A file-like-object open in binary mode, positioned at the start of the first trace_samples header. bps: The number of bytes per sample, such as obtained by a call to bytes_per_sample() trace_header_format: The class defining the trace header format. Defaults to TraceHeaderRev1. endian: '>' for big-endian data (the standard and default), '<' for little-endian (non-standard) progress: A unary callable which will be passed a number between zero and one indicating the progress made. If provided, this callback will be invoked at least once with an argument equal to 1 Returns: A 4-tuple of the form (trace_samples-offset-catalog, trace_samples-length-catalog, cdp-catalog, line-catalog)` where each catalog is an instance of ``collections.Mapping`` or None if no catalog could be built. """ progress_callback = progress if progress is not None else lambda p: None if not callable(progress_callback): raise TypeError("catalog_traces(): progress callback must be callable") class CatalogSubFormat(metaclass=SubFormatMeta, parent_format=trace_header_format, parent_field_names=( 'file_sequence_num', 'ensemble_num', 'num_samples', 'inline_number', 'crossline_number', )): pass trace_header_packer = make_header_packer(CatalogSubFormat, endian) length = file_length(fh) pos_begin = fh.tell() trace_offset_catalog_builder = CatalogBuilder() trace_length_catalog_builder = CatalogBuilder() line_catalog_builder = CatalogBuilder() alt_line_catalog_builder = CatalogBuilder() cdp_catalog_builder = CatalogBuilder() for trace_number in count(): progress_callback(_READ_PROPORTION * pos_begin / length) fh.seek(pos_begin) data = fh.read(TRACE_HEADER_NUM_BYTES) if len(data) < TRACE_HEADER_NUM_BYTES: break trace_header = trace_header_packer.unpack(data) num_samples = trace_header.num_samples trace_length_catalog_builder.add(trace_number, num_samples) samples_bytes = num_samples * bps trace_offset_catalog_builder.add(trace_number, pos_begin) # Should we check the data actually exists? line_catalog_builder.add((trace_header.inline_number, trace_header.crossline_number), trace_number) alt_line_catalog_builder.add((trace_header.file_sequence_num, trace_header.ensemble_num), trace_number) cdp_catalog_builder.add(trace_header.ensemble_num, trace_number) pos_end = pos_begin + TRACE_HEADER_NUM_BYTES + samples_bytes pos_begin = pos_end progress_callback(_READ_PROPORTION) trace_offset_catalog = trace_offset_catalog_builder.create() progress_callback(_READ_PROPORTION + (_READ_PROPORTION / 4)) trace_length_catalog = trace_length_catalog_builder.create() progress_callback(_READ_PROPORTION + (_READ_PROPORTION / 2)) cdp_catalog = cdp_catalog_builder.create() progress_callback(_READ_PROPORTION + (_READ_PROPORTION * 3 / 4)) line_catalog = line_catalog_builder.create() if line_catalog is None: # Some 3D files put Inline and Crossline numbers in (TraceSequenceFile, cdp) pair line_catalog = alt_line_catalog_builder.create() progress_callback(1) return (trace_offset_catalog, trace_length_catalog, cdp_catalog, line_catalog)
def test_adding_items_puts_them_in_the_catalog(self, mapping): builder = CatalogBuilder() for key, value in mapping.items(): builder.add(key, value) catalog = builder.create() assert all(catalog[key] == value for key, value in mapping.items())
def catalog_fixed_length_traces(fh, binary_reel_header, trace_header_format=TraceHeaderRev1, endian='>', progress=None): """Build catalogs to for a fixed length SEG Y file. This is much faster than the full catalog, but has limitations. No CDP, or inline, xline catalogs, and it only works for segy files with fixed legth SEG Y files. Note: This function is faster than the full catalog, but has limitations. No CDP, or inline, xline catalogs, and it only works for SEG Y files with a fixed number of samples in each trace. Two catalogs will be built: 1. A catalog mapping trace_samples index (0-based) to the position of that trace_samples header in the file. 2. A catalog mapping trace_samples index (0-based) to the number of samples in that trace_samples. Args: fh: A file-like-object open in binary mode, positioned at the start of the first trace_samples header. bps: The number of bytes per sample, such as obtained by a call to bytes_per_sample() trace_header_format: The class defining the trace header format. Defaults to TraceHeaderRev1. endian: '>' for big-endian data (the standard and default), '<' for little-endian (non-standard) progress: A unary callable which will be passed a number between zero and one indicating the progress made. If provided, this callback will be invoked at least once with an argument equal to 1 Returns: A 4-tuple of the form (trace_samples-offset-catalog, trace_samples-length-catalog, None, None)` where each catalog is an instance of ``collections.Mapping`` or None if no catalog could be built. """ revision = extract_revision(binary_reel_header) bps = bytes_per_sample(binary_reel_header, revision) progress_callback = progress if progress is not None else lambda p: None if not callable(progress_callback): raise TypeError("catalog_traces(): progress callback must be callable") class CatalogSubFormat(metaclass=SubFormatMeta, parent_format=trace_header_format, parent_field_names=( 'file_sequence_num', 'ensemble_num', 'num_samples', 'inline_number', 'crossline_number', )): pass num_file_bytes = file_length(fh) num_samples=binary_reel_header.num_samples num_traces_float = (num_file_bytes-REEL_HEADER_NUM_BYTES)/(TRACE_HEADER_NUM_BYTES+num_samples*bps) num_traces = int(num_traces_float) if num_traces != num_traces_float: raise ValueError( "SEG Y file {!r} of {} bytes is not consistent with a fixed trace length".format( filename_from_handle(fh), num_file_bytes)) trace_offset_catalog_builder = CatalogBuilder() trace_length_catalog_builder = CatalogBuilder() for trace_index in range(num_traces): pos_begin=REEL_HEADER_NUM_BYTES+(num_samples * bps+TRACE_HEADER_NUM_BYTES) * trace_index trace_length_catalog_builder.add(trace_index, num_samples) trace_offset_catalog_builder.add(trace_index, pos_begin) trace_offset_catalog = trace_offset_catalog_builder.create() trace_length_catalog = trace_length_catalog_builder.create() progress_callback(1) return (trace_offset_catalog, trace_length_catalog, None, None)