#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Domain definitions for the download helpers.
Subclass the :class:`~obspy.clients.fdsn.mass_downloader.domain.Domain` class
to define custom and potentially more complex domains. See its documentation
for an example.
:copyright:
Lion Krischer (krischer@geophysik.uni-muenchen.de), 2014-2015
:license:
GNU Lesser General Public License, Version 3
(https://www.gnu.org/copyleft/lesser.html)
"""
from abc import ABCMeta, abstractmethod
[docs]class Domain(metaclass=ABCMeta):
"""
Abstract base class defining a domain - subclass it to define a new domain.
Each subclass must implement the :meth:`~.get_query_parameters`
method and optionally the :meth:`~.is_in_domain` method which enables
the construction of arbitrarily complex domains. The
:meth:`~.get_query_parameters` method must return the query parameters to
download as much data as required. The :meth:`~.is_in_domain` can later be
used to refine the domain after the data has been downloaded.
It can be thought of as a boolean operation - first the rough domain is
specified including all the possible points, then some points are
removed again. This is illustrated with an example domain representing
Germany utilizing the external packages
`shapely <http://toblerity.org/shapely/>`_ and
`fiona <http://toblerity.org/fiona/>`_. Shapefiles can be found online
on many websites, for example on
`http://www.gadm.org/ <http://www.gadm.org/>`_. The example works by
first extracting the bounds of the country to formulate the FDSN query
and then removing points outside of the exact shape.
.. code-block:: python
import fiona
import shapely.geometry
from obspy.clients.fdsn.mass_downloader import Domain
class Germany(Domain):
def __init__(self):
Domain.__init__(self)
fiona_collection = fiona.open("./DEU_adm/DEU_adm0.shp")
geometry = fiona_collection.next()["geometry"]
self.shape = shapely.geometry.asShape(geometry)
self.b = fiona_collection.bounds
def get_query_parameters(self):
return {"minlatitude": self.b[1],
"minlongitude": self.b[0],
"maxlatitude": self.b[3],
"maxlongitude": self.b[2]}
def is_in_domain(self, latitude, longitude):
if self.shape.contains(shapely.geometry.Point(longitude,
latitude)):
return True
return False
This is further illustrated by the following image. The green rectangle
denotes the original FDSN query which returns the blue points. In the
second step the red points are discarded leaving only points (stations)
within Germany.
.. figure:: /_images/expensive_plots/mass_downloader_domain.png
:align: center
"""
[docs] @abstractmethod
def get_query_parameters(self):
"""
Return the domain specific query parameters for the
:meth:`~obspy.clients.fdsn.client.Client.get_stations` method as a
dictionary. Possibilities keys for rectangular queries are
* ``minlatitude``
* ``maxlatitude``
* ``minlongitude``
* ``maxlongitude``
For circular queries:
* ``latitude``
* ``longitude``
* ``minradius``
* ``maxradius``
"""
pass
[docs] def is_in_domain(self, latitude, longitude):
"""
Returns True/False depending on the point being in the domain.
If not implemented no further restrictions will be applied after the
data has been downloaded.
"""
raise NotImplementedError
[docs]class RectangularDomain(Domain):
"""
A rectangular domain defined by latitude and longitude bounds.
>>> domain = RectangularDomain(minlatitude=30, maxlatitude=50,
... minlongitude=5, maxlongitude=35)
"""
[docs] def __init__(self, minlatitude, maxlatitude, minlongitude,
maxlongitude):
self.minlatitude = minlatitude
self.maxlatitude = maxlatitude
self.minlongitude = minlongitude
self.maxlongitude = maxlongitude
[docs] def get_query_parameters(self):
return {
"minlatitude": self.minlatitude,
"maxlatitude": self.maxlatitude,
"minlongitude": self.minlongitude,
"maxlongitude": self.maxlongitude}
[docs]class CircularDomain(Domain):
"""
A circular domain defined by a center point and minimum and maximum
radius from that point in degrees.
>>> domain = CircularDomain(latitude=37.52, longitude=143.04,
... minradius=70.0, maxradius=90.0)
"""
[docs] def __init__(self, latitude, longitude, minradius, maxradius):
self.latitude = latitude
self.longitude = longitude
self.minradius = minradius
self.maxradius = maxradius
[docs] def get_query_parameters(self):
return {
"latitude": self.latitude,
"longitude": self.longitude,
"minradius": self.minradius,
"maxradius": self.maxradius}
[docs]class GlobalDomain(Domain):
"""
Domain spanning the whole globe.
>>> domain = GlobalDomain()
"""
[docs] def get_query_parameters(self):
return {}
if __name__ == '__main__':
import doctest
doctest.testmod(exclude_empty=True)