1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
5from __future__ import absolute_import, division
7import logging
9from pyrocko import util
10from pyrocko.util import urlopen
11from pyrocko.io import quakeml
12from .base_catalog import EarthquakeCatalog
14logger = logging.getLogger('pyrocko.client.isc')
16km = 1000.
19class ISCError(Exception):
20 pass
23class ISCBlocked(ISCError):
24 pass
27class ISC(EarthquakeCatalog):
28 '''
29 Interfacing the catalog of the Internation Seismological Centre (ISC).
30 '''
32 def __init__(self, catalog=None):
33 self.events = {}
35 def flush(self):
36 self.events = {}
38 def append_time_params(self, a, time_range):
39 date_start_s, tstart_s = util.time_to_str(
40 time_range[0], format='%Y-%m-%d %H:%M:%S').split()
41 date_end_s, tend_s = util.time_to_str(
42 time_range[1], format='%Y-%m-%d %H:%M:%S').split()
43 date_start_s = date_start_s.split('-')
44 date_end_s = date_end_s.split('-')
46 a('start_year=%s' % date_start_s[0])
47 a('start_month=%s' % date_start_s[1])
48 a('start_day=%s' % date_start_s[2])
49 a('start_time=%s' % tstart_s)
51 a('end_year=%s' % date_end_s[0])
52 a('end_month=%s' % date_end_s[1])
53 a('end_day=%s' % date_end_s[2])
54 a('end_time=%s' % tend_s)
56 def iter_event_names(
57 self,
58 time_range=None,
59 magmin=None,
60 magmax=None,
61 latmin=-90.,
62 latmax=90.,
63 lonmin=-180.,
64 lonmax=180.):
65 p = []
66 a = p.append
68 a('out_format=CATQuakeML')
69 a('request=REVIEWED')
70 a('searchshape=RECT')
72 self.append_time_params(a, time_range)
74 if magmin:
75 a('min_mag=%g' % magmin)
76 if magmax:
77 a('max_mag=%g' % magmax)
79 a('bot_lat=%g' % latmin)
80 a('top_lat=%g' % latmax)
81 a('left_lon=%g' % lonmin)
82 a('right_lon=%g' % lonmax)
83 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p)
85 logger.debug('Opening URL: %s' % url)
86 page = urlopen(url).read().decode()
87 logger.debug('Received page (%i bytes)' % len(page))
89 if 'The search could not be run due to problems' in page:
90 logger.warning('%s\nurl: %s' % (page, url))
91 return
92 elif 'No events were found.' in page:
93 logger.info('No events were found.')
94 events = []
95 else:
96 try:
97 data = quakeml.QuakeML.load_xml(string=page)
98 except Exception:
99 if page[:500].contains(
100 'Please try again in a few minutes') != -1:
102 raise ISCBlocked(
103 'Apparently, we have queried ISC too eagerly:\n'
104 + '-' * 79 + '\n' + page + '\n' + '-' * 79)
105 else:
106 raise ISCError(
107 'Couldn\'t parse XML results from ISC:\n'
108 + '-' * 79 + '\n' + page + '\n' + '-' * 79)
110 events = data.get_pyrocko_events()
112 for ev in events:
113 self.events[ev.name] = ev
115 for ev in events:
116 if time_range[0] <= ev.time and ev.time <= time_range[1]:
117 yield ev.name
119 def get_event(self, name):
120 if name not in self.events:
121 t = self._name_to_date(name)
122 for name2 in self.iter_event_names(
123 time_range=(t-24*60*60, t+24*60*60)):
125 if name2 == name:
126 break
128 return self.events[name]
130 def get_phase_markers(self, time_range, station_codes, phases):
131 '''
132 Download phase picks from ISC catalog and return them as a list
133 of `pyrocko.gui.PhaseMarker` instances.
135 :param time_range: Tuple with (tmin tmax)
136 :param station_codes: List with ISC station codes
137 (see http://www.isc.ac.uk/cgi-bin/stations?lista).
138 If `station_codes` is 'global', query all ISC stations.
139 :param phases: List of seismic phases. (e.g. ['P', 'PcP']
140 '''
142 p = []
143 a = p.append
145 a('out_format=QuakeML')
146 a('request=STNARRIVALS')
147 if station_codes == 'global':
148 a('stnsearch=GLOBAL')
149 else:
150 a('stnsearch=STN')
151 a('sta_list=%s' % ','.join(station_codes))
153 a('phaselist=%s' % ','.join(phases))
155 self.append_time_params(a, time_range)
157 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p)
159 logger.debug('Opening URL: %s' % url)
160 page = urlopen(url)
161 page = page.read().decode()
163 if 'No stations were found.' in page:
164 logger.info('No stations were found.')
165 return []
167 logger.debug('Received page (%i bytes)' % len(page))
169 data = quakeml.QuakeML.load_xml(string=page)
171 markers = data.get_pyrocko_phase_markers()
172 markers = self.replace_isc_codes(markers)
174 return markers
176 def replace_isc_codes(self, markers):
177 for m in markers:
178 new_nslc_ids = []
179 for (n, s, l_, c) in m.get_nslc_ids():
180 l_ = l_.replace('--', '')
181 c = c.replace('???', '*')
182 new_nslc_ids.append((n, s, l_, c))
183 m.nslc_ids = new_nslc_ids
185 return markers
187 def _name_to_date(self, name):
188 ds = name[-23:]
189 t = util.str_to_time(ds, format='%Y-%m-%d_%H-%M-%S.3FRAC')
190 return t