Example #1
0
    def testCum(self):
        t = self.mseed[0]
        # we did not write any processing to the trace:
        assert 'processing' not in t.stats or not t.stats.processing
        c1 = cumsumsq(t)
        assert t is not c1
        assert not np.allclose(t.data, c1.data, equal_nan=True)
        assert max(c1.data) <= 1
        # we wrote processing information in the trace:
        assert c1.stats.processing
        assert cumsumsq.__name__ in c1.stats.processing[0]

        c3 = cumsumsq(t, normalize=False)
        assert t is not c3
        assert not np.allclose(c1.data, c3.data, equal_nan=True)
        assert max(c3.data) > 1
        # we wrote processing information in the trace:
        assert c3.stats.processing
        assert cumsumsq.__name__ in c3.stats.processing[0]

        c2 = cumsumsq(t, copy=False)
        assert t is c2
        assert max(c2.data) <= 1
        assert np.allclose(c1.data, c2.data, equal_nan=True)
        # we wrote processing information in the trace:
        assert t.stats.processing
        assert cumsumsq.__name__ in c3.stats.processing[0]
Example #2
0
    def test_timeswhere(self):
        c1 = cumsumsq(self.mseed[0], normalize=True)
        t0, t1 = timeswhere(c1, 0, 1)
        assert t0 == c1.stats.starttime
        assert t1 == c1.stats.endtime
        assert c1[0] == 0
        assert c1[-1] == 1

        c2 = cumsumsq(self.mseed[0], normalize=False)
        t0, t1 = timeswhere(c2, 0, 1)
        assert t0 == c2.stats.starttime
        assert t1 < c2.stats.endtime
        assert c2[0] > 0
        assert c2[-1] > 1

        t0, t1 = timeswhere(c1, 0.1, .9)
        assert t0 > c1.stats.starttime
        assert t1 < c1.stats.endtime
        # test the old implementation, and check that values are the same:
        starttime = c1.stats.starttime
        delta = c1.stats.delta
        tracedata = c1.data
        tt0, tt1 = [
            starttime + delta * np.searchsorted(tracedata, v)
            for v in (0.1, .9)
        ]
        assert t0 == tt0 and t1 == tt1

        # padding with nans does not change the result:
        # left pad with nan
        tmp_pt = c1.data[0]
        c1.data[0] = np.nan
        t0, t1 = timeswhere(c1, 0, 1)
        assert t0 == c1.stats.starttime
        assert t1 == c1.stats.endtime
        c1.data[0] = tmp_pt
        # right pad with nan:
        tmp_pt = c1.data[-1]
        c1.data[-1] = np.nan
        t0, t1 = timeswhere(c1, 0, 1)
        assert t0 == c1.stats.starttime
        assert t1 == c1.stats.endtime
        c1.data[-1] = tmp_pt

        # test what happens if all are nans
        c1.data = np.array([np.nan] * len(c1.data))
        t0, t1 = timeswhere(c1, 0, 1)
        assert t0 == t1 == c1.stats.starttime
Example #3
0
File: pgapgv.py Project: rizac/sod
def cumsumsq_normalized(segment, config):
    '''Computes the cumulative of the squares of the segment's trace in the form of a Plot object.
    DOES modify the segment's stream or traces in-place. Normalizes the returned trace values in [0,1]

    -Being decorated with '@gui.sideplot' or '@gui.customplot', this function must return
     a numeric sequence y taken at successive equally spaced points in any of these forms:
        - a Trace object
        - a Stream object
        - the tuple (x0, dx, y) or (x0, dx, y, label), where
            - x0 (numeric, `datetime` or `UTCDateTime`) is the abscissa of the first point
            - dx (numeric or `timedelta`) is the sampling period
            - y (numpy array or numeric list) are the sequence values
            - label (string, optional) is the sequence name to be displayed on the plot legend.
              (if x0 is numeric and `dx` is a `timedelta` object, then x0 will be converted
              to `UTCDateTime(x0)`; if x0 is a `datetime` or `UTCDateTime` object and `dx` is
              numeric, then `dx` will be converted to `timedelta(seconds=dx)`)
        - a dict of any of the above types, where the keys (string) will denote each sequence
          name to be displayed on the plot legend.

    :return: an obspy.Trace

    :raise: an Exception if `segment.stream()` is empty or has more than one trace (possible
    gaps/overlaps)
    '''
    stream = segment.stream()
    assert1trace(stream)  # raise and return if stream has more than one trace
    return cumsumsq(stream[0], normalize=True)
