1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

4# ---|P------/S----------~Lg---------- 

5 

6import logging 

7 

8from pyrocko import util 

9from pyrocko.util import urlopen 

10from pyrocko.io import quakeml 

11from .base_catalog import EarthquakeCatalog 

12 

13logger = logging.getLogger('pyrocko.client.isc') 

14 

15km = 1000. 

16 

17 

18class ISCError(Exception): 

19 pass 

20 

21 

22class ISCBlocked(ISCError): 

23 pass 

24 

25 

26class ISC(EarthquakeCatalog): 

27 ''' 

28 Interfacing the catalog of the Internation Seismological Centre (ISC). 

29 ''' 

30 

31 def __init__(self, catalog=None): 

32 self.events = {} 

33 

34 def flush(self): 

35 self.events = {} 

36 

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('-') 

44 

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) 

49 

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) 

54 

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 

66 

67 a('out_format=CATQuakeML') 

68 a('request=REVIEWED') 

69 a('searchshape=RECT') 

70 

71 self.append_time_params(a, time_range) 

72 

73 if magmin: 

74 a('min_mag=%g' % magmin) 

75 if magmax: 

76 a('max_mag=%g' % magmax) 

77 

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) 

83 

84 logger.debug('Opening URL: %s' % url) 

85 page = urlopen(url).read().decode() 

86 logger.debug('Received page (%i bytes)' % len(page)) 

87 

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: 

100 

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) 

108 

109 events = data.get_pyrocko_events() 

110 

111 for ev in events: 

112 self.events[ev.name] = ev 

113 

114 for ev in events: 

115 if time_range[0] <= ev.time and ev.time <= time_range[1]: 

116 yield ev.name 

117 

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)): 

123 

124 if name2 == name: 

125 break 

126 

127 return self.events[name] 

128 

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. 

133 

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 ''' 

140 

141 p = [] 

142 a = p.append 

143 

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)) 

151 

152 a('phaselist=%s' % ','.join(phases)) 

153 

154 self.append_time_params(a, time_range) 

155 

156 url = 'http://www.isc.ac.uk/cgi-bin/web-db-v4?' + '&'.join(p) 

157 

158 logger.debug('Opening URL: %s' % url) 

159 page = urlopen(url) 

160 page = page.read().decode() 

161 

162 if 'No stations were found.' in page: 

163 logger.info('No stations were found.') 

164 return [] 

165 

166 logger.debug('Received page (%i bytes)' % len(page)) 

167 

168 data = quakeml.QuakeML.load_xml(string=page) 

169 

170 markers = data.get_pyrocko_phase_markers() 

171 markers = self.replace_isc_codes(markers) 

172 

173 return markers 

174 

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 

183 

184 return markers 

185 

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