Пример #1
0
def run_alarm(config, T0):

    time.sleep(config.latency)
    SCNL = DataFrame.from_dict(config.SCNL)
    lvlv = np.array(SCNL['value'])
    scnl = SCNL['scnl'].tolist()
    stas = [sta.split('.')[0] for sta in scnl]

    t1 = T0 - config.duration
    t2 = T0
    st = utils.grab_data(scnl, t1, t2, fill_value=0)

    #### preprocess data ####
    st.detrend('demean')
    st.taper(max_percentage=None, max_length=config.taper_val)
    st.filter('bandpass', freqmin=config.f1, freqmax=config.f2)

    #### calculate rsam ####
    rms = np.array([np.sqrt(np.mean(np.square(tr.data))) for tr in st])

    ############################# Icinga message #############################
    state_message = ''.join('{}: {:.0f}/{}, '.format(sta, rms[i], lvlv[i])
                            for i, sta in enumerate(stas[:-1]))
    state_message = ''.join([
        state_message,
        'Arrestor ({}): {:.0f}/{}'.format(stas[-1], rms[-1], lvlv[-1])
    ])
    ###########################################################################

    if (rms[-1] < lvlv[-1]) & (sum(rms[:-1] > lvlv[:-1]) >= config.min_sta):
        #### RSAM Detection!! ####
        ##########################
        print('********** DETECTION **********')
        state_message = '{} (UTC) RSAM detection! {}'.format(
            T0.strftime('%Y-%m-%d %H:%M'), state_message)
        state = 'CRITICAL'
        #### Generate Figure ####
        start = time.time()
        try:
            filename = make_figure(scnl, T0, config.alarm_name)
        except:
            filename = None
        ### Send Email Notification ####
        craft_and_send_email(t1, t2, stas, rms, lvlv, config.alarm_name,
                             filename)
        end = time.time()
        print('{:.2f} seconds to make figure & send email.'.format(end -
                                                                   start))
        #
    elif (rms[-1] < lvlv[-1]) & (sum(rms[:-1] > lvlv[:-1] / 2) >=
                                 config.min_sta):
        #### elevated RSAM ####
        #######################
        state_message = '{} (UTC) RSAM elevated! {}'.format(
            T0.strftime('%Y-%m-%d %H:%M'), state_message)
        state = 'WARNING'
        #
    elif sum(rms[:-1] != 0) < config.min_sta:
        #### not enough data ####
        #########################
        state_message = '{} (UTC) data missing! {}'.format(
            T0.strftime('%Y-%m-%d %H:%M'), state_message)
        state = 'WARNING'
        #
    elif (rms[-1] >= lvlv[-1]) & (sum(rms[:-1] > lvlv[:-1]) >= config.min_sta):
        ### RSAM arrested ###
        #####################
        state_message = '{} (UTC) RSAM normal (arrested). {}'.format(
            T0.strftime('%Y-%m-%d %H:%M'), state_message)
        state = 'WARNING'
        #
    else:
        #### RSAM normal ####
        #####################
        state_message = '{} (UTC) RSAM normal. {}'.format(
            T0.strftime('%Y-%m-%d %H:%M'), state_message)
        state = 'OK'

    # send heartbeat status message to icinga
    utils.icinga_state(config.alarm_name, state, state_message)
Пример #2
0
def make_figure(scnl, T0, alarm_name):
    import matplotlib as m
    m.use('Agg')
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    from matplotlib.colors import LinearSegmentedColormap
    from PIL import Image

    #### grab data ####
    start = time.time()
    st = utils.grab_data(scnl, T0 - 3600, T0, fill_value='interpolate')
    end = time.time()
    print('{:.2f} seconds to grab figure data.'.format(end - start))

    #### preprocess data ####
    st.detrend('demean')
    [
        tr.decimate(2, no_filter=True) for tr in st
        if tr.stats.sampling_rate == 100
    ]
    [
        tr.decimate(2, no_filter=True) for tr in st
        if tr.stats.sampling_rate == 50
    ]
    [tr.resample(25) for tr in st if tr.stats.sampling_rate != 25]

    colors = cm.jet(np.linspace(-1, 1.2, 256))
    color_map = LinearSegmentedColormap.from_list('Upper Half', colors)
    plt.figure(figsize=(4.5, 4.5))
    for i, tr in enumerate(st):
        ax = plt.subplot(len(st), 1, i + 1)
        tr.spectrogram(title='',
                       log=False,
                       samp_rate=25,
                       dbscale=True,
                       per_lap=0.5,
                       mult=25.0,
                       wlen=6,
                       cmap=color_map,
                       axes=ax)
        ax.set_yticks([3, 6, 9, 12])
        ax.set_ylabel(tr.stats.station + '\n' + tr.stats.channel,
                      fontsize=5,
                      rotation='horizontal',
                      multialignment='center',
                      horizontalalignment='right',
                      verticalalignment='center')
        ax.yaxis.set_ticks_position('right')
        ax.tick_params('y', labelsize=4)
        if i == 0:
            ax.set_title(alarm_name + ' Alarm')
        if i < len(st) - 1:
            ax.set_xticks([])
        else:
            d_sec = np.linspace(0, 3600, 7)
            ax.set_xticks(d_sec)
            T = [tr.stats.starttime + dt for dt in d_sec]
            ax.set_xticklabels([t.strftime('%H:%M') for t in T])
            ax.tick_params('x', labelsize=5)
            ax.set_xlabel(tr.stats.starttime.strftime('%Y-%m-%d') + ' UTC')

    plt.subplots_adjust(left=0.08, right=.94, top=0.92, bottom=0.1, hspace=0.1)
    filename = utils.tmp_figure_dir + '/' + UTCDateTime.utcnow().strftime(
        '%Y%m%d_%H%M%S_%f')
    plt.savefig(filename, dpi=250, format='png')
    im = Image.open(filename)
    remove(filename)
    filename = filename + '.jpg'
    im.save(filename)

    return filename
