Ejemplo n.º 1
0
 def test_load_selected_intervals(self):
     these_intervals = ['Sand E', 'Sand F']
     #these_intervals = ['Sand F']
     wp = Project(name='MyProject', log_to_stdout=True)
     wells = wp.load_all_wells(include_these_intervals=these_intervals)
     for _, well in wells.items():
         md = well.block[def_lb_name].get_md()
         print(well.well, md.min(), md.max())
     with self.subTest():
         self.assertTrue(True)
Ejemplo n.º 2
0
 def test_load_selected_wells(self):
     """
     For this test to work, the listed wells below need to have "use = Yes" in the project table
     """
     these_wells = ['WELL_A', 'WELL_B']
     wp = Project(name='MyProject', log_to_stdout=True)
     wells = wp.load_all_wells(include_these_wells=these_wells)
     for wname, _ in wells.items():
         with self.subTest():
             self.assertTrue(wname in these_wells)
         with self.subTest():
             self.assertFalse(wname == 'WELL_C')
Ejemplo n.º 3
0
 def test_collect_data(self):
     wp = Project(name='MyProject', log_to_stdout=True)
     wells = wp.load_all_wells()
     wis = wp.load_all_wis()
     log_table = {'Porosity': 'phie', 'S velocity': 'vs'}
     results, results_per_well, depth_from_top = uc.create_containers(
         list(log_table.values()))
     interval_names = [
         'Sand C', 'Shale C', 'Sand D', 'Sand E', 'Sand F', 'Shale G',
         'Sand H'
     ]
     for wi_name in interval_names:
         uc.collect_data_for_this_interval(wells, list(log_table.values()),
                                           wis, wi_name, results,
                                           results_per_well, depth_from_top,
                                           {}, log_table)
         with self.subTest():
             self.assertTrue(True)
