Beispiel #1
0
                #       print  tr.stats['station'],tr.stats['channel'],'-1,-1,-1'
                continue
            if tr.stats.distance > 20:  # only use stations within 20 degrees
                continue
            else:
                pass

#            numobs = tr.count()
#            print 'count', numobs
#            print 'seedid', seedid
#            print 'sample rate', tr.stats.sampling_rate
            sample_rate = tr.stats.sampling_rate

            try:
                tr.stats.great_circle_distance, azf, azb = gps2DistAzimuth(
                    tr.stats.coordinates.latitude,
                    tr.stats.coordinates.longitude, lat, lon)
                travel_times = vel_model.get_travel_times(
                    dep,
                    tr.stats.distance,
                    phase_list=['P', 'p', 'Pn', 'S', 'Sn']
                )  #,model="iasp91") # need to make more efficient in order
                # to only calculate once per station
                #print travel_times, type(travel_times)
                #try:
                #for arrival in travel_times:
                #    print arrival.phase.name
                #   arrivals= (item for item in travel_times if item.phase.name=='S' or item.phase.name=='Sn').next()
                #except StopIteration:
                #   print "WARNING: reference station ",tr.stats['station']," does not have S or Sn phases"
                P_time = None
Beispiel #2
0
def sachdr2assoc(header, pickmap=None):
    """
    Takes a sac header dictionary, and produces a list of up to 10
    Assoc instances. Header->phase mappings follow SAC2000, i.e.:

    * t0: P
    * t1: Pn
    * t2: Pg
    * t3: S
    * t4: Sn
    * t5: Sg
    * t6: Lg
    * t7: LR
    * t8: Rg
    * t9: pP

    An alternate mapping for some or all picks can be supplied, however,
    as a dictionary of strings in the above form.

    Note: arid values will not be filled in, so do:
    >>> for assoc in kbio.tables['assoc']:
            assoc.arid = lastarid+1
            lastarid += 1

    """
    pick2phase = {
        't0': 'P',
        't1': 'Pn',
        't2': 'Pg',
        't3': 'S',
        't4': 'Sn',
        't5': 'Sg',
        't6': 'Lg',
        't7': 'LR',
        't8': 'Rg',
        't9': 'pP'
    }

    #overwrite defaults with supplied map
    if pickmap:
        pick2phase.update(pickmap)

    #geographic relations
    # obspy.read tries to calculate these values if lcalca is True and needed
    #header info is there, so we only need to try to if lcalca is False.
    #XXX: I just calculate it if no values are currently filled in.
    sac_assoc = [('az', 'esaz'), ('baz', 'seaz'), ('gcarc', 'delta')]

    assocdict = AttribDict()
    for hdr, col in sac_assoc:
        val = header.get(hdr, None)
        assocdict[col] = val if val != SACDEFAULT[hdr] else None

    #overwrite if any are None
    if not assocdict:
        try:
            delta = geod.locations2degrees(header['stla'], header['stlo'],
                                           header['evla'], header['evlo'])
            m, seaz, esaz = geod.gps2DistAzimuth(header['stla'],
                                                 header['stlo'],
                                                 header['evla'],
                                                 header['evlo'])
            assocdict['esaz'] = esaz
            assocdict['seaz'] = seaz
            assocdict['delta'] = delta
        except (ValueError, TypeError):
            #some sac header values are None
            pass

    if header.get('kstnm', None):
        assocdict['sta'] = header['kstnm']

    orid = header.get('norid', None)
    assocdict['orid'] = orid if orid != SACDEFAULT['norid'] else None

    #now, do the phase arrival mappings
    #for each pick in hdr, make a separate dictionary containing assocdict plus
    #the new phase info.
    assocs = []
    for key in pick2phase:
        kkey = 'k' + key
        #if there's a value in t[0-9]
        if header.get(key, None) not in (SACDEFAULT[key], None):
            #if the phase name kt[0-9] is null
            if header[kkey] == SACDEFAULT[kkey]:
                #take it from the map
                iassoc = {'phase': pick2phase[key]}
            else:
                #take it directly
                iassoc = {'phase': header[kkey]}

            iassoc.update(assocdict)
            assocs.append(iassoc)

    return assocs
