1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6import os 

7import logging 

8 

9from pyrocko.gui.snuffler.marker import EventMarker 

10 

11from ..snuffling import Param, Snuffling, Switch, Choice 

12from pyrocko import util, io, model 

13from pyrocko.client import fdsn 

14pjoin = os.path.join 

15 

16logger = logging.getLogger('pyrocko.gui.snuffler.snufflings.download') 

17logger.setLevel(logging.INFO) 

18 

19 

20class Download(Snuffling): 

21 

22 def setup(self): 

23 ''' 

24 Customization of the snuffling. 

25 ''' 

26 

27 self.set_name('Download Waveforms') 

28 self.add_parameter(Param( 

29 'Min Radius [deg]', 'minradius', 0., 0., 180.)) 

30 self.add_parameter(Param( 

31 'Max Radius [deg]', 'maxradius', 5., 0., 180.)) 

32 self.add_parameter(Param( 

33 'Origin latitude [deg]', 'lat', 0, -90., 90.)) 

34 self.add_parameter(Param( 

35 'Origin longitude [deg]', 'lon', 0., -180., 180.)) 

36 self.add_parameter(Switch( 

37 'Use coordinates of selected event as origin', 'useevent', False)) 

38 self.add_parameter(Choice( 

39 'Datecenter', 'datacenter', 'GEOFON', ['GEOFON', 'IRIS'])) 

40 self.add_parameter(Choice( 

41 'Channels', 'channel_pattern', 'BH?', 

42 ['BH?', 'BHZ', 'HH?', '?H?', '*', '??Z'])) 

43 

44 self.add_trigger('Save', self.save) 

45 self.set_live_update(False) 

46 self.current_stuff = None 

47 

48 def call(self): 

49 ''' 

50 Main work routine of the snuffling. 

51 ''' 

52 

53 self.cleanup() 

54 

55 view = self.get_viewer() 

56 

57 tmin, tmax = view.get_time_range() 

58 if self.useevent: 

59 markers = view.selected_markers() 

60 if len(markers) != 1: 

61 self.fail('Exactly one marker must be selected.') 

62 marker = markers[0] 

63 if not isinstance(marker, EventMarker): 

64 self.fail('An event marker must be selected.') 

65 

66 ev = marker.get_event() 

67 

68 lat, lon = ev.lat, ev.lon 

69 else: 

70 lat, lon = self.lat, self.lon 

71 

72 site = self.datacenter.lower() 

73 try: 

74 kwargs = {} 

75 if site == 'iris': 

76 kwargs['matchtimeseries'] = True 

77 

78 sx = fdsn.station( 

79 site=site, latitude=lat, longitude=lon, 

80 minradius=self.minradius, maxradius=self.maxradius, 

81 startbefore=tmin, endafter=tmax, channel=self.channel_pattern, 

82 format='text', level='channel', includerestricted=False, 

83 **kwargs) 

84 

85 except fdsn.EmptyResult: 

86 self.fail('No stations matching given criteria.') 

87 

88 stations = sx.get_pyrocko_stations() 

89 networks = set([s.network for s in stations]) 

90 

91 t2s = util.time_to_str 

92 dir = self.tempdir() 

93 fns = [] 

94 for net in networks: 

95 nstations = [s for s in stations if s.network == net] 

96 selection = fdsn.make_data_selection(nstations, tmin, tmax) 

97 if selection: 

98 for x in selection: 

99 logger.info( 

100 'Adding data selection: %s.%s.%s.%s %s - %s' 

101 % (tuple(x[:4]) + (t2s(x[4]), t2s(x[5])))) 

102 

103 try: 

104 d = fdsn.dataselect(site=site, selection=selection) 

105 fn = pjoin(dir, 'data-%s.mseed' % net) 

106 f = open(fn, 'wb') 

107 f.write(d.read()) 

108 f.close() 

109 fns.append(fn) 

110 

111 except fdsn.EmptyResult: 

112 pass 

113 

114 all_traces = [] 

115 for fn in fns: 

116 try: 

117 traces = list(io.load(fn)) 

118 

119 all_traces.extend(traces) 

120 

121 except io.FileLoadError as e: 

122 logger.warning('File load error, %s' % e) 

123 

124 if all_traces: 

125 newstations = [] 

126 for sta in stations: 

127 if not view.has_station(sta): 

128 logger.info( 

129 'Adding station: %s.%s.%s' 

130 % (sta.network, sta.station, sta.location)) 

131 

132 newstations.append(sta) 

133 

134 view.add_stations(newstations) 

135 

136 for tr in all_traces: 

137 logger.info( 

138 'Adding trace: %s.%s.%s.%s %s - %s' 

139 % (tr.nslc_id + (t2s(tr.tmin), t2s(tr.tmax)))) 

140 

141 self.add_traces(all_traces) 

142 self.current_stuff = (all_traces, stations) 

143 

144 else: 

145 self.current_stuff = None 

146 self.fail('Did not get any data for given selection.') 

147 

148 def save(self): 

149 if not self.current_stuff: 

150 self.fail('Nothing to save.') 

151 

152 data_fn = self.output_filename( 

153 caption='Save Data', 

154 dir='data-%(network)s-%(station)s-%(location)s-%(channel)s-' 

155 '%(tmin)s.mseed') 

156 

157 stations_fn = self.output_filename( 

158 caption='Save Stations File', 

159 dir='stations.txt') 

160 

161 all_traces, stations = self.current_stuff 

162 io.save(all_traces, data_fn) 

163 model.station.dump_stations(stations, stations_fn) 

164 

165 

166def __snufflings__(): 

167 return [Download()]