Exemple #1
0
def corr_cluster(trace_list, thresh=0.9):
    """
    Group traces based on correlations above threshold with the stack - will
    run twice, once with a lower threshold, then again with your threshold to
    remove large outliers

    :type trace_list: List of :class:obspy.Trace
    :param trace_list: Traces to compute similarity between
    :type thresh: float
    :param thrsh: Correlation threshold between -1-1

    :returns: np.ndarray of bool
    """
    from eqcorrscan.utils import stacking
    from obspy import Stream
    from core.match_filter import normxcorr2
    stack=stacking.linstack([Stream(tr) for tr in trace_list])[0]
    output=np.array([False]*len(trace_list))
    group1=[]
    for i, tr in enumerate(trace_list):
        if normxcorr2(tr.data,stack.data)[0][0] > 0.6:
            output[i]=True
            group1.append(tr)
    stack=stacking.linstack([Stream(tr) for tr in group1])[0]
    group2=[]
    for i, tr in enumerate(trace_list):
        if normxcorr2(tr.data,stack.data)[0][0] > thresh:
            group2.append(tr)
            output[i]=True
        else:
            output[i]=False
    return output
def cross_chan_coherence(st1, st2):
    """
    Function to determine the cross-channel coherancy between two streams of
    multichannel seismic data.

    :type st1: obspy Stream
    :param st1: Stream one
    :type st2: obspy Stream
    :param st2: Stream two

    :returns: cross channel coherence, float - normalized by number of channels
    """
    from eqcorrscan.core.match_filter import normxcorr2
    cccoh=0.0
    kchan=0
    for tr in st1:
        tr1=tr.data
        # Assume you only have one waveform for each channel
        tr2=st2.select(station=tr.stats.station, \
                       channel=tr.stats.channel)
        if tr2:
            cccoh+=normxcorr2(tr1,tr2[0].data)[0][0]
            kchan+=1
    cccoh=cccoh/kchan
    return cccoh
Exemple #3
0
 def test_interp_not_enough_samples(self):
     synth_template = np.sin(np.arange(0, 2, 0.001))
     synth_detection = synth_template[11:]
     synth_template = synth_template[0:-10]
     ccc = normxcorr2(synth_detection, synth_template)[0]
     with self.assertRaises(IndexError):
         _xcorr_interp(ccc, 0.01)
Exemple #4
0
def cross_chan_coherence(st1, st2, i=0):
    """
    Function to determine the cross-channel coherancy between two streams of
    multichannel seismic data.

    :type st1: obspy Stream
    :param st1: Stream one
    :type st2: obspy Stream
    :param st2: Stream two
    :type i: int
    :param i: index used for parallel async processing, returned unaltered

    :returns: cross channel coherence, float - normalized by number of channels,
        if i, returns tuple of (cccoh, i) where i is int, as intput.
    """
    from eqcorrscan.core.match_filter import normxcorr2
    cccoh=0.0
    kchan=0
    for tr in st1:
        tr1=tr.data
        # Assume you only have one waveform for each channel
        tr2=st2.select(station=tr.stats.station, \
                       channel=tr.stats.channel)
        if tr2:
            cccoh+=normxcorr2(tr1,tr2[0].data)[0][0]
            kchan+=1
    if kchan:
        cccoh=cccoh/kchan
        return (cccoh, i)
    else:
        warnings.warn('No matching channels')
        return (0, i)
Exemple #5
0
def cassm_clock_correct(gmug_tr,
                        vbox_tr,
                        trig_tr,
                        which=0,
                        debug=0,
                        name=None):
    """
    Find first CASSM shot in common and use cross correlation to estimate
    the clock offset between the two systems.

    Will be done for each GMuG file, but not each Vibbox file

    :param gmug_st: Trace of B81 on gmug
    :param vbox_st: Trace of B81 on vbox
    :param trig_tr: Trace of the CASSM trigger
    :param which: 0 for first or -1 for last trigger
    :param debug: Debug flag for correlation plot
    :param name: Name of output h5 file for plot naming if debug > 0

    :return:
    """
    # Use derivative of PPS signal to find pulse start
    dt = np.diff(trig_tr.data)
    # Use 70 * MAD threshold
    samp_to_trig = np.where(
        dt > np.mean(dt) + 70 * median_absolute_deviation(dt))[0][which]
    trig1_time = vbox_tr.stats.starttime + (float(samp_to_trig) /
                                            vbox_tr.stats.sampling_rate)
    print('    Trigger: {}'.format(trig1_time))
    cc_vbox = vbox_tr.copy().trim(trig1_time,
                                  endtime=trig1_time + 0.01).detrend('demean')
    cc_gmug = gmug_tr.copy().trim(trig1_time,
                                  endtime=trig1_time + 0.2).detrend('demean')
    print('        Vbox {}--{}'.format(vbox_tr.stats.starttime,
                                       vbox_tr.stats.endtime))
    print('        GMuG {}--{}'.format(gmug_tr.stats.starttime,
                                       gmug_tr.stats.endtime))
    try:
        cc_gmug.resample(cc_vbox.stats.sampling_rate)
    except AttributeError as e:  # Outside range of gmug waveform
        return 0., np.array([0.0]), UTCDateTime()
    ccc = normxcorr2(cc_vbox.data, cc_gmug.data)
    max_cc = np.argmax(ccc[0])
    max_cc_sec = float(max_cc) / cc_vbox.stats.sampling_rate
    if debug > 0:
        fig, axes = plt.subplots(nrows=2)
        vbox_x = np.arange(start=max_cc, stop=max_cc + cc_vbox.data.shape[0])
        axes[0].plot(cc_gmug.data / np.max(cc_gmug.data),
                     color='k',
                     linewidth=0.7)
        axes[1].axvline(x=max_cc, linestyle=':', color='gray')
        axes[0].axvline(x=max_cc, linestyle=':', color='gray')
        axes[0].plot(vbox_x,
                     cc_vbox.data / np.max(cc_vbox.data),
                     color='r',
                     linewidth=0.7)
        axes[1].plot(ccc[0], color='b', linewidth=0.7)
        plt.savefig(name.replace('.h5', 'time_cc.png'))
        plt.close('all')
    return max_cc_sec, ccc, trig1_time
Exemple #6
0
 def test_interp_few_samples(self):
     synth_template = np.sin(np.arange(0, 2, 0.001))
     synth_detection = synth_template[13:]
     synth_template = synth_template[0:-10]
     ccc = normxcorr2(synth_detection, synth_template)
     shift, coeff = lag_calc._xcorr_interp(ccc, 0.01)
     self.assertEqual(shift.round(), 0.0)
     self.assertEqual(coeff.round(), 1.0)
Exemple #7
0
 def test_interp_normal(self):
     synth_template = np.sin(np.arange(0, 4, 0.01))
     image = np.zeros(1000)
     image[200] = 1
     image = np.convolve(image, synth_template)
     ccc = normxcorr2(synth_template, image)
     shift, coeff = _xcorr_interp(ccc, 0.01)
     self.assertEqual(shift.round(), 2.0)
     self.assertEqual(coeff.round(), 1.0)
Exemple #8
0
 def test_fail_normxcorr2(self):
     """Ensure if template is nan then return is nan
     """
     template = np.array([np.nan] * 100)
     image = np.zeros(1000)
     image[200] = 1.0
     image = np.convolve(template, image)
     ccc = normxcorr2(template, image)
     self.assertTrue(np.all(ccc == 0.0))
Exemple #9
0
 def test_perfect_normxcorr2(self):
     """Simple test of normxcorr2 to ensure data are detected
     """
     template = np.random.randn(100).astype(np.float32)
     image = np.zeros(1000).astype(np.float32)
     image[200] = 1.0
     image = np.convolve(template, image)
     ccc = normxcorr2(template, image).astype(np.float16)
     self.assertEqual(ccc.max(), 1.0)
Exemple #10
0
 def test_triple_plot(self):
     template = self.st[0].copy().trim(self.st[0].stats.starttime + 8,
                                       self.st[0].stats.starttime + 12)
     tr = self.st[0].copy()
     ccc = normxcorr2(template=template.data, image=tr.data)
     tr.data = tr.data[0:len(ccc[0])]
     fig = triple_plot(cccsum=ccc[0], cccsum_hist=ccc[0], trace=tr,
                       threshold=0.8, show=False, return_figure=True)
     return fig
