2014-03-13 13:27:34 +01:00
|
|
|
#!/usr/bin/env python
|
2014-03-31 12:57:08 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
PyLoT: Main program
|
|
|
|
===================
|
|
|
|
PyLoT is a seismic data processing software capable of picking seismic
|
|
|
|
phases (symmetric and asymmetric error assignment), exporting these to
|
|
|
|
several common phase data formats and post process the data, e.g. locating
|
|
|
|
events, via external localization software.
|
|
|
|
Additionally PyLoT is meant as an interface to autoPyLoT which can
|
|
|
|
automatically pick seismic phases, if the parameters have properly been
|
|
|
|
chosen for the particular data set.
|
|
|
|
|
2014-11-28 09:19:16 +01:00
|
|
|
Some icons are out of a free of charge icon set, which can be found here:
|
|
|
|
https://www.iconfinder.com/iconsets/flavour
|
|
|
|
|
2014-03-31 12:57:08 +02:00
|
|
|
:author:
|
|
|
|
Sebastian Wehling-Benatelli
|
|
|
|
:copyright:
|
|
|
|
The PyLoT Development Team (https://ariadne.geophysik.rub.de/trac/PyLoT)
|
|
|
|
:license:
|
|
|
|
GNU Lesser General Public License, Version 3
|
|
|
|
(http://www.gnu.org/copyleft/lesser.html)
|
|
|
|
"""
|
2014-01-09 10:43:40 +01:00
|
|
|
|
|
|
|
import sys
|
2014-12-04 05:13:32 +01:00
|
|
|
|
2014-03-13 13:27:34 +01:00
|
|
|
from PySide.QtCore import *
|
|
|
|
from PySide.QtGui import *
|
2014-12-04 05:13:32 +01:00
|
|
|
from obspy.core import (UTCDateTime)
|
|
|
|
|
2014-01-09 10:43:40 +01:00
|
|
|
from pylot.core.util import _getVersionString
|
2014-07-16 12:06:05 +02:00
|
|
|
from pylot.core.read import (Data,
|
|
|
|
FilterOptions)
|
2014-03-13 13:27:34 +01:00
|
|
|
from pylot.core.util import FILTERDEFAULTS
|
2014-12-01 12:34:44 +01:00
|
|
|
from pylot.core.util import fnConstructor
|
2014-03-31 12:57:08 +02:00
|
|
|
from pylot.core.util import checkurl
|
2014-12-04 05:13:32 +01:00
|
|
|
from pylot.core.util import (FilterOptionsDialog,
|
2014-06-10 16:37:07 +02:00
|
|
|
MPLWidget,
|
|
|
|
HelpForm)
|
2014-12-04 05:13:32 +01:00
|
|
|
|
2014-01-09 10:43:40 +01:00
|
|
|
|
|
|
|
# Version information
|
|
|
|
__version__ = _getVersionString()
|
|
|
|
|
2014-03-13 13:27:34 +01:00
|
|
|
|
2014-01-10 05:45:03 +01:00
|
|
|
class MainWindow(QMainWindow):
|
2014-03-13 13:27:34 +01:00
|
|
|
|
2014-01-10 05:45:03 +01:00
|
|
|
def __init__(self, parent=None):
|
|
|
|
super(MainWindow, self).__init__(parent)
|
2014-03-13 13:27:34 +01:00
|
|
|
|
2014-11-28 11:15:49 +01:00
|
|
|
settings = QSettings()
|
2014-12-01 12:36:23 +01:00
|
|
|
self.recentEvents = settings.value("recentEvents", [])
|
2014-11-28 11:15:49 +01:00
|
|
|
self.setWindowTitle("PyLoT - do seismic processing the pythonic way")
|
|
|
|
self.setWindowIcon(QIcon(":/icon.ico"))
|
|
|
|
self.seismicPhase = str(settings.value("phase", "P"))
|
2014-12-01 12:36:23 +01:00
|
|
|
if settings.value("dataRoot", None) is None:
|
|
|
|
dirname = QFileDialog().getExistingDirectory()
|
|
|
|
settings.setValue("dataRoot", dirname)
|
|
|
|
settings.sync()
|
2014-11-28 11:15:49 +01:00
|
|
|
|
2014-11-06 15:07:05 +01:00
|
|
|
# initialize filter parameter
|
2014-03-13 13:27:34 +01:00
|
|
|
filterOptionsP = FILTERDEFAULTS['P']
|
|
|
|
filterOptionsS = FILTERDEFAULTS['S']
|
2014-11-28 11:15:49 +01:00
|
|
|
print filterOptionsP, "\n", filterOptionsS
|
2014-03-13 13:27:34 +01:00
|
|
|
self.filterOptionsP = FilterOptions(**filterOptionsP)
|
|
|
|
self.filterOptionsS = FilterOptions(**filterOptionsS)
|
|
|
|
|
2014-11-06 15:07:05 +01:00
|
|
|
# initialize data
|
|
|
|
self.data = None
|
2014-03-28 05:25:46 +01:00
|
|
|
self.loadData()
|
|
|
|
self.updateFilterOptions()
|
2014-11-28 11:15:49 +01:00
|
|
|
print self.filteroptions
|
2014-11-26 08:46:16 +01:00
|
|
|
try:
|
|
|
|
self.startTime = min([tr.stats.starttime for tr in self.data.wfdata])
|
|
|
|
except:
|
|
|
|
self.startTime = UTCDateTime()
|
2014-03-28 05:25:46 +01:00
|
|
|
|
|
|
|
self.setupUi()
|
|
|
|
|
2014-10-27 11:57:34 +01:00
|
|
|
def _getCurrentPlotType(self):
|
|
|
|
return 'TestType'
|
|
|
|
|
2014-11-27 10:13:17 +01:00
|
|
|
def createAction(self, text, slot=None, shortcut=None, icon=None,
|
|
|
|
tip=None, checkable=False):
|
2014-12-04 05:13:32 +01:00
|
|
|
"""
|
|
|
|
:rtype : ~PySide.QtGui.QAction
|
|
|
|
"""
|
2014-11-27 10:13:17 +01:00
|
|
|
action = QAction(text, self)
|
|
|
|
if icon is not None:
|
|
|
|
action.setIcon(icon)
|
|
|
|
if shortcut is not None:
|
|
|
|
action.setShortcut(shortcut)
|
|
|
|
if tip is not None:
|
|
|
|
action.setToolTip(tip)
|
|
|
|
if slot is not None:
|
|
|
|
action.triggered.connect(slot)
|
|
|
|
if checkable:
|
|
|
|
action.setCheckable(True)
|
|
|
|
return action
|
|
|
|
|
2014-12-01 12:37:52 +01:00
|
|
|
def updateFileMenu(self):
|
|
|
|
|
|
|
|
self.fileMenu.clear()
|
|
|
|
self.addActions(self.fileMenu, self.fileMenuActions[:-1])
|
|
|
|
current = self.data.evtdata.getEventID()
|
|
|
|
recentEvents = []
|
|
|
|
for eventID in self.recentEvents:
|
|
|
|
fname = fnConstructor(eventID)
|
|
|
|
if eventID != current and QFile.exists(fname):
|
|
|
|
recentEvents.append(eventID)
|
|
|
|
if recentEvents:
|
|
|
|
self.fileMenu.addSeparator()
|
|
|
|
for i, eventID in enumerate(recentEvents):
|
|
|
|
fname = fnConstructor(eventID)
|
|
|
|
action = QAction(QIcon(":/icon.png"),
|
|
|
|
"&{0} {1}".format(i + 1,
|
|
|
|
QFileInfo(fname).fileName()),
|
|
|
|
self)
|
|
|
|
action.setData(fname)
|
|
|
|
self.connect(action, SIGNAL("triggered()"),
|
|
|
|
self.loadData)
|
|
|
|
self.fileMenu.addAction(action)
|
|
|
|
self.fileMenu.addSeparator()
|
|
|
|
self.fileMenu.addAction(self.fileMenuActions[-1])
|
2014-11-28 11:15:49 +01:00
|
|
|
|
2014-12-01 12:37:52 +01:00
|
|
|
|
|
|
|
def loadData(self, fname=None):
|
|
|
|
if fname is None:
|
|
|
|
action = self.sender()
|
|
|
|
if isinstance(action, QAction):
|
|
|
|
if action.data() is None:
|
|
|
|
fname = QFileDialog()
|
|
|
|
else:
|
|
|
|
fname = unicode(action.data().toString())
|
|
|
|
if not self.okToContinue():
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
return
|
|
|
|
if fname:
|
|
|
|
self.data = Data(evtdata=fname)
|
2014-11-26 08:46:16 +01:00
|
|
|
|
2014-11-28 11:15:49 +01:00
|
|
|
def saveData(self):
|
|
|
|
pass
|
|
|
|
|
2014-11-26 08:46:16 +01:00
|
|
|
def getComponent(self):
|
|
|
|
return self
|
2014-03-28 22:26:15 +01:00
|
|
|
|
2014-11-13 11:27:52 +01:00
|
|
|
def getData(self):
|
|
|
|
return self.data
|
|
|
|
|
|
|
|
def getDataWidget(self):
|
|
|
|
return self.DataPlot
|
|
|
|
|
2014-03-28 05:25:46 +01:00
|
|
|
def setupUi(self):
|
2014-11-28 09:19:16 +01:00
|
|
|
self.setWindowIcon(QIcon(":/icon.ico"))
|
2014-03-28 05:25:46 +01:00
|
|
|
|
2014-11-06 15:07:05 +01:00
|
|
|
xlab = self.startTime.strftime('seconds since %d %b %Y %H:%M:%S (%Z)')
|
2014-10-27 11:55:06 +01:00
|
|
|
plottitle = self._getCurrentPlotType()
|
2014-07-16 12:06:05 +02:00
|
|
|
|
2014-03-28 05:25:46 +01:00
|
|
|
# create central matplotlib figure widget
|
2014-07-16 12:06:05 +02:00
|
|
|
self.DataPlot = MPLWidget(parent=self,
|
|
|
|
xlabel=xlab,
|
2014-10-27 11:55:06 +01:00
|
|
|
ylabel=None,
|
|
|
|
title=plottitle)
|
2014-11-27 10:13:17 +01:00
|
|
|
|
|
|
|
self.setCentralWidget(self.getDataWidget())
|
|
|
|
|
2014-11-28 09:19:16 +01:00
|
|
|
openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon)
|
|
|
|
quitIcon = self.style().standardIcon(QStyle.SP_MediaStop)
|
2014-11-28 11:15:49 +01:00
|
|
|
saveIcon = self.style().standardIcon(QStyle.SP_DriveHDIcon)
|
2014-12-01 12:39:56 +01:00
|
|
|
openEventAction = self.createAction("&Open event ...", self.loadData,
|
|
|
|
QKeySequence.Open, openIcon,
|
|
|
|
"Open an event.")
|
|
|
|
openEventAction.setData(None)
|
|
|
|
saveEventAction = self.createAction("&Save event ...", self.saveData,
|
|
|
|
QKeySequence.Save, saveIcon,
|
|
|
|
"Save actual event data.")
|
|
|
|
quitAction = self.createAction("&Quit",
|
|
|
|
QCoreApplication.instance().quit,
|
|
|
|
QKeySequence.Close, quitIcon,
|
|
|
|
"Close event and quit PyLoT")
|
|
|
|
filterAction = self.createAction("&Filter ...", self.filterData,
|
|
|
|
"Ctrl+F", QIcon(":/filter.png"),
|
|
|
|
"""Toggle un-/filtered waveforms
|
|
|
|
to be displayed, according to the
|
|
|
|
desired seismic phase.""", True)
|
|
|
|
filterEditAction = self.createAction("&Filter parameter ...",
|
|
|
|
self.adjustFilterOptions,
|
|
|
|
"Alt+F", QIcon(None),
|
|
|
|
"""Adjust filter parameters.""")
|
|
|
|
selectPAction = self.createAction("&P", self.alterPhase, "Alt+P",
|
|
|
|
QIcon(":/picon.png"),
|
|
|
|
"Toggle P phase.", True)
|
|
|
|
selectSAction = self.createAction("&S", self.alterPhase, "Alt+S",
|
|
|
|
QIcon(":/sicon.png"),
|
|
|
|
"Toggle S phase", True)
|
|
|
|
printAction = self.createAction("&Print event ...",
|
|
|
|
self.printEvent, QKeySequence.Print,
|
|
|
|
QIcon(":/printer.png"),
|
|
|
|
"Print waveform overview.")
|
|
|
|
self.fileMenu = self.menuBar().addMenu('&File')
|
|
|
|
self.fileMenuActions = (openEventAction, saveEventAction, None,
|
|
|
|
quitAction)
|
|
|
|
self.fileMenu.aboutToShow.connect(self.updateFileMenu)
|
2014-12-04 05:13:32 +01:00
|
|
|
|
|
|
|
self.editMenu = self.menuBar().addMenu('&Edit')
|
|
|
|
for action in (filterAction, filterEditAction, None, selectPAction,
|
|
|
|
selectSAction, None, printAction):
|
|
|
|
if action is None:
|
|
|
|
self.editMenu.addSeparator()
|
|
|
|
else:
|
|
|
|
self.editMenu.addAction(action)
|
2014-03-28 05:25:46 +01:00
|
|
|
|
2014-04-01 16:46:10 +02:00
|
|
|
self.eventLabel = QLabel()
|
2014-11-27 10:13:17 +01:00
|
|
|
self.eventLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
|
2014-04-01 16:46:10 +02:00
|
|
|
status = self.statusBar()
|
|
|
|
status.setSizeGripEnabled(False)
|
|
|
|
status.addPermanentWidget(self.eventLabel)
|
2014-12-01 08:40:35 +01:00
|
|
|
status.showMessage("Ready", 500)
|
2014-04-01 16:46:10 +02:00
|
|
|
|
2014-12-01 12:41:13 +01:00
|
|
|
# statLayout = layoutStationButtons(self.getData(), self.getComponent())
|
|
|
|
# dataLayout = self.getDataWidget()
|
2014-03-28 05:25:46 +01:00
|
|
|
|
2014-12-01 12:41:13 +01:00
|
|
|
# maingrid = QGridLayout()
|
|
|
|
# maingrid.setSpacing(10)
|
|
|
|
# maingrid.addLayout(statLayout, 0, 0)
|
|
|
|
# maingrid.addWidget(self.getDataWidget(), 0, 1)
|
|
|
|
# self.setLayout(maingrid)
|
|
|
|
|
|
|
|
def okToContinue(self):
|
|
|
|
if self.dirty:
|
|
|
|
return self.saveData()
|
|
|
|
return True
|
2014-03-28 05:25:46 +01:00
|
|
|
|
2014-07-16 12:06:05 +02:00
|
|
|
def plotData(self):
|
2014-11-26 08:46:16 +01:00
|
|
|
pass #self.data.plotData(self.DataPlot)
|
2014-03-19 12:24:41 +01:00
|
|
|
|
2014-11-28 11:15:49 +01:00
|
|
|
def filterData(self):
|
|
|
|
pass
|
|
|
|
|
2014-11-06 15:07:05 +01:00
|
|
|
def adjustFilterOptions(self):
|
2014-12-04 05:13:32 +01:00
|
|
|
filterOptions = None
|
2014-11-13 11:27:52 +01:00
|
|
|
fstring = "Filter Options ({0})".format(self.getSeismicPhase())
|
|
|
|
filterDlg = FilterOptionsDialog(titleString=fstring,
|
2014-11-06 15:07:05 +01:00
|
|
|
parent=self,
|
2014-11-13 11:27:52 +01:00
|
|
|
filterOptions=self.getFilterOptions())
|
2014-12-01 12:42:50 +01:00
|
|
|
if filterDlg.exec_():
|
|
|
|
filterOptions = filterDlg.getFilterOptions()
|
2014-12-04 05:13:32 +01:00
|
|
|
|
|
|
|
assert isinstance(filterOptions, FilterOptions)
|
2014-12-01 12:42:50 +01:00
|
|
|
self.setFilterOptions(filterOptions)
|
2014-11-13 11:27:52 +01:00
|
|
|
|
|
|
|
def getFilterOptions(self):
|
|
|
|
return self.filteroptions
|
|
|
|
|
|
|
|
def setFilterOptions(self, filterOptions):
|
|
|
|
cases = {'P':self.filterOptionsP,
|
|
|
|
'S':self.filterOptionsS}
|
|
|
|
cases[self.getSeismicPhase()] = filterOptions
|
|
|
|
self.updateFilterOptions()
|
2014-11-06 15:07:05 +01:00
|
|
|
|
2014-03-28 05:25:46 +01:00
|
|
|
def updateFilterOptions(self):
|
2014-10-27 12:04:01 +01:00
|
|
|
try:
|
|
|
|
self.filteroptions = [self.filterOptionsP
|
|
|
|
if not self.seismicPhase == 'S'
|
2014-11-28 11:15:49 +01:00
|
|
|
else self.filterOptionsS][0]
|
2014-11-06 15:07:05 +01:00
|
|
|
except Exception, e:
|
2014-11-28 09:19:16 +01:00
|
|
|
self.updateStatus('Error ...')
|
2014-11-28 11:15:49 +01:00
|
|
|
emsg = QErrorMessage(self)
|
|
|
|
emsg.showMessage('Error: {0}'.format(e))
|
2014-10-27 12:04:01 +01:00
|
|
|
else:
|
2014-11-28 09:19:16 +01:00
|
|
|
self.updateStatus('Filter loaded ...')
|
2014-03-28 22:26:15 +01:00
|
|
|
|
2014-11-13 11:27:52 +01:00
|
|
|
def getSeismicPhase(self):
|
|
|
|
return self.seismicPhase
|
|
|
|
|
2014-11-28 11:15:49 +01:00
|
|
|
def alterPhase(self):
|
|
|
|
pass
|
|
|
|
|
2014-11-13 11:27:52 +01:00
|
|
|
def setSeismicPhase(self, phase):
|
2014-11-28 09:19:16 +01:00
|
|
|
self.seismicPhase = self.seismicPhaseButtonGroup.getValue()
|
2014-11-13 11:27:52 +01:00
|
|
|
|
2014-04-01 16:46:10 +02:00
|
|
|
def updateStatus(self, message):
|
|
|
|
self.statusBar().showMessage(message, 5000)
|
|
|
|
|
2014-11-28 11:15:49 +01:00
|
|
|
def printEvent(self):
|
|
|
|
pass
|
|
|
|
|
2014-12-01 12:41:13 +01:00
|
|
|
def closeEvent(self):
|
|
|
|
return self.saveData()
|
2014-11-28 11:15:49 +01:00
|
|
|
|
2014-03-28 22:26:15 +01:00
|
|
|
def helpHelp(self):
|
2014-06-11 15:19:37 +02:00
|
|
|
if checkurl():
|
2014-07-03 10:18:42 +02:00
|
|
|
form = HelpForm('https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/wiki')
|
2014-06-11 15:19:37 +02:00
|
|
|
else:
|
|
|
|
form = HelpForm(':/help.html')
|
|
|
|
form.show()
|
2014-03-28 22:26:15 +01:00
|
|
|
|
2014-01-10 05:45:03 +01:00
|
|
|
|
2014-03-28 22:26:15 +01:00
|
|
|
def main():
|
2014-11-06 15:07:05 +01:00
|
|
|
# create the Qt application
|
2014-12-01 08:40:35 +01:00
|
|
|
pylot_app = QApplication(sys.argv[0])
|
2014-01-09 10:43:40 +01:00
|
|
|
|
2014-03-28 22:26:15 +01:00
|
|
|
# set Application Information
|
|
|
|
pylot_app.setOrganizationName("Ruhr-University Bochum / MAGS2")
|
|
|
|
pylot_app.setOrganizationDomain("rub.de")
|
|
|
|
pylot_app.setApplicationName("PyLoT")
|
2014-11-28 09:19:16 +01:00
|
|
|
pylot_app.setWindowIcon(QIcon(":/icon.ico"))
|
2014-03-28 22:26:15 +01:00
|
|
|
|
|
|
|
# create the main window
|
|
|
|
pylot_form = MainWindow()
|
2014-01-09 10:43:40 +01:00
|
|
|
|
2014-03-13 13:27:34 +01:00
|
|
|
# Show main window and run the app
|
2014-03-28 22:26:15 +01:00
|
|
|
pylot_form.show()
|
2014-12-01 08:40:35 +01:00
|
|
|
sys.exit(pylot_app.exec_())
|
2014-03-28 22:26:15 +01:00
|
|
|
|
2014-04-11 19:39:29 +02:00
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|