Beispiel #3
0
def distaz_query(records, deg=None, km=None, swath=None):
    """ 
    Out-of-database subset based on distances and/or azimuths.
    
    Parameters
    ----------
    records : iterable of objects with lat, lon attribute floats
        Target of the subset.
    deg : list or tuple of numbers, optional
        (centerlat, centerlon, minr, maxr)
        minr, maxr in degrees or None for unconstrained.
    km : list or tuple of numbers, optional
        (centerlat, centerlon, minr, maxr)
        minr, maxr in km or None for unconstrained.
    swath : list or tuple of numbers, optional
        (lat, lon, azimuth, tolerance)
        Azimuth (from North) +/-tolerance from lat,lon point in degrees.

    Returns
    -------
    list
        Subset of supplied records.

    """
    #initial True array to propagate through multiple logical AND comparisons
    mask0 = np.ones(len(records), dtype=np.bool)

    if deg:
        dgen = (geod.locations2degrees(irec.lat, irec.lon, deg[0], deg[1]) \
                for irec in records)
        degrees = np.fromiter(dgen, dtype=float)
        if deg[2] is not None:
            mask0 = np.logical_and(mask0, deg[2] <= degrees)
        if deg[3] is not None:
            mask0 = np.logical_and(mask0, deg[3] >= degrees)

        #mask0 = np.logical_and(mask0, mask)

    if km:
        #???: this may be backwards
        mgen = (geod.gps2DistAzimuth(irec.lat, irec.lon, km[0], km[1])[0] \
                  for irec in records)
        kilometers = np.fromiter(mgen, dtype=float) / 1e3
        #meters, azs, bazs = zip(*valgen)
        #kilometers = np.array(meters)/1e3
        if km[2] is not None:
            mask0 = np.logical_and(mask0, km[2] <= kilometers)
        if km[3] is not None:
            mask0 = np.logical_and(mask0, km[3] >= kilometers)

        #mask0 = np.logical_and(mask0, mask)

    if swath is not None:
        minaz = swath[2] - swath[3]
        maxaz = swath[2] + swath[3]
        #???: this may be backwards
        azgen = (geod.gps2DistAzimuth(irec.lat, irec.lon, km[0], km[1])[1] \
                 for irec in records)
        azimuths = np.fromiter(azgen, dtype=float)
        mask0 = np.logical_and(mask0, azimuths >= minaz)
        mask0 = np.logical_and(mask0, azimuths <= maxaz)

    #idx = np.nonzero(np.atleast_1d(mask0))[0] ???
    idx = np.nonzero(mask0)[0]
    recs = [records[i] for i in idx]

    return recs
Beispiel #4
0
def distaz_query(records, deg=None, km=None, swath=None):
    """ 
    Out-of-database subset based on distances and/or azimuths.
    
    Parameters
    ----------
    records : iterable of objects with lat, lon attribute floats
        Target of the subset.
    deg : list or tuple of numbers, optional
        (centerlat, centerlon, minr, maxr)
        minr, maxr in degrees or None for unconstrained.
    km : list or tuple of numbers, optional
        (centerlat, centerlon, minr, maxr)
        minr, maxr in km or None for unconstrained.
    swath : list or tuple of numbers, optional
        (lat, lon, azimuth, tolerance)
        Azimuth (from North) +/-tolerance from lat,lon point in degrees.

    Returns
    -------
    list
        Subset of supplied records.

    """
    #initial True array to propagate through multiple logical AND comparisons
    mask0 = np.ones(len(records), dtype=np.bool)

    if deg:
        dgen = (geod.locations2degrees(irec.lat, irec.lon, deg[0], deg[1]) \
                for irec in records)
        degrees = np.fromiter(dgen, dtype=float)
        if deg[2] is not None:
            mask0 = np.logical_and(mask0, deg[2] <= degrees)
        if deg[3] is not None:
            mask0 = np.logical_and(mask0, deg[3] >= degrees)

        #mask0 = np.logical_and(mask0, mask)

    if km:
        #???: this may be backwards
        mgen = (geod.gps2DistAzimuth(irec.lat, irec.lon, km[0], km[1])[0] \
                  for irec in records)
        kilometers = np.fromiter(mgen, dtype=float)/1e3
        #meters, azs, bazs = zip(*valgen)
        #kilometers = np.array(meters)/1e3
        if km[2] is not None:
            mask0 = np.logical_and(mask0, km[2] <= kilometers)
        if km[3] is not None:
            mask0 = np.logical_and(mask0, km[3] >= kilometers)

        #mask0 = np.logical_and(mask0, mask)

    if swath is not None:
        minaz = swath[2] - swath[3]
        maxaz = swath[2] + swath[3]
        #???: this may be backwards
        azgen = (geod.gps2DistAzimuth(irec.lat, irec.lon, km[0], km[1])[1] \
                 for irec in records)
        azimuths = np.fromiter(azgen, dtype=float)
        mask0 = np.logical_and(mask0, azimuths >= minaz)
        mask0 = np.logical_and(mask0, azimuths <= maxaz)

    #idx = np.nonzero(np.atleast_1d(mask0))[0] ???
    idx = np.nonzero(mask0)[0]
    recs = [records[i] for i in idx]

    return recs
