Merge branch 'develop' into feature/refactor

This commit is contained in:
Darius Arnold 2018-04-06 13:53:04 +02:00
commit 1edc745903
30 changed files with 122600 additions and 105397 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.pyc
*~
pylot/RELEASE-VERSION

269
PyLoT.py
View File

@ -75,7 +75,7 @@ from pylot.core.util.dataprocessing import read_metadata, restitute_data
from pylot.core.util.utils import fnConstructor, getLogin, \ from pylot.core.util.utils import fnConstructor, getLogin, \
full_range, readFilterInformation, trim_station_components, check4gaps, make_pen, pick_color_plt, \ full_range, readFilterInformation, trim_station_components, check4gaps, make_pen, pick_color_plt, \
pick_linestyle_plt, remove_underscores, check4doubled, identifyPhaseID, excludeQualityClasses, has_spe, \ pick_linestyle_plt, remove_underscores, check4doubled, identifyPhaseID, excludeQualityClasses, has_spe, \
check4rotated, transform_colors_mpl, transform_colors_mpl_str check4rotated, transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions
from pylot.core.util.event import Event from pylot.core.util.event import Event
from pylot.core.io.location import create_creation_info, create_event from pylot.core.io.location import create_creation_info, create_event
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \ from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
@ -182,25 +182,22 @@ class MainWindow(QMainWindow):
settings.setValue("data/dataRoot", dirname) settings.setValue("data/dataRoot", dirname)
if settings.value('compclass', None) is None: if settings.value('compclass', None) is None:
settings.setValue('compclass', SetChannelComponents()) settings.setValue('compclass', SetChannelComponents())
if settings.value('useGuiFilter') is None:
settings.setValue('useGuiFilter', False)
if settings.value('output/Format', None) is None: if settings.value('output/Format', None) is None:
outformat = QInputDialog.getText(self, outformat = QInputDialog.getText(self,
"Enter output format (*.xml, *.cnv, *.obs):", "Enter output format (*.xml, *.cnv, *.obs):",
"Format") "Format")
settings.setValue("output/Format", outformat) settings.setValue("output/Format", outformat)
if settings.value('autoFilter', None) is None:
settings.setValue('autoFilter', True)
settings.sync() settings.sync()
# setup UI # setup UI
self.setupUi() self.setupUi()
filter_info = readFilterInformation(self._inputs) self.updateFilteroptions()
p_filter = filter_info['P']
s_filter = filter_info['S']
self.filteroptions = {'P': FilterOptions(p_filter['filtertype'],
p_filter['freq'],
p_filter['order']),
'S': FilterOptions(s_filter['filtertype'],
s_filter['freq'],
s_filter['order'])}
self.loc = False self.loc = False
def setupUi(self): def setupUi(self):
@ -270,8 +267,12 @@ class MainWindow(QMainWindow):
s_icon.addPixmap(QPixmap(':/icons/key_S.png')) s_icon.addPixmap(QPixmap(':/icons/key_S.png'))
print_icon = QIcon() print_icon = QIcon()
print_icon.addPixmap(QPixmap(':/icons/printer.png')) print_icon.addPixmap(QPixmap(':/icons/printer.png'))
filter_icon = QIcon() self.filter_icon = QIcon()
filter_icon.addPixmap(QPixmap(':/icons/filter.png')) self.filter_icon.addPixmap(QPixmap(':/icons/filter.png'))
self.filter_icon_p = QIcon()
self.filter_icon_p.addPixmap(QPixmap(':/icons/filter_p.png'))
self.filter_icon_s = QIcon()
self.filter_icon_s.addPixmap(QPixmap(':/icons/filter_s.png'))
z_icon = QIcon() z_icon = QIcon()
z_icon.addPixmap(QPixmap(':/icons/key_Z.png')) z_icon.addPixmap(QPixmap(':/icons/key_Z.png'))
n_icon = QIcon() n_icon = QIcon()
@ -286,6 +287,8 @@ class MainWindow(QMainWindow):
locate_icon.addPixmap(QPixmap(':/icons/locate_button.png')) locate_icon.addPixmap(QPixmap(':/icons/locate_button.png'))
compare_icon = QIcon() compare_icon = QIcon()
compare_icon.addPixmap(QPixmap(':/icons/compare_button.png')) compare_icon.addPixmap(QPixmap(':/icons/compare_button.png'))
qualities_icon = QIcon()
qualities_icon.addPixmap(QPixmap(':/icons/pick_qualities_button.png'))
self.newProjectAction = self.createAction(self, "&New project ...", self.newProjectAction = self.createAction(self, "&New project ...",
self.createNewProject, self.createNewProject,
QKeySequence.New, newIcon, QKeySequence.New, newIcon,
@ -366,15 +369,23 @@ class MainWindow(QMainWindow):
self.setParameter, self.setParameter,
None, paraIcon, None, paraIcon,
"Modify Parameter") "Modify Parameter")
self.filterAction = self.createAction(self, "&Filter ...", self.filterActionP = createAction(parent=self, text='Apply P Filter',
self.filterWaveformData, slot=self.filterP,
"Ctrl+F", filter_icon, icon=self.filter_icon_p,
"""Toggle un-/filtered waveforms tip='Toggle filtered/original'
to be displayed, according to the ' waveforms',
desired seismic phase.""", True) checkable=True,
shortcut='P')
self.filterActionS = createAction(parent=self, text='Apply S Filter',
slot=self.filterS,
icon=self.filter_icon_s,
tip='Toggle filtered/original'
' waveforms',
checkable=True,
shortcut='S')
filterEditAction = self.createAction(self, "&Filter parameter ...", filterEditAction = self.createAction(self, "&Filter parameter ...",
self.adjustFilterOptions, self.adjustFilterOptions,
"Alt+F", filter_icon, "Ctrl+F", self.filter_icon,
"""Adjust filter parameters.""") """Adjust filter parameters.""")
self.inventoryAction = self.createAction(self, "Select &Inventory ...", self.inventoryAction = self.createAction(self, "Select &Inventory ...",
self.get_new_metadata, self.get_new_metadata,
@ -402,6 +413,10 @@ class MainWindow(QMainWindow):
"automatic pick " "automatic pick "
"data.", False) "data.", False)
self.compare_action.setEnabled(False) self.compare_action.setEnabled(False)
self.qualities_action = self.createAction(parent=self, text='Show pick qualitites...',
slot=self.pickQualities, shortcut='Alt+Q',
icon=qualities_icon, tip='Histogram of pick qualities')
self.qualities_action.setEnabled(False)
printAction = self.createAction(self, "&Print event ...", printAction = self.createAction(self, "&Print event ...",
self.show_event_information, QKeySequence.Print, self.show_event_information, QKeySequence.Print,
@ -472,7 +487,7 @@ class MainWindow(QMainWindow):
' the complete project on grid engine.') ' the complete project on grid engine.')
self.auto_pick_sge.setEnabled(False) self.auto_pick_sge.setEnabled(False)
pickActions = (self.auto_tune, self.auto_pick, self.compare_action) pickActions = (self.auto_tune, self.auto_pick, self.compare_action, self.qualities_action)
# pickToolBar = self.addToolBar("PickTools") # pickToolBar = self.addToolBar("PickTools")
# pickToolActions = (selectStation, ) # pickToolActions = (selectStation, )
@ -500,8 +515,8 @@ class MainWindow(QMainWindow):
self.updateFileMenu() self.updateFileMenu()
self.editMenu = self.menuBar().addMenu('&Edit') self.editMenu = self.menuBar().addMenu('&Edit')
editActions = (self.filterAction, filterEditAction, None, editActions = (self.filterActionP, self.filterActionS, filterEditAction, None,
self.selectPAction, self.selectSAction, None, #self.selectPAction, self.selectSAction, None,
self.inventoryAction, self.initMapAction, None, self.inventoryAction, self.initMapAction, None,
prefsEventAction) prefsEventAction)
#printAction) #TODO: print event? #printAction) #TODO: print event?
@ -561,20 +576,29 @@ class MainWindow(QMainWindow):
style = settings.value('style') style = settings.value('style')
self.set_style(style) self.set_style(style)
# add event combo box and ref/test buttons # add event combo box, forward, backward and ref/test buttons
self.eventBox = self.createEventBox() self.eventBox = self.createEventBox()
self.eventBox.setMaxVisibleItems(30) self.eventBox.setMaxVisibleItems(30)
self.eventBox.setEnabled(False) self.eventBox.setEnabled(False)
self.previous_button = QPushButton('<')
self.next_button = QPushButton('>')
self.init_ref_test_buttons() self.init_ref_test_buttons()
self._event_layout = QHBoxLayout() self._event_layout = QHBoxLayout()
self._event_layout.addWidget(QLabel('Event: ')) self._event_layout.addWidget(QLabel('Event: '))
self._event_layout.addWidget(self.eventBox) self._event_layout.addWidget(self.eventBox)
self._event_layout.addWidget(self.previous_button)
self._event_layout.addWidget(self.next_button)
self._event_layout.addWidget(self.ref_event_button) self._event_layout.addWidget(self.ref_event_button)
self._event_layout.addWidget(self.test_event_button) self._event_layout.addWidget(self.test_event_button)
self._event_layout.setStretch(1, 1) # set stretch of item 1 to 1 self._event_layout.setStretch(1, 1) # set stretch of item 1 to 1
self._main_layout.addLayout(self._event_layout) self._main_layout.addLayout(self._event_layout)
self.eventBox.activated.connect(self.refreshEvents) self.eventBox.activated.connect(self.refreshEvents)
self.previous_button.clicked.connect(self.previous_event)
self.next_button.clicked.connect(self.next_event)
self.previous_button.setEnabled(False)
self.next_button.setEnabled(False)
# add main tab widget # add main tab widget
self.tabs = QTabWidget(self) self.tabs = QTabWidget(self)
self._main_layout.addWidget(self.tabs) self._main_layout.addWidget(self.tabs)
@ -650,6 +674,8 @@ class MainWindow(QMainWindow):
''' '''
self.ref_event_button = QtGui.QPushButton('Tune') self.ref_event_button = QtGui.QPushButton('Tune')
self.test_event_button = QtGui.QPushButton('Test') self.test_event_button = QtGui.QPushButton('Test')
self.ref_event_button.setMinimumWidth(100)
self.test_event_button.setMinimumWidth(100)
self.ref_event_button.setToolTip('Set manual picks of current ' + self.ref_event_button.setToolTip('Set manual picks of current ' +
'event as reference picks for autopicker tuning.') 'event as reference picks for autopicker tuning.')
self.test_event_button.setToolTip('Set manual picks of current ' + self.test_event_button.setToolTip('Set manual picks of current ' +
@ -763,6 +789,17 @@ class MainWindow(QMainWindow):
def metadata(self, value): def metadata(self, value):
self._metadata = value self._metadata = value
def updateFilteroptions(self):
filter_info = readFilterInformation(self._inputs)
p_filter = filter_info['P']
s_filter = filter_info['S']
self.filteroptions = {'P': FilterOptions(p_filter['filtertype'],
p_filter['freq'],
p_filter['order']),
'S': FilterOptions(s_filter['filtertype'],
s_filter['freq'],
s_filter['order'])}
def updateFileMenu(self): def updateFileMenu(self):
self.fileMenu.clear() self.fileMenu.clear()
@ -1004,7 +1041,8 @@ class MainWindow(QMainWindow):
and len(item.split('/')[-1].split('.')) == 3 and len(item.split('/')[-1].split('.')) == 3
and len(item.split('/')[-1]) == 12] and len(item.split('/')[-1]) == 12]
if not eventlist: if not eventlist:
print('No events found! Expected structure for event folders: [evID.DOY.YR]') print('No events found! Expected structure for event folders: [eEVID.DOY.YR],\n'
' e.g. eventID=1, doy=2, yr=2016: e0001.002.16')
return return
else: else:
return return
@ -1100,9 +1138,16 @@ class MainWindow(QMainWindow):
Initiate GUI widgets in case of changed or newly added events. Initiate GUI widgets in case of changed or newly added events.
''' '''
nitems = self.eventBox.count() nitems = self.eventBox.count()
if len(self.project.eventlist) == 0: is_data = self.data_check()
if len(self.project.eventlist) == 0 or not is_data:
print('No events to init.') print('No events to init.')
self.clearWaveformDataPlot() self.clearWaveformDataPlot()
if not is_data:
new_path, modifypath = self.user_modify_path('Event folders not found! ')
if modifypath:
self.modify_project_path(new_path)
self.init_events(True)
self.setDirty(True)
return return
self.eventBox.setEnabled(True) self.eventBox.setEnabled(True)
self.fill_eventbox() self.fill_eventbox()
@ -1113,6 +1158,31 @@ class MainWindow(QMainWindow):
self.refreshEvents() self.refreshEvents()
tabindex = self.tabs.currentIndex() tabindex = self.tabs.currentIndex()
def user_modify_path(self, reason=''):
dialog = QtGui.QInputDialog(parent=self)
new_path, executed = dialog.getText(self, 'Change Project rootpath',
'{}Rename project path {}:'.format(reason, self.project.rootpath))
return new_path, executed
def data_check(self):
paths_exist = [os.path.exists(event.path) for event in self.project.eventlist]
if all(paths_exist):
return True
else:
info_str = ''
for event, path_exists in zip(self.project.eventlist, paths_exist):
info_str += '\n{} exists: {}'.format(event.path, path_exists)
print('Unable to find certain event paths:{}'.format(info_str))
return False
def modify_project_path(self, new_rootpath):
self.project.rootpath = new_rootpath
for event in self.project.eventlist:
event.rootpath = new_rootpath
event.path = os.path.join(event.rootpath, event.datapath, event.database, event.pylot_id)
event.path = event.path.replace('\\', '/')
event.path = event.path.replace('//', '/')
def fill_eventbox(self, event=None, eventBox=None, select_events='all'): def fill_eventbox(self, event=None, eventBox=None, select_events='all'):
''' '''
(Re)fill the selected eventBox (type = QtGui.QComboBox). (Re)fill the selected eventBox (type = QtGui.QComboBox).
@ -1353,6 +1423,9 @@ class MainWindow(QMainWindow):
self.cmpw.refresh_tooltips() self.cmpw.refresh_tooltips()
self.cmpw.show() self.cmpw.show()
def pickQualities(self):
return
def compareMulti(self): def compareMulti(self):
if not self.compareoptions: if not self.compareoptions:
return return
@ -1401,7 +1474,8 @@ class MainWindow(QMainWindow):
return None return None
def getStime(self): def getStime(self):
return self._stime if self.get_data():
return full_range(self.get_data().getWFData())[0]
def addActions(self, target, actions): def addActions(self, target, actions):
for action in actions: for action in actions:
@ -1470,6 +1544,26 @@ class MainWindow(QMainWindow):
if self.tap: if self.tap:
self.tap.fill_eventbox() self.tap.fill_eventbox()
def checkEventButtons(self):
if self.eventBox.currentIndex() == 0:
prev_state = False
else:
prev_state = True
if self.eventBox.currentIndex() == len(self.project.eventlist) - 1:
next_state = False
else:
next_state = True
self.previous_button.setEnabled(prev_state)
self.next_button.setEnabled(next_state)
def previous_event(self):
self.eventBox.setCurrentIndex(self.eventBox.currentIndex() - 1)
self.eventBox.activated.emit(-1)
def next_event(self):
self.eventBox.setCurrentIndex(self.eventBox.currentIndex() + 1)
self.eventBox.activated.emit(+1)
def refreshEvents(self): def refreshEvents(self):
''' '''
Refresh GUI when events get changed. Refresh GUI when events get changed.
@ -1480,6 +1574,7 @@ class MainWindow(QMainWindow):
# array_map refresh is not necessary when changing event in waveform plot tab, # array_map refresh is not necessary when changing event in waveform plot tab,
# but gets necessary when switching from one to another after changing an event. # but gets necessary when switching from one to another after changing an event.
self._eventChanged = [True, True] self._eventChanged = [True, True]
self.checkEventButtons()
self.refreshTabs() self.refreshTabs()
def refreshTabs(self): def refreshTabs(self):
@ -1554,18 +1649,38 @@ class MainWindow(QMainWindow):
# else: # else:
# ans = False # ans = False
self.fnames = self.getWFFnames_from_eventbox() self.fnames = self.getWFFnames_from_eventbox()
self.data.setWFData(self.fnames) self.data.setWFData(self.fnames,
wfdat = self.data.getWFData() # all available streams checkRotated=True,
# remove possible underscores in station names metadata=self.metadata)
wfdat = remove_underscores(wfdat)
# check for gaps and doubled channels def check_plot_quantity(self):
check4gaps(wfdat) settings = QSettings()
check4doubled(wfdat) nth_sample = settings.value("nth_sample") if settings.value("nth_sample") else 1
# check for stations with rotated components npts_max = 1e6
wfdat = check4rotated(wfdat, self.metadata, verbosity=0) npts = self.get_npts_to_plot()
# trim station components to same start value npts2plot = npts/nth_sample
trim_station_components(wfdat, trim_start=True, trim_end=False) if npts2plot < npts_max:
self._stime = full_range(self.get_data().getWFData())[0] return
nth_sample_new = int(np.ceil(npts/npts_max))
message = "You are about to plot a huge dataset with {npts} datapoints. With a current setting of " \
"nth_sample = {nth_sample} a total of {npts2plot} points will be plotted which is more " \
"than the maximum setting of {npts_max}. " \
"PyLoT recommends to raise nth_sample from {nth_sample} to {nth_sample_new}. Continue?"
ans = QMessageBox.question(self, self.tr("Optimize plot performance..."),
self.tr(message.format(npts=npts,
nth_sample=nth_sample,
npts_max=npts_max,
nth_sample_new=nth_sample_new,
npts2plot=npts2plot)),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes)
if ans == QMessageBox.Yes:
settings.setValue("nth_sample", nth_sample_new)
settings.sync()
def get_npts_to_plot(self):
return sum(trace.stats.npts for trace in self.data.getWFData())
def connectWFplotEvents(self): def connectWFplotEvents(self):
''' '''
@ -1661,8 +1776,10 @@ class MainWindow(QMainWindow):
if event.pylot_picks: if event.pylot_picks:
self.drawPicks(picktype='manual') self.drawPicks(picktype='manual')
self.locateEvent.setEnabled(True) self.locateEvent.setEnabled(True)
self.qualities_action.setEnabled(True)
if event.pylot_autopicks: if event.pylot_autopicks:
self.drawPicks(picktype='auto') self.drawPicks(picktype='auto')
self.qualities_action.setEnabled(True)
if True in self.comparable.values(): if True in self.comparable.values():
self.compare_action.setEnabled(True) self.compare_action.setEnabled(True)
self.draw() self.draw()
@ -1724,18 +1841,20 @@ class MainWindow(QMainWindow):
self.disableSaveEventAction() self.disableSaveEventAction()
self.draw() self.draw()
def plotWaveformDataThread(self): def plotWaveformDataThread(self, filter=True):
''' '''
Open a modal thread to plot current waveform data. Open a modal thread to plot current waveform data.
''' '''
self.check_plot_quantity()
self.clearWaveformDataPlot() self.clearWaveformDataPlot()
self.wfp_thread = Thread(self, self.plotWaveformData, self.wfp_thread = Thread(self, self.plotWaveformData,
arg=filter,
progressText='Plotting waveform data...', progressText='Plotting waveform data...',
pb_widget=self.mainProgressBarWidget) pb_widget=self.mainProgressBarWidget)
self.wfp_thread.finished.connect(self.finishWaveformDataPlot) self.wfp_thread.finished.connect(self.finishWaveformDataPlot)
self.wfp_thread.start() self.wfp_thread.start()
def plotWaveformData(self): def plotWaveformData(self, filter=True):
''' '''
Plot waveform data to current plotWidget. Plot waveform data to current plotWidget.
''' '''
@ -1747,6 +1866,10 @@ class MainWindow(QMainWindow):
comp = self.getComponent() comp = self.getComponent()
title = 'section: {0} components'.format(zne_text[comp]) title = 'section: {0} components'.format(zne_text[comp])
wfst = self.get_data().getWFData() wfst = self.get_data().getWFData()
if self.filterActionP.isChecked() and filter:
self.filterWaveformData(plot=False, phase='P')
elif self.filterActionS.isChecked() and filter:
self.filterWaveformData(plot=False, phase='S')
# wfst = self.get_data().getWFData().select(component=comp) # wfst = self.get_data().getWFData().select(component=comp)
# wfst += self.get_data().getWFData().select(component=alter_comp) # wfst += self.get_data().getWFData().select(component=alter_comp)
plotWidget = self.getPlotWidget() plotWidget = self.getPlotWidget()
@ -1786,18 +1909,51 @@ class MainWindow(QMainWindow):
def pushFilterWF(self, param_args): def pushFilterWF(self, param_args):
self.get_data().filterWFData(param_args) self.get_data().filterWFData(param_args)
def filterWaveformData(self): def filterP(self):
self.filterActionS.setChecked(False)
if self.filterActionP.isChecked():
self.filterWaveformData(phase='P')
else:
self.resetWFData()
def filterS(self):
self.filterActionP.setChecked(False)
if self.filterActionS.isChecked():
self.filterWaveformData(phase='S')
else:
self.resetWFData()
def resetWFData(self):
self.get_data().resetWFData()
self.plotWaveformDataThread()
def filterWaveformData(self, plot=True, phase=None):
if not self.get_current_event():
return
if self.get_data(): if self.get_data():
if self.getFilterOptions() and self.filterAction.isChecked(): if not phase:
kwargs = self.getFilterOptions()[self.getSeismicPhase()].parseFilterOptions() if self.filterActionP.isChecked():
phase = 'P'
elif self.filterActionS.isChecked():
phase = 'S'
if self.getFilterOptions():
if (phase == 'P' and self.filterActionP.isChecked()) or (phase == 'S' and self.filterActionS.isChecked()):
kwargs = self.getFilterOptions()[phase].parseFilterOptions()
self.pushFilterWF(kwargs) self.pushFilterWF(kwargs)
elif self.filterAction.isChecked(): else:
self.get_data().resetWFData()
elif self.filterActionP.isChecked() or self.filterActionS.isChecked():
self.adjustFilterOptions() self.adjustFilterOptions()
else: else:
self.get_data().resetWFData() self.get_data().resetWFData()
self.plotWaveformDataThread() if plot:
self.drawPicks() self.plotWaveformDataThread(filter=False)
self.draw() #self.drawPicks()
#self.draw()
def getAutoFilteroptions(self, phase):
return getAutoFilteroptions(phase, self._inputs)
def adjustFilterOptions(self): def adjustFilterOptions(self):
fstring = "Filter Options" fstring = "Filter Options"
@ -1806,10 +1962,11 @@ class MainWindow(QMainWindow):
if self.filterDlg.exec_(): if self.filterDlg.exec_():
filteroptions = self.filterDlg.getFilterOptions() filteroptions = self.filterDlg.getFilterOptions()
self.setFilterOptions(filteroptions) self.setFilterOptions(filteroptions)
if self.filterAction.isChecked(): if self.filterActionP.isChecked() or self.filterActionS.isChecked():
kwargs = self.getFilterOptions()[self.getSeismicPhase()].parseFilterOptions() kwargs = self.getFilterOptions()[self.getSeismicPhase()].parseFilterOptions()
self.pushFilterWF(kwargs) self.pushFilterWF(kwargs)
self.plotWaveformDataThread() self.plotWaveformDataThread()
return True
def checkFilterOptions(self): def checkFilterOptions(self):
fstring = "Filter Options" fstring = "Filter Options"
@ -1886,7 +2043,7 @@ class MainWindow(QMainWindow):
# '[{0}: {1} Hz]'.format( # '[{0}: {1} Hz]'.format(
# self.getFilterOptions().getFilterType(), # self.getFilterOptions().getFilterType(),
# self.getFilterOptions().getFreq())) # self.getFilterOptions().getFreq()))
# if self.filterAction.isChecked(): # if self.filterActionP.isChecked() or self.filterActionS.isChecked():
# self.filterWaveformData() # self.filterWaveformData()
def getSeismicPhase(self): def getSeismicPhase(self):
@ -1934,7 +2091,7 @@ class MainWindow(QMainWindow):
if self._shift: if self._shift:
factor = {'up': 1. / 2., factor = {'up': 1. / 2.,
'down': 2.} 'down': 2.}
xlims = self.dataPlot.getXLims() xlims = self.dataPlot.getXLims(self.dataPlot.axes[0])
xdiff = xlims[1] - xlims[0] xdiff = xlims[1] - xlims[0]
xdiff *= factor[button] xdiff *= factor[button]
xl = x - 0.5 * xdiff xl = x - 0.5 * xdiff
@ -1943,7 +2100,7 @@ class MainWindow(QMainWindow):
xl = self._max_xlims[0] xl = self._max_xlims[0]
if xr > self._max_xlims[1]: if xr > self._max_xlims[1]:
xr = self._max_xlims[1] xr = self._max_xlims[1]
self.dataPlot.setXLims((xl, xr)) self.dataPlot.setXLims(self.dataPlot.axes[0], (xl, xr))
self.dataPlot.draw() self.dataPlot.draw()
def pickOnStation(self, gui_event): def pickOnStation(self, gui_event):
@ -1970,7 +2127,7 @@ class MainWindow(QMainWindow):
if not station: if not station:
return return
self.update_status('picking on station {0}'.format(station)) self.update_status('picking on station {0}'.format(station))
data = self.get_data().getWFData() data = self.get_data().getOriginalWFData().copy()
event = self.get_current_event() event = self.get_current_event()
pickDlg = PickDlg(self, parameter=self._inputs, pickDlg = PickDlg(self, parameter=self._inputs,
data=data.select(station=station), data=data.select(station=station),
@ -1979,6 +2136,9 @@ class MainWindow(QMainWindow):
autopicks=self.getPicksOnStation(station, 'auto'), autopicks=self.getPicksOnStation(station, 'auto'),
metadata=self.metadata, event=event, metadata=self.metadata, event=event,
filteroptions=self.filteroptions) filteroptions=self.filteroptions)
if self.filterActionP.isChecked() or self.filterActionS.isChecked():
pickDlg.currentPhase = self.getSeismicPhase()
pickDlg.filterWFData()
pickDlg.nextStation.setChecked(nextStation) pickDlg.nextStation.setChecked(nextStation)
if pickDlg.exec_(): if pickDlg.exec_():
if pickDlg._dirty: if pickDlg._dirty:
@ -2315,7 +2475,7 @@ class MainWindow(QMainWindow):
if self.pg: if self.pg:
pw = self.getPlotWidget().plotWidget pw = self.getPlotWidget().plotWidget
else: else:
ax = self.getPlotWidget().axes ax = self.getPlotWidget().axes[0]
ylims = np.array([-.5, +.5]) + plotID ylims = np.array([-.5, +.5]) + plotID
stat_picks = self.getPicks(type=picktype)[station] stat_picks = self.getPicks(type=picktype)[station]
@ -2385,7 +2545,7 @@ class MainWindow(QMainWindow):
else: else:
if picktype == 'manual': if picktype == 'manual':
linestyle_mpp, width_mpp = pick_linestyle_plt(picktype, 'mpp') linestyle_mpp, width_mpp = pick_linestyle_plt(picktype, 'mpp')
color = pick_color_plt(picktype, phase, quality) color = pick_color_plt(picktype, self.getPhaseID(phase), quality)
if picks['epp'] and picks['lpp']: if picks['epp'] and picks['lpp']:
ax.fill_between([epp, lpp], ylims[0], ylims[1], ax.fill_between([epp, lpp], ylims[0], ylims[1],
alpha=.25, color=color, label='EPP, LPP') alpha=.25, color=color, label='EPP, LPP')
@ -2927,6 +3087,7 @@ class MainWindow(QMainWindow):
if hasattr(self.project, 'parameter'): if hasattr(self.project, 'parameter'):
if self.project.parameter: if self.project.parameter:
self._inputs = self.project.parameter self._inputs = self.project.parameter
self.updateFilteroptions()
self.tabs.setCurrentIndex(0) # implemented to prevent double-loading of waveform data self.tabs.setCurrentIndex(0) # implemented to prevent double-loading of waveform data
self.init_events(new=True) self.init_events(new=True)
self.setDirty(False) self.setDirty(False)

View File

@ -338,6 +338,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
local_mag = LocalMagnitude(corr_dat, evt, local_mag = LocalMagnitude(corr_dat, evt,
parameter.get('sstop'), parameter.get('sstop'),
WAscaling, True, iplot) WAscaling, True, iplot)
# update pick with local magnitude property values
for stats, amplitude in local_mag.amplitudes.items(): for stats, amplitude in local_mag.amplitudes.items():
picks[stats]['S']['Ao'] = amplitude.generic_amplitude picks[stats]['S']['Ao'] = amplitude.generic_amplitude
print("Local station magnitudes scaled with:") print("Local station magnitudes scaled with:")
@ -412,6 +413,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
local_mag = LocalMagnitude(corr_dat, evt, local_mag = LocalMagnitude(corr_dat, evt,
parameter.get('sstop'), parameter.get('sstop'),
WAscaling, True, iplot) WAscaling, True, iplot)
# update pick with local magnitude property values
for stats, amplitude in local_mag.amplitudes.items(): for stats, amplitude in local_mag.amplitudes.items():
if stats in picks: if stats in picks:
picks[stats]['S']['Ao'] = amplitude.generic_amplitude picks[stats]['S']['Ao'] = amplitude.generic_amplitude
@ -496,7 +498,7 @@ if __name__ == "__main__":
help='''full path to the file containing the input help='''full path to the file containing the input
parameters for autoPyLoT''') parameters for autoPyLoT''')
parser.add_argument('-p', '-P', '--iplot', type=int, parser.add_argument('-p', '-P', '--iplot', type=int,
action='store', action='store', default=0,
help='''optional, logical variable for plotting: 0=none, 1=partial, 2=all''') help='''optional, logical variable for plotting: 0=none, 1=partial, 2=all''')
parser.add_argument('-f', '-F', '--fnames', type=str, parser.add_argument('-f', '-F', '--fnames', type=str,
action='store', action='store',

View File

@ -29,10 +29,12 @@
<file>icons/map.png</file> <file>icons/map.png</file>
<file>icons/openloc.png</file> <file>icons/openloc.png</file>
<file>icons/compare_button.png</file> <file>icons/compare_button.png</file>
<file>icons/pick_qualities_button.png</file>
<file>icons/locate_button.png</file> <file>icons/locate_button.png</file>
<file>icons/Matlab_PILOT_icon.png</file> <file>icons/Matlab_PILOT_icon.png</file>
<file>icons/printer.png</file> <file>icons/printer.png</file>
<file>icons/delete.png</file> <file>icons/delete.png</file>
<file>icons/key_A.png</file>
<file>icons/key_E.png</file> <file>icons/key_E.png</file>
<file>icons/key_N.png</file> <file>icons/key_N.png</file>
<file>icons/key_P.png</file> <file>icons/key_P.png</file>
@ -45,6 +47,8 @@
<file>icons/key_W.png</file> <file>icons/key_W.png</file>
<file>icons/key_Z.png</file> <file>icons/key_Z.png</file>
<file>icons/filter.png</file> <file>icons/filter.png</file>
<file>icons/filter_p.png</file>
<file>icons/filter_s.png</file>
<file>icons/sync.png</file> <file>icons/sync.png</file>
<file>icons/zoom_0.png</file> <file>icons/zoom_0.png</file>
<file>icons/zoom_in.png</file> <file>icons/zoom_in.png</file>

BIN
icons/filter_p.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
icons/filter_s.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
icons/key_A.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,6 @@ from pylot.core.util.utils import common_range, fit_curve
from scipy import integrate, signal from scipy import integrate, signal
from scipy.optimize import curve_fit from scipy.optimize import curve_fit
def richter_magnitude_scaling(delta): def richter_magnitude_scaling(delta):
distance = np.array([0, 10, 20, 25, 30, 35, 40, 45, 50, 60, 70, 75, 85, 90, 100, 110, distance = np.array([0, 10, 20, 25, 30, 35, 40, 45, 50, 60, 70, 75, 85, 90, 100, 110,
120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 230, 240, 250, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 230, 240, 250,
@ -133,7 +132,7 @@ class Magnitude(object):
station_count=len(self.magnitudes), station_count=len(self.magnitudes),
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap) azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
else: else:
# no saling necessary # no scaling necessary
mag = ope.Magnitude( mag = ope.Magnitude(
mag=np.median([M.mag for M in self.magnitudes.values()]), mag=np.median([M.mag for M in self.magnitudes.values()]),
magnitude_type=self.type, magnitude_type=self.type,
@ -233,17 +232,33 @@ class LocalMagnitude(Magnitude):
# check for plot flag (for debugging only) # check for plot flag (for debugging only)
fig = None fig = None
if iplot > 1: if iplot > 1:
st.plot()
fig = plt.figure() fig = plt.figure()
ax = fig.add_subplot(111) ax = fig.add_subplot(211)
ax.plot(th, st[0].data, 'k')
ax.plot(th, sqH) ax.plot(th, sqH)
ax.plot(th[iwin], sqH[iwin], 'g') ax.plot(th[iwin], sqH[iwin], 'g')
ax.plot([t0, t0], [0, max(sqH)], 'r', linewidth=2) ax.plot([t0 - stime, t0 - stime], [0, max(sqH)], 'r', linewidth=2)
ax.title( ax.set_title('Station %s, Channel %s, RMS Horizontal Trace, '
'Station %s, RMS Horizontal Traces, WA-peak-to-peak=%4.1f mm' \ 'WA-peak-to-peak=%6.3f mm' % (st[0].stats.station,
% (st[0].stats.station, wapp)) st[0].stats.channel,
wapp))
ax.set_xlabel('Time [s]') ax.set_xlabel('Time [s]')
ax.set_ylabel('Displacement [mm]') ax.set_ylabel('Displacement [mm]')
ax = fig.add_subplot(212)
ax.plot(th, st[1].data, 'k')
ax.plot(th, sqH)
ax.plot(th[iwin], sqH[iwin], 'g')
ax.plot([t0 - stime, t0 - stime], [0, max(sqH)], 'r', linewidth=2)
ax.set_title('Channel %s, RMS Horizontal Trace, '
'WA-peak-to-peak=%6.3f mm' % (st[1].stats.channel,
wapp))
ax.set_xlabel('Time [s]')
ax.set_ylabel('Displacement [mm]')
fig.show()
try: input()
except SyntaxError: pass
plt.close(fig)
return wapp, fig return wapp, fig
@ -251,6 +266,10 @@ class LocalMagnitude(Magnitude):
for a in self.arrivals: for a in self.arrivals:
if a.phase not in 'sS': if a.phase not in 'sS':
continue continue
# make sure calculating Ml only from reliable onsets
# NLLoc: time_weight = 0 => do not use onset!
if a.time_weight == 0:
continue
pick = a.pick_id.get_referred_object() pick = a.pick_id.get_referred_object()
station = pick.waveform_id.station_code station = pick.waveform_id.station_code
wf = select_for_phase(self.stream.select( wf = select_for_phase(self.stream.select(
@ -349,6 +368,10 @@ class MomentMagnitude(Magnitude):
for a in self.arrivals: for a in self.arrivals:
if a.phase not in 'pP': if a.phase not in 'pP':
continue continue
# make sure calculating Mo only from reliable onsets
# NLLoc: time_weight = 0 => do not use onset!
if a.time_weight == 0:
continue
pick = a.pick_id.get_referred_object() pick = a.pick_id.get_referred_object()
station = pick.waveform_id.station_code station = pick.waveform_id.station_code
scopy = self.stream.copy() scopy = self.stream.copy()

View File

@ -12,7 +12,8 @@ from pylot.core.io.phases import readPILOTEvent, picks_from_picksdict, \
picksdict_from_pilot, merge_picks picksdict_from_pilot, merge_picks
from pylot.core.util.errors import FormatError, OverwriteError from pylot.core.util.errors import FormatError, OverwriteError
from pylot.core.util.event import Event from pylot.core.util.event import Event
from pylot.core.util.utils import fnConstructor, full_range from pylot.core.util.utils import fnConstructor, full_range, remove_underscores, check4gaps, check4doubled, \
check4rotated, trim_station_components
import pylot.core.loc.velest as velest import pylot.core.loc.velest as velest
@ -99,6 +100,11 @@ class Data(object):
return self return self
def getPicksStr(self): def getPicksStr(self):
"""
Return picks in event data
:return: picks seperated by newlines
:rtype: str
"""
picks_str = '' picks_str = ''
for pick in self.get_evt_data().picks: for pick in self.get_evt_data().picks:
picks_str += str(pick) + '\n' picks_str += str(pick) + '\n'
@ -106,18 +112,11 @@ class Data(object):
def getParent(self): def getParent(self):
""" """
Get PySide.QtGui.QWidget parent object
:return:
""" """
return self._parent return self._parent
def isNew(self): def isNew(self):
"""
:return:
"""
return self._new return self._new
def setNew(self): def setNew(self):
@ -125,9 +124,9 @@ class Data(object):
def getCutTimes(self): def getCutTimes(self):
""" """
Returns earliest start and latest end of all waveform data
:return: minimum start time and maximum end time as a tuple
:return: :rtype: (UTCDateTime, UTCDateTime)
""" """
if self.cuttimes is None: if self.cuttimes is None:
self.updateCutTimes() self.updateCutTimes()
@ -135,22 +134,34 @@ class Data(object):
def updateCutTimes(self): def updateCutTimes(self):
""" """
Update cuttimes to contain earliest start and latest end time
of all waveform data
:rtype: None
""" """
self.cuttimes = full_range(self.getWFData()) self.cuttimes = full_range(self.getWFData())
def getEventFileName(self): def getEventFileName(self):
"""
:return:
"""
ID = self.getID() ID = self.getID()
# handle forbidden filenames especially on windows systems # handle forbidden filenames especially on windows systems
return fnConstructor(str(ID)) return fnConstructor(str(ID))
def checkEvent(self, event, fcheck, forceOverwrite=False): def checkEvent(self, event, fcheck, forceOverwrite=False):
"""
Check information in supplied event and own event and replace own
information with supplied information if own information not exiisting
or forced by forceOverwrite
:param event: Event that supplies information for comparison
:type event: pylot.core.util.event.Event
:param fcheck: check and delete existing information
can be a str or a list of strings of ['manual', 'auto', 'origin', 'magnitude']
:type fcheck: str, [str]
:param forceOverwrite: Set to true to force overwrite own information. If false,
supplied information from event is only used if there is no own information in that
category (given in fcheck: manual, auto, origin, magnitude)
:type forceOverwrite: bool
:return:
:rtype: None
"""
if 'origin' in fcheck: if 'origin' in fcheck:
self.replaceOrigin(event, forceOverwrite) self.replaceOrigin(event, forceOverwrite)
if 'magnitude' in fcheck: if 'magnitude' in fcheck:
@ -161,18 +172,47 @@ class Data(object):
self.replacePicks(event, 'manual') self.replacePicks(event, 'manual')
def replaceOrigin(self, event, forceOverwrite=False): def replaceOrigin(self, event, forceOverwrite=False):
"""
Replace own origin with the one supplied in event if own origin is not
existing or forced by forceOverwrite = True
:param event: Event that supplies information for comparison
:type event: pylot.core.util.event.Event
:param forceOverwrite: always replace own information with supplied one if true
:type forceOverwrite: bool
:return:
:rtype: None
"""
if self.get_evt_data().origins or forceOverwrite: if self.get_evt_data().origins or forceOverwrite:
if event.origins: if event.origins:
print("Found origin, replace it by new origin.") print("Found origin, replace it by new origin.")
event.origins = self.get_evt_data().origins event.origins = self.get_evt_data().origins
def replaceMagnitude(self, event, forceOverwrite=False): def replaceMagnitude(self, event, forceOverwrite=False):
"""
Replace own magnitude with the one supplied in event if own magnitude is not
existing or forced by forceOverwrite = True
:param event: Event that supplies information for comparison
:type event: pylot.core.util.event.Event
:param forceOverwrite: always replace own information with supplied one if true
:type forceOverwrite: bool
:return:
:rtype: None
"""
if self.get_evt_data().magnitudes or forceOverwrite: if self.get_evt_data().magnitudes or forceOverwrite:
if event.magnitudes: if event.magnitudes:
print("Found magnitude, replace it by new magnitude") print("Found magnitude, replace it by new magnitude")
event.magnitudes = self.get_evt_data().magnitudes event.magnitudes = self.get_evt_data().magnitudes
def replacePicks(self, event, picktype): def replacePicks(self, event, picktype):
"""
Replace own picks with the one in event
:param event: Event that supplies information for comparison
:type event: pylot.core.util.event.Event
:param picktype: 'auto' or 'manual' picks
:type picktype: str
:return:
:rtype: None
"""
checkflag = 0 checkflag = 0
picks = event.picks picks = event.picks
# remove existing picks # remove existing picks
@ -189,10 +229,10 @@ class Data(object):
picks.append(pick) picks.append(pick)
def exportEvent(self, fnout, fnext='.xml', fcheck='auto', upperErrors=None): def exportEvent(self, fnout, fnext='.xml', fcheck='auto', upperErrors=None):
""" """
Export event to file
:param fnout: basename of file :param fnout: basename of file
:param fnext: file extension :param fnext: file extension, xml, cnv, obs
:param fcheck: check and delete existing information :param fcheck: check and delete existing information
can be a str or a list of strings of ['manual', 'auto', 'origin', 'magnitude'] can be a str or a list of strings of ['manual', 'auto', 'origin', 'magnitude']
""" """
@ -304,17 +344,13 @@ class Data(object):
def getComp(self): def getComp(self):
""" """
Get component (ZNE)
:return:
""" """
return self.comp return self.comp
def getID(self): def getID(self):
""" """
Get unique resource id
:return:
""" """
try: try:
return self.evtdata.get('resource_id').id return self.evtdata.get('resource_id').id
@ -323,16 +359,20 @@ class Data(object):
def filterWFData(self, kwargs): def filterWFData(self, kwargs):
""" """
Filter waveform data
:param kwargs: :param kwargs: arguments to pass through to filter function
""" """
self.getWFData().filter(**kwargs) data = self.getWFData()
data.detrend('linear')
data.taper(0.02, type='cosine')
data.filter(**kwargs)
self.dirty = True self.dirty = True
def setWFData(self, fnames): def setWFData(self, fnames, checkRotated=False, metadata=None):
""" """
Clear current waveform data and set given waveform data
:param fnames: :param fnames: waveform data names to append
:type fnames: list
""" """
self.wfdata = Stream() self.wfdata = Stream()
self.wforiginal = None self.wforiginal = None
@ -340,14 +380,31 @@ class Data(object):
self.appendWFData(fnames) self.appendWFData(fnames)
else: else:
return False return False
# various pre-processing steps:
# remove possible underscores in station names
self.wfdata = remove_underscores(self.wfdata)
# check for gaps and doubled channels
check4gaps(self.wfdata)
check4doubled(self.wfdata)
# check for stations with rotated components
if checkRotated and metadata is not None:
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
# trim station components to same start value
trim_station_components(self.wfdata, trim_start=True, trim_end=False)
# make a copy of original data
self.wforiginal = self.getWFData().copy() self.wforiginal = self.getWFData().copy()
self.dirty = False self.dirty = False
return True return True
def appendWFData(self, fnames): def appendWFData(self, fnames):
""" """
Read waveform data from fnames and append it to current wf data
:param fnames: :param fnames: waveform data to append
:type fnames: list
""" """
assert isinstance(fnames, list), "input parameter 'fnames' is " \ assert isinstance(fnames, list), "input parameter 'fnames' is " \
"supposed to be of type 'list' " \ "supposed to be of type 'list' " \
@ -372,54 +429,45 @@ class Data(object):
print(warnmsg) print(warnmsg)
def getWFData(self): def getWFData(self):
"""
:return:
"""
return self.wfdata return self.wfdata
def getOriginalWFData(self): def getOriginalWFData(self):
"""
:return:
"""
return self.wforiginal return self.wforiginal
def resetWFData(self): def resetWFData(self):
""" """
Set waveform data to original waveform data
""" """
if self.getOriginalWFData():
self.wfdata = self.getOriginalWFData().copy() self.wfdata = self.getOriginalWFData().copy()
else:
self.wfdata = Stream()
self.dirty = False self.dirty = False
def resetPicks(self): def resetPicks(self):
""" """
Clear all picks from event
""" """
self.get_evt_data().picks = [] self.get_evt_data().picks = []
def get_evt_data(self): def get_evt_data(self):
"""
:return:
"""
return self.evtdata return self.evtdata
def setEvtData(self, event): def setEvtData(self, event):
self.evtdata = event self.evtdata = event
def applyEVTData(self, data, typ='pick', authority_id='rub'): def applyEVTData(self, data, typ='pick', authority_id='rub'):
""" """
Either takes an `obspy.core.event.Event` object and applies all new
:param data: information on the event to the actual data if typ is 'event or
:param typ: creates ObsPy pick objects and append it to the picks list from the
:param authority_id: PyLoT dictionary contain all picks if type is pick
:param data: data to apply, either picks or complete event
:type data:
:param typ: which event data to apply, 'pick' or 'event'
:type typ: str
:param authority_id: (currently unused)
:type: str
:raise OverwriteError: :raise OverwriteError:
""" """

View File

@ -1,5 +1,10 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import numpy as np
"""
Default parameters used for picking
"""
defaults = {'rootpath': {'type': str, defaults = {'rootpath': {'type': str,
'tooltip': 'project path', 'tooltip': 'project path',
@ -74,11 +79,15 @@ defaults = {'rootpath': {'type': str,
'vp': {'type': float, 'vp': {'type': float,
'tooltip': 'average P-wave velocity', 'tooltip': 'average P-wave velocity',
'value': 3530., 'value': 3530.,
'min': 0.,
'max': np.inf,
'namestring': 'P-velocity'}, 'namestring': 'P-velocity'},
'rho': {'type': float, 'rho': {'type': float,
'tooltip': 'average rock density [kg/m^3]', 'tooltip': 'average rock density [kg/m^3]',
'value': 2500., 'value': 2500.,
'min': 0.,
'max': np.inf,
'namestring': 'Density'}, 'namestring': 'Density'},
'Qp': {'type': (float, float), 'Qp': {'type': (float, float),
@ -90,42 +99,58 @@ defaults = {'rootpath': {'type': str,
'tooltip': 'start time [s] for calculating CF for P-picking (if TauPy:' 'tooltip': 'start time [s] for calculating CF for P-picking (if TauPy:'
' seconds relative to estimated onset)', ' seconds relative to estimated onset)',
'value': 15.0, 'value': 15.0,
'min': -np.inf,
'max': np.inf,
'namestring': 'P start'}, 'namestring': 'P start'},
'pstop': {'type': float, 'pstop': {'type': float,
'tooltip': 'end time [s] for calculating CF for P-picking (if TauPy:' 'tooltip': 'end time [s] for calculating CF for P-picking (if TauPy:'
' seconds relative to estimated onset)', ' seconds relative to estimated onset)',
'value': 60.0, 'value': 60.0,
'min': -np.inf,
'max': np.inf,
'namestring': 'P stop'}, 'namestring': 'P stop'},
'sstart': {'type': float, 'sstart': {'type': float,
'tooltip': 'start time [s] relative to P-onset for calculating CF for S-picking', 'tooltip': 'start time [s] relative to P-onset for calculating CF for S-picking',
'value': -1.0, 'value': -1.0,
'min': -np.inf,
'max': np.inf,
'namestring': 'S start'}, 'namestring': 'S start'},
'sstop': {'type': float, 'sstop': {'type': float,
'tooltip': 'end time [s] after P-onset for calculating CF for S-picking', 'tooltip': 'end time [s] after P-onset for calculating CF for S-picking',
'value': 10.0, 'value': 10.0,
'min': -np.inf,
'max': np.inf,
'namestring': 'S stop'}, 'namestring': 'S stop'},
'bpz1': {'type': (float, float), 'bpz1': {'type': (float, float),
'tooltip': 'lower/upper corner freq. of first band pass filter Z-comp. [Hz]', 'tooltip': 'lower/upper corner freq. of first band pass filter Z-comp. [Hz]',
'value': (2, 20), 'value': (2, 20),
'min': (0., 0.),
'max': (np.inf, np.inf),
'namestring': ('Z-bandpass 1', 'Lower', 'Upper')}, 'namestring': ('Z-bandpass 1', 'Lower', 'Upper')},
'bpz2': {'type': (float, float), 'bpz2': {'type': (float, float),
'tooltip': 'lower/upper corner freq. of second band pass filter Z-comp. [Hz]', 'tooltip': 'lower/upper corner freq. of second band pass filter Z-comp. [Hz]',
'value': (2, 30), 'value': (2, 30),
'min': (0., 0.),
'max': (np.inf, np.inf),
'namestring': ('Z-bandpass 2', 'Lower', 'Upper')}, 'namestring': ('Z-bandpass 2', 'Lower', 'Upper')},
'bph1': {'type': (float, float), 'bph1': {'type': (float, float),
'tooltip': 'lower/upper corner freq. of first band pass filter H-comp. [Hz]', 'tooltip': 'lower/upper corner freq. of first band pass filter H-comp. [Hz]',
'value': (2, 15), 'value': (2, 15),
'min': (0., 0.),
'max': (np.inf, np.inf),
'namestring': ('H-bandpass 1', 'Lower', 'Upper')}, 'namestring': ('H-bandpass 1', 'Lower', 'Upper')},
'bph2': {'type': (float, float), 'bph2': {'type': (float, float),
'tooltip': 'lower/upper corner freq. of second band pass filter z-comp. [Hz]', 'tooltip': 'lower/upper corner freq. of second band pass filter z-comp. [Hz]',
'value': (2, 20), 'value': (2, 20),
'min': (0., 0.),
'max': (np.inf, np.inf),
'namestring': ('H-bandpass 2', 'Lower', 'Upper')}, 'namestring': ('H-bandpass 2', 'Lower', 'Upper')},
'algoP': {'type': str, 'algoP': {'type': str,
@ -136,76 +161,106 @@ defaults = {'rootpath': {'type': str,
'tlta': {'type': float, 'tlta': {'type': float,
'tooltip': 'for HOS-/AR-AIC-picker, length of LTA window [s]', 'tooltip': 'for HOS-/AR-AIC-picker, length of LTA window [s]',
'value': 7.0, 'value': 7.0,
'min': 0.,
'max': np.inf,
'namestring': 'LTA window'}, 'namestring': 'LTA window'},
'hosorder': {'type': int, 'hosorder': {'type': int,
'tooltip': 'for HOS-picker, order of Higher Order Statistics', 'tooltip': 'for HOS-picker, order of Higher Order Statistics',
'value': 4, 'value': 4,
'min': 0,
'max': np.inf,
'namestring': 'HOS order'}, 'namestring': 'HOS order'},
'Parorder': {'type': int, 'Parorder': {'type': int,
'tooltip': 'for AR-picker, order of AR process of Z-component', 'tooltip': 'for AR-picker, order of AR process of Z-component',
'value': 2, 'value': 2,
'min': 0,
'max': np.inf,
'namestring': 'AR order P'}, 'namestring': 'AR order P'},
'tdet1z': {'type': float, 'tdet1z': {'type': float,
'tooltip': 'for AR-picker, length of AR determination window [s] for Z-component, 1st pick', 'tooltip': 'for AR-picker, length of AR determination window [s] for Z-component, 1st pick',
'value': 1.2, 'value': 1.2,
'min': 0.,
'max': np.inf,
'namestring': 'AR det. window Z 1'}, 'namestring': 'AR det. window Z 1'},
'tpred1z': {'type': float, 'tpred1z': {'type': float,
'tooltip': 'for AR-picker, length of AR prediction window [s] for Z-component, 1st pick', 'tooltip': 'for AR-picker, length of AR prediction window [s] for Z-component, 1st pick',
'value': 0.4, 'value': 0.4,
'min': 0.,
'max': np.inf,
'namestring': 'AR pred. window Z 1'}, 'namestring': 'AR pred. window Z 1'},
'tdet2z': {'type': float, 'tdet2z': {'type': float,
'tooltip': 'for AR-picker, length of AR determination window [s] for Z-component, 2nd pick', 'tooltip': 'for AR-picker, length of AR determination window [s] for Z-component, 2nd pick',
'value': 0.6, 'value': 0.6,
'min': 0.,
'max': np.inf,
'namestring': 'AR det. window Z 2'}, 'namestring': 'AR det. window Z 2'},
'tpred2z': {'type': float, 'tpred2z': {'type': float,
'tooltip': 'for AR-picker, length of AR prediction window [s] for Z-component, 2nd pick', 'tooltip': 'for AR-picker, length of AR prediction window [s] for Z-component, 2nd pick',
'value': 0.2, 'value': 0.2,
'min': 0.,
'max': np.inf,
'namestring': 'AR pred. window Z 2'}, 'namestring': 'AR pred. window Z 2'},
'addnoise': {'type': float, 'addnoise': {'type': float,
'tooltip': 'add noise to seismogram for stable AR prediction', 'tooltip': 'add noise to seismogram for stable AR prediction',
'value': 0.001, 'value': 0.001,
'min': 0.,
'max': np.inf,
'namestring': 'Add noise'}, 'namestring': 'Add noise'},
'tsnrz': {'type': (float, float, float, float), 'tsnrz': {'type': (float, float, float, float),
'tooltip': 'for HOS/AR, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]', 'tooltip': 'for HOS/AR, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]',
'value': (3, 0.1, 0.5, 1.0), 'value': (3, 0.1, 0.5, 1.0),
'min': (0., 0., 0., 0.),
'max': (np.inf, np.inf, np.inf, np.inf),
'namestring': ('SNR windows P', 'Noise', 'Safety', 'Signal', 'Slope')}, 'namestring': ('SNR windows P', 'Noise', 'Safety', 'Signal', 'Slope')},
'pickwinP': {'type': float, 'pickwinP': {'type': float,
'tooltip': 'for initial AIC pick, length of P-pick window [s]', 'tooltip': 'for initial AIC pick, length of P-pick window [s]',
'value': 3.0, 'value': 3.0,
'min': 0.,
'max': np.inf,
'namestring': 'AIC window P'}, 'namestring': 'AIC window P'},
'Precalcwin': {'type': float, 'Precalcwin': {'type': float,
'tooltip': 'for HOS/AR, window length [s] for recalculation of CF (relative to 1st pick)', 'tooltip': 'for HOS/AR, window length [s] for recalculation of CF (relative to 1st pick)',
'value': 6.0, 'value': 6.0,
'min': 0.,
'max': np.inf,
'namestring': 'Recal. window P'}, 'namestring': 'Recal. window P'},
'aictsmooth': {'type': float, 'aictsmooth': {'type': float,
'tooltip': 'for HOS/AR, take average of samples for smoothing of AIC-function [s]', 'tooltip': 'for HOS/AR, take average of samples for smoothing of AIC-function [s]',
'value': 0.2, 'value': 0.2,
'min': 0.,
'max': np.inf,
'namestring': 'AIC smooth P'}, 'namestring': 'AIC smooth P'},
'tsmoothP': {'type': float, 'tsmoothP': {'type': float,
'tooltip': 'for HOS/AR, take average of samples in this time window for smoothing CF [s]', 'tooltip': 'for HOS/AR, take average of samples in this time window for smoothing CF [s]',
'value': 0.1, 'value': 0.1,
'min': 0.,
'max': np.inf,
'namestring': 'CF smooth P'}, 'namestring': 'CF smooth P'},
'ausP': {'type': float, 'ausP': {'type': float,
'tooltip': 'for HOS/AR, artificial uplift of samples (aus) of CF (P)', 'tooltip': 'for HOS/AR, artificial uplift of samples (aus) of CF (P)',
'value': 0.001, 'value': 0.001,
'min': 0.,
'max': np.inf,
'namestring': 'Artificial uplift P'}, 'namestring': 'Artificial uplift P'},
'nfacP': {'type': float, 'nfacP': {'type': float,
'tooltip': 'for HOS/AR, noise factor for noise level determination (P)', 'tooltip': 'for HOS/AR, noise factor for noise level determination (P)',
'value': 1.3, 'value': 1.3,
'min': 0.,
'max': np.inf,
'namestring': 'Noise factor P'}, 'namestring': 'Noise factor P'},
'algoS': {'type': str, 'algoS': {'type': str,
@ -216,61 +271,85 @@ defaults = {'rootpath': {'type': str,
'tdet1h': {'type': float, 'tdet1h': {'type': float,
'tooltip': 'for HOS/AR, length of AR-determination window [s], H-components, 1st pick', 'tooltip': 'for HOS/AR, length of AR-determination window [s], H-components, 1st pick',
'value': 0.8, 'value': 0.8,
'min': 0.,
'max': np.inf,
'namestring': 'AR det. window H 1'}, 'namestring': 'AR det. window H 1'},
'tpred1h': {'type': float, 'tpred1h': {'type': float,
'tooltip': 'for HOS/AR, length of AR-prediction window [s], H-components, 1st pick', 'tooltip': 'for HOS/AR, length of AR-prediction window [s], H-components, 1st pick',
'value': 0.4, 'value': 0.4,
'min': 0.,
'max': np.inf,
'namestring': 'AR pred. window H 1'}, 'namestring': 'AR pred. window H 1'},
'tdet2h': {'type': float, 'tdet2h': {'type': float,
'tooltip': 'for HOS/AR, length of AR-determinaton window [s], H-components, 2nd pick', 'tooltip': 'for HOS/AR, length of AR-determinaton window [s], H-components, 2nd pick',
'value': 0.6, 'value': 0.6,
'min': 0.,
'max': np.inf,
'namestring': 'AR det. window H 2'}, 'namestring': 'AR det. window H 2'},
'tpred2h': {'type': float, 'tpred2h': {'type': float,
'tooltip': 'for HOS/AR, length of AR-prediction window [s], H-components, 2nd pick', 'tooltip': 'for HOS/AR, length of AR-prediction window [s], H-components, 2nd pick',
'value': 0.3, 'value': 0.3,
'min': 0.,
'max': np.inf,
'namestring': 'AR pred. window H 2'}, 'namestring': 'AR pred. window H 2'},
'Sarorder': {'type': int, 'Sarorder': {'type': int,
'tooltip': 'for AR-picker, order of AR process of H-components', 'tooltip': 'for AR-picker, order of AR process of H-components',
'value': 4, 'value': 4,
'min': 0,
'max': np.inf,
'namestring': 'AR order S'}, 'namestring': 'AR order S'},
'Srecalcwin': {'type': float, 'Srecalcwin': {'type': float,
'tooltip': 'for AR-picker, window length [s] for recalculation of CF (2nd pick) (H)', 'tooltip': 'for AR-picker, window length [s] for recalculation of CF (2nd pick) (H)',
'value': 5.0, 'value': 5.0,
'min': 0.,
'max': np.inf,
'namestring': 'Recal. window S'}, 'namestring': 'Recal. window S'},
'pickwinS': {'type': float, 'pickwinS': {'type': float,
'tooltip': 'for initial AIC pick, length of S-pick window [s]', 'tooltip': 'for initial AIC pick, length of S-pick window [s]',
'value': 3.0, 'value': 3.0,
'min': 0.,
'max': np.inf,
'namestring': 'AIC window S'}, 'namestring': 'AIC window S'},
'tsnrh': {'type': (float, float, float, float), 'tsnrh': {'type': (float, float, float, float),
'tooltip': 'for ARH/AR3, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]', 'tooltip': 'for ARH/AR3, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]',
'value': (2, 0.2, 1.5, 0.5), 'value': (2, 0.2, 1.5, 0.5),
'min': (0., 0., 0., 0.),
'max': (np.inf, np.inf, np.inf, np.inf),
'namestring': ('SNR windows S', 'Noise', 'Safety', 'Signal', 'Slope')}, 'namestring': ('SNR windows S', 'Noise', 'Safety', 'Signal', 'Slope')},
'aictsmoothS': {'type': float, 'aictsmoothS': {'type': float,
'tooltip': 'for AIC-picker, take average of samples in this time window for smoothing of AIC-function [s]', 'tooltip': 'for AIC-picker, take average of samples in this time window for smoothing of AIC-function [s]',
'value': 0.5, 'value': 0.5,
'min': 0.,
'max': np.inf,
'namestring': 'AIC smooth S'}, 'namestring': 'AIC smooth S'},
'tsmoothS': {'type': float, 'tsmoothS': {'type': float,
'tooltip': 'for AR-picker, take average of samples for smoothing CF [s] (S)', 'tooltip': 'for AR-picker, take average of samples for smoothing CF [s] (S)',
'value': 0.7, 'value': 0.7,
'min': 0.,
'max': np.inf,
'namestring': 'CF smooth S'}, 'namestring': 'CF smooth S'},
'ausS': {'type': float, 'ausS': {'type': float,
'tooltip': 'for HOS/AR, artificial uplift of samples (aus) of CF (S)', 'tooltip': 'for HOS/AR, artificial uplift of samples (aus) of CF (S)',
'value': 0.9, 'value': 0.9,
'min': 0.,
'max': np.inf,
'namestring': 'Artificial uplift S'}, 'namestring': 'Artificial uplift S'},
'nfacS': {'type': float, 'nfacS': {'type': float,
'tooltip': 'for AR-picker, noise factor for noise level determination (S)', 'tooltip': 'for AR-picker, noise factor for noise level determination (S)',
'value': 1.5, 'value': 1.5,
'min': 0.,
'max': np.inf,
'namestring': 'Noise factor S'}, 'namestring': 'Noise factor S'},
'minfmweight': {'type': int, 'minfmweight': {'type': int,
@ -281,103 +360,143 @@ defaults = {'rootpath': {'type': str,
'minFMSNR': {'type': float, 'minFMSNR': {'type': float,
'tooltip': 'miniumum required SNR for first-motion determination', 'tooltip': 'miniumum required SNR for first-motion determination',
'value': 2., 'value': 2.,
'min': 0.,
'max': np.inf,
'namestring': 'Min SNR'}, 'namestring': 'Min SNR'},
'fmpickwin': {'type': float, 'fmpickwin': {'type': float,
'tooltip': 'pick window [s] around P onset for calculating zero crossings', 'tooltip': 'pick window [s] around P onset for calculating zero crossings',
'value': 0.2, 'value': 0.2,
'min': 0.,
'max': np.inf,
'namestring': 'Zero crossings window'}, 'namestring': 'Zero crossings window'},
'timeerrorsP': {'type': (float, float, float, float), 'timeerrorsP': {'type': (float, float, float, float),
'tooltip': 'discrete time errors [s] corresponding to picking weights [0 1 2 3] for P', 'tooltip': 'discrete time errors [s] corresponding to picking weights [0 1 2 3] for P',
'value': (0.01, 0.02, 0.04, 0.08), 'value': (0.01, 0.02, 0.04, 0.08),
'min': (0., 0., 0., 0.),
'max': (np.inf, np.inf, np.inf, np.inf),
'namestring': ('Time errors P', '0', '1', '2', '3')}, 'namestring': ('Time errors P', '0', '1', '2', '3')},
'timeerrorsS': {'type': (float, float, float, float), 'timeerrorsS': {'type': (float, float, float, float),
'tooltip': 'discrete time errors [s] corresponding to picking weights [0 1 2 3] for S', 'tooltip': 'discrete time errors [s] corresponding to picking weights [0 1 2 3] for S',
'value': (0.04, 0.08, 0.16, 0.32), 'value': (0.04, 0.08, 0.16, 0.32),
'min': (0., 0., 0., 0.),
'max': (np.inf, np.inf, np.inf, np.inf),
'namestring': ('Time errors S', '0', '1', '2', '3')}, 'namestring': ('Time errors S', '0', '1', '2', '3')},
'minAICPslope': {'type': float, 'minAICPslope': {'type': float,
'tooltip': 'below this slope [counts/s] the initial P pick is rejected', 'tooltip': 'below this slope [counts/s] the initial P pick is rejected',
'value': 0.8, 'value': 0.8,
'min': 0.,
'max': np.inf,
'namestring': 'Min. slope P'}, 'namestring': 'Min. slope P'},
'minAICPSNR': {'type': float, 'minAICPSNR': {'type': float,
'tooltip': 'below this SNR the initial P pick is rejected', 'tooltip': 'below this SNR the initial P pick is rejected',
'value': 1.1, 'value': 1.1,
'min': 0.,
'max': np.inf,
'namestring': 'Min. SNR P'}, 'namestring': 'Min. SNR P'},
'minAICSslope': {'type': float, 'minAICSslope': {'type': float,
'tooltip': 'below this slope [counts/s] the initial S pick is rejected', 'tooltip': 'below this slope [counts/s] the initial S pick is rejected',
'value': 1., 'value': 1.,
'min': 0.,
'max': np.inf,
'namestring': 'Min. slope S'}, 'namestring': 'Min. slope S'},
'minAICSSNR': {'type': float, 'minAICSSNR': {'type': float,
'tooltip': 'below this SNR the initial S pick is rejected', 'tooltip': 'below this SNR the initial S pick is rejected',
'value': 1.5, 'value': 1.5,
'min': 0.,
'max': np.inf,
'namestring': 'Min. SNR S'}, 'namestring': 'Min. SNR S'},
'minsiglength': {'type': float, 'minsiglength': {'type': float,
'tooltip': 'length of signal part for which amplitudes must exceed noiselevel [s]', 'tooltip': 'length of signal part for which amplitudes must exceed noiselevel [s]',
'value': 1., 'value': 1.,
'min': 0.,
'max': np.inf,
'namestring': 'Min. signal length'}, 'namestring': 'Min. signal length'},
'noisefactor': {'type': float, 'noisefactor': {'type': float,
'tooltip': 'noiselevel*noisefactor=threshold', 'tooltip': 'noiselevel*noisefactor=threshold',
'value': 1.0, 'value': 1.0,
'min': 0.,
'max': np.inf,
'namestring': 'Noise factor'}, 'namestring': 'Noise factor'},
'minpercent': {'type': float, 'minpercent': {'type': float,
'tooltip': 'required percentage of amplitudes exceeding threshold', 'tooltip': 'required percentage of amplitudes exceeding threshold',
'value': 10., 'value': 10.,
'min': 0.,
'max': np.inf,
'namestring': 'Min amplitude [%]'}, 'namestring': 'Min amplitude [%]'},
'zfac': {'type': float, 'zfac': {'type': float,
'tooltip': 'P-amplitude must exceed at least zfac times RMS-S amplitude', 'tooltip': 'P-amplitude must exceed at least zfac times RMS-S amplitude',
'value': 1.5, 'value': 1.5,
'min': 0.,
'max': np.inf,
'namestring': 'Z factor'}, 'namestring': 'Z factor'},
'mdttolerance': {'type': float, 'mdttolerance': {'type': float,
'tooltip': 'maximum allowed deviation of P picks from median [s]', 'tooltip': 'maximum allowed deviation of P picks from median [s]',
'value': 6.0, 'value': 6.0,
'min': 0.,
'max': np.inf,
'namestring': 'Median tolerance'}, 'namestring': 'Median tolerance'},
'wdttolerance': {'type': float, 'wdttolerance': {'type': float,
'tooltip': 'maximum allowed deviation from Wadati-diagram', 'tooltip': 'maximum allowed deviation from Wadati-diagram',
'value': 1.0, 'value': 1.0,
'min': 0.,
'max': np.inf,
'namestring': 'Wadati tolerance'}, 'namestring': 'Wadati tolerance'},
'jackfactor': {'type': float, 'jackfactor': {'type': float,
'tooltip': 'pick is removed if the variance of the subgroup with the pick removed is larger than the mean variance of all subgroups times safety factor', 'tooltip': 'pick is removed if the variance of the subgroup with the pick removed is larger than the mean variance of all subgroups times safety factor',
'value': 5.0, 'value': 5.0,
'min': 0.,
'max': np.inf,
'namestring': 'Jackknife safety factor'}, 'namestring': 'Jackknife safety factor'},
'WAscaling': {'type': (float, float, float), 'WAscaling': {'type': (float, float, float),
'tooltip': 'Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] \ 'tooltip': 'Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] \
If zeros are set, original Richter magnitude is calculated!', If zeros are set, original Richter magnitude is calculated!',
'value': (0., 0., 0.), 'value': (0., 0., 0.),
'min': (0., 0., 0.),
'max': (np.inf, np.inf, np.inf),
'namestring': ('Wood-Anderson scaling', '', '', '')}, 'namestring': ('Wood-Anderson scaling', '', '', '')},
'magscaling': {'type': (float, float), 'magscaling': {'type': (float, float),
'tooltip': 'Scaling relation for derived local magnitude [a*Ml+b]. \ 'tooltip': 'Scaling relation for derived local magnitude [a*Ml+b]. \
If zeros are set, no scaling of network magnitude is applied!', If zeros are set, no scaling of network magnitude is applied!',
'value': (0., 0.), 'value': (0., 0.),
'min': (0., 0.),
'max': (np.inf, np.inf),
'namestring': ('Local mag. scaling', '', '')}, 'namestring': ('Local mag. scaling', '', '')},
'minfreq': {'type': (float, float), 'minfreq': {'type': (float, float),
'tooltip': 'Lower filter frequency [P, S]', 'tooltip': 'Lower filter frequency [P, S]',
'value': (1.0, 1.0), 'value': (1.0, 1.0),
'min': (0., 0.),
'max': (np.inf, np.inf),
'namestring': ('Lower freq.', 'P', 'S')}, 'namestring': ('Lower freq.', 'P', 'S')},
'maxfreq': {'type': (float, float), 'maxfreq': {'type': (float, float),
'tooltip': 'Upper filter frequency [P, S]', 'tooltip': 'Upper filter frequency [P, S]',
'value': (10.0, 10.0), 'value': (10.0, 10.0),
'min': (0., 0.),
'max': (np.inf, np.inf),
'namestring': ('Upper freq.', 'P', 'S')}, 'namestring': ('Upper freq.', 'P', 'S')},
'filter_order': {'type': (int, int), 'filter_order': {'type': (int, int),
'tooltip': 'filter order [P, S]', 'tooltip': 'filter order [P, S]',
'value': (2, 2), 'value': (2, 2),
'min': (0, 0),
'max': (np.inf, np.inf),
'namestring': ('Order', 'P', 'S')}, 'namestring': ('Order', 'P', 'S')},
'filter_type': {'type': (str, str), 'filter_type': {'type': (str, str),

View File

@ -70,6 +70,7 @@ class PylotParameter(object):
# Set default values of parameter names # Set default values of parameter names
def __init_default_paras(self): def __init_default_paras(self):
"""set default values of parameter names"""
parameters = default_parameters.defaults parameters = default_parameters.defaults
self.__defaults = parameters self.__defaults = parameters
@ -92,6 +93,11 @@ class PylotParameter(object):
return None return None
def __setitem__(self, key, value): def __setitem__(self, key, value):
try:
value = self.check_range(value, self.__defaults[key]['max'], self.__defaults[key]['min'])
except KeyError:
# no min/max values in defaults
pass
self.__parameter[key] = value self.__parameter[key] = value
def __delitem__(self, key): def __delitem__(self, key):
@ -104,15 +110,34 @@ class PylotParameter(object):
return len(self.__parameter.keys()) return len(self.__parameter.keys())
def iteritems(self): def iteritems(self):
"""
Iterate over parameters
:return: key, value tupel
:rtype:
"""
for key, value in self.__parameter.items(): for key, value in self.__parameter.items():
yield key, value yield key, value
def hasParam(self, parameter): def hasParam(self, parameter):
"""
Check if parameter is in keys
:param parameter: parameter to look for in keys
:type parameter:
:return:
:rtype: bool
"""
if parameter in self.__parameter.keys(): if parameter in self.__parameter.keys():
return True return True
return False return False
def get(self, *args): def get(self, *args):
"""
Get first available parameter in args
:param args:
:type args:
:return:
:rtype:
"""
try: try:
for param in args: for param in args:
try: try:
@ -128,15 +153,35 @@ class PylotParameter(object):
raise ParameterError(e) raise ParameterError(e)
def get_defaults(self): def get_defaults(self):
"""
get default parameters
:return:
:rtype: dict
"""
return self.__defaults return self.__defaults
def get_main_para_names(self): def get_main_para_names(self):
"""
Get main parameter names
:return: list of keys available in parameters
:rtype:
"""
return self._settings_main return self._settings_main
def get_special_para_names(self): def get_special_para_names(self):
"""
Get pick parameter names
:return: list of keys available in parameters
:rtype:
"""
return self._settings_special_pick return self._settings_special_pick
def get_all_para_names(self): def get_all_para_names(self):
"""
Get all parameter names
:return:
:rtype: list
"""
all_names = [] all_names = []
all_names += self.get_main_para_names()['dirs'] all_names += self.get_main_para_names()['dirs']
all_names += self.get_main_para_names()['nlloc'] all_names += self.get_main_para_names()['nlloc']
@ -150,7 +195,43 @@ class PylotParameter(object):
all_names += self.get_special_para_names()['quality'] all_names += self.get_special_para_names()['quality']
return all_names return all_names
@staticmethod
def check_range(value, max_value, min_value):
"""
Check if value is within the min/max values defined in default_parameters. Works for tuple and scalar values.
:param value: Value to be checked against min/max range
:param max_value: Maximum allowed value, tuple or scalar
:param min_value: Minimum allowed value, tuple or scalar
:return: value tuple/scalar clamped to the valid range
>>> checkRange(-5, 10, 0)
0
>>> checkRange((-5., 100.), (10., 10.), (0., 0.))
(0.0, 10.0)
"""
try:
# Try handling tuples by comparing their elements
comparisons = [(a > b) for a, b in zip(value, max_value)]
if True in comparisons:
value = tuple(max_value[i] if comp else value[i] for i, comp in enumerate(comparisons))
comparisons = [(a < b) for a, b in zip(value, min_value)]
if True in comparisons:
value = tuple(min_value[i] if comp else value[i] for i, comp in enumerate(comparisons))
except TypeError:
value = max(min_value, min(max_value, value))
return value
def checkValue(self, param, value): def checkValue(self, param, value):
"""
Check type of value against expected type of param.
Print warning message if type check fails
:param param:
:type param:
:param value:
:type value:
:return:
:rtype:
"""
is_type = type(value) is_type = type(value)
expect_type = self.get_defaults()[param]['type'] expect_type = self.get_defaults()[param]['type']
if not is_type == expect_type and not is_type == tuple: if not is_type == expect_type and not is_type == tuple:
@ -159,9 +240,25 @@ class PylotParameter(object):
print(Warning(message)) print(Warning(message))
def setParamKV(self, param, value): def setParamKV(self, param, value):
"""
set parameter param to value
:param param:
:type param:
:param value:
:type value:
:return:
:rtype: None
"""
self.__setitem__(param, value) self.__setitem__(param, value)
def setParam(self, **kwargs): def setParam(self, **kwargs):
"""
Set multiple parameters
:param kwargs:
:type kwargs:
:return:
:rtype: None
"""
for key in kwargs: for key in kwargs:
self.__setitem__(key, kwargs[key]) self.__setitem__(key, kwargs[key])
@ -170,11 +267,23 @@ class PylotParameter(object):
print('ParameterError:\n non-existent parameter %s' % errmsg) print('ParameterError:\n non-existent parameter %s' % errmsg)
def reset_defaults(self): def reset_defaults(self):
"""
Reset current parameters to default parameters
:return:
:rtype: None
"""
defaults = self.get_defaults() defaults = self.get_defaults()
for param in defaults: for param in defaults:
self.setParamKV(param, defaults[param]['value']) self.setParamKV(param, defaults[param]['value'])
def from_file(self, fnin=None): def from_file(self, fnin=None):
"""
read parameters from file and set values to read values
:param fnin: filename
:type fnin:
:return:
:rtype: None
"""
if not fnin: if not fnin:
if self.__filename is not None: if self.__filename is not None:
fnin = self.__filename fnin = self.__filename
@ -221,6 +330,13 @@ class PylotParameter(object):
self.__parameter = self._parFileCont self.__parameter = self._parFileCont
def export2File(self, fnout): def export2File(self, fnout):
"""
Export parameters to file
:param fnout: Filename of export file
:type fnout: str
:return:
:rtype:
"""
fid_out = open(fnout, 'w') fid_out = open(fnout, 'w')
lines = [] lines = []
# for key, value in self.iteritems(): # for key, value in self.iteritems():
@ -257,6 +373,19 @@ class PylotParameter(object):
'quality assessment', None) 'quality assessment', None)
def write_section(self, fid, names, title, separator): def write_section(self, fid, names, title, separator):
"""
write a section of parameters to file
:param fid: File object to write to
:type fid:
:param names: which parameter names to write to file
:type names:
:param title: title of section
:type title: str
:param separator: section separator, written at start of section
:type separator: str
:return:
:rtype:
"""
if separator: if separator:
fid.write(separator) fid.write(separator)
fid.write('#{}#\n'.format(title)) fid.write('#{}#\n'.format(title))
@ -341,7 +470,9 @@ class FilterOptions(object):
def parseFilterOptions(self): def parseFilterOptions(self):
if self: if self:
robject = {'type': self.getFilterType(), 'corners': self.getOrder()} robject = {'type': self.getFilterType(),
'corners': self.getOrder(),
'zerophase': False}
if not self.getFilterType() in ['highpass', 'lowpass']: if not self.getFilterType() in ['highpass', 'lowpass']:
robject['freqmin'] = self.getFreq()[0] robject['freqmin'] = self.getFreq()[0]
robject['freqmax'] = self.getFreq()[1] robject['freqmax'] = self.getFreq()[1]

View File

@ -54,7 +54,7 @@ def create_arrival(pickresID, cinfo, phase, azimuth=None, dist=None):
def create_creation_info(agency_id=None, creation_time=None, author=None): def create_creation_info(agency_id=None, creation_time=None, author=None):
''' '''
get creation info of obspy event
:param agency_id: :param agency_id:
:param creation_time: :param creation_time:
:param author: :param author:
@ -197,9 +197,9 @@ def create_pick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
def create_resourceID(timetohash, restype, authority_id=None, hrstr=None): def create_resourceID(timetohash, restype, authority_id=None, hrstr=None):
''' '''
create unique resource id
:param timetohash: :param timetohash: event origin time to hash
:type timetohash :type timetohash: class: `~obspy.core.utcdatetime.UTCDateTime` object
:param restype: type of the resource, e.g. 'orig', 'earthquake' ... :param restype: type of the resource, e.g. 'orig', 'earthquake' ...
:type restype: str :type restype: str
:param authority_id: name of the institution carrying out the processing :param authority_id: name of the institution carrying out the processing

View File

@ -16,7 +16,8 @@ from pylot.core.io.inputs import PylotParameter
from pylot.core.io.location import create_event, \ from pylot.core.io.location import create_event, \
create_magnitude create_magnitude
from pylot.core.pick.utils import select_for_phase from pylot.core.pick.utils import select_for_phase
from pylot.core.util.utils import getOwner, full_range, four_digits from pylot.core.util.utils import getOwner, full_range, four_digits, transformFilteroptions2String, \
transformFilterString4Export, backtransformFilterString
def add_amplitudes(event, amplitudes): def add_amplitudes(event, amplitudes):
@ -118,6 +119,13 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id='RUB', **kwargs):
def picksdict_from_pilot(fn): def picksdict_from_pilot(fn):
"""
Create pick dictionary from matlab file
:param fn: matlab file
:type fn:
:return: pick dictionary
:rtype: dict
"""
from pylot.core.util.defaults import TIMEERROR_DEFAULTS from pylot.core.util.defaults import TIMEERROR_DEFAULTS
picks = dict() picks = dict()
phases_pilot = sio.loadmat(fn) phases_pilot = sio.loadmat(fn)
@ -147,6 +155,13 @@ def picksdict_from_pilot(fn):
def stations_from_pilot(stat_array): def stations_from_pilot(stat_array):
"""
Create stations list from pilot station array
:param stat_array:
:type stat_array:
:return:
:rtype: list
"""
stations = list() stations = list()
cur_stat = None cur_stat = None
for stat in stat_array: for stat in stat_array:
@ -164,6 +179,13 @@ def stations_from_pilot(stat_array):
def convert_pilot_times(time_array): def convert_pilot_times(time_array):
"""
Convert pilot times to UTCDateTimes
:param time_array: pilot times
:type time_array:
:return:
:rtype:
"""
times = [int(time) for time in time_array] times = [int(time) for time in time_array]
microseconds = int((time_array[-1] - times[-1]) * 1e6) microseconds = int((time_array[-1] - times[-1]) * 1e6)
times.append(microseconds) times.append(microseconds)
@ -171,6 +193,13 @@ def convert_pilot_times(time_array):
def picksdict_from_obs(fn): def picksdict_from_obs(fn):
"""
create pick dictionary from obs file
:param fn: filename
:type fn:
:return:
:rtype:
"""
picks = dict() picks = dict()
station_name = str() station_name = str()
for line in open(fn, 'r'): for line in open(fn, 'r'):
@ -207,6 +236,10 @@ def picksdict_from_picks(evt):
network = pick.waveform_id.network_code network = pick.waveform_id.network_code
mpp = pick.time mpp = pick.time
spe = pick.time_errors.uncertainty spe = pick.time_errors.uncertainty
if pick.filter_id:
filter_id = backtransformFilterString(str(pick.filter_id.id))
else:
filter_id = None
try: try:
picker = str(pick.method_id) picker = str(pick.method_id)
if picker.startswith('smi:local/'): if picker.startswith('smi:local/'):
@ -222,10 +255,15 @@ def picksdict_from_picks(evt):
lpp = mpp + pick.time_errors.upper_uncertainty lpp = mpp + pick.time_errors.upper_uncertainty
epp = mpp - pick.time_errors.lower_uncertainty epp = mpp - pick.time_errors.lower_uncertainty
except TypeError as e: except TypeError as e:
msg = e + ',\n falling back to symmetric uncertainties' if not spe:
warnings.warn(msg) msg = 'No uncertainties found for pick: {}. Uncertainty set to 0'.format(pick)
lpp = mpp
epp = mpp
else:
msg = str(e) + ',\n falling back to symmetric uncertainties'
lpp = mpp + spe lpp = mpp + spe
epp = mpp - spe epp = mpp - spe
warnings.warn(msg)
phase['mpp'] = mpp phase['mpp'] = mpp
phase['epp'] = epp phase['epp'] = epp
phase['lpp'] = lpp phase['lpp'] = lpp
@ -233,6 +271,7 @@ def picksdict_from_picks(evt):
phase['channel'] = channel phase['channel'] = channel
phase['network'] = network phase['network'] = network
phase['picker'] = picker phase['picker'] = picker
phase['filter_id'] = filter_id if filter_id is not None else ''
onsets[pick.phase_hint] = phase.copy() onsets[pick.phase_hint] = phase.copy()
picksdict[picker][station] = onsets.copy() picksdict[picker][station] = onsets.copy()
@ -240,6 +279,16 @@ def picksdict_from_picks(evt):
def picks_from_picksdict(picks, creation_info=None): def picks_from_picksdict(picks, creation_info=None):
"""
Create a list of picks out of a pick dictionary
:param picks: pick dictionary
:type picks: dict
:param creation_info: obspy creation information to apply to picks
:type creation_info:
:param creation_info: obspy creation information to apply to picks
:return: list of picks
:rtype: list
"""
picks_list = list() picks_list = list()
for station, onsets in picks.items(): for station, onsets in picks.items():
for label, phase in onsets.items(): for label, phase in onsets.items():
@ -274,6 +323,13 @@ def picks_from_picksdict(picks, creation_info=None):
pick.waveform_id = ope.WaveformStreamID(station_code=station, pick.waveform_id = ope.WaveformStreamID(station_code=station,
channel_code=ccode, channel_code=ccode,
network_code=ncode) network_code=ncode)
try:
filter_id = phase['filteroptions']
filter_id = transformFilterString4Export(filter_id)
except KeyError as e:
warnings.warn(e.message, RuntimeWarning)
filter_id = ''
pick.filter_id = filter_id
try: try:
polarity = phase['fm'] polarity = phase['fm']
if polarity == 'U' or '+': if polarity == 'U' or '+':
@ -290,7 +346,6 @@ def picks_from_picksdict(picks, creation_info=None):
picks_list.append(pick) picks_list.append(pick)
return picks_list return picks_list
def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0): def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0):
import glob import glob
@ -410,25 +465,24 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
HYPO71, NLLoc, VELEST, HYPOSAT, and hypoDD HYPO71, NLLoc, VELEST, HYPOSAT, and hypoDD
:param: arrivals :param arrivals:dictionary containing all phase information including
:type: dictionary containing all phase information including station ID, phase, first motion, weight (uncertainty), ...
station ID, phase, first motion, weight (uncertainty), :type arrivals: dict
....
:param: fformat :param fformat: chosen file format (location routine),
:type: string, chosen file format (location routine),
choose between NLLoc, HYPO71, HYPOSAT, VELEST, choose between NLLoc, HYPO71, HYPOSAT, VELEST,
HYPOINVERSE, and hypoDD HYPOINVERSE, and hypoDD
:type fformat: str
:param: filename, full path and name of phase file :param filename: full path and name of phase file
:type: string :type filename: string
:param: parameter, all input information :param parameter: all input information
:type: object :type parameter: object
:param: eventinfo, optional, needed for VELEST-cnv file :param eventinfo: optional, needed for VELEST-cnv file
and FOCMEC- and HASH-input files and FOCMEC- and HASH-input files
:type: `obspy.core.event.Event` object :type eventinfo: `obspy.core.event.Event` object
""" """
if fformat == 'NLLoc': if fformat == 'NLLoc':
@ -877,6 +931,16 @@ def getQualitiesfromxml(xmlnames, ErrorsP, ErrorsS, plotflag=1):
Script to get onset uncertainties from Quakeml.xml files created by PyLoT. Script to get onset uncertainties from Quakeml.xml files created by PyLoT.
Uncertainties are tranformed into quality classes and visualized via histogram if desired. Uncertainties are tranformed into quality classes and visualized via histogram if desired.
Ludger Küperkoch, BESTEC GmbH, 07/2017 Ludger Küperkoch, BESTEC GmbH, 07/2017
:param xmlnames: list of xml obspy event files containing picks
:type xmlnames: list
:param ErrorsP: time errors of P waves for the four discrete quality classes
:type ErrorsP:
:param ErrorsS: time errors of S waves for the four discrete quality classes
:type ErrorsS:
:param plotflag:
:type plotflag:
:return:
:rtype:
""" """
from pylot.core.pick.utils import getQualityFromUncertainty from pylot.core.pick.utils import getQualityFromUncertainty

View File

@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo):
:param fnout: complete path to the exporting obs file :param fnout: complete path to the exporting obs file
:type fnout: str :type fnout: str
:param: parameter, all input information :param parameter: all input information
:type: object :type parameter: object
:param: eventinfo, source information needed for focmec format :param eventinfo: source information needed for focmec format
:type: list object :type eventinfo: list object
''' '''
# write phases to FOCMEC-phase file # write phases to FOCMEC-phase file
writephases(picks, 'FOCMEC', fnout, parameter, eventinfo) writephases(picks, 'FOCMEC', fnout, parameter, eventinfo)

View File

@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo):
:param fnout: complete path to the exporting obs file :param fnout: complete path to the exporting obs file
:type fnout: str :type fnout: str
:param: parameter, all input information :param parameter: all input information
:type: object :type parameter: object
:param: eventinfo, source information needed for HASH format :param eventinfo: source information needed for HASH format
:type: list object :type eventinfo: list object
''' '''
# write phases to HASH-phase file # write phases to HASH-phase file
writephases(picks, 'HASH', fnout, parameter, eventinfo) writephases(picks, 'HASH', fnout, parameter, eventinfo)

View File

@ -18,8 +18,8 @@ def export(picks, fnout, parameter):
:param fnout: complete path to the exporting obs file :param fnout: complete path to the exporting obs file
:type fnout: str :type fnout: str
:param: parameter, all input information :param parameter: all input information
:type: object :type parameter: object
''' '''
# write phases to HYPO71-phase file # write phases to HYPO71-phase file
writephases(picks, 'HYPO71', fnout, parameter) writephases(picks, 'HYPO71', fnout, parameter)

View File

@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo):
:param fnout: complete path to the exporting obs file :param fnout: complete path to the exporting obs file
:type fnout: str :type fnout: str
:param: parameter, all input information :param parameter: all input information
:type: object :type parameter: object
:param: eventinfo, source information needed for hypoDD format :param eventinfo: source information needed for hypoDD format
:type: list object :type eventinfo: list object
''' '''
# write phases to hypoDD-phase file # write phases to hypoDD-phase file
writephases(picks, 'hypoDD', fnout, parameter, eventinfo) writephases(picks, 'hypoDD', fnout, parameter, eventinfo)

View File

@ -18,8 +18,8 @@ def export(picks, fnout, parameter):
:param fnout: complete path to the exporting obs file :param fnout: complete path to the exporting obs file
:type fnout: str :type fnout: str
:param: parameter, all input information :param parameter: all input information
:type: object :type parameter: object
''' '''
# write phases to HYPOSAT-phase file # write phases to HYPOSAT-phase file
writephases(picks, 'HYPOSAT', fnout, parameter) writephases(picks, 'HYPOSAT', fnout, parameter)

View File

@ -28,8 +28,8 @@ def export(picks, fnout, parameter):
:param fnout: complete path to the exporting obs file :param fnout: complete path to the exporting obs file
:type fnout: str :type fnout: str
:param: parameter, all input information :param parameter: all input information
:type: object :type parameter: object
''' '''
# write phases to NLLoc-phase file # write phases to NLLoc-phase file
writephases(picks, 'NLLoc', fnout, parameter) writephases(picks, 'NLLoc', fnout, parameter)
@ -38,19 +38,19 @@ def export(picks, fnout, parameter):
def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn): def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn):
''' '''
:param ctrfn: name of NLLoc-control file :param ctrfn: name of NLLoc-control file
:type: str :type ctrfn: str
:param root: root path to NLLoc working directory :param root: root path to NLLoc working directory
:type: str :type root: str
:param nllocoutn: name of NLLoc-location output file :param nllocoutn: name of NLLoc-location output file
:type: str :type nllocoutn: str
:param phasefn: name of NLLoc-input phase file :param phasefn: name of NLLoc-input phase file
:type: str :type phasefn: str
:param tttn: pattern of precalculated NLLoc traveltime tables :param tttn: pattern of precalculated NLLoc traveltime tables
:type: str :type tttn: str
''' '''
# For locating the event the NLLoc-control file has to be modified! # For locating the event the NLLoc-control file has to be modified!
# create comment line for NLLoc-control file NLLoc-output file # create comment line for NLLoc-control file NLLoc-output file
@ -75,9 +75,9 @@ def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn):
def locate(fnin, infile=None): def locate(fnin, infile=None):
""" """
takes an external program name takes an external program name and tries to run it
:param fnin: :param fnin: external program name
:return: :return: None
""" """
if infile is None: if infile is None:

View File

@ -18,11 +18,11 @@ def export(picks, fnout, eventinfo, parameter=None):
:param fnout: complete path to the exporting obs file :param fnout: complete path to the exporting obs file
:type fnout: str :type fnout: str
:param: eventinfo, source time needed for VELEST-cnv format :param eventinfo: source time needed for VELEST-cnv format
:type: list object :type eventinfo: list object
:param: parameter, all input information :param parameter: all input information
:type: object :type parameter: object
''' '''
# write phases to VELEST-phase file # write phases to VELEST-phase file
writephases(picks, 'VELEST', fnout, parameter, eventinfo) writephases(picks, 'VELEST', fnout, parameter, eventinfo)

View File

@ -155,7 +155,7 @@ def autopickstation(wfstream, pickparam, verbose=False,
:type metadata: tuple (str, ~obspy.io.xseed.parser.Parser) :type metadata: tuple (str, ~obspy.io.xseed.parser.Parser)
:param origin: list containing origin objects representing origins for all events :param origin: list containing origin objects representing origins for all events
:type origin: list(~obspy.core.event.origin) :type origin: list(~obspy.core.event.origin)
:return: :dictionary containing P pick, S pick and station name :return: dictionary containing P pick, S pick and station name
:rtype: dict :rtype: dict
""" """

View File

@ -8,6 +8,13 @@ except:
def checkurl(url='https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/'): def checkurl(url='https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/'):
"""
check if URL is available
:param url: url
:type url: str
:return: available: True/False
:rtype: bool
"""
try: try:
urlopen(url, timeout=1) urlopen(url, timeout=1)
return True return True

View File

@ -15,6 +15,11 @@ class Event(ObsPyEvent):
''' '''
def __init__(self, path): def __init__(self, path):
"""
Initialize event by event directory
:param path: path to event directory
:type path: str
"""
self.pylot_id = path.split('/')[-1] self.pylot_id = path.split('/')[-1]
# initialize super class # initialize super class
super(Event, self).__init__(resource_id=ResourceIdentifier('smi:local/' + self.pylot_id)) super(Event, self).__init__(resource_id=ResourceIdentifier('smi:local/' + self.pylot_id))
@ -30,10 +35,20 @@ class Event(ObsPyEvent):
self.get_notes() self.get_notes()
def get_notes_path(self): def get_notes_path(self):
"""
Notes files is freely editable by the user and can contain notes regarding the event
:return: path to notes file
:rtype: str
"""
notesfile = os.path.join(self.path, 'notes.txt') notesfile = os.path.join(self.path, 'notes.txt')
return notesfile return notesfile
def get_notes(self): def get_notes(self):
"""
set self.note attribute to content of notes file
:return:
:rtype: None
"""
notesfile = self.get_notes_path() notesfile = self.get_notes_path()
if os.path.isfile(notesfile): if os.path.isfile(notesfile):
with open(notesfile) as infile: with open(notesfile) as infile:
@ -48,34 +63,81 @@ class Event(ObsPyEvent):
pass pass
def addNotes(self, notes): def addNotes(self, notes):
"""
Set new notes string
:param notes: notes to save in Event object
:type notes: str
:return:
:rtype: None
"""
self.notes = str(notes) self.notes = str(notes)
def clearNotes(self): def clearNotes(self):
"""
Clear event notes
:return:
:rtype: None
"""
self.notes = None self.notes = None
def isRefEvent(self): def isRefEvent(self):
"""
Return reference event flag
:return: True if event is refence event
:rtype: bool
"""
return self._refEvent return self._refEvent
def isTestEvent(self): def isTestEvent(self):
"""
Return test event flag
:return: True if event is test event
:rtype: bool
"""
return self._testEvent return self._testEvent
def setRefEvent(self, bool): def setRefEvent(self, bool):
"""
Set reference event flag
:param bool: new reference event flag
:type bool: bool
:return:
:rtype: None
"""
self._refEvent = bool self._refEvent = bool
if bool: self._testEvent = False if bool: self._testEvent = False
def setTestEvent(self, bool): def setTestEvent(self, bool):
"""
Set test event flag
:param bool: new test event flag
:type bool: bool
:return:
:rtype: None
"""
self._testEvent = bool self._testEvent = bool
if bool: self._refEvent = False if bool: self._refEvent = False
def clearObsPyPicks(self, picktype): def clearObsPyPicks(self, picktype):
"""
Remove picks of a certain type from event
:param picktype: type of picks to remove, 'auto' or 'manual'
:type picktype: str
:return:
:rtype: None
"""
for index, pick in reversed(list(enumerate(self.picks))): for index, pick in reversed(list(enumerate(self.picks))):
if picktype in str(pick.method_id): if picktype in str(pick.method_id):
self.picks.pop(index) self.picks.pop(index)
def addPicks(self, picks): def addPicks(self, picks):
''' """
add pylot picks and overwrite existing ones add pylot picks and overwrite existing ones
''' :param picks: picks to add to event in pick dictionary
:type picks: dict
:return:
:rtype: None
"""
for station in picks: for station in picks:
self.pylot_picks[station] = picks[station] self.pylot_picks[station] = picks[station]
# add ObsPy picks (clear old manual and copy all new manual from pylot) # add ObsPy picks (clear old manual and copy all new manual from pylot)
@ -83,6 +145,13 @@ class Event(ObsPyEvent):
self.picks += picks_from_picksdict(self.pylot_picks) self.picks += picks_from_picksdict(self.pylot_picks)
def addAutopicks(self, autopicks): def addAutopicks(self, autopicks):
"""
Add automatic picks to event
:param autopicks: automatic picks to add to event
:type autopicks dict:
:return:
:rtype: None
"""
for station in autopicks: for station in autopicks:
self.pylot_autopicks[station] = autopicks[station] self.pylot_autopicks[station] = autopicks[station]
# add ObsPy picks (clear old auto and copy all new auto from pylot) # add ObsPy picks (clear old auto and copy all new auto from pylot)
@ -90,6 +159,15 @@ class Event(ObsPyEvent):
self.picks += picks_from_picksdict(self.pylot_autopicks) self.picks += picks_from_picksdict(self.pylot_autopicks)
def setPick(self, station, pick): def setPick(self, station, pick):
"""
Set pick for a station
:param station: station name
:type station: str
:param pick:
:type pick: dict
:return:
:rtype:
"""
if pick: if pick:
self.pylot_picks[station] = pick self.pylot_picks[station] = pick
else: else:
@ -101,21 +179,46 @@ class Event(ObsPyEvent):
self.picks += picks_from_picksdict(self.pylot_picks) self.picks += picks_from_picksdict(self.pylot_picks)
def setPicks(self, picks): def setPicks(self, picks):
''' """
set pylot picks and delete and overwrite all existing Set pylot picks and delete and overwrite all existing
''' :param picks: new picks
:type picks: dict
:return:
:rtype: None
"""
self.pylot_picks = picks self.pylot_picks = picks
self.clearObsPyPicks('manual') self.clearObsPyPicks('manual')
self.picks += picks_from_picksdict(self.pylot_picks) self.picks += picks_from_picksdict(self.pylot_picks)
def getPick(self, station): def getPick(self, station):
"""
Get pick at station
:param station: station name
:type station: str
:return: pick dictionary of station
:rtype: dict
"""
if station in self.pylot_picks.keys(): if station in self.pylot_picks.keys():
return self.pylot_picks[station] return self.pylot_picks[station]
def getPicks(self): def getPicks(self):
"""
Return pylot picks
:return:
:rtype: dict
"""
return self.pylot_picks return self.pylot_picks
def setAutopick(self, station, pick): def setAutopick(self, station, pick):
"""
Set pick at station
:param station: station name
:type station: str
:param pick:
:type pick: dict
:return:
:rtype: None
"""
if pick: if pick:
self.pylot_autopicks[station] = pick self.pylot_autopicks[station] = pick
else: else:
@ -127,25 +230,46 @@ class Event(ObsPyEvent):
self.picks += picks_from_picksdict(self.pylot_autopicks) self.picks += picks_from_picksdict(self.pylot_autopicks)
def setAutopicks(self, picks): def setAutopicks(self, picks):
''' """
set pylot picks and delete and overwrite all existing Set pylot picks and delete and overwrite all existing
''' :param picks: new picks
:type picks: dict
:return:
:rtype: None
"""
self.pylot_autopicks = picks self.pylot_autopicks = picks
self.clearObsPyPicks('auto') self.clearObsPyPicks('auto')
self.picks += picks_from_picksdict(self.pylot_autopicks) self.picks += picks_from_picksdict(self.pylot_autopicks)
def getAutopick(self, station): def getAutopick(self, station):
"""
Return autopick at station
:param station: station name
:type station: str
:return: pick dictionary
:rtype: dict
"""
if station in self.pylot_autopicks.keys(): if station in self.pylot_autopicks.keys():
return self.pylot_autopicks[station] return self.pylot_autopicks[station]
def getAutopicks(self): def getAutopicks(self):
"""
Get autopicks of event
:return: dict containing automatic picks
:rtype: dict
"""
return self.pylot_autopicks return self.pylot_autopicks
def save(self, filename): def save(self, filename):
''' """
Save PyLoT Event to a file. Save PyLoT Event to a file.
Can be loaded by using event.load(filename). Can be loaded by using event.load(filename).
''' Uses pickling to save event object to file
:param filename: filename to save project under
:type filename: str
:return:
:rtype: None
"""
try: try:
import cPickle import cPickle
except ImportError: except ImportError:
@ -159,9 +283,13 @@ class Event(ObsPyEvent):
@staticmethod @staticmethod
def load(filename): def load(filename):
''' """
Load project from filename. Load project from filename
''' :param filename: to load event file
:type filename: str
:return: event loaded from file
:rtype: Event
"""
try: try:
import cPickle import cPickle
except ImportError: except ImportError:

View File

@ -24,7 +24,7 @@ class Thread(QThread):
if self.redirect_stdout: if self.redirect_stdout:
sys.stdout = self sys.stdout = self
try: try:
if self.arg: if self.arg is not None:
self.data = self.func(self.arg) self.data = self.func(self.arg)
else: else:
self.data = self.func() self.data = self.func()

View File

@ -13,7 +13,7 @@ from obspy.core import AttribDict
from obspy.signal.rotate import rotate2zne from obspy.signal.rotate import rotate2zne
from obspy.io.xseed.utils import SEEDParserException from obspy.io.xseed.utils import SEEDParserException
from pylot.core.io.inputs import PylotParameter from pylot.core.io.inputs import PylotParameter, FilterOptions
from pylot.styles import style_settings from pylot.styles import style_settings
from scipy.interpolate import splrep, splev from scipy.interpolate import splrep, splev
@ -31,6 +31,15 @@ def _pickle_method(m):
else: else:
return getattr, (m.im_self, m.im_func.func_name) return getattr, (m.im_self, m.im_func.func_name)
def getAutoFilteroptions(phase, parameter):
filtername = {'P': 'bpz2',
'S': 'bph2'}
if not phase in filtername.keys():
print('autoPickParameter: No filter options for phase {}.'.format(phase))
return
freqmin, freqmax = parameter.get(filtername[phase])
filteroptions = FilterOptions(type='bandpass', freq=[freqmin, freqmax], order=4) # order=4 default from obspy
return filteroptions
def readDefaultFilterInformation(fname): def readDefaultFilterInformation(fname):
""" """
@ -327,9 +336,9 @@ def real_Bool(value):
:return: true boolean value :return: true boolean value
:rtype: bool :rtype: bool
""" """
if value == 'True': if value in ['True', 'true']:
return True return True
elif value == 'False': elif value in ['False', 'false']:
return False return False
else: else:
return value return value
@ -391,6 +400,38 @@ def full_range(stream):
return min_start, max_end return min_start, max_end
def transformFilteroptions2String(filtopts):
st = ''
if not filtopts:
return st
if 'type' in filtopts.keys():
st += '{}'.format(filtopts['type'])
if 'freq' in filtopts.keys():
st += ' | freq: {}'.format(filtopts['freq'])
elif 'freqmin' in filtopts.keys() and 'freqmax' in filtopts.keys():
st += ' | freqmin: {} | freqmax: {}'.format(filtopts['freqmin'], filtopts['freqmax'])
for key, value in filtopts.items():
if key in ['type', 'freq', 'freqmin', 'freqmax']:
continue
st += ' | {}: {}'.format(key, value)
return st
def transformFilterString4Export(st):
st = st.replace('|', '//')
st = st.replace(':', '/')
st = st.replace(' ', '')
return st
def backtransformFilterString(st):
st = st.split('smi:local/')
st = st[1] if len(st) > 1 else st[0]
st = st.replace('//', ' | ')
st = st.replace('/', ': ')
return st
def getHash(time): def getHash(time):
""" """
takes a time object and returns the corresponding SHA1 hash of the formatted date string takes a time object and returns the corresponding SHA1 hash of the formatted date string
@ -945,7 +986,7 @@ def check4rotated(data, metadata=None, verbosity=1):
dip = blockette_.dip dip = blockette_.dip
azimut = blockette_.azimuth azimut = blockette_.azimuth
break break
if dip is None or azimut is None: if (dip is None or azimut is None) or (dip == 0 and azimut == 0):
error_msg = 'Dip and azimuth not available for trace_id {}'.format(trace_id) error_msg = 'Dip and azimuth not available for trace_id {}'.format(trace_id)
raise ValueError(error_msg) raise ValueError(error_msg)
return dip, azimut return dip, azimut
@ -1111,6 +1152,9 @@ def loopIdentifyPhase(phase):
""" """
from pylot.core.util.defaults import ALTSUFFIX from pylot.core.util.defaults import ALTSUFFIX
if phase == None:
raise NameError('Can not identify phase that is None')
phase_copy = phase phase_copy = phase
while not identifyPhase(phase_copy): while not identifyPhase(phase_copy):
identified = False identified = False
@ -1135,8 +1179,10 @@ def identifyPhase(phase):
:rtype: str or bool :rtype: str or bool
""" """
# common phase suffix for P and S # common phase suffix for P and S
common_P = ['P', 'p'] common_P = ['P', 'p', 'R']
common_S = ['S', 's'] common_S = ['S', 's']
if phase is None:
return False
if phase[-1] in common_P: if phase[-1] in common_P:
return 'P' return 'P'
if phase[-1] in common_S: if phase[-1] in common_S:

File diff suppressed because it is too large Load Diff

View File

@ -124,7 +124,6 @@ color:rgba(0, 0, 0, 255);
border-style: outset; border-style: outset;
border-width: 1px; border-width: 1px;
border-color: rgba(100, 100, 120, 255); border-color: rgba(100, 100, 120, 255);
min-width: 6em;
padding: 4px; padding: 4px;
padding-left:5px; padding-left:5px;
padding-right:5px; padding-right:5px;

View File

@ -123,7 +123,6 @@ color:rgba(255, 255, 255, 255);
border-style: outset; border-style: outset;
border-width: 2px; border-width: 2px;
border-color: rgba(50, 50, 60, 255); border-color: rgba(50, 50, 60, 255);
min-width: 6em;
padding: 4px; padding: 4px;
padding-left:5px; padding-left:5px;
padding-right:5px; padding-right:5px;