Exemple #11
0
def template_remove(tr, template, cc_thresh, windowlength,
                    interp_len, debug=0):
    """
    Looks for instances of template in the trace and removes the matches.

    :type tr: obspy.core.Trace
    :param tr: Trace to remove spikes from.
    :type template: osbpy.core.Trace
    :param template: Spike template to look for in data.
    :type cc_thresh: float
    :param cc_thresh: Cross-correlation threshold (-1 - 1).
    :type windowlength: float
    :param windowlength: Length of window to look for spikes in in seconds.
    :type interp_len: float
    :param interp_len: Window length to remove and fill in seconds.
    :type debug: int
    :param debug: Debug level.

    :returns: tr, works in place.
    """
    from eqcorrscan.core.match_filter import normxcorr2
    from eqcorrscan.utils.findpeaks import find_peaks2_short
    from obspy import Trace
    from eqcorrscan.utils.timer import Timer
    import matplotlib.pyplot as plt
    import warnings

    data_in = tr.copy()
    _interp_len = int(tr.stats.sampling_rate * interp_len)
    if _interp_len < len(template.data):
        warnings.warn('Interp_len is less than the length of the template,'
                      'will used the length of the template!')
        _interp_len = len(template.data)
    if isinstance(template, Trace):
        template = template.data
    with Timer() as t:
        cc = normxcorr2(tr.data.astype(np.float32),
                        template.astype(np.float32))
        if debug > 3:
            plt.plot(cc.flatten(), 'k', label='cross-correlation')
            plt.legend()
            plt.show()
        peaks = find_peaks2_short(arr=cc.flatten(), thresh=cc_thresh,
                                  trig_int=windowlength * tr.stats.
                                  sampling_rate)
        for peak in peaks:
            tr.data = _interp_gap(data=tr.data,
                                  peak_loc=peak[1] + int(0.5 * _interp_len),
                                  interp_len=_interp_len)
    print("Despiking took: %s s" % t.secs)
    if debug > 2:
        plt.plot(data_in.data, 'r', label='raw')
        plt.plot(tr.data, 'k', label='despiked')
        plt.legend()
        plt.show()
    return tr
Exemple #12
0
 def test_normal_normxcorr2(self):
     """Check that if match is not perfect correlation max isn't unity
     """
     template = np.random.randn(100) * 10.0
     image = np.zeros(1000)
     image[200] = 1.0
     image = np.convolve(template, image)
     image += np.random.randn(1099)  # Add random noise
     ccc = normxcorr2(template, image)
     self.assertNotEqual(ccc.max(), 1.0)
Exemple #13
0
def corr_cluster(trace_list, thresh=0.9):
    """
    Group traces based on correlations above threshold with the stack.

    Will run twice, once with a lower threshold to remove large outliers that
    would negatively affect the stack, then again with your threshold.

    :type trace_list: list
    :param trace_list:
        List of :class:`obspy.core.stream.Trace`s to compute similarity between
    :type thresh: float
    :param thresh: Correlation threshold between -1-1

    :returns:
        :class:`numpy.ndarray` of bool of whether that trace correlates well
        enough (above your given threshold) with the stack.

    .. note::
        We recommend that you align the data before computing the clustering,
        e.g., the P-arrival on all templates for the same channel should
        appear at the same time in the trace.  See the
        :func:`eqcorrscan.utils.stacking.align_traces` function for a way to do
        this.
    """
    stack = stacking.linstack([Stream(tr) for tr in trace_list])[0]
    output = np.array([False] * len(trace_list))
    group1 = []
    for i, tr in enumerate(trace_list):
        if normxcorr2(tr.data, stack.data)[0][0] > 0.6:
            output[i] = True
            group1.append(tr)
    if not group1:
        warnings.warn('Nothing made it past the first 0.6 threshold')
        return output
    stack = stacking.linstack([Stream(tr) for tr in group1])[0]
    group2 = []
    for i, tr in enumerate(trace_list):
        if normxcorr2(tr.data, stack.data)[0][0] > thresh:
            group2.append(tr)
            output[i] = True
        else:
            output[i] = False
    return output
Exemple #14
0
def template_remove(tr,
                    template,
                    cc_thresh,
                    windowlength,
                    interp_len,
                    debug=0):
    """
    Looks for instances of template in the trace and removes the matches.

    :type tr: obspy.core.trace.Trace
    :param tr: Trace to remove spikes from.
    :type template: osbpy.core.trace.Trace
    :param template: Spike template to look for in data.
    :type cc_thresh: float
    :param cc_thresh: Cross-correlation threshold (-1 - 1).
    :type windowlength: float
    :param windowlength: Length of window to look for spikes in in seconds.
    :type interp_len: float
    :param interp_len: Window length to remove and fill in seconds.
    :type debug: int
    :param debug: Debug level.

    :returns: tr, works in place.
    :rtype: :class:`obspy.core.trace.Trace`
    """
    data_in = tr.copy()
    _interp_len = int(tr.stats.sampling_rate * interp_len)
    if _interp_len < len(template.data):
        warnings.warn('Interp_len is less than the length of the template,'
                      'will used the length of the template!')
        _interp_len = len(template.data)
    if isinstance(template, Trace):
        template = template.data
    with Timer() as t:
        cc = normxcorr2(image=tr.data.astype(np.float32),
                        template=template.astype(np.float32))
        if debug > 3:
            plt.plot(cc.flatten(), 'k', label='cross-correlation')
            plt.legend()
            plt.show()
        peaks = find_peaks2_short(arr=cc.flatten(),
                                  thresh=cc_thresh,
                                  trig_int=windowlength *
                                  tr.stats.sampling_rate)
        for peak in peaks:
            tr.data = _interp_gap(data=tr.data,
                                  peak_loc=peak[1] + int(0.5 * _interp_len),
                                  interp_len=_interp_len)
    print("Despiking took: %s s" % t.secs)
    if debug > 2:
        plt.plot(data_in.data, 'r', label='raw')
        plt.plot(tr.data, 'k', label='despiked')
        plt.legend()
        plt.show()
    return tr
Exemple #15
0
 def test_fail_normxcorr2(self):
     """Ensure it template is nan then return is nan
     """
     import numpy as np
     from eqcorrscan.core.match_filter import normxcorr2
     template = np.array([np.nan] * 100)
     image = np.zeros(1000)
     image[200] = 1.0
     image = np.convolve(template, image)
     ccc = normxcorr2(template, image)
     self.assertTrue(np.all(ccc == 0.0))
Exemple #16
0
 def test_perfect_normxcorr2(self):
     """Simple test of normxcorr2 to ensure data are detected
     """
     import numpy as np
     from eqcorrscan.core.match_filter import normxcorr2
     template = np.random.randn(100).astype(np.float32)
     image = np.zeros(1000).astype(np.float32)
     image[200] = 1.0
     image = np.convolve(template, image)
     ccc = normxcorr2(template, image).astype(np.float16)
     self.assertEqual(ccc.max(), 1.0)
Exemple #17
0
 def test_perfect_normxcorr2(self):
     """Simple test of normxcorr2 to ensure data are detected
     """
     import numpy as np
     from eqcorrscan.core.match_filter import normxcorr2
     template = np.random.randn(100).astype(np.float32)
     image = np.zeros(1000).astype(np.float32)
     image[200] = 1.0
     image = np.convolve(template, image)
     ccc = normxcorr2(template, image).astype(np.float16)
     self.assertEqual(ccc.max(), 1.0)
Exemple #18
0
 def test_fail_normxcorr2(self):
     """Ensure if template is nan then return is nan
     """
     import numpy as np
     from eqcorrscan.core.match_filter import normxcorr2
     template = np.array([np.nan] * 100)
     image = np.zeros(1000)
     image[200] = 1.0
     image = np.convolve(template, image)
     ccc = normxcorr2(template, image)
     self.assertTrue(np.all(ccc == 0.0))
Exemple #19
0
def coherence(stream_in, stations=['all'], clip=False):
    """
    Determine the average network coherence of a given template or detection.
    You will want your stream to contain only \
    signal as noise will reduce the coherence (assuming it is incoherent \
    random noise).

    :type stream_in: obspy.core.stream.Stream
    :param stream_in: The stream of seismic data you want to calculate the \
            coherence for.
    :type stations: list
    :param stations: List of stations to use for coherence, default is all
    :type clip: tuple
    :param clip: Default is to use all the data given - \
            tuple of start and end in seconds from start of trace

    :return: float - coherence, int number of channels used
    """
    from eqcorrscan.core.match_filter import normxcorr2
    stream = stream_in.copy()  # Copy the data before we remove stations
    # First check that all channels in stream have data of the same length
    maxlen = np.max([len(tr.data) for tr in stream])
    if maxlen == 0:
        warnings.warn('template without data')
        return 0.0, len(stream)
    if not stations[0] == 'all':
        for tr in stream:
            if tr.stats.station not in stations:
                stream.remove(tr)  # Remove stations we don't want to use
    for tr in stream:
        if not len(tr.data) == maxlen and not len(tr.data) == 0:
            warnings.warn(tr.stats.station + '.' + tr.stats.channel +
                          ' is not the same length, padding \n' +
                          'Length is ' + str(len(tr.data)) + ' samples')
            pad = np.zeros(maxlen - len(tr.data))
            if tr.stats.starttime.hour == 0:
                tr.data = np.concatenate((pad, tr.data), axis=0)
            else:
                tr.data = np.concatenate((tr.data, pad), axis=0)
        elif len(tr.data) == 0:
            tr.data = np.zeros(maxlen)
    # Clip the data to the set length
    if clip:
        for tr in stream:
            tr.trim(tr.stats.starttime + clip[0], tr.stats.starttime + clip[1])
    coherence = 0.0
    # Loop through channels and generate a correlation value for each
    # unique cross-channel pairing
    for i in range(len(stream)):
        for j in range(i + 1, len(stream)):
            coherence += np.abs(normxcorr2(stream[i].data,
                                           stream[j].data))[0][0]
    coherence = 2 * coherence / (len(stream) * (len(stream) - 1))
    return coherence, len(stream)
