Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/io/eventdata.py: 37%

114 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-10-06 15:01 +0000

1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6''' 

7Event data access interface (*deprecated*). 

8''' 

9 

10from pyrocko import model, response 

11 

12import logging 

13import copy 

14import pickle 

15 

16logger = logging.getLogger('pyrocko.io.eventdata') 

17 

18 

19class NoRestitution(Exception): 

20 pass 

21 

22 

23class FileNotFound(Exception): 

24 

25 def __init__(self, s): 

26 self.s = s 

27 

28 def __str__(self): 

29 return 'File not found: %s' % self.s 

30 

31 

32class Problems(object): 

33 def __init__(self): 

34 self._problems = {} 

35 

36 def add(self, kind, nslct): 

37 if kind not in self._problems: 

38 self._problems[kind] = set() 

39 problem = self._problems[kind] 

40 problem.add(nslct) 

41 

42 def dump(self, fn): 

43 f = open(fn, 'wb') 

44 pickle.dump(self._problems, f) 

45 f.close() 

46 

47 def load(self, fn): 

48 f = open(fn, 'rb') 

49 self._problems = pickle.load(f) 

50 f.close() 

51 

52 def mapped(self, mapping=lambda nslct: nslct[:3]): 

53 p = {} 

54 for kind, problem in self._problems.items(): 

55 nsl = set() 

56 for nslct in problem: 

57 nsl.add(mapping(nslct)) 

58 p[kind] = nsl 

59 

60 return p 

61 

62 

63class EventDataAccess(object): 

64 ''' 

65 Abstract base class for event data access (see rdseed.py). 

66 ''' 

67 

68 def __init__(self, events=None, stations=None, datapile=None): 

69 

70 self._pile = datapile 

71 self._events = events 

72 

73 if stations is None: 

74 self._stations = None 

75 else: 

76 self._stations = {} 

77 for station in stations: 

78 self._stations[station.nsl()] = station 

79 

80 self._problems = Problems() 

81 

82 def get_pile(self): 

83 return self._pile 

84 

85 def get_pyrocko_events(self): 

86 ''' 

87 Extract :py:class:`~pyrocko.model.event.Event` instances from the 

88 volume. 

89 ''' 

90 

91 if not self._events: 

92 self._events = self._get_events_from_file() 

93 return self._events 

94 

95 def get_pyrocko_station(self, tr, relative_event=None): 

96 ''' 

97 Get station information for a given trace. 

98 

99 :param tr: :py:class:`~pyrocko.trace.Trace` instance 

100 

101 :returns: :py:class:`~pyrocko.model.station.Station` objects. 

102 ''' 

103 

104 self._update_stations() 

105 s = copy.deepcopy(self._stations[tr.nslc_id[:3]]) 

106 if relative_event is not None: 

107 s.set_event_relative_data(relative_event) 

108 return s 

109 

110 def get_pyrocko_channel(self, tr): 

111 ''' 

112 Get channel information for a given trace. 

113 

114 :param tr: :py:class:`~pyrocko.trace.Trace` instance 

115 

116 :returns: :py:class:`~pyrocko.model.station.Channel` objects. 

117 ''' 

118 sta = self.get_station(tr) 

119 return sta.get_channel(tr.channel) 

120 

121 def get_pyrocko_stations(self): 

122 ''' 

123 Exctract a list of :py:class:`~pyrocko.model.station.Station` 

124 instances. 

125 ''' 

126 return list(self._get_stations().values()) 

127 

128 def _get_stations(self, relative_event=None): 

129 self._update_stations() 

130 stations = copy.deepcopy(self._stations) 

131 if relative_event is not None: 

132 for s in stations.values(): 

133 s.set_event_relative_data(relative_event) 

134 

135 return stations 

136 

137 def _update_stations(self): 

138 if not self._stations: 

139 self._stations = {} 

140 for station in self._get_stations_from_file(): 

141 self._stations[station.nsl()] = station 

142 self._insert_channel_descriptions(self._stations) 

143 

144 def _insert_channel_descriptions(self, stations): 

145 pile = self.get_pile() 

146 nslc_ids = pile.gather_keys( 

147 lambda tr: (tr.network, tr.station, tr.location, tr.channel)) 

148 

149 for nslc in nslc_ids: 

150 if nslc[:3] not in stations: 

151 logger.warning( 

152 'No station description for trace %s.%s.%s.%s' % nslc) 

153 continue 

154 

155 sta = stations[nslc[:3]] 

156 try: 

157 sta.add_channel(self._get_channel_description_from_file(nslc)) 

158 except FileNotFound: 

159 logger.warning( 

160 'No channel description for trace %s.%s.%s.%s' % nslc) 

161 

162 def _get_channel_description_from_file(self, nslc): 

163 return model.Channel(nslc[3], None, None, 1.) 

164 

165 def iter_traces(self, group_selector=None, trace_selector=None): 

166 

167 for traces in self.get_pile().chopper_grouped( 

168 gather=lambda tr: (tr.network, tr.station, tr.location), 

169 group_selector=group_selector, 

170 trace_selector=trace_selector): 

171 

172 yield traces 

173 

174 def problems(self): 

175 return self._problems 

176 

177 def _redundant_channel_weeder(self, redundant_channel_priorities, nslcs): 

178 

179 if redundant_channel_priorities is None: 

180 return [] 

181 

182 # n=network,s=station,l=location,c=channel 

183 # channels by station 

184 by_nsl = {} 

185 for nslc in nslcs: 

186 nsl = nslc[:3] 

187 if nsl not in by_nsl: 

188 by_nsl[nsl] = [] 

189 

190 by_nsl[nsl].append(nslc) 

191 

192 # figure out what items to remove 

193 to_delete = [] 

194 for ((h1, h2), (l1, l2)) in redundant_channel_priorities: 

195 for nsl, nslcs in by_nsl.items(): 

196 channels = [nslc[3] for nslc in nslcs] 

197 if h1 in channels and \ 

198 h2 in channels and \ 

199 l1 in channels and \ 

200 l2 in channels: 

201 

202 to_delete.append(nslc[:3] + (l1,)) 

203 to_delete.append(nslc[:3] + (l2,)) 

204 

205 return to_delete 

206 

207 def get_restitution(self, tr, allowed_methods): 

208 if 'integration' in allowed_methods: 

209 response.IntegrationResponse() 

210 else: 

211 raise Exception('only "integration" restitution method is allowed')