def make_lookup(phase_families, h5f, st, evdp, int_3d): cdp = np.arange(50, 1010, 20) mod = TauPyModel('prem') for idx, tr in enumerate(st): name = tr.stats.network + tr.stats.station + tr.stats.location print name, round(float(idx) / len(f.keys()) * 100., 2), '%' h5f.create_group(name) for keys in phase_families: h5f[name].create_group(keys) arr = mod.get_ray_paths_geo( source_depth_in_km=evdp, source_latitude_in_deg=tr.stats.evla, source_longitude_in_deg=tr.stats.evlo, receiver_latitude_in_deg=tr.stats.stla, receiver_longitude_in_deg=tr.stats.stlo, phase_list=[keys]) h5f[name][keys].create_dataset('1d_time', data=[arr[0].time]) main_path = np.array( [list((i[3], -i[4], i[5])) for i in arr[0].path]) main_trace = 1 - (int_3d(main_path)[1::] * 0.01) main_dt = np.diff(np.array([i[1] for i in arr[0].path])) time_3d = np.sum(main_dt * main_trace) h5f[name][keys].create_dataset('3d_time', data=[time_3d]) for phase in phase_families[keys]: h5f[name][keys].create_group(phase) master_time = [] master_time_3d = [] master_depth = [] if phase.startswith('s'): for ii in cdp: time_list, time_list_3d, depth_list = top_depth_times( evdp, ii, phase, tr, int_3d) master_time.append(time_list) master_time_3d.append(time_list_3d) master_depth.append(depth_list) elif phase.startswith('S'): for ii in cdp: time_list, time_list_3d, depth_list = bot_depth_times( evdp, ii, phase, tr, int_3d) master_time.append(time_list) master_time_3d.append(time_list_3d) master_depth.append(depth_list) master_time = np.array(master_time) master_time = np.vstack((0, master_time)) master_time_3d = np.array(master_time_3d) master_time_3d = np.vstack((0, master_time_3d)) master_depth = np.array(master_depth) master_depth = np.vstack((0, master_depth)) h5f[name][keys][phase].create_dataset('1d_time', data=master_time) h5f[name][keys][phase].create_dataset('3d_time', data=master_time_3d) h5f[name][keys][phase].create_dataset('depth', data=master_depth)
def top_depth_times(evdp,cdp,phase_list_in,stla,stlo,evla,evlo,int_3d): mod = TauPyModel(model='prem'+str(int(cdp))) phase_list = phase_list_in phase_list = phase_list.replace('X',str(cdp)) depth_list = [] time_list = [] time_list_3d = [] arr = mod.get_ray_paths_geo(source_depth_in_km=evdp, source_latitude_in_deg=evla, source_longitude_in_deg=evlo, receiver_latitude_in_deg=stla, receiver_longitude_in_deg=stlo, phase_list=[phase_list]) pure_depth = float(re.findall('\d+',arr[0].purist_name)[0]) depth_list.append(pure_depth) time = arr[0].time time_list.append(time) rev_path = np.array([list((i[3],-i[4],i[5])) for i in arr[0].path]) rev_trace = 1-(int_3d(rev_path)[1::]*0.01) rev_dt = np.diff(np.array([i[1] for i in arr[0].path])) time_list_3d.append(np.sum(rev_dt*rev_trace)) return time_list,time_list_3d,depth_list
def test_single_path_geo_iasp91(self): """ Test the raypath for a single phase given geographical input. This tests the case when geographiclib is installed. """ filename = os.path.join(DATA, "taup_path_-mod_iasp91_-o_stdout_-h_10_" + "-ph_P_-sta_-45_-60_evt_-80_-60") expected = np.genfromtxt(filename, comments='>') m = TauPyModel(model="iasp91") arrivals = m.get_ray_paths_geo(source_depth_in_km=10.0, source_latitude_in_deg=-80.0, source_longitude_in_deg=-60.0, receiver_latitude_in_deg=-45.0, receiver_longitude_in_deg=-60.0, phase_list=["P"]) self.assertEqual(len(arrivals), 1) # Interpolate both paths to 100 samples and make sure they are # approximately equal. sample_points = np.linspace(0, 35, 100) interpolated_expected_depth = np.interp( sample_points, expected[:, 0], expected[:, 1]) interpolated_expected_lat = np.interp( sample_points, expected[:, 0], expected[:, 2]) interpolated_expected_lon = np.interp( sample_points, expected[:, 0], expected[:, 3]) interpolated_actual_depth = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(6371 - arrivals[0].path['depth'], 2)) interpolated_actual_lat = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(arrivals[0].path['lat'], 2)) interpolated_actual_lon = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(arrivals[0].path['lon'], 2)) np.testing.assert_allclose(interpolated_actual_depth, interpolated_expected_depth, rtol=1E-4, atol=0) np.testing.assert_allclose(interpolated_actual_lat, interpolated_expected_lat, rtol=1E-4, atol=0) np.testing.assert_allclose(interpolated_actual_lon, interpolated_expected_lon, rtol=1E-4, atol=0)
def test_single_path_geo_iasp91(self): """ Test the raypath for a single phase given geographical input. This tests the case when geographiclib is installed. """ filename = os.path.join( DATA, "taup_path_-mod_iasp91_-o_stdout_-h_10_" + "-ph_P_-sta_-45_-60_evt_-80_-60") expected = np.genfromtxt(filename, comments='>') m = TauPyModel(model="iasp91") with warnings.catch_warnings(record=True): warnings.simplefilter("always") arrivals = m.get_ray_paths_geo(source_depth_in_km=10.0, source_latitude_in_deg=-80.0, source_longitude_in_deg=-60.0, receiver_latitude_in_deg=-45.0, receiver_longitude_in_deg=-60.0, phase_list=["P"]) self.assertEqual(len(arrivals), 1) # Interpolate both paths to 100 samples and make sure they are # approximately equal. sample_points = np.linspace(0, 35, 100) interpolated_expected_depth = np.interp(sample_points, expected[:, 0], expected[:, 1]) interpolated_expected_lat = np.interp(sample_points, expected[:, 0], expected[:, 2]) interpolated_expected_lon = np.interp(sample_points, expected[:, 0], expected[:, 3]) interpolated_actual_depth = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(6371 - arrivals[0].path['depth'], 2)) np.testing.assert_allclose(interpolated_actual_depth, interpolated_expected_depth, rtol=1E-4, atol=0) if geodetics.GEOGRAPHICLIB_VERSION_AT_LEAST_1_34: interpolated_actual_lat = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(arrivals[0].path['lat'], 2)) interpolated_actual_lon = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(arrivals[0].path['lon'], 2)) np.testing.assert_allclose(interpolated_actual_lat, interpolated_expected_lat, rtol=1E-4, atol=0) np.testing.assert_allclose(interpolated_actual_lon, interpolated_expected_lon, rtol=1E-4, atol=0)
def test_single_path_geo_fallback_iasp91(self): """ Test the raypath for a single phase given geographical input. This version of the test checks that things still work when geographiclib is not installed. """ has_geographiclib_real = geodetics.HAS_GEOGRAPHICLIB geodetics.HAS_GEOGRAPHICLIB = False filename = os.path.join(DATA, "taup_path_-o_stdout_-h_10_-ph_P_-deg_35") expected = np.genfromtxt(filename, comments='>') m = TauPyModel(model="iasp91") with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") arrivals = m.get_ray_paths_geo(source_depth_in_km=10.0, source_latitude_in_deg=-80.0, source_longitude_in_deg=-60.0, receiver_latitude_in_deg=-45.0, receiver_longitude_in_deg=-60.0, phase_list=["P"]) geodetics.HAS_GEOGRAPHICLIB = has_geographiclib_real self.assertTrue(issubclass(w[-1].category, UserWarning)) self.assertEqual(len(arrivals), 1) # Interpolate both paths to 100 samples and make sure they are # approximately equal. sample_points = np.linspace(0, 35, 100) interpolated_expected = np.interp( sample_points, expected[:, 0], expected[:, 1]) interpolated_actual = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(6371 - arrivals[0].path['depth'], 2)) np.testing.assert_allclose(interpolated_actual, interpolated_expected, rtol=1E-4, atol=0) # NB: we do not check path['lat'] and path['lon'] here, as these # are not calculated when geographiclib is not installed. We check # that they are not present. with self.assertRaises(ValueError): arrivals[0].path["lat"] with self.assertRaises(ValueError): arrivals[0].path["lon"]
def test_single_path_geo_fallback_iasp91(self): """ Test the raypath for a single phase given geographical input. This version of the test checks that things still work when geographiclib is not installed. """ has_geographiclib_real = geodetics.HAS_GEOGRAPHICLIB geodetics.HAS_GEOGRAPHICLIB = False filename = os.path.join(DATA, "taup_path_-o_stdout_-h_10_-ph_P_-deg_35") expected = np.genfromtxt(filename, comments='>') m = TauPyModel(model="iasp91") with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") arrivals = m.get_ray_paths_geo(source_depth_in_km=10.0, source_latitude_in_deg=-80.0, source_longitude_in_deg=-60.0, receiver_latitude_in_deg=-45.0, receiver_longitude_in_deg=-60.0, phase_list=["P"]) geodetics.HAS_GEOGRAPHICLIB = has_geographiclib_real assert issubclass(w[-1].category, UserWarning) self.assertEqual(len(arrivals), 1) # Interpolate both paths to 100 samples and make sure they are # approximately equal. sample_points = np.linspace(0, 35, 100) interpolated_expected = np.interp( sample_points, expected[:, 0], expected[:, 1]) interpolated_actual = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(6371 - arrivals[0].path['depth'], 2)) np.testing.assert_allclose(interpolated_actual, interpolated_expected, rtol=1E-4, atol=0) # NB: we do not check path['lat'] and path['lon'] here, as these # are not calculated when geographiclib is not installed. We check # that they are not present. with self.assertRaises(ValueError): arrivals[0].path["lat"] with self.assertRaises(ValueError): arrivals[0].path["lon"]
def calculate_ray(elat, elon, slat, slon, evdp): """function calculates the path along a seismic ray and outputs a list of lonlat values to be used in calculations """ #print(elat, elon, slat, slon, evdp) model = TauPyModel(model="ak135") arrivals = model.get_ray_paths_geo(evdp, elat, elon, slat, slon, \ phase_list=('S')) arrival = arrivals[0] path_array = arrival.path latlons = [] print(path_array) for point in path_array: latlon = [point[4], point[5]] latlons.append(latlon) latlons = np.array(latlons) return latlons
print( c_fdsn.get_stations(network=network, station=station, format="text")[0][0]) # + {"deletable": true, "editable": true} # Plot the ray paths just to illustrate what we are working with. from obspy.taup import TauPyModel m = TauPyModel("ak135") print( m.get_travel_times_geo(source_depth_in_km=17.4, source_latitude_in_deg=-31.130, source_longitude_in_deg=-72.090, receiver_latitude_in_deg=34.95, receiver_longitude_in_deg=-106.46)) m.get_ray_paths_geo(source_depth_in_km=17.4, source_latitude_in_deg=-31.130, source_longitude_in_deg=-72.090, receiver_latitude_in_deg=34.95, receiver_longitude_in_deg=-106.46, phase_list=["P", "pP", "sP", "PcP", "PP"]).plot() # + {"deletable": true, "editable": true} # Calculate distance. from obspy.geodetics import locations2degrees locations2degrees(lat1=-31.130, long1=-72.090, lat2=34.95, long2=-106.46) # + {"deletable": true, "editable": true} components = "Z" # Varying length of databases. Use common time range. starttime = obspy.UTCDateTime("2015-09-16T22:55:22.000000Z") endtime = obspy.UTCDateTime("2015-09-16T23:23:46.200000Z")
def get_ray_paths(inventory, catalog, phase_list=['P'], coordinate_system='XYZ', taup_model='iasp91'): """ This function returns lat, lon, depth coordinates from an event location to all stations in the inventory object :param inventory: an obspy station inventory :param catalog: an obspy event catalog :param phase_list: a list of seismic phase names that is passed to taup :param coordinate_system: can be either 'XYZ' or 'RTP'. :param taup_model: the taup model for which the greatcircle paths are computed :returns: a list of tuples ``[(gcircle, phase_name, station_label, event_timestamp, event_magnitude, event_id, origin_id), ...]``. ``gcircle`` is an array of shape ``[3, npoints]`` with the path coordinates. ``phase_name`` is the name of the seismic phase, ``station_label`` is the name of the station and network that belongs to the path. ``event_timestamp``, ``event_magnitude``, ``event_id`` and ``origin_id`` describe the event that belongs to the path. """ # GEOGRAPHICLIB is mandatory for this function if not geodetics.HAS_GEOGRAPHICLIB: raise ImportError('Geographiclib not found but required by ray path ' 'routine') stlats = [] stlons = [] stlabels = [] for network in inventory: for station in network: label_ = ".".join((network.code, station.code)) if station.latitude is None or station.longitude is None: msg = ("Station '%s' does not have latitude/longitude " "information and will not be plotted." % label_) warnings.warn(msg) continue stlats.append(station.latitude) stlons.append(station.longitude) stlabels.append(label_) # make a big list of event coordinates and names # this part should be included as a subroutine of catalog that extracts # a list of event properties. E.g. catalog.extract(['latitiude', # 'longitude', 'depth', 'mag', 'focal_mechanism') The same should be done # for an inventory with stations evlats = [] evlons = [] evdepths = [] event_ids = [] origin_ids = [] magnitudes = [] times = [] for event in catalog: if not event.origins: msg = ("Event '%s' does not have an origin and will not be " "plotted." % str(event.resource_id)) warnings.warn(msg) continue if not event.magnitudes: msg = ("Event '%s' does not have a magnitude and will not be " "plotted." % str(event.resource_id)) warnings.warn(msg) continue origin = event.preferred_origin() or event.origins[0] evlats.append(origin.latitude) evlons.append(origin.longitude) if not origin.get('depth'): # XXX do we really want to include events without depth??? origin.depth = 0. evdepths.append(origin.get('depth') * 1e-3) magnitude = event.preferred_magnitude() or event.magnitudes[0] mag = magnitude.mag event_ids.append(str(event.resource_id)) origin_ids.append(str(origin.resource_id)) magnitudes.append(mag) times.append(origin.time.timestamp) # initialize taup model if it is not provided if isinstance(taup_model, str): from obspy.taup import TauPyModel model = TauPyModel(model=taup_model) else: model = taup_model # now loop through all stations and source combinations r_earth = model.model.radius_of_planet greatcircles = [] for stlat, stlon, stlabel in zip(stlats, stlons, stlabels): for evlat, evlon, evdepth_km, time, magnitude, event_id, origin_id \ in zip(evlats, evlons, evdepths, times, magnitudes, event_ids, origin_ids): arrivals = model.get_ray_paths_geo(evdepth_km, evlat, evlon, stlat, stlon, phase_list=phase_list, resample=True) if len(arrivals) == 0: continue for arr in arrivals: radii = (r_earth - arr.path['depth']) / r_earth thetas = np.radians(90. - arr.path['lat']) phis = np.radians(arr.path['lon']) if coordinate_system == 'RTP': gcircle = np.array([radii, thetas, phis]) if coordinate_system == 'XYZ': gcircle = np.array([ radii * np.sin(thetas) * np.cos(phis), radii * np.sin(thetas) * np.sin(phis), radii * np.cos(thetas) ]) greatcircles.append((gcircle, arr.name, stlabel, time, magnitude, event_id, origin_id)) return greatcircles
def mig_one_station(stream, model="ak135", earth_radius=6378137.0, depth_range=(0, 300, 1)): try: # prior to the model used to calculate traveltime model = stream[0].stats.model except AttributeError: model = model taup_model = TauPyModel(model=model) for tr in stream: evdp = tr.stats.event_depth evla = tr.stats.event_latitude evlo = tr.stats.event_longitude stla = tr.stats.station_latitude stlo = tr.stats.station_longitude phase = tr.stats.phase # tr.filter(type="bandpass", freqmin=0.05, freqmax=0.5, zerophase=True) arrivals = taup_model.get_ray_paths_geo(source_depth_in_km=evdp, source_latitude_in_deg=evla, source_longitude_in_deg=evlo, receiver_latitude_in_deg=stla, receiver_longitude_in_deg=stlo, phase_list=(phase,), resample=True) arr = arrivals[0] # raypath coordinates. The dataframe contains six columns, ray_p, traveltime, dist in rad, depth, lat and lon. df = pd.DataFrame(arr.path) # one-way reflection time time = tr.times() / 2 data = tr.data # ray path information: traveltime, depth, and coordinates # reverse time: the maximum traveltime minus traveltime at varied depths or points df["time_reverse"] = df["time"].iloc[-1] - df["time"] # get sub-dataset with traveltime (ray path) slightly longer than the one-way reflected traveltime from acc # for convenience of interpolation df2 = df[df["time_reverse"] < time[-1] * 1.2] # convert the raypath information from dataframe to numpy array ttime = df["time_reverse"].to_numpy() depth = df["depth"].to_numpy() lat = df["lat"].to_numpy() lon = df["lon"].to_numpy() # simple migration by back projection fdepth = interp1d(ttime, depth) flat = interp1d(ttime, lat) flon = interp1d(ttime, lon) # interpolation fitting in with one-way reflection time to accomplish back projection depths = fdepth(time) lats = flat(time) lons = flon(time) # calculate the distances from pierce points to station at different depths # or varied radius dists = np.zeros_like(depths) for i, d in enumerate(depths): dists[i], az, baz = gps2dist_azimuth(lat1=tr.stats.station_latitude, lon1=tr.stats.station_longitude, lat2=lats[i], lon2=lons[i], a=earth_radius-d) # convert the unit from m to km. If the piere point is to the south of the station then distance is negative. if lats[i] <= tr.stats.station_latitude: dists[i] = -dists[i] dists /= 1000 # the following several lines can be commented. This was firstly written to save data with # irregular depth sampling intervals. mig1sta = pd.DataFrame(columns=["time", "depth", "dist", "lat", "lon", "data"]) mig1sta["depth"] = depths mig1sta["lat"] = lats mig1sta["lon"] = lons mig1sta["time"] = time tr.normalize() mig1sta["data"] = tr.data mig1sta["dist"] = dists # second interpolation to regular depth grid. after back-projection the depth sampling is irregular. # depth range 0-300 km with an interval of 0.5 km. delta = depth_range[2] d = np.arange(depth_range[0], depth_range[1]+delta, delta) tr.stats.delta = delta ftime = interp1d(depths, time) fdist = interp1d(depths, dists) flat = interp1d(depths, lats) flon = interp1d(depths, lons) fdata = interp1d(depths, tr.data) time = ftime(d) dists = fdist(d) lats = flat(d) lons = flon(d) tr.data = fdata(d) depths = np.copy(d) mig1sta = pd.DataFrame(columns=["time", "depth", "dist", "lat", "lon", "data"]) mig1sta["depth"] = depths mig1sta["lat"] = lats mig1sta["lon"] = lons mig1sta["time"] = time tr.normalize() mig1sta["data"] = tr.data mig1sta["dist"] = dists header = {"path": df2, "mig":mig1sta} tr.stats.update(header) return stream
def get_ray_paths(inventory, catalog, phase_list=['P'], coordinate_system='XYZ', taup_model='iasp91'): """ This function returns lat, lon, depth coordinates from an event location to all stations in the inventory object :param inventory: an obspy station inventory :param catalog: an obspy event catalog :param phase_list: a list of seismic phase names that is passed to taup :param coordinate_system: can be either 'XYZ' or 'RTP'. :param taup_model: the taup model for which the greatcircle paths are computed :returns: a list of tuples ``[(gcircle, phase_name, station_label, event_timestamp, event_magnitude, event_id, origin_id), ...]``. ``gcircle`` is an array of shape ``[3, npoints]`` with the path coordinates. ``phase_name`` is the name of the seismic phase, ``station_label`` is the name of the station and network that belongs to the path. ``event_timestamp``, ``event_magnitude``, ``event_id`` and ``origin_id`` describe the event that belongs to the path. """ # GEOGRAPHICLIB is mandatory for this function if not geodetics.HAS_GEOGRAPHICLIB: raise ImportError('Geographiclib not found but required by ray path ' 'routine') stlats = [] stlons = [] stlabels = [] for network in inventory: for station in network: label_ = ".".join((network.code, station.code)) if station.latitude is None or station.longitude is None: msg = ("Station '%s' does not have latitude/longitude " "information and will not be plotted." % label_) warnings.warn(msg) continue stlats.append(station.latitude) stlons.append(station.longitude) stlabels.append(label_) # make a big list of event coordinates and names # this part should be included as a subroutine of catalog that extracts # a list of event properties. E.g. catalog.extract(['latitiude', # 'longitude', 'depth', 'mag', 'focal_mechanism') The same should be done # for an inventory with stations evlats = [] evlons = [] evdepths = [] event_ids = [] origin_ids = [] magnitudes = [] times = [] for event in catalog: if not event.origins: msg = ("Event '%s' does not have an origin and will not be " "plotted." % str(event.resource_id)) warnings.warn(msg) continue if not event.magnitudes: msg = ("Event '%s' does not have a magnitude and will not be " "plotted." % str(event.resource_id)) warnings.warn(msg) continue origin = event.preferred_origin() or event.origins[0] evlats.append(origin.latitude) evlons.append(origin.longitude) if not origin.get('depth'): # XXX do we really want to include events without depth??? origin.depth = 0. evdepths.append(origin.get('depth') * 1e-3) magnitude = event.preferred_magnitude() or event.magnitudes[0] mag = magnitude.mag event_ids.append(str(event.resource_id)) origin_ids.append(str(origin.resource_id)) magnitudes.append(mag) times.append(origin.time.timestamp) # initialize taup model if it is not provided if isinstance(taup_model, str): from obspy.taup import TauPyModel model = TauPyModel(model=taup_model) else: model = taup_model # now loop through all stations and source combinations r_earth = model.model.radius_of_planet greatcircles = [] for stlat, stlon, stlabel in zip(stlats, stlons, stlabels): for evlat, evlon, evdepth_km, time, magnitude, event_id, origin_id \ in zip(evlats, evlons, evdepths, times, magnitudes, event_ids, origin_ids): arrivals = model.get_ray_paths_geo( evdepth_km, evlat, evlon, stlat, stlon, phase_list=phase_list, resample=True) if len(arrivals) == 0: continue for arr in arrivals: radii = (r_earth - arr.path['depth']) / r_earth thetas = np.radians(90. - arr.path['lat']) phis = np.radians(arr.path['lon']) if coordinate_system == 'RTP': gcircle = np.array([radii, thetas, phis]) if coordinate_system == 'XYZ': gcircle = np.array([radii * np.sin(thetas) * np.cos(phis), radii * np.sin(thetas) * np.sin(phis), radii * np.cos(thetas)]) greatcircles.append((gcircle, arr.name, stlabel, time, magnitude, event_id, origin_id)) return greatcircles