User contributed plug-ins for Pyrocko's seismic waveform browser Snuffler.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
5.1 KiB

4 years ago
5 years ago
  1. import os.path as op
  2. import logging
  3. import math
  4. from pyrocko import io
  5. from pyrocko import model
  6. from pyrocko.gui.snuffling import Snuffling, Choice, Switch, Param
  7. logger = logging.getLogger('export')
  8. class ExportWaveforms(Snuffling):
  9. '''
  10. <html>
  11. <head>
  12. <style type="text/css">
  13. body { margin-left:10px };
  14. </style>
  15. </head>
  16. <h1 align="center">Export selected or visible traces</h1>
  17. <body>
  18. <p>
  19. Choose the desired format from the <b>Format</b> menu and press
  20. <b>Run</b>.
  21. If no traces have been selected using extended markers all traces visible
  22. in the viewer will be exported.
  23. </p>
  24. <p>
  25. Note that exporting to miniseed requires the network, station, location and
  26. channel codes to be of length 2, 5, 2 and 3, respectively. Codes exceeding
  27. these lenghts will be silently truncated.<br />
  28. In order to have more control on code replacements it is recommended to use
  29. the command line tool <b>jackseis</b> which is shipped with pyrocko.<br />
  30. When exporting to miniseed it is possible to combine all traces into
  31. one file by giving a filename without template placeholders.
  32. </p>
  33. </body>
  34. </html>
  35. '''
  36. def setup(self):
  37. self.set_name('Export Waveforms')
  38. self.add_parameter(
  39. Choice(
  40. 'Format', 'format', 'mseed', ['mseed', 'text', 'sac', 'yaff']))
  41. self.add_parameter(
  42. Param(
  43. 'Time length limit for output files', 'tinc', None,
  44. 0.1, 86400., low_is_none=True))
  45. self.add_parameter(Switch('Save Station Meta', 'save_stations', False))
  46. self.add_parameter(Switch('Apply Filters/Rotation', 'apply_filter', False))
  47. self.set_live_update(False)
  48. def call(self):
  49. self.cleanup()
  50. if self.tinc is not None:
  51. template = \
  52. 'trace_%n.%s.%l.%c_%(tmin_us)s'
  53. else:
  54. template = 'trace_%n.%s.%l.%c'
  55. if self.format == 'text':
  56. default_output_filename = template + '.dat'
  57. else:
  58. default_output_filename = template + '.' + self.format
  59. out_filename = self.output_filename('Template for output files',
  60. default_output_filename)
  61. viewer = self.get_viewer()
  62. for trs in self.chopper_selected_traces(fallback=True, tinc=self.tinc):
  63. traces_save = []
  64. for tr in trs:
  65. if self.format == 'mseed':
  66. if len(tr.network) > 2:
  67. tr.set_network(tr.network[:2])
  68. if len(tr.station) > 5:
  69. tr.set_station(tr.station[:5])
  70. if len(tr.location) > 2:
  71. tr.set_location(tr.location[:2])
  72. if len(tr.channel) > 3:
  73. tr.set_channel(tr.channel[:3])
  74. if self.apply_filter:
  75. if viewer.lowpass is not None and \
  76. viewer.highpass is not None:
  77. tr.bandpass(2, viewer.highpass, viewer.lowpass)
  78. elif viewer.lowpass is not None:
  79. if viewer.lowpass < 0.5/tr.deltat:
  80. tr.lowpass(4, viewer.lowpass, demean=False)
  81. elif viewer.highpass is not None:
  82. if viewer.highpass < 0.5/tr.deltat:
  83. tr.highpass(4, viewer.highpass, demean=False)
  84. traces_save.append(tr)
  85. if viewer.rotate != 0.0 and self.apply_filter:
  86. phi = viewer.rotate/180.*math.pi
  87. cphi = math.cos(phi)
  88. sphi = math.sin(phi)
  89. for a in traces_save:
  90. for b in traces_save:
  91. if (a.network == b.network
  92. and a.station == b.station
  93. and a.location == b.location
  94. and ((a.channel.lower().endswith('n')
  95. and b.channel.lower().endswith('e'))
  96. or (a.channel.endswith('1')
  97. and b.channel.endswith('2')))
  98. and abs(a.deltat-b.deltat) < a.deltat*0.001
  99. and abs(a.tmin-b.tmin) < a.deltat*0.01 and
  100. a.get_ydata().size == b.get_ydata().size):
  101. aydata = a.get_ydata()*cphi+b.get_ydata()*sphi
  102. bydata = -a.get_ydata()*sphi+b.get_ydata()*cphi
  103. a.set_ydata(aydata)
  104. b.set_ydata(bydata)
  105. try:
  106. io.save(
  107. traces_save, out_filename,
  108. format=self.format,
  109. overwrite=True)
  110. except io.io_common.FileSaveError as e:
  111. self.fail(str(e))
  112. logger.info('saved waveforms to %s', out_filename)
  113. if self.save_stations:
  114. stations = viewer.stations.values()
  115. fn = self.output_filename('Save Stations', 'stations.pf')
  116. model.dump_stations(list(stations), fn)
  117. logger.info('saved stations to %s', fn)
  118. def __snufflings__():
  119. return [ExportWaveforms()]