Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/gui/snuffler/snuffler.py: 62%

130 statements  

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

1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6''' 

7Effective seismological trace viewer. 

8''' 

9 

10import os 

11import sys 

12import logging 

13import gc 

14import tempfile 

15import shutil 

16import glob 

17 

18from os.path import join as pjoin 

19from optparse import OptionParser 

20 

21 

22from pyrocko import deps 

23from pyrocko import pile as pile_mod 

24from pyrocko import util 

25from pyrocko import model 

26from pyrocko import config 

27from pyrocko import io 

28from pyrocko.io import stationxml 

29 

30from . import marker 

31 

32 

33logger = logging.getLogger('pyrocko.gui.snuffler.snuffler') 

34 

35 

36def extend_paths(paths): 

37 paths_r = [] 

38 for p in paths: 

39 paths_r.extend(glob.glob(p)) 

40 return paths_r 

41 

42 

43def snuffle(pile=None, **kwargs): 

44 ''' 

45 View pile in a snuffler window. 

46 

47 :param pile: :py:class:`~pyrocko.pile.Pile` object to be visualized 

48 :param stations: list of `pyrocko.model.Station` objects or ``None`` 

49 :param events: list of `pyrocko.model.Event` objects or ``None`` 

50 :param markers: list of `pyrocko.gui.snuffler.util.Marker` objects or 

51 ``None`` 

52 :param ntracks: float, number of tracks to be shown initially (default: 12) 

53 :param marker_editor_sortable: bool, whether to allow sorting in marker 

54 table (default True). Disabling this will give better performance 

55 when working with many markers. 

56 :param follow: time interval (in seconds) for real time follow mode or 

57 ``None`` 

58 :param controls: bool, whether to show the main controls (default: 

59 ``True``) 

60 :param opengl: bool, whether to use opengl (default: ``None`` - automatic 

61 choice). 

62 :param paths: list of files and directories to search for trace files 

63 :param pattern: regex which filenames must match 

64 :param format: format of input files 

65 :param cache_dir: cache directory with trace meta information 

66 :param force_cache: bool, whether to use the cache when attribute spoofing 

67 is active 

68 :param store_path: filename template, where to store trace data from input 

69 streams 

70 :param store_interval: float, time interval (in seconds) between stream 

71 buffer dumps 

72 :param want_markers: bool, whether markers should be returned 

73 :param launch_hook: callback function called before snuffler window is 

74 shown 

75 :param instant_close: bool, whether to bypass close window confirmation 

76 dialog 

77 ''' 

78 from .snuffler_app import SnufflerWindow, \ 

79 setup_acquisition_sources, PollInjector 

80 

81 if pile is None: 

82 pile = pile_mod.make_pile() 

83 

84 from pyrocko.gui import util as gui_util 

85 app = gui_util.get_app() 

86 

87 kwargs_load = {} 

88 for k in ('paths', 'regex', 'format', 'cache_dir', 'force_cache'): 

89 try: 

90 kwargs_load[k] = kwargs.pop(k) 

91 except KeyError: 

92 pass 

93 

94 store_path = kwargs.pop('store_path', None) 

95 store_interval = kwargs.pop('store_interval', 600) 

96 want_markers = kwargs.pop('want_markers', False) 

97 launch_hook = kwargs.pop('launch_hook', None) 

98 

99 win = SnufflerWindow(pile, **kwargs) 

100 app.set_main_window(win) 

101 

102 if launch_hook: 

103 if not isinstance(launch_hook, list): 

104 launch_hook = [launch_hook] 

105 for hook in launch_hook: 

106 hook(win) 

107 

108 sources = [] 

109 pollinjector = None 

110 tempdir = None 

111 if 'paths' in kwargs_load: 

112 sources.extend(setup_acquisition_sources(kwargs_load['paths'])) 

113 if sources: 

114 if store_path is None: 

115 tempdir = tempfile.mkdtemp('', 'snuffler-tmp-') 

116 store_path = pjoin( 

117 tempdir, 

118 'trace-%(network)s.%(station)s.%(location)s.%(channel)s.' 

119 '%(tmin_ms)s.mseed') 

120 elif os.path.isdir(store_path): 

121 store_path = pjoin( 

122 store_path, 

123 'trace-%(network)s.%(station)s.%(location)s.%(channel)s.' 

124 '%(tmin_ms)s.mseed') 

125 

126 interval = min( 

127 source.get_wanted_poll_interval() for source in sources) 

128 

129 pollinjector = PollInjector( 

130 pile, 

131 fixation_length=store_interval, 

132 path=store_path, 

133 interval=interval) 

134 

135 for source in sources: 

136 source.start() 

137 pollinjector.add_source(source) 

138 

139 win.get_view().load(**kwargs_load) 

140 

141 if not win.is_closing(): 

142 app.install_sigint_handler() 

143 try: 

144 app.exec_() 

145 

146 finally: 

147 app.uninstall_sigint_handler() 

148 app.set_main_window(None) 

149 

150 for source in sources: 

151 source.stop() 

152 

153 if pollinjector: 

154 pollinjector.fixate_all() 

155 

156 ret = win.return_tag() 

157 

158 if want_markers: 

159 markers = win.get_view().get_markers() 

160 

161 del win 

162 gc.collect() 

163 

164 if tempdir: 

165 shutil.rmtree(tempdir) 

166 

167 if want_markers: 

168 return ret, markers 

169 else: 

170 return ret 

171 

172 

173def snuffler_from_commandline(args=None): 

174 if args is None: 

175 args = sys.argv[1:] 

176 

177 usage = '''usage: %prog [options] waveforms ...''' 