Beispiel #5
0
def sachdr2assoc(header, pickmap=None):
    """
    Takes a sac header dictionary, and produces a list of up to 10
    Assoc instances. Header->phase mappings follow SAC2000, i.e.:

    * t0: P
    * t1: Pn
    * t2: Pg
    * t3: S
    * t4: Sn
    * t5: Sg
    * t6: Lg
    * t7: LR
    * t8: Rg
    * t9: pP

    An alternate mapping for some or all picks can be supplied, however,
    as a dictionary of strings in the above form.

    Note: arid values will not be filled in, so do:
    >>> for assoc in kbio.tables['assoc']:
            assoc.arid = lastarid+1
            lastarid += 1

    """
    pick2phase = {'t0': 'P', 't1': 'Pn', 't2': 'Pg', 't3': 'S',
                  't4': 'Sn', 't5': 'Sg', 't6': 'Lg', 't7': 'LR', 't8': 'Rg',
                  't9': 'pP'}

    # overwrite defaults with supplied map
    if pickmap:
        pick2phase.update(pickmap)

    # geographic relations
    # obspy.read tries to calculate these values if lcalca is True and needed
    # header info is there, so we only need to try to if lcalca is False.
    # XXX: I just calculate it if no values are currently filled in.
    sac_assoc = [('az', 'esaz'),
                 ('baz', 'seaz'),
                 ('gcarc', 'delta')]

    assocdict = AttribDict()
    for hdr, col in sac_assoc:
        val = header.get(hdr, None)
        assocdict[col] = val if val != SACDEFAULT[hdr] else None

    # overwrite if any are None
    if not assocdict:
        try:
            delta = geod.locations2degrees(header['stla'], header['stlo'],
                                           header['evla'], header['evlo'])
            m, seaz, esaz = geod.gps2DistAzimuth(header['stla'], header['stlo'],
                                                 header['evla'], header['evlo'])
            assocdict['esaz'] = esaz
            assocdict['seaz'] = seaz
            assocdict['delta'] = delta
        except (ValueError, TypeError):
            # some sac header values are None
            pass

    if header.get('kstnm', None):
        assocdict['sta'] = header['kstnm']

    orid = header.get('norid', None)
    assocdict['orid'] = orid if orid != SACDEFAULT['norid'] else None

    # now, do the phase arrival mappings
    # for each pick in hdr, make a separate dictionary containing assocdict plus
    # the new phase info.
    assocs = []
    for key in pick2phase:
        kkey = 'k' + key
        # if there's a value in t[0-9]
        if header.get(key, None) not in (SACDEFAULT[key], None):
            # if the phase name kt[0-9] is null
            if header[kkey] == SACDEFAULT[kkey]:
                # take it from the map
                iassoc = {'phase': pick2phase[key]}
            else:
                # take it directly
                iassoc = {'phase': header[kkey]}

            iassoc.update(assocdict)
            assocs.append(iassoc)

    return assocs