Example #4
0
def cumulative(segment, config):
    '''Computes the cumulative of the squares of the segment's trace in the form of a Plot object.
    Modifies the segment's stream or traces in-place. Normalizes the returned trace values
    in [0,1]

    :return: an obspy.Trace

    :raise: an Exception if `segment.stream()` is empty or has more than one trace (possible
    gaps/overlaps)
    '''
    stream = segment.stream()
    assert1trace(stream)  # raise and return if stream has more than one trace
    return cumsumsq(stream[0], normalize=True, copy=False)
Example #5
0
def derivcum2(segment, config):
    """
    compute the second derivative of the cumulative function using savitzy-golay.
    Modifies the segment's stream or traces in-place

    :return: the tuple (starttime, timedelta, values)

    :raise: an Exception if `segment.stream()` is empty or has more than one trace (possible
    gaps/overlaps)
    """
    stream = segment.stream()
    assert1trace(stream)  # raise and return if stream has more than one trace
    cum = cumsumsq(stream[0], normalize=True, copy=False)
    cfg = config['savitzky_golay']
    sec_der = savitzky_golay(cum.data, cfg['wsize'], cfg['order'],
                             cfg['deriv'])
    sec_der_abs = np.abs(sec_der)
    sec_der_abs /= np.nanmax(sec_der_abs)
    # the stream object has surely only one trace (see 'cumulative')
    return segment.stream()[0].stats.starttime, segment.stream(
    )[0].stats.delta, sec_der_abs
