Merge branch 'develop' into feature/refactor
This commit is contained in:
commit
1edc745903
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.pyc
|
||||
*~
|
||||
pylot/RELEASE-VERSION
|
271
PyLoT.py
271
PyLoT.py
@ -75,7 +75,7 @@ from pylot.core.util.dataprocessing import read_metadata, restitute_data
|
||||
from pylot.core.util.utils import fnConstructor, getLogin, \
|
||||
full_range, readFilterInformation, trim_station_components, check4gaps, make_pen, pick_color_plt, \
|
||||
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.io.location import create_creation_info, create_event
|
||||
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
||||
@ -182,25 +182,22 @@ class MainWindow(QMainWindow):
|
||||
settings.setValue("data/dataRoot", dirname)
|
||||
if settings.value('compclass', None) is None:
|
||||
settings.setValue('compclass', SetChannelComponents())
|
||||
if settings.value('useGuiFilter') is None:
|
||||
settings.setValue('useGuiFilter', False)
|
||||
if settings.value('output/Format', None) is None:
|
||||
outformat = QInputDialog.getText(self,
|
||||
"Enter output format (*.xml, *.cnv, *.obs):",
|
||||
"Format")
|
||||
settings.setValue("output/Format", outformat)
|
||||
if settings.value('autoFilter', None) is None:
|
||||
settings.setValue('autoFilter', True)
|
||||
settings.sync()
|
||||
|
||||
# setup UI
|
||||
self.setupUi()
|
||||
|
||||
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'])}
|
||||
self.updateFilteroptions()
|
||||
|
||||
self.loc = False
|
||||
|
||||
def setupUi(self):
|
||||
@ -270,8 +267,12 @@ class MainWindow(QMainWindow):
|
||||
s_icon.addPixmap(QPixmap(':/icons/key_S.png'))
|
||||
print_icon = QIcon()
|
||||
print_icon.addPixmap(QPixmap(':/icons/printer.png'))
|
||||
filter_icon = QIcon()
|
||||
filter_icon.addPixmap(QPixmap(':/icons/filter.png'))
|
||||
self.filter_icon = QIcon()
|
||||
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.addPixmap(QPixmap(':/icons/key_Z.png'))
|
||||
n_icon = QIcon()
|
||||
@ -286,6 +287,8 @@ class MainWindow(QMainWindow):
|
||||
locate_icon.addPixmap(QPixmap(':/icons/locate_button.png'))
|
||||
compare_icon = QIcon()
|
||||
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.createNewProject,
|
||||
QKeySequence.New, newIcon,
|
||||
@ -366,15 +369,23 @@ class MainWindow(QMainWindow):
|
||||
self.setParameter,
|
||||
None, paraIcon,
|
||||
"Modify Parameter")
|
||||
self.filterAction = self.createAction(self, "&Filter ...",
|
||||
self.filterWaveformData,
|
||||
"Ctrl+F", filter_icon,
|
||||
"""Toggle un-/filtered waveforms
|
||||
to be displayed, according to the
|
||||
desired seismic phase.""", True)
|
||||
self.filterActionP = createAction(parent=self, text='Apply P Filter',
|
||||
slot=self.filterP,
|
||||
icon=self.filter_icon_p,
|
||||
tip='Toggle filtered/original'
|
||||
' waveforms',
|
||||
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 ...",
|
||||
self.adjustFilterOptions,
|
||||
"Alt+F", filter_icon,
|
||||
"Ctrl+F", self.filter_icon,
|
||||
"""Adjust filter parameters.""")
|
||||
self.inventoryAction = self.createAction(self, "Select &Inventory ...",
|
||||
self.get_new_metadata,
|
||||
@ -402,6 +413,10 @@ class MainWindow(QMainWindow):
|
||||
"automatic pick "
|
||||
"data.", 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 ...",
|
||||
self.show_event_information, QKeySequence.Print,
|
||||
@ -472,7 +487,7 @@ class MainWindow(QMainWindow):
|
||||
' the complete project on grid engine.')
|
||||
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")
|
||||
# pickToolActions = (selectStation, )
|
||||
@ -500,8 +515,8 @@ class MainWindow(QMainWindow):
|
||||
self.updateFileMenu()
|
||||
|
||||
self.editMenu = self.menuBar().addMenu('&Edit')
|
||||
editActions = (self.filterAction, filterEditAction, None,
|
||||
self.selectPAction, self.selectSAction, None,
|
||||
editActions = (self.filterActionP, self.filterActionS, filterEditAction, None,
|
||||
#self.selectPAction, self.selectSAction, None,
|
||||
self.inventoryAction, self.initMapAction, None,
|
||||
prefsEventAction)
|
||||
#printAction) #TODO: print event?
|
||||
@ -561,20 +576,29 @@ class MainWindow(QMainWindow):
|
||||
style = settings.value('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.setMaxVisibleItems(30)
|
||||
self.eventBox.setEnabled(False)
|
||||
self.previous_button = QPushButton('<')
|
||||
self.next_button = QPushButton('>')
|
||||
self.init_ref_test_buttons()
|
||||
self._event_layout = QHBoxLayout()
|
||||
self._event_layout.addWidget(QLabel('Event: '))
|
||||
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.test_event_button)
|
||||
self._event_layout.setStretch(1, 1) # set stretch of item 1 to 1
|
||||
self._main_layout.addLayout(self._event_layout)
|
||||
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
|
||||
self.tabs = QTabWidget(self)
|
||||
self._main_layout.addWidget(self.tabs)
|
||||
@ -650,6 +674,8 @@ class MainWindow(QMainWindow):
|
||||
'''
|
||||
self.ref_event_button = QtGui.QPushButton('Tune')
|
||||
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 ' +
|
||||
'event as reference picks for autopicker tuning.')
|
||||
self.test_event_button.setToolTip('Set manual picks of current ' +
|
||||
@ -763,6 +789,17 @@ class MainWindow(QMainWindow):
|
||||
def metadata(self, 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):
|
||||
|
||||
self.fileMenu.clear()
|
||||
@ -1004,7 +1041,8 @@ class MainWindow(QMainWindow):
|
||||
and len(item.split('/')[-1].split('.')) == 3
|
||||
and len(item.split('/')[-1]) == 12]
|
||||
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
|
||||
else:
|
||||
return
|
||||
@ -1100,9 +1138,16 @@ class MainWindow(QMainWindow):
|
||||
Initiate GUI widgets in case of changed or newly added events.
|
||||
'''
|
||||
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.')
|
||||
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
|
||||
self.eventBox.setEnabled(True)
|
||||
self.fill_eventbox()
|
||||
@ -1113,6 +1158,31 @@ class MainWindow(QMainWindow):
|
||||
self.refreshEvents()
|
||||
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'):
|
||||
'''
|
||||
(Re)fill the selected eventBox (type = QtGui.QComboBox).
|
||||
@ -1353,6 +1423,9 @@ class MainWindow(QMainWindow):
|
||||
self.cmpw.refresh_tooltips()
|
||||
self.cmpw.show()
|
||||
|
||||
def pickQualities(self):
|
||||
return
|
||||
|
||||
def compareMulti(self):
|
||||
if not self.compareoptions:
|
||||
return
|
||||
@ -1401,7 +1474,8 @@ class MainWindow(QMainWindow):
|
||||
return None
|
||||
|
||||
def getStime(self):
|
||||
return self._stime
|
||||
if self.get_data():
|
||||
return full_range(self.get_data().getWFData())[0]
|
||||
|
||||
def addActions(self, target, actions):
|
||||
for action in actions:
|
||||
@ -1470,6 +1544,26 @@ class MainWindow(QMainWindow):
|
||||
if self.tap:
|
||||
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):
|
||||
'''
|
||||
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,
|
||||
# but gets necessary when switching from one to another after changing an event.
|
||||
self._eventChanged = [True, True]
|
||||
self.checkEventButtons()
|
||||
self.refreshTabs()
|
||||
|
||||
def refreshTabs(self):
|
||||
@ -1554,18 +1649,38 @@ class MainWindow(QMainWindow):
|
||||
# else:
|
||||
# ans = False
|
||||
self.fnames = self.getWFFnames_from_eventbox()
|
||||
self.data.setWFData(self.fnames)
|
||||
wfdat = self.data.getWFData() # all available streams
|
||||
# remove possible underscores in station names
|
||||
wfdat = remove_underscores(wfdat)
|
||||
# check for gaps and doubled channels
|
||||
check4gaps(wfdat)
|
||||
check4doubled(wfdat)
|
||||
# check for stations with rotated components
|
||||
wfdat = check4rotated(wfdat, self.metadata, verbosity=0)
|
||||
# trim station components to same start value
|
||||
trim_station_components(wfdat, trim_start=True, trim_end=False)
|
||||
self._stime = full_range(self.get_data().getWFData())[0]
|
||||
self.data.setWFData(self.fnames,
|
||||
checkRotated=True,
|
||||
metadata=self.metadata)
|
||||
|
||||
def check_plot_quantity(self):
|
||||
settings = QSettings()
|
||||
nth_sample = settings.value("nth_sample") if settings.value("nth_sample") else 1
|
||||
npts_max = 1e6
|
||||
npts = self.get_npts_to_plot()
|
||||
npts2plot = npts/nth_sample
|
||||
if npts2plot < npts_max:
|
||||
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):
|
||||
'''
|
||||
@ -1661,8 +1776,10 @@ class MainWindow(QMainWindow):
|
||||
if event.pylot_picks:
|
||||
self.drawPicks(picktype='manual')
|
||||
self.locateEvent.setEnabled(True)
|
||||
self.qualities_action.setEnabled(True)
|
||||
if event.pylot_autopicks:
|
||||
self.drawPicks(picktype='auto')
|
||||
self.qualities_action.setEnabled(True)
|
||||
if True in self.comparable.values():
|
||||
self.compare_action.setEnabled(True)
|
||||
self.draw()
|
||||
@ -1724,18 +1841,20 @@ class MainWindow(QMainWindow):
|
||||
self.disableSaveEventAction()
|
||||
self.draw()
|
||||
|
||||
def plotWaveformDataThread(self):
|
||||
def plotWaveformDataThread(self, filter=True):
|
||||
'''
|
||||
Open a modal thread to plot current waveform data.
|
||||
'''
|
||||
self.check_plot_quantity()
|
||||
self.clearWaveformDataPlot()
|
||||
self.wfp_thread = Thread(self, self.plotWaveformData,
|
||||
arg=filter,
|
||||
progressText='Plotting waveform data...',
|
||||
pb_widget=self.mainProgressBarWidget)
|
||||
self.wfp_thread.finished.connect(self.finishWaveformDataPlot)
|
||||
self.wfp_thread.start()
|
||||
|
||||
def plotWaveformData(self):
|
||||
def plotWaveformData(self, filter=True):
|
||||
'''
|
||||
Plot waveform data to current plotWidget.
|
||||
'''
|
||||
@ -1747,6 +1866,10 @@ class MainWindow(QMainWindow):
|
||||
comp = self.getComponent()
|
||||
title = 'section: {0} components'.format(zne_text[comp])
|
||||
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=alter_comp)
|
||||
plotWidget = self.getPlotWidget()
|
||||
@ -1786,18 +1909,51 @@ class MainWindow(QMainWindow):
|
||||
def pushFilterWF(self, 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.getFilterOptions() and self.filterAction.isChecked():
|
||||
kwargs = self.getFilterOptions()[self.getSeismicPhase()].parseFilterOptions()
|
||||
self.pushFilterWF(kwargs)
|
||||
elif self.filterAction.isChecked():
|
||||
if not phase:
|
||||
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)
|
||||
else:
|
||||
self.get_data().resetWFData()
|
||||
elif self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
self.adjustFilterOptions()
|
||||
else:
|
||||
self.get_data().resetWFData()
|
||||
self.plotWaveformDataThread()
|
||||
self.drawPicks()
|
||||
self.draw()
|
||||
if plot:
|
||||
self.plotWaveformDataThread(filter=False)
|
||||
#self.drawPicks()
|
||||
#self.draw()
|
||||
|
||||
def getAutoFilteroptions(self, phase):
|
||||
return getAutoFilteroptions(phase, self._inputs)
|
||||
|
||||
def adjustFilterOptions(self):
|
||||
fstring = "Filter Options"
|
||||
@ -1806,10 +1962,11 @@ class MainWindow(QMainWindow):
|
||||
if self.filterDlg.exec_():
|
||||
filteroptions = self.filterDlg.getFilterOptions()
|
||||
self.setFilterOptions(filteroptions)
|
||||
if self.filterAction.isChecked():
|
||||
if self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
kwargs = self.getFilterOptions()[self.getSeismicPhase()].parseFilterOptions()
|
||||
self.pushFilterWF(kwargs)
|
||||
self.plotWaveformDataThread()
|
||||
return True
|
||||
|
||||
def checkFilterOptions(self):
|
||||
fstring = "Filter Options"
|
||||
@ -1886,7 +2043,7 @@ class MainWindow(QMainWindow):
|
||||
# '[{0}: {1} Hz]'.format(
|
||||
# self.getFilterOptions().getFilterType(),
|
||||
# self.getFilterOptions().getFreq()))
|
||||
# if self.filterAction.isChecked():
|
||||
# if self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
# self.filterWaveformData()
|
||||
|
||||
def getSeismicPhase(self):
|
||||
@ -1934,7 +2091,7 @@ class MainWindow(QMainWindow):
|
||||
if self._shift:
|
||||
factor = {'up': 1. / 2.,
|
||||
'down': 2.}
|
||||
xlims = self.dataPlot.getXLims()
|
||||
xlims = self.dataPlot.getXLims(self.dataPlot.axes[0])
|
||||
xdiff = xlims[1] - xlims[0]
|
||||
xdiff *= factor[button]
|
||||
xl = x - 0.5 * xdiff
|
||||
@ -1943,7 +2100,7 @@ class MainWindow(QMainWindow):
|
||||
xl = self._max_xlims[0]
|
||||
if 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()
|
||||
|
||||
def pickOnStation(self, gui_event):
|
||||
@ -1970,7 +2127,7 @@ class MainWindow(QMainWindow):
|
||||
if not station:
|
||||
return
|
||||
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()
|
||||
pickDlg = PickDlg(self, parameter=self._inputs,
|
||||
data=data.select(station=station),
|
||||
@ -1979,6 +2136,9 @@ class MainWindow(QMainWindow):
|
||||
autopicks=self.getPicksOnStation(station, 'auto'),
|
||||
metadata=self.metadata, event=event,
|
||||
filteroptions=self.filteroptions)
|
||||
if self.filterActionP.isChecked() or self.filterActionS.isChecked():
|
||||
pickDlg.currentPhase = self.getSeismicPhase()
|
||||
pickDlg.filterWFData()
|
||||
pickDlg.nextStation.setChecked(nextStation)
|
||||
if pickDlg.exec_():
|
||||
if pickDlg._dirty:
|
||||
@ -2315,7 +2475,7 @@ class MainWindow(QMainWindow):
|
||||
if self.pg:
|
||||
pw = self.getPlotWidget().plotWidget
|
||||
else:
|
||||
ax = self.getPlotWidget().axes
|
||||
ax = self.getPlotWidget().axes[0]
|
||||
ylims = np.array([-.5, +.5]) + plotID
|
||||
|
||||
stat_picks = self.getPicks(type=picktype)[station]
|
||||
@ -2385,7 +2545,7 @@ class MainWindow(QMainWindow):
|
||||
else:
|
||||
if picktype == 'manual':
|
||||
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']:
|
||||
ax.fill_between([epp, lpp], ylims[0], ylims[1],
|
||||
alpha=.25, color=color, label='EPP, LPP')
|
||||
@ -2927,6 +3087,7 @@ class MainWindow(QMainWindow):
|
||||
if hasattr(self.project, 'parameter'):
|
||||
if self.project.parameter:
|
||||
self._inputs = self.project.parameter
|
||||
self.updateFilteroptions()
|
||||
self.tabs.setCurrentIndex(0) # implemented to prevent double-loading of waveform data
|
||||
self.init_events(new=True)
|
||||
self.setDirty(False)
|
||||
|
@ -338,6 +338,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
local_mag = LocalMagnitude(corr_dat, evt,
|
||||
parameter.get('sstop'),
|
||||
WAscaling, True, iplot)
|
||||
# update pick with local magnitude property values
|
||||
for stats, amplitude in local_mag.amplitudes.items():
|
||||
picks[stats]['S']['Ao'] = amplitude.generic_amplitude
|
||||
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,
|
||||
parameter.get('sstop'),
|
||||
WAscaling, True, iplot)
|
||||
# update pick with local magnitude property values
|
||||
for stats, amplitude in local_mag.amplitudes.items():
|
||||
if stats in picks:
|
||||
picks[stats]['S']['Ao'] = amplitude.generic_amplitude
|
||||
@ -496,7 +498,7 @@ if __name__ == "__main__":
|
||||
help='''full path to the file containing the input
|
||||
parameters for autoPyLoT''')
|
||||
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''')
|
||||
parser.add_argument('-f', '-F', '--fnames', type=str,
|
||||
action='store',
|
||||
|
@ -29,10 +29,12 @@
|
||||
<file>icons/map.png</file>
|
||||
<file>icons/openloc.png</file>
|
||||
<file>icons/compare_button.png</file>
|
||||
<file>icons/pick_qualities_button.png</file>
|
||||
<file>icons/locate_button.png</file>
|
||||
<file>icons/Matlab_PILOT_icon.png</file>
|
||||
<file>icons/printer.png</file>
|
||||
<file>icons/delete.png</file>
|
||||
<file>icons/key_A.png</file>
|
||||
<file>icons/key_E.png</file>
|
||||
<file>icons/key_N.png</file>
|
||||
<file>icons/key_P.png</file>
|
||||
@ -45,6 +47,8 @@
|
||||
<file>icons/key_W.png</file>
|
||||
<file>icons/key_Z.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/zoom_0.png</file>
|
||||
<file>icons/zoom_in.png</file>
|
||||
|
BIN
icons/filter_p.png
Normal 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
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
BIN
icons/key_A.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
11574
icons_rc_2.py
11574
icons_rc_2.py
File diff suppressed because it is too large
Load Diff
214148
icons_rc_3.py
214148
icons_rc_3.py
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,6 @@ from pylot.core.util.utils import common_range, fit_curve
|
||||
from scipy import integrate, signal
|
||||
from scipy.optimize import curve_fit
|
||||
|
||||
|
||||
def richter_magnitude_scaling(delta):
|
||||
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,
|
||||
@ -133,7 +132,7 @@ class Magnitude(object):
|
||||
station_count=len(self.magnitudes),
|
||||
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
|
||||
else:
|
||||
# no saling necessary
|
||||
# no scaling necessary
|
||||
mag = ope.Magnitude(
|
||||
mag=np.median([M.mag for M in self.magnitudes.values()]),
|
||||
magnitude_type=self.type,
|
||||
@ -233,17 +232,33 @@ class LocalMagnitude(Magnitude):
|
||||
# check for plot flag (for debugging only)
|
||||
fig = None
|
||||
if iplot > 1:
|
||||
st.plot()
|
||||
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[iwin], sqH[iwin], 'g')
|
||||
ax.plot([t0, t0], [0, max(sqH)], 'r', linewidth=2)
|
||||
ax.title(
|
||||
'Station %s, RMS Horizontal Traces, WA-peak-to-peak=%4.1f mm' \
|
||||
% (st[0].stats.station, wapp))
|
||||
ax.plot([t0 - stime, t0 - stime], [0, max(sqH)], 'r', linewidth=2)
|
||||
ax.set_title('Station %s, Channel %s, RMS Horizontal Trace, '
|
||||
'WA-peak-to-peak=%6.3f mm' % (st[0].stats.station,
|
||||
st[0].stats.channel,
|
||||
wapp))
|
||||
ax.set_xlabel('Time [s]')
|
||||
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
|
||||
|
||||
@ -251,6 +266,10 @@ class LocalMagnitude(Magnitude):
|
||||
for a in self.arrivals:
|
||||
if a.phase not in 'sS':
|
||||
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()
|
||||
station = pick.waveform_id.station_code
|
||||
wf = select_for_phase(self.stream.select(
|
||||
@ -347,7 +366,11 @@ class MomentMagnitude(Magnitude):
|
||||
|
||||
def calc(self):
|
||||
for a in self.arrivals:
|
||||
if a.phase not in 'pP':
|
||||
if a.phase not in 'pP':
|
||||
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()
|
||||
station = pick.waveform_id.station_code
|
||||
|
@ -12,7 +12,8 @@ from pylot.core.io.phases import readPILOTEvent, picks_from_picksdict, \
|
||||
picksdict_from_pilot, merge_picks
|
||||
from pylot.core.util.errors import FormatError, OverwriteError
|
||||
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
|
||||
|
||||
|
||||
@ -99,6 +100,11 @@ class Data(object):
|
||||
return self
|
||||
|
||||
def getPicksStr(self):
|
||||
"""
|
||||
Return picks in event data
|
||||
:return: picks seperated by newlines
|
||||
:rtype: str
|
||||
"""
|
||||
picks_str = ''
|
||||
for pick in self.get_evt_data().picks:
|
||||
picks_str += str(pick) + '\n'
|
||||
@ -106,18 +112,11 @@ class Data(object):
|
||||
|
||||
def getParent(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
Get PySide.QtGui.QWidget parent object
|
||||
"""
|
||||
return self._parent
|
||||
|
||||
def isNew(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self._new
|
||||
|
||||
def setNew(self):
|
||||
@ -125,9 +124,9 @@ class Data(object):
|
||||
|
||||
def getCutTimes(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
Returns earliest start and latest end of all waveform data
|
||||
:return: minimum start time and maximum end time as a tuple
|
||||
:rtype: (UTCDateTime, UTCDateTime)
|
||||
"""
|
||||
if self.cuttimes is None:
|
||||
self.updateCutTimes()
|
||||
@ -135,22 +134,34 @@ class Data(object):
|
||||
|
||||
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())
|
||||
|
||||
def getEventFileName(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
"""
|
||||
ID = self.getID()
|
||||
# handle forbidden filenames especially on windows systems
|
||||
return fnConstructor(str(ID))
|
||||
|
||||
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:
|
||||
self.replaceOrigin(event, forceOverwrite)
|
||||
if 'magnitude' in fcheck:
|
||||
@ -161,18 +172,47 @@ class Data(object):
|
||||
self.replacePicks(event, 'manual')
|
||||
|
||||
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 event.origins:
|
||||
print("Found origin, replace it by new origin.")
|
||||
event.origins = self.get_evt_data().origins
|
||||
|
||||
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 event.magnitudes:
|
||||
print("Found magnitude, replace it by new magnitude")
|
||||
event.magnitudes = self.get_evt_data().magnitudes
|
||||
|
||||
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
|
||||
picks = event.picks
|
||||
# remove existing picks
|
||||
@ -189,10 +229,10 @@ class Data(object):
|
||||
picks.append(pick)
|
||||
|
||||
def exportEvent(self, fnout, fnext='.xml', fcheck='auto', upperErrors=None):
|
||||
|
||||
"""
|
||||
Export event to file
|
||||
:param fnout: basename of file
|
||||
:param fnext: file extension
|
||||
:param fnext: file extension, xml, cnv, obs
|
||||
:param fcheck: check and delete existing information
|
||||
can be a str or a list of strings of ['manual', 'auto', 'origin', 'magnitude']
|
||||
"""
|
||||
@ -304,17 +344,13 @@ class Data(object):
|
||||
|
||||
def getComp(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
Get component (ZNE)
|
||||
"""
|
||||
return self.comp
|
||||
|
||||
def getID(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
Get unique resource id
|
||||
"""
|
||||
try:
|
||||
return self.evtdata.get('resource_id').id
|
||||
@ -323,16 +359,20 @@ class Data(object):
|
||||
|
||||
def filterWFData(self, kwargs):
|
||||
"""
|
||||
|
||||
:param kwargs:
|
||||
Filter waveform data
|
||||
: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
|
||||
|
||||
def setWFData(self, fnames):
|
||||
def setWFData(self, fnames, checkRotated=False, metadata=None):
|
||||
"""
|
||||
|
||||
:param fnames:
|
||||
Clear current waveform data and set given waveform data
|
||||
:param fnames: waveform data names to append
|
||||
:type fnames: list
|
||||
"""
|
||||
self.wfdata = Stream()
|
||||
self.wforiginal = None
|
||||
@ -340,14 +380,31 @@ class Data(object):
|
||||
self.appendWFData(fnames)
|
||||
else:
|
||||
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.dirty = False
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def appendWFData(self, fnames):
|
||||
"""
|
||||
|
||||
:param fnames:
|
||||
Read waveform data from fnames and append it to current wf data
|
||||
:param fnames: waveform data to append
|
||||
:type fnames: list
|
||||
"""
|
||||
assert isinstance(fnames, list), "input parameter 'fnames' is " \
|
||||
"supposed to be of type 'list' " \
|
||||
@ -372,54 +429,45 @@ class Data(object):
|
||||
print(warnmsg)
|
||||
|
||||
def getWFData(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self.wfdata
|
||||
|
||||
def getOriginalWFData(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self.wforiginal
|
||||
|
||||
def resetWFData(self):
|
||||
"""
|
||||
|
||||
|
||||
Set waveform data to original waveform data
|
||||
"""
|
||||
self.wfdata = self.getOriginalWFData().copy()
|
||||
if self.getOriginalWFData():
|
||||
self.wfdata = self.getOriginalWFData().copy()
|
||||
else:
|
||||
self.wfdata = Stream()
|
||||
self.dirty = False
|
||||
|
||||
def resetPicks(self):
|
||||
"""
|
||||
|
||||
|
||||
Clear all picks from event
|
||||
"""
|
||||
self.get_evt_data().picks = []
|
||||
|
||||
def get_evt_data(self):
|
||||
"""
|
||||
|
||||
|
||||
:return:
|
||||
"""
|
||||
return self.evtdata
|
||||
|
||||
def setEvtData(self, event):
|
||||
self.evtdata = event
|
||||
|
||||
def applyEVTData(self, data, typ='pick', authority_id='rub'):
|
||||
|
||||
"""
|
||||
|
||||
:param data:
|
||||
:param typ:
|
||||
:param authority_id:
|
||||
Either takes an `obspy.core.event.Event` object and applies all new
|
||||
information on the event to the actual data if typ is 'event or
|
||||
creates ObsPy pick objects and append it to the picks list from the
|
||||
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:
|
||||
"""
|
||||
|
||||
|
@ -1,5 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import numpy as np
|
||||
|
||||
"""
|
||||
Default parameters used for picking
|
||||
"""
|
||||
|
||||
defaults = {'rootpath': {'type': str,
|
||||
'tooltip': 'project path',
|
||||
@ -74,11 +79,15 @@ defaults = {'rootpath': {'type': str,
|
||||
'vp': {'type': float,
|
||||
'tooltip': 'average P-wave velocity',
|
||||
'value': 3530.,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'P-velocity'},
|
||||
|
||||
'rho': {'type': float,
|
||||
'tooltip': 'average rock density [kg/m^3]',
|
||||
'value': 2500.,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Density'},
|
||||
|
||||
'Qp': {'type': (float, float),
|
||||
@ -90,42 +99,58 @@ defaults = {'rootpath': {'type': str,
|
||||
'tooltip': 'start time [s] for calculating CF for P-picking (if TauPy:'
|
||||
' seconds relative to estimated onset)',
|
||||
'value': 15.0,
|
||||
'min': -np.inf,
|
||||
'max': np.inf,
|
||||
'namestring': 'P start'},
|
||||
|
||||
'pstop': {'type': float,
|
||||
'tooltip': 'end time [s] for calculating CF for P-picking (if TauPy:'
|
||||
' seconds relative to estimated onset)',
|
||||
'value': 60.0,
|
||||
'min': -np.inf,
|
||||
'max': np.inf,
|
||||
'namestring': 'P stop'},
|
||||
|
||||
'sstart': {'type': float,
|
||||
'tooltip': 'start time [s] relative to P-onset for calculating CF for S-picking',
|
||||
'value': -1.0,
|
||||
'min': -np.inf,
|
||||
'max': np.inf,
|
||||
'namestring': 'S start'},
|
||||
|
||||
'sstop': {'type': float,
|
||||
'tooltip': 'end time [s] after P-onset for calculating CF for S-picking',
|
||||
'value': 10.0,
|
||||
'min': -np.inf,
|
||||
'max': np.inf,
|
||||
'namestring': 'S stop'},
|
||||
|
||||
'bpz1': {'type': (float, float),
|
||||
'tooltip': 'lower/upper corner freq. of first band pass filter Z-comp. [Hz]',
|
||||
'value': (2, 20),
|
||||
'min': (0., 0.),
|
||||
'max': (np.inf, np.inf),
|
||||
'namestring': ('Z-bandpass 1', 'Lower', 'Upper')},
|
||||
|
||||
'bpz2': {'type': (float, float),
|
||||
'tooltip': 'lower/upper corner freq. of second band pass filter Z-comp. [Hz]',
|
||||
'value': (2, 30),
|
||||
'min': (0., 0.),
|
||||
'max': (np.inf, np.inf),
|
||||
'namestring': ('Z-bandpass 2', 'Lower', 'Upper')},
|
||||
|
||||
'bph1': {'type': (float, float),
|
||||
'tooltip': 'lower/upper corner freq. of first band pass filter H-comp. [Hz]',
|
||||
'value': (2, 15),
|
||||
'min': (0., 0.),
|
||||
'max': (np.inf, np.inf),
|
||||
'namestring': ('H-bandpass 1', 'Lower', 'Upper')},
|
||||
|
||||
'bph2': {'type': (float, float),
|
||||
'tooltip': 'lower/upper corner freq. of second band pass filter z-comp. [Hz]',
|
||||
'value': (2, 20),
|
||||
'min': (0., 0.),
|
||||
'max': (np.inf, np.inf),
|
||||
'namestring': ('H-bandpass 2', 'Lower', 'Upper')},
|
||||
|
||||
'algoP': {'type': str,
|
||||
@ -136,76 +161,106 @@ defaults = {'rootpath': {'type': str,
|
||||
'tlta': {'type': float,
|
||||
'tooltip': 'for HOS-/AR-AIC-picker, length of LTA window [s]',
|
||||
'value': 7.0,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'LTA window'},
|
||||
|
||||
'hosorder': {'type': int,
|
||||
'tooltip': 'for HOS-picker, order of Higher Order Statistics',
|
||||
'value': 4,
|
||||
'min': 0,
|
||||
'max': np.inf,
|
||||
'namestring': 'HOS order'},
|
||||
|
||||
'Parorder': {'type': int,
|
||||
'tooltip': 'for AR-picker, order of AR process of Z-component',
|
||||
'value': 2,
|
||||
'min': 0,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR order P'},
|
||||
|
||||
'tdet1z': {'type': float,
|
||||
'tooltip': 'for AR-picker, length of AR determination window [s] for Z-component, 1st pick',
|
||||
'value': 1.2,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR det. window Z 1'},
|
||||
|
||||
'tpred1z': {'type': float,
|
||||
'tooltip': 'for AR-picker, length of AR prediction window [s] for Z-component, 1st pick',
|
||||
'value': 0.4,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR pred. window Z 1'},
|
||||
|
||||
'tdet2z': {'type': float,
|
||||
'tooltip': 'for AR-picker, length of AR determination window [s] for Z-component, 2nd pick',
|
||||
'value': 0.6,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR det. window Z 2'},
|
||||
|
||||
'tpred2z': {'type': float,
|
||||
'tooltip': 'for AR-picker, length of AR prediction window [s] for Z-component, 2nd pick',
|
||||
'value': 0.2,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR pred. window Z 2'},
|
||||
|
||||
'addnoise': {'type': float,
|
||||
'tooltip': 'add noise to seismogram for stable AR prediction',
|
||||
'value': 0.001,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Add noise'},
|
||||
|
||||
'tsnrz': {'type': (float, float, float, float),
|
||||
'tooltip': 'for HOS/AR, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]',
|
||||
'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')},
|
||||
|
||||
'pickwinP': {'type': float,
|
||||
'tooltip': 'for initial AIC pick, length of P-pick window [s]',
|
||||
'value': 3.0,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AIC window P'},
|
||||
|
||||
'Precalcwin': {'type': float,
|
||||
'tooltip': 'for HOS/AR, window length [s] for recalculation of CF (relative to 1st pick)',
|
||||
'value': 6.0,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Recal. window P'},
|
||||
|
||||
'aictsmooth': {'type': float,
|
||||
'tooltip': 'for HOS/AR, take average of samples for smoothing of AIC-function [s]',
|
||||
'value': 0.2,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AIC smooth P'},
|
||||
|
||||
'tsmoothP': {'type': float,
|
||||
'tooltip': 'for HOS/AR, take average of samples in this time window for smoothing CF [s]',
|
||||
'value': 0.1,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'CF smooth P'},
|
||||
|
||||
'ausP': {'type': float,
|
||||
'tooltip': 'for HOS/AR, artificial uplift of samples (aus) of CF (P)',
|
||||
'value': 0.001,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Artificial uplift P'},
|
||||
|
||||
'nfacP': {'type': float,
|
||||
'tooltip': 'for HOS/AR, noise factor for noise level determination (P)',
|
||||
'value': 1.3,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Noise factor P'},
|
||||
|
||||
'algoS': {'type': str,
|
||||
@ -216,61 +271,85 @@ defaults = {'rootpath': {'type': str,
|
||||
'tdet1h': {'type': float,
|
||||
'tooltip': 'for HOS/AR, length of AR-determination window [s], H-components, 1st pick',
|
||||
'value': 0.8,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR det. window H 1'},
|
||||
|
||||
'tpred1h': {'type': float,
|
||||
'tooltip': 'for HOS/AR, length of AR-prediction window [s], H-components, 1st pick',
|
||||
'value': 0.4,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR pred. window H 1'},
|
||||
|
||||
'tdet2h': {'type': float,
|
||||
'tooltip': 'for HOS/AR, length of AR-determinaton window [s], H-components, 2nd pick',
|
||||
'value': 0.6,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR det. window H 2'},
|
||||
|
||||
'tpred2h': {'type': float,
|
||||
'tooltip': 'for HOS/AR, length of AR-prediction window [s], H-components, 2nd pick',
|
||||
'value': 0.3,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR pred. window H 2'},
|
||||
|
||||
'Sarorder': {'type': int,
|
||||
'tooltip': 'for AR-picker, order of AR process of H-components',
|
||||
'value': 4,
|
||||
'min': 0,
|
||||
'max': np.inf,
|
||||
'namestring': 'AR order S'},
|
||||
|
||||
'Srecalcwin': {'type': float,
|
||||
'tooltip': 'for AR-picker, window length [s] for recalculation of CF (2nd pick) (H)',
|
||||
'value': 5.0,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Recal. window S'},
|
||||
|
||||
'pickwinS': {'type': float,
|
||||
'tooltip': 'for initial AIC pick, length of S-pick window [s]',
|
||||
'value': 3.0,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AIC window S'},
|
||||
|
||||
'tsnrh': {'type': (float, float, float, float),
|
||||
'tooltip': 'for ARH/AR3, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]',
|
||||
'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')},
|
||||
|
||||
'aictsmoothS': {'type': float,
|
||||
'tooltip': 'for AIC-picker, take average of samples in this time window for smoothing of AIC-function [s]',
|
||||
'value': 0.5,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'AIC smooth S'},
|
||||
|
||||
'tsmoothS': {'type': float,
|
||||
'tooltip': 'for AR-picker, take average of samples for smoothing CF [s] (S)',
|
||||
'value': 0.7,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'CF smooth S'},
|
||||
|
||||
'ausS': {'type': float,
|
||||
'tooltip': 'for HOS/AR, artificial uplift of samples (aus) of CF (S)',
|
||||
'value': 0.9,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Artificial uplift S'},
|
||||
|
||||
'nfacS': {'type': float,
|
||||
'tooltip': 'for AR-picker, noise factor for noise level determination (S)',
|
||||
'value': 1.5,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Noise factor S'},
|
||||
|
||||
'minfmweight': {'type': int,
|
||||
@ -281,103 +360,143 @@ defaults = {'rootpath': {'type': str,
|
||||
'minFMSNR': {'type': float,
|
||||
'tooltip': 'miniumum required SNR for first-motion determination',
|
||||
'value': 2.,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Min SNR'},
|
||||
|
||||
'fmpickwin': {'type': float,
|
||||
'tooltip': 'pick window [s] around P onset for calculating zero crossings',
|
||||
'value': 0.2,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Zero crossings window'},
|
||||
|
||||
'timeerrorsP': {'type': (float, float, float, float),
|
||||
'tooltip': 'discrete time errors [s] corresponding to picking weights [0 1 2 3] for P',
|
||||
'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')},
|
||||
|
||||
'timeerrorsS': {'type': (float, float, float, float),
|
||||
'tooltip': 'discrete time errors [s] corresponding to picking weights [0 1 2 3] for S',
|
||||
'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')},
|
||||
|
||||
'minAICPslope': {'type': float,
|
||||
'tooltip': 'below this slope [counts/s] the initial P pick is rejected',
|
||||
'value': 0.8,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Min. slope P'},
|
||||
|
||||
'minAICPSNR': {'type': float,
|
||||
'tooltip': 'below this SNR the initial P pick is rejected',
|
||||
'value': 1.1,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Min. SNR P'},
|
||||
|
||||
'minAICSslope': {'type': float,
|
||||
'tooltip': 'below this slope [counts/s] the initial S pick is rejected',
|
||||
'value': 1.,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Min. slope S'},
|
||||
|
||||
'minAICSSNR': {'type': float,
|
||||
'tooltip': 'below this SNR the initial S pick is rejected',
|
||||
'value': 1.5,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Min. SNR S'},
|
||||
|
||||
'minsiglength': {'type': float,
|
||||
'tooltip': 'length of signal part for which amplitudes must exceed noiselevel [s]',
|
||||
'value': 1.,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Min. signal length'},
|
||||
|
||||
'noisefactor': {'type': float,
|
||||
'tooltip': 'noiselevel*noisefactor=threshold',
|
||||
'value': 1.0,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Noise factor'},
|
||||
|
||||
'minpercent': {'type': float,
|
||||
'tooltip': 'required percentage of amplitudes exceeding threshold',
|
||||
'value': 10.,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Min amplitude [%]'},
|
||||
|
||||
'zfac': {'type': float,
|
||||
'tooltip': 'P-amplitude must exceed at least zfac times RMS-S amplitude',
|
||||
'value': 1.5,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Z factor'},
|
||||
|
||||
'mdttolerance': {'type': float,
|
||||
'tooltip': 'maximum allowed deviation of P picks from median [s]',
|
||||
'value': 6.0,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Median tolerance'},
|
||||
|
||||
'wdttolerance': {'type': float,
|
||||
'tooltip': 'maximum allowed deviation from Wadati-diagram',
|
||||
'value': 1.0,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Wadati tolerance'},
|
||||
|
||||
'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',
|
||||
'value': 5.0,
|
||||
'namestring': 'Jackknife 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,
|
||||
'min': 0.,
|
||||
'max': np.inf,
|
||||
'namestring': 'Jackknife safety factor'},
|
||||
|
||||
'WAscaling': {'type': (float, float, float),
|
||||
'tooltip': 'Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] \
|
||||
If zeros are set, original Richter magnitude is calculated!',
|
||||
'value': (0., 0., 0.),
|
||||
'min': (0., 0., 0.),
|
||||
'max': (np.inf, np.inf, np.inf),
|
||||
'namestring': ('Wood-Anderson scaling', '', '', '')},
|
||||
|
||||
'magscaling': {'type': (float, float),
|
||||
'tooltip': 'Scaling relation for derived local magnitude [a*Ml+b]. \
|
||||
If zeros are set, no scaling of network magnitude is applied!',
|
||||
'value': (0., 0.),
|
||||
'min': (0., 0.),
|
||||
'max': (np.inf, np.inf),
|
||||
'namestring': ('Local mag. scaling', '', '')},
|
||||
|
||||
'minfreq': {'type': (float, float),
|
||||
'tooltip': 'Lower filter frequency [P, S]',
|
||||
'value': (1.0, 1.0),
|
||||
'min': (0., 0.),
|
||||
'max': (np.inf, np.inf),
|
||||
'namestring': ('Lower freq.', 'P', 'S')},
|
||||
|
||||
'maxfreq': {'type': (float, float),
|
||||
'tooltip': 'Upper filter frequency [P, S]',
|
||||
'value': (10.0, 10.0),
|
||||
'min': (0., 0.),
|
||||
'max': (np.inf, np.inf),
|
||||
'namestring': ('Upper freq.', 'P', 'S')},
|
||||
|
||||
'filter_order': {'type': (int, int),
|
||||
'tooltip': 'filter order [P, S]',
|
||||
'value': (2, 2),
|
||||
'min': (0, 0),
|
||||
'max': (np.inf, np.inf),
|
||||
'namestring': ('Order', 'P', 'S')},
|
||||
|
||||
'filter_type': {'type': (str, str),
|
||||
|
@ -70,6 +70,7 @@ class PylotParameter(object):
|
||||
|
||||
# Set default values of parameter names
|
||||
def __init_default_paras(self):
|
||||
"""set default values of parameter names"""
|
||||
parameters = default_parameters.defaults
|
||||
self.__defaults = parameters
|
||||
|
||||
@ -92,6 +93,11 @@ class PylotParameter(object):
|
||||
return None
|
||||
|
||||
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
|
||||
|
||||
def __delitem__(self, key):
|
||||
@ -104,15 +110,34 @@ class PylotParameter(object):
|
||||
return len(self.__parameter.keys())
|
||||
|
||||
def iteritems(self):
|
||||
"""
|
||||
Iterate over parameters
|
||||
:return: key, value tupel
|
||||
:rtype:
|
||||
"""
|
||||
for key, value in self.__parameter.items():
|
||||
yield key, value
|
||||
|
||||
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():
|
||||
return True
|
||||
return False
|
||||
|
||||
def get(self, *args):
|
||||
"""
|
||||
Get first available parameter in args
|
||||
:param args:
|
||||
:type args:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
try:
|
||||
for param in args:
|
||||
try:
|
||||
@ -128,15 +153,35 @@ class PylotParameter(object):
|
||||
raise ParameterError(e)
|
||||
|
||||
def get_defaults(self):
|
||||
"""
|
||||
get default parameters
|
||||
:return:
|
||||
:rtype: dict
|
||||
"""
|
||||
return self.__defaults
|
||||
|
||||
def get_main_para_names(self):
|
||||
"""
|
||||
Get main parameter names
|
||||
:return: list of keys available in parameters
|
||||
:rtype:
|
||||
"""
|
||||
return self._settings_main
|
||||
|
||||
def get_special_para_names(self):
|
||||
"""
|
||||
Get pick parameter names
|
||||
:return: list of keys available in parameters
|
||||
:rtype:
|
||||
"""
|
||||
return self._settings_special_pick
|
||||
|
||||
def get_all_para_names(self):
|
||||
"""
|
||||
Get all parameter names
|
||||
:return:
|
||||
:rtype: list
|
||||
"""
|
||||
all_names = []
|
||||
all_names += self.get_main_para_names()['dirs']
|
||||
all_names += self.get_main_para_names()['nlloc']
|
||||
@ -150,7 +195,43 @@ class PylotParameter(object):
|
||||
all_names += self.get_special_para_names()['quality']
|
||||
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):
|
||||
"""
|
||||
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)
|
||||
expect_type = self.get_defaults()[param]['type']
|
||||
if not is_type == expect_type and not is_type == tuple:
|
||||
@ -159,9 +240,25 @@ class PylotParameter(object):
|
||||
print(Warning(message))
|
||||
|
||||
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)
|
||||
|
||||
def setParam(self, **kwargs):
|
||||
"""
|
||||
Set multiple parameters
|
||||
:param kwargs:
|
||||
:type kwargs:
|
||||
:return:
|
||||
:rtype: None
|
||||
"""
|
||||
for key in kwargs:
|
||||
self.__setitem__(key, kwargs[key])
|
||||
|
||||
@ -170,11 +267,23 @@ class PylotParameter(object):
|
||||
print('ParameterError:\n non-existent parameter %s' % errmsg)
|
||||
|
||||
def reset_defaults(self):
|
||||
"""
|
||||
Reset current parameters to default parameters
|
||||
:return:
|
||||
:rtype: None
|
||||
"""
|
||||
defaults = self.get_defaults()
|
||||
for param in defaults:
|
||||
self.setParamKV(param, defaults[param]['value'])
|
||||
|
||||
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 self.__filename is not None:
|
||||
fnin = self.__filename
|
||||
@ -221,6 +330,13 @@ class PylotParameter(object):
|
||||
self.__parameter = self._parFileCont
|
||||
|
||||
def export2File(self, fnout):
|
||||
"""
|
||||
Export parameters to file
|
||||
:param fnout: Filename of export file
|
||||
:type fnout: str
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
fid_out = open(fnout, 'w')
|
||||
lines = []
|
||||
# for key, value in self.iteritems():
|
||||
@ -257,6 +373,19 @@ class PylotParameter(object):
|
||||
'quality assessment', None)
|
||||
|
||||
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:
|
||||
fid.write(separator)
|
||||
fid.write('#{}#\n'.format(title))
|
||||
@ -341,7 +470,9 @@ class FilterOptions(object):
|
||||
|
||||
def parseFilterOptions(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']:
|
||||
robject['freqmin'] = self.getFreq()[0]
|
||||
robject['freqmax'] = self.getFreq()[1]
|
||||
|
@ -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):
|
||||
'''
|
||||
|
||||
get creation info of obspy event
|
||||
:param agency_id:
|
||||
:param creation_time:
|
||||
: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):
|
||||
'''
|
||||
|
||||
:param timetohash:
|
||||
:type timetohash
|
||||
create unique resource id
|
||||
:param timetohash: event origin time to hash
|
||||
:type timetohash: class: `~obspy.core.utcdatetime.UTCDateTime` object
|
||||
:param restype: type of the resource, e.g. 'orig', 'earthquake' ...
|
||||
:type restype: str
|
||||
:param authority_id: name of the institution carrying out the processing
|
||||
|
@ -16,7 +16,8 @@ from pylot.core.io.inputs import PylotParameter
|
||||
from pylot.core.io.location import create_event, \
|
||||
create_magnitude
|
||||
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):
|
||||
@ -118,6 +119,13 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id='RUB', **kwargs):
|
||||
|
||||
|
||||
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
|
||||
picks = dict()
|
||||
phases_pilot = sio.loadmat(fn)
|
||||
@ -147,6 +155,13 @@ def picksdict_from_pilot(fn):
|
||||
|
||||
|
||||
def stations_from_pilot(stat_array):
|
||||
"""
|
||||
Create stations list from pilot station array
|
||||
:param stat_array:
|
||||
:type stat_array:
|
||||
:return:
|
||||
:rtype: list
|
||||
"""
|
||||
stations = list()
|
||||
cur_stat = None
|
||||
for stat in stat_array:
|
||||
@ -164,6 +179,13 @@ def stations_from_pilot(stat_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]
|
||||
microseconds = int((time_array[-1] - times[-1]) * 1e6)
|
||||
times.append(microseconds)
|
||||
@ -171,6 +193,13 @@ def convert_pilot_times(time_array):
|
||||
|
||||
|
||||
def picksdict_from_obs(fn):
|
||||
"""
|
||||
create pick dictionary from obs file
|
||||
:param fn: filename
|
||||
:type fn:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
picks = dict()
|
||||
station_name = str()
|
||||
for line in open(fn, 'r'):
|
||||
@ -207,6 +236,10 @@ def picksdict_from_picks(evt):
|
||||
network = pick.waveform_id.network_code
|
||||
mpp = pick.time
|
||||
spe = pick.time_errors.uncertainty
|
||||
if pick.filter_id:
|
||||
filter_id = backtransformFilterString(str(pick.filter_id.id))
|
||||
else:
|
||||
filter_id = None
|
||||
try:
|
||||
picker = str(pick.method_id)
|
||||
if picker.startswith('smi:local/'):
|
||||
@ -222,10 +255,15 @@ def picksdict_from_picks(evt):
|
||||
lpp = mpp + pick.time_errors.upper_uncertainty
|
||||
epp = mpp - pick.time_errors.lower_uncertainty
|
||||
except TypeError as e:
|
||||
msg = e + ',\n falling back to symmetric uncertainties'
|
||||
if not spe:
|
||||
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
|
||||
epp = mpp - spe
|
||||
warnings.warn(msg)
|
||||
lpp = mpp + spe
|
||||
epp = mpp - spe
|
||||
phase['mpp'] = mpp
|
||||
phase['epp'] = epp
|
||||
phase['lpp'] = lpp
|
||||
@ -233,6 +271,7 @@ def picksdict_from_picks(evt):
|
||||
phase['channel'] = channel
|
||||
phase['network'] = network
|
||||
phase['picker'] = picker
|
||||
phase['filter_id'] = filter_id if filter_id is not None else ''
|
||||
|
||||
onsets[pick.phase_hint] = phase.copy()
|
||||
picksdict[picker][station] = onsets.copy()
|
||||
@ -240,6 +279,16 @@ def picksdict_from_picks(evt):
|
||||
|
||||
|
||||
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()
|
||||
for station, onsets in picks.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,
|
||||
channel_code=ccode,
|
||||
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:
|
||||
polarity = phase['fm']
|
||||
if polarity == 'U' or '+':
|
||||
@ -290,7 +346,6 @@ def picks_from_picksdict(picks, creation_info=None):
|
||||
picks_list.append(pick)
|
||||
return picks_list
|
||||
|
||||
|
||||
def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0):
|
||||
import glob
|
||||
|
||||
@ -410,25 +465,24 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
||||
|
||||
HYPO71, NLLoc, VELEST, HYPOSAT, and hypoDD
|
||||
|
||||
:param: arrivals
|
||||
:type: dictionary containing all phase information including
|
||||
station ID, phase, first motion, weight (uncertainty),
|
||||
....
|
||||
:param arrivals:dictionary containing all phase information including
|
||||
station ID, phase, first motion, weight (uncertainty), ...
|
||||
:type arrivals: dict
|
||||
|
||||
:param: fformat
|
||||
:type: string, chosen file format (location routine),
|
||||
choose between NLLoc, HYPO71, HYPOSAT, VELEST,
|
||||
HYPOINVERSE, and hypoDD
|
||||
:param fformat: chosen file format (location routine),
|
||||
choose between NLLoc, HYPO71, HYPOSAT, VELEST,
|
||||
HYPOINVERSE, and hypoDD
|
||||
:type fformat: str
|
||||
|
||||
:param: filename, full path and name of phase file
|
||||
:type: string
|
||||
:param filename: full path and name of phase file
|
||||
:type filename: string
|
||||
|
||||
:param: parameter, all input information
|
||||
:type: object
|
||||
:param parameter: all input information
|
||||
: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
|
||||
:type: `obspy.core.event.Event` object
|
||||
:type eventinfo: `obspy.core.event.Event` object
|
||||
"""
|
||||
|
||||
if fformat == 'NLLoc':
|
||||
@ -874,10 +928,20 @@ def merge_picks(event, picks):
|
||||
|
||||
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.
|
||||
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.util.utils import loopIdentifyPhase, identifyPhase
|
||||
|
@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo):
|
||||
:param fnout: complete path to the exporting obs file
|
||||
:type fnout: str
|
||||
|
||||
:param: parameter, all input information
|
||||
:type: object
|
||||
:param parameter: all input information
|
||||
:type parameter: object
|
||||
|
||||
:param: eventinfo, source information needed for focmec format
|
||||
:type: list object
|
||||
:param eventinfo: source information needed for focmec format
|
||||
:type eventinfo: list object
|
||||
'''
|
||||
# write phases to FOCMEC-phase file
|
||||
writephases(picks, 'FOCMEC', fnout, parameter, eventinfo)
|
||||
|
@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo):
|
||||
:param fnout: complete path to the exporting obs file
|
||||
:type fnout: str
|
||||
|
||||
:param: parameter, all input information
|
||||
:type: object
|
||||
:param parameter: all input information
|
||||
:type parameter: object
|
||||
|
||||
:param: eventinfo, source information needed for HASH format
|
||||
:type: list object
|
||||
:param eventinfo: source information needed for HASH format
|
||||
:type eventinfo: list object
|
||||
'''
|
||||
# write phases to HASH-phase file
|
||||
writephases(picks, 'HASH', fnout, parameter, eventinfo)
|
||||
|
@ -18,8 +18,8 @@ def export(picks, fnout, parameter):
|
||||
:param fnout: complete path to the exporting obs file
|
||||
:type fnout: str
|
||||
|
||||
:param: parameter, all input information
|
||||
:type: object
|
||||
:param parameter: all input information
|
||||
:type parameter: object
|
||||
'''
|
||||
# write phases to HYPO71-phase file
|
||||
writephases(picks, 'HYPO71', fnout, parameter)
|
||||
|
@ -18,11 +18,11 @@ def export(picks, fnout, parameter, eventinfo):
|
||||
:param fnout: complete path to the exporting obs file
|
||||
:type fnout: str
|
||||
|
||||
:param: parameter, all input information
|
||||
:type: object
|
||||
:param parameter: all input information
|
||||
:type parameter: object
|
||||
|
||||
:param: eventinfo, source information needed for hypoDD format
|
||||
:type: list object
|
||||
:param eventinfo: source information needed for hypoDD format
|
||||
:type eventinfo: list object
|
||||
'''
|
||||
# write phases to hypoDD-phase file
|
||||
writephases(picks, 'hypoDD', fnout, parameter, eventinfo)
|
||||
|
@ -18,8 +18,8 @@ def export(picks, fnout, parameter):
|
||||
:param fnout: complete path to the exporting obs file
|
||||
:type fnout: str
|
||||
|
||||
:param: parameter, all input information
|
||||
:type: object
|
||||
:param parameter: all input information
|
||||
:type parameter: object
|
||||
'''
|
||||
# write phases to HYPOSAT-phase file
|
||||
writephases(picks, 'HYPOSAT', fnout, parameter)
|
||||
|
@ -28,8 +28,8 @@ def export(picks, fnout, parameter):
|
||||
:param fnout: complete path to the exporting obs file
|
||||
:type fnout: str
|
||||
|
||||
:param: parameter, all input information
|
||||
:type: object
|
||||
:param parameter: all input information
|
||||
:type parameter: object
|
||||
'''
|
||||
# write phases to NLLoc-phase file
|
||||
writephases(picks, 'NLLoc', fnout, parameter)
|
||||
@ -38,19 +38,19 @@ def export(picks, fnout, parameter):
|
||||
def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn):
|
||||
'''
|
||||
:param ctrfn: name of NLLoc-control file
|
||||
:type: str
|
||||
:type ctrfn: str
|
||||
|
||||
:param root: root path to NLLoc working directory
|
||||
:type: str
|
||||
:type root: str
|
||||
|
||||
:param nllocoutn: name of NLLoc-location output file
|
||||
:type: str
|
||||
:type nllocoutn: str
|
||||
|
||||
:param phasefn: name of NLLoc-input phase file
|
||||
:type: str
|
||||
:type phasefn: str
|
||||
|
||||
: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!
|
||||
# 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):
|
||||
"""
|
||||
takes an external program name
|
||||
:param fnin:
|
||||
:return:
|
||||
takes an external program name and tries to run it
|
||||
:param fnin: external program name
|
||||
:return: None
|
||||
"""
|
||||
|
||||
if infile is None:
|
||||
|
@ -18,11 +18,11 @@ def export(picks, fnout, eventinfo, parameter=None):
|
||||
:param fnout: complete path to the exporting obs file
|
||||
:type fnout: str
|
||||
|
||||
:param: eventinfo, source time needed for VELEST-cnv format
|
||||
:type: list object
|
||||
:param eventinfo: source time needed for VELEST-cnv format
|
||||
:type eventinfo: list object
|
||||
|
||||
:param: parameter, all input information
|
||||
:type: object
|
||||
:param parameter: all input information
|
||||
:type parameter: object
|
||||
'''
|
||||
# write phases to VELEST-phase file
|
||||
writephases(picks, 'VELEST', fnout, parameter, eventinfo)
|
||||
|
@ -155,7 +155,7 @@ def autopickstation(wfstream, pickparam, verbose=False,
|
||||
:type metadata: tuple (str, ~obspy.io.xseed.parser.Parser)
|
||||
:param origin: list containing origin objects representing origins for all events
|
||||
: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
|
||||
"""
|
||||
|
||||
|
@ -8,6 +8,13 @@ except:
|
||||
|
||||
|
||||
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:
|
||||
urlopen(url, timeout=1)
|
||||
return True
|
||||
|
@ -15,6 +15,11 @@ class Event(ObsPyEvent):
|
||||
'''
|
||||
|
||||
def __init__(self, path):
|
||||
"""
|
||||
Initialize event by event directory
|
||||
:param path: path to event directory
|
||||
:type path: str
|
||||
"""
|
||||
self.pylot_id = path.split('/')[-1]
|
||||
# initialize super class
|
||||
super(Event, self).__init__(resource_id=ResourceIdentifier('smi:local/' + self.pylot_id))
|
||||
@ -30,10 +35,20 @@ class Event(ObsPyEvent):
|
||||
self.get_notes()
|
||||
|
||||
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')
|
||||
return notesfile
|
||||
|
||||
def get_notes(self):
|
||||
"""
|
||||
set self.note attribute to content of notes file
|
||||
:return:
|
||||
:rtype: None
|
||||
"""
|
||||
notesfile = self.get_notes_path()
|
||||
if os.path.isfile(notesfile):
|
||||
with open(notesfile) as infile:
|
||||
@ -48,34 +63,81 @@ class Event(ObsPyEvent):
|
||||
pass
|
||||
|
||||
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)
|
||||
|
||||
def clearNotes(self):
|
||||
"""
|
||||
Clear event notes
|
||||
:return:
|
||||
:rtype: None
|
||||
"""
|
||||
self.notes = None
|
||||
|
||||
def isRefEvent(self):
|
||||
"""
|
||||
Return reference event flag
|
||||
:return: True if event is refence event
|
||||
:rtype: bool
|
||||
"""
|
||||
return self._refEvent
|
||||
|
||||
def isTestEvent(self):
|
||||
"""
|
||||
Return test event flag
|
||||
:return: True if event is test event
|
||||
:rtype: bool
|
||||
"""
|
||||
return self._testEvent
|
||||
|
||||
def setRefEvent(self, bool):
|
||||
"""
|
||||
Set reference event flag
|
||||
:param bool: new reference event flag
|
||||
:type bool: bool
|
||||
:return:
|
||||
:rtype: None
|
||||
"""
|
||||
self._refEvent = bool
|
||||
if bool: self._testEvent = False
|
||||
|
||||
def setTestEvent(self, bool):
|
||||
"""
|
||||
Set test event flag
|
||||
:param bool: new test event flag
|
||||
:type bool: bool
|
||||
:return:
|
||||
:rtype: None
|
||||
"""
|
||||
self._testEvent = bool
|
||||
if bool: self._refEvent = False
|
||||
|
||||
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))):
|
||||
if picktype in str(pick.method_id):
|
||||
self.picks.pop(index)
|
||||
|
||||
def addPicks(self, picks):
|
||||
'''
|
||||
"""
|
||||
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:
|
||||
self.pylot_picks[station] = picks[station]
|
||||
# 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)
|
||||
|
||||
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:
|
||||
self.pylot_autopicks[station] = autopicks[station]
|
||||
# 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)
|
||||
|
||||
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:
|
||||
self.pylot_picks[station] = pick
|
||||
else:
|
||||
@ -101,21 +179,46 @@ class Event(ObsPyEvent):
|
||||
self.picks += picks_from_picksdict(self.pylot_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.clearObsPyPicks('manual')
|
||||
self.picks += picks_from_picksdict(self.pylot_picks)
|
||||
|
||||
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():
|
||||
return self.pylot_picks[station]
|
||||
|
||||
def getPicks(self):
|
||||
"""
|
||||
Return pylot picks
|
||||
:return:
|
||||
:rtype: dict
|
||||
"""
|
||||
return self.pylot_picks
|
||||
|
||||
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:
|
||||
self.pylot_autopicks[station] = pick
|
||||
else:
|
||||
@ -127,25 +230,46 @@ class Event(ObsPyEvent):
|
||||
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
||||
|
||||
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.clearObsPyPicks('auto')
|
||||
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
||||
|
||||
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():
|
||||
return self.pylot_autopicks[station]
|
||||
|
||||
def getAutopicks(self):
|
||||
"""
|
||||
Get autopicks of event
|
||||
:return: dict containing automatic picks
|
||||
:rtype: dict
|
||||
"""
|
||||
return self.pylot_autopicks
|
||||
|
||||
def save(self, filename):
|
||||
'''
|
||||
Save PyLoT Event to a file.
|
||||
"""
|
||||
Save PyLoT Event to a file.
|
||||
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:
|
||||
import cPickle
|
||||
except ImportError:
|
||||
@ -159,9 +283,13 @@ class Event(ObsPyEvent):
|
||||
|
||||
@staticmethod
|
||||
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:
|
||||
import cPickle
|
||||
except ImportError:
|
||||
|
@ -24,7 +24,7 @@ class Thread(QThread):
|
||||
if self.redirect_stdout:
|
||||
sys.stdout = self
|
||||
try:
|
||||
if self.arg:
|
||||
if self.arg is not None:
|
||||
self.data = self.func(self.arg)
|
||||
else:
|
||||
self.data = self.func()
|
||||
|
@ -13,7 +13,7 @@ from obspy.core import AttribDict
|
||||
from obspy.signal.rotate import rotate2zne
|
||||
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 scipy.interpolate import splrep, splev
|
||||
@ -31,6 +31,15 @@ def _pickle_method(m):
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
@ -327,9 +336,9 @@ def real_Bool(value):
|
||||
:return: true boolean value
|
||||
:rtype: bool
|
||||
"""
|
||||
if value == 'True':
|
||||
if value in ['True', 'true']:
|
||||
return True
|
||||
elif value == 'False':
|
||||
elif value in ['False', 'false']:
|
||||
return False
|
||||
else:
|
||||
return value
|
||||
@ -391,6 +400,38 @@ def full_range(stream):
|
||||
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):
|
||||
"""
|
||||
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
|
||||
azimut = blockette_.azimuth
|
||||
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)
|
||||
raise ValueError(error_msg)
|
||||
return dip, azimut
|
||||
@ -1111,6 +1152,9 @@ def loopIdentifyPhase(phase):
|
||||
"""
|
||||
from pylot.core.util.defaults import ALTSUFFIX
|
||||
|
||||
if phase == None:
|
||||
raise NameError('Can not identify phase that is None')
|
||||
|
||||
phase_copy = phase
|
||||
while not identifyPhase(phase_copy):
|
||||
identified = False
|
||||
@ -1135,8 +1179,10 @@ def identifyPhase(phase):
|
||||
:rtype: str or bool
|
||||
"""
|
||||
# common phase suffix for P and S
|
||||
common_P = ['P', 'p']
|
||||
common_P = ['P', 'p', 'R']
|
||||
common_S = ['S', 's']
|
||||
if phase is None:
|
||||
return False
|
||||
if phase[-1] in common_P:
|
||||
return 'P'
|
||||
if phase[-1] in common_S:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -124,7 +124,6 @@ color:rgba(0, 0, 0, 255);
|
||||
border-style: outset;
|
||||
border-width: 1px;
|
||||
border-color: rgba(100, 100, 120, 255);
|
||||
min-width: 6em;
|
||||
padding: 4px;
|
||||
padding-left:5px;
|
||||
padding-right:5px;
|
||||
|
@ -123,7 +123,6 @@ color:rgba(255, 255, 255, 255);
|
||||
border-style: outset;
|
||||
border-width: 2px;
|
||||
border-color: rgba(50, 50, 60, 255);
|
||||
min-width: 6em;
|
||||
padding: 4px;
|
||||
padding-left:5px;
|
||||
padding-right:5px;
|
||||
|
Loading…
Reference in New Issue
Block a user