ObsPy Tutorial
Downloading/Processing Exercise
</div> </div> </div> image: User:Abbaszade656 / Wikimedia Commons / CC-BY-SA-4.0

Workshop for the "Training in Network Management Systems and Analytical Tools for Seismic"

Baku, October 2018

Seismo-Live: http://seismo-live.org

Authors:

For the this exercise we will download some data from the Tohoku-Oki earthquake, cut out a certain time window around the first arrival and remove the instrument response from the data.

In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = 12, 8

The first step is to download all the necessary information using the ObsPy FDSN client. Learn to read the documentation!

We need the following things:

  1. Event information about the 2014 South Napa earthquake. Use the get_events() method of the client. A good provider of event data is the USGS.
  2. Waveform information for a certain station. Choose your favorite one! If you have no preference, use II.PFO which is available for example from IRIS. Use the get_waveforms() method.
  3. Download the associated station/instrument information with the get_stations() method.
In [2]:
import obspy
from obspy.clients.fdsn import Client

c_event = Client("USGS")

# Event time.
event_time = obspy.UTCDateTime("2014-08-24T10:20:44.0")

# Get the event information. The temporal and magnitude constraints make it unique
cat = c_event.get_events(starttime=event_time - 10, endtime=event_time + 10,
                         minmagnitude=6)
print(cat)

c = Client("IRIS")
# Download station information at the response level!
inv = c.get_stations(network="II", station="PFO", location="00", channel="BHZ",
                     starttime=event_time - 10 * 60, endtime=event_time + 30 * 60,
                     level="response")
print(inv)

# Download 3 component waveforms.
st = c.get_waveforms(network="II", station="PFO", location="00",
                     channel="BHZ", starttime=event_time - 10 * 60,
                     endtime=event_time + 30 * 60)
print(st)
1 Event(s) in Catalog:
2014-08-24T10:20:44.070000Z | +38.215, -122.312 | 6.02 mw | manual
Inventory created at 2019-11-04T08:59:10.000000Z
	Created by: IRIS WEB SERVICE: fdsnws-station | version: 1.1.37
		    http://service.iris.edu/fdsnws/station/1/query?starttime=2014-08-24...
	Sending institution: IRIS-DMC (IRIS-DMC)
	Contains:
		Networks (1):
			II
		Stations (1):
			II.PFO (Pinon Flat, California, USA)
		Channels (1):
			II.PFO.00.BHZ
1 Trace(s) in Stream:
II.PFO.00.BHZ | 2014-08-24T10:10:44.019500Z - 2014-08-24T10:50:43.969500Z | 20.0 Hz, 48000 samples

Have a look at the just downloaded data.

In [3]:
inv.plot()
inv.plot_response(0.001)
cat.plot()
st.plot()
/Users/lion/miniconda3/envs/seismo_live/lib/python3.7/site-packages/obspy/imaging/maps.py:45: UserWarning: basemap/pyproj with proj4 version >= 5 has a bug that results in inverted map axes. Your maps may be wrong. Please use another version of proj4, or use cartopy.
  warnings.warn(msg)
Out[3]:

Exercise

The goal of this exercise is to cut the data from 1 minute before the first arrival to 5 minutes after it, and then remove the instrument response.

Step 1: Determine Coordinates of Station

In [4]:
coords = inv.get_coordinates("II.PFO.00.BHZ")
coords
Out[4]:
{'latitude': 33.610699,
 'longitude': -116.455498,
 'elevation': 1280.0,
 'local_depth': 5.3}

Step 2: Determine Coordinates of Event

In [5]:
origin = cat[0].origins[0]
print(origin)
Origin
	        resource_id: ResourceIdentifier(id="quakeml:earthquake.usgs.gov/archive/product/origin/nc72282711/nc/1503942901517/product.xml")
	               time: UTCDateTime(2014, 8, 24, 10, 20, 44, 70000)
	          longitude: -122.3123333
	           latitude: 38.2151667
	              depth: 11120.0 [uncertainty=150.0]
	            quality: OriginQuality(used_phase_count=400, used_station_count=369, standard_error=0.18, azimuthal_gap=28.0, minimum_distance=0.03604)
	 origin_uncertainty: OriginUncertainty(horizontal_uncertainty=110.0, preferred_description='horizontal uncertainty')
	    evaluation_mode: 'manual'
	      creation_info: CreationInfo(agency_id='NC', creation_time=UTCDateTime(2017, 8, 28, 17, 55, 1, 517000), version='28')

Step 3: Calculate distance of event and station.

Use obspy.geodetics.locations2degree.

In [6]:
from obspy.geodetics import locations2degrees

distance = locations2degrees(origin.latitude, origin.longitude,
                             coords["latitude"], coords["longitude"])
print(distance)
6.60787717357

Step 4: Calculate Theoretical Arrivals

from obspy.taup import TauPyModel
m = TauPyModel(model="ak135")
arrivals = m.get_ray_paths(...)
arrivals.plot()
In [7]:
from obspy.taup import TauPyModel

m = TauPyModel(model="ak135")

arrivals = m.get_ray_paths(
    distance_in_degree=distance,
    source_depth_in_km=origin.depth / 1000.0)

arrivals.plot();
/Users/lion/miniconda3/envs/seismo_live/lib/python3.7/site-packages/obspy/taup/tau_branch.py:496: UserWarning: Resizing a TauP array inplace failed due to the existence of other references to the array, creating a new array. See Obspy #2280.
  warnings.warn(msg)
/Users/lion/miniconda3/envs/seismo_live/lib/python3.7/site-packages/ipykernel_launcher.py:9: ObsPyDeprecationWarning: The plot() function is deprecated. Please use arrivals.plot_rays()
  if __name__ == '__main__':

Step 5: Calculate absolute time of the first arrivals at the station

In [8]:
first_arrival = origin.time + arrivals[0].time

print(first_arrival)
2014-08-24T10:22:21.096374Z

Step 6: Cut to 1 minute before and 5 minutes after the first arrival

In [9]:
st.trim(first_arrival - 60, first_arrival + 300)
st.plot();

Step 7: Remove the instrument response

st.remove_response(inventory=inv, pre_filt=...)

taper

In [10]:
st.remove_response(inventory=inv,
                   pre_filt=(1.0 / 100.0, 1.0 / 50.0, 10.0, 20.0),
                   output="VEL")
st.plot()
Out[10]:

Bonus: Interactive IPython widgets

In [11]:
from ipywidgets import interact
from obspy.taup import TauPyModel

m = TauPyModel("ak135")

def plot_raypaths(distance, depth, wavetype):
    try:
        plt.close()
    except:
        pass
    if wavetype == "ttall":
        phases = ["ttall"]
    elif wavetype == "diff":
        phases = ["Pdiff", "pPdiff"]
    m.get_ray_paths(distance_in_degree=distance,
                    source_depth_in_km=depth,
                    phase_list=phases).plot();

interact(plot_raypaths, distance=(1, 180),
         depth=(0, 700), wavetype=["ttall", "diff"]);
/Users/lion/miniconda3/envs/seismo_live/lib/python3.7/site-packages/obspy/taup/tau_branch.py:496: UserWarning: Resizing a TauP array inplace failed due to the existence of other references to the array, creating a new array. See Obspy #2280.
  warnings.warn(msg)
/Users/lion/miniconda3/envs/seismo_live/lib/python3.7/site-packages/ipykernel_launcher.py:17: ObsPyDeprecationWarning: The plot() function is deprecated. Please use arrivals.plot_rays()