Example #1
0
 def test_degrees2kilometers(self):
     """
     """
     # Test if it works.
     assert degrees2kilometers(1.0, radius=6371) == 111.19492664455873
     # Test if setting the radius actually does something. Round to avoid
     # some precision problems on different machines.
     assert round(degrees2kilometers(1.0, radius=6381), 5) == \
            round(111.36945956975816, 5)
Example #2
0
 def test_degrees2kilometers(self):
     """
     """
     # Test if it works.
     self.assertEqual(degrees2kilometers(1.0, radius=6371),
                      111.19492664455873)
     # Test if setting the radius actually does something. Round to avoid
     # some precision problems on different machines.
     self.assertEqual(round(degrees2kilometers(1.0, radius=6381), 5),
                      round(111.36945956975816, 5))
def _get_points(r, lat, distance, ilat):
    r0 = r * math.cos(_rad(lat))
    circle = 2 * math.pi * r0
    npts = int(circle / distance)
    if npts % 2:
        npts -= 1
    dlon = 360 / npts
    real_d = locations2degrees(lat, 0, lat, dlon)
    real_d_km = degrees2kilometers(real_d) * r / R_EARTH

    print(
        "r={1:8.2f}km | latitude={0:8.2f} |  npts={2:5d} | dlon = {3:5.2f} | "
        "p2p distance={4:8.2f} ({5:8.2f}km)".format(lat, r, npts, dlon, real_d,
                                                    real_d_km))

    ps = []
    for ilon in range(npts):
        p = {
            "latitude": lat,
            "longitude": dlon * ilon,
            "sign": (-1)**(ilon + ilat)
        }
        ps.append(p)

    return ps
Example #4
0
 def calc(self):
     for a in self.arrivals:
         if a.phase not in 'pP':
             continue
         pick = a.pick_id.get_referred_object()
         station = pick.waveform_id.station_code
         scopy = self.stream.copy()
         wf = scopy.select(station=station)
         if not wf:
             continue
         onset = pick.time
         distance = degrees2kilometers(a.distance)
         azimuth = a.azimuth
         incidence = a.takeoff_angle
         w0, fc = calcsourcespec(wf, onset, self.p_velocity, distance,
                                 azimuth, incidence, self.p_attenuation,
                                 self.plot_flag, self.verbose)
         if w0 is None or fc is None:
             if self.verbose:
                 print("WARNING: insufficient frequency information")
             continue
         WF = select_for_phase(self.stream.select(station=station), a.phase)
         WF = select_for_phase(WF, "P")
         m0, mw = calcMoMw(WF, w0, self.rock_density, self.p_velocity,
                           distance, self.verbose)
         self.moment_props = (station, dict(w0=w0, fc=fc, Mo=m0))
         magnitude = ope.StationMagnitude(mag=mw)
         magnitude.origin_id = self.origin_id
         magnitude.waveform_id = pick.waveform_id
         magnitude.station_magnitude_type = self.type
         self.event.station_magnitudes.append(magnitude)
         self.magnitudes = (station, magnitude)
Example #5
0
def gmt_dist_project(dist_start, dist_end, lon0, lat0, az):
    """
    Get the points along the great circle line with the even spacing of the point distances.
    """
    g = pyproj.Geod(ellps='WGS84')
    # * note when we are talking distance in degree of Earth, it should refer to the spherical Earth or meaningless
    # firstly we convert the distance to meters
    dist_start_meter = degrees2kilometers(dist_start) * 1000
    dist_end_meter = degrees2kilometers(dist_end) * 1000

    # get the starting and endding points
    lon_start, lat_start, _ = g.fwd(lon0, lat0, az, dist_start_meter)
    lon_end, lat_end, _ = g.fwd(lon0, lat0, az, dist_end_meter)

    result = g.npts(lon_start, lat_start, lon_end, lat_end, 1000)
    result = np.array(result)

    return result[:, 0], result[:, 1]
Example #6
0
def get_y_axis(wave, setting):
    yaxis = setting["axis"]
    if (yaxis == "epicenter_distance"):
        return float(wave.stats.sac.gcarc)
    elif (yaxis == "euclidean_distance"):
        gcarc_km = degrees2kilometers(float(wave.stats.sac.gcarc))
        depth_km = float(wave.stats.sac.evdp)
        return np.sqrt(gcarc_km**2 + depth_km**2)
    elif (yaxis == "depth"):
        return float(wave.stats.sac.evdp)
Example #7
0
def discretize_world(check_ins, km=25):
    km_25 = km / degrees2kilometers(1)

    check_ins[['check_in_lat', 'check_in_long'
               ]] = check_ins.loc[:, ["latitude", "longitude"]].div(
                   km_25, axis=1).astype('int').mul(km_25)
    check_ins['cell'] = check_ins.apply(
        lambda x: (x['check_in_lat'], x['check_in_long']), axis=1)

    return check_ins
Example #8
0
 def test_ppointvsobspytaup_S2P(self):
     slowness = 12.33
     evdep = 12.4
     evdist = 67.7
     pp1 = self.model.ppoint_distance(200, slowness, phase='P')
     model = TauPyModel(model='iasp91')
     arrivals = model.get_ray_paths(evdep, evdist, ('S250p',))
     arrival = arrivals[0]
     index = np.searchsorted(arrival.path['depth'][::-1], 200)
     pdist = arrival.path['dist']
     pp2 = degrees2kilometers((pdist[-1] - pdist[-index-1]) * 180 / np.pi)
     self.assertLess(abs(pp1-pp2)/pp2, 0.2)
Example #9
0
 def test_ppointvsobspytaup_S2P(self):
     slowness = 12.33
     evdep = 12.4
     evdist = 67.7
     pp1 = self.model.ppoint_distance(200, slowness, phase='P')
     model = TauPyModel(model='iasp91')
     arrivals = model.get_ray_paths(evdep, evdist, ('S250p', ))
     arrival = arrivals[0]
     index = np.searchsorted(arrival.path['depth'][::-1], 200)
     pdist = arrival.path['dist']
     pp2 = degrees2kilometers((pdist[-1] - pdist[-index - 1]) * 180 / np.pi)
     self.assertLess(abs(pp1 - pp2) / pp2, 0.2)
Example #10
0
 def test_ppointvsobspytaup_P2S(self):
     slowness = 6.28
     evdep = 12.4
     evdist = 67.7
     depth = 200
     pp1 = self.model.ppoint_distance(depth, slowness)
     model = TauPyModel(model='iasp91')
     arrivals = model.get_ray_paths(evdep, evdist, ('P250s', ))
     arrival = arrivals[0]
     index = np.searchsorted(arrival.path['depth'][::-1], depth)
     pdist = arrival.path['dist']
     pp2 = degrees2kilometers((pdist[-1] - pdist[-index - 1]) * 180 / np.pi)
     self.assertLess(abs(pp1 - pp2) / pp2, 0.1)
Example #11
0
 def test_ppointvsobspytaup_P2S(self):
     slowness = 6.28
     evdep = 12.4
     evdist = 67.7
     depth = 200
     pp1 = self.model.ppoint_distance(depth, slowness)
     model = TauPyModel(model='iasp91')
     arrivals = model.get_ray_paths(evdep, evdist, ('P250s',))
     arrival = arrivals[0]
     index = np.searchsorted(arrival.path['depth'][::-1], depth)
     pdist = arrival.path['dist']
     pp2 = degrees2kilometers((pdist[-1] - pdist[-index-1]) * 180 / np.pi)
     self.assertLess(abs(pp1-pp2)/pp2, 0.1)
