1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6import logging
8from pyrocko import util
9from pyrocko.util import urlopen
10from pyrocko.io import quakeml
11from .base_catalog import EarthquakeCatalog
13logger = logging.getLogger('pyrocko.client.isc')
15km = 1000.
18class ISCError(Exception):
19 pass
22class ISCBlocked(ISCError):
23 pass
26class ISC(EarthquakeCatalog):
27 '''
28 Interfacing the catalog of the Internation Seismological Centre (ISC).
29 '''
31 def __init__(self, catalog=None):
32 self.events = {}
34 def flush(self):
35 self.events = {}
37 def append_time_params(self, a, time_range):
38 date_start_s, tstart_s = util.time_to_str(
39 time_range[0], format='%Y-%m-%d %H:%M:%S').split()
40 date_end_s, tend_s = util.time_to_str(
41 time_range[1], format='%Y-%m-%d %H:%M:%S').split()
42 date_start_s = date_start_s.split('-')
43 date_end_s = date_end_s.split('-')
45 a('start_year=%s' % date_start_s[0])
46 a('start_month=%s' % date_start_s[1])
47 a('start_day=%s' % date_start_s[2])
48 a('start_time=%s' % tstart_s)
50 a('end_year=%s' % date_end_s[0])
51 a('end_month=%s' % date_end_s[1])
52 a('end_day=%s' % date_end_s[2])
53 a('end_time=%s' % tend_s)
55 def iter_event_names(
56 self,
57 time_range=None,
58 magmin=None,
59 magmax=None,
60 latmin=-90.,
61 latmax=90.,
62 lonmin=-180.,
63 lonmax=180.):
64 p = []
65 a = p.append
67 a('out_format=CATQuakeML')
68 a('request=REVIEWED')
69 a('searchshape=RECT')
71 self.append_time_params(a, time_range)
73 if magmin:
74 a('min_mag=%g' % magmin)
75 if magmax:
76 a('max_mag=%g' % magmax)
78 a('bot_lat=%g' % latmin)
79 a('top_lat=%g' % latmax)
80 a('left_lon=%g' % lonmin)
81 a('right_lon=%g' % lonmax)
82 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p)
84 logger.debug('Opening URL: %s' % url)
85 page = urlopen(url).read().decode()
86 logger.debug('Received page (%i bytes)' % len(page))
88 if 'The search could not be run due to problems' in page:
89 logger.warning('%s\nurl: %s' % (page, url))
90 return
91 elif 'No events were found.' in page:
92 logger.info('No events were found.')
93 events = []
94 else:
95 try:
96 data = quakeml.QuakeML.load_xml(string=page)
97 except Exception:
98 if page[:500].find(
99 'Please try again in a few minutes') != -1:
101 raise ISCBlocked(
102 'Apparently, we have queried ISC too eagerly:\n'
103 + '-' * 79 + '\n' + page + '\n' + '-' * 79)
104 else:
105 raise ISCError(
106 "Couldn't parse XML results from ISC:\n"
107 + '-' * 79 + '\n' + page + '\n' + '-' * 79)
109 events = data.get_pyrocko_events()
111 for ev in events:
112 self.events[ev.name] = ev
114 for ev in events:
115 if time_range[0] <= ev.time and ev.time <= time_range[1]:
116 yield ev.name
118 def get_event(self, name):
119 if name not in self.events:
120 t = self._name_to_date(name)
121 for name2 in self.iter_event_names(
122 time_range=(t-24*60*60, t+24*60*60)):
124 if name2 == name:
125 break
127 return self.events[name]
129 def get_phase_markers(self, time_range, station_codes, phases):
130 '''
131 Download phase picks from ISC catalog and return them as a list
132 of `pyrocko.gui.PhaseMarker` instances.
134 :param time_range: Tuple with (tmin tmax)
135 :param station_codes: List with ISC station codes
136 (see http://www.isc.ac.uk/cgi-bin/stations?lista).
137 If `station_codes` is 'global', query all ISC stations.
138 :param phases: List of seismic phases. (e.g. ['P', 'PcP']
139 '''
141 p = []
142 a = p.append
144 a('out_format=QuakeML')
145 a('request=STNARRIVALS')
146 if station_codes == 'global':
147 a('stnsearch=GLOBAL')
148 else:
149 a('stnsearch=STN')
150 a('sta_list=%s' % ','.join(station_codes))
152 a('phaselist=%s' % ','.join(phases))
154 self.append_time_params(a, time_range)
156 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p)
158 logger.debug('Opening URL: %s' % url)
159 page = urlopen(url)
160 page = page.read().decode()
162 if 'No stations were found.' in page:
163 logger.info('No stations were found.')
164 return []
166 logger.debug('Received page (%i bytes)' % len(page))
168 data = quakeml.QuakeML.load_xml(string=page)
170 markers = data.get_pyrocko_phase_markers()
171 markers = self.replace_isc_codes(markers)
173 return markers
175 def replace_isc_codes(self, markers):
176 for m in markers:
177 new_nslc_ids = []
178 for (n, s, l_, c) in m.get_nslc_ids():
179 l_ = l_.replace('--', '')
180 c = c.replace('???', '*')
181 new_nslc_ids.append((n, s, l_, c))
182 m.nslc_ids = new_nslc_ids
184 return markers
186 def _name_to_date(self, name):
187 ds = name[-23:]
188 t = util.str_to_time(ds, format='%Y-%m-%d_%H-%M-%S.3FRAC')
189 return t