Пример #3
0
                         '0')  # round down to the nearest 10-minute
    except:
        warnings.warn(
            'Needs end-time argument. eg: array_processing.py 201701020205')
        sys.exit()

t1 = T0 - config.duration
t2 = T0
print('{} - {}'.format(t1.strftime('%Y.%m.%d %H:%M'),
                       t2.strftime('%Y.%m.%d %H:%M')))
for array in config.arrays:
    print('--- ' + array['Name'] + ' ---')
    #### download data ####
    SCNL = DataFrame.from_dict(array['SCNL'])
    st = utils.grab_data(SCNL['scnl'].tolist(),
                         t1 - config.latency,
                         t2 + config.latency + config.window_length,
                         fill_value=0)
    st = utils.add_coordinate_info(st, SCNL)
    array = utils.get_volcano_backazimuth(st, array)
    ########################

    #### check for enough data ####
    for tr in st:
        if np.sum(np.abs(tr.data)) == 0:
            st.remove(tr)
    if len(st) < config.min_chan:
        print('Too many blank traces. Skipping.')
        continue
    ########################

    #### check for gappy data ####
Пример #4
0
STALTA_SEC = [3, 8]

# Timeseries plot variables
TSPLOTW = 900
TSPLOTH = 200
TSTOOLS = 'pan,reset'

# Trigger settings
ntriggersta = 2  # number of required channels w a coincident detection for a trigger

#####################

# Initialize data download and cft calculation

st = utils.grab_data(settings['server'], settings['port'], settings['scnl'],
                     UTCDateTime(settings['startstop'][0]),
                     UTCDateTime(settings['startstop'][1]))

from obspy.signal.trigger import coincidence_trigger

from obspy.signal.trigger import classic_sta_lta
cft = classic_sta_lta(st[0].data, int(3 * st[0].stats.sampling_rate),
                      int(8 * st[0].stats.sampling_rate))

# set up widgets

ticker_alg = Select(value=list(STALTA_ALGORITHMS.keys())[0],
                    options=list(STALTA_ALGORITHMS.keys()))