Exemple #20
0
 def test_xcorr_plot_cc_vec(self):
     st = self.st.copy().detrend('simple').filter(
         'bandpass', freqmin=2, freqmax=15)
     cc_vec = normxcorr2(
         template=st[0].data.astype(np.float32)[40:-40],
         image=st[1].data.astype(np.float32))
     cc_vec = cc_vec[0]
     fig = xcorr_plot(
         template=st[1].data[40:-40], image=st[0].data, cc_vec=cc_vec,
         show=False, return_figure=True)
     return fig
def coherence(stream_in, stations=['all'], clip=False):
    """
    Determine the average network coherence of a given template or detection.

    You will want your stream to contain only signal as noise will reduce the
    coherence (assuming it is incoherent random noise).

    :type stream_in: obspy.core.stream.Stream
    :param stream_in: The stream of seismic data you want to calculate the \
            coherence for.
    :type stations: list
    :param stations: List of stations to use for coherence, default is all
    :type clip: tuple
    :param clip: Default is to use all the data given (`False`) - \
            tuple of start and end in seconds from start of trace

    :return: tuple of coherence and number of channels used.
    :rtype: tuple
    """
    stream = stream_in.copy()  # Copy the data before we remove stations
    # First check that all channels in stream have data of the same length
    maxlen = np.max([len(tr.data) for tr in stream])
    if maxlen == 0:
        warnings.warn('template without data')
        return 0.0, len(stream)
    if not stations[0] == 'all':
        for tr in stream:
            if tr.stats.station not in stations:
                stream.remove(tr)  # Remove stations we don't want to use
    for tr in stream:
        if not len(tr.data) == maxlen and not len(tr.data) == 0:
            warnings.warn(tr.stats.station + '.' + tr.stats.channel +
                          ' is not the same length, padding \n' +
                          'Length is ' + str(len(tr.data)) + ' samples')
            pad = np.zeros(maxlen - len(tr.data))
            if tr.stats.starttime.hour == 0:
                tr.data = np.concatenate((pad, tr.data), axis=0)
            else:
                tr.data = np.concatenate((tr.data, pad), axis=0)
        elif len(tr.data) == 0:
            tr.data = np.zeros(maxlen)
    # Clip the data to the set length
    if clip:
        for tr in stream:
            tr.trim(tr.stats.starttime + clip[0], tr.stats.starttime + clip[1])
    _coherence = 0.0
    # Loop through channels and generate a correlation value for each
    # unique cross-channel pairing
    for i in range(len(stream)):
        for j in range(i + 1, len(stream)):
            _coherence += np.abs(normxcorr2(stream[i].data,
                                            stream[j].data))[0][0]
    _coherence = 2 * _coherence / (len(stream) * (len(stream) - 1))
    return _coherence, len(stream)
Exemple #22
0
def corr_cluster(trace_list, thresh=0.9):
    """
    Group traces based on correlations above threshold with the stack.

    Will run twice, once with a lower threshold, then again with your
    threshold to remove large outliers.

    :type trace_list: list of obspy.Trace
    :param trace_list: Traces to compute similarity between
    :type thresh: float
    :param thresh: Correlation threshold between -1-1

    :returns: np.ndarray of bool

    .. note:: We recommend that you align the data before computing the \
        clustering, e.g., the P-arrival on all templates for the same channel \
        should appear at the same time in the trace.  See the \
        stacking.align_traces function for a way to do this
    """
    from eqcorrscan.utils import stacking
    from obspy import Stream
    from eqcorrscan.core.match_filter import normxcorr2
    stack = stacking.linstack([Stream(tr) for tr in trace_list])[0]
    output = np.array([False]*len(trace_list))
    group1 = []
    for i, tr in enumerate(trace_list):
        if normxcorr2(tr.data, stack.data)[0][0] > 0.6:
            output[i] = True
            group1.append(tr)
    if not group1:
        warnings.warn('Nothing made it past the first 0.6 threshold')
        return output
    stack = stacking.linstack([Stream(tr) for tr in group1])[0]
    group2 = []
    for i, tr in enumerate(trace_list):
        if normxcorr2(tr.data, stack.data)[0][0] > thresh:
            group2.append(tr)
            output[i] = True
        else:
            output[i] = False
    return output
Exemple #23
0
def corr_cluster(trace_list, thresh=0.9):
    """
    Group traces based on correlations above threshold with the stack.

    Will run twice, once with a lower threshold, then again with your
    threshold to remove large outliers.

    :type trace_list: list of obspy.Trace
    :param trace_list: Traces to compute similarity between
    :type thresh: float
    :param thresh: Correlation threshold between -1-1

    :returns: np.ndarray of bool

    .. note:: We recommend that you align the data before computing the \
        clustering, e.g., the P-arrival on all templates for the same channel \
        should appear at the same time in the trace.  See the \
        stacking.align_traces function for a way to do this
    """
    from eqcorrscan.utils import stacking
    from obspy import Stream
    from eqcorrscan.core.match_filter import normxcorr2
    stack = stacking.linstack([Stream(tr) for tr in trace_list])[0]
    output = np.array([False] * len(trace_list))
    group1 = []
    for i, tr in enumerate(trace_list):
        if normxcorr2(tr.data, stack.data)[0][0] > 0.6:
            output[i] = True
            group1.append(tr)
    if not group1:
        warnings.warn('Nothing made it past the first 0.6 threshold')
        return output
    stack = stacking.linstack([Stream(tr) for tr in group1])[0]
    group2 = []
    for i, tr in enumerate(trace_list):
        if normxcorr2(tr.data, stack.data)[0][0] > thresh:
            group2.append(tr)
            output[i] = True
        else:
            output[i] = False
    return output
Exemple #24
0
 def test_normal_normxcorr2(self):
     """Check that if match is not perfect correlation max isn't unity
     """
     import numpy as np
     from eqcorrscan.core.match_filter import normxcorr2
     template = np.random.randn(100) * 10.0
     image = np.zeros(1000)
     image[200] = 1.0
     image = np.convolve(template, image)
     image += np.random.randn(1099)  # Add random noise
     ccc = normxcorr2(template, image)
     self.assertNotEqual(ccc.max(), 1.0)
Exemple #25
0
def cross_chan_coherence(st1, st2, allow_shift=False, shift_len=0.2, i=0):
    """
    Calculate cross-channel coherency.

    Determine the cross-channel coherency between two streams of multichannel
    seismic data.

    :type st1: obspy.core.stream.Stream
    :param st1: Stream one
    :type st2: obspy.core.stream.Stream
    :param st2: Stream two
    :type allow_shift: bool
    :param allow_shift:
        Whether to allow the optimum alignment to be found for coherence,
        defaults to `False` for strict coherence
    :type shift_len: int
    :param shift_len: Samples to shift, only used if `allow_shift=True`
    :type i: int
    :param i: index used for parallel async processing, returned unaltered

    :returns:
        cross channel coherence, float - normalized by number of channels,
        and i, where i is int, as input.
    :rtype: tuple
    """
    cccoh = 0.0
    kchan = 0
    if allow_shift:
        for tr in st1:
            tr2 = st2.select(station=tr.stats.station,
                             channel=tr.stats.channel)
            if tr2:
                index, corval = xcorr(tr, tr2[0], shift_len)
                cccoh += corval
                kchan += 1
    else:
        for tr in st1:
            tr1 = tr.data
            # Assume you only have one waveform for each channel
            tr2 = st2.select(station=tr.stats.station,
                             channel=tr.stats.channel)
            if tr2:
                cccoh += normxcorr2(tr1, tr2[0].data)[0][0]
                kchan += 1
    if kchan:
        cccoh /= kchan
        return cccoh, i
    else:
        warnings.warn('No matching channels')
        return 0, i