Example #6
0
def main(segment, config):
    """{{ PROCESS_PY_MAINFUNC | indent }}
    """
    stream = segment.stream()
    assert1trace(stream)  # raise and return if stream has more than one trace
    trace = stream[0]  # work with the (surely) one trace now

    # discard saturated signals (according to the threshold set in the config file):
    amp_ratio = ampratio(trace)
    if amp_ratio >= config['amp_ratio_threshold']:
        raise ValueError('possibly saturated (amp. ratio exceeds)')

    # bandpass the trace, according to the event magnitude.
    # WARNING: this modifies the segment.stream() permanently!
    # If you want to preserve the original stream, store trace.copy() beforehand.
    # Also, use a 'try catch': sometimes Inventories are corrupted and obspy raises
    # a TypeError, which would break the WHOLE processing execution.
    # Raising a ValueError will stop the execution of the currently processed
    # segment only (logging the error message):
    try:
        trace = bandpass_remresp(segment, config)
    except TypeError as type_error:
        raise ValueError("Error in 'bandpass_remresp': %s" % str(type_error))

    spectra = signal_noise_spectra(segment, config)
    normal_f0, normal_df, normal_spe = spectra['Signal']
    noise_f0, noise_df, noise_spe = spectra['Noise']
    evt = segment.event
    fcmin = mag2freq(evt.magnitude)
    fcmax = config['preprocess'][
        'bandpass_freq_max']  # used in bandpass_remresp
    snr_ = snr(normal_spe,
               noise_spe,
               signals_form=config['sn_spectra']['type'],
               fmin=fcmin,
               fmax=fcmax,
               delta_signal=normal_df,
               delta_noise=noise_df)
    snr1_ = snr(normal_spe,
                noise_spe,
                signals_form=config['sn_spectra']['type'],
                fmin=fcmin,
                fmax=1,
                delta_signal=normal_df,
                delta_noise=noise_df)
    snr2_ = snr(normal_spe,
                noise_spe,
                signals_form=config['sn_spectra']['type'],
                fmin=1,
                fmax=10,
                delta_signal=normal_df,
                delta_noise=noise_df)
    snr3_ = snr(normal_spe,
                noise_spe,
                signals_form=config['sn_spectra']['type'],
                fmin=10,
                fmax=fcmax,
                delta_signal=normal_df,
                delta_noise=noise_df)
    if snr_ < config['snr_threshold']:
        raise ValueError('low snr %f' % snr_)

    # calculate cumulative

    cum_labels = [0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.99]
    cum_trace = cumsumsq(
        trace, normalize=True,
        copy=True)  # copy=True prevent original trace from being modified
    cum_times = timeswhere(cum_trace, *cum_labels)

    # double event
    try:
        (score, t_double, tt1, tt2) = \
            get_multievent_sg(
                cum_trace, cum_times[1], cum_times[-2],
                config['savitzky_golay'], config['multievent_thresholds']
            )
    except IndexError as _ierr:
        raise ValueError("Error in 'get_multievent_sg': %s" % str(_ierr))
    if score in {1, 3}:
        raise ValueError('Double event detected %d %s %s %s' %
                         (score, t_double, tt1, tt2))

    # calculate PGA and times of occurrence (t_PGA):
    # note: you can also provide tstart tend for slicing
    t_PGA, PGA = maxabs(trace, cum_times[1], cum_times[-2])
    trace_int = trace.copy()
    trace_int.integrate()
    t_PGV, PGV = maxabs(trace_int, cum_times[1], cum_times[-2])
    meanoff = meanslice(trace_int, 100, cum_times[-1], trace_int.stats.endtime)

    # calculates amplitudes at the frequency bins given in the config file:
    required_freqs = config['freqs_interp']
    ampspec_freqs = normal_f0 + np.arange(len(normal_spe)) * normal_df
    required_amplitudes = np.interp(np.log10(required_freqs),
                                    np.log10(ampspec_freqs),
                                    normal_spe) / segment.sample_rate

    # compute synthetic WA.
    trace_wa = synth_wood_anderson(segment, config, trace.copy())
    t_WA, maxWA = maxabs(trace_wa)

    # write stuff to csv:
    ret = OrderedDict()

    ret['snr'] = snr_
    ret['snr1'] = snr1_
    ret['snr2'] = snr2_
    ret['snr3'] = snr3_
    for cum_lbl, cum_t in zip(cum_labels[slice(1, 8, 3)],
                              cum_times[slice(1, 8, 3)]):
        ret['cum_t%f' % cum_lbl] = float(
            cum_t)  # convert cum_times to float for saving

    ret['dist_deg'] = segment.event_distance_deg  # dist
    ret['dist_km'] = d2km(segment.event_distance_deg)  # dist_km
    # t_PGA is a obspy UTCDateTime. This type is not supported in HDF output, thus
    # convert it to Python datetime. Note that in CSV output, the value will be written as
    # str(t_PGA.datetime): another option might be to store it as string
    # with str(t_PGA) (returns the iso-formatted string, supported in all output formats):
    ret['t_PGA'] = t_PGA.datetime  # peak info
    ret['PGA'] = PGA
    # (for t_PGV, see note above for t_PGA)
    ret['t_PGV'] = t_PGV.datetime  # peak info
    ret['PGV'] = PGV
    # (for t_WA, see note above for t_PGA)
    ret['t_WA'] = t_WA.datetime
    ret['maxWA'] = maxWA
    ret['channel'] = segment.channel.channel
    ret['channel_component'] = segment.channel.channel[-1]
    # event metadata:
    ret['ev_id'] = segment.event.id
    ret['ev_lat'] = segment.event.latitude
    ret['ev_lon'] = segment.event.longitude
    ret['ev_dep'] = segment.event.depth_km
    ret['ev_mag'] = segment.event.magnitude
    ret['ev_mty'] = segment.event.mag_type
    # station metadata:
    ret['st_id'] = segment.station.id
    ret['st_name'] = segment.station.station
    ret['st_net'] = segment.station.network
    ret['st_lat'] = segment.station.latitude
    ret['st_lon'] = segment.station.longitude
    ret['st_ele'] = segment.station.elevation
    ret['score'] = score
    ret['d2max'] = float(tt1)
    ret['offset'] = np.abs(meanoff / PGV)
    for freq, amp in zip(required_freqs, required_amplitudes):
        ret['f_%.5f' % freq] = float(amp)

    return ret
