Example #1
0
def write_segy_based_on(hf, segy_y_reader, data, endian='>'):
  """
  Purpose:
    make it easy to write new (processed) data back to a new segy file based on the original
    segy file

  Args:
    fh: A file-like object open for binary write.

    segy_y_reader: a SegYReader instance from which the segy headers and other parameters can be retreived

    data: a numpy array containing trace samples organised in (trace, inline, crossline order)

  """

  encoding = segy_y_reader.encoding

  if not is_supported_encoding(encoding):
      raise UnsupportedEncodingError("Writing SEG Y", encoding)

  write_textual_reel_header(fh, segy_y_reader.textual_reel_header, encoding)
  write_binary_reel_header(fh, segy_y_reader.binary_reel_header, endian)
  write_extended_textual_headers(fh, segy_y_reader.extended_textual_header, encoding)

  trace_header_packer = HeaderPacker(trace_header_format, endian)

  il_xl = list(itertools.product(segy_y_reader.inline_range(), segy_y_reader.xline_range()))
  x_y = list(itertools.product(range(0,segy_y_reader.num_inlines()), range(0,segy_y_reader.num_xlines())))
  for ix,ij in zip(il_xl, x_y):
      idx = reader.trace_index((ix[0],ix[1]))
      write_trace_header(fh, segy_y_reader.trace_header(idx), trace_header_packer)
      write_trace_samples(fh, data[:,ij[0],ij[1]], segy_y_reader.data_sample_format, endian=endian)
Example #2
0
def write_segy(fh,
               dataset,
               encoding=None,
               trace_header_format=TraceHeaderRev1,
               endian='>',
               progress=None):
    """
    Args:
        fh: A file-like object open for binary write, positioned to write the textual reel header.

        dataset: An object implementing the interface of segpy.dataset.Dataset, such as a SegYReader.

        trace_header_format: The class which defines the layout of the trace header. Defaults to TraceHeaderRev1.

        encoding: Optional encoding for text data. Typically 'cp037' for EBCDIC or 'ascii' for ASCII. If omitted, the
            seg_y_data object will be queries for an encoding property.

        endian: Big endian by default. If omitted, the seg_y_data object will be queried for an encoding property.

        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 one.

    Raises:
        UnsupportedEncodingError: If the specified encoding is neither ASCII nor EBCDIC
        UnicodeError: If textual data provided cannot be encoded into the required encoding.
    """

    progress_callback = progress if progress is not None else lambda p: None

    if not callable(progress_callback):
        raise TypeError("write_segy(): progress callback must be callable")

    encoding = encoding or (hasattr(dataset, 'encoding')
                            and dataset.encoding) or ASCII

    if not is_supported_encoding(encoding):
        raise UnsupportedEncodingError("Writing SEG Y", encoding)

    write_textual_reel_header(fh, dataset.textual_reel_header, encoding)
    write_binary_reel_header(fh, dataset.binary_reel_header, endian)
    write_extended_textual_headers(fh, dataset.extended_textual_header,
                                   encoding)

    trace_header_packer = make_header_packer(trace_header_format, endian)

    num_traces = dataset.num_traces()

    for trace_index in dataset.trace_indexes():
        write_trace_header(fh, dataset.trace_header(trace_index),
                           trace_header_packer)
        write_trace_samples(fh,
                            dataset.trace_samples(trace_index),
                            dataset.data_sample_format,
                            endian=endian)
        progress_callback(trace_index / num_traces)

    progress_callback(1)