178 parser = OptionParser(usage=usage) 

179 

180 parser.add_option( 

181 '--format', 

182 dest='format', 

183 default='detect', 

184 choices=io.allowed_formats('load'), 

185 help='assume input files are of given FORMAT. Choices: %s' 

186 % io.allowed_formats('load', 'cli_help', 'detect')) 

187 

188 parser.add_option( 

189 '--pattern', 

190 dest='regex', 

191 metavar='REGEX', 

192 help='only include files whose paths match REGEX') 

193 

194 parser.add_option( 

195 '--stations', 

196 dest='station_fns', 

197 action='append', 

198 default=[], 

199 metavar='STATIONS', 

200 help='read station information from file STATIONS') 

201 

202 parser.add_option( 

203 '--stationxml', 

204 dest='stationxml_fns', 

205 action='append', 

206 default=[], 

207 metavar='STATIONSXML', 

208 help='read station information from XML file STATIONSXML') 

209 

210 parser.add_option( 

211 '--event', '--events', 

212 dest='event_fns', 

213 action='append', 

214 default=[], 

215 metavar='EVENT', 

216 help='read event information from file EVENT') 

217 

218 parser.add_option( 

219 '--markers', 

220 dest='marker_fns', 

221 action='append', 

222 default=[], 

223 metavar='MARKERS', 

224 help='read marker information file MARKERS') 

225 

226 parser.add_option( 

227 '--follow', 

228 type='float', 

229 dest='follow', 

230 metavar='N', 

231 help='follow real time with a window of N seconds') 

232 

233 parser.add_option( 

234 '--cache', 

235 dest='cache_dir', 

236 default=config.config().cache_dir, 

237 metavar='DIR', 

238 help='use directory DIR to cache trace metadata ' 

239 "(default='%default')") 

240 

241 parser.add_option( 

242 '--force-cache', 

243 dest='force_cache', 

244 action='store_true', 

245 default=False, 

246 help='use the cache even when trace attribute spoofing is active ' 

247 '(may have silly consequences)') 

248 

249 parser.add_option( 

250 '--store-path', 

251 dest='store_path', 

252 metavar='PATH_TEMPLATE', 

253 help='store data received through streams to PATH_TEMPLATE') 

254 

255 parser.add_option( 

256 '--store-interval', 

257 type='float', 

258 dest='store_interval', 

259 default=600, 

260 metavar='N', 

261 help='dump stream data to file every N seconds [default: %default]') 

262 

263 parser.add_option( 

264 '--ntracks', 

265 type='int', 

266 dest='ntracks', 

267 default=24, 

268 metavar='N', 

269 help='initially use N waveform tracks in viewer [default: %default]') 

270 

271 parser.add_option( 

272 '--disable-marker-sorting', 

273 action='store_false', 

274 dest='marker_editor_sortable', 

275 default=True, 

276 help='disable sorting in marker table for improved performance with ' 

277 '100000+ markers') 

278 

279 parser.add_option( 

280 '--hptime', 

281 choices=('on', 'off', 'config'), 

282 dest='hp_time', 

283 default='config', 

284 metavar='on|off|config', 

285 help='set high precision time mode [default: %default]') 

286 

287 parser.add_option( 

288 '--opengl', 

289 dest='opengl', 

290 action='store_true', 

291 default=None, 

292 help='use OpenGL for drawing') 

293 

294 parser.add_option( 

295 '--no-opengl', 

296 dest='opengl', 

297 action='store_false', 

298 default=None, 

299 help='do not use OpenGL for drawing') 

300 

301 parser.add_option( 

302 '--debug', 

303 dest='debug', 

304 action='store_true', 

305 default=False, 

306 help='print debugging information to stderr') 

307 

308 options, args = parser.parse_args(list(args)) 

309 

310 if options.debug: 

311 util.setup_logging('snuffler', 'debug') 

312 else: 

313 util.setup_logging('snuffler', 'info') 

314 

315 if options.hp_time in ('on', 'off'): 

316 util.use_high_precision_time(options.hp_time == 'on') 

317 

318 this_pile = pile_mod.Pile() 

319 stations = [] 

320 for stations_fn in extend_paths(options.station_fns): 

321 stations.extend(model.station.load_stations(stations_fn)) 

322 

323 for stationxml_fn in extend_paths(options.stationxml_fns): 

324 stations.extend( 

325 stationxml.load_xml( 

326 filename=stationxml_fn).get_pyrocko_stations()) 

327 

328 events = [] 

329 for event_fn in extend_paths(options.event_fns): 

330 events.extend(model.load_events(event_fn)) 

331 

332 markers = [] 

333 for marker_fn in extend_paths(options.marker_fns): 

334 markers.extend(marker.load_markers(marker_fn)) 

335 

336 import pyrocko 

337 

338 try: 

339 return pyrocko.snuffle( 

340 this_pile, 

341 stations=stations, 

342 events=events, 

343 markers=markers, 

344 ntracks=options.ntracks, 

345 marker_editor_sortable=options.marker_editor_sortable, 

346 follow=options.follow, 

347 controls=True, 

348 opengl=options.opengl, 

349 paths=args, 

350 cache_dir=options.cache_dir, 

351 regex=options.regex, 

352 format=options.format, 

353 force_cache=options.force_cache, 

354 store_path=options.store_path, 

355 store_interval=options.store_interval) 

356 

357 except deps.MissingPyrockoDependency as e: 

358 logger.fatal(str(e)) 

359 sys.exit(1) 

360 

361 

362if __name__ == '__main__': 

363 snuffler_from_commandline()