Example #7
0
File: pgapgv.py Project: rizac/sod
def _main(segment, config, raw_trace_for_noisepsd, inventory_used):
    """
    called by main with supplied inventory_used, which MUST be the inventory used
    on the raw trace to obtain `segment.stream()[0]`
    """
    trace = segment.stream()[0]

    # cumulative of squares:
    cum_labels = [0.05, 0.95]
    cum_trace = cumsumsq(trace, normalize=True, copy=True)
    cum_times = timeswhere(cum_trace, *cum_labels)

    # Caluclate PGA and PGV
    # FIXME! THERE IS AN ERROR HERE WE SHOULD ITNEGRATE ONLY IF WE HAVE AN
    # ACCELEROMETER! ISN't IT?
    t_PGA, PGA = maxabs(trace, cum_times[0], cum_times[-1])
    trace_int = trace.copy().integrate()
    t_PGV, PGV = maxabs(trace_int, cum_times[0], cum_times[-1])

    # CALCULATE SPECTRA (SIGNAL and NOISE)
    spectra = _sn_spectra(segment, config)
    normal_f0, normal_df, normal_spe = spectra['Signal']
    noise_f0, noise_df, noise_spe = spectra['Noise']  # @UnusedVariable

    # AMPLITUDE (or POWER) SPECTRA VALUES and FREQUENCIES:
    required_freqs = config['freqs_interp']
    ampspec_freqs = normal_f0 + normal_df * np.arange(len(normal_spe))
    required_amplitudes = np.interp(np.log10(required_freqs),
                                    np.log10(ampspec_freqs),
                                    normal_spe) / segment.sample_rate

    # SNR:
    magnitude = segment.event.magnitude
    fcmin = mag2freq(magnitude)
    fcmax = config['preprocess']['bandpass_freq_max']  # used in bandpass_remresp
    spectrum_type = config['sn_spectra']['type']
    snr_ = snr(normal_spe, noise_spe, signals_form=spectrum_type,
               fmin=fcmin, fmax=fcmax, delta_signal=normal_df, delta_noise=noise_df)

    # PSD NOISE VALUES:
    # FIXME! DO I HAVE TO PASS THE PROCESSED TRACE (AS IT IS) or THE RAW ONE
    # (segment.stream(True)[0])?
    required_psd_periods = config['noise_psd_periods']
    required_psd_values = psd_values(segment, required_psd_periods,
                                     raw_trace_for_noisepsd,
                                     inventory_used)

    # calculates amplitudes at the frequency bins given in the config file:

    # write stuff to csv:
    ret = OrderedDict()

    distance = segment.event_distance_km

    ret['event_id'] = segment.event_id
    ret['station_id'] = segment.station.id
    ret['event_time'] = segment.event.time
    ret['snr'] = snr_
    ret['magnitude'] = magnitude
    ret['distance_km'] = distance
    ret['pga_observed'] = PGA
    ret['pga_predicted'] = gmpe_reso_14(magnitude, distance, mode='pga')
    ret['pgv_observed'] = PGV
    ret['pgv_predicted'] = gmpe_reso_14(magnitude, distance, mode='pgv')

    for f, a in zip(required_freqs, required_amplitudes):
        ret['%s@%shz' % (spectrum_type, str(f))] = float(a)

    for f, a in zip(required_psd_periods, required_psd_values):
        ret['noise_psd@%ssec' % str(f)] = float(a)

    ret['outlier'] = 0
    ret['modified'] = ''

    return ret