Exemple #26
0
def plot_rand_correlation(cat, d_thresh, temp_dict, stream_dict):
    """
    Calculate cross correlation coefficients for events located further than d_thresh from
    each other. This should represent correlation of uncorrelated signals and help determine
    ccval_cutoff
    :param cat:
    :param dist_thresh:
    :param temp_dict:
    :param stream_dict:
    :return:
    """
    from eqcorrscan.utils.mag_calc import dist_calc
    from eqcorrscan.core.match_filter import normxcorr2
    import numpy as np

    corrs = []
    for i, ev in enumerate(cat):
        print i
        ev_tup = (ev.preferred_origin().latitude, ev.preferred_origin().longitude,
                  ev.preferred_origin().depth / 1000.)
        for ev2 in cat[i+1:]:
            ev_tup2 = (ev2.preferred_origin().latitude, ev2.preferred_origin().longitude,
                      ev2.preferred_origin().depth / 1000.)
            dist = dist_calc(ev_tup, ev_tup2)
            if dist > d_thresh:
                det_rid = str(ev2.resource_id).split('/')[-1]
                temp_rid = str(ev.resource_id).split('/')[-1].split('_')[0]
                temp = temp_dict[temp_rid + '_1sec']
                stream = stream_dict[det_rid]
                for pk in ev.picks:
                    if pk.phase_hint == 'P':
                        sta = pk.waveform_id.station_code
                        chan = pk.waveform_id.channel_code
                        if len(temp.select(station=sta, channel=chan)) > 0:
                            tr = temp.select(station=sta,
                                             channel=chan)[0]
                        else:
                            continue
                        if len(stream.select(station=sta, channel=chan)) > 0:
                            st_tr = stream.select(station=sta,
                                                  channel=chan)[0]
                        else:
                            continue
                        # # still correcting for 0.1 sec pre-pick time here...gross
                        # pk_samp =
                        # corr_start = pk_samp - 5
                        # corr_end = pk_samp + 6
                        ccc = normxcorr2(tr.data, st_tr.data[140:201])[0]
                        corrs.append(max(ccc.max(), ccc.min(), key=abs))
    return corrs
Exemple #27
0
def cross_chan_coherence(st1, st2, allow_shift=False, shift_len=0.2, i=0):
    """
    Calculate cross-channel coherency.

    Determine the cross-channel coherency between two streams of \
    multichannel seismic data.

    :type st1: obspy.core.stream.Stream
    :param st1: Stream one
    :type st2: obspy.core.stream.Stream
    :param st2: Stream two
    :type allow_shift: bool
    :param allow_shift: Allow shift?
    :type shift_len: int
    :param shift_len: Samples to shift
    :type i: int
    :param i: index used for parallel async processing, returned unaltered

    :returns: cross channel coherence, float - normalized by number of\
        channels, if i, returns tuple of (cccoh, i) where i is int, as input.
    """

    from eqcorrscan.core.match_filter import normxcorr2
    from obspy.signal.cross_correlation import xcorr
    cccoh = 0.0
    kchan = 0
    if allow_shift:
        for tr in st1:
            tr2 = st2.select(station=tr.stats.station,
                             channel=tr.stats.channel)
            if tr2:
                index, corval = xcorr(tr, tr2[0], shift_len)
                cccoh += corval
                kchan += 1
    else:
        for tr in st1:
            tr1 = tr.data
            # Assume you only have one waveform for each channel
            tr2 = st2.select(station=tr.stats.station,
                             channel=tr.stats.channel)
            if tr2:
                cccoh += normxcorr2(tr1, tr2[0].data)[0][0]
                kchan += 1
    if kchan:
        cccoh = cccoh / kchan
        return (cccoh, i)
    else:
        warnings.warn('No matching channels')
        return (0, i)
Exemple #28
0
 def test_set_normxcorr2(self):
     """Check that correlations output are the same irrespective of version.
     """
     testing_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                                 'test_data')
     template = read(os.path.join(testing_path, 'test_template.ms'))
     template = template[0].data.astype(np.float32)
     image = read(os.path.join(testing_path, 'test_image.ms'))
     image = image[0].data.astype(np.float32)
     ccc = normxcorr2(template, image)[0]
     expected_ccc = np.load(os.path.join(testing_path, 'test_ccc.npy'))
     # We know that conda installs of openCV give a different results
     # to source built - allow this and allow it to pass.
     self.assertTrue((np.gradient(expected_ccc).round(2) ==
                      np.gradient(ccc).round(2)).all())
     if not (ccc == expected_ccc).all():
         warnings.warn('The expected result was not achieved, ' +
                       'but it has the same shape')
Exemple #29
0
 def test_set_normxcorr2(self):
     """Check that correlations output are the same irrespective of version.
     """
     import numpy as np
     from eqcorrscan.core.match_filter import normxcorr2
     from obspy import read
     import os
     import warnings
     testing_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                                 'test_data')
     template = read(os.path.join(testing_path, 'test_template.ms'))
     template = template[0].data.astype(np.float32)
     image = read(os.path.join(testing_path, 'test_image.ms'))
     image = image[0].data.astype(np.float32)
     ccc = normxcorr2(template, image)[0]
     expected_ccc = np.load(os.path.join(testing_path, 'test_ccc.npy'))
     # We know that conda installs of openCV give a different results
     # to source built - allow this and allow it to pass.
     self.assertTrue((np.gradient(expected_ccc).round(2) ==
                      np.gradient(ccc).round(2)).all())
     if not (ccc == expected_ccc).all():
         warnings.warn('The expected result was not achieved')
Exemple #30
0
def weight_corr_picks(cat, temp_dict=None, stream_dict=None, method='SNR_temp', temp_cat=False, show_ccs=False):
    """
    Implementing pick weighting by SNR of cc function
    :param cat: catalog of detections
    :param template_dir: directory where the templates live
    :param stream: directory where the longer event waveforms
    :param method: 'SNR_temp', 'SNR_ccval', 'doub_diff_ccval'
    :return: obspy.core.event.Catalog

    ** Note: Hypoellipse default quality mapping: 0.05, 0.1, 0.2, 0.4 sec (0, 1, 2, 3?)
             We can go with these values based on SNR of cc function, I suppose.
    """
    import warnings
    import numpy as np
    from eqcorrscan.core.match_filter import normxcorr2
    import matplotlib.pyplot as plt
    from obspy.core.event import QuantityError

    SNRs = []
    if temp_cat:
        temp_SNRs = {str(ev.resource_id).split('/')[-1].split('_')[0]:
                         {amp.waveform_id.station_code + '.EZ':
                              amp.snr for amp in ev.amplitudes} for ev in temp_cat}
    for ev in cat:
        det_rid = str(ev.resource_id).split('/')[-1]
        temp_rid = str(ev.resource_id).split('/')[-1].split('_')[0]
        picks = list(ev.picks)
        for i, pk in enumerate(picks):
            if pk.phase_hint == 'P':
                sta = pk.waveform_id.station_code
                chan = pk.waveform_id.channel_code
                if method == 'SNR_ccval':
                    temp = temp_dict[temp_rid + '_1sec']
                    stream = stream_dict[det_rid]
                    tr = temp.select(station=sta,
                                     channel=chan)[0]
                    st_tr = stream.select(station=sta,
                                          channel=chan)[0]
                    ccc = normxcorr2(tr.data, st_tr.data)[0]
                    pk_samp = int(tr.stats.sampling_rate * (pk.time - st_tr.stats.starttime) - 5)
                    sta_start = pk_samp - 5
                    sta_end = pk_samp + 5
                    LTA = np.std(ccc)
                    STA = np.std(ccc[sta_start:sta_end])
                    # STA = abs(ccc[pk_samp])
                    SNR = STA / LTA
                    # Here we map the ccval SNR to time uncertainty in the original catalog
                    orig_pk = ev.picks[i]
                    if SNR < 0.75: orig_pk.time_errors = QuantityError(uncertainty=0.40)
                    elif SNR < 1.25: orig_pk.time_errors = QuantityError(uncertainty=0.20)
                    elif SNR < 1.75: orig_pk.time_errors = QuantityError(uncertainty=0.10)
                    elif SNR < 2.25: orig_pk.time_errors = QuantityError(uncertainty=0.05)
                    else: orig_pk.time_errors = QuantityError(uncertainty=0.01)
                    SNRs.append(SNR)
                    if show_ccs:
                        fig, ax = plt.subplots()
                        ax.plot(ccc)
                        ax.set_title('%s.%s: %f' % (sta, chan, SNR))
                        fig.show()
                elif method == 'SNR_temp':
                    orig_pk = ev.picks[i]
                    try:
                        SNR = temp_SNRs[temp_rid]['%s.%s' % (sta, chan)]
                    except KeyError:
                        warnings.warn('%s.%s has no amplitude pick' % (sta, chan))
                        orig_pk.time_errors = QuantityError(uncertainty=0.10)
                        continue
                    if SNR < 1.0:
                        orig_pk.time_errors = QuantityError(uncertainty=0.20)
                    elif SNR < 2.:
                        orig_pk.time_errors = QuantityError(uncertainty=0.10)
                    elif SNR < 5.:
                        orig_pk.time_errors = QuantityError(uncertainty=0.05)
                    else:
                        orig_pk.time_errors = QuantityError(uncertainty=0.01)
    return cat