Ejemplo n.º 4
0
def main():
    # Create a project
    wp = Project(
        name='FluidSub',
        project_table='excels/project_table.xlsx')

    # Load wells
    wells = wp.load_all_wells(block_name='FBlock')
    w = wells['WELL_F']

    # Load working intervals and templates
    wis = uio.project_working_intervals(wp.project_table)
    templates = uio.project_templates(wp.project_table)

    # Load fluids
    myfluids = FluidMix()
    myfluids.read_excel(wp.project_table)
    print(myfluids.print_all_fluids())

    # Load minerals
    mymins = MineralMix()
    mymins.read_excel(wp.project_table)
    print(mymins.print_all_minerals())

    # Fluid substitution
    cutoffs = {'Volume': ['<', 0.5], 'Porosity': ['>', 0.1]}
    log_table = {'P velocity': 'vp_dry', 'S velocity': 'vs_dry', 'Density': 'rho_dry',
                 'Porosity': 'phie', 'Volume': 'vcl'}

    tag = 'fs'  # tag the resulting logs after fluid substitution
    rp.run_fluid_sub(wells, log_table, mymins, myfluids, cutoffs, wis, tag, templates=templates, block_name='FBlock')

    # plot results
    fig, ax = plt.subplots(figsize=(10, 8))
    log_table = {'P velocity': 'vp_dry', 'S velocity': 'vs_dry', 'Density': 'rho_dry',
                 'Porosity': 'phie', 'Volume': 'vcl'}
    templates['WELL_F']['color'] = 'b'
    prp.plot_rp(wells, log_table, wis, 'SAND E', cutoffs, templates, fig=fig, ax=ax, edge_color=False, show_masked=True,
                block_name='FBlock')

    # specify the new logs coming from the fluid substitution
    log_table = {'P velocity': 'vp_dry_fs', 'S velocity': 'vs_dry_fs', 'Density': 'rho_dry_fs',
                 'Porosity': 'phie', 'Volume': 'vcl'}
    templates['WELL_F']['color'] = 'r'
    prp.plot_rp(wells, log_table, wis, 'SAND E', cutoffs, templates, fig=fig, ax=ax, edge_color=False,
                block_name='FBlock')

    # specify the new logs coming from the RokDoc fluid substitution stored in the las file
    log_table = {'P velocity': 'vp_so08', 'S velocity': 'vs_so08', 'Density': 'rho_so08',
                 'Porosity': 'phie', 'Volume': 'vcl'}
    templates['WELL_F']['color'] = 'g'
    prp.plot_rp(wells, log_table, wis, 'SAND E', cutoffs, templates, fig=fig, ax=ax, edge_color=False,
                block_name='FBlock')

    del(wells['WELL_F'].block['FBlock'].logs['rho_so08'])
    del(wells['WELL_F'].block['FBlock'].logs['rho_sg08'])
    wells['WELL_F'].depth_plot('Density')


    # Save results
    for well in wells.values():
        uio.write_las(
            os.path.join(wp.working_dir, 'results_folder', '{}.las'.format(well.well)),
            well.header,
            well.block['FBlock'].header,
            well.block['FBlock'].logs
        )

    plt.show()
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
class PlotTestCase(unittest.TestCase):
    wp = Project()
    well_table = {
        os.path.join(wp.working_dir, 'test_data/Well D.las'): {
            'Given well name': 'WELL_D',
            'logs': {
                'ac': 'Sonic',
                'acs': 'Shear sonic',
                'cali': 'Caliper',
                'den': 'Density',
                'neu': 'Neutron density',
                'gr': 'Gamma ray',
                'rdep': 'Resistivity',
                'rmed': 'Resistivity',
                'rsha': 'Resistivity',
                'neu': 'Neutron density'
            },
            'Note': 'Some notes for well A'
        }
    }
    wis = {
        'WELL_D': {
            'SAND C': [1585.0, 1826.0],
            'SHALE C': [1585.0, 1826.0],
            'SAND D': [1826.0, 1878.0],
            'SAND E': [1878.0, 1984.0],
            'SAND F': [1984.0, 2158.0],
            'SHALE G': [2158.0, 2211.0],
            'SAND H': [2211.0, 2365.0]
        }
    }

    w = Well()
    w.read_well_table(well_table, 0, block_name='Logs')

    def test_axis_header(self):
        templ = uio.project_templates(PlotTestCase.wp.project_table)
        fig, ax = plt.subplots()
        log_types = ['P velocity', 'Density', 'Caliper', 'Resistivity']
        limits = [[templ[x]['min'], templ[x]['max']] for x in log_types]
        legends = ['test [{}]'.format(templ[x]['unit']) for x in log_types]
        styles = [{
            'lw': templ[x]['line width'],
            'color': templ[x]['line color'],
            'ls': templ[x]['line style']
        } for x in log_types]
        header_plot(ax, limits, legends, styles)
        plt.show()
        with self.subTest():
            self.assertTrue(True)

    def test_axis_plot(self):
        templ = uio.project_templates(PlotTestCase.wp.project_table)
        fig = plt.figure()
        ax = fig.add_subplot(2, 2, 1)
        log_types = ['Gamma ray', 'Caliper']
        limits = [[templ[x]['min'], templ[x]['max']] for x in log_types]
        data = [PlotTestCase.w.get_logs_of_type(x)[0].data for x in log_types]
        y = PlotTestCase.w.block['Logs'].logs['depth'].data
        styles = [{
            'lw': templ[x]['line width'],
            'color': templ[x]['line color'],
            'ls': templ[x]['line style']
        } for x in log_types]
        axis_plot(ax, y, data, limits, styles, nxt=2)

        plt.show()

    def test_plot_logs(self):
        from blixt_utils.io.io import invert_well_table
        w = PlotTestCase.w
        templates = uio.project_templates(PlotTestCase.wp.project_table)
        ppl.plot_logs(w,
                      invert_well_table(PlotTestCase.well_table,
                                        'WELL_D',
                                        rename=False),
                      PlotTestCase.wis,
                      "SAND E",
                      templates,
                      buffer=50.)
        #savefig='C:/users/mblixt/PycharmProjects/blixt_rp/results_folder/test.png')
        #savefig='C:/Users/marten/PycharmProjects/blixt_rp/results_folder/test.png')
        with self.subTest():
            self.assertTrue(True)