Example #3
0
def write_segy(fh,
               seg_y_data,
               encoding=None,
               trace_header_format=TraceHeaderRev1,
               endian='>',
               progress=None):
    """
    Args:
        fh: A file-like object open for binary write, positioned to write the textual reel header.

        seg_y_data:  An object from which the headers and trace_samples data can be retrieved. Requires the following
            properties and methods:
              seg_y_data.textual_reel_header
              seg_y_data.binary_reel_header
              seg_y_data.extended_textual_header
              seg_y_data.trace_indexes
              seg_y_data.trace_header(trace_index)
              seg_y_data.trace_samples(trace_index)

              seg_y_data.encoding
              seg_y_data.endian

              One such legitimate object would be a SegYReader instance.

        trace_header_format: The class which defines the layout of the trace header. Defaults to TraceHeaderRev1.

        encoding: Optional encoding for text data. Typically 'cp037' for EBCDIC or 'ascii' for ASCII. If omitted, the
            seg_y_data object will be queries for an encoding property.

        endian: Big endian by default. If omitted, the seg_y_data object will be queried for an encoding property.

        progress: An optional progress bar object.

    Raises:
        UnsupportedEncodingError: If the specified encoding is neither ASCII nor EBCDIC
        UnicodeError: If textual data provided cannot be encoded into the required encoding.
    """

    encoding = encoding or (hasattr(seg_y_data, 'encoding')
                            and seg_y_data.encoding) or ASCII

    if not is_supported_encoding(encoding):
        raise UnsupportedEncodingError("Writing SEG Y", encoding)

    write_textual_reel_header(fh, seg_y_data.textual_reel_header, encoding)
    write_binary_reel_header(fh, seg_y_data.binary_reel_header, endian)
    write_extended_textual_headers(fh, seg_y_data.extended_textual_header,
                                   encoding)

    trace_header_packer = make_header_packer(trace_header_format, endian)

    for trace_index in seg_y_data.trace_indexes():
        write_trace_header(fh, seg_y_data.trace_header(trace_index),
                           trace_header_packer)
        write_trace_samples(fh,
                            seg_y_data.trace_samples(trace_index),
                            seg_y_data.data_sample_format,
                            endian=endian)
Example #4
0
    def test_roundtrip(self, write_header, endian):
        with BytesIO() as write_stream:
            write_binary_reel_header(write_stream, write_header, endian)
            written_stream = write_stream.getvalue()

        with BytesIO(written_stream) as read_stream:
            read_header = read_binary_reel_header(read_stream, endian)

        assert are_equal(write_header, read_header)
Example #5
0
    def test_roundtrip(self, write_header, endian):
        with BytesIO() as write_stream:
            write_binary_reel_header(write_stream, write_header, endian)
            written_stream = write_stream.getvalue()

        with BytesIO(written_stream) as read_stream:
            read_header = read_binary_reel_header(read_stream, endian)

        self.assertTrue(are_equal(write_header, read_header))
Example #6
0
File: writer.py Project: rth/segpy
def write_segy(fh,
               seg_y_data,
               encoding=None,
               trace_header_format=TraceHeaderRev1,
               endian='>',
               progress=None):
    """
    Args:
        fh: A file-like object open for binary write, positioned to write the textual reel header.

        seg_y_data:  An object from which the headers and trace_samples data can be retrieved. Requires the following
            properties and methods:
              seg_y_data.textual_reel_header
              seg_y_data.binary_reel_header
              seg_y_data.extended_textual_header
              seg_y_data.trace_indexes
              seg_y_data.trace_header(trace_index)
              seg_y_data.trace_samples(trace_index)

              seg_y_data.encoding
              seg_y_data.endian
              seg_y_data.data_sample_format

              One such legitimate object would be a SegYReader instance.

        trace_header_format: The class which defines the layout of the trace header. Defaults to TraceHeaderRev1.

        encoding: Optional encoding for text data. Typically 'cp037' for EBCDIC or 'ascii' for ASCII. If omitted, the
            seg_y_data object will be queries for an encoding property.

        endian: Big endian by default. If omitted, the seg_y_data object will be queried for an encoding property.

        progress: An optional progress bar object.

    Raises:
        UnsupportedEncodingError: If the specified encoding is neither ASCII nor EBCDIC
        UnicodeError: If textual data provided cannot be encoded into the required encoding.
    """

    encoding = encoding or (hasattr(seg_y_data, 'encoding') and seg_y_data.encoding) or ASCII

    if not is_supported_encoding(encoding):
        raise UnsupportedEncodingError("Writing SEG Y", encoding)

    write_textual_reel_header(fh, seg_y_data.textual_reel_header, encoding)
    write_binary_reel_header(fh, seg_y_data.binary_reel_header, endian)
    write_extended_textual_headers(fh, seg_y_data.extended_textual_header, encoding)

    trace_header_packer = make_header_packer(trace_header_format, endian)

    for trace_index in seg_y_data.trace_indexes():
        write_trace_header(fh, seg_y_data.trace_header(trace_index), trace_header_packer)
        write_trace_samples(fh, seg_y_data.trace_samples(trace_index), seg_y_data.data_sample_format, endian=endian)