Exemple #31
0
def _channel_loop(detection, template, min_cc, interpolate=False, i=0,
                  debug=0):
    """
    Inner loop for correlating and assigning picks.

    Utility function to take a stream of data for the detected event and write
    maximum correlation to absolute time as picks in an obspy.core.event.Event
    object.
    Only outputs picks for picks above min_cc.

    :type detection: obspy.core.stream.Stream
    :param detection: Stream of data for the slave event detected using \
        template.
    :type template: obspy.core.stream.Stream
    :param template: Stream of data as the template for the detection.
    :type interpolate: bool
    :param interpolate: Interpolate the correlation function to achieve \
        sub-sample precision.
    :type i: int
    :param i: Used to track which process has occurred when running in \
        parallel.

    :returns: Event object containing net, sta, chan information
    :rtype: obspy.core.event.Event
    """
    from obspy.core.event import Event, Pick, WaveformStreamID
    from obspy.core.event import ResourceIdentifier
    event = Event()
    s_stachans = {}
    used_s_sta = []
    for tr in template:
        temp_net = tr.stats.network
        temp_sta = tr.stats.station
        temp_chan = tr.stats.channel
        image = detection.select(station=temp_sta,
                                 channel=temp_chan)
        if image:
            ccc = normxcorr2(tr.data, image[0].data)
            # Convert the maximum cross-correlation time to an actual time
            if debug > 3:
                print('********DEBUG: Maximum cross-corr=%s' % np.amax(ccc))
            if np.amax(ccc) > min_cc:
                if interpolate:
                    try:
                        interp_max = _xcorr_interp(ccc=ccc,
                                                   dt=image[0].stats.delta)
                    except IndexError:
                        print('Could not interpolate ccc, not smooth')
                        interp_max = np.argmax(ccc) * image[0].stats.delta
                    picktime = image[0].stats.starttime + interp_max
                else:
                    picktime = image[0].stats.starttime + (np.argmax(ccc) *
                                                           image[0].stats.delta)
            else:
                continue
            # Perhaps weight each pick by the cc val or cc val^2?
            # weight = np.amax(ccc) ** 2
            if temp_chan[-1:] == 'Z':
                phase = 'P'
            # Only take the S-pick with the best correlation
            elif temp_chan[-1:] in ['E', 'N']:
                phase = 'S'
                if temp_sta not in s_stachans and np.amax(ccc) > min_cc:
                    s_stachans[temp_sta] = ((temp_chan, np.amax(ccc),
                                             picktime))
                elif temp_sta in s_stachans and np.amax(ccc) > min_cc:
                    if np.amax(ccc) > s_stachans[temp_sta][1]:
                        picktime = picktime
                    else:
                        picktime = s_stachans[temp_sta][2]
                        temp_chan = s_stachans[temp_sta][0]
                elif np.amax(ccc) < min_cc and temp_sta not in used_s_sta:
                    used_s_sta.append(temp_sta)
                else:
                    continue
            else:
                phase = None
            _waveform_id = WaveformStreamID(network_code=temp_net,
                                            station_code=temp_sta,
                                            channel_code=temp_chan)
            event.picks.append(Pick(waveform_id=_waveform_id,
                                    time=picktime,
                                    method_id=ResourceIdentifier('EQcorrscan'),
                                    phase_hint=phase))
    return (i, event)
Exemple #32
0
def multi_event_singlechan(streams, catalog, clip=10.0, pre_pick=2.0,
                           freqmin=False, freqmax=False, realign=False,
                           cut=(-3.0, 5.0), PWS=False, title=False):
    r"""Function to plot data from a single channel at a single station for \
    multiple events - data will be alligned by their pick-time given in the \
    picks.

    :type streams: list of :class:obspy.stream
    :param streams: List of the streams to use, can contain more traces than \
        you plan on plotting
    :type catalog: obspy.core.event.Catalog
    :param catalog: Catalog of events, one for each trace, with a single pick
    :type clip: float
    :param clip: Length in seconds to plot, defaults to 10.0
    :type pre_pick: float
    :param pre_pick: Length in seconds to extract and plot before the pick, \
        defaults to 2.0
    :type freqmin: float
    :param freqmin: Low cut for bandpass in Hz
    :type freqmax: float
    :param freqmax: High cut for bandpass in Hz
    :type realign: bool
    :param realign: To compute best alignement based on correlation or not.
    :type cut: tuple
    :param cut: tuple of start and end times for cut in seconds from the pick
    :type PWS: bool
    :param PWS: compute Phase Weighted Stack, if False, will compute linear \
        stack.
    :type title: str
    :param title: Plot title.

    :returns: Alligned and cut traces, and new picks
    """
    from eqcorrscan.utils import stacking
    import copy
    from eqcorrscan.core.match_filter import normxcorr2
    from obspy import Stream
    import warnings
    fig, axes = plt.subplots(len(catalog)+1, 1, sharex=True, figsize=(7, 12))
    axes = axes.ravel()
    traces = []
    al_traces = []
    # Keep input safe
    clist = copy.deepcopy(catalog)
    st_list = copy.deepcopy(streams)
    for i, event in enumerate(clist):
        if st_list[i].select(station=event.picks[0].waveform_id.station_code,
                             channel='*' +
                             event.picks[0].waveform_id.channel_code[-1]):
            tr = st_list[i].select(station=event.picks[0].waveforms_id.
                                   station_code,
                                   channel='*' +
                                   event.picks[0].waveform_id.
                                   channel_code[-1])[0]
        else:
            print('No data for '+event.pick[0].waveform_id)
            continue
        tr.detrend('linear')
        if freqmin:
            tr.filter('bandpass', freqmin=freqmin, freqmax=freqmax)
        if realign:
            tr_cut = tr.copy()
            tr_cut.trim(event.picks[0].time + cut[0],
                        event.picks[0].time + cut[1],
                        nearest_sample=False)
            if len(tr_cut.data) <= (0.5 * (cut[1] - cut[0]) *
                                    tr_cut.stats.sampling_rate):
                msg = ''.join(['Not enough in the trace for ',
                               tr.stats.station,
                               '.', tr.stats.channel, '\n',
                               'Suggest removing pick from sfile at time ',
                               str(event.picks[0].time)])
                warnings.warn(msg)
            else:
                al_traces.append(tr_cut)
        else:
            tr.trim(event.picks[0].time - pre_pick,
                    event.picks[0].time + clip - pre_pick,
                    nearest_sample=False)
        if len(tr.data) == 0:
            msg = ''.join(['No data in the trace for ', tr.stats.station,
                           '.', tr.stats.channel, '\n',
                           'Suggest removing pick from sfile at time ',
                           str(event.picks[0].time)])
            warnings.warn(msg)
            continue
        traces.append(tr)
    if realign:
        shift_len = int(0.25 * (cut[1] - cut[0]) *
                        al_traces[0].stats.sampling_rate)
        shifts = stacking.align_traces(al_traces, shift_len)
        for i in xrange(len(shifts)):
            print('Shifting by '+str(shifts[i])+' seconds')
            event.picks[0].time -= shifts[i]
            traces[i].trim(event.picks[0].time - pre_pick,
                           event.picks[0].time + clip-pre_pick,
                           nearest_sample=False)
    # We now have a list of traces
    traces = [(trace, trace.stats.starttime.datetime) for trace in traces]
    traces.sort(key=lambda tup: tup[1])
    traces = [trace[0] for trace in traces]
    # Plot the traces
    for i, tr in enumerate(traces):
        y = tr.data
        x = np.arange(len(y))
        x = x / tr.stats.sampling_rate  # convert to seconds
        axes[i+1].plot(x, y, 'k', linewidth=1.1)
        axes[i+1].yaxis.set_ticks([])
    traces = [Stream(trace) for trace in traces]
    if PWS:
        linstack = stacking.PWS_stack(traces)
    else:
        linstack = stacking.linstack(traces)
    tr = linstack.select(station=event[0].picks[0].waveform_id.station_code,
                         channel='*' +
                         event[0].picks[0].waveform_id.channel_code[-1])[0]
    y = tr.data
    x = np.arange(len(y))
    x = x / tr.stats.sampling_rate
    axes[0].plot(x, y, 'r', linewidth=2.0)
    axes[0].set_ylabel('Stack', rotation=0)
    axes[0].yaxis.set_ticks([])
    for i, slave in enumerate(traces):
        cc = normxcorr2(tr.data, slave[0].data)
        axes[i+1].set_ylabel('cc='+str(round(np.max(cc), 2)), rotation=0)
        axes[i+1].text(0.9, 0.15, str(round(np.max(slave[0].data))),
                       bbox=dict(facecolor='white', alpha=0.95),
                       transform=axes[i+1].transAxes)
        axes[i+1].text(0.7, 0.85, slave[0].stats.starttime.datetime.
                       strftime('%Y/%m/%d %H:%M:%S'),
                       bbox=dict(facecolor='white', alpha=0.95),
                       transform=axes[i+1].transAxes)
    axes[-1].set_xlabel('Time (s)')
    if title:
        axes[0].set_title(title)
    plt.subplots_adjust(hspace=0)
    plt.show()
    return traces, clist