Example #12
0
        def get_isc_match(row):
            global match_index
            global length_oth_df
            progressDialog.setValue(match_index)
            print "\r     Matching event from Local Cat", match_index, ' of ', length_oth_df, ' ....',
            sys.stdout.flush()
            temp = self.isc_df_drop.apply(lambda x: abs(x - row),
                                          axis=1)  # Pandas DF
            # NaNs are treated as small
            smallest_temp = temp.nsmallest(2,
                                           columns=['lat', 'lon', 'qtime'
                                                    ]).iloc[0]  # Pandas Series

            distance_diff = degrees2kilometers(
                math.sqrt(
                    abs(smallest_temp['lat'])**2 +
                    abs(smallest_temp['lon'])**2))

            isc_index = smallest_temp.name

            if smallest_temp['qtime'] <= 15 and \
                    (abs(smallest_temp['lon']) <= 1 or np.isnan(smallest_temp['lon'])) and \
                    (abs(smallest_temp['lat']) <= 1 or np.isnan(smallest_temp['lat'])):
                ret_s = pd.Series([
                    isc_index, self.isc_df.loc[isc_index, 'event_id'],
                    self.isc_df.loc[isc_index, 'qtime'],
                    self.isc_df.loc[isc_index,
                                    'lat'], self.isc_df.loc[isc_index, 'lon'],
                    self.isc_df.loc[isc_index, 'depth'],
                    self.isc_df.loc[isc_index, 'mag'], smallest_temp['qtime'],
                    distance_diff, smallest_temp['depth'], smallest_temp['mag']
                ],
                                  index=[
                                      'isc_ind', 'event_id_match',
                                      'qtime_match', 'lat_match', 'lon_match',
                                      'depth_match', 'mag_match', 'qtime_diff',
                                      'dist_diff', 'depth_diff', 'mag_diff'
                                  ])
            else:
                ret_s = pd.Series([None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                                  index=[
                                      'isc_ind', 'event_id_match',
                                      'qtime_match', 'lat_match', 'lon_match',
                                      'depth_match', 'mag_match', 'qtime_diff',
                                      'dist_diff', 'depth_diff', 'mag_diff'
                                  ])

            match_index += 1
            return ret_s
Example #13
0
    def search_stns_in_range(self, lat, lon, rad, stations):

        stns = []
        for stn, in stations:
            stn_lon, stn_lat = self.nsta_db.query(
                NSTATable.longitude,
                NSTATable.latitude).filter(NSTATable.sta == stn).first()

            Dist = degrees2kilometers(
                locations2degrees(lat, lon, stn_lat, stn_lon))

            if Dist <= rad:
                stns.append(stn)

        return stns
Example #14
0
 def calc(self):
     for a in self.arrivals:
         if a.phase not in 'sS':
             continue
         pick = a.pick_id.get_referred_object()
         station = pick.waveform_id.station_code
         wf = select_for_phase(self.stream.select(station=station), a.phase)
         if not wf:
             if self.verbose:
                 print('WARNING: no waveform data found for station {0}'.
                       format(station))
             continue
         delta = degrees2kilometers(a.distance)
         onset = pick.time
         a0, self.p2p_fig = self.peak_to_peak(wf, onset)
         amplitude = ope.Amplitude(generic_amplitude=a0 * 1e-3)
         amplitude.unit = 'm'
         amplitude.category = 'point'
         amplitude.waveform_id = pick.waveform_id
         amplitude.magnitude_hint = self.type
         amplitude.pick_id = pick.resource_id
         amplitude.type = 'AML'
         self.event.amplitudes.append(amplitude)
         self.amplitudes = (station, amplitude)
         # using standard Gutenberg-Richter relation
         # or scale WA amplitude with given scaling relation
         if str(self.wascaling) == '[0.0, 0.0, 0.0]':
             print("Calculating original Richter magnitude ...")
             magnitude = ope.StationMagnitude(mag=np.log10(a0) \
                                                  + richter_magnitude_scaling(delta))
         else:
             print("Calculating scaled local magnitude ...")
             a0 = a0 * 1e03  # mm to nm (see Havskov & Ottemöller, 2010)
             magnitude = ope.StationMagnitude(mag=np.log10(a0) \
                                                  + self.wascaling[0] * np.log10(delta) + self.wascaling[1]
                                                                                          * delta + self.wascaling[
                                                      2])
         magnitude.origin_id = self.origin_id
         magnitude.waveform_id = pick.waveform_id
         magnitude.amplitude_id = amplitude.resource_id
         magnitude.station_magnitude_type = self.type
         self.event.station_magnitudes.append(magnitude)
         self.magnitudes = (station, magnitude)
Example #15
0
def great_circle_distance(lat_1, lon_1, lat_2, lon_2, mode='degrees'):
    """Calculate the Great Circle ditsnce"""

    theta_1 = (90.0 - lat_1) * radius_deg
    theta_2 = (90.0 - lat_2) * radius_deg
    phi_1 = lon_1 * radius_deg
    phi_2 = lon_2 * radius_deg
    angle = math.acos(
        min(
            1.0,
            math.sin(theta_1) * math.sin(theta_2) * math.cos(phi_2 - phi_1) +
            math.cos(theta_1) * math.cos(theta_2)))
    distance_deg = angle / radius_deg
    distance_km = degrees2kilometers(distance_deg)
    if mode == 'degrees':
        return distance_deg
    if mode == 'km':
        return distance_km

    return distance_deg, distance_km
Example #16
0
def regionQuery(D, P, eps):
    """
    Find all points in dataset `D` within distance `eps` of point `P`.
    
    This function calculates the distance between a point P and every other 
    point in the dataset, and then returns only those points which are within a
    threshold distance `eps`.
    """
    neighbors = []

    # For each point in the dataset...
    for Pn in range(0, len(D)):

        # Convert degrees to kilometers first
        # If the distance is below the current epsilon (magnitude), add it to the neighbors list.

        if degrees2kilometers(
                numpy.linalg.norm(D.iloc[P, 0:2] -
                                  D.iloc[Pn, 0:2])) < eps.iloc[P]:
            neighbors.append(Pn)

    return neighbors
Example #17
0
def _distazbaz(station_lat, station_lon, event_lat, event_lon):
    """We compute the distance, azimuth and back_azimuth, between two pairs
    lat lon.
    """
    degrees2rad = np.pi / 180.0
    arco_circulo = locations2degrees(event_lat, event_lon, station_lat,
                                     station_lon)
    distance = degrees2kilometers(arco_circulo)
    azimuth = np.arctan2(
            np.cos(station_lat * degrees2rad) * np.cos(event_lat * degrees2rad)\
            * np.sin((station_lon - event_lon) * degrees2rad),
            np.sin(station_lat * degrees2rad) - np.cos(arco_circulo * degrees2rad)\
            * np.sin(event_lat * degrees2rad))
    azimuth = azimuth / degrees2rad
    azimuth = np.remainder(azimuth, 360)

    sin_comp_baz = np.sin(
            (station_lon - event_lon) * degrees2rad)\
            * np.sin((90 - event_lat) * degrees2rad)\
            / np.sin(arco_circulo * degrees2rad)
    back_azimuth = 2 * np.pi - np.arcsin(sin_comp_baz)
    back_azimuth = back_azimuth / degrees2rad
    back_azimuth = np.remainder(back_azimuth, 360)
    return distance, azimuth, back_azimuth
Example #18
0
"""

A file for regularly used constants. Such as the Earth's radius.


"""
from obspy.geodetics import degrees2kilometers


# Earth's radius in km
R_EARTH = 6371.

DEG2KM = degrees2kilometers(1)
KM2DEG = 1.0/DEG2KM
maxz = 750  # maximum interpolation depth in km
maxzm = 200  # maximum depth for multiple interpolation in km
res = 1  # vertical resolution in km for interpolation and ccp bins
Example #19
0
File: core.py Project: mbyt/obspy
def nordpick(event):
    """
    Format picks in an :class:`~obspy.core.event.event.Event` to nordic.

    :type event: :class:`~obspy.core.event.event.Event`
    :param event: A single obspy event.

    :returns: List of String

    .. note::

        Currently finalweight is unsupported, nor is velocity, or
        angle of incidence.  This is because
        :class:`~obspy.core.event.event.Event` stores slowness
        in s/deg and takeoff angle, which would require computation
        from the values stored in seisan.  Multiple weights are also
        not supported.
    """

    pick_strings = []
    for pick in event.picks:
        if not pick.waveform_id:
            msg = ('No waveform id for pick at time %s, skipping' % pick.time)
            warnings.warn(msg)
            continue
        # Convert string to short sting
        if pick.onset == 'impulsive':
            impulsivity = 'I'
        elif pick.onset == 'emergent':
            impulsivity = 'E'
        else:
            impulsivity = ' '

        # Convert string to short string
        if pick.polarity == 'positive':
            polarity = 'C'
        elif pick.polarity == 'negative':
            polarity = 'D'
        else:
            polarity = ' '
        # Extract velocity: Note that horizontal slowness in quakeML is stored
        # as s/deg
        if pick.horizontal_slowness is not None:
            # velocity = 1.0 / pick.horizontal_slowness
            velocity = ' '  # Currently this conversion is unsupported.
        else:
            velocity = ' '
        # Extract azimuth
        if pick.backazimuth is not None:
            azimuth = pick.backazimuth
        else:
            azimuth = ' '
        # Extract the correct arrival info for this pick - assuming only one
        # arrival per pick...
        arrival = [arrival for arrival in event.origins[0].arrivals
                   if arrival.pick_id == pick.resource_id]
        if len(arrival) > 0:
            arrival = arrival[0]
            # Extract weight - should be stored as 0-4, or 9 for seisan.
            if arrival.time_weight is not None:
                weight = int(arrival.time_weight)
            else:
                weight = '0'
            # Extract azimuth residual
            if arrival.backazimuth_residual is not None:
                azimuthres = int(arrival.backazimuth_residual)
            else:
                azimuthres = ' '
            # Extract time residual
            if arrival.time_residual is not None:
                timeres = arrival.time_residual
            else:
                timeres = ' '
            # Extract distance
            if arrival.distance is not None:
                distance = degrees2kilometers(arrival.distance)
                if distance >= 100.0:
                    distance = str(_int_conv(distance))
                elif 10.0 < distance < 100.0:
                    distance = _str_conv(round(distance, 1), 1)
                elif distance < 10.0:
                    distance = _str_conv(round(distance, 2), 2)
                else:
                    distance = _str_conv(distance, False)
            else:
                distance = ' '
            # Extract CAZ
            if arrival.azimuth is not None:
                caz = int(arrival.azimuth)
            else:
                caz = ' '
        else:
            caz = ' '
            distance = ' '
            timeres = ' '
            azimuthres = ' '
            azimuth = ' '
            weight = 0
        if not pick.phase_hint:
            # Cope with some authorities not providing phase hints :(
            phase_hint = ' '
        else:
            phase_hint = pick.phase_hint
        # Extract amplitude: note there can be multiple amplitudes, but they
        # should be associated with different picks.
        amplitude = [amplitude for amplitude in event.amplitudes
                     if amplitude.pick_id == pick.resource_id]
        if len(amplitude) > 0:
            if len(amplitude) > 1:
                msg = 'Nordic files need one pick for each amplitude, ' + \
                      'using the first amplitude only'
                warnings.warn(msg)
            amplitude = amplitude[0]
            # Determine type of amplitude
            if amplitude.type != 'END':
                # Extract period
                if amplitude.period is not None:
                    peri = amplitude.period
                    if peri < 10.0:
                        peri_round = 2
                    elif peri >= 10.0:
                        peri_round = 1
                    else:
                        peri_round = False
                else:
                    peri = ' '
                    peri_round = False
                # Extract amplitude and convert units
                if amplitude.generic_amplitude is not None:
                    amp = amplitude.generic_amplitude
                    if amplitude.unit in ['m', 'm/s', 'm/(s*s)', 'm*s']:
                        amp *= 1e9
                    # Otherwise we will assume that the amplitude is in counts
                else:
                    amp = None
                coda = ' '
                if amplitude.magnitude_hint.upper() == 'ML':
                    phase_hint = 'IAML'
                    impulsivity = ' '
            else:
                coda = int(amplitude.generic_amplitude)
                peri = ' '
                peri_round = False
                amp = None
        else:
            peri = ' '
            peri_round = False
            amp = None
            coda = ' '
        # If the weight is 0 then we don't need to print it
        if weight == 0 or weight == '0':
            weight = None  # this will return an empty string using _str_conv
        elif weight is not None:
            weight = int(weight)
        if pick.evaluation_mode == "automatic":
            eval_mode = "A"
        elif pick.evaluation_mode == "manual":
            eval_mode = " "
        else:
            warnings.warn("Evaluation mode %s is not supported"
                          % pick.evaluation_mode)
        # Generate a print string and attach it to the list
        channel_code = pick.waveform_id.channel_code or '   '
        pick_strings.append(' ' + pick.waveform_id.station_code.ljust(5) +
                            channel_code[0] + channel_code[-1] +
                            ' ' + impulsivity + phase_hint.ljust(4) +
                            _str_conv(weight).rjust(1) + eval_mode +
                            polarity.rjust(1) + ' ' +
                            str(pick.time.hour).rjust(2) +
                            str(pick.time.minute).rjust(2) +
                            str(pick.time.second).rjust(3) + '.' +
                            str(float(pick.time.microsecond) /
                            (10 ** 4)).split('.')[0].zfill(2) +
                            _str_conv(coda).rjust(5)[0:5] +
                            _str_conv(amp, rounded=1).rjust(7)[0:7] +
                            _str_conv(peri, rounded=peri_round).rjust(5) +
                            _str_conv(azimuth).rjust(6) +
                            _str_conv(velocity).rjust(5) +
                            _str_conv(' ').rjust(4) +
                            _str_conv(azimuthres).rjust(3) +
                            _str_conv(timeres, rounded=2).rjust(5)[0:5] +
                            _str_conv(' ').rjust(2) +
                            distance.rjust(5) +
                            _str_conv(caz).rjust(4) + ' ')
        # Note that currently finalweight is unsupported, nor is velocity, or
        # angle of incidence.  This is because obspy.event stores slowness in
        # s/deg and takeoff angle, which would require computation from the
        # values stored in seisan.  Multiple weights are also not supported in
        # Obspy.event
    return pick_strings
Example #20
0
def nordpick(event):
    """
    Format information from an obspy.event class to nordic string format.

    :type event: obspy.core.event.Event
    :param event: A single obspy event.

    :returns: List of String

    .. note:: Currently finalweight is unsupported, nor is velocity, or \
    angle of incidence.  This is because obspy.event stores slowness in \
    s/deg and takeoff angle, which would require computation from the \
    values stored in seisan.  Multiple weights are also not supported in \
    Obspy.event.

    .. versionadded:: 0.1.0
    """

    pick_strings = []
    for pick in event.picks:
        if not pick.waveform_id:
            msg = 'No waveform id for pick, skipping'
            warnings.warn(msg)
            continue
        # Convert string to short sting
        if pick.onset == 'impulsive':
            impulsivity = 'I'
        elif pick.onset == 'emergent':
            impulsivity = 'E'
        else:
            impulsivity = ' '

        # Convert string to short string
        if pick.polarity == 'positive':
            polarity = 'C'
        elif pick.polarity == 'negative':
            polarity = 'D'
        else:
            polarity = ' '
        # Extract velocity: Note that horizontal slowness in quakeML is stored
        # as s/deg
        if pick.horizontal_slowness:
            # velocity = 1.0 / pick.horizontal_slowness
            velocity = ' '  # Currently this conversion is unsupported.
        else:
            velocity = ' '
        # Extract azimuth
        if pick.backazimuth:
            azimuth = pick.backazimuth
        else:
            azimuth = ' '
        # Extract the correct arrival info for this pick - assuming only one
        # arrival per pick...
        arrival = [
            arrival for arrival in event.origins[0].arrivals
            if arrival.pick_id == pick.resource_id
        ]
        if len(arrival) > 0:
            arrival = arrival[0]
            # Extract weight - should be stored as 0-4, or 9 for seisan.
            if arrival.time_weight:
                weight = int(arrival.time_weight)
            else:
                weight = '0'
            # Extract azimuth residual
            if arrival.backazimuth_residual:
                azimuthres = int(arrival.backazimuth_residual)
            else:
                azimuthres = ' '
            # Extract time residual
            if arrival.time_residual:
                timeres = arrival.time_residual
            else:
                timeres = ' '
            # Extract distance
            if arrival.distance:
                distance = degrees2kilometers(arrival.distance)
                if distance >= 100.0:
                    distance = str(_int_conv(distance))
                elif 10.0 < distance < 100.0:
                    distance = _str_conv(round(distance, 1), 1)
                elif distance < 10.0:
                    distance = _str_conv(round(distance, 2), 2)
                else:
                    distance = _str_conv(distance, False)
            else:
                distance = ' '
            # Extract CAZ
            if arrival.azimuth:
                CAZ = int(arrival.azimuth)
            else:
                CAZ = ' '
        else:
            CAZ = ' '
            distance = ' '
            timeres = ' '
            azimuthres = ' '
            azimuth = ' '
            weight = 0
        if not pick.phase_hint:
            # Cope with some authorities not providing phase hints :(
            phase_hint = ' '
        else:
            phase_hint = pick.phase_hint
        # Extract amplitude: note there can be multiple amplitudes, but they
        # should be associated with different picks.
        amplitude = [
            amplitude for amplitude in event.amplitudes
            if amplitude.pick_id == pick.resource_id
        ]
        if len(amplitude) > 0:
            if len(amplitude) > 1:
                msg = 'Nordic files need one pick for each amplitude, ' + \
                      'using the first amplitude only'
                warnings.warn(msg)
            amplitude = amplitude[0]
            # Determine type of amplitude
            if amplitude.type != 'END':
                # Extract period
                if amplitude.period:
                    peri = amplitude.period
                    if peri < 10.0:
                        peri_round = 2
                    elif peri >= 10.0:
                        peri_round = 1
                    else:
                        peri_round = False
                else:
                    peri = ' '
                    peri_round = False
                # Extract amplitude and convert units
                if amplitude.generic_amplitude:
                    amp = amplitude.generic_amplitude
                    if amplitude.unit in ['m', 'm/s', 'm/(s*s)', 'm*s']:
                        amp *= 10**9
                    # Otherwise we will assume that the amplitude is in counts
                else:
                    amp = np.nan
                coda = ' '
                if amplitude.magnitude_hint == 'Ml':
                    phase_hint = 'IAML'
                    impulsivity = ' '
            else:
                coda = int(amplitude.generic_amplitude)
                peri = ' '
                peri_round = False
                amp = np.nan
        else:
            peri = ' '
            peri_round = False
            amp = np.nan
            coda = ' '
        # If the weight is 0 then we don't need to print it
        if weight == 0 or weight == '0':
            weight = 999  # this will return an empty string using _str_conv
        # Generate a print string and attach it to the list
        channel_code = pick.waveform_id.channel_code or '   '
        pick_strings.append(
            ' ' + pick.waveform_id.station_code.ljust(5) + channel_code[0] +
            channel_code[-1] + ' ' + impulsivity + phase_hint.ljust(4) +
            _str_conv(int(weight)).rjust(1) + ' ' + polarity.rjust(1) + ' ' +
            str(pick.time.hour).rjust(2) + str(pick.time.minute).rjust(2) +
            str(pick.time.second).rjust(3) + '.' +
            str(float(pick.time.microsecond) /
                (10**4)).split('.')[0].zfill(2) +
            _str_conv(coda).rjust(5)[0:5] +
            _str_conv(round(amp, 1)).rjust(7)[0:7] +
            _str_conv(peri, rounded=peri_round).rjust(5) +
            _str_conv(azimuth).rjust(6) + _str_conv(velocity).rjust(5) +
            _str_conv(' ').rjust(4) + _str_conv(azimuthres).rjust(3) +
            _str_conv(timeres, rounded=2).rjust(5)[0:5] +
            _str_conv(' ').rjust(2) + distance.rjust(5) +
            _str_conv(CAZ).rjust(4) + ' ')
        # Note that currently finalweight is unsupported, nor is velocity, or
        # angle of incidence.  This is because obspy.event stores slowness in
        # s/deg and takeoff angle, which would require computation from the
        # values stored in seisan.  Multiple weights are also not supported in
        # Obspy.event
    return pick_strings
Example #21
0
    def pick_sw(self,
                stream,
                pick_info,
                epi,
                prior,
                npts,
                directory,
                plot_modus=False):
        if plot_modus == True:
            dir_SW = directory + '/Blind_rayleigh'
            if not os.path.exists(dir_SW):
                os.makedirs(dir_SW)
        Rayleigh_st = Stream()
        Love_st = Stream()

        dist = degrees2kilometers(epi, prior['radius'])
        phase = 0
        for pick in pick_info:
            if pick['phase_name'] == 'R1':
                if plot_modus == True:
                    dir_phases = dir_SW + '/Rayleigh_%.2f_%.2f' % (
                        pick['lower_frequency'], pick['upper_frequency'])
                    if not os.path.exists(dir_phases):
                        os.makedirs(dir_phases)
                Z_trace = stream.traces[0].copy()
                if plot_modus == True:
                    Z_trace.plot(outfile=dir_SW + '/Z_comp.pdf')
                Z_trace.detrend(type="demean")
                if (pick['lower_frequency']
                        == float(0.0)) and (pick['upper_frequency']
                                            == float(0.0)):
                    pass
                else:
                    Z_trace.filter('highpass',
                                   freq=pick['lower_frequency'],
                                   zerophase=True)
                    Z_trace.filter('lowpass',
                                   freq=pick['upper_frequency'],
                                   zerophase=True)
                Z_trace.detrend()
                Z_trace.detrend(type="demean")

                if plot_modus == True:
                    start_vline = int(
                        ((pick['time'].timestamp - pick['lower_uncertainty']) -
                         Z_trace.meta.starttime.timestamp) /
                        Z_trace.stats.delta)
                    end_vline = int(
                        ((pick['time'].timestamp + pick['lower_uncertainty']) -
                         Z_trace.meta.starttime.timestamp) /
                        Z_trace.stats.delta)
                    plt.figure()
                    ax = plt.subplot(111)
                    plt.plot(Z_trace.data, alpha=0.5)
                    ymin, ymax = ax.get_ylim()
                    plt.plot(Z_trace.data)
                    plt.vlines([start_vline, end_vline], ymin, ymax)
                    plt.xlabel(
                        Z_trace.meta.starttime.strftime(
                            '%Y-%m-%dT%H:%M:%S + sec'))
                    plt.tight_layout()
                    plt.savefig(dir_phases + '/sw_with_Rayleigh_windows.pdf')
                    # plt.show()
                    plt.close()
                Period = 1.0 / pick['frequency']
                Z_trace.trim(starttime=pick['time'] - Period,
                             endtime=pick['time'] + Period)
                zero_trace = Trace(np.zeros(npts),
                                   header={
                                       "starttime": pick['time'] - Period,
                                       'delta': Z_trace.meta.delta,
                                       "station": Z_trace.meta.station,
                                       "network": Z_trace.meta.network,
                                       "location": Z_trace.meta.location,
                                       "channel": Z_trace.meta.channel
                                   })
                total_trace = zero_trace.__add__(Z_trace,
                                                 method=0,
                                                 interpolation_samples=0,
                                                 fill_value=Z_trace.data,
                                                 sanity_checks=False)
                Rayleigh_st.append(total_trace)
                if plot_modus == True:
                    plt.figure()
                    plt.plot(
                        Z_trace.data,
                        label='%.2f_%.2f' %
                        (pick['lower_frequency'], pick['upper_frequency']))
                    plt.legend()
                    plt.tight_layout()
                    plt.savefig(dir_phases + '/diff_Love_freq.pdf')
                    plt.close()

            elif pick['phase_name'] == 'G1':
                if plot_modus == True:
                    dir_phases = dir_SW + '/Love_%.2f_%.2f' % (
                        pick['lower_frequency'], pick['upper_frequency'])
                    if not os.path.exists(dir_phases):
                        os.makedirs(dir_phases)
                T_trace = stream.traces[2].copy()
                if plot_modus == True:
                    T_trace.plot(outfile=dir_SW + '/T_comp.pdf')
                T_trace.detrend(type="demean")
                if (pick['lower_frequency']
                        == float(0.0)) and (pick['upper_frequency']
                                            == float(0.0)):
                    pass
                else:
                    T_trace.filter('highpass',
                                   freq=pick['lower_frequency'],
                                   zerophase=True)
                    T_trace.filter('lowpass',
                                   freq=pick['upper_frequency'],
                                   zerophase=True)
                T_trace.detrend()
                T_trace.detrend(type="demean")

                if plot_modus == True:
                    start_vline = int(
                        ((pick['time'].timestamp - pick['lower_uncertainty']) -
                         T_trace.meta.starttime.timestamp) /
                        T_trace.stats.delta)
                    end_vline = int(
                        ((pick['time'].timestamp + pick['lower_uncertainty']) -
                         T_trace.meta.starttime.timestamp) /
                        T_trace.stats.delta)
                    plt.figure()
                    ax = plt.subplot(111)
                    plt.plot(T_trace.data, alpha=0.5)
                    ymin, ymax = ax.get_ylim()
                    plt.plot(T_trace.data)
                    plt.vlines([start_vline, end_vline], ymin, ymax)
                    plt.xlabel(
                        T_trace.meta.starttime.strftime(
                            '%Y-%m-%dT%H:%M:%S + sec'))
                    plt.tight_layout()
                    plt.savefig(dir_phases + '/sw_with_Love_windows.pdf')
                    # plt.show()
                    plt.close()
                Period = 1.0 / pick['frequency']
                T_trace.trim(starttime=pick['time'] - Period,
                             endtime=pick['time'] + Period)
                zero_trace = Trace(np.zeros(npts),
                                   header={
                                       "starttime": pick['time'] - Period,
                                       'delta': T_trace.meta.delta,
                                       "station": T_trace.meta.station,
                                       "network": T_trace.meta.network,
                                       "location": T_trace.meta.location,
                                       "channel": T_trace.meta.channel
                                   })
                total_trace = zero_trace.__add__(T_trace,
                                                 method=0,
                                                 interpolation_samples=0,
                                                 fill_value=T_trace.data,
                                                 sanity_checks=False)
                Love_st.append(total_trace)
                if plot_modus == True:
                    plt.figure()
                    plt.plot(
                        T_trace.data,
                        label='%.2f_%.2f' %
                        (pick['lower_frequency'], pick['upper_frequency']))
                    plt.legend()
                    plt.tight_layout()
                    plt.savefig(dir_phases + '/diff_Love_freq.pdf')
                    plt.close()
        return Rayleigh_st, Love_st
Example #22
0
def amp_pick_event(event,
                   st,
                   inventory,
                   chans=['Z'],
                   var_wintype=True,
                   winlen=0.9,
                   pre_pick=0.2,
                   pre_filt=True,
                   lowcut=1.0,
                   highcut=20.0,
                   corners=4,
                   min_snr=1.0,
                   plot=False,
                   remove_old=False,
                   ps_multiplier=0.34,
                   velocity=False,
                   water_level=0):
    """
    Pick amplitudes for local magnitude for a single event.

    Looks for maximum peak-to-trough amplitude for a channel in a stream, and
    picks this amplitude and period.  There are a few things it does
    internally to stabilise the result:

        1. Applies a given filter to the data using obspy's bandpass filter.
        The filter applied is a time-domain digital SOS filter.
        This is often necessary for small magnitude earthquakes.  To correct
        for this filter later the gain of the filter at the period of the
        maximum amplitude is retrieved using scipy's sosfreqz, and used to
        divide the resulting picked amplitude.

        2. Picks the peak-to-trough amplitude, but records half of this to
        cope with possible DC offsets.

        3. Despite the original definition of local magnitude requiring the
        use of a horizontal channel, more recent work has shown that the
        vertical channels give more consistent magnitude estimations between
        stations, due to a reduction in site-amplification effects, we
        therefore use the vertical channels by default, but allow the user
        to chose which channels they deem appropriate;

        4. The maximum amplitude within the given window is picked. Care must
        be taken to avoid including surface waves in the window;

        6. A variable window-length is used by default that takes into account
        P-S times if available, this is in an effort to include only the
        body waves.  When P-S times are not available the ps_multiplier
        variable is used, which defaults to 0.34 x hypocentral distance.

    :type event: obspy.core.event.event.Event
    :param event: Event to pick
    :type st: obspy.core.stream.Stream
    :param st: Stream associated with event
    :type inventory: obspy.core.inventory.Inventory
    :param inventory:
        Inventory containing response information for the stations in st.
    :type chans: list
    :param chans:
        List of the channels to pick on, defaults to ['Z'] - should just be
        the orientations, e.g. Z, 1, 2, N, E
    :type var_wintype: bool
    :param var_wintype:
        If True, the winlen will be multiplied by the P-S time if both P and
        S picks are available, otherwise it will be multiplied by the
        hypocentral distance*ps_multiplier, defaults to True
    :type winlen: float
    :param winlen:
        Length of window, see above parameter, if var_wintype is False then
        this will be in seconds, otherwise it is the multiplier to the
        p-s time, defaults to 0.9.
    :type pre_pick: float
    :param pre_pick:
        Time before the s-pick to start the cut window, defaults to 0.2.
    :type pre_filt: bool
    :param pre_filt: To apply a pre-filter or not, defaults to True
    :type lowcut: float
    :param lowcut: Lowcut in Hz for the pre-filter, defaults to 1.0
    :type highcut: float
    :param highcut: Highcut in Hz for the pre-filter, defaults to 20.0
    :type corners: int
    :param corners: Number of corners to use in the pre-filter
    :type min_snr: float
    :param min_snr:
        Minimum signal-to-noise ratio to allow a pick - see note below on
        signal-to-noise ratio calculation.
    :type plot: bool
    :param plot: Turn plotting on or off.
    :type remove_old: bool
    :param remove_old:
        If True, will remove old amplitudes and associated picks from event
        and overwrite with new picks. Defaults to False.
    :type ps_multiplier: float
    :param ps_multiplier:
        A p-s time multiplier of hypocentral distance - defaults to 0.34,
        based on p-s ratio of 1.68 and an S-velocity 0f 1.5km/s, deliberately
        chosen to be quite slow.
    :type velocity: bool
    :param velocity:
        Whether to make the pick in velocity space or not. Original definition
        of local magnitude used displacement of Wood-Anderson, MLv in seiscomp
        and Antelope uses a velocity measurement.
    :type water_level: float
    :param water_level:
        Water-level for seismometer simulation, see

    :returns: Picked event
    :rtype: :class:`obspy.core.event.Event`

    .. Note::
        Signal-to-noise ratio is calculated using the filtered data by
        dividing the maximum amplitude in the signal window (pick window)
        by the normalized noise amplitude (taken from the whole window
        supplied).
    """
    try:
        event_origin = event.preferred_origin() or event.origins[0]
    except IndexError:
        event_origin = Origin()
    depth = event_origin.depth
    if depth is None:
        Logger.warning("No depth for the event, setting to 0 km")
        depth = 0

    # Remove amplitudes and picks for those amplitudes - this is not always
    # safe: picks may not be exclusively linked to amplitudes - hence the
    # default is *not* to do this.
    if remove_old and event.amplitudes:
        removal_ids = {amp.pick_id for amp in event.amplitudes}
        event.picks = [
            p for p in event.picks if p.resource_id not in removal_ids
        ]
        event.amplitudes = []

    # We just want to look at P and S picks.
    picks = [
        p for p in event.picks
        if p.phase_hint and p.phase_hint[0].upper() in ("P", "S")
    ]
    if len(picks) == 0:
        Logger.warning('No P or S picks found')
        return event

    st = st.copy().merge()  # merge the data, just in case! Work on a copy.
    # For each station cut the window
    for sta in {p.waveform_id.station_code for p in picks}:
        for chan in chans:
            Logger.info(f'Working on {sta} {chan}')
            tr = st.select(station=sta, component=chan)
            if not tr:
                Logger.warning(f'{sta} {chan} not found in the stream.')
                continue
            tr = tr.merge()[0]
            # Apply the pre-filter
            if pre_filt:
                tr = tr.split().detrend('simple').merge(fill_value=0)[0]
                tr.filter('bandpass',
                          freqmin=lowcut,
                          freqmax=highcut,
                          corners=corners)
            tr = _sim_WA(tr,
                         inventory,
                         water_level=water_level,
                         velocity=velocity)
            if tr is None:  # None returned when no matching response is found
                continue

            # Get the distance from an appropriate arrival
            sta_picks = [p for p in picks if p.waveform_id.station_code == sta]
            distances = []
            for pick in sta_picks:
                distances += [
                    a.distance for a in event_origin.arrivals
                    if a.pick_id == pick.resource_id and a.distance is not None
                ]
            if len(distances) == 0:
                Logger.error(f"Arrivals for station: {sta} do not contain "
                             "distances. Have you located this event?")
                hypo_dist = None
            else:
                # They should all be the same, but take the mean to be sure...
                distance = np.mean(distances)
                hypo_dist = np.sqrt(
                    np.square(degrees2kilometers(distance)) +
                    np.square(depth / 1000))

            # Get the earliest P and S picks on this station
            phase_picks = {"P": None, "S": None}
            for _hint in phase_picks.keys():
                _picks = sorted(
                    [p for p in sta_picks if p.phase_hint[0].upper() == _hint],
                    key=lambda p: p.time)
                if len(_picks) > 0:
                    phase_picks[_hint] = _picks[0]
            p_pick = phase_picks["P"]
            s_pick = phase_picks["S"]
            # Get the window size.
            if var_wintype:
                if p_pick and s_pick:
                    p_time, s_time = p_pick.time, s_pick.time
                elif s_pick and hypo_dist:
                    s_time = s_pick.time
                    p_time = s_time - (hypo_dist * ps_multiplier)
                elif p_pick and hypo_dist:
                    p_time = p_pick.time
                    s_time = p_time + (hypo_dist * ps_multiplier)
                elif (s_pick or p_pick) and hypo_dist is None:
                    Logger.error(
                        "No hypocentral distance and no matching P and S "
                        f"picks for {sta}, skipping.")
                    continue
                else:
                    raise NotImplementedError(
                        "No p or s picks - you should not have been able to "
                        "get here")
                trim_start = s_time - pre_pick
                trim_end = s_time + (s_time - p_time) * winlen
                # Work out the window length based on p-s time or distance
            else:  # Fixed window-length
                if s_pick:
                    s_time = s_pick.time
                elif p_pick and hypo_dist:
                    # In this case, there is no S-pick and the window length is
                    # fixed we need to calculate an expected S_pick based on
                    # the hypocentral distance, this will be quite hand-wavey
                    # as we are not using any kind of velocity model.
                    s_time = p_pick.time + hypo_dist * ps_multiplier
                else:
                    Logger.warning(
                        "No s-pick or hypocentral distance to predict "
                        f"s-arrival for station {sta}, skipping")
                    continue
                trim_start = s_time - pre_pick
                trim_end = s_time + winlen
            tr = tr.trim(trim_start, trim_end)
            if len(tr.data) <= 10:
                Logger.warning(f'Insufficient data for {sta}')
                continue
            # Get the amplitude
            try:
                amplitude, period, delay, peak, trough = _max_p2t(
                    tr.data, tr.stats.delta, return_peak_trough=True)
            except ValueError as e:
                Logger.error(e)
                Logger.error(f'No amplitude picked for tr {tr.id}')
                continue
            # Calculate the normalized noise amplitude
            snr = amplitude / np.sqrt(np.mean(np.square(tr.data)))
            if amplitude == 0.0:
                continue
            if snr < min_snr:
                Logger.info(
                    f'Signal to noise ratio of {snr} is below threshold.')
                continue
            if plot:
                plt.plot(np.arange(len(tr.data)), tr.data, 'k')
                plt.scatter(tr.stats.sampling_rate * delay, peak)
                plt.scatter(tr.stats.sampling_rate * (delay + period / 2),
                            trough)
                plt.show()
            Logger.info(f'Amplitude picked: {amplitude}')
            Logger.info(f'Signal-to-noise ratio is: {snr}')
            # Note, amplitude should be in meters at the moment!
            # Remove the pre-filter response
            if pre_filt:
                # Generate poles and zeros for the filter we used earlier.
                # We need to get the gain for the digital SOS filter used by
                # obspy.
                sos = iirfilter(corners, [
                    lowcut / (0.5 * tr.stats.sampling_rate), highcut /
                    (0.5 * tr.stats.sampling_rate)
                ],
                                btype='band',
                                ftype='butter',
                                output='sos')
                _, gain = sosfreqz(sos,
                                   worN=[1 / period],
                                   fs=tr.stats.sampling_rate)
                gain = np.abs(gain[0])  # Convert from complex to real.
                amplitude /= gain
                Logger.debug(f"Removed filter gain: {gain}")
            # Write out the half amplitude, approximately the peak amplitude as
            # used directly in magnitude calculations
            amplitude *= 0.5
            # Append an amplitude reading to the event
            _waveform_id = WaveformStreamID(station_code=tr.stats.station,
                                            channel_code=tr.stats.channel,
                                            network_code=tr.stats.network)
            pick = Pick(waveform_id=_waveform_id,
                        phase_hint='IAML',
                        polarity='undecidable',
                        time=tr.stats.starttime + delay,
                        evaluation_mode='automatic')
            event.picks.append(pick)
            if not velocity:
                event.amplitudes.append(
                    Amplitude(generic_amplitude=amplitude,
                              period=period,
                              pick_id=pick.resource_id,
                              waveform_id=pick.waveform_id,
                              unit='m',
                              magnitude_hint='ML',
                              type='AML',
                              category='point'))
            else:
                event.amplitudes.append(
                    Amplitude(generic_amplitude=amplitude,
                              period=period,
                              pick_id=pick.resource_id,
                              waveform_id=pick.waveform_id,
                              unit='m/s',
                              magnitude_hint='ML',
                              type='AML',
                              category='point'))
    return event
Example #23
0
    sys.exit()

### Read

if format_file is 'nlloc':
    Cat_events = read_events(input_file, format='NLLOC_HYP')
else:
    Cat_events = read_DD(input_file, 'OO')

### Loop and print

for event in Cat_events:
    lon = event.origins[0].longitude
    lat = event.origins[0].latitude
    depth = event.origins[0].depth / 1000
    x_err = degrees2kilometers(event.origins[0].longitude_errors.uncertainty)
    y_err = degrees2kilometers(event.origins[0].latitude_errors.uncertainty)
    z_err = event.origins[0].depth_errors.uncertainty / 1000
    time = event.origins[0].time
    rms = event.origins[0].quality.standard_error
    if hasattr(Cat_events[0], 'magnitude') == False:
        mag = 999
    else:
        mag = 999

    ### Print

    print(\
          "%10.4f %10.4f %7.3f %s %6.2f %7.3f %7.3f %7.3f %7.3f"\
          %(lon,lat,depth,time,mag,x_err,y_err,z_err,rms)\
          )
Example #24
0
def amp_pick_event(event,
                   st,
                   respdir,
                   chans=['Z'],
                   var_wintype=True,
                   winlen=0.9,
                   pre_pick=0.2,
                   pre_filt=True,
                   lowcut=1.0,
                   highcut=20.0,
                   corners=4,
                   min_snr=1.0,
                   plot=False,
                   remove_old=False,
                   ps_multiplier=0.34,
                   velocity=False):
    """
    Pick amplitudes for local magnitude for a single event.

    Looks for maximum peak-to-trough amplitude for a channel in a stream, and
    picks this amplitude and period.  There are a few things it does
    internally to stabilise the result:

        1. Applies a given filter to the data - very necessary for small
        magnitude earthquakes;

        2. Keeps track of the poles and zeros of this filter and removes them
        from the picked amplitude;

        3. Picks the peak-to-trough amplitude, but records half of this: the
        specification for the local magnitude is to use a peak amplitude on
        a horizontal, however, with modern digital seismometers, the peak
        amplitude often has an additional, DC-shift applied to it, to
        stabilise this, and to remove possible issues with de-meaning data
        recorded during the wave-train of an event (e.g. the mean may not be
        the same as it would be for longer durations), we use half the
        peak-to-trough amplitude;

        4. Despite the original definition of local magnitude requiring the
        use of a horizontal channel, more recent work has shown that the
        vertical channels give more consistent magnitude estimations between
        stations, due to a reduction in site-amplification effects, we
        therefore use the vertical channels by default, but allow the user
        to chose which channels they deem appropriate;

        5. We do not specify that the maximum amplitude should be the
        S-phase: The original definition holds that the maximum body-wave
        amplitude should be used - while this is often the S-phase, we do not
        discriminate against the P-phase.  We do note that, unless the user
        takes care when assigning winlen and filters, they may end up with
        amplitude picks for surface waves;

        6. We use a variable window-length by default that takes into account
        P-S times if available, this is in an effort to include only the
        body waves.  When P-S times are not available we us the ps_multiplier
        variable, which defaults to 0.34 x hypocentral distance.

    :type event: obspy.core.event.event.Event
    :param event: Event to pick
    :type st: obspy.core.stream.Stream
    :param st: Stream associated with event
    :type respdir: str
    :param respdir: Path to the response information directory
    :type chans: list
    :param chans:
        List of the channels to pick on, defaults to ['Z'] - should just be
        the orientations, e.g. Z, 1, 2, N, E
    :type var_wintype: bool
    :param var_wintype:
        If True, the winlen will be multiplied by the P-S time if both P and
        S picks are available, otherwise it will be multiplied by the
        hypocentral distance*ps_multiplier, defaults to True
    :type winlen: float
    :param winlen:
        Length of window, see above parameter, if var_wintype is False then
        this will be in seconds, otherwise it is the multiplier to the
        p-s time, defaults to 0.9.
    :type pre_pick: float
    :param pre_pick:
        Time before the s-pick to start the cut window, defaults to 0.2.
    :type pre_filt: bool
    :param pre_filt: To apply a pre-filter or not, defaults to True
    :type lowcut: float
    :param lowcut: Lowcut in Hz for the pre-filter, defaults to 1.0
    :type highcut: float
    :param highcut: Highcut in Hz for the pre-filter, defaults to 20.0
    :type corners: int
    :param corners: Number of corners to use in the pre-filter
    :type min_snr: float
    :param min_snr:
        Minimum signal-to-noise ratio to allow a pick - see note below on
        signal-to-noise ratio calculation.
    :type plot: bool
    :param plot: Turn plotting on or off.
    :type remove_old: bool
    :param remove_old:
        If True, will remove old amplitude picks from event and overwrite
        with new picks. Defaults to False.
    :type ps_multiplier: float
    :param ps_multiplier:
        A p-s time multiplier of hypocentral distance - defaults to 0.34,
        based on p-s ratio of 1.68 and an S-velocity 0f 1.5km/s, deliberately
        chosen to be quite slow.
    :type velocity: bool
    :param velocity:
        Whether to make the pick in velocity space or not. Original definition
        of local magnitude used displacement of Wood-Anderson, MLv in seiscomp
        and Antelope uses a velocity measurement.

    :returns: Picked event
    :rtype: :class:`obspy.core.event.Event`

    .. Note::
        Signal-to-noise ratio is calculated using the filtered data by
        dividing the maximum amplitude in the signal window (pick window)
        by the normalized noise amplitude (taken from the whole window
        supplied).

    .. Warning::
        Works in place on data - will filter and remove response from data,
        you are recommended to give this function a copy of the data if you
        are using it in a loop.
    """
    # Convert these picks into a lists
    stations = []  # List of stations
    channels = []  # List of channels
    picktimes = []  # List of pick times
    picktypes = []  # List of pick types
    picks_out = []
    try:
        depth = _get_origin(event).depth
    except MatchFilterError:
        depth = 0
    if remove_old and event.amplitudes:
        for amp in event.amplitudes:
            # Find the pick and remove it too
            pick = [p for p in event.picks if p.resource_id == amp.pick_id][0]
            event.picks.remove(pick)
        event.amplitudes = []
    for pick in event.picks:
        if pick.phase_hint in ['P', 'S']:
            picks_out.append(pick)  # Need to be able to remove this if there
            # isn't data for a station!
            stations.append(pick.waveform_id.station_code)
            channels.append(pick.waveform_id.channel_code)
            picktimes.append(pick.time)
            picktypes.append(pick.phase_hint)
    if len(picktypes) == 0:
        warnings.warn('No P or S picks found')
    st.merge()  # merge the data, just in case!
    # For each station cut the window
    uniq_stas = list(set(stations))
    for sta in uniq_stas:
        for chan in chans:
            print('Working on ' + sta + ' ' + chan)
            tr = st.select(station=sta, channel='*' + chan)
            if not tr:
                warnings.warn(
                    'There is no station and channel match in the wavefile!')
                continue
            else:
                tr = tr[0]
            # Apply the pre-filter
            if pre_filt:
                try:
                    tr.split().detrend('simple').merge(fill_value=0)
                except:
                    print('Some issue splitting this one')
                    dummy = tr.split()
                    dummy.detrend('simple')
                    tr = dummy.merge(fill_value=0)
                try:
                    tr.filter('bandpass',
                              freqmin=lowcut,
                              freqmax=highcut,
                              corners=corners)
                except NotImplementedError:
                    print('For some reason trace is not continuous:')
                    print(tr)
                    continue
            # Find the response information
            resp_info = _find_resp(tr.stats.station, tr.stats.channel,
                                   tr.stats.network, tr.stats.starttime,
                                   tr.stats.delta, respdir)
            PAZ = []
            seedresp = []
            if resp_info and 'gain' in resp_info:
                PAZ = resp_info
            elif resp_info:
                seedresp = resp_info
            # Simulate a Wood Anderson Seismograph
            if PAZ and len(tr.data) > 10:
                # Set ten data points to be the minimum to pass
                tr = _sim_WA(tr, PAZ, None, 10, velocity=velocity)
            elif seedresp and len(tr.data) > 10:
                tr = _sim_WA(tr, None, seedresp, 10, velocity=velocity)
            elif len(tr.data) > 10:
                warnings.warn('No PAZ for ' + tr.stats.station + ' ' +
                              tr.stats.channel + ' at time: ' +
                              str(tr.stats.starttime))
                continue
            sta_picks = [i for i in range(len(stations)) if stations[i] == sta]
            pick_id = event.picks[sta_picks[0]].resource_id
            arrival = [
                arrival for arrival in event.origins[0].arrivals
                if arrival.pick_id == pick_id
            ][0]
            hypo_dist = np.sqrt(
                np.square(degrees2kilometers(arrival.distance)) +
                np.square(depth / 1000))
            if var_wintype and hypo_dist:
                if 'S' in [picktypes[i] for i in sta_picks] and\
                   'P' in [picktypes[i] for i in sta_picks]:
                    # If there is an S-pick we can use this :D
                    s_pick = [
                        picktimes[i] for i in sta_picks if picktypes[i] == 'S'
                    ]
                    s_pick = min(s_pick)
                    p_pick = [
                        picktimes[i] for i in sta_picks if picktypes[i] == 'P'
                    ]
                    p_pick = min(p_pick)
                    try:
                        tr.trim(starttime=s_pick - pre_pick,
                                endtime=s_pick + (s_pick - p_pick) * winlen)
                    except ValueError:
                        continue
                elif 'S' in [picktypes[i] for i in sta_picks]:
                    s_pick = [
                        picktimes[i] for i in sta_picks if picktypes[i] == 'S'
                    ]
                    s_pick = min(s_pick)
                    p_modelled = s_pick - (hypo_dist * ps_multiplier)
                    try:
                        tr.trim(starttime=s_pick - pre_pick,
                                endtime=s_pick +
                                (s_pick - p_modelled) * winlen)
                    except ValueError:
                        continue
                else:
                    # In this case we only have a P pick
                    p_pick = [
                        picktimes[i] for i in sta_picks if picktypes[i] == 'P'
                    ]
                    p_pick = min(p_pick)
                    s_modelled = p_pick + (hypo_dist * ps_multiplier)
                    print('P_pick=%s' % str(p_pick))
                    print('hypo_dist: %s' % str(hypo_dist))
                    print('S modelled=%s' % str(s_modelled))
                    try:
                        tr.trim(starttime=s_modelled - pre_pick,
                                endtime=s_modelled +
                                (s_modelled - p_pick) * winlen)
                        print(tr)
                    except ValueError:
                        continue
                # Work out the window length based on p-s time or distance
            elif 'S' in [picktypes[i] for i in sta_picks]:
                # If the window is fixed we still need to find the start time,
                # which can be based either on the S-pick (this elif), or
                # on the hypocentral distance and the P-pick

                # Take the minimum S-pick time if more than one S-pick is
                # available
                s_pick = [
                    picktimes[i] for i in sta_picks if picktypes[i] == 'S'
                ]
                s_pick = min(s_pick)
                try:
                    tr.trim(starttime=s_pick - pre_pick,
                            endtime=s_pick + winlen)
                except ValueError:
                    continue
            else:
                # In this case, there is no S-pick and the window length is
                # fixed we need to calculate an expected S_pick based on the
                # hypocentral distance, this will be quite hand-wavey as we
                # are not using any kind of velocity model.
                p_pick = [
                    picktimes[i] for i in sta_picks if picktypes[i] == 'P'
                ]
                print(picktimes)
                p_pick = min(p_pick)
                s_modelled = p_pick + hypo_dist * ps_multiplier
                try:
                    tr.trim(starttime=s_modelled - pre_pick,
                            endtime=s_modelled + winlen)
                except ValueError:
                    continue
            if len(tr.data) <= 10:
                warnings.warn('No data found for: ' + tr.stats.station)
                continue
            # Get the amplitude
            try:
                amplitude, period, delay = _max_p2t(tr.data, tr.stats.delta)
            except ValueError:
                print('No amplitude picked for tr %s' % str(tr))
                continue
            # Calculate the normalized noise amplitude
            noise_amplitude = np.sqrt(np.mean(np.square(tr.data)))
            if amplitude == 0.0:
                continue
            if amplitude / noise_amplitude < min_snr:
                print('Signal to noise ratio of %s is below threshold.' %
                      (amplitude / noise_amplitude))
                continue
            if plot:
                plt.plot(np.arange(len(tr.data)), tr.data, 'k')
                plt.scatter(tr.stats.sampling_rate * delay, amplitude / 2)
                plt.scatter(tr.stats.sampling_rate * (delay + period),
                            -amplitude / 2)
                plt.show()
            print('Amplitude picked: ' + str(amplitude))
            print('Signal-to-noise ratio is: %s' %
                  (amplitude / noise_amplitude))
            # Note, amplitude should be in meters at the moment!
            # Remove the pre-filter response
            if pre_filt:
                # Generate poles and zeros for the filter we used earlier: this
                # is how the filter is designed in the convenience methods of
                # filtering in obspy.
                z, p, k = iirfilter(corners, [
                    lowcut / (0.5 * tr.stats.sampling_rate), highcut /
                    (0.5 * tr.stats.sampling_rate)
                ],
                                    btype='band',
                                    ftype='butter',
                                    output='zpk')
                filt_paz = {
                    'poles': list(p),
                    'zeros': list(z),
                    'gain': k,
                    'sensitivity': 1.0
                }
                amplitude /= (
                    paz_2_amplitude_value_of_freq_resp(filt_paz, 1 / period) *
                    filt_paz['sensitivity'])
            if PAZ:
                amplitude /= 1000
            if seedresp:  # Seedresp method returns mm
                amplitude *= 1000000
            # Write out the half amplitude, approximately the peak amplitude as
            # used directly in magnitude calculations
            amplitude *= 0.5
            # Append an amplitude reading to the event
            _waveform_id = WaveformStreamID(station_code=tr.stats.station,
                                            channel_code=tr.stats.channel,
                                            network_code=tr.stats.network)
            pick_ind = len(event.picks)
            event.picks.append(
                Pick(waveform_id=_waveform_id,
                     phase_hint='IAML',
                     polarity='undecidable',
                     time=tr.stats.starttime + delay,
                     evaluation_mode='automatic'))
            if not velocity:
                event.amplitudes.append(
                    Amplitude(generic_amplitude=amplitude / 1e9,
                              period=period,
                              pick_id=event.picks[pick_ind].resource_id,
                              waveform_id=event.picks[pick_ind].waveform_id,
                              unit='m',
                              magnitude_hint='ML',
                              type='AML',
                              category='point'))
            else:
                event.amplitudes.append(
                    Amplitude(generic_amplitude=amplitude / 1e9,
                              period=period,
                              pick_id=event.picks[pick_ind].resource_id,
                              waveform_id=event.picks[pick_ind].waveform_id,
                              unit='m/s',
                              magnitude_hint='ML',
                              type='AML',
                              category='point'))
    return event
Example #25
0
n = 2.

# Magnitude
Mw = 0.5

# Attenuation at 24.4 km from prem
Qmu = 600.
Qk = 57823.

# Density in g /m^3 from source and receiver at 24.4 km
rhos = 2.9 * 10**6
rhor = 1.02 * 10**6

# Distance in degrees to meters
deg = 1.
Rrs = degrees2kilometers(deg) * 1000.
Rrs = 100 * 1000.

# Velocity of P-waves
vpr = 1.45 * 1000.  # At receiver
vps = 6.8 * 1000.  # At source
vss = 3.9 * 1000.  # At source

# Quality Factor from Shearer
L = (4. / 3.) * (vpr / vss)**2
Qinv = L * (1. / Qmu) + (1. - L) * (1. / Qk)
Q = 1. / Qinv

# Seismic Moment
M0 = 10.**((Mw + 10.7) * (3. / 2.))
Example #26
0
def plot_map(canvas, df, event, projection, background, beachball,
             textBrowser_map_log):
    figure = canvas.fig
    figure.clf()
    ax = figure.add_subplot(111)

    # * for different projection methods, we have different Basemap
    origin = event.preferred_origin() or event.origins[0]
    evla = origin.latitude
    evlo = origin.longitude
    evdp = origin.depth / 1000

    # info from ds
    lats = df.values[:, 1]
    lons = df.values[:, 2]
    ids = df.values[:, 0]

    max_gcarc = np.max(df.values[:, 3])
    width = degrees2kilometers(max_gcarc) * 1000
    if (projection == "Azimuthal Equidistant Projection"):
        # find the max gcarc, use it as the reference of the width
        m = Basemap(width=width * 2,
                    height=width * 2,
                    projection='aeqd',
                    lat_0=evla,
                    lon_0=evlo,
                    ax=ax,
                    resolution="c")
        # draw parallels and meridians
        m.drawparallels(np.linspace(
            round(evla - max_gcarc, -1), round(evla + max_gcarc, -1),
            int((round(evla + max_gcarc, -1) - round(evla - max_gcarc, -1)) //
                10) + 1),
                        labels=[False, True, True, False])
        m.drawmeridians(np.linspace(
            round(evlo - max_gcarc, -1), round(evlo + max_gcarc, -1),
            int((round(evlo + max_gcarc, -1) - round(evlo - max_gcarc, -1)) //
                10) + 1),
                        labels=[True, False, False, True])
    elif (projection == "Mercator Projection"):
        # just don'y consider 180 line
        maxlat = np.max(lats)
        minlat = np.min(lats)
        maxlon = np.max(lons)
        minlon = np.min(lons)
        m = Basemap(projection='merc',
                    llcrnrlat=minlat,
                    urcrnrlat=maxlat,
                    llcrnrlon=minlon,
                    urcrnrlon=maxlon,
                    lat_ts=(maxlat + minlat) / 2,
                    resolution='c',
                    ax=ax)
        # draw parallels and meridians
        m.drawparallels(np.linspace(
            round(minlat, -1), round(maxlat, -1),
            int((round(maxlat, -1) - round(minlat, -1)) // 10) + 1),
                        labels=[False, True, True, False])
        m.drawmeridians(np.linspace(
            round(minlon, -1), round(maxlon, -1),
            int((round(maxlon, -1) - round(minlon, -1)) // 10) + 1),
                        labels=[True, False, False, True])
    elif (projection == "Equidistant Cylindrical Projection"):
        # just don'y consider 180 line
        maxlat = np.max(lats)
        minlat = np.min(lats)
        maxlon = np.max(lons)
        minlon = np.min(lons)
        m = Basemap(projection='cyl',
                    llcrnrlat=minlat,
                    urcrnrlat=maxlat,
                    llcrnrlon=minlon,
                    urcrnrlon=maxlon,
                    lat_ts=(maxlat + minlat) / 2,
                    resolution='c',
                    ax=ax)
        # draw parallels and meridians
        m.drawparallels(np.linspace(
            round(minlat, -1), round(maxlat, -1),
            int((round(maxlat, -1) - round(minlat, -1)) // 10) + 1),
                        labels=[False, True, True, False])
        m.drawmeridians(np.linspace(
            round(minlon, -1), round(maxlon, -1),
            int((round(maxlon, -1) - round(minlon, -1)) // 10) + 1),
                        labels=[True, False, False, True])

    if (background == "normal"):
        m.drawmapboundary(fill_color='aqua')
        m.drawcoastlines(linewidth=0.5)
        m.fillcontinents(color='coral', lake_color='aqua')

    if (beachball):
        # draw beach ball
        tensor = event.focal_mechanisms[0].moment_tensor.tensor
        moment_list = [
            tensor.m_rr, tensor.m_tt, tensor.m_pp, tensor.m_rt, tensor.m_rp,
            tensor.m_tp
        ]
        moment_list = copy.deepcopy(moment_list)
        x, y = m(evlo, evla)
        b = beach(moment_list, xy=(x, y), width=width / 18)
        b.set_zorder(10)
        ax.add_collection(b)
    else:
        x, y = m(evlo, evla)
        m.plot(x, y, "r*", markersize=5.0)

    # plot stations
    for index, row in df.iterrows():
        xpt, ypt = m(row.stlo, row.stla)
        m.plot(xpt, ypt, "ko", markersize=1.5)

    # change coordinate show
    def set_coord_format(x, y):
        lon, lat = m(x, y, inverse=True)
        result = get_clicked_station(lon, lat, lons, lats, ids)
        if (result == None):
            return f"lon: {lon:.3f}, lat: {lat:.3f}"
        else:
            return f"id: {result[0]}, lon: {result[1]}, lat: {result[2]}"

    ax.format_coord = lambda x, y: set_coord_format(x, y)

    canvas.draw()
    return m
Example #27
0
def gradosAkilometros(x):
    y = og.degrees2kilometers(x)
    return y
Example #28
0
dd_file = 'dd.xyz'
nlloc_file = 'nlloc_20m_GAU.xyz'

### Read

dd_data = readxyz(dd_file)
nlloc_data = readxyz(nlloc_file)

###

fig = plt.figure(figsize=(12, 20))
fig.suptitle('(Inversion - Grid) location differences', fontsize=20)
xbins = np.arange(-4, 4, 0.1)

ax = plt.subplot(3, 1, 1)
ax.hist(degrees2kilometers(dd_data[0] - nlloc_data[0]), xbins, color='0.75')
ax.set_xlabel('X diff [km]')
ax = plt.subplot(3, 1, 2)
ax.hist(degrees2kilometers(dd_data[1] - nlloc_data[1]), xbins, color='0.75')
ax.set_xlabel('Y diff [km]')
ax = plt.subplot(3, 1, 3)
ax.hist(dd_data[2] - nlloc_data[2], xbins, color='0.75')
ax.set_xlabel('Z diff [km]')

fig.savefig("loc_diff.png")

#plt.hist(dd_data[2]-nlloc_data[2],xbins)

#plt.hist(dd_data[2],50)
    return ()


# this will actually run the code if called stand-alone:
if __name__ == '__main__':
    main()

#%%

eqlon = 162.05
eqlat = -11.463

#SNZO
lat1 = -41.309
lon1 = 174.704
rad1 = degrees2kilometers(32)

#JCP
lat2 = 27.0957
lon2 = 142.1849
rad2 = degrees2kilometers(42)

#UWB
lat3 = 19.425
lon3 = -155.226
rad3 = degrees2kilometers(50)

# a map:
plt.figure()
ax = plt.axes(projection=ccrs.Robinson(central_longitude=180))
ax.set_extent([80, 270, 35, -80])