1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6from __future__ import absolute_import, print_function 

7 

8import logging 

9from builtins import str as newstr 

10 

11from pyrocko.io.io_common import get_stats, touch # noqa 

12from ... import model 

13 

14logger = logging.getLogger('psq.io.textfiles') 

15 

16 

17def provided_formats(): 

18 return ['pyrocko_stations', 'pyrocko_events'] 

19 

20 

21def detect_pyrocko_stations(first512): 

22 try: 

23 first512 = first512.decode('utf-8') 

24 except UnicodeDecodeError: 

25 return False 

26 

27 for line in first512.splitlines(): 

28 t = line.split(None, 5) 

29 if len(t) in (5, 6): 

30 if len(t[0].split('.')) != 3: 

31 return False 

32 

33 try: 

34 lat, lon, ele, dep = map(float, t[1:5]) 

35 if lat < -90. or 90 < lat: 

36 return False 

37 if lon < -180. or 180 < lon: 

38 return False 

39 

40 return True 

41 

42 except Exception: 

43 raise 

44 return False 

45 

46 return False 

47 

48 

49g_event_keys = set(''' 

50name region catalog magnitude_type latitude longitude magnitude depth duration 

51north_shift east_shift mnn mee mdd mne mnd med strike1 dip1 rake1 strike2 dip2 

52rake2 duration time tags moment 

53'''.split()) 

54 

55 

56def detect_pyrocko_events(first512): 

57 try: 

58 first512 = first512.decode('utf-8') 

59 except UnicodeDecodeError: 

60 return False 

61 

62 lines = first512.splitlines()[:-1] 

63 ok = 0 

64 for line in lines: 

65 line = line.strip() 

66 if not line or line.startswith('#'): 

67 continue 

68 

69 t = line.split(' = ', 1) 

70 if len(t) == 2: 

71 if t[0].strip() in g_event_keys: 

72 ok += 1 

73 continue 

74 else: 

75 return False 

76 

77 if line.startswith('---'): 

78 ok += 1 

79 continue 

80 

81 return False 

82 

83 return ok > 2 

84 

85 

86def detect(first512): 

87 if detect_pyrocko_stations(first512): 

88 return 'pyrocko_stations' 

89 

90 elif detect_pyrocko_events(first512): 

91 return 'pyrocko_events' 

92 

93 return None 

94 

95 

96def float_or_none(s): 

97 if s.lower() == 'nan': 

98 return None 

99 else: 

100 return float(s) 

101 

102 

103def iload(format, file_path, segment, content): 

104 if format == 'pyrocko_stations': 

105 return iload_pyrocko_stations(file_path, segment, content) 

106 

107 if format == 'pyrocko_events': 

108 return iload_pyrocko_events(file_path, segment, content) 

109 

110 

111def iload_pyrocko_stations(file_path, segment, content): 

112 

113 inut = 0 

114 tmin = None 

115 tmax = None 

116 with open(file_path, 'r') as f: 

117 

118 have_station = False 

119 for (iline, line) in enumerate(f): 

120 try: 

121 toks = line.split(None, 5) 

122 if len(toks) == 5 or len(toks) == 6: 

123 net, sta, loc = toks[0].split('.') 

124 lat, lon, elevation, depth = [float(x) for x in toks[1:5]] 

125 if len(toks) == 5: 

126 description = u'' 

127 else: 

128 description = newstr(toks[5]) 

129 

130 agn = '' 

131 

132 nut = model.make_station_nut( 

133 file_segment=0, 

134 file_element=inut, 

135 agency=agn, 

136 network=net, 

137 station=sta, 

138 location=loc, 

139 tmin=tmin, 

140 tmax=tmax) 

141 

142 if 'station' in content: 

143 nut.content = model.Station( 

144 lat=lat, 

145 lon=lon, 

146 elevation=elevation, 

147 depth=depth, 

148 description=description, 

149 **nut.station_kwargs) 

150 

151 yield nut 

152 inut += 1 

153 

154 have_station = True 

155 

156 elif len(toks) == 4 and have_station: 

157 cha = toks[0] 

158 azi = float_or_none(toks[1]) 

159 dip = float_or_none(toks[2]) 

160 gain = float(toks[3]) 

161 

162 if gain != 1.0: 

163 logger.warning( 

164 '%s.%s.%s.%s gain value from stations ' 

165 'file ignored - please check' % ( 

166 net, sta, loc, cha)) 

167 

168 nut = model.make_channel_nut( 

169 file_segment=0, 

170 file_element=inut, 

171 agency=agn, 

172 network=net, 

173 station=sta, 

174 location=loc, 

175 channel=cha, 

176 tmin=tmin, 

177 tmax=tmax) 

178 

179 if 'channel' in content: 

180 nut.content = model.Channel( 

181 lat=lat, 

182 lon=lon, 

183 elevation=elevation, 

184 depth=depth, 

185 azimuth=azi, 

186 dip=dip, 

187 **nut.channel_kwargs) 

188 

189 yield nut 

190 inut += 1 

191 

192 else: 

193 raise Exception('invalid syntax') 

194 

195 except Exception as e: 

196 logger.warning( 

197 'skipping invalid station/channel definition: %s ' 

198 '(line: %i, file: %s' % (str(e), iline, file_path)) 

199 

200 

201def iload_pyrocko_events(file_path, segment, content): 

202 from pyrocko import model as pmodel 

203 

204 for iev, ev in enumerate(pmodel.Event.load_catalog(file_path)): 

205 nut = model.make_event_nut( 

206 file_segment=0, 

207 file_element=iev, 

208 name=ev.name or '', 

209 tmin=ev.time, 

210 tmax=ev.time) 

211 

212 if 'event' in content: 

213 nut.content = ev 

214 

215 yield nut