Exemple #33
0
def align_traces(trace_list,
                 shift_len,
                 master=False,
                 positive=False,
                 plot=False):
    """
    Align traces relative to each other based on their cross-correlation value.

    Uses the :func:`eqcorrscan.core.match_filter.normxcorr2` function to find
    the optimum shift to align traces relative to a master event.  Either uses
    a given master to align traces, or uses the trace with the highest MAD
    amplitude.

    :type trace_list: list
    :param trace_list: List of traces to align
    :type shift_len: int
    :param shift_len: Length to allow shifting within in samples
    :type master: obspy.core.trace.Trace
    :param master: Master trace to align to, if set to False will align to \
        the largest amplitude trace (default)
    :type positive: bool
    :param positive: Return the maximum positive cross-correlation, or the \
        absolute maximum, defaults to False (absolute maximum).
    :type plot: bool
    :param plot: If true, will plot each trace aligned with the master.

    :returns: list of shifts and correlations for best alignment in seconds.
    :rtype: list
    """
    from eqcorrscan.core.match_filter import normxcorr2
    from eqcorrscan.utils.plotting import xcorr_plot
    traces = deepcopy(trace_list)
    if not master:
        # Use trace with largest MAD amplitude as master
        master = traces[0]
        MAD_master = np.median(np.abs(master.data))
        for i in range(1, len(traces)):
            if np.median(np.abs(traces[i].data)) > MAD_master:
                master = traces[i]
                MAD_master = np.median(np.abs(master.data))
    else:
        print('Using master given by user')
    shifts = []
    ccs = []
    for i in range(len(traces)):
        if not master.stats.sampling_rate == traces[i].stats.sampling_rate:
            raise ValueError('Sampling rates not the same')
        cc_vec = normxcorr2(template=traces[i].data.astype(
            np.float32)[shift_len:-shift_len],
                            image=master.data.astype(np.float32))
        cc_vec = cc_vec[0]
        shift = np.abs(cc_vec).argmax()
        cc = cc_vec[shift]
        if plot:
            xcorr_plot(template=traces[i].data.astype(
                np.float32)[shift_len:-shift_len],
                       image=master.data.astype(np.float32),
                       shift=shift,
                       cc=cc)
        shift -= shift_len
        if cc < 0 and positive:
            cc = cc_vec.max()
            shift = cc_vec.argmax() - shift_len
        shifts.append(shift / master.stats.sampling_rate)
        ccs.append(cc)
    return shifts, ccs
def multi_event_singlechan(streams, picks, clip=10.0, pre_pick=2.0,\
                           freqmin=False, freqmax=False, realign=False, \
                           cut=(-3.0,5.0), PWS=False, title=False):
    """
    Function to plot data from a single channel at a single station for multiple
    events - data will be alligned by their pick-time given in the picks

    :type streams: List of :class:obspy.stream
    :param streams: List of the streams to use, can contain more traces than\
        you plan on plotting
    :type picks: List of :class:PICK
    :param picks: List of picks, one for each stream
    :type clip: float
    :param clip: Length in seconds to plot, defaults to 10.0
    :type pre_pick: Float
    :param pre_pick: Length in seconds to extract and plot before the pick,\
        defaults to 2.0
    :type freqmin: float
    :param freqmin: Low cut for bandpass in Hz
    :type freqmax: float
    :param freqmax: High cut for bandpass in Hz
    :type realign: Bool
    :param realign: To compute best alignement based on correlation or not.
    :type cut: tuple:
    :param cut: tuple of start and end times for cut in seconds from the pick
    :type PWS: bool
    :param PWS: compute Phase Weighted Stack, if False, will compute linear stack
    :type title: str
    :param title: Plot title.

    :returns: Alligned and cut traces, and new picks
    """
    from eqcorrscan.utils import stacking
    import copy
    from eqcorrscan.core.match_filter import normxcorr2
    from obspy import Stream
    fig, axes = plt.subplots(len(picks) + 1, 1, sharex=True, figsize=(7, 12))
    axes = axes.ravel()
    traces = []
    al_traces = []
    # Keep input safe
    plist = copy.deepcopy(picks)
    st_list = copy.deepcopy(streams)
    for i, pick in enumerate(plist):
        if st_list[i].select(station=pick.station, \
            channel='*'+pick.channel[-1]):
            tr=st_list[i].select(station=pick.station, \
                channel='*'+pick.channel[-1])[0]
        else:
            print 'No data for ' + pick.station + '.' + pick.channel
            continue
        tr.detrend('linear')
        if freqmin:
            tr.filter('bandpass', freqmin=freqmin, freqmax=freqmax)
        if realign:
            tr_cut = tr.copy()
            tr_cut.trim(pick.time+cut[0], pick.time+cut[1],\
                        nearest_sample=False)
            if len(tr_cut.data) <= 0.5 * (cut[1] -
                                          cut[0]) * tr_cut.stats.sampling_rate:
                print 'Not enough in the trace for ' + pick.station + '.' + pick.channel
                print 'Suggest removing pick from sfile at time ' + str(
                    pick.time)
            else:
                al_traces.append(tr_cut)
        else:
            tr.trim(pick.time-pre_pick, pick.time+clip-pre_pick,\
                    nearest_sample=False)
        if len(tr.data) == 0:
            print 'No data in the trace for ' + pick.station + '.' + pick.channel
            print 'Suggest removing pick from sfile at time ' + str(pick.time)
            continue
        traces.append(tr)
    if realign:
        shift_len = int(0.25 * (cut[1] - cut[0]) *
                        al_traces[0].stats.sampling_rate)
        shifts = stacking.align_traces(al_traces, shift_len)
        for i in xrange(len(shifts)):
            print 'Shifting by ' + str(shifts[i]) + ' seconds'
            pick.time -= shifts[i]
            traces[i].trim(pick.time - pre_pick, pick.time + clip-pre_pick,\
                           nearest_sample=False)
    # We now have a list of traces
    traces = [(trace, trace.stats.starttime.datetime) for trace in traces]
    traces.sort(key=lambda tup: tup[1])
    traces = [trace[0] for trace in traces]
    # Plot the traces
    for i, tr in enumerate(traces):
        y = tr.data
        x = np.arange(len(y))
        x = x / tr.stats.sampling_rate  # convert to seconds
        axes[i + 1].plot(x, y, 'k', linewidth=1.1)
        # axes[i+1].set_ylabel(tr.stats.starttime.datetime.strftime('%Y/%m/%d %H:%M'),\
        # rotation=0)
        axes[i + 1].yaxis.set_ticks([])
    traces = [Stream(trace) for trace in traces]
    if PWS:
        linstack = stacking.PWS_stack(traces)
    else:
        linstack = stacking.linstack(traces)
    tr=linstack.select(station=picks[0].station, \
            channel='*'+picks[0].channel[-1])[0]
    y = tr.data
    x = np.arange(len(y))
    x = x / tr.stats.sampling_rate
    axes[0].plot(x, y, 'r', linewidth=2.0)
    axes[0].set_ylabel('Stack', rotation=0)
    axes[0].yaxis.set_ticks([])
    for i, slave in enumerate(traces):
        cc = normxcorr2(tr.data, slave[0].data)
        axes[i + 1].set_ylabel('cc=' + str(round(np.max(cc), 2)), rotation=0)
        axes[i+1].text(0.9, 0.15, str(round(np.max(slave[0].data))), \
                       bbox=dict(facecolor='white', alpha=0.95),\
                       transform=axes[i+1].transAxes)
        axes[i+1].text(0.7, 0.85, slave[0].stats.starttime.datetime.strftime('%Y/%m/%d %H:%M:%S'), \
                       bbox=dict(facecolor='white', alpha=0.95),\
                       transform=axes[i+1].transAxes)
    axes[-1].set_xlabel('Time (s)')
    if title:
        axes[0].set_title(title)
    plt.subplots_adjust(hspace=0)
    plt.show()
    return traces, plist