Ejemplo n.º 8
0
class MasksTestCase(unittest.TestCase):
    wp = Project(name='MyProject', log_to_stdout=True)
    # Instead of creating the well table directly from the project table,
    # we can assure the well table to contain the  desired well by
    # writing it explicitly
    well_table = {os.path.join(wp.working_dir, 'test_data/Well A.las'):
                      {'Given well name': 'WELL_A',
                       'logs': {
                           'vp_dry': 'P velocity',
                           'vp_sg08': 'P velocity',
                           'vp_so08': 'P velocity',
                           'vs_dry': 'S velocity',
                           'vs_sg08': 'S velocity',
                           'vs_so08': 'S velocity',
                           'rho_dry': 'Density',
                           'rho_sg08': 'Density',
                           'rho_so08': 'Density',
                           'phie': 'Porosity',
                           'vcl': 'Volume'},
                       'Note': 'Some notes for well A'}}

    # las_file = os.path.join(wp.working_dir, 'test_data', 'Well A.las')
    # my_logs = None
    tops = {
        'WELL_A': {'TOP A': 408.0,
                   'TOP B': 1560.0,
                   'TOP C': 1585.0,
                   'TOP D': 1826.0,
                   'TOP E': 1878.0,
                   'TOP F': 1984.0,
                   'BASE F': 2158.0,
                   'TOP G': 2158.0,
                   'TOP H': 2211.0,
                   'BASE H': 2365.0,
                   'TOP I': 2365.0,
                   'TOP J': 2452.0}
    }
    wis = {'WELL_A': {
        'SAND C': [1585.0, 1826.0],
        'SHALE C': [1585.0, 1826.0],
        'SAND D': [1826.0, 1878.0],
        'SAND E': [1878.0, 1984.0],
        'SAND F': [1984.0, 2158.0],
        'SHALE G': [2158.0, 2211.0],
        'SAND H': [2211.0, 2365.0]
    }}

    def test_calc_mask(self):
        lmt = 0.1
        w, phie = create_test_data('phie')
        masked_length = len(phie[phie < lmt])

        #
        # Create the same mask using the create mask function
        #
        cutoff = {'phie': ['<', lmt]}
        w.calc_mask(cutoff, name=def_msk_name, log_type_input=False)
        msk = w.block[def_lb_name].masks[def_msk_name].data
        # Test length
        with self.subTest():
            print(masked_length, len(phie[msk]))
            self.assertEqual(masked_length, len(phie[msk]))
        # Test value
        with self.subTest():
            print(np.nanmax(phie[msk]), lmt)
            self.assertLess(np.nanmax(phie[msk]), lmt)
        del (w.block[def_lb_name].masks[def_msk_name])

        #
        # Create the same mask using the create mask function with log type
        #
        print('Testing log type input: Porosity')
        w.calc_mask({'Porosity': ['<', lmt]}, name=def_msk_name, log_type_input=True)
        msk = w.block[def_lb_name].masks[def_msk_name].data
        # Test length
        with self.subTest():
            print(masked_length, len(phie[msk]))
            self.assertEqual(masked_length, len(phie[msk]))
        # Test value
        with self.subTest():
            print(np.nanmax(phie[msk]), lmt)
            self.assertLess(np.nanmax(phie[msk]), lmt)
        del (w.block[def_lb_name].masks[def_msk_name])

        #
        # Create mask applying tops
        #
        print('Test masking with tops input')
        w.calc_mask({'Porosity': ['<', lmt]}, name=def_msk_name,
                    tops=MasksTestCase.tops, use_tops=['TOP C', 'BASE F'], log_type_input=True)
        msk = w.block[def_lb_name].masks[def_msk_name].data
        # Test value
        with self.subTest():
            print(np.nanmax(phie[msk]), lmt)
            self.assertLess(np.nanmax(phie[msk]), lmt)
        del (w.block[def_lb_name].masks[def_msk_name])

        #
        # Create mask from empty cutoffs, allow all data
        #
        print('Test mask with empty cutoffs')
        w.calc_mask({})
        msk = w.block[def_lb_name].masks[def_msk_name].data
        with self.subTest():
            print(len(phie), len(phie[msk]))
            self.assertEqual(len(phie), len(phie[msk]))

        del (w.block[def_lb_name].masks[def_msk_name])

        #
        # Ask for a mask for a log that does not exists
        #
        print('Test mask without any valid logs')
        any_error = False
        try:
            w.calc_mask({'Saturation': ['<', lmt]}, name=def_msk_name, log_type_input=True)
        except:
            any_error = True
        # Test if error was raised
        with self.subTest():
            self.assertFalse(any_error)

        #
        # Create mask applying working intervals
        #
        print('Test masking with working intervals input')
        w.calc_mask({'Porosity': ['<', lmt]}, name=def_msk_name,
                    wis=MasksTestCase.wis, wi_name='SAND E', log_type_input=True)
        msk = w.block[def_lb_name].masks[def_msk_name].data
        # Test value
        with self.subTest():
            print(np.nanmax(phie[msk]), lmt)
            self.assertLess(np.nanmax(phie[msk]), lmt)
        del (w.block[def_lb_name].masks[def_msk_name])

        #
        # Create mask using working intervals, but no cutoffs
        #
        print('Test masking with working intervals, but no cutoff')
        w.calc_mask({}, name=def_msk_name,
                    wis=MasksTestCase.wis, wi_name='SAND E')
        msk = w.block[def_lb_name].masks[def_msk_name].data
        print('SAND E MD limits in WELL_A:', MasksTestCase.wis['WELL_A']['SAND E'])
        depths = w.block[def_lb_name].get_md()[msk]
        print('Masked MD min and max:', depths.min(), depths.max())

        # w.calc_mask({'sw': ['<', lmt]}, name=def_msk_name, log_type_input=False)
        # msk = w.block[def_lb_name].masks[def_msk_name].data
        ## Test length
        # with self.subTest():
        #    print(masked_length, len(phie[msk]))
        #    self.assertEqual(masked_length, len(phie[msk]))

    def test_apply_mask(self):
        lmt = 0.1
        w, phie = create_test_data('phie')
        masked_length = len(phie[phie < lmt])

        cutoff = {'phie': ['<', lmt]}
        w.calc_mask(cutoff, name=def_msk_name, log_type_input=False)
        msk = w.block[def_lb_name].masks[def_msk_name].data
        w.apply_mask(def_msk_name)
        m_phie = w.block[def_lb_name].logs['phie'].data

        # Test length
        with self.subTest():
            print(masked_length, len(m_phie))
            self.assertEqual(masked_length, len(m_phie))
        # Test value
        with self.subTest():
            print(np.nanmax(m_phie), lmt)
            self.assertLess(np.nanmax(m_phie), lmt)

        w.calc_mask({}, name=def_msk_name,
                    wis=MasksTestCase.wis, wi_name='Sand F')
        msk = w.block[def_lb_name].masks[def_msk_name].data
        w.apply_mask(def_msk_name)
        print('Sand F MD limits in WELL_A:', MasksTestCase.wis['WELL_A']['SAND F'])
        depths = w.block[def_lb_name].get_md()
        print('Masked MD min and max:', depths.min(), depths.max())

    def test_append_mask(self):
        w, phie = create_test_data('phie')

        lmt1 = 0.05;
        lmt2 = 0.1
        masked_length = len(phie[(phie > lmt1) & (phie < lmt2)])

        # create first mask
        cutoff_1 = {'phie': ['>', lmt1]}
        w.calc_mask(cutoff_1, name=def_msk_name, log_type_input=False)
        msk = w.block[def_lb_name].masks[def_msk_name].data
        # Test value
        with self.subTest():
            print(np.nanmin(phie[msk]), lmt1)
            self.assertGreater(np.nanmin(phie[msk]), lmt1)

        # append second mask
        cutoff_2 = {'phie': ['<', lmt2]}
        w.calc_mask(cutoff_2, name=def_msk_name, append='AND', log_type_input=False)
        msk = w.block[def_lb_name].masks[def_msk_name].data
        # Test value
        with self.subTest():
            print(np.nanmax(phie[msk]), lmt2)
            self.assertLess(np.nanmin(phie[msk]), lmt2)
        # Test length
        with self.subTest():
            print(masked_length, len(phie[msk]))
            print(w.block[def_lb_name].masks[def_msk_name].header.desc)
            self.assertEqual(masked_length, len(phie[msk]))