def plotXcorrEvent(st, stn, stack, maxlag, acausal=False, figurename=None):

    eventtime = UTCDateTime(1998, 7, 15, 4, 53, 21, 0)  # event near MLAC

    # station locations
    latP, lonP = 35.41, -120.55  # station PHL
    latM, lonM = 37.63, -118.84  # station MLAC
    latE, lonE = 37.55, -118.809  # event 1998

    # calculate distance between stations
    dist = gps2DistAzimuth(latP, lonP, latM, lonM)[0]  # between PHL and MLAC
    distE = gps2DistAzimuth(latP, lonP, latE, lonE)[0]  # between event and PHL
    #
    # CROSSCORRELATION
    # reverse stack to plot acausal part (= negative times of correlation)
    if acausal:
        stack = stack[::-1]

    # find center of stack
    c = int(np.ceil(len(stack) / 2.) + 1)

    #cut stack to maxlag
    stack = stack[c - maxlag * int(np.ceil(stn[0].stats.sampling_rate)):c +
                  maxlag * int(np.ceil(stn[0].stats.sampling_rate))]

    # find new center of stack
    c2 = int(np.ceil(len(stack) / 2.) + 1)

    # define time vector for cross correlation
    limit = (len(stack) / 2.) * stn[0].stats.delta
    timevec = np.arange(-limit, limit, stn[0].stats.delta)
    # define timevector: dist / t
    timevecDist = dist / timevec

    # EVENT
    ste = st.copy()
    st_PHL_e = ste.select(station='PHL')

    # cut down event trace to 'maxlag' seconds
    dt = len(stack[c2:]) / stn[0].stats.sampling_rate  #xcorrlength
    st_PHL_e[0].trim(eventtime, eventtime + dt)

    # create time vector for event signal
    # extreme values:
    limit = st_PHL_e[0].stats.npts * st_PHL_e[0].stats.delta
    timevecSig = np.arange(0, limit, st_PHL_e[0].stats.delta)

    # PLOTTING
    fig = plt.figure(figsize=(12.0, 6.0))
    ax1 = fig.add_subplot(2, 1, 1)
    ax2 = fig.add_subplot(2, 1, 2)

    # plot noise correlation
    ax1.plot(timevecDist[c2:], stack[c2:], 'k')
    ax1.set_title('Noise correlation between MLAC and PHL')

    # plot event near MLAC measured at PHL
    ax2.plot(distE / timevecSig,
             st_PHL_e[0].data / np.max(np.abs(st_PHL_e[0].data)), 'r')
    ax2.set_title('Event near MLAC observed at PHL')

    ax2.set_xlim((0, 8000))
    ax1.set_xlim((0, 8000))

    ax2.set_xlabel("group velocity [m/s]")

    if figurename is not None:
        fig.savefig(figurename, format="pdf")
    else:
        plt.show()
