# Source code for obspy.clients.fdsn.mass_downloader.domain

    #!/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 __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    from future.builtins import *  # NOQA
    from future.utils import with_metaclass

    from abc import ABCMeta, abstractmethod

    class Domain(with_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

        """
        @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

        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

    class RectangularDomain(Domain):
        """
        A rectangular domain defined by latitude and longitude bounds.

        >>> domain = RectangularDomain(minlatitude=30, maxlatitude=50,
        ...                            minlongitude=5, maxlongitude=35)

        """
        def __init__(self, minlatitude, maxlatitude, minlongitude,
                     maxlongitude):
            self.minlatitude = minlatitude
            self.maxlatitude = maxlatitude
            self.minlongitude = minlongitude
            self.maxlongitude = maxlongitude

        def get_query_parameters(self):
            return {
                "minlatitude": self.minlatitude,
                "maxlatitude": self.maxlatitude,
                "minlongitude": self.minlongitude,
                "maxlongitude": self.maxlongitude}

    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)

        """
        def __init__(self, latitude, longitude, minradius, maxradius):
            self.latitude = latitude
            self.longitude = longitude
            self.minradius = minradius
            self.maxradius = maxradius

        def get_query_parameters(self):
            return {
                "latitude": self.latitude,
                "longitude": self.longitude,
                "minradius": self.minradius,
                "maxradius": self.maxradius}

    class GlobalDomain(Domain):
        """
        Domain spanning the whole globe.

        >>> domain = GlobalDomain()
        """
        def get_query_parameters(self):
            return {}

    if __name__ == '__main__':
        import doctest
        doctest.testmod(exclude_empty=True)

### Thank you!

We would like to thank our contributors, whose efforts make this software what it is. These people have helped by writing code and documentation, and by testing. They have created and maintained this product, its associated libraries and applications, our build tools and our web sites.

#### Contributors

- Ackerley, Nick
- Allgeyer, Sebastien
- Ammon, Charles J.
- Antunes, Emanuel
- Arnarsson, Ólafur St.
- Bank, Markus
- Barsch, Robert
- Behr, Yannik
- Bernardi, Fabrizio
- Bernauer, Felix
- Bes de Berc, Maxime
- Beyreuther, Moritz
- Boltz, Shawn
- Bonaimé, Sébastien
- Carothers, Lloyd
- Chamberlain, Calum
- Chambers, Derrick
- Chen, Zhao
- Clark, Adam
- Danecek, Peter
- Egdorf, Sven
- Engels, Fabian
- Ermert, Laura
- Eulenfeld, Tom

- Fabbri, Tommaso
- Falco, Nicholas
- Fee, Jeremy
- Grellier, Clément
- Grunberg, Marc
- Hammer, Conny
- Heimann, Sebastian
- Heiniger, Lukas
- Hope, Gaute
- Igel, Heiner
- Inza, Adolfo
- Isken, Marius
- Ketchum, David
- Koymans, Mathijs
- Kremers, Simon
- Kress, Victor
- Krieger, Lars
- Krischer, Lion
- Kula, Damian
- Käufl, Paul
- Köhler, Andreas
- Lecocq, Thomas
- Leeman, John
- Legovini, Paride

- Lesage, Philippe
- Li, Yulin
- Lomax, Anthony
- Lopes, Rui L.
- MacCarthy, Jonathan
- Maggi, Alessia
- Martin, Henri
- Medlin, Andrew
- Megies, Tobias
- Meschede, Matthias
- Michelini, Alberto
- Miller, Nathaniel C.
- Morgenstern, Bernhard
- Nof, Ran Novitsky
- Panning, Mark P.
- Parker, Tom
- Pestourie, Romain
- Rapagnani, Giovanni
- Reyes, Celso
- Ringler, Adam
- Rothenhäusler, Nicolas
- Russo, Emiliano
- Sales de Andrade, Elliott

- Satriano, Claudio
- Saul, Joachim
- Scheingraber, Chris
- Schneider, Simon
- Sippl, Christian
- Snoke, Arthur
- Stange, Stefan
- Stähler, Simon C.
- Sullivan, Benjamin
- Tian, Dongdong
- Trabant, Chad
- Trani, Luca
- Uieda, Leonardo
- Walker, Andrew
- Walther, Marcus
- Wassermann, Joachim
- Williams, Mark C.
- Winkelman, Andrew
- Zaccarelli, Riccardo
- Zad, Seyed Kasra Hosseini
- Zhu, Lijun
- van Driel, Martin
- van Wijk, Kasper

#### Funds

ObsPy was partially funded by the

- German Science Foundation (DFG) via grant DFG IG 16/9-1
- German Ministry for Education and Research (BMBF), GEOTECHNOLOGIEN grant 03G0646H.
- NERA project (Network of European Research Infrastructures for Earthquake Risk Assessment and Mitigation) under the European Community's Seventh Framework Programme (FP7/2007-2013) grant agreement n° 262330
- Leibniz Institute for Applied Geophysics (LIAG)
- VERCE EU-FP7 project (no. 283543)