Ejemplo n.º 9
0
class LasTestCase(unittest.TestCase):
    wp = Project(name='MyProject', log_to_stdout=True)
    well_table = uio.project_wells(wp.project_table, wp.working_dir)
    #las_file = list(well_table.keys())[0]
    las_file = os.path.join(wp.working_dir, 'test_data/Well A.las')
    #my_logs = well_table[las_file]['logs']
    my_logs = None

    def test_read_las(self):
        null_value, gen_keys, well_dict = read_las(LasTestCase.las_file)
        with self.subTest():
            print(len(gen_keys), len(list(well_dict['data'].keys())))
            self.assertEqual(len(gen_keys),
                             len(list(well_dict['data'].keys())))

    def test_header_types(self):
        """
        All header keys in the well header, and Block header should be of the AttribDict type
        :return:
        """
        w, data = create_test_data('phie')
        success = True
        for key in list(w.header.keys()):
            if key == 'well':
                # the well name is having a special treatment:-(
                continue
            if not isinstance(w.header[key], AttribDict):
                print(key, w.header[key])
                success = False
        for lblock in list(w.block.keys()):
            for key in list(w.block[lblock].header.keys()):
                if key == 'well':
                    continue
                if not isinstance(w.block[lblock].header[key], AttribDict):
                    print(key, w.block[lblock].header[key])
                    success = False
        self.assertTrue(success)

    def test_null_value(self):
        """
        When reading in a las file, any 'null values' should be replaced with np.nan
        :return:
        """
        null_value, gen_keys, well_dict = read_las(LasTestCase.las_file)
        var_name = gen_keys[1]
        data = np.array(well_dict['data'][var_name])
        # data should not contain explicit 'null_value's, so below null_data should have length zero
        null_data = data[data == float(null_value)]
        with self.subTest():
            print(var_name, null_value, len(null_data))
            self.assertEqual(0, len(null_data))
        with self.subTest():
            # these test data should contain NaN's, so t below should contain some True elements
            t = np.isnan(data)
            print('Data contains NaN:', any(t))
            self.assertTrue(any(t))

    def test_well_info(self):
        _las_file = os.path.join(LasTestCase.wp.working_dir,
                                 'test_data/WrongWellInfo.las')
        null_value, gen_keys, well_dict = read_las(_las_file)
        for key in list(well_dict['well_info'].keys()):
            print(well_dict['well_info'][key]['value'],
                  type(well_dict['well_info'][key]['value']))