Exemple #35
0
def _channel_loop(detection,
                  template,
                  min_cc,
                  detection_id,
                  interpolate,
                  i,
                  pre_lag_ccsum=None,
                  detect_chans=0):
    """
    Inner loop for correlating and assigning picks.

    Utility function to take a stream of data for the detected event and write
    maximum correlation to absolute time as picks in an obspy.core.event.Event
    object.
    Only outputs picks for picks above min_cc.

    :type detection: obspy.core.stream.Stream
    :param detection:
        Stream of data for the slave event detected using template.
    :type template: obspy.core.stream.Stream
    :param template: Stream of data as the template for the detection.
    :type min_cc: float
    :param min_cc: Minimum cross-correlation value to allow a pick to be made.
    :type detection_id: str
    :param detection_id: Detection ID to associate the event with.
    :type interpolate: bool
    :param interpolate:
        Interpolate the correlation function to achieve sub-sample precision.
    :type i: int
    :param i:
        Used to track which process has occurred when running in parallel.
    :type pre_lag_ccsum: float
    :param pre_lag_ccsum:
        Cross-correlation sum before lag-calc, will check that the
        cross-correlation sum is increased by lag-calc (using all channels,
        ignoring min_cc)
    :type detect_chans: int
    :param detect_chans:
        Number of channels originally used in detections, must match the number
        used here to allow for cccsum checking.

    :returns:
        Event object containing network, station, channel and pick information.
    :rtype: :class:`obspy.core.event.Event`
    """
    event = Event()
    s_stachans = {}
    used_s_sta = []
    cccsum = 0
    checksum = 0
    used_chans = 0
    for tr in template:
        temp_net = tr.stats.network
        temp_sta = tr.stats.station
        temp_chan = tr.stats.channel
        image = detection.select(station=temp_sta, channel=temp_chan)
        if image:
            if interpolate:
                try:
                    ccc = normxcorr2(tr.data, image[0].data)
                    shift, cc_max = _xcorr_interp(ccc=ccc,
                                                  dt=image[0].stats.delta)
                except IndexError:
                    log.error('Could not interpolate ccc, not smooth')
                    ccc = normxcorr2(tr.data, image[0].data)
                    cc_max = np.amax(ccc)
                    shift = np.argmax(ccc) * image[0].stats.delta
                # Convert the maximum cross-correlation time to an actual time
                picktime = image[0].stats.starttime + shift
            else:
                # Convert the maximum cross-correlation time to an actual time
                ccc = normxcorr2(tr.data, image[0].data)
                cc_max = np.amax(ccc)
                picktime = image[0].stats.starttime + (np.argmax(ccc) *
                                                       image[0].stats.delta)
            log.debug('********DEBUG: Maximum cross-corr=%s' % cc_max)
            checksum += cc_max
            used_chans += 1
            if cc_max < min_cc:
                continue
            cccsum += cc_max
            # Perhaps weight each pick by the cc val or cc val^2?
            # weight = np.amax(ccc) ** 2
            if temp_chan[-1:] == 'Z':
                phase = 'P'
            # Only take the S-pick with the best correlation
            elif temp_chan[-1:] in ['E', 'N']:
                phase = 'S'
                if temp_sta not in s_stachans and np.amax(ccc) > min_cc:
                    s_stachans[temp_sta] = ((temp_chan, np.amax(ccc),
                                             picktime))
                elif temp_sta in s_stachans and np.amax(ccc) > min_cc:
                    if np.amax(ccc) > s_stachans[temp_sta][1]:
                        picktime = picktime
                    else:
                        picktime = s_stachans[temp_sta][2]
                        temp_chan = s_stachans[temp_sta][0]
                elif np.amax(ccc) < min_cc and temp_sta not in used_s_sta:
                    used_s_sta.append(temp_sta)
                else:
                    continue
            else:
                phase = None
            _waveform_id = WaveformStreamID(network_code=temp_net,
                                            station_code=temp_sta,
                                            channel_code=temp_chan)
            event.picks.append(
                Pick(waveform_id=_waveform_id,
                     time=picktime,
                     method_id=ResourceIdentifier('EQcorrscan'),
                     phase_hint=phase,
                     creation_info='eqcorrscan.core.lag_calc',
                     comments=[Comment(text='cc_max=%s' % cc_max)]))
            event.resource_id = detection_id
    ccc_str = ("detect_val=%s" % cccsum)
    event.comments.append(Comment(text=ccc_str))
    if used_chans == detect_chans:
        if pre_lag_ccsum is not None and checksum - pre_lag_ccsum < -0.05:
            msg = ('lag-calc has decreased cccsum from %f to %f - '
                   'report this error' % (pre_lag_ccsum, checksum))
            raise LagCalcError(msg)
    else:
        warnings.warn('Cannot check is cccsum is better, used %i channels '
                      'for detection, but %i are used here' %
                      (detect_chans, used_chans))
    return i, event
Exemple #36
0
def multi_event_singlechan(streams,
                           catalog,
                           clip=10.0,
                           pre_pick=2.0,
                           freqmin=False,
                           freqmax=False,
                           realign=False,
                           cut=(-3.0, 5.0),
                           PWS=False,
                           title=False,
                           save=False,
                           savefile=None):
    r"""Function to plot data from a single channel at a single station for \
    multiple events - data will be alligned by their pick-time given in the \
    picks.

    :type streams: list of :class:obspy.stream
    :param streams: List of the streams to use, can contain more traces than \
        you plan on plotting
    :type catalog: obspy.core.event.Catalog
    :param catalog: Catalog of events, one for each trace, with a single pick
    :type clip: float
    :param clip: Length in seconds to plot, defaults to 10.0
    :type pre_pick: float
    :param pre_pick: Length in seconds to extract and plot before the pick, \
        defaults to 2.0
    :type freqmin: float
    :param freqmin: Low cut for bandpass in Hz
    :type freqmax: float
    :param freqmax: High cut for bandpass in Hz
    :type realign: bool
    :param realign: To compute best alignement based on correlation or not.
    :type cut: tuple
    :param cut: tuple of start and end times for cut in seconds from the pick
    :type PWS: bool
    :param PWS: compute Phase Weighted Stack, if False, will compute linear \
        stack.
    :type title: str
    :param title: Plot title.
    :type save: bool
    :param save: False will plot to screen, true will save plot and not show \
        to screen.
    :type savefile: str
    :param savefile: Filename to save to, required for save=True

    :returns: Alligned and cut traces, and new picks
    """
    _check_save_args(save, savefile)
    from eqcorrscan.utils import stacking
    import copy
    from eqcorrscan.core.match_filter import normxcorr2
    from obspy import Stream
    import warnings
    fig, axes = plt.subplots(len(catalog) + 1, 1, sharex=True, figsize=(7, 12))
    axes = axes.ravel()
    traces = []
    al_traces = []
    # Keep input safe
    clist = copy.deepcopy(catalog)
    st_list = copy.deepcopy(streams)
    for i, event in enumerate(clist):
        if st_list[i].select(station=event.picks[0].waveform_id.station_code,
                             channel='*' +
                             event.picks[0].waveform_id.channel_code[-1]):
            tr = st_list[i].select(
                station=event.picks[0].waveforms_id.station_code,
                channel='*' + event.picks[0].waveform_id.channel_code[-1])[0]
        else:
            print('No data for ' + event.pick[0].waveform_id)
            continue
        tr.detrend('linear')
        if freqmin:
            tr.filter('bandpass', freqmin=freqmin, freqmax=freqmax)
        if realign:
            tr_cut = tr.copy()
            tr_cut.trim(event.picks[0].time + cut[0],
                        event.picks[0].time + cut[1],
                        nearest_sample=False)
            if len(tr_cut.data) <= (0.5 * (cut[1] - cut[0]) *
                                    tr_cut.stats.sampling_rate):
                msg = ''.join([
                    'Not enough in the trace for ', tr.stats.station, '.',
                    tr.stats.channel, '\n',
                    'Suggest removing pick from sfile at time ',
                    str(event.picks[0].time)
                ])
                warnings.warn(msg)
            else:
                al_traces.append(tr_cut)
        else:
            tr.trim(event.picks[0].time - pre_pick,
                    event.picks[0].time + clip - pre_pick,
                    nearest_sample=False)
        if len(tr.data) == 0:
            msg = ''.join([
                'No data in the trace for ', tr.stats.station, '.',
                tr.stats.channel, '\n',
                'Suggest removing pick from sfile at time ',
                str(event.picks[0].time)
            ])
            warnings.warn(msg)
            continue
        traces.append(tr)
    if realign:
        shift_len = int(0.25 * (cut[1] - cut[0]) *
                        al_traces[0].stats.sampling_rate)
        shifts = stacking.align_traces(al_traces, shift_len)
        for i in xrange(len(shifts)):
            print('Shifting by ' + str(shifts[i]) + ' seconds')
            event.picks[0].time -= shifts[i]
            traces[i].trim(event.picks[0].time - pre_pick,
                           event.picks[0].time + clip - pre_pick,
                           nearest_sample=False)
    # We now have a list of traces
    traces = [(trace, trace.stats.starttime.datetime) for trace in traces]
    traces.sort(key=lambda tup: tup[1])
    traces = [trace[0] for trace in traces]
    # Plot the traces
    for i, tr in enumerate(traces):
        y = tr.data
        x = np.arange(len(y))
        x = x / tr.stats.sampling_rate  # convert to seconds
        axes[i + 1].plot(x, y, 'k', linewidth=1.1)
        axes[i + 1].yaxis.set_ticks([])
    traces = [Stream(trace) for trace in traces]
    if PWS:
        linstack = stacking.PWS_stack(traces)
    else:
        linstack = stacking.linstack(traces)
    tr = linstack.select(station=event[0].picks[0].waveform_id.station_code,
                         channel='*' +
                         event[0].picks[0].waveform_id.channel_code[-1])[0]
    y = tr.data
    x = np.arange(len(y))
    x = x / tr.stats.sampling_rate
    axes[0].plot(x, y, 'r', linewidth=2.0)
    axes[0].set_ylabel('Stack', rotation=0)
    axes[0].yaxis.set_ticks([])
    for i, slave in enumerate(traces):
        cc = normxcorr2(tr.data, slave[0].data)
        axes[i + 1].set_ylabel('cc=' + str(round(np.max(cc), 2)), rotation=0)
        axes[i + 1].text(0.9,
                         0.15,
                         str(round(np.max(slave[0].data))),
                         bbox=dict(facecolor='white', alpha=0.95),
                         transform=axes[i + 1].transAxes)
        axes[i + 1].text(
            0.7,
            0.85,
            slave[0].stats.starttime.datetime.strftime('%Y/%m/%d %H:%M:%S'),
            bbox=dict(facecolor='white', alpha=0.95),
            transform=axes[i + 1].transAxes)
    axes[-1].set_xlabel('Time (s)')
    if title:
        axes[0].set_title(title)
    plt.subplots_adjust(hspace=0)
    if not save:
        plt.show()
    else:
        plt.savefig(savefile)
    return traces, clist
