#d!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Provides the Inventory class.
:copyright:
Lion Krischer (krischer@geophysik.uni-muenchen.de), 2013
:license:
GNU Lesser General Public License, Version 3
(http://www.gnu.org/copyleft/lesser.html)
"""
from pkg_resources import load_entry_point
import obspy
from obspy.core.util.base import ComparingObject
from obspy.core.util import getExampleFile
from obspy.core.util.base import ENTRY_POINTS, _readFromPlugin
from obspy.station.stationxml import SOFTWARE_MODULE, SOFTWARE_URI
from obspy.station.network import Network
import textwrap
import warnings
from copy import deepcopy
[docs]def read_inventory(path_or_file_object, format=None):
"""
Function to read inventory files.
:param path_or_file_object: Filename or file like object.
"""
# if pathname starts with /path/to/ try to search in examples
if isinstance(path_or_file_object, basestring) and \
path_or_file_object.startswith('/path/to/'):
try:
path_or_file_object = getExampleFile(path_or_file_object[9:])
except:
# otherwise just try to read the given /path/to folder
pass
return _readFromPlugin("inventory", path_or_file_object, format=format)[0]
[docs]class Inventory(ComparingObject):
"""
The root object of the Inventory->Network->Station->Channel hierarchy.
In essence just a container for one or more networks.
"""
[docs] def __init__(self, networks, source, sender=None, created=None,
module=SOFTWARE_MODULE, module_uri=SOFTWARE_URI):
"""
:type networks: List of :class:`~obspy.station.network.Network`
:param networks: A list of networks part of this inventory.
:type source: String
:param source: Network ID of the institution sending the message.
:type sender: String
:param sender: Name of the institution sending this message. Optional.
:type created: :class:`~obspy.core.utcddatetime.UTCDateTime`
:param created: The time when the document was created. Will be set to
the current time if not given. Optional.
:type module: String
:param module: Name of the software module that generated this
document, defaults to ObsPy related information.
:type module_uri: String
:param module_uri: This is the address of the query that generated the
document, or, if applicable, the address of the software that
generated this document, defaults to ObsPy related information.
"""
self.networks = networks
self.source = source
self.sender = sender
self.module = module
self.module_uri = module_uri
# Set the created field to the current time if not given otherwise.
if created is None:
self.created = obspy.UTCDateTime()
else:
self.created = created
[docs] def __add__(self, other):
new = deepcopy(self)
if isinstance(other, Inventory):
new.networks.extend(other.networks)
elif isinstance(other, Network):
new.networks.append(other)
else:
msg = ("Only Inventory and Network objects can be added to "
"an Inventory.")
raise TypeError(msg)
return new
[docs] def __iadd__(self, other):
if isinstance(other, Inventory):
self.networks.extend(other.networks)
elif isinstance(other, Network):
self.networks.append(other)
else:
msg = ("Only Inventory and Network objects can be added to "
"an Inventory.")
raise TypeError(msg)
return self
[docs] def __getitem__(self, index):
return self.networks[index]
[docs] def get_contents(self):
"""
Returns a dictionary containing the contents of the object.
Example
>>> example_filename = "/path/to/IRIS_single_channel_with_response.xml"
>>> inventory = read_inventory(example_filename)
>>> inventory.get_contents() # doctest: +NORMALIZE_WHITESPACE
{'channels': ['IU.ANMO.10.BHZ'],
'networks': ['IU'],
'stations': [u'IU.ANMO (Albuquerque, New Mexico, USA)']}
"""
content_dict = {
"networks": [],
"stations": [],
"channels": []}
for network in self.networks:
content_dict['networks'].append(network.code)
for key, value in network.get_contents().iteritems():
content_dict.setdefault(key, [])
content_dict[key].extend(value)
content_dict[key].sort()
return content_dict
[docs] def __str__(self):
ret_str = "Inventory created at %s\n" % str(self.created)
if self.module:
module_uri = self.module_uri
if module_uri and len(module_uri) > 70:
module_uri = textwrap.wrap(module_uri, width=67)[0] + "..."
ret_str += ("\tCreated by: %s%s\n" % (
self.module,
"\n\t\t %s" % (module_uri if module_uri else "")))
ret_str += "\tSending institution: %s%s\n" % (
self.source, " (%s)" % self.sender if self.sender else "")
contents = self.get_contents()
ret_str += "\tContains:\n"
ret_str += "\t\tNetworks (%i):\n" % len(contents["networks"])
ret_str += "\n".join(["\t\t\t%s" % _i for _i in contents["networks"]])
ret_str += "\n"
ret_str += "\t\tStations (%i):\n" % len(contents["stations"])
ret_str += "\n".join(["\t\t\t%s" % _i for _i in contents["stations"]])
ret_str += "\n"
ret_str += "\t\tChannels (%i):\n" % len(contents["channels"])
ret_str += "\n".join(textwrap.wrap(
", ".join(contents["channels"]), initial_indent="\t\t\t",
subsequent_indent="\t\t\t", expand_tabs=False))
return ret_str
[docs] def write(self, path_or_file_object, format, **kwargs):
"""
Writes the inventory object to a file or file-like object in
the specified format.
:param path_or_file_object: Filename or file-like object to be written
to.
:param format: The format of the written file.
"""
format = format.upper()
try:
# get format specific entry point
format_ep = ENTRY_POINTS['inventory_write'][format]
# search writeFormat method for given entry point
writeFormat = load_entry_point(
format_ep.dist.key,
'obspy.plugin.inventory.%s' % (format_ep.name), 'writeFormat')
except (IndexError, ImportError, KeyError):
msg = "Writing format \"%s\" is not supported. Supported types: %s"
raise TypeError(msg % (format,
', '.join(ENTRY_POINTS['inventory_write'])))
return writeFormat(self, path_or_file_object, **kwargs)
@property
def networks(self):
return self._networks
@networks.setter
def networks(self, value):
if not hasattr(value, "__iter__"):
msg = "networks needs to be iterable, e.g. a list."
raise ValueError(msg)
if any([not isinstance(x, Network) for x in value]):
msg = "networks can only contain Network objects."
raise ValueError(msg)
self._networks = value
[docs] def get_response(self, seed_id, datetime):
"""
Find response for a given channel at given time.
>>> from obspy import read_inventory, UTCDateTime
>>> inventory = read_inventory("/path/to/BW_RJOB.xml")
>>> datetime = UTCDateTime("2009-08-24T00:20:00")
>>> response = inventory.get_response("BW.RJOB..EHZ", datetime)
>>> print response # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
Channel Response
From M/S (Velocity in Meters Per Second) to COUNTS (Digital Counts)
Overall Sensitivity: 2.5168e+09 defined at 0.020 Hz
4 stages:
Stage 1: PolesZerosResponseStage from M/S to V, gain: 1500.00
Stage 2: CoefficientsTypeResponseStage from V to COUNTS, ...
Stage 3: FIRResponseStage from COUNTS to COUNTS, gain: 1.00
Stage 4: FIRResponseStage from COUNTS to COUNTS, gain: 1.00
:type seed_id: str
:param seed_id: SEED ID string of channel to get response for.
:type datetime: :class:`~obspy.core.utcdatetime.UTCDateTime`
:param datetime: Time to get response for.
:rtype: :class:`~obspy.station.response.Response`
:returns: Response for timeseries specified by input arguments.
"""
network, station, location, channel = seed_id.split(".")
networks = [net for net in self.networks if net.code == network]
stations = [sta for sta in net.stations if sta.code == station
for net in networks]
channels = [cha for sta in stations for cha in sta.channels
if cha.code == channel
and cha.location_code == location
and (cha.start_date is None or cha.start_date <= datetime)
and (cha.end_date is None or cha.end_date >= datetime)]
responses = [cha.response for cha in channels
if cha.response is not None]
if len(responses) > 1:
msg = "Found more than one matching response. Returning first."
warnings.warn(msg)
elif len(responses) < 1:
msg = "No matching response information found."
raise Exception(msg)
return responses[0]
if __name__ == '__main__':
import doctest
doctest.testmod(exclude_empty=True)