Example #7
0
def write_segy(fh,
               dataset,
               encoding=None,
               trace_header_format=TraceHeaderRev1,
               endian='>',
               progress=None):
    """
    Args:
        fh: A file-like object open for binary write, positioned to write the textual reel header.

        dataset: An object implementing the interface of segpy.dataset.Dataset, such as a SegYReader.

        trace_header_format: The class which defines the layout of the trace header. Defaults to TraceHeaderRev1.

        encoding: Optional encoding for text data. Typically 'cp037' for EBCDIC or 'ascii' for ASCII. If omitted, the
            seg_y_data object will be queries for an encoding property.

        endian: Big endian by default. If omitted, the dataset object will be queried for an encoding property.

        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 one.

    Raises:
        UnsupportedEncodingError: If the specified encoding is neither ASCII nor EBCDIC
        UnicodeError: If textual data provided cannot be encoded into the required encoding.
    """

    progress_callback = progress if progress is not None else lambda p: None

    if not callable(progress_callback):
        raise TypeError("write_segy(): progress callback must be callable")

    encoding = encoding or (hasattr(dataset, 'encoding') and dataset.encoding) or ASCII

    if not is_supported_encoding(encoding):
        raise UnsupportedEncodingError("Writing SEG Y", encoding)

    write_textual_reel_header(fh, dataset.textual_reel_header, encoding)
    write_binary_reel_header(fh, dataset.binary_reel_header, endian)
    write_extended_textual_headers(fh, dataset.extended_textual_header, encoding)

    trace_header_packer = make_header_packer(trace_header_format, endian)

    num_traces = dataset.num_traces()

    for trace_index in dataset.trace_indexes():
        write_trace_header(fh, dataset.trace_header(trace_index), trace_header_packer)
        write_trace_samples(fh, dataset.trace_samples(trace_index), dataset.data_sample_format, endian=endian)
        progress_callback(trace_index / num_traces)

    progress_callback(1)
Example #8
0
def write_segy(fh,
               dataset,
               encoding=None,
               trace_header_format=TraceHeaderRev1,
               endian='>',
               progress=None):
    """
    Args:
        fh: A file-like object open for binary write, positioned to write the textual reel header.

        dataset: An object implementing the interface of segpy.dataset.Dataset, such as a SegYReader.

        trace_header_format: The class which defines the layout of the trace header. Defaults to TraceHeaderRev1.

        encoding: Optional encoding for text data. Typically 'cp037' for EBCDIC or 'ascii' for ASCII. If omitted, the
            seg_y_data object will be queries for an encoding property.

        endian: Big endian by default. If omitted, the seg_y_data object will be queried for an encoding property.

        progress: An optional progress bar object.

    Raises:
        UnsupportedEncodingError: If the specified encoding is neither ASCII nor EBCDIC
        UnicodeError: If textual data provided cannot be encoded into the required encoding.
    """

    encoding = encoding or (hasattr(dataset, 'encoding') and dataset.encoding) or ASCII

    if not is_supported_encoding(encoding):
        raise UnsupportedEncodingError("Writing SEG Y", encoding)

    write_textual_reel_header(fh, dataset.textual_reel_header, encoding)
    write_binary_reel_header(fh, dataset.binary_reel_header, endian)
    write_extended_textual_headers(fh, dataset.extended_textual_header, encoding)

    trace_header_packer = make_header_packer(trace_header_format, endian)

    for trace_index in dataset.trace_indexes():
        write_trace_header(fh, dataset.trace_header(trace_index), trace_header_packer)
        write_trace_samples(fh, dataset.trace_samples(trace_index), dataset.data_sample_format, endian=endian)
Example #9
0
    binary_reel_header.sample_interval = int(
        args.sample_rate * 1000)  # samples length microseconds
    binary_reel_header.num_samples = len(itimes)  # number of samples
    binary_reel_header.data_traces_per_ensemble = 0  # len(data) # also must be # not sure how to work this out, maybe I need to scan the file first or after insert it
    binary_reel_header.auxiliary_traces_per_ensemble = 0
    binary_reel_header.trace_sorting = 4  # http://oivdoc91.vsg3d.com/APIS/RefManCpp/struct_so_v_r_segy_file_header.html#a612dab3b4d9c671ba6554a8fb4a88057
    binary_reel_header.format_revision_num = 256  # 0 or 1 TODO move to 1
    binary_reel_header.data_sample_format = args.dtype  # see binary header def.py file as it changes by revision. 1 is always ibm float
    if args.use_extended_header:
        binary_reel_header.num_extended_textual_headers = len(
            extended_textual_header
        )  # see binary header def.py file as it changes by revision. 1 is always ibm float

    # Write headers
    toolkit.write_textual_reel_header(fo, textual_reel_header, segyencoding)
    toolkit.write_binary_reel_header(fo, binary_reel_header, endian)
    if args.use_extended_header:
        toolkit.write_extended_textual_headers(fo, extended_textual_header,
                                               segyencoding)

    # Pre-Format trace headerf
    trace_header_format = toolkit.make_header_packer(
        segpy.trace_header.TraceHeaderRev1, endian)

    if args.seismic_dimensions == 3:
        # either iterate over the grid for 3d
        xxlines, iinlines = np.meshgrid(xlines, inlines)
        trace_iter = np.vstack([iinlines.flat, xxlines.flat]).T
    else:
        # or for 2d just iterate over cdp an sp
        trace_iter = np.vstack([inlines_r, xlines_r]).T