Exemple #37
0
def _channel_loop(detection,
                  template,
                  min_cc,
                  detection_id,
                  interpolate,
                  i,
                  pre_lag_ccsum=None,
                  detect_chans=0,
                  horizontal_chans=['E', 'N', '1', '2'],
                  vertical_chans=['Z'],
                  debug=0):
    """
    Inner loop for correlating and assigning picks.

    Utility function to take a stream of data for the detected event and write
    maximum correlation to absolute time as picks in an obspy.core.event.Event
    object.
    Only outputs picks for picks above min_cc.

    :type detection: obspy.core.stream.Stream
    :param detection:
        Stream of data for the slave event detected using template.
    :type template: obspy.core.stream.Stream
    :param template: Stream of data as the template for the detection.
    :type min_cc: float
    :param min_cc: Minimum cross-correlation value to allow a pick to be made.
    :type detection_id: str
    :param detection_id: Detection ID to associate the event with.
    :type interpolate: bool
    :param interpolate:
        Interpolate the correlation function to achieve sub-sample precision.
    :type i: int
    :param i:
        Used to track which process has occurred when running in parallel.
    :type pre_lag_ccsum: float
    :param pre_lag_ccsum:
        Cross-correlation sum before lag-calc, will check that the
        cross-correlation sum is increased by lag-calc (using all channels,
        ignoring min_cc)
    :type detect_chans: int
    :param detect_chans:
        Number of channels originally used in detections, must match the number
        used here to allow for cccsum checking.
    :type horizontal_chans: list
    :param horizontal_chans:
        List of channel endings for horizontal-channels, on which S-picks will
        be made.
    :type vertical_chans: list
    :param vertical_chans:
        List of channel endings for vertical-channels, on which P-picks will
        be made.
    :type debug: int
    :param debug: Debug output level 0-5.

    :returns:
        Event object containing network, station, channel and pick information.
    :rtype: :class:`obspy.core.event.Event`
    """
    from eqcorrscan.core.match_filter import normxcorr2
    event = Event()
    s_stachans = {}
    cccsum = 0
    checksum = 0
    used_chans = 0
    for tr in template:
        temp_net = tr.stats.network
        temp_sta = tr.stats.station
        temp_chan = tr.stats.channel
        debug_print('Working on: %s.%s.%s' % (temp_net, temp_sta, temp_chan),
                    3, debug)
        image = detection.select(station=temp_sta, channel=temp_chan)
        if len(image) == 0:
            print('No match in image.')
            continue
        if interpolate:
            try:
                ccc = normxcorr2(tr.data, image[0].data)
            except Exception:
                print('Could not calculate cc')
                print('Image is %i long' % len(image[0].data))
                print('Template is %i long' % len(tr.data))
                continue
            try:
                shift, cc_max = _xcorr_interp(ccc=ccc, dt=image[0].stats.delta)
            except IndexError:
                print('Could not interpolate ccc, not smooth')
                ccc = normxcorr2(tr.data, image[0].data)
                cc_max = np.amax(ccc)
                shift = np.argmax(ccc) * image[0].stats.delta
            # Convert the maximum cross-correlation time to an actual time
            picktime = image[0].stats.starttime + shift
        else:
            # Convert the maximum cross-correlation time to an actual time
            try:
                ccc = normxcorr2(tr.data, image[0].data)
            except Exception:
                print('Could not calculate cc')
                print('Image is %i long' % len(image[0].data))
                print('Template is %i long' % len(tr.data))
                continue
            cc_max = np.amax(ccc)
            picktime = image[0].stats.starttime + (np.argmax(ccc) *
                                                   image[0].stats.delta)
        debug_print('Maximum cross-corr=%s' % cc_max, 3, debug)
        checksum += cc_max
        used_chans += 1
        if cc_max < min_cc:
            debug_print('Correlation below threshold, not used', 3, debug)
            continue
        cccsum += cc_max
        # Perhaps weight each pick by the cc val or cc val^2?
        # weight = np.amax(ccc) ** 2
        if temp_chan[-1] in vertical_chans:
            phase = 'P'
        # Only take the S-pick with the best correlation
        elif temp_chan[-1] in horizontal_chans:
            phase = 'S'
            debug_print(
                'Making S-pick on: %s.%s.%s' % (temp_net, temp_sta, temp_chan),
                4, debug)
            if temp_sta not in s_stachans.keys():
                s_stachans[temp_sta] = ((temp_chan, np.amax(ccc), picktime))
            elif temp_sta in s_stachans.keys():
                if np.amax(ccc) > s_stachans[temp_sta][1]:
                    picktime = picktime
                else:
                    continue
        else:
            phase = None
        _waveform_id = WaveformStreamID(network_code=temp_net,
                                        station_code=temp_sta,
                                        channel_code=temp_chan)
        event.picks.append(
            Pick(waveform_id=_waveform_id,
                 time=picktime,
                 method_id=ResourceIdentifier('EQcorrscan'),
                 phase_hint=phase,
                 creation_info='eqcorrscan.core.lag_calc',
                 comments=[Comment(text='cc_max=%s' % cc_max)]))
        event.resource_id = detection_id
    ccc_str = ("detect_val=%s" % cccsum)
    event.comments.append(Comment(text=ccc_str))
    if used_chans == detect_chans:
        if pre_lag_ccsum is not None and\
           checksum - pre_lag_ccsum < -(0.30 * pre_lag_ccsum):
            msg = ('lag-calc has decreased cccsum from %f to %f - ' %
                   (pre_lag_ccsum, checksum))
            # warnings.warn(msg)
            raise LagCalcError(msg)
    else:
        warnings.warn('Cannot check if cccsum is better, used %i channels '
                      'for detection, but %i are used here' %
                      (detect_chans, used_chans))
    return i, event