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)
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)
def write_trace_samples(self,trace_index,samples): num_samples_in_trace = self.num_trace_samples(trace_index) start_pos = (self.trace_position(trace_index) + TRACE_HEADER_NUM_BYTES) if not num_samples_in_trace==len(samples): raise ValueError( "Length of samples {} does not fit in trace size {}".format(len(samples),num_samples_in_trace)) write_trace_samples(self._fh, samples, self.data_sample_format, pos=start_pos, endian='>')
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)
def write_trace_samples(self, trace_index, samples): num_samples_in_trace = self.num_trace_samples(trace_index) start_pos = self.trace_position(trace_index) + TRACE_HEADER_NUM_BYTES if not num_samples_in_trace == len(samples): raise ValueError( "Length of samples {} does not fit in trace size {}".format(len(samples), num_samples_in_trace) ) write_trace_samples(self._fh, samples, self.data_sample_format, pos=start_pos, endian=">")
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)
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)
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)
trace_header.shotpoint_number = sp trace_header.num_samples = len(samples) # number of samples trace_header.sample_interval = args.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, seg_y_type=SEG_Y_TYPE, endian=endian, pos=None) tracen += 1 print("Writing trace: {: 8.0f}/{}, {: 6.2f}%".format( i, len(trace_iter), (1.0 * i / len(trace_iter)) * 100)) print("Done") if not fo.closed: fo.close() if args.test: #Validate outfile from segpy.reader import create_reader from segpy.writer import write_segy def load_save(in_filename, out_filename):
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))