Example #1
0
 def test_arbitrary_mapping(self, mapping):
     builder = CatalogBuilder(mapping)
     catalog = builder.create()
     shared_items = set(mapping.items()) & set(catalog.items())
     self.assertEqual(len(shared_items), len(mapping))
Example #2
0
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)
Example #3
0
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)