stalta_slider = RangeSlider(start=1,
                            end=15,
                            value=(3, 8),
Пример #5
0
def make_figure(st, volcano, T0, config, mx_pressure):
    import matplotlib as m
    m.use('Agg')
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    from matplotlib.colors import LinearSegmentedColormap
    from PIL import Image
    import matplotlib.dates as mdates

    start = time.time()
    ##### get seismic data #####
    seis = utils.grab_data(volcano['seismic_scnl'],
                           T0 - 3600,
                           T0,
                           fill_value='interpolate')
    ##### get infrasound data #####
    infra_scnl = [
        '{}.{}.{}.{}'.format(tr.stats.station, tr.stats.channel,
                             tr.stats.network, tr.stats.location) for tr in st
    ]
    infra = utils.grab_data(infra_scnl, T0 - 600, T0, fill_value='interpolate')
    end = time.time()
    print('{:.2f} seconds to grab figure data.'.format(end - start))

    ###################################################
    ################# plot infrasound #################

    #### preprocess data ####
    infra.detrend('demean')
    infra.taper(max_percentage=None, max_length=config.taper_val)
    infra.filter('bandpass', freqmin=config.f1, freqmax=config.f2)
    [
        tr.decimate(2, no_filter=True) for tr in infra
        if tr.stats.sampling_rate == 100
    ]
    [
        tr.decimate(2, no_filter=True) for tr in infra
        if tr.stats.sampling_rate == 50
    ]
    [tr.resample(25) for tr in infra if tr.stats.sampling_rate != 25]

    ##### stack infrasound data #####
    print('stacking infrasound data')
    stack = xcorr_align_stream(infra, config)

    ##### plot stack spectrogram #####
    plt.figure(figsize=(4.5, 4.5))
    colors = cm.jet(np.linspace(-1, 1.2, 256))
    color_map = LinearSegmentedColormap.from_list('Upper Half', colors)

    ax = plt.subplot(len(seis) + 3, 1, 1)
    ax.set_title(config.alarm_name + ' Alarm: ' + volcano['volcano'] +
                 ' detection!')
    print(np.max(stack.data))
    stack.spectrogram(title='',
                      log=False,
                      samp_rate=25,
                      dbscale=True,
                      per_lap=0.7,
                      mult=25.0,
                      wlen=3,
                      cmap=color_map,
                      axes=ax)
    ax.set_yticks([3, 6, 9, 12])
    ax.set_ylim(0, 12.5)
    ax.set_ylabel(stack.stats.station + '\nstack',
                  fontsize=5,
                  rotation='horizontal',
                  multialignment='center',
                  horizontalalignment='right',
                  verticalalignment='center')
    ax.yaxis.set_ticks_position('right')
    ax.tick_params('y', labelsize=4)
    ax.set_xticks([])

    ##### plot stack trace #####
    ax = plt.subplot(len(seis) + 3, 1, 2)
    t1 = mdates.date2num(infra[0].stats.starttime.datetime)
    t1 = round(t1 * 24 * 60) / (24 * 60)  # round to nearest minute
    t2 = mdates.date2num(infra[0].stats.endtime.datetime)
    t2 = round(t2 * 24 * 60) / (24 * 60)  # round to nearest minute
    t_vector = np.linspace(t1, t2, stack.stats.npts)
    plt.plot(t_vector, stack.data, color='k', LineWidth=0.2)
    ax.set_ylabel(stack.stats.station + '\nstack',
                  fontsize=5,
                  rotation='horizontal',
                  multialignment='center',
                  horizontalalignment='right',
                  verticalalignment='center')
    ax.yaxis.set_ticks_position('right')
    ax.tick_params('y', labelsize=4)
    ax.set_xlim(t1, t2)
    t_ticks = np.linspace(t1, t2, 6)
    ax.set_xticks(t_ticks)
    ax.set_xticklabels([mdates.num2date(t).strftime('%H:%M') for t in t_ticks])
    ax.tick_params('x', labelsize=5)
    ax.set_xlabel(
        '{:.0f} Minute Infrasound Stack\n{} UTC,   Peak Pressure: {:.1f} Pa'.
        format(round((t2 - t1) * 24 * 60),
               tr.stats.starttime.strftime('%Y-%b-%d'), mx_pressure))
    ###################################################
    ###################################################

    ###################################################
    ################## plot seismic ###################

    #### preprocess data ####
    seis.detrend('demean')
    [
        tr.decimate(2, no_filter=True) for tr in seis
        if tr.stats.sampling_rate == 100
    ]
    [
        tr.decimate(2, no_filter=True) for tr in seis
        if tr.stats.sampling_rate == 50
    ]
    [tr.resample(25) for tr in seis if tr.stats.sampling_rate != 25]

    for i, tr in enumerate(seis):
        ax = plt.subplot(len(seis) + 3, 1, i + 1 + 3)
        tr.spectrogram(title='',
                       log=False,
                       samp_rate=25,
                       dbscale=True,
                       per_lap=0.5,
                       mult=25.0,
                       wlen=6,
                       cmap=color_map,
                       axes=ax)
        ax.set_yticks([3, 6, 9, 12])
        ax.set_ylabel(tr.stats.station + '\n' + tr.stats.channel,
                      fontsize=5,
                      rotation='horizontal',
                      multialignment='center',
                      horizontalalignment='right',
                      verticalalignment='center')
        ax.yaxis.set_ticks_position('right')
        ax.tick_params('y', labelsize=4)

        if i != len(seis) - 1:
            ax.set_xticks([])
        else:
            d_sec = np.linspace(0, 3600, 7)
            ax.set_xticks(d_sec)
            T = [tr.stats.starttime + dt for dt in d_sec]
            ax.set_xticklabels([t.strftime('%H:%M') for t in T])
            ax.tick_params('x', labelsize=5)
            ax.set_xlabel('{:.0f} Minute Local Seismic Data'.format(
                round(tr.stats.endtime - tr.stats.starttime) / 60))

    ###################################################
    ###################################################

    plt.subplots_adjust(left=0.08, right=.94, top=0.92, bottom=0.1, hspace=0.1)
    filename = utils.tmp_figure_dir + '/' + UTCDateTime.utcnow().strftime(
        '%Y%m%d_%H%M%S_%f')
    plt.savefig(filename, dpi=250, format='png')
    im = Image.open(filename)
    remove(filename)
    filename = filename + '.jpg'
    im.save(filename)

    return filename
Пример #6
0
def run_alarm(config, T0):

    time.sleep(config.latency)
    state_message = '{} (UTC) {}'.format(T0.strftime('%Y-%m-%d %H:%M'),
                                         config.alarm_name)

    #### download data ####
    SCNL = DataFrame.from_dict(config.SCNL)
    t1 = T0 - config.duration
    t2 = T0
    st = utils.grab_data(SCNL['scnl'].tolist(), t1, t2, fill_value=0)
    st = add_coordinate_info(st, SCNL)
    ########################

    #### check for enough data ####
    for tr in st:
        if np.sum(np.abs(np.abs(tr.data))) == 0:
            st.remove(tr)
    if len(st) < config.min_chan:
        state_message = '{} - Not enough channels!'.format(state_message)
        state = 'WARNING'
        utils.icinga_state(config.alarm_name, state, state_message)
        return
    ########################

    #### check for gappy data ####
    for tr in st:
        num_zeros = len(np.where(tr.data == 0)[0])
        if num_zeros / float(tr.stats.npts) > 0.01:
            st.remove(tr)
    if len(st) < config.min_chan:
        state_message = '{} - Gappy data!'.format(state_message)
        state = 'WARNING'
        utils.icinga_state(config.alarm_name, state, state_message)
        return
    ########################

    #### preprocess data ####
    st.detrend('demean')
    st.taper(max_percentage=None, max_length=config.taper_val)
    st.filter('bandpass', freqmin=config.f1, freqmax=config.f2)
    for tr in st:
        if tr.stats['sampling_rate'] == 100:
            tr.decimate(2)
        if tr.stats['sampling_rate'] != 50:
            tr.resample(50.0)
    ########################

    #### check amplitude threshold ####
    min_pa = np.array([v['min_pa'] for v in config.VOLCANO]).min()
    st = Stream(
        [tr for tr in st if np.any(np.abs(tr.data * config.digouti) > min_pa)])
    if len(st) < config.min_chan:
        state_message = '{} - not enough channels exceeding amplitude threshold!'.format(
            state_message)
        state = 'OK'
        utils.icinga_state(config.alarm_name, state, state_message)
        return
    ########################

    #### Set up grid ####
    config = get_volcano_backazimuth(st, config)
    yx, intsd, ints_az = setup_coordinate_system(st)
    #### Cross correlate ####
    lags, lags_inds1, lags_inds2 = calc_triggers(st, config, intsd)
    cmbm2, cmbm2n, counter, mpk = associator(lags_inds1, lags_inds2, st,
                                             config)

    if counter == 0:
        state_message = '{} - alarm normal.'.format(state_message)
        state = 'OK'
    else:
        #### some event detected...determine velocity and azimuth ####
        velocity, azimuth, rms = inversion(cmbm2n, cmbm2, intsd, ints_az,
                                           lags_inds1, lags_inds2, lags, mpk)
        d_Azimuth = azimuth - np.array(
            [t['back_azimuth'] for t in config.VOLCANO])
        az_tolerance = np.array(
            [t['Azimuth_tolerance'] for t in config.VOLCANO])
        #### check if this is airwave velocity from a volcano in config file list ####
        if np.any(np.abs(d_Azimuth) < az_tolerance):
            v_ind = np.argmax(np.abs(d_Azimuth) < az_tolerance)
            mx_pressure = np.max(np.array([tr.data
                                           for tr in st])) * config.digouti
            if config.VOLCANO[v_ind]['vmin'] < velocity < config.VOLCANO[v_ind][
                    'vmax'] and mx_pressure > config.VOLCANO[v_ind]['min_pa']:
                #### DETECTION ####
                volcano = config.VOLCANO[v_ind]
                d_Azimuth = d_Azimuth[v_ind]

                print('Airwave Detection!!!')
                state_message = '{} - {} detection! {:.1f} Pa peak pressure'.format(
                    state_message, volcano['volcano'], mx_pressure)
                state = 'CRITICAL'
                try:
                    filename = make_figure(st, volcano, T0, config,
                                           mx_pressure)
                except:
                    filename = None
                craft_and_send_email(t1, t2, config, volcano, d_Azimuth,
                                     velocity, mx_pressure, filename)
            else:
                print('Non-volcano detect!!!')
                state_message = '{} - Detection with wrong velocity ({:.1f} km/s) or maximum pressure ({:.1f} Pa)'.format(
                    state_message, velocity, mx_pressure)
                state = 'WARNING'
        else:
            #### trigger, but not from volcano ####
            print('Non-volcano detect!!!')
            state_message = '{} - Detection with wrong backazimuth ({:.0f} from N)'.format(
                state_message, azimuth)
            state = 'WARNING'

    # send heartbeat status message to icinga
    utils.icinga_state(config.alarm_name, state, state_message)