def test_intercept(self): """ Should test if the intercept calculation returns the same result when using 'along_wiggle' as for single layer :return: """ rho = RpTestCase.w.block['Logs'].logs['den'].data vp = cnvrt(RpTestCase.w.block['Logs'].logs['ac'].data, 'us/ft', 'm/s') incept2 = rp.intercept(vp, None, rho, None, along_wiggle=True) i = np.nanargmax(incept2) incept1 = rp.intercept(vp[i], vp[i + 1], rho[i], rho[i + 1]) incept1_2 = rp.intercept(vp[i + 1], vp[i + 2], rho[i + 1], rho[i + 2]) with self.subTest(): print('Layer based intercept at i {}: {}'.format(i, incept1)) print('Layer based intercept at i {}: {}'.format(i + 1, incept1_2)) print('Wiggle based intercept at i {}: {}'.format( i, incept2[i:i + 2])) self.assertTrue(True)
def test_step(self): i = 5 theta = 10. # degrees x1 = np.linspace(1, 10, 10) x2 = np.linspace(2, 11, 10) x3 = np.linspace(3, 12, 10) d1 = rp.step(x1[i], x1[i + 1]) d2 = rp.step(x1, None, along_wiggle=True) incept1 = rp.intercept(x1[i], x1[i + 1], x3[i], x3[i + 1]) incept2 = rp.intercept(x1, None, x3, None, along_wiggle=True) grad1 = rp.gradient(x1[i], x1[i + 1], x2[i], x2[i + 1], x3[i], x3[i + 1]) grad2 = rp.gradient(x1, None, x2, None, x3, None, along_wiggle=True) func1 = rp.reflectivity(x1[i], x1[i + 1], x2[i], x2[i + 1], x3[i], x3[i + 1]) func2 = rp.reflectivity(x1, None, x2, None, x3, None, along_wiggle=True) with self.subTest(): print('Layer based step at i {}: {}'.format(i, d1)) print('Wiggle based step at i {}: {}'.format(i, d2[i])) print('Layer based intercept at i {}: {}'.format(i, incept1)) print('Wiggle based intercept at i {}: {}'.format(i, incept2[i])) print('Layer based gradient at i {}: {}'.format(i, grad1)) print('Wiggle based gradient at i {}: {}'.format(i, grad2[i])) print('Layer based refl. coeff. at i {} at {} deg.: {}'.format( i, theta, func1(theta))) print('Wiggle based refl. coeff. at i {} at {} deg.: {}'.format( i, theta, func2(theta)[i])) self.assertTrue(True)
def rpt_phi_sw(_phi, _sw, **kwargs): plot_type = kwargs.pop('plot_type', 'AI-VpVs') ref_val = kwargs.pop( 'ref_val', [3500., 1700., 2.6 ]) # ref values of Vp, Vs and rho for calculating I x G model = kwargs.pop('model', 'stiff') phic = kwargs.pop('phic', 0.4) # critical porosity cn = kwargs.pop( 'cn', 8) # coordination number, average number of contacts per grain p = kwargs.pop('p', 10) # Confining pressure in MPa (effective pressure?) f = kwargs.pop( 'f', 0.3 ) # shear modulus correction factor (1=dry pack with perfect adhesion, 0=dry frictionless pack) rho_b = kwargs.pop('rho_b', 1.1) # Brine density g/cm3 k_b = kwargs.pop('k_b', 2.8) # Brine bulk modulus GPa rho_hc = kwargs.pop('rho_hc', 0.2) # HC density k_hc = kwargs.pop('k_hc', 0.06) # HC bulk modulus rho_min = kwargs.pop('rho_min', 2.7) # Density [g/cm3] of mineral mix k_min = kwargs.pop('k_min', 30.) # Bulk modulus GPa of mineral mix mu_min = kwargs.pop('mu_min', 20.) # Shear modulus of mineral mix # Apply the rock physics model to modify the mineral properties if model == 'stiff': k_dry, mu_dry = rp.stiffsand(k_min, mu_min, _phi, phic, cn, p, f) else: k_dry, mu_dry = rp.softsand(k_min, mu_min, _phi, phic, cn, p, f) # Calculate the final fluid properties for the given water saturation k_f2 = rp.vrh_bounds([_sw, 1. - _sw], [k_b, k_hc])[1] # K_f rho_f2 = rp.vrh_bounds([_sw, 1. - _sw], [rho_b, rho_hc])[0] #RHO_f # Use Gassman to calculate the final elastic properties vp_2, vs_2, rho_2, k_2 = rp.vels(k_dry, mu_dry, k_min, rho_min, k_f2, rho_f2, _phi) if plot_type == 'AI-VpVs': xx = rho_2 * vp_2 yy = vp_2 / vs_2 elif plot_type == 'Phi-Vp': xx = _phi yy = vp_2 elif plot_type == 'I-G': xx = rp.intercept(ref_val[0], vp_2, ref_val[2], rho_2) yy = rp.gradient(ref_val[0], vp_2, ref_val[1], vs_2, ref_val[2], rho_2) else: raise IOError('No valid plot_type selected') return xx, yy
def plot_one_interface(sums, name1, name2, color, fig_ig, ax_ig, fig_refl, ax_refl, n_samps=1000): # elastics_from_stats calculates the normally distributed variables, with correlations, given # the mean, std and correlation, using a multivariate function vp1, vs1, rho1 = elastics_from_stats(sums[name1], n_samps) vp2, vs2, rho2 = elastics_from_stats(sums[name2], n_samps) # Calculate statistics of the reflection coefficient, assuming 50 samples from 0 to 40 deg incidence angle theta = np.linspace(0, 40, 50) refs = np.full((n_samps, 50), np.nan) # calculate the reflectivity as a function of theta for all variations of the elastic properties for i, params in enumerate(zip(vp1, vp2, vs1, vs2, rho1, rho2)): refs[i, :] = rp.reflectivity(*params)(theta) refl_stds = np.std(refs, 0) # Calculate the mean reflectivity curve mean_refl = rp.reflectivity( sums[name1]['VpMean'], sums[name2]['VpMean'], sums[name1]['VsMean'], sums[name2]['VsMean'], sums[name1]['RhoMean'], sums[name2]['RhoMean'], ) # plot the mean reflectivity curve together with the uncertainty mypr.plot(theta, mean_refl(theta), c=color, yerror=refl_stds, yerr_style='fill', fig=fig_refl, ax=ax_refl) intercept = rp.intercept(vp1, vp2, rho1, rho2) gradient = rp.gradient(vp1, vp2, vs1, vs2, rho1, rho2) #res = least_squares( # mycf.residuals, # [1.,1.], # args=(intercept, gradient), # kwargs={'target_function': straight_line} #) #print('{} on {}: WS = {:.4f}*I {:.4f} - G'.format(name1, name2, *res.x)) #print(res.status) #print(res.message) #print(res.success) myxp.plot(intercept, gradient, cdata=color, fig=fig_ig, ax=ax_ig, edge_color=None, alpha=0.2) #x_new = np.linspace(-0.75, 0.75, 50) #ax_ig.plot(x_new, straight_line(x_new, *res.x), c=color, label='_nolegend_') # Do AVO classification c1 = len(gradient[(intercept > 0.) & (gradient > -4 * intercept) & (gradient < 0.)]) c2p = len(gradient[(intercept > 0.) & (gradient < -4 * intercept)]) c2 = len(gradient[(intercept > -0.02) & (intercept < 0.) & (gradient < 0.)]) c3 = len(gradient[(intercept < -0.02) & (gradient < 0.)]) c4 = len(gradient[(intercept < 0.) & (gradient > 0.)]) rest = len(gradient[(intercept > 0.) & (gradient > 0.)]) print( 'Class I: {:.0f}% \nClass IIp: {:.0f}% \nClass II: {:.0f}% \nClass III: {:.0f}% \nClass IV: {:.0f}%' .format(100. * c1 / n_samps, 100. * c2p / n_samps, 100. * c2 / n_samps, 100. * c3 / n_samps, 100. * c4 / n_samps)) print('Rest: {:.0f}%'.format(100. * rest / n_samps))
def test_synt2(): """ This essentially tries to copy test_synt(), which is based on https://github.com/seg/tutorials-2014/blob/master/1406_Make_a_synthetic/how_to_make_synthetic.ipynb but using blixt_rp built in functionality instead :return: """ import blixt_utils.io.io as uio import plotting.plot_logs as ppl from core.well import Project from core.well import Well import blixt_utils.misc.convert_data as ucd wp = Project() wells = wp.load_all_wells() w = wells[list(wells.keys())[0]] # take first well wis = uio.project_working_intervals(wp.project_table) log_table = { 'P velocity': 'vp_dry', 'S velocity': 'vs_dry', 'Density': 'rho_dry' } # when input is in feet and usec #depth = ucd.convert(w.block['Logs'].logs['depth'].data, 'ft', 'm') #rho_orig = w.block['Logs'].logs['rhob'].data * 1000. # g/cm3 to kg/m3 #vp_orig = ucd.convert(w.block['Logs'].logs['dt'].data, 'us/ft', 'm/s') #dt_orig = w.block['Logs'].logs['dt'].data * 3.2804 # convert usec/ft to usec/m # else depth = w.block['Logs'].logs['depth'].data rho_orig = w.block['Logs'].logs[ log_table['Density']].data * 1000. # g/cm3 to kg/m3 vp_orig = w.block['Logs'].logs[log_table['P velocity']].data vs_orig = w.block['Logs'].logs[log_table['S velocity']].data # when input is in feet and usec #rho = w.block['Logs'].logs['rhob'].despike(0.1) * 1000. # g/cm3 to kg/m3 #vp = ucd.convert(w.block['Logs'].logs['dt'].despike(5), 'us/ft', 'm/s') #dt = w.block['Logs'].logs['dt'].despike(5) * 3.2804 # convert usec/ft to usec/m # else rho = w.block['Logs'].logs[log_table['Density']].despike( 0.1) * 1000. # g/cm3 to kg/m3 vp = w.block['Logs'].logs[log_table['P velocity']].despike(200) vs = w.block['Logs'].logs[log_table['S velocity']].despike(200) start = 13000 end = 14500 # Plot despiking results plot = False if plot: fig, axes = plt.subplots(3, 1, sharex=True, figsize=(18, 12)) for i, y1, y2 in zip([0, 1, 2], [rho_orig, vp_orig, vs_orig], [rho, vp, vs]): axes[i].plot(depth[start:end], y2[start:end], 'y', lw=3) axes[i].plot(depth[start:end], y1[start:end], 'k', lw=0.5) axes[i].legend(['Smooth & despiked', 'Original']) tdr = w.time_to_depth(log_table['P velocity'], debug=False) r0 = rp.intercept(vp, None, rho, None, along_wiggle=True) plot = True
def twolayer(vp0, vs0, rho0, vp1, vs1, rho1, angels=None): #from bruges.reflection import shuey2 #from bruges.filters import ricker from rp.rp_core import reflectivity, intercept, gradient if angels is None: angels = [5, 15, 30] n_samples = 500 interface = int(n_samples / 2) ang = np.arange(31) wavelet = ricker(.25, 0.001, 25) model_ip, model_vpvs, rc0, rc1, rc2 = (np.zeros(n_samples) for _ in range(5)) model_z = np.arange(n_samples) model_ip[:interface] = vp0 * rho0 model_ip[interface:] = vp1 * rho1 model_vpvs[:interface] = np.true_divide(vp0, vs0) model_vpvs[interface:] = np.true_divide(vp1, vs1) #avo = shuey2(vp0, vs0, rho0, vp1, vs1, rho1, ang) _avo = reflectivity(vp0, vp1, vs0, vs1, rho0, rho1, version='ShueyAkiRich') avo = _avo(ang) rc0[interface] = avo[angels[0]] rc1[interface] = avo[angels[1]] rc2[interface] = avo[angels[2]] synt0 = np.convolve(rc0, wavelet, mode='same') synt1 = np.convolve(rc1, wavelet, mode='same') synt2 = np.convolve(rc2, wavelet, mode='same') clip = np.max(np.abs([synt0, synt1, synt2])) clip += clip * .2 ic = intercept(vp0, vp1, rho0, rho1) gr = gradient(vp0, vp1, vs0, vs1, rho0, rho1) opz0 = {'color': 'b', 'linewidth': 4} opz1 = {'color': 'k', 'linewidth': 2} opz2 = {'linewidth': 0, 'alpha': 0.5} opz3 = {'color': 'tab:red', 'linewidth': 0, 'markersize': 8, 'marker': 'o'} opz4 = { 'color': 'tab:blue', 'linewidth': 0, 'markersize': 8, 'marker': 'o' } f = plt.subplots(figsize=(12, 10)) ax0 = plt.subplot2grid((2, 12), (0, 0), colspan=3) # ip ax1 = plt.subplot2grid((2, 12), (0, 3), colspan=3) # vp/vs ax2 = plt.subplot2grid((2, 12), (0, 6), colspan=2) # synthetic @ 0 deg ax3 = plt.subplot2grid((2, 12), (0, 8), colspan=2) # synthetic @ 30 deg ax35 = plt.subplot2grid((2, 12), (0, 10), colspan=2) # synthetic @ 30 deg ax4 = plt.subplot2grid((2, 12), (1, 0), colspan=5) # avo curve ax6 = plt.subplot2grid((2, 12), (1, 7), colspan=5) # avo curve ax0.plot(model_ip, model_z, **opz0) ax0.set_xlabel('IP') ax0.locator_params(axis='x', nbins=2) ax1.plot(model_vpvs, model_z, **opz0) ax1.set_xlabel('VP/VS') ax1.locator_params(axis='x', nbins=2) ax2.plot(synt0, model_z, **opz1) ax2.plot(synt0[interface], model_z[interface], **opz3) ax2.fill_betweenx(model_z, 0, synt0, where=synt0 > 0, facecolor='black', **opz2) ax2.set_xlim(-clip, clip) ax2.set_xlabel('angle={:.0f}'.format(angels[0])) ax2.locator_params(axis='x', nbins=2) ax3.plot(synt1, model_z, **opz1) ax3.plot(synt1[interface], model_z[interface], **opz3) ax3.fill_betweenx(model_z, 0, synt1, where=synt1 > 0, facecolor='black', **opz2) ax3.set_xlim(-clip, clip) ax3.set_xlabel('angle={:.0f}'.format(angels[1])) ax3.locator_params(axis='x', nbins=2) ax35.plot(synt2, model_z, **opz1) ax35.plot(synt2[interface], model_z[interface], **opz3) ax35.fill_betweenx(model_z, 0, synt2, where=synt2 > 0, facecolor='black', **opz2) ax35.set_xlim(-clip, clip) ax35.set_xlabel('angle={:.0f}'.format(angels[2])) ax35.locator_params(axis='x', nbins=2) ax4.plot(ang, avo, **opz0) ax4.axhline(0, color='k', lw=2) ax4.set_xlabel('angle of incidence') ax4.tick_params(which='major', labelsize=8) ax5 = ax4.twinx() color = 'tab:red' ax5.plot(angels, [s[interface] for s in [synt0, synt1, synt2]], **opz3) ax5.set_ylabel('Seismic amplitude') ax5.tick_params(axis='y', labelcolor=color, labelsize=8) # Calculate intercept & gradient based on the three "angle stacks"1G res = least_squares( mycf.residuals, [1., 1.], args=(np.array(angels), np.array([s[interface] for s in [synt0, synt1, synt2]])), kwargs={'target_function': straight_line}) print('amp = {:.4f}*theta + {:.4f}'.format(*res.x)) print(res.status) print(res.message) print(res.success) ax5.plot(ang, straight_line(ang, *res.x), c='tab:red') res2 = least_squares( mycf.residuals, [1., 1.], args=(np.sin(np.array(angels) * np.pi / 180.)**2, np.array([s[interface] for s in [synt0, synt1, synt2]])), kwargs={'target_function': straight_line}) print('amp = {:.4f}*theta + {:.4f}'.format(*res2.x)) print(res2.status) print(res2.message) print(res2.success) ax6.plot(ic, gr, **opz4) ax6.plot(*res2.x[::-1], **opz3) ax6.set_xlabel('Intercept') ax6.set_ylabel('Gradient') for aa in [ax0, ax1, ax2, ax3, ax35]: aa.set_ylim(350, 150) aa.tick_params(which='major', labelsize=8) aa.set_yticklabels([]) plt.subplots_adjust(wspace=.8, left=0.05, right=0.95)
def test_synt(): """ https://github.com/seg/tutorials-2014/blob/master/1406_Make_a_synthetic/how_to_make_synthetic.ipynb :return: """ import blixt_utils.io.io as uio import plotting.plot_logs as ppl from core.well import Project from core.well import Well import blixt_utils.misc.convert_data as ucd wp = Project() well_table = { os.path.join(wp.working_dir, 'test_data/L-30.las'): { 'Given well name': 'WELL_L', 'logs': { 'dt': 'Sonic', 'cald': 'Caliper', 'cals': 'Caliper', 'rhob': 'Density', 'grd': 'Gamma ray', 'grs': 'Gamma ray', 'ild': 'Resistivity', 'ilm': 'Resistivity', 'll8': 'Resistivity', 'nphils': 'Neutron density' }, 'Note': 'Some notes for well A' } } wis = uio.project_working_intervals(wp.project_table) w = Well() w.read_well_table(well_table, 0, block_name='Logs') depth = w.block['Logs'].logs['depth'].data / 3.28084 # feet to m rho_orig = w.block['Logs'].logs['rhob'].data * 1000. # g/cm3 to kg/m3 vp_orig = ucd.convert(w.block['Logs'].logs['dt'].data, 'us/ft', 'm/s') dt_orig = w.block['Logs'].logs[ 'dt'].data * 3.2804 # convert usec/ft to usec/m # # Start of copying the notebook results: # https://github.com/seg/tutorials-2014/blob/master/1406_Make_a_synthetic/how_to_make_synthetic.ipynb # def f2m(item_in_feet): "converts feet to meters" try: return item_in_feet / 3.28084 except TypeError: return float(item_in_feet) / 3.28084 kb = f2m(w.header.kb.value) water_depth = f2m(w.header.gl.value) # has a negative value #top_of_log = f2m(w.block['Logs'].header.strt.value) top_of_log = f2m(1150.5000) # The DT log starts at this value repl_int = top_of_log - kb + water_depth water_vel = 1480 # m/s EGL_time = 2.0 * np.abs(kb) / water_vel #water_twt = 2.0 * abs(water_depth + EGL_time) / water_vel # ORIG THIS SEEMS LIKE MIXING distance with time! water_twt = 2.0 * abs(water_depth + np.abs(kb)) / water_vel # My version repl_vel = 1600. # m/s repl_time = 2. * repl_int / repl_vel log_start_time = water_twt + repl_time print('KB elevation: {} [m]'.format(kb)) print('Seafloor elevation: {} [m]'.format(water_depth)) print('Ground level time above SRD: {} [s]'.format(EGL_time)) print('Water time: {} [s]'.format(water_twt)) print('Top of Sonic log: {} [m]'.format(top_of_log)) print('Replacement interval: {} [m]'.format(repl_int)) print('Two-way replacement time: {} [s]'.format(repl_time)) print('Top-of-log starting time: {} [s]'.format(log_start_time)) def tvdss(md): # Assumes a vertical well # md in meter return md - kb def rolling_window(a, window): shape = a.shape[:-1] + (a.shape[-1] - window + 1, window) strides = a.strides + (a.strides[-1], ) rolled = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) return rolled #plt.figure(figsize=(18, 4)) #plt.plot(depth, rho_sm, 'b', depth, rho, 'k', alpha=0.5) def despike(curve, curve_sm, max_clip): spikes = np.where(curve - curve_sm > max_clip)[0] spukes = np.where(curve_sm - curve > max_clip)[0] out = np.copy(curve) out[spikes] = curve_sm[ spikes] + max_clip # Clip at the max allowed diff out[spukes] = curve_sm[ spukes] - max_clip # Clip at the min allowed diff return out window = 13 # the length of filter is 13 samples or ~ 2 metres # Density rho_sm = np.median(rolling_window(rho_orig, window), -1) rho_sm = np.pad(rho_sm, int(window / 2), mode='edge') rho = despike(rho_orig, rho_sm, max_clip=100) rho_test = w.block['Logs'].logs['rhob'].despike( 0.1) * 1000. # g/cm3 to kg/m3 # dt dt_sm = np.median(rolling_window(dt_orig, window), -1) dt_sm = np.pad(dt_sm, int(window / 2), mode='edge') dt = despike(dt_orig, dt_sm, max_clip=10) # My test of despiking the velocity directly vp_sm = np.median(rolling_window(vp_orig, window), -1) vp_sm = np.pad(vp_sm, int(window / 2), mode='edge') vp = despike(vp_orig, vp_sm, max_clip=200) # Plot result of despiking start = 13000 end = 14500 plot = True if plot: plt.figure(figsize=(18, 4)) plt.plot(depth[start:end], rho_orig[start:end], 'b', lw=3) #plt.plot(depth[start:end], rho_sm[start:end], 'b') plt.plot(depth[start:end], rho[start:end], 'r', lw=2) plt.plot(depth[start:end], rho_test[start:end], 'k--') plt.title('de-spiked density') plt.figure(figsize=(18, 4)) plt.plot(depth[start:end], dt_orig[start:end], 'k') plt.plot(depth[start:end], dt_sm[start:end], 'b') plt.plot(depth[start:end], dt[start:end], 'r') plt.title('de-spiked sonic') #plt.figure(figsize=(18, 4)) #plt.plot(depth[start:end], vp_orig[start:end], 'k') #plt.plot(depth[start:end], vp_sm[start:end], 'b') #plt.plot(depth[start:end], vp[start:end], 'r') #plt.title('de-spiked Vp') # Compute the time-depth relationship # two-way-time to depth relationship scaled_dt = 0.1524 * np.nan_to_num( dt ) / 1.e6 # scale the sonic log by the sample interval (6 inches or 0.1524 m) # and go from usec to sec tcum = 2 * np.cumsum(scaled_dt) # integration tdr = tcum + log_start_time print(tdr[:10], tdr[-10:]) # Compute acoustic impedance ai = (1e6 / dt) * rho # Compute reflection rc = (ai[1:] - ai[:-1]) / (ai[1:] + ai[:-1]) # Compute reflection "my way" r0 = rp.intercept(vp, None, rho, None, along_wiggle=True) # The difference between rc and r0 lies basically in the difference in smoothing and clipping of dt vs. vp plot = False if plot: plt.figure(figsize=(18, 4)) plt.plot(depth[start:end], rc[start:end], 'k') plt.plot(depth[start:end], r0[start:end], 'b') plt.title('Comparison of reflection coefficients') plt.legend(['Notebook way', 'My way']) def find_nearest(array, value): idx = (np.abs(array - value)).argmin() return idx tops = {} for _key in list(wis['WELL_L'].keys()): tops[_key] = wis['WELL_L'][_key][0] tops_twt = {} for _key in list(wis['WELL_L'].keys()): tops_twt[_key] = tdr[find_nearest(depth, wis['WELL_L'][_key][0])] # RESAMPLING FUNCTION t_step = 0.004 max_t = 3.0 t = np.arange(0, max_t, t_step) ai_t = np.interp(x=t, xp=tdr, fp=ai) rc_t = (ai_t[1:] - ai_t[:-1]) / (ai_t[1:] + ai_t[:-1]) # Compute the depth-time relation dtr = np.array([depth[find_nearest(tdr, tt)] for tt in t]) # Define a Ricker wavelet def ricker(_f, _length, _dt): _t = np.linspace(-_length / 2, (_length - _dt) / 2, _length / _dt) _y = (1. - 2. * (np.pi**2) * (_f**2) * (_t**2)) * np.exp(-(np.pi**2) * (_f**2) * (_t**2)) return _t, _y # Do the convolution rc_t = np.nan_to_num(rc_t) tw, w = ricker(_f=25, _length=0.512, _dt=0.004) synth = np.convolve(w, rc_t, mode='same') plot = False if plot: f2 = plt.figure(figsize=[10, 12]) ax1 = f2.add_axes([0.05, 0.1, 0.2, 0.9]) ax1.plot(ai, depth, 'k', alpha=0.75) ax1.set_title('impedance') ax1.set_ylabel('measured depth ' + '$[m]$', fontsize='12') ax1.set_xlabel(r'$kg/m^2s^2$ ', fontsize='16') ax1.set_ylim(0, 4500) ax1.set_xticks([0.0e7, 0.5e7, 1.0e7, 1.5e7, 2.0e7]) ax1.invert_yaxis() ax1.grid() ax2 = f2.add_axes([0.325, 0.1, 0.2, 0.9]) ppl.wiggle_plot(ax2, dtr[:-1], synth, fill='pos') ax2.set_ylim(0, 4500) ax2.invert_yaxis() ax2.grid() ax3 = f2.add_axes([0.675, 0.1, 0.1, 0.9]) ax3.plot(ai_t, t, 'k', alpha=0.75) ax3.set_title('impedance') ax3.set_ylabel('two-way time ' + '$[s]$', fontsize='12') ax3.set_xlabel(r'$kg/m^2s^2$ ', fontsize='16') ax3.set_ylim(0, 3) ax3.set_xticks([0.0e7, 0.5e7, 1.0e7, 1.5e7, 2.0e7]) ax3.invert_yaxis() ax3.grid() ax4 = f2.add_axes([0.8, 0.1, 0.2, 0.9]) ppl.wiggle_plot(ax4, t[:-1], synth, scaling=10, fill='pos') ax4.set_ylim(0, 3) ax4.invert_yaxis() ax4.grid() for top, depth in tops.items(): f2.axes[0].axhline(y=float(depth), color='b', lw=2, alpha=0.5, xmin=0.05, xmax=0.95) f2.axes[0].text(x=1e7, y=float(depth) - 0.015, s=top, alpha=0.75, color='k', fontsize='12', horizontalalignment='center', verticalalignment='center', bbox=dict(facecolor='white', alpha=0.5, lw=0.5), weight='light') for top, depth in tops.items(): f2.axes[1].axhline(y=float(depth), color='b', lw=2, alpha=0.5, xmin=0.05, xmax=0.95) for i in range(2, 4): for twt in tops_twt.values(): f2.axes[i].axhline(y=float(twt), color='b', lw=2, alpha=0.5, xmin=0.05, xmax=0.95)
def plot_rp(wells, log_table, wis, wi_name, cutoffs=None, templates=None, legend_items=None, plot_type=None, ref_val=None, fig=None, ax=None, block_name=None, savefig=None, **kwargs): """ Plots some standard rock physics crossplots for the given wells :param wells: dict dictionary with well names as keys, and core.well.Well object as values As returned from core.well.Project.load_all_wells() :param log_table: dict Dictionary of log type: log name key: value pairs which decides which log, under each log type, to plot E.G. log_table = { 'P velocity': 'vp', 'S velocity': 'vs', 'Density': 'rhob', 'Porosity': 'phie', 'Volume': 'vcl'} :param wis: dict working intervals, as defined in the "Working intervals" sheet of the project table, and loaded through: wp = Project() wis = rp_utils.io.project_working_intervals(wp.project_table) :param wi_name: str name of working interval to plot :param cutoffs: dict Dictionary with log types as keys, and list with mask definition as value E.G. {'Volume': ['<', 0.5], 'Porosity': ['>', 0.1]} :param templates: dict templates dictionary as returned from rp_utils.io.project_templates() :param legend_items: list list of Line2D objects that are used in the legends. if None, the well names will be used :param plot_type: str plot_type = 'AI-VpVs': AI versus Vp/Vs plot 'Phi-Vp': Porosity versus Vp plot 'I-G': Intercept versus Gradient plot :param ref_val: list List of reference Vp [m/s], Vs [m/s], and rho [g/cm3] that are used when calculating the Intercept and gradient :param fig: :param ax: :param block_name: str Name of the log block from where the logs are picked :param savefig str full pathname of file to save the plot to :param **kwargs: keyword arguments passed on to crossplot.plot() :return: """ # # some initial setups log_table = small_log_table(log_table) if block_name is None: block_name = cw.def_lb_name _savefig = False if plot_type is None: plot_type = 'AI-VpVs' elif plot_type == 'I-G' and ref_val is None: ref_val = [3500., 1700., 2.6] logs = [n.lower() for n in list(log_table.values())] if savefig is not None: _savefig = True # # set up plotting environment if fig is None: if ax is None: fig = plt.figure(figsize=(10, 10)) ax = fig.subplots() else: # Only ax is set, but not fig. Which means all functionality calling fig must be turned off _savefig = False elif ax is None: ax = fig.subplots() # load well_names = [] desc = '' for wname, _well in wells.items(): print('Plotting well {}'.format(wname)) # create a deep copy of the well so that the original is not altered well = deepcopy(_well) these_wis = wis[wname] if wi_name.upper() not in [ _x.upper() for _x in list(these_wis.keys()) ]: warn_txt = 'Working interval {} does not exist in well {}'.format( wi_name, wname) print('WARNING: {}'.format(warn_txt)) logger.warning(warn_txt) continue # this working interval does not exist in current well # test if necessary logs are in the well skip = False for _log in logs: if _log not in list(well.block[block_name].logs.keys()): warn_txt = '{} log is lacking in {}'.format(_log, wname) print('WARNING: {}'.format(warn_txt)) logger.warning(warn_txt) skip = True if skip: continue # create mask based on working interval well.calc_mask({}, name='XXX', wis=wis, wi_name=wi_name) # apply mask (which also deletes the mask itself) well.apply_mask('XXX') # create mask based on cutoffs if cutoffs is not None: well.calc_mask(cutoffs, name='cmask', log_type_input=True, log_table=log_table) mask = well.block[block_name].masks['cmask'].data desc = well.block[block_name].masks['cmask'].header.desc else: mask = None # collect data for plot if plot_type == 'AI-VpVs': if 'P velocity' in list(log_table.keys()): # Calculating Vp / Vs using vp and vs x_data = well.block[block_name].logs[log_table['P velocity'].lower()].data * \ well.block[block_name].logs[log_table['Density'].lower()].data x_unit = '{} {}'.format( well.block[block_name].logs[ log_table['P velocity'].lower()].header.unit, well.block[block_name].logs[ log_table['Density'].lower()].header.unit) y_data = well.block[block_name].logs[log_table['P velocity'].lower()].data / \ well.block[block_name].logs[log_table['S velocity'].lower()].data else: # Assume we are calculating Vp / Vs using sonic logs x_data = well.block[block_name].logs[log_table['Density'].lower()].data / \ well.block[block_name].logs[log_table['Sonic'].lower()].data x_unit = '{}/{}'.format( well.block[block_name].logs[ log_table['Density'].lower()].header.unit, well.block[block_name].logs[ log_table['Sonic'].lower()].header.unit) y_data = well.block[block_name].logs[log_table['Shear sonic'].lower()].data / \ well.block[block_name].logs[log_table['Sonic'].lower()].data y_unit = '-' xtempl = {'full_name': 'AI', 'unit': x_unit} ytempl = {'full_name': 'Vp/Vs', 'unit': y_unit} elif (plot_type == 'Vp-bd') or (plot_type == 'Vp-tvd'): if 'P velocity' in list(log_table.keys()): x_data = well.block[block_name].logs[ log_table['P velocity'].lower()].data x_unit = '{}'.format(well.block[block_name].logs[ log_table['P velocity'].lower()].header.unit) xtempl = {'full_name': log_table['P velocity'], 'unit': x_unit} else: x_data = 1. / well.block[block_name].logs[ log_table['Sonic'].lower()].data x_unit = '1/{}'.format(well.block[block_name].logs[ log_table['Sonic'].lower()].header.unit) xtempl = {'full_name': '1/Sonic', 'unit': x_unit} if plot_type == 'Vp-bd': y_data = well.get_burial_depth(templates, block_name) ytempl = {'full_name': 'Burial depth', 'unit': 'm'} else: y_data = well.block[block_name].get_tvd() ytempl = {'full_name': 'TVD', 'unit': 'm'} elif (plot_type == 'VpVs-bd') or (plot_type == 'VpVs-tvd'): x_data = well.block[block_name].logs[log_table['P velocity'].lower()].data / \ well.block[block_name].logs[log_table['S velocity'].lower()].data xtempl = {'full_name': 'Vp/Vs', 'unit': '-'} if plot_type == 'VpVs-bd': y_data = well.get_burial_depth(templates, block_name) ytempl = {'full_name': 'Burial depth', 'unit': 'm'} else: y_data = well.block[block_name].get_tvd() ytempl = {'full_name': 'TVD', 'unit': 'm'} elif (plot_type == 'AI-bd') or (plot_type == 'AI-tvd'): x_data = well.block[block_name].logs[log_table['P velocity'].lower()].data * \ well.block[block_name].logs[log_table['Density'].lower()].data x_unit = '{} {}'.format( well.block[block_name].logs[ log_table['P velocity'].lower()].header.unit, well.block[block_name].logs[ log_table['Density'].lower()].header.unit) xtempl = {'full_name': 'AI', 'unit': x_unit} if plot_type == 'AI-bd': y_data = well.get_burial_depth(templates, block_name) ytempl = {'full_name': 'Burial depth', 'unit': 'm'} else: y_data = well.block[block_name].get_tvd() ytempl = {'full_name': 'TVD', 'unit': 'm'} elif (plot_type == 'Rho-bd') or (plot_type == 'Rho-tvd'): x_data = well.block[block_name].logs[ log_table['Density'].lower()].data x_unit = '{}'.format(well.block[block_name].logs[ log_table['Density'].lower()].header.unit) xtempl = {'full_name': log_table['Density'], 'unit': x_unit} if plot_type == 'Rho-bd': y_data = well.get_burial_depth(templates, block_name) ytempl = {'full_name': 'Burial depth', 'unit': 'm'} else: y_data = well.block[block_name].get_tvd() ytempl = {'full_name': 'TVD', 'unit': 'm'} elif plot_type == 'Phi-Vp': x_data = well.block[block_name].logs[ log_table['Porosity'].lower()].data x_unit = '{}'.format(well.block[block_name].logs[ log_table['Porosity'].lower()].header.unit) if 'P velocity' in list(log_table.keys()): # Calculating Vp using vp y_data = well.block[block_name].logs[ log_table['P velocity'].lower()].data y_unit = '{}'.format(well.block[block_name].logs[ log_table['P velocity'].lower()].header.unit) else: # Assume we are calculating Vp using sonic logs y_data = cnvrt( well.block[block_name].logs[ log_table['P velocity'].lower()].data, 'us/ft', 'm/s') y_unit = 'm/s' xtempl = {'full_name': 'Porosity', 'unit': x_unit} ytempl = {'full_name': 'Vp', 'unit': y_unit} elif plot_type == 'I-G': x_data = rp.intercept( ref_val[0], well.block[block_name].logs[ log_table['P velocity'].lower()].data, ref_val[2], well.block[block_name].logs[log_table['Density'].lower()].data) x_unit = '-' y_data = rp.gradient( ref_val[0], well.block[block_name].logs[ log_table['P velocity'].lower()].data, ref_val[1], well.block[block_name].logs[ log_table['S velocity'].lower()].data, ref_val[2], well.block[block_name].logs[log_table['Density'].lower()].data) y_unit = '-' xtempl = {'full_name': 'Intercept', 'unit': x_unit} ytempl = {'full_name': 'Gradient', 'unit': y_unit} else: raise IOError('No known plot type selected') well_names.append(wname) # start plotting xp.plot(x_data, y_data, cdata=templates[wname]['color'], mdata=templates[wname]['symbol'], xtempl=xtempl, ytempl=ytempl, mask=mask, fig=fig, ax=ax, **kwargs) ax.autoscale(True, axis='both') if ('tvd' in plot_type) or ('bd' in plot_type): ax.set_ylim(ax.get_ylim()[::-1]) ax.set_title('{}, {}'.format(wi_name, desc)) # if legend_items is None: legend_items = [] for wname in well_names: legend_items.append( Line2D([0], [0], color=templates[wname]['color'], lw=0, marker=templates[wname]['symbol'], label=wname)) legend_names = [x._label for x in legend_items] this_legend = ax.legend(legend_items, legend_names, prop=FontProperties(size='smaller'), scatterpoints=1, markerscale=2, loc=1) if _savefig: fig.savefig(savefig)