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 ISC(EarthquakeCatalog):
24 '''
25 Interfacing the catalog of the Internation Seismological Centre (ISC).
26 '''
28 def __init__(self, catalog=None):
29 self.events = {}
31 def flush(self):
32 self.events = {}
34 def append_time_params(self, a, time_range):
35 date_start_s, tstart_s = util.time_to_str(
36 time_range[0], format='%Y-%m-%d %H:%M:%S').split()
37 date_end_s, tend_s = util.time_to_str(
38 time_range[1], format='%Y-%m-%d %H:%M:%S').split()
39 date_start_s = date_start_s.split('-')
40 date_end_s = date_end_s.split('-')
42 a('start_year=%s' % date_start_s[0])
43 a('start_month=%s' % date_start_s[1])
44 a('start_day=%s' % date_start_s[2])
45 a('start_time=%s' % tstart_s)
47 a('end_year=%s' % date_end_s[0])
48 a('end_month=%s' % date_end_s[1])
49 a('end_day=%s' % date_end_s[2])
50 a('end_time=%s' % tend_s)
52 def iter_event_names(
53 self,
54 time_range=None,
55 magmin=None,
56 magmax=None,
57 latmin=-90.,
58 latmax=90.,
59 lonmin=-180.,
60 lonmax=180.):
61 p = []
62 a = p.append
64 a('out_format=CATQuakeML')
65 a('request=REVIEWED')
66 a('searchshape=RECT')
68 self.append_time_params(a, time_range)
70 if magmin:
71 a('min_mag=%g' % magmin)
72 if magmax:
73 a('max_mag=%g' % magmax)
75 a('bot_lat=%g' % latmin)
76 a('top_lat=%g' % latmax)
77 a('left_lon=%g' % lonmin)
78 a('right_lon=%g' % lonmax)
79 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p)
81 logger.debug('Opening URL: %s' % url)
82 page = urlopen(url).read().decode()
83 logger.debug('Received page (%i bytes)' % len(page))
85 if 'The search could not be run due to problems' in page:
86 logger.warning('%s\nurl: %s' % (page, url))
87 return
88 elif 'No events were found.' in page:
89 logger.info('No events were found.')
90 events = []
91 else:
92 try:
93 data = quakeml.QuakeML.load_xml(string=page)
94 except Exception:
95 raise ISCError(
96 'Couldn\'t parse XML results from ISC:\n'
97 + '-' * 79 + '\n' + page + '\n' + '-' * 79)
99 events = data.get_pyrocko_events()
101 for ev in events:
102 self.events[ev.name] = ev
104 for ev in events:
105 if time_range[0] <= ev.time and ev.time <= time_range[1]:
106 yield ev.name
108 def get_event(self, name):
109 if name not in self.events:
110 t = self._name_to_date(name)
111 for name2 in self.iter_event_names(
112 time_range=(t-24*60*60, t+24*60*60)):
114 if name2 == name:
115 break
117 return self.events[name]
119 def get_phase_markers(self, time_range, station_codes, phases):
120 '''
121 Download phase picks from ISC catalog and return them as a list
122 of `pyrocko.gui.PhaseMarker` instances.
124 :param time_range: Tuple with (tmin tmax)
125 :param station_codes: List with ISC station codes
126 (see http://www.isc.ac.uk/cgi-bin/stations?lista).
127 If `station_codes` is 'global', query all ISC stations.
128 :param phases: List of seismic phases. (e.g. ['P', 'PcP']
129 '''
131 p = []
132 a = p.append
134 a('out_format=QuakeML')
135 a('request=STNARRIVALS')
136 if station_codes == 'global':
137 a('stnsearch=GLOBAL')
138 else:
139 a('stnsearch=STN')
140 a('sta_list=%s' % ','.join(station_codes))
142 a('phaselist=%s' % ','.join(phases))
144 self.append_time_params(a, time_range)
146 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p)
148 logger.debug('Opening URL: %s' % url)
149 page = urlopen(url)
150 page = page.read().decode()
152 if 'No stations were found.' in page:
153 logger.info('No stations were found.')
154 return []
156 logger.debug('Received page (%i bytes)' % len(page))
158 data = quakeml.QuakeML.load_xml(string=page)
160 markers = data.get_pyrocko_phase_markers()
161 markers = self.replace_isc_codes(markers)
163 return markers
165 def replace_isc_codes(self, markers):
166 for m in markers:
167 new_nslc_ids = []
168 for (n, s, l_, c) in m.get_nslc_ids():
169 l_ = l_.replace('--', '')
170 c = c.replace('???', '*')
171 new_nslc_ids.append((n, s, l_, c))
172 m.nslc_ids = new_nslc_ids
174 return markers
176 def _name_to_date(self, name):
177 ds = name[-23:]
178 t = util.str_to_time(ds, format='%Y-%m-%d_%H-%M-%S.3FRAC')
179 return t