diff --git a/tests/baseline/test_well_synthetic_plot.png b/tests/baseline/test_well_synthetic_plot.png index 0df2630..41d0f26 100644 Binary files a/tests/baseline/test_well_synthetic_plot.png and b/tests/baseline/test_well_synthetic_plot.png differ diff --git a/tests/test_plots.py b/tests/test_plots.py index 51975ab..56e98f0 100644 --- a/tests/test_plots.py +++ b/tests/test_plots.py @@ -9,6 +9,7 @@ https://pypi.python.org/pypi/pytest-mpl/0.3 """ +import matplotlib.pyplot as plt import pytest from welly import Well @@ -114,7 +115,8 @@ def test_synthetic_plot(): test_params = {'dt': 0.004} s = Synthetic(data, params=test_params) - fig = s.plot().get_figure() + fig, ax = plt.subplots(figsize=(2, 10)) + s.plot(ax) return fig @@ -127,7 +129,8 @@ def test_well_synthetic_plot(): w = Well.from_las(FNAME) w.make_synthetic() - fig = w.data['Synthetic'].plot().get_figure() + fig, ax = plt.subplots(figsize=(2, 10)) + w.data['Synthetic'].plot(ax) return fig diff --git a/tests/test_synthetic.py b/tests/test_synthetic.py index 88b37fc..bdb84e5 100644 --- a/tests/test_synthetic.py +++ b/tests/test_synthetic.py @@ -1,6 +1,6 @@ # -*- coding: utf 8 -*- """ -Define a suite a tests for the Curve module. +Define a suite a tests for the Synthetic class. """ import numpy as np @@ -17,3 +17,18 @@ def test_synthetic(): assert s.dt == 0.004 assert s.name == 'Synthetic' + + +def test_synthetic_as_curve(): + """ + Test synthetic to curve. + """ + data = np.array([4, 2, 0, -4, -2, 1, 3, 6, 3, 1, -2, -5, -1, 0]) + params = {'dt': 0.004} + s = Synthetic(data, params=params) + + crv = s.as_curve(0, 500, 0.1, mnemonic="SYNTH_CRV") + + assert crv.index[0] == 0 + assert round((crv.index[1]-crv.index[0]),2) == 0.1 + assert crv.mnemonic == 'SYNTH_CRV' \ No newline at end of file diff --git a/welly/location.py b/welly/location.py index 683ce5d..31ff29e 100644 --- a/welly/location.py +++ b/welly/location.py @@ -338,7 +338,7 @@ def trajectory(self, datum=None, elev=True, points=1000, **kwargs): Returns: ndarray. An array with shape (`points` x 3) representing the well - trajectory. Columns are (x, y, z). + trajectory. Columns are (x, y, z). """ pos = self.position.copy() diff --git a/welly/synthetic.py b/welly/synthetic.py index 54b5fee..c6d638d 100644 --- a/welly/synthetic.py +++ b/welly/synthetic.py @@ -55,14 +55,22 @@ def basis(self): precision_adj = self.dt / 100 return np.arange(self.start, self.stop - precision_adj, self.dt) - def as_curve(self, data): + def as_curve(self, depth_start=0., depth_stop=99999., depth_step=0.1524, mnemonic="SYN"): """ Get the synthetic as a Curve, in depth. Facilitates plotting along- side other curve data. """ - params = {'mnemonic': 'SYN'} + if depth_stop <= 0.: + depth_stop = 99999. - return Curve(data, **params) + new_crv = None + if depth_stop > depth_start: + depth_basis = np.arange(depth_start, depth_stop+depth_step, depth_step) + data = np.interp(depth_basis, self.basis, self) + + new_crv = Curve(data, mnemonic=mnemonic, index=depth_basis) + + return new_crv def plot(self, ax=None, **kwargs): """ @@ -93,5 +101,5 @@ def plot(self, ax=None, **kwargs): if return_ax: return ax - - return fig + else: + return None diff --git a/welly/utils.py b/welly/utils.py index aa470f1..c10c66f 100644 --- a/welly/utils.py +++ b/welly/utils.py @@ -84,7 +84,7 @@ def bbox(points): def aspect(points): """ - Aspect like 2:1 is twice as wide as high. + Aspect like 2:1 is shape like |___ (twice as wide as high). This function returns the WIDTH per unit height. """ @@ -542,16 +542,16 @@ def ricker(f, length, dt): A Ricker wavelet. Args: - f (float): frequency in Haz, e.g. 25 Hz. + f (float): frequency in Hz, e.g. 25 Hz. length (float): Length in s, e.g. 0.128. dt (float): sample interval in s, e.g. 0.001. Returns: tuple. time basis, amplitude values. """ - t = np.linspace(-int(length / 2), int((length - dt) / 2), int(length / dt)) - y = (1. - 2. * (np.pi ** 2) * (f ** 2) * (t ** 2)) * np.exp(-(np.pi ** 2) * (f ** 2) * (t ** 2)) - return t, y + time = np.arange(-length/2, length/2, dt) + amp = (1. - 2.*(np.pi**2)*(f**2)*(time**2))*np.exp(-(np.pi**2)*(f**2)*(time**2)) + return time, amp def hex_to_rgb(hexx): diff --git a/welly/well.py b/welly/well.py index 707b116..6a161a4 100644 --- a/welly/well.py +++ b/welly/well.py @@ -935,27 +935,33 @@ def is_complete(self, keys=None, alias=None): def alias_has_multiple(self, mnemonic, alias): return 1 < len([a for a in alias[mnemonic] if a in self.data]) - def make_synthetic(self, srd=0, v_repl_seismic=2000, v_repl_log=2000, f=50, + def make_synthetic(self, + srd=0, + sonic_mnemonic="DT", + density_mnemonic="RHOB", + v_repl_seismic=2000, + v_repl_log=2000, + f=50, dt=0.001): """ Early hack. Use with extreme caution. Hands-free. There'll be a more granualr version in synthetic.py. - Assumes DT is in µs/m and RHOB is kg/m3. + Assumes Sonic is in µs/m and Density is kg/m3. There is no handling yet for TVD. The datum handling is probably sketchy. """ kb = getattr(self.location, 'kb', None) or 0 - data0 = self.data['DT'].start + data0 = self.data[sonic_mnemonic].start log_start_time = ((srd - kb) / v_repl_seismic) + (data0 / v_repl_log) # Basic log values. - dt_log = self.data['DT'].despike() # assume µs/m - rho_log = self.data['RHOB'].despike() # assume kg/m3 - if not np.allclose(dt_log.df.index, rho_log.df.index): + dt_log = self.data[sonic_mnemonic].despike() # assume µs/m + rho_log = self.data[density_mnemonic].despike() # assume kg/m3 + if not np.allclose(dt_log.basis, rho_log.basis): rho_log = rho_log.to_basis_like(dt_log) Z = (1e6 / dt_log.df.values) * rho_log.df.values @@ -977,12 +983,13 @@ def make_synthetic(self, srd=0, v_repl_seismic=2000, v_repl_log=2000, f=50, # Convolve. _, ricker = utils.ricker(f=f, length=0.128, dt=dt) - synth = np.convolve(ricker, rc_t, mode='same') + synth = np.convolve(rc_t, ricker, mode='same') - params = {'dt': dt, 'z start': dt_log.start, 'z stop': dt_log.stop} + params = {'dt': dt, + 'start': dt_log.start, + } self.data['Synthetic'] = Synthetic(synth, basis=t_reg, params=params) - return None def qc_curve_group(self, tests, keys=None, alias=None):