forked from HongjianFang/global_tomo_taup
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ray_paths.py
143 lines (126 loc) · 5.43 KB
/
ray_paths.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Calculations for 3D ray paths.
:author:
Matthias Meschede
:copyright:
The ObsPy Development Team ([email protected])
:license:
GNU Lesser General Public License, Version 3
(http://www.gnu.org/copyleft/lesser.html)
"""
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from future.builtins import * # NOQA @UnusedWildImport
import warnings
import numpy as np
import obspy.geodetics.base as geodetics
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
if __name__ == '__main__':
import doctest
doctest.testmod(exclude_empty=True)