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)
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
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)
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]
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)
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
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)
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)
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)
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)
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
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
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)
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
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
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
""" 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
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
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
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
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
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)\ )
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
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.))
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
def gradosAkilometros(x): y = og.degrees2kilometers(x) return y
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])