0
# Travel Time Calculations
1
2
Seismic ray theory calculations using multiple 1D Earth models for travel times, ray paths, and pierce points. Essential for earthquake location, phase identification, and tomographic studies using the TauP toolkit integrated into ObsPy.
3
4
## Capabilities
5
6
### TauPy Model Interface
7
8
Primary interface for travel time calculations using various Earth models with comprehensive phase support.
9
10
```python { .api }
11
# Import from obspy.taup
12
class TauPyModel:
13
def __init__(self, model: str = "iasp91", verbose: bool = False, **kwargs):
14
"""
15
Initialize TauP model for travel time calculations.
16
17
Args:
18
model: Earth model name
19
verbose: Enable verbose output
20
**kwargs: Additional model options
21
22
Available Models:
23
'1066a', '1066b', 'ak135', 'ak135f', 'ak135f_no_mud', 'herrin',
24
'iasp91', 'jb', 'prem', 'pwdk', 'sp6'
25
"""
26
27
def get_travel_times(self, source_depth_in_km: float, distance_in_degree: float = None,
28
distance_in_km: float = None, phase_list: list[str] = ['p', 's'],
29
receiver_depth_in_km: float = 0.0) -> list:
30
"""
31
Calculate seismic phase travel times.
32
33
Args:
34
source_depth_in_km: Earthquake depth in kilometers
35
distance_in_degree: Epicentral distance in degrees (or use distance_in_km)
36
distance_in_km: Epicentral distance in kilometers (or use distance_in_degree)
37
phase_list: List of seismic phases to calculate
38
receiver_depth_in_km: Receiver depth in kilometers (default: surface)
39
40
Returns:
41
List of Arrival objects with travel time information
42
43
Common Phases:
44
P, S - Direct body waves
45
PP, SS - Surface reflected waves
46
PcP, ScS - Core reflected waves
47
PKP, SKS - Core transmitted waves
48
Pdiff, Sdiff - Diffracted waves
49
PmP, SmS - Moho reflected waves
50
pP, sS - Depth phases
51
"""
52
53
def get_ray_paths(self, source_depth_in_km: float, distance_in_degree: float = None,
54
distance_in_km: float = None, phase_list: list[str] = ['p', 's'],
55
receiver_depth_in_km: float = 0.0) -> list:
56
"""
57
Calculate seismic ray paths through Earth model.
58
59
Args:
60
source_depth_in_km: Source depth in km
61
distance_in_degree: Distance in degrees (or use distance_in_km)
62
distance_in_km: Distance in km (or use distance_in_degree)
63
phase_list: Seismic phases to calculate
64
receiver_depth_in_km: Receiver depth in km
65
66
Returns:
67
List of RayPath objects with ray geometry information
68
"""
69
70
def get_pierce_points(self, source_depth_in_km: float, distance_in_degree: float = None,
71
distance_in_km: float = None, phase_list: list[str] = ['p', 's'],
72
receiver_depth_in_km: float = 0.0) -> list:
73
"""
74
Calculate ray pierce points at discontinuities.
75
76
Args:
77
source_depth_in_km: Source depth in km
78
distance_in_degree: Distance in degrees (or use distance_in_km)
79
distance_in_km: Distance in km (or use distance_in_degree)
80
phase_list: Seismic phases to calculate
81
receiver_depth_in_km: Receiver depth in km
82
83
Returns:
84
List of PiercePoint objects with pierce point information
85
"""
86
87
def get_travel_times_geo(self, source_latitude: float, source_longitude: float,
88
source_depth_in_km: float, receiver_latitude: float,
89
receiver_longitude: float, phase_list: list[str] = ['p', 's'],
90
receiver_depth_in_km: float = 0.0) -> list:
91
"""
92
Calculate travel times using geographic coordinates.
93
94
Args:
95
source_latitude: Event latitude in degrees
96
source_longitude: Event longitude in degrees
97
source_depth_in_km: Event depth in km
98
receiver_latitude: Station latitude in degrees
99
receiver_longitude: Station longitude in degrees
100
phase_list: Seismic phases to calculate
101
receiver_depth_in_km: Station elevation (negative for depth) in km
102
103
Returns:
104
List of Arrival objects with travel times and ray parameters
105
"""
106
107
def get_ray_paths_geo(self, source_latitude: float, source_longitude: float,
108
source_depth_in_km: float, receiver_latitude: float,
109
receiver_longitude: float, phase_list: list[str] = ['p', 's'],
110
receiver_depth_in_km: float = 0.0) -> list:
111
"""
112
Calculate ray paths using geographic coordinates.
113
114
Args:
115
source_latitude: Event latitude
116
source_longitude: Event longitude
117
source_depth_in_km: Event depth in km
118
receiver_latitude: Station latitude
119
receiver_longitude: Station longitude
120
phase_list: Seismic phases
121
receiver_depth_in_km: Station depth in km
122
123
Returns:
124
List of RayPath objects with geographic ray paths
125
"""
126
```
127
128
### Travel Time Plotting Functions
129
130
Visualization functions for travel time curves and ray path diagrams.
131
132
```python { .api }
133
def plot_travel_times(source_depth: float, ax=None, fig=None, phase_list: list[str] = None,
134
npoints: int = 100, model: str = 'iasp91', legend: bool = True,
135
**kwargs):
136
"""
137
Plot travel time curves for seismic phases.
138
139
Args:
140
source_depth: Source depth in km
141
ax: Matplotlib axes object (created if None)
142
fig: Matplotlib figure object (created if None)
143
phase_list: Phases to plot (common phases if None)
144
npoints: Number of distance points
145
model: Earth model to use
146
legend: Show phase legend
147
**kwargs: Additional plotting options
148
149
Returns:
150
Matplotlib figure and axes objects
151
"""
152
153
def plot_ray_paths(source_depth: float, distance: float, ax=None, fig=None,
154
phase_list: list[str] = None, model: str = 'iasp91',
155
legend: bool = True, **kwargs):
156
"""
157
Plot ray paths through Earth model.
158
159
Args:
160
source_depth: Source depth in km
161
distance: Epicentral distance in degrees
162
ax: Matplotlib axes object
163
fig: Matplotlib figure object
164
phase_list: Phases to plot
165
model: Earth model
166
legend: Show legend
167
**kwargs: Plotting options
168
169
Returns:
170
Figure and axes objects
171
"""
172
```
173
174
### Result Classes
175
176
Data structures containing travel time calculation results.
177
178
```python { .api }
179
class Arrival:
180
"""Travel time calculation result for single phase."""
181
182
@property
183
def name(self) -> str:
184
"""Phase name (e.g., 'P', 'S', 'PKP')."""
185
186
@property
187
def time(self) -> float:
188
"""Travel time in seconds."""
189
190
@property
191
def distance(self) -> float:
192
"""Epicentral distance in degrees."""
193
194
@property
195
def ray_param(self) -> float:
196
"""Ray parameter in s/degree."""
197
198
@property
199
def ray_param_sec_degree(self) -> float:
200
"""Ray parameter in s/degree."""
201
202
@property
203
def takeoff_angle(self) -> float:
204
"""Takeoff angle from source in degrees."""
205
206
@property
207
def incident_angle(self) -> float:
208
"""Incident angle at receiver in degrees."""
209
210
@property
211
def purist_distance(self) -> float:
212
"""Distance for which phase is pure."""
213
214
@property
215
def purist_name(self) -> str:
216
"""Purist phase name."""
217
218
class RayPath:
219
"""Ray path through Earth model."""
220
221
@property
222
def name(self) -> str:
223
"""Phase name."""
224
225
@property
226
def time(self) -> float:
227
"""Travel time in seconds."""
228
229
@property
230
def distance(self) -> float:
231
"""Distance in degrees."""
232
233
@property
234
def ray_param(self) -> float:
235
"""Ray parameter."""
236
237
@property
238
def path(self) -> dict:
239
"""Ray path coordinates.
240
241
Returns:
242
Dictionary with 'dist' and 'depth' arrays for plotting
243
"""
244
245
class PiercePoint:
246
"""Ray pierce point at discontinuity."""
247
248
@property
249
def name(self) -> str:
250
"""Phase name."""
251
252
@property
253
def time(self) -> float:
254
"""Time to pierce point."""
255
256
@property
257
def distance(self) -> float:
258
"""Distance to pierce point."""
259
260
@property
261
def depth(self) -> float:
262
"""Depth of pierce point."""
263
```
264
265
## Usage Examples
266
267
### Basic Travel Time Calculations
268
269
```python
270
from obspy.taup import TauPyModel
271
from obspy import UTCDateTime
272
273
# Initialize model
274
model = TauPyModel(model="iasp91")
275
276
# Calculate P and S arrival times
277
arrivals = model.get_travel_times(source_depth_in_km=10.0,
278
distance_in_degree=45.0,
279
phase_list=['P', 'S'])
280
281
print("Phase Arrivals:")
282
for arrival in arrivals:
283
print(f"{arrival.name}: {arrival.time:.2f} s")
284
print(f" Takeoff angle: {arrival.takeoff_angle:.1f}°")
285
print(f" Ray parameter: {arrival.ray_param:.3f} s/°")
286
287
# Calculate more phases including core phases
288
arrivals = model.get_travel_times(source_depth_in_km=150.0,
289
distance_in_degree=85.0,
290
phase_list=['P', 'S', 'PP', 'SS', 'PKP', 'SKS'])
291
292
print(f"\nTotal arrivals found: {len(arrivals)}")
293
```
294
295
### Earthquake Location Application
296
297
```python
298
from obspy.taup import TauPyModel
299
from obspy.geodetics import gps2dist_azimuth
300
from obspy import UTCDateTime
301
302
# Event and station information
303
event_lat, event_lon = 35.0, 140.0 # Japan
304
event_depth = 10.0 # km
305
origin_time = UTCDateTime("2023-01-15T10:30:00")
306
307
stations = [
308
("Tokyo", 35.7, 139.7),
309
("Osaka", 34.7, 135.5),
310
("Sendai", 38.3, 140.9)
311
]
312
313
model = TauPyModel(model="ak135")
314
315
print("Predicted P-wave arrivals:")
316
for station_name, sta_lat, sta_lon in stations:
317
# Calculate distance and azimuth
318
dist_m, az, baz = gps2dist_azimuth(event_lat, event_lon, sta_lat, sta_lon)
319
dist_deg = dist_m / 111319.9 # Convert to degrees
320
321
# Get P-wave travel time
322
arrivals = model.get_travel_times(source_depth_in_km=event_depth,
323
distance_in_degree=dist_deg,
324
phase_list=['P'])
325
326
if arrivals:
327
p_arrival = arrivals[0]
328
predicted_time = origin_time + p_arrival.time
329
print(f"{station_name}: {predicted_time} ({p_arrival.time:.2f} s)")
330
```
331
332
### Ray Path Analysis
333
334
```python
335
from obspy.taup import TauPyModel, plot_ray_paths
336
import matplotlib.pyplot as plt
337
338
model = TauPyModel(model="prem")
339
340
# Get ray paths for different phases
341
source_depth = 600.0 # Deep earthquake
342
distance = 75.0 # Teleseismic distance
343
344
ray_paths = model.get_ray_paths(source_depth_in_km=source_depth,
345
distance_in_degree=distance,
346
phase_list=['P', 'PP', 'PKP', 'PKIKP'])
347
348
print("Ray path information:")
349
for path in ray_paths:
350
print(f"{path.name}: {path.time:.2f} s, {path.ray_param:.3f} s/°")
351
352
# Get path coordinates
353
coords = path.path
354
max_depth = max(coords['depth'])
355
print(f" Maximum depth: {max_depth:.1f} km")
356
357
# Plot ray paths
358
plot_ray_paths(source_depth, distance,
359
phase_list=['P', 'PP', 'PKP', 'PKIKP'],
360
model='prem')
361
plt.title(f"Ray Paths: {source_depth} km depth, {distance}° distance")
362
plt.show()
363
```
364
365
### Travel Time Curves
366
367
```python
368
from obspy.taup import plot_travel_times
369
import matplotlib.pyplot as plt
370
371
# Plot travel time curves for shallow earthquake
372
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
373
374
# Shallow earthquake (crustal phases important)
375
plot_travel_times(source_depth=10.0, ax=ax1,
376
phase_list=['P', 'S', 'Pg', 'Sg', 'Pn', 'Sn'],
377
model='iasp91')
378
ax1.set_title("Shallow Earthquake (10 km depth)")
379
ax1.set_xlim(0, 30) # Regional distances
380
381
# Deep earthquake (core phases visible)
382
plot_travel_times(source_depth=600.0, ax=ax2,
383
phase_list=['P', 'S', 'PP', 'SS', 'PKP', 'SKS'],
384
model='iasp91')
385
ax2.set_title("Deep Earthquake (600 km depth)")
386
ax2.set_xlim(0, 180) # Global distances
387
388
plt.tight_layout()
389
plt.show()
390
```
391
392
### Pierce Point Analysis
393
394
```python
395
from obspy.taup import TauPyModel
396
397
model = TauPyModel(model="ak135")
398
399
# Get pierce points for P wave
400
pierce_points = model.get_pierce_points(source_depth_in_km=50.0,
401
distance_in_degree=60.0,
402
phase_list=['P'])
403
404
if pierce_points:
405
p_pierce = pierce_points[0]
406
print("P-wave pierce points:")
407
408
# Pierce points are stored in path attribute
409
for i, (dist, depth) in enumerate(zip(p_pierce.pierce['dist'],
410
p_pierce.pierce['depth'])):
411
print(f"Point {i}: {dist:.2f}° distance, {depth:.1f} km depth")
412
413
# Analyze core phase pierce points
414
pierce_points = model.get_pierce_points(source_depth_in_km=100.0,
415
distance_in_degree=120.0,
416
phase_list=['PKP'])
417
418
if pierce_points:
419
pkp_pierce = pierce_points[0]
420
print(f"\nPKP phase ({pkp_pierce.name}):")
421
print(f"Time: {pkp_pierce.time:.2f} s")
422
print(f"Ray parameter: {pkp_pierce.ray_param:.3f} s/°")
423
```
424
425
### Multi-Model Comparison
426
427
```python
428
from obspy.taup import TauPyModel
429
import matplotlib.pyplot as plt
430
import numpy as np
431
432
# Compare travel times between models
433
models = ['iasp91', 'ak135', 'prem']
434
source_depth = 100.0
435
distances = np.linspace(10, 90, 9)
436
437
fig, ax = plt.subplots(figsize=(10, 6))
438
439
for model_name in models:
440
model = TauPyModel(model=model_name)
441
p_times = []
442
443
for dist in distances:
444
arrivals = model.get_travel_times(source_depth_in_km=source_depth,
445
distance_in_degree=dist,
446
phase_list=['P'])
447
if arrivals:
448
p_times.append(arrivals[0].time)
449
else:
450
p_times.append(np.nan)
451
452
ax.plot(distances, p_times, 'o-', label=f'{model_name} P-wave')
453
454
ax.set_xlabel('Distance (degrees)')
455
ax.set_ylabel('Travel Time (seconds)')
456
ax.set_title(f'P-wave Travel Times - {source_depth} km depth')
457
ax.legend()
458
ax.grid(True, alpha=0.3)
459
plt.show()
460
461
# Print model differences
462
print("P-wave time differences at 45° distance:")
463
ref_model = TauPyModel(model='iasp91')
464
ref_time = ref_model.get_travel_times(100.0, 45.0, ['P'])[0].time
465
466
for model_name in ['ak135', 'prem']:
467
test_model = TauPyModel(model=model_name)
468
test_time = test_model.get_travel_times(100.0, 45.0, ['P'])[0].time
469
diff = test_time - ref_time
470
print(f"{model_name} vs iasp91: {diff:.2f} s")
471
```
472
473
## Types
474
475
```python { .api }
476
# Earth model information
477
ModelInfo = {
478
'name': str, # Model name
479
'description': str, # Model description
480
'min_radius': float, # Minimum radius (km)
481
'max_radius': float, # Maximum radius (km)
482
'discontinuities': list[float], # Major discontinuity depths
483
'phases': list[str] # Supported seismic phases
484
}
485
486
# Travel time result structure
487
TravelTimeResult = {
488
'phase': str, # Phase name
489
'time': float, # Travel time (s)
490
'distance': float, # Distance (degrees)
491
'ray_param': float, # Ray parameter (s/degree)
492
'takeoff_angle': float, # Takeoff angle (degrees)
493
'incident_angle': float, # Incident angle (degrees)
494
'purist_distance': float, # Purist distance (degrees)
495
'purist_name': str # Purist phase name
496
}
497
```