def merge_segy_files(output_path, bar=True, **kwargs): """Merge segy files into a single segy file. Parameters ---------- output_path : str Path to output file. bar : bool Whether to how progress bar (default = True). kwargs : dict Keyword arguments to index input segy files. Returns ------- """ segy_index = SegyFilesIndex(**kwargs, name='data') spec = segyio.spec() spec.sorting = None spec.format = 1 spec.tracecount = sum(segy_index.tracecounts) with segyio.open(segy_index.indices[0], strict=False) as file: spec.samples = file.samples with segyio.create(output_path, spec) as dst: i = 0 iterable = tqdm(segy_index.indices) if bar else segy_index.indices for index in iterable: with segyio.open(index, strict=False) as src: dst.trace[i:i + src.tracecount] = src.trace dst.header[i:i + src.tracecount] = src.header for j in range(src.tracecount): dst.header[i + j].update( {segyio.TraceField.TRACE_SEQUENCE_FILE: i + j + 1}) i += src.tracecount
def convert_to_segy(self, out_file): spec = segyio.spec() spec.samples = self.zslices spec.offsets = [0] spec.xlines = self.xlines spec.ilines = self.ilines spec.sorting = 2 # seimcic-zfp stores the binary header from the source SEG-Y file. # In case someone forgot to do this, give them IEEE data_sample_format_code = bytes_to_int( self.headerbytes[DISK_BLOCK_BYTES + 3225:DISK_BLOCK_BYTES + 3227]) if data_sample_format_code in [1, 5]: spec.format = data_sample_format_code else: spec.format = 5 with warnings.catch_warnings(): # segyio will warn us that out padded cube is not contiguous. This is expected, and safe. warnings.filterwarnings( "ignore", message="Implicit conversion to contiguous array") with segyio.create(out_file, spec) as segyfile: self.read_variant_headers() # Doing this is fine now there is decent caching on the loader segyfile.trace = [ self.get_trace(i) for i in range(len(segyfile.trace)) ] segyfile.header = [ self.gen_trace_header(i) for i in range(len(segyfile.header)) ] with open(out_file, "r+b") as f: f.write(self.headerbytes[DISK_BLOCK_BYTES:DISK_BLOCK_BYTES + SEGY_FILE_HEADER_BYTES])
def learn7(): read_path = 'E:/Research/data/F3_entire.segy' save_path = 'F:/test1.segy' col_num = 1000 with segyio.open(read_path) as src: # ----- 输入数据处理 input_list = src.trace.raw[:col_num] header_list = [] for i1 in range(col_num): header_list.append(src.header[i1]) # ----- print('@ 开始保存新Segy文件,原文件共{0}条数据,单条长{1};新内容共{2}条数据,单条长{3}。'.format( len(src.trace), len(src.samples), len(input_list), len(input_list[0])), end='') spec = segyio.spec() spec.sorting = src.sorting spec.format = src.format spec.samples = input_list[0] spec.ilines = src.ilines spec.xlines = src.xlines spec.tracecount = len(input_list) print('SegyIO信息:src.tracecount={0},src.samples长度={1}。'.format( src.tracecount, len(src.samples))) with segyio.create(save_path, spec) as dst: dst.text[0] = src.text[0] dst.bin = src.bin dst.header = header_list dst.trace = input_list print('@ 提示:“{0}”文件已经写入完成'.format(save_path))
def main(): if len(sys.argv) < 3: sys.exit("Usage: {} [source-file] [destination-file]".format( sys.argv[0])) sourcefile = sys.argv[1] destfile = sys.argv[2] with segyio.open(sourcefile) as src: spec = segyio.spec() spec.sorting = int(src.sorting) spec.format = int(src.format) spec.samples = 50 spec.ilines = src.ilines[:5] spec.xlines = src.xlines[:5] with segyio.create(destfile, spec) as dst: # Copy all textual headers, including possible extended for i in range(1 + src.ext_headers): dst.text[i] = src.text[i] # copy the binary header, then insert the modifications needed for # the new shape dst.bin = src.bin dst.bin = { segyio.BinField.Samples: 50, segyio.BinField.Traces: 5 * 5 } # Copy all headers in the new inlines. Since we know we're copying # the five first we don't have to take special care to update # headers dst.header.iline = src.header.iline # the copy traces (in line mode) dst.iline = src.iline
def main(): if len(sys.argv) < 2: sys.exit('Usage: {} [output]'.format(sys.argv[0])) spec = segyio.spec() filename = sys.argv[1] spec.format = 1 spec.samples = range(25) spec.tracecount = 61 with segyio.create(filename, spec) as f: trno = 0 keys = [2, 3, 5, 8] lens = [10, 12, 13, 26] for key, length in zip(keys, lens): for i in range(length): f.header[trno].update( offset=1, fldr=key, grnofr=(i % 2) + 1, tracf=spec.tracecount - i, ) trace = np.linspace(start=key, stop=key + 1, num=len(spec.samples)) f.trace[trno] = trace trno += 1 f.bin.update()
def create_segy(path): """ Create file with data suitable for relevant tests. | xlines-ilines | 1 | 2 | 3 | |---------------|---------------|---------------|---------------| | 10 | 100, 101, 102 | 106, 107, 108 | 112, 113, 114 | | 11 | 103, 104, 105 | 109, 110, 111 | 115, 116, 177 | """ spec = segyio.spec() spec.sorting = 2 spec.format = 1 spec.samples = [0, 1, 2] spec.ilines = [1, 2, 3] spec.xlines = [10, 11] with segyio.create(path, spec) as f: data = 100 tr = 0 for il in spec.ilines: for xl in spec.xlines: f.header[tr] = {segyio.su.iline: il, segyio.su.xline: xl} data = data + len(spec.samples) f.trace[tr] = np.arange(start=data - len(spec.samples), stop=data, step=1, dtype=np.single) tr += 1 f.bin.update(tsort=segyio.TraceSortingFormat.INLINE_SORTING)
def convert_to_segy(self, out_file): # Currently only works for default SGZ layout (?) assert (self.blockshape[0] == 4) assert (self.blockshape[1] == 4) spec = segyio.spec() spec.samples = self.zslices spec.offsets = [0] spec.xlines = self.xlines spec.ilines = self.ilines spec.sorting = 2 # seimcic-zfp stores the binary header from the source SEG-Y file. # In case someone forgot to do this, give them IEEE data_sample_format_code = bytes_to_int( self.headerbytes[DISK_BLOCK_BYTES+3225: DISK_BLOCK_BYTES+3227]) if data_sample_format_code in [1, 5]: spec.format = data_sample_format_code else: spec.format = 5 with warnings.catch_warnings(): # segyio will warn us that out padded cube is not contiguous. This is expected, and safe. warnings.filterwarnings("ignore", message="Implicit conversion to contiguous array") with segyio.create(out_file, spec) as segyfile: self.read_variant_headers() for i, iline in enumerate(spec.ilines): if i % self.blockshape[0] == 0: decompressed = self.loader.read_and_decompress_il_set(i) for h in range(i * len(spec.xlines), (i + 1) * len(spec.xlines)): segyfile.header[h] = self.gen_trace_header(h) segyfile.iline[iline] = decompressed[i % self.blockshape[0], 0:self.n_xlines, 0:self.n_samples] with open(out_file, "r+b") as f: f.write(self.headerbytes[DISK_BLOCK_BYTES: DISK_BLOCK_BYTES + SEGY_FILE_HEADER_BYTES])
def test_create_sgy_skip_lines(self): fname = "lines.sgy" dstfile = "lines-halved.sgy" with TestContext("create_sgy_skip_lines") as context: mklines(fname) with segyio.open(fname, "r") as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = src.samples spec.ilines = src.ilines[::2] spec.xlines = src.xlines[::2] with segyio.create(dstfile, spec) as dst: # use the inline headers as base dst.header.iline = src.header.iline[::2] # then update crossline numbers from the crossline headers for xl in dst.xlines: f = next(src.header.xline[xl])[TraceField.CROSSLINE_3D] dst.header.xline[xl] = {TraceField.CROSSLINE_3D: f} # but we override the last xline to be 6, not 5 dst.header.xline[5] = {TraceField.CROSSLINE_3D: 6} dst.iline = src.iline[::2] with segyio.open(dstfile, "r") as f: self.assertListEqual(list(f.ilines), list(spec.ilines)) self.assertListEqual(list(f.xlines), [1, 3, 6]) self.assertAlmostEqual(1, f.iline[1][0][0], places=4) self.assertAlmostEqual(3.004, f.iline[3][0][4], places=4) self.assertAlmostEqual(3.014, f.iline[3][1][4], places=4) self.assertAlmostEqual(7.023, f.iline[7][2][3], places=4)
def test_create_sgy(self): with TestContext("create_sgy") as context: context.copy_file(self.filename) src_file = "small.sgy" dst_file = "small_created.sgy" with segyio.open(src_file, "r") as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = src.samples spec.ilines = src.ilines spec.xlines = src.xlines with segyio.create(dst_file, spec) as dst: dst.text[0] = src.text[0] dst.bin = src.bin # copy all headers dst.header = src.header for i, srctr in enumerate(src.trace): dst.trace[i] = srctr dst.trace = src.trace # this doesn't work yet, some restructuring is necessary # if it turns out to be a desired feature it's rather easy to do #for dsth, srch in zip(dst.header, src.header): # dsth = srch #for dsttr, srctr in zip(dst.trace, src.trace): # dsttr = srctr self.assertTrue(filecmp.cmp(src_file, dst_file))
def test_create_from_naught(self): fname = "test-data/mk.sgy" spec = segyio.spec() spec.format = 5 spec.sorting = 2 spec.samples = 150 spec.ilines = range(1, 11) spec.xlines = range(1, 6) with segyio.create(fname, spec) as dst: tr = np.arange( start = 1.000, stop = 1.151, step = 0.001, dtype = np.single) for i in xrange( len( dst.trace ) ): dst.trace[i] = tr tr += 1.000 for il in spec.ilines: dst.header.iline[il] = { TraceField.INLINE_3D: il } for xl in spec.xlines: dst.header.xline[xl] = { TraceField.CROSSLINE_3D: xl } # Set header field 'offset' to 1 in all headers dst.header = { TraceField.offset: 1 } with segyio.open(fname, "r") as f: self.assertAlmostEqual(1, f.trace[0][0], places = 4) self.assertAlmostEqual(1.001, f.trace[0][1], places = 4) self.assertAlmostEqual(1.149, f.trace[0][-1], places = 4) self.assertAlmostEqual(50.100, f.trace[-1][100], places = 4) self.assertEqual(f.header[0][TraceField.offset], f.header[1][TraceField.offset]) self.assertEqual(1, f.header[1][TraceField.offset])
def from_array_unstructured( filename: Path, data: np.ndarray, format: segyio.SegySampleFormat = segyio.SegySampleFormat.IBM_FLOAT_4_BYTE, dt: int = 4000, delrt: int = 0, ) -> None: dt = int(dt) delrt = int(delrt) data = np.asarray(data) dimensions = len(data.shape) if dimensions != 2: raise ValueError(f"Expected 2 dimensions, {dimensions} was given") spec = segyio.spec() spec.format = format spec.sorting = segyio.TraceSortingFormat.UNKNOWN_SORTING spec.tracecount = np.size(data, 0) spec.samples = list(range(np.size(data, 1))) samplecount = len(spec.samples) with segyio.create(filename, spec) as f: for tr in range(f.tracecount): f.header[tr] = { segyio.su.tracf: tr, segyio.su.cdpt: tr, segyio.su.ns: samplecount, segyio.su.dt: dt, segyio.su.delrt: delrt, } f.trace[tr] = data[tr, :] f.bin.update(tsort=spec.sorting, hdt=dt, dto=dt)
def mklines(fname): spec = segyio.spec() spec.format = 5 spec.sorting = 2 spec.samples = range(10) spec.ilines = range(1, 11) spec.xlines = range(1, 6) # create a file with 10 inlines, with values on the form l.0tv where # l = line no # t = trace number (within line) # v = trace value # i.e. 2.043 is the value at inline 2's fourth trace's third value with segyio.create(fname, spec) as dst: ln = np.arange(start=0, stop=0.001 * (5 * 10), step=0.001, dtype=np.single).reshape(5, 10) for il in spec.ilines: ln += 1 dst.header.iline[il] = {TraceField.INLINE_3D: il} dst.iline[il] = ln for xl in spec.xlines: dst.header.xline[xl] = {TraceField.CROSSLINE_3D: xl}
def test_ref_new_file(small): # this is the case the trace.ref feature was designed to support, namely # creating a file trace-by-trace based on some transformation of another # file, or an operation on multiple, where the trace index itself is # uninteresting. orig = str(small.dirname + '/small.sgy') fresh = str(small.dirname + '/fresh.sgy') with segyio.open(orig) as src: spec = segyio.tools.metadata(src) with segyio.create(fresh, spec) as dst: dst.text[0] = src.text[0] dst.bin = src.bin # copy all headers dst.header = src.header with dst.trace.ref as ref: for x, y in zip(ref[:], src.trace): # x default-inits to 0, so += is essentially copyto() # since traces hasn't been written yet, this has to handle # read miss errors x += y with segyio.open(fresh) as dst: npt.assert_array_almost_equal(src.trace.raw[:], dst.trace.raw[:])
def test_create_sgy_skip_lines(tmpdir): mklines(tmpdir / "lines.sgy") with segyio.open(tmpdir / "lines.sgy") as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = src.samples spec.ilines = src.ilines[::2] spec.xlines = src.xlines[::2] with segyio.create(tmpdir / "lines-halved.sgy", spec) as dst: # use the inline headers as base dst.header.iline = src.header.iline[::2] # then update crossline numbers from the crossline headers for xl in dst.xlines: f = next(src.header.xline[xl])[TraceField.CROSSLINE_3D] dst.header.xline[xl] = {TraceField.CROSSLINE_3D: f} # but we override the last xline to be 6, not 5 dst.header.xline[5] = {TraceField.CROSSLINE_3D: 6} dst.iline = src.iline[::2] with segyio.open(tmpdir / "lines-halved.sgy") as f: assert list(f.ilines) == list(spec.ilines) assert list(f.xlines) == [1, 3, 6] assert 1 == approx(f.iline[1][0][0], abs=1e-4) assert 3.004 == approx(f.iline[3][0][4], abs=1e-4) assert 3.014 == approx(f.iline[3][1][4], abs=1e-4) assert 7.023 == approx(f.iline[7][2][3], abs=1e-4)
def test_create_sgy(small): orig = str(small.dirname + '/small.sgy') fresh = str(small.dirname + '/fresh.sgy') with segyio.open(orig) as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = src.samples spec.ilines = src.ilines spec.xlines = src.xlines with segyio.create(fresh, spec) as dst: dst.text[0] = src.text[0] dst.bin = src.bin # copy all headers dst.header = src.header for i, srctr in enumerate(src.trace): dst.trace[i] = srctr dst.trace = src.trace # this doesn't work yet, some restructuring is necessary # if it turns out to be a desired feature it's rather easy to do # for dsth, srch in zip(dst.header, src.header): # dsth = srch # for dsttr, srctr in zip(dst.trace, src.trace): # dsttr = srctr assert filecmp.cmp(orig, fresh)
def segy_write(data, sourceX, sourceZ, groupX, groupZ, dt, filename, sourceY=None, groupY=None, elevScalar=-1000, coordScalar=-1000): nt = data.shape[0] nxrec = len(groupX) if sourceY is None and groupY is None: sourceY = np.zeros(1, dtype='int') groupY = np.zeros(nxrec, dtype='int') # Create spec object spec = segyio.spec() spec.ilines = np.arange(nxrec) # dummy trace count spec.xlines = np.zeros(1, dtype='int') # assume coordinates are already vectorized for 3D spec.samples = range(nt) spec.format=1 spec.sorting=1 with segyio.create(filename, spec) as segyfile: for i in range(nxrec): segyfile.header[i] = { segyio.su.tracl : i+1, segyio.su.tracr : i+1, segyio.su.fldr : 1, segyio.su.tracf : i+1, segyio.su.sx : int(np.round(sourceX[0] * np.abs(coordScalar))), segyio.su.sy : int(np.round(sourceY[0] * np.abs(coordScalar))), segyio.su.selev: int(np.round(sourceZ[0] * np.abs(elevScalar))), segyio.su.gx : int(np.round(groupX[i] * np.abs(coordScalar))), segyio.su.gy : int(np.round(groupY[i] * np.abs(coordScalar))), segyio.su.gelev : int(np.round(groupZ[i] * np.abs(elevScalar))), segyio.su.dt : int(np.round(dt, decimals=6)*1e3), segyio.su.scalel : int(elevScalar), segyio.su.scalco : int(coordScalar) } segyfile.trace[i] = data[:, i] segyfile.dt=int(np.round(dt, decimals=6)*1e3)
def test_create_from_naught(tmpdir): spec = segyio.spec() spec.format = 5 spec.sorting = 2 spec.samples = range(150) spec.ilines = range(1, 11) spec.xlines = range(1, 6) with segyio.create(tmpdir / "mk.sgy", spec) as dst: tr = np.arange(start=1.000, stop=1.151, step=0.001, dtype=np.single) for i in range(len(dst.trace)): dst.trace[i] = tr tr += 1.000 for il in spec.ilines: dst.header.iline[il] = {TraceField.INLINE_3D: il} for xl in spec.xlines: dst.header.xline[xl] = {TraceField.CROSSLINE_3D: xl} # Set header field 'offset' to 1 in all headers dst.header = {TraceField.offset: 1} with segyio.open(tmpdir / "mk.sgy") as f: assert 1 == approx(f.trace[0][0], abs=1e-4) assert 1.001 == approx(f.trace[0][1], abs=1e-4) assert 1.149 == approx(f.trace[0][-1], abs=1e-4) assert 50.100 == approx(f.trace[-1][100], abs=1e-4) assert f.header[0][TraceField.offset] == f.header[1][TraceField.offset] assert 1 == f.header[1][TraceField.offset]
def test_create_sgy_shorter_traces(small): orig = str(small.dirname + '/small.sgy') fresh = str(small.dirname + '/small_created_shorter.sgy') with segyio.open(orig) as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = src.samples[:20] # reduces samples per trace spec.ilines = src.ilines spec.xlines = src.xlines with segyio.create(fresh, spec) as dst: for i, srch in enumerate(src.header): dst.header[i] = srch d = {TraceField.INLINE_3D: srch[TraceField.INLINE_3D] + 100} dst.header[i] = d for lineno in dst.ilines: dst.iline[lineno] = src.iline[lineno] # alternative form using left-hand-side slices dst.iline[2:4] = src.iline for lineno in dst.xlines: dst.xline[lineno] = src.xline[lineno] with segyio.open(fresh) as dst: assert 20 == len(dst.samples) assert [x + 100 for x in src.ilines] == list(dst.ilines)
def test_create_sgy_shorter_traces(self): dstfile = self.filename.replace(".sgy", "-shorter.sgy") with segyio.open(self.filename, "r") as src: spec = segyio.spec() spec.format = int(src.format) spec.sorting = int(src.sorting) spec.samples = 20 # reduces samples per trace spec.ilines = src.ilines spec.xlines = src.xlines with segyio.create(dstfile, spec) as dst: for i, srch in enumerate(src.header): dst.header[i] = srch d = { TraceField.INLINE_3D: srch[TraceField.INLINE_3D] + 100 } dst.header[i] = d for lineno in dst.ilines: dst.iline[lineno] = src.iline[lineno] # alternative form using left-hand-side slices dst.iline[2:4] = src.iline buf = None # reuse buffer for speed for lineno in dst.xlines: dst.xline[lineno] = src.xline[lineno, buf] with segyio.open(dstfile, "r") as dst: self.assertEqual(20, dst.samples) self.assertEqual([x + 100 for x in src.ilines], list(dst.ilines))
def make_subcube(path, geometry, path_save, i_range, x_range): """ Make subcube from .sgy cube by removing some of its first and last ilines and xlines. Parameters ---------- path : str Location of original .sgy cube. geometry : SeismicGeometry Infered information about original cube. path_save : str Place to save subcube. i_range : array-like Ilines to include in subcube. x_range : array-like Xlines to include in subcube. Notes ----- Common use of this function is to remove not fully filled slices of .sgy cubes. """ i_low, i_high = i_range[0], i_range[-1] x_low, x_high = x_range[0], x_range[-1] with segyio.open(path, 'r', strict=False) as src: src.mmap() spec = segyio.spec() spec.sorting = int(src.sorting) spec.format = int(src.format) spec.samples = range(geometry.depth) spec.ilines = geometry.ilines[i_low:i_high] spec.xlines = geometry.xlines[x_low:x_high] with segyio.create(path_save, spec) as dst: # Copy all textual headers, including possible extended for i in range(1 + src.ext_headers): dst.text[i] = src.text[i] c = 0 for il_ in tqdm(spec.ilines): for xl_ in spec.xlines: tr_ = geometry.il_xl_trace[(il_, xl_)] dst.header[c] = src.header[tr_] dst.header[c][segyio.TraceField.FieldRecord] = il_ dst.header[c][segyio.TraceField.TRACE_SEQUENCE_FILE] = il_ dst.header[c][segyio.TraceField. TraceNumber] = xl_ - geometry.xlines_offset dst.header[c][ segyio.TraceField. TRACE_SEQUENCE_LINE] = xl_ - geometry.xlines_offset dst.trace[c] = src.trace[tr_] c += 1 dst.bin = src.bin dst.bin = {segyio.BinField.Traces: c} # Check that repaired cube can be opened in 'strict' mode with segyio.open(path_save, 'r', strict=True) as _: pass
def create_temp_segy(n, test_file, skew=False): data = np.zeros((n, n, n)) spec = segyio.spec() # to create a file from nothing, we need to tell segyio about the structure of # the file, i.e. its inline numbers, crossline numbers, etc. You can also add # more structural information, but offsets etc. have sensible defautls. This is # the absolute minimal specification for a N-by-M volume spec.sorting = 2 spec.format = 1 spec.iline = 189 spec.xline = 193 spec.samples = range(n) if skew: spec.ilines = range(n + n - 1) else: spec.ilines = range(n) spec.xlines = range(n) xl_val = range(n + 1, n + n + 1, 1) il_val = range(1, n + 1, 1) cdpx, cdpy = np.meshgrid(il_val, xl_val) if skew: for i, x in enumerate(cdpx): cdpx[i, :] = x + i with segyio.create(test_file, spec) as segyf: for i, (t, il, xl) in enumerate( zip(data.reshape(-1, n), cdpx.ravel(), cdpy.ravel()) ): segyf.header[i] = { segyio.su.offset: 1, 189: il, 193: xl, segyio.su.cdpx: il * 1000, segyio.su.cdpy: xl * 1000, segyio.su.ns: n, } segyf.trace[i] = t segyf.bin.update( tsort=segyio.TraceSortingFormat.INLINE_SORTING, hdt=1000, mfeet=1, jobid=1, lino=1, reno=1, ntrpr=n * n, nart=n * n, fold=1, ) if not skew: put_segy_texthead(test_file, create_default_texthead()) else: put_segy_texthead( test_file, create_default_texthead(override={7: "Is Skewed Test"}) )
def create_segy(path): """ Create file with data suitable for relevant tests. | xlines-ilines | 1 | 2 | 3 | |---------------|---------------|---------------|---------------| | 10 | 100, 101, 102 | 106, 107, 108 | 112, 113, 114 | | 11 | 103, 104, 105 | 109, 110, 111 | 115, 116, 177 | UTM coordinates for headers: | xlines-ilines | 1 | 2 | 3 | |---------------|-------------|---------------|---------------| | 10 | x=1, y=3 | x=2.1, y=3 | x=3.2, y=3 | | 11 | x=1, y=6.3 | x=2.1, y=6.3 | x=3.2, y=6.3 | """ spec = segyio.spec() spec.sorting = 2 spec.format = 1 spec.samples = [0, 1, 2] spec.ilines = [1, 2, 3] spec.xlines = [10, 11] # We use scaling constant of -10, meaning that values will be divided by 10 il_step_x = int(1.1 * 10) il_step_y = int(0 * 10) xl_step_x = int(0 * 10) xl_step_y = int(3.3 * 10) ori_x = int(1 * 10) ori_y = int(3 * 10) with segyio.create(path, spec) as f: data = 100 tr = 0 for il in spec.ilines: for xl in spec.xlines: f.header[tr] = { segyio.su.iline: il, segyio.su.xline: xl, segyio.su.cdpx: (il - spec.ilines[0]) * il_step_x + (xl - spec.xlines[0]) * xl_step_x + ori_x, segyio.su.cdpy: (il - spec.ilines[0]) * il_step_y + (xl - spec.xlines[0]) * xl_step_y + ori_y, segyio.su.scalco: -10, } data = data + len(spec.samples) f.trace[tr] = np.arange(start=data - len(spec.samples), stop=data, step=1, dtype=np.single) tr += 1 f.bin.update(tsort=segyio.TraceSortingFormat.INLINE_SORTING)
def duplicate_segy(input_file, output_file): ''' Duplicates a 2d data from disk into disk as a segy format ''' with segyio.open(input_file, ignore_geometry=True) as src: spec = segyio.tools.metadata(src) with segyio.create(output_file, spec) as dst: dst.text[0] = src.text[0] dst.bin = src.bin dst.header = src.header dst.trace = src.trace
def merge_segy_files(path, output_path, bar=True): """Merge segy files into a single segy file. Parameters ---------- path : str or list of str Paths of files to merge, can use glob patterns output_path : str Path to output file. bar : bool Whether to how progress bar (default = True). """ if len(path) == 0: raise ValueError("`path` cannot be empty.") if isinstance(path, str): path = (path, ) files_list = [f for p in path for f in glob.iglob(p, recursive=True)] tracecounts = 0 samples = None for fname in files_list: with segyio.open(fname, strict=False, ignore_geometry=True) as f: if samples is None: samples = f.samples else: if np.all(samples != f.samples): raise ValueError( "Inconsistent samples in files!" + f"Samples is {f.samples} in {fname}, previous value was {samples}" ) tracecounts += f.tracecount spec = segyio.spec() spec.sorting = None spec.format = 1 spec.tracecount = tracecounts spec.samples = samples with segyio.create(output_path, spec) as dst: i = 0 iterable = tqdm(files_list) if bar else files_list for index in iterable: with segyio.open(index, strict=False, ignore_geometry=True) as src: dst.trace[i:i + src.tracecount] = src.trace dst.header[i:i + src.tracecount] = src.header for j in range(src.tracecount): dst.header[i + j].update( {segyio.TraceField.TRACE_SEQUENCE_FILE: i + j + 1}) i += src.tracecount
def main(): if len(sys.argv) < 9: sys.exit(" ".join(["Usage: {} [file] [samples]", "[first iline] [last iline]", "[first xline] [last xline]", "[first offset] [last offset]"] ).format(sys.argv[0])) spec = segyio.spec() filename = sys.argv[1] # to create a file from nothing, we need to tell segyio about the structure of # the file, i.e. its inline numbers, crossline numbers, etc. You can also add # more structural information, This is the absolute minimal specification for a # N-by-M volume with K offsets volume spec.sorting = 2 spec.format = 1 spec.samples = range(int(sys.argv[2])) spec.ilines = range(*map(int, sys.argv[3:5])) spec.xlines = range(*map(int, sys.argv[5:7])) spec.offsets = range(*map(int, sys.argv[7:9])) if len(spec.offsets) == 0: spec.offsets = [1] with segyio.create(filename, spec) as f: # one inline consists of 50 traces # which in turn consists of 2000 samples start = 0.0 step = 0.00001 # fill a trace with predictable values: left-of-comma is the inline # number. Immediately right of comma is the crossline number # the rightmost digits is the index of the sample in that trace meaning # looking up an inline's i's jth crosslines' k should be roughly equal # to (offset*100) + i.j0k. trace = np.arange(start = start, stop = start + step * len(spec.samples), step = step, dtype = np.single) # Write the file trace-by-trace and update headers with iline, xline # and offset tr = 0 for il in spec.ilines: for xl in spec.xlines: for off in spec.offsets: f.header[tr] = { segyio.su.offset : off, segyio.su.iline : il, segyio.su.xline : xl } f.trace[tr] = trace + (xl / 100.0) + il + (off * 100) tr += 1 f.bin.update( tsort=segyio.TraceSortingFormat.INLINE_SORTING )
def main(): if len(sys.argv) < 9: sys.exit(" ".join(["Usage: {} [file] [samples]", "[first iline] [last iline]", "[first xline] [last xline]", "[first offset] [last offset]"] ).format(sys.argv[0])) spec = segyio.spec() filename = sys.argv[1] # to create a file from nothing, we need to tell segyio about the structure of # the file, i.e. its inline numbers, crossline numbers, etc. You can also add # more structural information, This is the absolute minimal specification for a # N-by-M volume with K offsets volume spec.sorting = 2 spec.format = 1 spec.samples = range(int(sys.argv[2])) spec.ilines = range(*map(int, sys.argv[3:5])) spec.xlines = range(*map(int, sys.argv[5:7])) spec.offsets = range(*map(int, sys.argv[7:9])) if len(spec.offsets) == 0: spec.offsets = [1] with segyio.create(filename, spec) as f: # one inline consists of 50 traces # which in turn consists of 2000 samples start = 0.0 step = 0.00001 # fill a trace with predictable values: left-of-comma is the inline # number. Immediately right of comma is the crossline number # the rightmost digits is the index of the sample in that trace meaning # looking up an inline's i's jth crosslines' k should be roughly equal # to (offset*100) + i.j0k. trace = np.arange(start = start, stop = start + step * len(spec.samples), step = step, dtype = np.single) nx, no = len(spec.xlines), len(spec.offsets) # one inline is N traces concatenated. We fill in the xline number line = np.concatenate([trace + (xl / 100.0) for xl in spec.xlines]) line = line.reshape( (nx, len(spec.samples)) ) for ilindex, ilno in enumerate(spec.ilines): iline = line + ilno for tr, xlno in enumerate(spec.xlines): for offset_index, offset in enumerate(spec.offsets): ix = (ilindex * nx * no) + (tr * no) + offset_index f.trace[ix] = iline[tr] + (offset * 100) f.header[ix] = { segyio.TraceField.INLINE_3D: ilno, segyio.TraceField.CROSSLINE_3D: xlno, segyio.TraceField.offset: offset }
def test_create_unstructured_hasattrs(tmpdir): spec = segyio.spec() spec.format = 5 spec.samples = range(150) spec.tracecount = 50 with segyio.create(tmpdir / "mk.sgy", spec) as dst: # accessing the sorting, inline and crossline attributes should work, # but not raise errors assert not dst.sorting assert not dst.ilines assert not dst.xlines assert dst.unstructured
def create_segy(): spec = segyio.spec() spec.format = 5 spec.samples = [0, 1] spec.ilines = [1] spec.xlines = [1] spec.endian = "little" s1 = 3 s2 = 5.5 with segyio.create(path, spec) as f: f.header[0] = {segyio.su.iline: 1, segyio.su.xline: 1} f.trace[0] = [s1, s2]
def from_array_crossline( filename: Path, data: np.ndarray, iline: int = 189, xline: int = 193, format: segyio.SegySampleFormat = segyio.SegySampleFormat.IBM_FLOAT_4_BYTE, dt: int = 4000, delrt: int = 0, ) -> None: dt = int(dt) delrt = int(delrt) data = np.asarray(data) dimensions = len(data.shape) if dimensions not in range(3, 5): raise ValueError(f"Expected 3 or 4 dimensions, {dimensions} was given") spec = segyio.spec() spec.iline = iline spec.xline = xline spec.format = format spec.sorting = segyio.TraceSortingFormat.CROSSLINE_SORTING spec.ilines = list(range(1, np.size(data, 0) + 1)) spec.xlines = list(range(1, np.size(data, 1) + 1)) if dimensions == 3: spec.samples = list(range(np.size(data, 2))) else: spec.offsets = list(range(1, np.size(data, 2) + 1)) spec.samples = list(range(np.size(data, 3))) samplecount = len(spec.samples) with segyio.create(filename, spec) as f: tr = 0 for xlno, xl in enumerate(spec.xlines): for ilno, il in enumerate(spec.ilines): for offno, off in enumerate(spec.offsets): f.header[tr] = { segyio.su.tracf: tr, segyio.su.cdpt: tr, segyio.su.offset: off, segyio.su.ns: samplecount, segyio.su.dt: dt, segyio.su.delrt: delrt, segyio.su.iline: il, segyio.su.xline: xl, } if dimensions == 3: f.trace[tr] = data[ilno, xlno, :] else: f.trace[tr] = data[ilno, xlno, offno, :] tr += 1 f.bin.update(tsort=spec.sorting, hdt=dt, dto=dt)
def main(): if len(sys.argv) < 7: sys.exit( "Usage: {} [file] [samples] [first iline] [last iline] [first xline] [last xline]" .format(sys.argv[0])) spec = segyio.spec() filename = sys.argv[1] # to create a file from nothing, we need to tell segyio about the structure of # the file, i.e. its inline numbers, crossline numbers, etc. You can also add # more structural information, but offsets etc. have sensible defautls. This is # the absolute minimal specification for a N-by-M volume spec.sorting = 2 spec.format = 1 spec.samples = range(int(sys.argv[2])) spec.ilines = range(*map(int, sys.argv[3:5])) spec.xlines = range(*map(int, sys.argv[5:7])) with segyio.create(filename, spec) as f: # one inline consists of 50 traces # which in turn consists of 2000 samples start = 0.0 step = 0.00001 # fill a trace with predictable values: left-of-comma is the inline # number. Immediately right of comma is the crossline number # the rightmost digits is the index of the sample in that trace meaning # looking up an inline's i's jth crosslines' k should be roughly equal # to i.j0k trace = np.arange(start=start, stop=start + step * len(spec.samples), step=step, dtype=np.single) # one inline is N traces concatenated. We fill in the xline number line = np.concatenate([trace + (xl / 100.0) for xl in spec.xlines]) line = line.reshape((len(spec.xlines), len(spec.samples))) # write the line itself to the file # write the inline number in all this line's headers for ilno in spec.ilines: f.iline[ilno] = (line + ilno) f.header.iline[ilno] = { segyio.TraceField.INLINE_3D: ilno, segyio.TraceField.offset: 1 } # then do the same for xlines for xlno in spec.xlines: f.header.xline[xlno] = {segyio.TraceField.CROSSLINE_3D: xlno}