Added Obspy Methods

Obsplus adds methods to existing obspy data structures in order to “unify” the data-requesting interfaces (ie the get_whatever methods). This is done dynamically upon importing obsplus using a technique known as monkeypatching. You can then write source-agnostic code; any seismological data source, from in-memory obspy data structures, a directory of files, or a remote resource like IRIS can be treated the same way. If the data sources need to be changed it can be done seamlessly.

The following figure demonstrates this concept with waveform data. In-memory (Stream), on disk (WaveBank), or remote (Client) all share the get_waveforms method.

get_waveforms_diagram

[1]:
# get a catalog, stream, and inventory to play with
import obspy
import obsplus

cat = obspy.read_events()
st = obspy.read()
inv = obspy.read_inventory()

Catalog

[2]:
print(cat)
3 Event(s) in Catalog:
2012-04-04T14:21:42.300000Z | +41.818,  +79.689 | 4.4  mb | manual
2012-04-04T14:18:37.000000Z | +39.342,  +41.044 | 4.3  ML | manual
2012-04-04T14:08:46.000000Z | +38.017,  +37.736 | 3.0  ML | manual
[3]:
print(cat.get_events(minmagnitude=4))
2 Event(s) in Catalog:
2012-04-04T14:21:42.300000Z | +41.818,  +79.689 | 4.4  mb | manual
2012-04-04T14:18:37.000000Z | +39.342,  +41.044 | 4.3  ML | manual

Inventory

[4]:
print(inv)
Inventory created at 2014-03-03T11:07:06.198000Z
        Created by: fdsn-stationxml-converter/1.0.0
                    http://www.iris.edu/fdsnstationconverter
        Sending institution: Erdbebendienst Bayern
        Contains:
                Networks (2):
                        BW, GR
                Stations (5):
                        BW.RJOB (Jochberg, Bavaria, BW-Net) (3x)
                        GR.FUR (Fuerstenfeldbruck, Bavaria, GR-Net)
                        GR.WET (Wettzell, Bavaria, GR-Net)
                Channels (30):
                        BW.RJOB..EHZ (3x), BW.RJOB..EHN (3x), BW.RJOB..EHE (3x),
                        GR.FUR..BHZ, GR.FUR..BHN, GR.FUR..BHE, GR.FUR..HHZ, GR.FUR..HHN,
                        GR.FUR..HHE, GR.FUR..LHZ, GR.FUR..LHN, GR.FUR..LHE, GR.FUR..VHZ,
                        GR.FUR..VHN, GR.FUR..VHE, GR.WET..BHZ, GR.WET..BHN, GR.WET..BHE,
                        GR.WET..HHZ, GR.WET..HHN, GR.WET..HHE, GR.WET..LHZ, GR.WET..LHN,
                        GR.WET..LHE
[5]:
print(inv.get_stations(station='WET'))
Inventory created at 2014-03-03T11:07:06.198000Z
        Created by: fdsn-stationxml-converter/1.0.0
                    http://www.iris.edu/fdsnstationconverter
        Sending institution: Erdbebendienst Bayern
        Contains:
                Networks (1):
                        GR
                Stations (1):
                        GR.WET (Wettzell, Bavaria, GR-Net)
                Channels (9):
                        GR.WET..BHZ, GR.WET..BHN, GR.WET..BHE, GR.WET..HHZ, GR.WET..HHN,
                        GR.WET..HHE, GR.WET..LHZ, GR.WET..LHN, GR.WET..LHE

Stream

[6]:
print(st)
3 Trace(s) in Stream:
BW.RJOB..EHZ | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.990000Z | 100.0 Hz, 3000 samples
BW.RJOB..EHN | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.990000Z | 100.0 Hz, 3000 samples
BW.RJOB..EHE | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.990000Z | 100.0 Hz, 3000 samples
[7]:
t1 = st[0].stats.starttime + 10
print(st.get_waveforms('BW', 'RJOB', '*', 'EH[NEZ]', starttime=t1, endtime=t1 + 5))
3 Trace(s) in Stream:
BW.RJOB..EHZ | 2009-08-24T00:20:13.000000Z - 2009-08-24T00:20:18.000000Z | 100.0 Hz, 501 samples
BW.RJOB..EHN | 2009-08-24T00:20:13.000000Z - 2009-08-24T00:20:18.000000Z | 100.0 Hz, 501 samples
BW.RJOB..EHE | 2009-08-24T00:20:13.000000Z - 2009-08-24T00:20:18.000000Z | 100.0 Hz, 501 samples

Getting client_like objects

Obsplus has a few convenience functions for getting client-like objects (meaning they implement the appropriate get_whatever methods) from various sources. For example, the object returned after calling get_waveform_client is guaranteed to have a get_waveforms method or the function will raise a TypeError. The input could be a single miniseed file, a directory of waveforms files, a Stream object, or a valid waveform client.

For example:

[8]:
import tempfile
from pathlib import Path

from obspy.clients.fdsn import Client

from obsplus import get_waveform_client

cl = Client()
[9]:
# get waveform client from various sources
print(type(get_waveform_client(st)))
<class 'obspy.core.stream.Stream'>
[10]:
print(type(get_waveform_client(cl)))
<class 'obspy.clients.fdsn.client.Client'>
[11]:
# save a single file to disk
p = Path(tempfile.mkdtemp()) / 'stream.mseed'
p.parent.mkdir(exist_ok=True, parents=True)
st.write(str(p), 'mseed')
# get client from a single file
print(type(get_waveform_client(p)))
<class 'obspy.core.stream.Stream'>
[12]:
# create a directory of waveforms, get a client
p = Path(tempfile.mkdtemp())
p.mkdir(exist_ok=True, parents=True)
for num, tr in enumerate(st):
    tr.write(str(p / f'{num}.mseed'), 'mseed')
# get client from waveform directory
print(type(get_waveform_client(p)))
<class 'obsplus.bank.wavebank.WaveBank'>
[13]:
# A TypeErorr is raised if get_waveform_client cannot get a waveform_client
try:
    get_waveform_client(cat)
except TypeError as e:
    print(e)
a waveform client could not be extracted from 3 Event(s) in Catalog:
2012-04-04T14:21:42.300000Z | +41.818,  +79.689 | 4.4  mb | manual
2012-04-04T14:18:37.000000Z | +39.342,  +41.044 | 4.3  ML | manual
2012-04-04T14:08:46.000000Z | +38.017,  +37.736 | 3.0  ML | manual