Beispiel #7
0
def process_grid(pfile, ofile, atime):
    tolerance = 0.5  # Tolerance (consider alert correct if within this range; typical value is 0.5)
    mmi_thresholds = [2.0, 3.0, 4.0, 5.0, 6.0, 7.0]  # MMI thresholds
    true_pos_rate = [0.0, 0.0, 0.0, 0.0, 0.0,
                     0.0]  # True positive rate for certain MMI
    false_pos_rate = [0.0, 0.0, 0.0, 0.0, 0.0,
                      0.0]  # False positive rate for certain MMI
    true_pos_rate2 = [0.0, 0.0, 0.0, 0.0, 0.0,
                      0.0]  # True positive rate for certain MMI (timeliness)
    false_pos_rate2 = [0.0, 0.0, 0.0, 0.0, 0.0,
                       0.0]  # False positive rate for certain MMI (timeliness)
    s_wave_velocity = 3.0  # S-wave velocity (to estimate peak shaking arrival time)
    pred_grid_data = []  # Predicted grid 2D array (read in from file)
    obs_grid_data = []  # Observed grid 2D array  (read in from file)
    distance_grid = []  # grid to hold the distances between obs and pred

    # Data structure to count each type of positive or negative result
    # when calculating the ROC curve.
    # https://en.wikipedia.org/wiki/Receiver_operating_characteristic
    num_true_pos = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    num_false_pos = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    num_true_neg = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    num_false_neg = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

    # when considering timeliness (time from eq to station alert)
    num_true_pos_timeliness = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    num_false_pos_timeliness = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    num_true_neg_timeliness = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    num_false_neg_timeliness = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

    with open(pfile, 'r') as predicted_file:
        pred_data = predicted_file.read()

    with open(ofile, 'r') as observed_file:
        obs_data = observed_file.read()

    # predicted data values
    pred_header = pred_data.split('\n', 1)[0]
    pred_grid = pred_data.split('\n')
    pred_alert_time = atime  # for now it is the time passed into the function. Should get from Analysis results
    pred_eq_lat = pred_header.split(' ')[2]
    pred_eq_lon = pred_header.split(' ')[3]

    # observed data values
    obs_header = obs_data.split('\n', 1)[0]
    obs_grid = obs_data.split('\n')
    obs_alert_time = atime  # for now it is the time passed into the function. Should get from Shakemap
    obs_eq_lat = obs_header.split(' ')[2]
    obs_eq_lon = obs_header.split(' ')[3]

    # populate pred_grid_data with grid.xyz from predicted shakemap
    for i, g in enumerate(pred_grid):
        if i != 0:
            pred_grid_data.append(g.split(' '))

    # populate obs_grid_data with grid.xyz from observed shakemap
    for i, g in enumerate(obs_grid):
        if i != 0:
            obs_grid_data.append(g.split(' '))

    pred_grid_size = len(pred_grid_data)
    obs_grid_size = len(obs_grid_data)

    #
    # compute distances grids
    #
    for i, pred_data in enumerate(pred_grid_data[:-1]):
        meters, az, baz = gps.gps2DistAzimuth(float(obs_eq_lat),
                                              float(obs_eq_lon),
                                              float(pred_grid_data[i][1]),
                                              float(pred_grid_data[i][0]))
        distance_grid.append(meters)

    #
    # comparing the two grids not taking into account timeliness
    # ignoring the timeliness calculations
    #
    for j, mmi in enumerate(mmi_thresholds):  # j, mmi values = 0 - 4 / 2 - 7
        for i, obs_data in enumerate(
                obs_grid_data[:-1]
        ):  # i = 0 thru obs_grid_size - 1. Last entry is a emtpy string.
            if float(obs_data[4]) > mmi_thresholds[j]:
                if float(pred_grid_data[i][4]) + tolerance > mmi_thresholds[j]:
                    num_true_pos[j] = num_true_pos[j] + 1.0
                else:
                    num_false_neg[j] = num_false_neg[j] + 1.0
            else:
                if float(pred_grid_data[i][4]) - tolerance > mmi_thresholds[j]:
                    num_false_pos[j] = num_false_pos[j] + 1.0
                else:
                    num_true_neg[j] = num_true_neg[j] + 1.0

        if num_true_pos[j] + num_false_neg[j] != 0.0:
            true_pos_rate[j] = num_true_pos[j] / (num_true_pos[j] +
                                                  num_false_neg[j])
            false_pos_rate[j] = num_false_pos[j] / (num_true_pos[j] +
                                                    num_false_neg[j])

    #
    # Timeliness calculations
    #
    for j, mmi in enumerate(mmi_thresholds):  # values = 0 - 4 / 2 - 7
        for i, obs_data in enumerate(
                obs_grid_data[:-1]
        ):  # i = 0 thru obs_grid_size - 1. Last entry is emtpy string.
            dist_km = distance_grid[i] / 1000.0
            ground_motion_time = dist_km / s_wave_velocity
            if float(obs_grid_data[i][4]) > mmi_thresholds[j]:
                if float(pred_grid_data[i][4]) + tolerance > mmi_thresholds[j]:
                    if float(obs_alert_time) <= float(
                            ground_motion_time
                    ):  # obs_alert_time might need to be type cast to float.
                        num_true_pos_timeliness[
                            j] = num_true_pos_timeliness[j] + 1.0
                    else:
                        num_false_neg_timeliness[
                            j] = num_false_neg_timeliness[j] + 1.0
                else:
                    num_false_neg_timeliness[
                        j] = num_false_neg_timeliness[j] + 1.0
            else:
                if float(pred_grid_data[i][4]) - tolerance > mmi_thresholds[j]:
                    num_false_pos_timeliness[
                        j] = num_false_pos_timeliness[j] + 1.0
                else:
                    num_true_neg_timeliness[
                        j] = num_true_neg_timeliness[j] + 1.0

        if num_true_pos_timeliness[j] + num_false_neg_timeliness[j] != 0.0:
            true_pos_rate2[j] = num_true_pos_timeliness[j] / (
                num_true_pos_timeliness[j] + num_false_neg_timeliness[j])
            false_pos_rate2[j] = num_false_pos_timeliness[j] / (
                num_true_pos_timeliness[j] + num_false_neg_timeliness[j])

    print "Non-timeliness"
    print "true pos rate {}".format(true_pos_rate)
    print "false pos rate {}".format(false_pos_rate)
    print "\n"
    print "Timeliness"
    print "true pos rate (timeliness) {}".format(true_pos_rate2)
    print "false pos rate (timeliness) {}".format(false_pos_rate2)