Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/client/isc.py: 85%
110 statements
« prev ^ index » next coverage.py v6.5.0, created at 2024-10-02 07:18 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2024-10-02 07:18 +0000
1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6'''
7Client to get earthquake catalog information from
8`ISC <http://www.isc.ac.uk/>`_.
9'''
11import logging
12import re
14from pyrocko import util
15from pyrocko.util import urlopen
16from pyrocko.io import quakeml
17from .base_catalog import EarthquakeCatalog
19logger = logging.getLogger('pyrocko.client.isc')
21km = 1000.
24class ISCError(Exception):
25 pass
28class ISCBlocked(ISCError):
29 pass
32class ISC(EarthquakeCatalog):
33 '''
34 Interfacing the catalog of the Internation Seismological Centre (ISC).
35 '''
37 def __init__(self, catalog=None):
38 self.events = {}
40 def flush(self):
41 self.events = {}
43 def append_time_params(self, a, time_range):
44 date_start_s, tstart_s = util.time_to_str(
45 time_range[0], format='%Y-%m-%d %H:%M:%S').split()
46 date_end_s, tend_s = util.time_to_str(
47 time_range[1], format='%Y-%m-%d %H:%M:%S').split()
48 date_start_s = date_start_s.split('-')
49 date_end_s = date_end_s.split('-')
51 a('start_year=%s' % date_start_s[0])
52 a('start_month=%s' % date_start_s[1])
53 a('start_day=%s' % date_start_s[2])
54 a('start_time=%s' % tstart_s)
56 a('end_year=%s' % date_end_s[0])
57 a('end_month=%s' % date_end_s[1])
58 a('end_day=%s' % date_end_s[2])
59 a('end_time=%s' % tend_s)
61 def iter_event_names(
62 self,
63 time_range=None,
64 magmin=None,
65 magmax=None,
66 latmin=-90.,
67 latmax=90.,
68 lonmin=-180.,
69 lonmax=180.):
70 p = []
71 a = p.append
73 a('out_format=CATQuakeML')
74 a('request=REVIEWED')
75 a('searchshape=RECT')
77 self.append_time_params(a, time_range)
79 if magmin:
80 a('min_mag=%g' % magmin)
81 if magmax:
82 a('max_mag=%g' % magmax)
84 a('bot_lat=%g' % latmin)
85 a('top_lat=%g' % latmax)
86 a('left_lon=%g' % lonmin)
87 a('right_lon=%g' % lonmax)
88 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p)
90 logger.debug('Opening URL: %s' % url)
91 page = urlopen(url).read().decode()
92 logger.debug('Received page (%i bytes)' % len(page))
94 if 'The search could not be run due to problems' in page:
95 logger.warning('%s\nurl: %s' % (page, url))
96 return
97 elif 'No events were found.' in page:
98 logger.info('No events were found.')
99 events = []
100 else:
101 try:
102 data = quakeml.QuakeML.load_xml(string=page)
103 except Exception as e:
104 if page[:500].find(
105 'Please try again in a few minutes') != -1:
107 raise ISCBlocked(
108 'Apparently, we have queried ISC too eagerly:\n'
109 + '-' * 79 + '\n' + re.sub(r'<[^>]+>', ' ', page)
110 + '\n' + '-' * 79) from None
111 else:
112 raise ISCError(
113 "Couldn't parse XML results from ISC:\n"
114 + '-' * 79 + '\n' + re.sub(r'<[^>]+>', ' ', page)
115 + '\n' + '-' * 79) from e
117 events = data.get_pyrocko_events()
119 for ev in events:
120 self.events[ev.name] = ev
122 for ev in events:
123 if time_range[0] <= ev.time and ev.time <= time_range[1]:
124 yield ev.name
126 def get_event(self, name):
127 if name not in self.events:
128 t = self._name_to_date(name)
129 for name2 in self.iter_event_names(
130 time_range=(t-24*60*60, t+24*60*60)):
132 if name2 == name:
133 break
135 return self.events[name]
137 def get_phase_markers(self, time_range, station_codes, phases):
138 '''
139 Download phase picks from ISC catalog and return them as a list
140 of `pyrocko.gui.PhaseMarker` instances.
142 :param time_range: Tuple with (tmin tmax)
143 :param station_codes: List with ISC station codes
144 (see http://www.isc.ac.uk/cgi-bin/stations?lista).
145 If `station_codes` is 'global', query all ISC stations.
146 :param phases: List of seismic phases. (e.g. ['P', 'PcP']
147 '''
149 p = []
150 a = p.append
152 a('out_format=QuakeML')
153 a('request=STNARRIVALS')
154 if station_codes == 'global':
155 a('stnsearch=GLOBAL')
156 else:
157 a('stnsearch=STN')
158 a('sta_list=%s' % ','.join(station_codes))
160 a('phaselist=%s' % ','.join(phases))
162 self.append_time_params(a, time_range)
164 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p)
166 logger.debug('Opening URL: %s' % url)
167 page = urlopen(url)
168 page = page.read().decode()
170 if 'No stations were found.' in page:
171 logger.info('No stations were found.')
172 return []
174 logger.debug('Received page (%i bytes)' % len(page))
175 if -1 != page.find(
176 'Sorry, but your request cannot be processed at the present '
177 'time'):
178 raise ISCBlocked(
179 'Apparently, we have queried ISC too eagerly:\n'
180 + '-' * 79 + '\n' + re.sub(r'<[^>]+>', ' ', page)
181 + '\n' + '-' * 79)
183 data = quakeml.QuakeML.load_xml(string=page)
185 markers = data.get_pyrocko_phase_markers()
186 markers = self.replace_isc_codes(markers)
188 return markers
190 def replace_isc_codes(self, markers):
191 for m in markers:
192 new_nslc_ids = []
193 for (n, s, l_, c) in m.get_nslc_ids():
194 l_ = l_.replace('--', '')
195 c = c.replace('???', '*')
196 new_nslc_ids.append((n, s, l_, c))
197 m.nslc_ids = new_nslc_ids
199 return markers
201 def _name_to_date(self, name):
202 ds = name[-23:]
203 t = util.str_to_time(ds, format='%Y-%m-%d_%H-%M-%S.3FRAC')
204 return t