Example #10
0
 def write_binary_reel_header(self, binary_reel_header):
     self._fh.seek(REEL_HEADER_NUM_BYTES)
     write_binary_reel_header(self._fh, binary_reel_header, self.endian)
Example #11
0
 def write_binary_reel_header(self,binary_reel_header):
     self._fh.seek(REEL_HEADER_NUM_BYTES)
     write_binary_reel_header(self._fh, binary_reel_header, self.endian)
Example #12
0
def write_segy_file(data: pd.DataFrame, outfile: str):
    metadata = data.groupby(data.itrace).first()  # one row for each trace

    # lets work out the whole inline xline grid
    inlines_r = pd.Series(data.inline.unique())

    xlines_r = pd.Series(data.xline.unique())

    # choose interval as most common inline step, should I use min but ignore zero and nan?
    inline_int = inlines_r.diff().mode().values
    xline_int = xlines_r.diff().mode().values
    inlines = np.arange(inlines_r.min(), inlines_r.max(), inline_int)
    xlines = np.arange(xlines_r.min(), xlines_r.max(), xline_int)

    # find inline and xline with most data
    xline_lens = metadata.xline.groupby(metadata.xline).count()
    longest_xline_n = xline_lens.argmax()
    longest_xline = metadata[metadata.xline == longest_xline_n]
    inline_lens = metadata.inline.groupby(metadata.inline).count()
    longest_inline_n = inline_lens.argmax()
    longest_inline = metadata[metadata.inline == longest_inline_n]

    if SEISMIC_DIMENSIONS == 3:
        # work out bins spacing
        ibins = pylab.distances_along_curve(
            longest_xline[['x', 'y']]) / longest_xline.inline.diff().iloc[1:]
        ibin = ibins.mean()
        xbins = pylab.distances_along_curve(
            longest_inline[['x', 'y']]) / longest_inline.xline.diff().iloc[1:]
        xbin = xbins.mean()

        inline_angs = angles(longest_inline[['x', 'y']].values)
        inline_rot = inline_angs.mean()

        pi = metadata.iloc[
            0]  # reference point, might not be origin as we don't have that yet
        pj = metadata.iloc[100]  # use this for a test
        gd = Grid(pi, inline_rot, ibin, xbin)
        x, y = gd.ix2xy(pj.inline, pj.xline)

        # check the predicted coords are right withing a meter
        np.testing.assert_allclose(pj.x, x, atol=1)
        np.testing.assert_allclose(pj.y, y, atol=1)

    logger.info("Writing segy {}".format(OUTFILE))
    tmin = data.t.min()
    # times to interpolate onto
    itimes = np.arange(tmin, data.t.max() + SAMPLE_RATE, SAMPLE_RATE)

    template_trace = segpy.trace_header.TraceHeaderRev1()
    template_binary_reel_header = segpy.binary_reel_header.BinaryReelHeader()

    header = []
    textual_reel_header = get_header(header)
    metadata = data.groupby(data.itrace).first()

    # Format text header
    if USE_EXTENDED_HEADER:
        logger.debug("Formating extended textual header")
        extended_textual_header = toolkit.format_extended_textual_header(
            '', DEFAULT_SEGY_ENCODING)
    else:
        extended_textual_header = toolkit.format_extended_textual_header(
            ''.join(header), DEFAULT_SEGY_ENCODING)

    # Format binary header
    binary_reel_header = template_binary_reel_header
    # samples length microseconds
    binary_reel_header.sample_interval = int(SAMPLE_RATE * 1000)

    # number of samples
    binary_reel_header.num_samples = len(itimes)
    # len(data) # also must be # not sure how to work this out,
    #  maybe I need to scan the file first or after insert it
    binary_reel_header.data_traces_per_ensemble = 0
    binary_reel_header.auxiliary_traces_per_ensemble = 0
    # http://oivdoc91.vsg3d.com/APIS/RefManCpp/struct_so_v_r_segy_file_header.html#a612dab3b4d9c671ba6554a8fb4a88057
    binary_reel_header.trace_sorting = 4

    # 0 or 1 TODO move to 1
    binary_reel_header.format_revision_num = 256

    # see binary header def.py file as it changes by revision. 1 is always ibm float
    binary_reel_header.data_sample_format = DTYPE
    if USE_EXTENDED_HEADER:
        # see binary header def.py file as it changes by revision. 1 is always ibm float
        binary_reel_header.num_extended_textual_headers = len(
            extended_textual_header)

        # Pre-Format trace headerf
        trace_header_format = toolkit.make_header_packer(
            segpy.trace_header.TraceHeaderRev1, ENDIAN)

    if SEISMIC_DIMENSIONS == 3:
        # either iterate over the grid for 3d
        xxlines, iinlines = np.meshgrid(xlines, inlines)
        trace_iter = np.vstack([iinlines.flat, xxlines.flat]).T
    else:
        # or for 2d just iterate over cdp an sp
        trace_iter = np.vstack([inlines_r, xlines_r]).T

    i = 0
    tracen = 1

    with open(outfile, 'wb') as fo:
        # Write headers
        toolkit.write_textual_reel_header(fo, textual_reel_header,
                                          DEFAULT_SEGY_ENCODING)
        toolkit.write_binary_reel_header(fo, binary_reel_header, ENDIAN)
        if USE_EXTENDED_HEADER:
            toolkit.write_extended_textual_headers(fo, extended_textual_header,
                                                   DEFAULT_SEGY_ENCODING)

        for inline, xline in trace_iter:
            i += 1
            if ((metadata.inline == inline) * (metadata.xline == xline)):
                trace = data[(data.inline == inline) * (data.xline == xline)]
                metatrace = metadata[(metadata.inline == inline) *
                                     (metadata.xline == xline)]
                x = metatrace.x
                y = metatrace.y
                times = trace.t.values
                vels = trace.v.values
            elif SEISMIC_DIMENSIONS == 3:
                x, y = gd.ix2xy(inline, xline)
                times = itimes
                vels = np.zeros(itimes.shape)
            else:
                logger.warning("inline/xline or cdp/sp not found", inline,
                               xline)
                continue

            cdp = inline
            sp = xline

            if i % 1000 == 0:
                logger.debug("Writing trace: "
                             "{: 8.0f}/{}, {: 6.2f}%".format(
                                 i, len(trace_iter),
                                 (1.0 * i / len(trace_iter)) * 100))

            if len(vels) == 0:
                logger.error("Error no vels on trace", i)
                continue

            # interpolate data
            samples = np.interp(itimes, times, vels)

            # ensure datatype is ok
            samples = np.require(samples, dtype='d')

            # Format trace header
            trace_header = template_trace
            trace_header.line_sequence_num = 1000 + tracen
            trace_header.field_record_num = tracen
            trace_header.trace_num = tracen
            if SEISMIC_DIMENSIONS == 3:
                trace_header.file_sequence_num = inline
                trace_header.ensemble_num = xline
                trace_header.inline_number = inline
                trace_header.crossline_number = xline
            else:
                trace_header.file_sequence_num = 1000 + tracen
                trace_header.ensemble_num = cdp
                trace_header.shotpoint_number = sp
            trace_header.num_samples = len(samples)  # number of samples
            trace_header.sample_interval = SAMPLE_RATE  # sample interval
            trace_header.cdp_x = x
            trace_header.cdp_y = y
            trace_header.source_x = x
            trace_header.source_y = y

            # write trace header and data
            toolkit.write_trace_header(fo,
                                       trace_header,
                                       trace_header_format,
                                       pos=None)
            toolkit.write_trace_samples(fo,
                                        samples=samples,
                                        ctype=SEG_Y_TYPE,
                                        endian=ENDIAN,
                                        pos=None)

            tracen += 1
        logger.debug("Writing trace: {: 8.0f}/{}, {: 6.2f}%".format(
            i, len(trace_iter), (1.0 * i / len(trace_iter)) * 100))