Ejemplo n.º 10
0
class RpTestCase(unittest.TestCase):
    wp = Project()
    well_table = {
        os.path.join(wp.working_dir, 'test_data/Well D.las'): {
            'Given well name': 'WELL_D',
            'logs': {
                'ac': 'Sonic',
                'acs': 'Shear sonic',
                'cali': 'Caliper',
                'den': 'Density',
                'gr': 'Gamma ray',
                'rdep': 'Resistivity',
                'rmed': 'Resistivity',
                'rsha': 'Resistivity',
                'neu': 'Neutron density'
            },
            'Note': 'Some notes for well A'
        }
    }
    wis = {
        'WELL_D': {
            'SAND C': [1585.0, 1826.0],
            'SHALE C': [1585.0, 1826.0],
            'SAND D': [1826.0, 1878.0],
            'SAND E': [1878.0, 1984.0],
            'SAND F': [1984.0, 2158.0],
            'SHALE G': [2158.0, 2211.0],
            'SAND H': [2211.0, 2365.0]
        }
    }

    w = Well()
    w.read_well_table(well_table, 0, block_name='Logs')

    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 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_gradient(self):
        """
        Should test if the gradient 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')
        vs = cnvrt(RpTestCase.w.block['Logs'].logs['acs'].data, 'us/ft', 'm/s')
        grad2 = rp.gradient(vp, None, vs, None, rho, None, along_wiggle=True)
        i = 10637
        grad1 = rp.gradient(vp[i], vp[i + 1], vs[i], vs[i + 1], rho[i],
                            rho[i + 1])
        grad1_2 = rp.gradient(vp[i + 1], vp[i + 2], vs[i + 1], vs[i + 2],
                              rho[i + 1], rho[i + 2])

        with self.subTest():
            print('Layer based gradient at i {}: {}'.format(i, grad1))
            print('Layer based gradient at i {}: {}'.format(i + 1, grad1_2))
            print('Wiggle based gradient at i {}: {}'.format(
                i, grad2[i:i + 2]))
            self.assertTrue(True)

    def test_reflectivity(self):
        """
        What happens when the input to the reflectivity is an array?
        :return:
        """
        i = 10637
        theta = 10.  # degrees
        rho = RpTestCase.w.block['Logs'].logs['den'].data
        vp = cnvrt(RpTestCase.w.block['Logs'].logs['ac'].data, 'us/ft', 'm/s')
        vs = cnvrt(RpTestCase.w.block['Logs'].logs['acs'].data, 'us/ft', 'm/s')

        func1 = rp.reflectivity(vp[i], vp[i + 1], vs[i], vs[i + 1], rho[i],
                                rho[i + 1])
        func1_2 = rp.reflectivity(vp[i + 1], vp[i + 2], vs[i + 1], vs[i + 2],
                                  rho[i + 1], rho[i + 2])
        func2 = rp.reflectivity(vp,
                                None,
                                vs,
                                None,
                                rho,
                                None,
                                along_wiggle=True)

        with self.subTest():
            print('Layer based refl. coeff. at i {} at {} deg.: {}'.format(
                i, theta, func1(theta)))
            print('Layer based refl. coeff. at i {} at {} deg.: {}'.format(
                i + 1, theta, func1_2(theta)))
            print('Wiggle based refl. coeff. at i {} at {} deg.: {}'.format(
                i, theta,
                func2(theta)[i:i + 2]))
            self.assertTrue(True)

    def test_greenberg_castagna(self):
        """
        Example taken from p. 248 in Rock physics handbook, Mavko et al. 1999
        :return:
        """
        vp = 3000.
        f = [0.6, 0.4]
        mono_mins = ['sandstone', 'SHALE']
        gc_coeffs = {
            'sandstone': [0., 0.80416, -0.85588],
            'limestone': [-0.05508, 1.01677, -1.03049],
            'dolomite': [0., 0.58321, -0.07775],
            'shale': [0., 0.76969, -0.86735]
        }
        vs = rp.greenberg_castagna(vp, f, mono_mins, gc_coeffs)

        with self.subTest():
            print('Greenberg Castagna Vs estimate: {}'.format(vs.value))
            self.assertAlmostEqual(vs.value, 1509.58, places=1)
Ejemplo n.º 11
0
 def test_load_wells(self):
     wp = Project(name='MyProject', log_to_stdout=True)
     wells = wp.load_all_wells()
     for _, well in wells.items():
         with self.subTest():
             self.assertTrue(well, Well)
Ejemplo n.º 12
0
 def test_create_project(self):
     wp = Project(name='MyProject', log_to_stdout=True)
     with self.subTest():
         print(type(wp))
         self.assertTrue(isinstance(wp, Project))
Ejemplo n.º 13
0
def test():
    from core.well import Project
    import blixt_utils.io.io as uio
    from core.minerals import MineralMix
    wi_name = 'SAND E'

    plot_type = 'AI-VpVs'
    ref_val = [2695., 1340., 2.35]  # Kvitnos shale

    fig, ax = plt.subplots()

    wp = Project()
    log_table = {
        'P velocity': 'vp_dry',
        'S velocity': 'vs_dry',
        'Density': 'rho_dry',
        'Porosity': 'phie',
        'Volume': 'vcl'
    }
    wis = uio.project_working_intervals(wp.project_table)
    templates = uio.project_templates(wp.project_table)
    cutoffs = {'Volume': ['<', 0.4], 'Porosity': ['>', 0.1]}
    wells = wp.load_all_wells()
    plot_rp(wells,
            log_table,
            wis,
            wi_name,
            cutoffs,
            templates,
            plot_type=plot_type,
            ref_val=ref_val,
            fig=fig,
            ax=ax)

    # Calculate average properties of mineral mix in desired working interval
    mm = MineralMix()
    mm.read_excel(wp.project_table)
    _rho_min = np.ones(0)  # zero length empty array
    _k_min = np.ones(0)
    _mu_min = np.ones(0)
    for well in wells.values():
        # calculate the mask for the given cut-offs, and for the given working interval
        well.calc_mask(cutoffs,
                       wis=wis,
                       wi_name=wi_name,
                       name='this_mask',
                       log_table=log_table)
        mask = well.block['Logs'].masks['this_mask'].data

        _rho_min = np.append(
            _rho_min,
            well.calc_vrh_bounds(mm, param='rho', wis=wis,
                                 method='Voigt')[wi_name][mask])
        _k_min = np.append(
            _k_min,
            well.calc_vrh_bounds(mm,
                                 param='k',
                                 wis=wis,
                                 method='Voigt-Reuss-Hill')[wi_name][mask])
        _mu_min = np.append(
            _mu_min,
            well.calc_vrh_bounds(mm,
                                 param='mu',
                                 wis=wis,
                                 method='Voigt-Reuss-Hill')[wi_name][mask])

    rho_min = np.nanmean(_rho_min)
    k_min = np.nanmean(_k_min)
    mu_min = np.nanmean(_mu_min)

    phi = np.linspace(0.05, 0.3, 6)
    sw = np.array([0.8, 0.95, 1.])
    sizes = np.empty((sw.size, phi.size))
    colors = np.array([np.ones(6) * 100 * (i + 1)**2 for i in range(3)]) / 900.
    # iterate over all phi values
    for i, val in enumerate(phi):
        sizes[:, i] = 10 + (40 * val)**2

    xx, yy = plot_rpt(phi,
                      rpt_phi_sw,
                      sw, {
                          'plot_type': plot_type,
                          'ref_value': ref_val,
                          'model': 'stiff',
                          'rho_min': rho_min,
                          'k_min': k_min,
                          'mu_min': mu_min
                      },
                      sizes,
                      colors,
                      fig=fig,
                      ax=ax)

    # Annotate rpt
    dx = 0
    dy = 0.0
    plt.text(xx[-1][-1] + dx, yy[-1][-1] + dy,
             '$\phi={:.02f}$'.format(phi[-1]), **opt1)
    plt.text(xx[-1][0] + dx, yy[-1][0] + dy, '$\phi={:.02f}$'.format(phi[0]),
             **opt1)
    for i, _sw in enumerate(sw):
        plt.text(xx[i][-1] + dx, yy[i][-1] + dy, '$S_w={:.02f}$'.format(_sw),
                 **opt2)

    plt.show()