Merge remote-tracking branch 'origin/develop' into feature/refactor
This commit is contained in:
commit
a45e817213
364
PyLoT.py
364
PyLoT.py
@ -32,6 +32,8 @@ import matplotlib
|
|||||||
|
|
||||||
matplotlib.use('Qt4Agg')
|
matplotlib.use('Qt4Agg')
|
||||||
matplotlib.rcParams['backend.qt4'] = 'PySide'
|
matplotlib.rcParams['backend.qt4'] = 'PySide'
|
||||||
|
matplotlib.rcParams['savefig.dpi'] = 300
|
||||||
|
|
||||||
|
|
||||||
from PySide import QtGui, QtCore
|
from PySide import QtGui, QtCore
|
||||||
from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, \
|
from PySide.QtCore import QCoreApplication, QSettings, Signal, QFile, \
|
||||||
@ -48,12 +50,7 @@ from obspy.core.util import AttribDict
|
|||||||
|
|
||||||
from pylot.core.util.obspyDMT_interface import check_obspydmt_structure
|
from pylot.core.util.obspyDMT_interface import check_obspydmt_structure
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
except Exception as e:
|
|
||||||
print('PyLoT: Could not import pyqtgraph. {}'.format(e))
|
|
||||||
pg = None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from matplotlib.backends.backend_qt4agg import FigureCanvas
|
from matplotlib.backends.backend_qt4agg import FigureCanvas
|
||||||
@ -67,25 +64,25 @@ from pylot.core.io.data import Data
|
|||||||
from pylot.core.io.inputs import FilterOptions, PylotParameter
|
from pylot.core.io.inputs import FilterOptions, PylotParameter
|
||||||
from autoPyLoT import autoPyLoT
|
from autoPyLoT import autoPyLoT
|
||||||
from pylot.core.pick.compare import Comparison
|
from pylot.core.pick.compare import Comparison
|
||||||
from pylot.core.pick.utils import symmetrize_error, get_quality_class
|
from pylot.core.pick.utils import symmetrize_error, getQualityFromUncertainty, getPickQuality, get_quality_class
|
||||||
from pylot.core.io.phases import picksdict_from_picks
|
from pylot.core.io.phases import picksdict_from_picks
|
||||||
import pylot.core.loc.nll as nll
|
import pylot.core.loc.nll as nll
|
||||||
from pylot.core.util.defaults import FILTERDEFAULTS, SetChannelComponents
|
from pylot.core.util.defaults import FILTERDEFAULTS
|
||||||
from pylot.core.util.errors import DatastructureError, \
|
from pylot.core.util.errors import DatastructureError, \
|
||||||
OverwriteError
|
OverwriteError
|
||||||
from pylot.core.util.connection import checkurl
|
from pylot.core.util.connection import checkurl
|
||||||
from pylot.core.util.dataprocessing import read_metadata, restitute_data
|
from pylot.core.util.dataprocessing import 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, \
|
||||||
check4rotated, transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
check4rotated, transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
||||||
check_all_pylot, real_Bool
|
check_all_pylot, real_Bool, SetChannelComponents
|
||||||
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, \
|
||||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||||
getDataType, ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
getDataType, ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||||
CompareEventsWidget
|
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget
|
||||||
from pylot.core.util.array_map import Array_map
|
from pylot.core.util.array_map import Array_map
|
||||||
from pylot.core.util.structure import DATASTRUCTURE
|
from pylot.core.util.structure import DATASTRUCTURE
|
||||||
from pylot.core.util.thread import Thread, Worker
|
from pylot.core.util.thread import Thread, Worker
|
||||||
@ -121,7 +118,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.apw = None
|
self.apw = None
|
||||||
self.paraBox = None
|
self.paraBox = None
|
||||||
self.array_map = None
|
self.array_map = None
|
||||||
self._metadata = None
|
self._metadata = Metadata()
|
||||||
self._eventChanged = [False, False]
|
self._eventChanged = [False, False]
|
||||||
self.apd_local = None
|
self.apd_local = None
|
||||||
self.apd_sge = None
|
self.apd_sge = None
|
||||||
@ -135,6 +132,9 @@ class MainWindow(QMainWindow):
|
|||||||
self._ctrl = False # control key pressed
|
self._ctrl = False # control key pressed
|
||||||
self._shift = False # shift key pressed
|
self._shift = False # shift key pressed
|
||||||
|
|
||||||
|
self.drawnPicks = {'auto': {},
|
||||||
|
'manual': {}}
|
||||||
|
|
||||||
# default factor for dataplot e.g. enabling/disabling scrollarea
|
# default factor for dataplot e.g. enabling/disabling scrollarea
|
||||||
self.height_factor = 12
|
self.height_factor = 12
|
||||||
self.plot_method = 'normal'
|
self.plot_method = 'normal'
|
||||||
@ -155,6 +155,8 @@ class MainWindow(QMainWindow):
|
|||||||
self.data._new = False
|
self.data._new = False
|
||||||
self.autodata = Data(self)
|
self.autodata = Data(self)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
if settings.value("user/FullName", None) is None:
|
if settings.value("user/FullName", None) is None:
|
||||||
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
|
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
|
||||||
settings.setValue("user/FullName", fulluser)
|
settings.setValue("user/FullName", fulluser)
|
||||||
@ -164,6 +166,21 @@ class MainWindow(QMainWindow):
|
|||||||
"Enter authority/institution name:",
|
"Enter authority/institution name:",
|
||||||
"Authority")
|
"Authority")
|
||||||
settings.setValue("agency_id", agency)
|
settings.setValue("agency_id", agency)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
qmb = QMessageBox(self, icon=QMessageBox.Question,
|
||||||
|
text='Could not init application settings: {}.'
|
||||||
|
'Do you want to reset application settings?'.format(e),
|
||||||
|
windowTitle='PyLoT - Init QSettings warning')
|
||||||
|
qmb.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
||||||
|
qmb.setDefaultButton(QMessageBox.No)
|
||||||
|
ret = qmb.exec_()
|
||||||
|
if ret == qmb.Yes:
|
||||||
|
settings.clear()
|
||||||
|
else:
|
||||||
|
sys.exit()
|
||||||
|
print('Settings cleared!')
|
||||||
|
|
||||||
self.fnames = None
|
self.fnames = None
|
||||||
self._stime = None
|
self._stime = None
|
||||||
structure_setting = settings.value("data/Structure", "PILOT")
|
structure_setting = settings.value("data/Structure", "PILOT")
|
||||||
@ -195,7 +212,6 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
self.loc = False
|
self.loc = False
|
||||||
|
|
||||||
|
|
||||||
def init_config_files(self, infile):
|
def init_config_files(self, infile):
|
||||||
pylot_config_dir = os.path.join(os.path.expanduser('~'), '.pylot')
|
pylot_config_dir = os.path.join(os.path.expanduser('~'), '.pylot')
|
||||||
if not os.path.exists(pylot_config_dir):
|
if not os.path.exists(pylot_config_dir):
|
||||||
@ -210,7 +226,6 @@ class MainWindow(QMainWindow):
|
|||||||
self._inputs.export2File(infile)
|
self._inputs.export2File(infile)
|
||||||
self.infile = infile
|
self.infile = infile
|
||||||
|
|
||||||
|
|
||||||
def setupUi(self):
|
def setupUi(self):
|
||||||
try:
|
try:
|
||||||
self.startTime = min(
|
self.startTime = min(
|
||||||
@ -339,7 +354,7 @@ class MainWindow(QMainWindow):
|
|||||||
"Ctrl+A",
|
"Ctrl+A",
|
||||||
openEventsIcon,
|
openEventsIcon,
|
||||||
"Load event data automatically "
|
"Load event data automatically "
|
||||||
"for for all events.")
|
"for all events.")
|
||||||
self.openEventsAutoAction.setEnabled(False)
|
self.openEventsAutoAction.setEnabled(False)
|
||||||
self.openEventsAutoAction.setData(None)
|
self.openEventsAutoAction.setData(None)
|
||||||
|
|
||||||
@ -398,10 +413,10 @@ class MainWindow(QMainWindow):
|
|||||||
self.adjustFilterOptions,
|
self.adjustFilterOptions,
|
||||||
"Ctrl+F", self.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, "Manage &Inventories ...",
|
||||||
self.get_new_metadata,
|
self.add_metadata,
|
||||||
"Ctrl+I", self.inventoryIcon,
|
"Ctrl+I", self.inventoryIcon,
|
||||||
"""Select metadata for current project""",
|
"""Manage metadata for current project""",
|
||||||
False)
|
False)
|
||||||
self.initMapAction = self.createAction(self, "Init array map ...",
|
self.initMapAction = self.createAction(self, "Init array map ...",
|
||||||
self.init_array_map,
|
self.init_array_map,
|
||||||
@ -428,6 +443,8 @@ class MainWindow(QMainWindow):
|
|||||||
slot=self.pickQualities, shortcut='Alt+Q',
|
slot=self.pickQualities, shortcut='Alt+Q',
|
||||||
icon=qualities_icon, tip='Histogram of pick qualities')
|
icon=qualities_icon, tip='Histogram of pick qualities')
|
||||||
self.qualities_action.setEnabled(False)
|
self.qualities_action.setEnabled(False)
|
||||||
|
# MP MP not yet implemented, therefore hide:
|
||||||
|
self.qualities_action.setVisible(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,
|
||||||
@ -471,7 +488,6 @@ class MainWindow(QMainWindow):
|
|||||||
checkable=True)
|
checkable=True)
|
||||||
self.e_action.setEnabled(False)
|
self.e_action.setEnabled(False)
|
||||||
|
|
||||||
|
|
||||||
componentActions = (self.z_action, self.n_action, self.e_action)
|
componentActions = (self.z_action, self.n_action, self.e_action)
|
||||||
|
|
||||||
self.auto_tune = self.createAction(parent=self, text='autoTune',
|
self.auto_tune = self.createAction(parent=self, text='autoTune',
|
||||||
@ -504,15 +520,15 @@ class MainWindow(QMainWindow):
|
|||||||
# pickToolActions = (selectStation, )
|
# pickToolActions = (selectStation, )
|
||||||
# pickToolBar.setObjectName("PickTools")
|
# pickToolBar.setObjectName("PickTools")
|
||||||
# self.addActions(pickToolBar, pickToolActions)
|
# self.addActions(pickToolBar, pickToolActions)
|
||||||
self.locateEvent = self.createAction(parent=self, text='locate the event',
|
self.locateEventAction = self.createAction(parent=self, text='locate the event',
|
||||||
slot=self.locate_event,
|
slot=self.locate_event,
|
||||||
shortcut='Alt+Ctrl+L',
|
shortcut='Alt+Ctrl+L',
|
||||||
icon=locate_icon,
|
icon=locate_icon,
|
||||||
tip='Locate the event using '
|
tip='Locate the event using '
|
||||||
'the displayed manual arrivals.')
|
'the displayed manual arrivals.')
|
||||||
self.locateEvent.setEnabled(False)
|
self.locateEventAction.setEnabled(False)
|
||||||
|
|
||||||
locationToolActions = (self.locateEvent,)
|
locationToolActions = (self.locateEventAction,)
|
||||||
|
|
||||||
# add top menu
|
# add top menu
|
||||||
self.fileMenu = self.menuBar().addMenu('&File')
|
self.fileMenu = self.menuBar().addMenu('&File')
|
||||||
@ -546,13 +562,11 @@ class MainWindow(QMainWindow):
|
|||||||
self.openProjectAction, self.saveProjectAction,
|
self.openProjectAction, self.saveProjectAction,
|
||||||
self.saveProjectAsAction)
|
self.saveProjectAsAction)
|
||||||
|
|
||||||
|
|
||||||
eventToolActions = (self.addEventDataAction,
|
eventToolActions = (self.addEventDataAction,
|
||||||
self.openEventAction, self.openEventsAutoAction,
|
self.openEventAction, self.openEventsAutoAction,
|
||||||
self.saveEventAction, self.loadlocationaction,
|
self.saveEventAction, self.loadlocationaction,
|
||||||
self.loadpilotevent)
|
self.loadpilotevent)
|
||||||
|
|
||||||
|
|
||||||
toolbars_keys = [
|
toolbars_keys = [
|
||||||
"FileTools",
|
"FileTools",
|
||||||
"EventTools",
|
"EventTools",
|
||||||
@ -616,7 +630,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.tabs.currentChanged.connect(self.refreshTabs)
|
self.tabs.currentChanged.connect(self.refreshTabs)
|
||||||
|
|
||||||
# add progressbar
|
# add progressbar
|
||||||
self.mainProgressBarWidget = QtGui.QWidget()
|
self.mainProgressBarWidget = ProgressBarWidget(self)
|
||||||
self._main_layout.addWidget(self.mainProgressBarWidget)
|
self._main_layout.addWidget(self.mainProgressBarWidget)
|
||||||
|
|
||||||
# add scroll area used in case number of traces gets too high
|
# add scroll area used in case number of traces gets too high
|
||||||
@ -672,15 +686,9 @@ class MainWindow(QMainWindow):
|
|||||||
self.setCentralWidget(_widget)
|
self.setCentralWidget(_widget)
|
||||||
|
|
||||||
def init_wfWidget(self):
|
def init_wfWidget(self):
|
||||||
settings = QSettings()
|
|
||||||
xlab = self.startTime.strftime('seconds since %Y/%m/%d %H:%M:%S (%Z)')
|
xlab = self.startTime.strftime('seconds since %Y/%m/%d %H:%M:%S (%Z)')
|
||||||
plottitle = None # "Overview: {0} components ".format(self.getComponent())
|
plottitle = None # "Overview: {0} components ".format(self.getComponent())
|
||||||
self.disconnectWFplotEvents()
|
self.disconnectWFplotEvents()
|
||||||
if str(settings.value('pyqtgraphic')) == 'false' or not pg:
|
|
||||||
self.pg = False
|
|
||||||
self.dataPlot = PylotCanvas(parent=self, connect_events=False, multicursor=True)
|
|
||||||
self.dataPlot.updateWidget(xlab, None, plottitle)
|
|
||||||
else:
|
|
||||||
self.pg = pg
|
self.pg = pg
|
||||||
self.dataPlot = WaveformWidgetPG(parent=self,
|
self.dataPlot = WaveformWidgetPG(parent=self,
|
||||||
title=plottitle)
|
title=plottitle)
|
||||||
@ -860,7 +868,8 @@ class MainWindow(QMainWindow):
|
|||||||
def inputs(self):
|
def inputs(self):
|
||||||
return self._inputs
|
return self._inputs
|
||||||
|
|
||||||
def getRoot(self):
|
@staticmethod
|
||||||
|
def getRoot():
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
return settings.value("data/dataRoot")
|
return settings.value("data/dataRoot")
|
||||||
|
|
||||||
@ -900,6 +909,7 @@ class MainWindow(QMainWindow):
|
|||||||
return
|
return
|
||||||
if self.get_current_event().pylot_picks:
|
if self.get_current_event().pylot_picks:
|
||||||
self.refreshEvents()
|
self.refreshEvents()
|
||||||
|
self.fill_eventbox()
|
||||||
self.setDirty(True)
|
self.setDirty(True)
|
||||||
|
|
||||||
def load_data(self, fname=None, loc=False, draw=True, event=None, overwrite=False):
|
def load_data(self, fname=None, loc=False, draw=True, event=None, overwrite=False):
|
||||||
@ -934,7 +944,9 @@ class MainWindow(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.data = data
|
self.data = data
|
||||||
print('Loading event info from file {}.'.format(fname))
|
message = 'Loading event info from file {}.'.format(fname)
|
||||||
|
print(message)
|
||||||
|
self.update_status(message)
|
||||||
if not loc:
|
if not loc:
|
||||||
self.updatePicks(type='auto', event=event)
|
self.updatePicks(type='auto', event=event)
|
||||||
self.updatePicks(type='manual', event=event)
|
self.updatePicks(type='manual', event=event)
|
||||||
@ -1019,7 +1031,8 @@ class MainWindow(QMainWindow):
|
|||||||
raise DatastructureError('not specified')
|
raise DatastructureError('not specified')
|
||||||
return fnames
|
return fnames
|
||||||
|
|
||||||
def getPhaseID(self, phase):
|
@staticmethod
|
||||||
|
def getPhaseID(phase):
|
||||||
return identifyPhaseID(phase)
|
return identifyPhaseID(phase)
|
||||||
|
|
||||||
def get_current_event(self, eventbox=None):
|
def get_current_event(self, eventbox=None):
|
||||||
@ -1028,7 +1041,7 @@ class MainWindow(QMainWindow):
|
|||||||
'''
|
'''
|
||||||
if not eventbox:
|
if not eventbox:
|
||||||
eventbox = self.eventBox
|
eventbox = self.eventBox
|
||||||
path = eventbox.currentText()
|
path = eventbox.currentText().split('*')[0]
|
||||||
return self.project.getEventFromPath(path)
|
return self.project.getEventFromPath(path)
|
||||||
|
|
||||||
def get_current_event_path(self, eventbox=None):
|
def get_current_event_path(self, eventbox=None):
|
||||||
@ -1065,7 +1078,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.dataStructure = DATASTRUCTURE['obspyDMT']()
|
self.dataStructure = DATASTRUCTURE['obspyDMT']()
|
||||||
eventlist = check_all_obspy(eventlist)
|
eventlist = check_all_obspy(eventlist)
|
||||||
else:
|
else:
|
||||||
print('Settings Datastructure to PILOT')
|
print('Setting Datastructure to PILOT')
|
||||||
self.dataStructure = DATASTRUCTURE['PILOT']()
|
self.dataStructure = DATASTRUCTURE['PILOT']()
|
||||||
eventlist = check_all_pylot(eventlist)
|
eventlist = check_all_pylot(eventlist)
|
||||||
if not eventlist:
|
if not eventlist:
|
||||||
@ -1147,7 +1160,8 @@ class MainWindow(QMainWindow):
|
|||||||
self.project.remove_event(event)
|
self.project.remove_event(event)
|
||||||
self.init_events(True)
|
self.init_events(True)
|
||||||
|
|
||||||
def createEventBox(self):
|
@staticmethod
|
||||||
|
def createEventBox():
|
||||||
'''
|
'''
|
||||||
Eventbox generator.
|
Eventbox generator.
|
||||||
'''
|
'''
|
||||||
@ -1257,6 +1271,8 @@ class MainWindow(QMainWindow):
|
|||||||
'auto': event.pylot_autopicks}
|
'auto': event.pylot_autopicks}
|
||||||
ma_count = {'manual': 0,
|
ma_count = {'manual': 0,
|
||||||
'auto': 0}
|
'auto': 0}
|
||||||
|
ma_count_total = {'manual': 0,
|
||||||
|
'auto': 0}
|
||||||
|
|
||||||
for ma in ma_props.keys():
|
for ma in ma_props.keys():
|
||||||
if ma_props[ma]:
|
if ma_props[ma]:
|
||||||
@ -1264,8 +1280,9 @@ class MainWindow(QMainWindow):
|
|||||||
for phasename, pick in picks.items():
|
for phasename, pick in picks.items():
|
||||||
if not type(pick) in [dict, AttribDict]:
|
if not type(pick) in [dict, AttribDict]:
|
||||||
continue
|
continue
|
||||||
if get_quality_class(has_spe(pick), phaseErrors[self.getPhaseID(phasename)]) < 4:
|
if pick.get('spe'):
|
||||||
ma_count[ma] += 1
|
ma_count[ma] += 1
|
||||||
|
ma_count_total[ma] += 1
|
||||||
|
|
||||||
event_ref = event.isRefEvent()
|
event_ref = event.isRefEvent()
|
||||||
event_test = event.isTestEvent()
|
event_test = event.isTestEvent()
|
||||||
@ -1287,15 +1304,18 @@ class MainWindow(QMainWindow):
|
|||||||
# p=event_npicks,
|
# p=event_npicks,
|
||||||
# a=event_nautopicks)
|
# a=event_nautopicks)
|
||||||
|
|
||||||
item_path = QtGui.QStandardItem('{path:{plen}}'.format(path=event_path, plen=plmax))
|
event_str = '{path:{plen}}'.format(path=event_path, plen=plmax)
|
||||||
|
if event.dirty:
|
||||||
|
event_str += '*'
|
||||||
|
item_path = QtGui.QStandardItem(event_str)
|
||||||
item_time = QtGui.QStandardItem('{}'.format(time))
|
item_time = QtGui.QStandardItem('{}'.format(time))
|
||||||
item_lat = QtGui.QStandardItem('{}'.format(lat))
|
item_lat = QtGui.QStandardItem('{}'.format(lat))
|
||||||
item_lon = QtGui.QStandardItem('{}'.format(lon))
|
item_lon = QtGui.QStandardItem('{}'.format(lon))
|
||||||
item_depth = QtGui.QStandardItem('{}'.format(depth))
|
item_depth = QtGui.QStandardItem('{}'.format(depth))
|
||||||
item_mag = QtGui.QStandardItem('{}'.format(mag))
|
item_mag = QtGui.QStandardItem('{}'.format(mag))
|
||||||
item_nmp = QtGui.QStandardItem(str(ma_count['manual']))
|
item_nmp = QtGui.QStandardItem('{}({})'.format(ma_count['manual'], ma_count_total['manual']))
|
||||||
item_nmp.setIcon(self.manupicksicon_small)
|
item_nmp.setIcon(self.manupicksicon_small)
|
||||||
item_nap = QtGui.QStandardItem(str(ma_count['auto']))
|
item_nap = QtGui.QStandardItem('{}({})'.format(ma_count['auto'], ma_count_total['auto']))
|
||||||
item_nap.setIcon(self.autopicksicon_small)
|
item_nap.setIcon(self.autopicksicon_small)
|
||||||
item_ref = QtGui.QStandardItem() # str(event_ref))
|
item_ref = QtGui.QStandardItem() # str(event_ref))
|
||||||
item_test = QtGui.QStandardItem() # str(event_test))
|
item_test = QtGui.QStandardItem() # str(event_test))
|
||||||
@ -1330,7 +1350,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.setItemColor(itemlist, id, event, current_event)
|
self.setItemColor(itemlist, id, event, current_event)
|
||||||
|
|
||||||
model.appendRow(itemlist)
|
model.appendRow(itemlist)
|
||||||
if not event.path == self.eventBox.itemText(id).strip():
|
if not event.path == self.eventBox.itemText(id).split('*')[0].strip():
|
||||||
message = ('Path missmatch creating eventbox.\n'
|
message = ('Path missmatch creating eventbox.\n'
|
||||||
'{} unequal {}.'
|
'{} unequal {}.'
|
||||||
.format(event.path, self.eventBox.itemText(id)))
|
.format(event.path, self.eventBox.itemText(id)))
|
||||||
@ -1429,15 +1449,24 @@ class MainWindow(QMainWindow):
|
|||||||
self.update_status(msg)
|
self.update_status(msg)
|
||||||
print(msg)
|
print(msg)
|
||||||
|
|
||||||
|
event.dirty = False
|
||||||
|
self.fill_eventbox()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def exportAllEvents(self, outformats=['.xml']):
|
def exportEvents(self, outformats=['.xml'], events='all'):
|
||||||
for event in self.project.eventlist:
|
if events == 'all':
|
||||||
|
events = self.project.eventlist
|
||||||
|
assert type(events) == list, 'Wrong input type: {}'.format(type(events))
|
||||||
|
for event in events:
|
||||||
|
if not event.dirty:
|
||||||
|
continue
|
||||||
self.get_data().setEvtData(event)
|
self.get_data().setEvtData(event)
|
||||||
try:
|
try:
|
||||||
self.saveData(event, event.path, outformats)
|
self.saveData(event, event.path, outformats)
|
||||||
|
event.dirty = False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('WARNING! Could not save event {}. Reason: {}'.format(event.path, e))
|
print('WARNING! Could not save event {}. Reason: {}'.format(event.path, e))
|
||||||
|
self.fill_eventbox()
|
||||||
|
|
||||||
def enableSaveEventAction(self):
|
def enableSaveEventAction(self):
|
||||||
self.saveEventAction.setEnabled(True)
|
self.saveEventAction.setEnabled(True)
|
||||||
@ -1485,7 +1514,6 @@ class MainWindow(QMainWindow):
|
|||||||
if len(eventdict) < 1:
|
if len(eventdict) < 1:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# init event selection options for autopick
|
# init event selection options for autopick
|
||||||
self.compareoptions = [('tune events', self.get_ref_events, self._style['ref']['rgba']),
|
self.compareoptions = [('tune events', self.get_ref_events, self._style['ref']['rgba']),
|
||||||
('test events', self.get_test_events, self._style['test']['rgba']),
|
('test events', self.get_test_events, self._style['test']['rgba']),
|
||||||
@ -1512,7 +1540,6 @@ class MainWindow(QMainWindow):
|
|||||||
compare_widget = self.buildMultiCompareWidget(eventlist_overlap)
|
compare_widget = self.buildMultiCompareWidget(eventlist_overlap)
|
||||||
compare_widget.show()
|
compare_widget.show()
|
||||||
|
|
||||||
|
|
||||||
def buildMultiCompareWidget(self, eventlist):
|
def buildMultiCompareWidget(self, eventlist):
|
||||||
global_comparison = Comparison(eventlist=eventlist)
|
global_comparison = Comparison(eventlist=eventlist)
|
||||||
compare_widget = ComparisonWidget(global_comparison, self)
|
compare_widget = ComparisonWidget(global_comparison, self)
|
||||||
@ -1911,7 +1938,7 @@ class MainWindow(QMainWindow):
|
|||||||
event = self.get_current_event()
|
event = self.get_current_event()
|
||||||
if event.pylot_picks:
|
if event.pylot_picks:
|
||||||
self.drawPicks(picktype='manual')
|
self.drawPicks(picktype='manual')
|
||||||
self.locateEvent.setEnabled(True)
|
self.locateEventAction.setEnabled(True)
|
||||||
self.qualities_action.setEnabled(True)
|
self.qualities_action.setEnabled(True)
|
||||||
if event.pylot_autopicks:
|
if event.pylot_autopicks:
|
||||||
self.drawPicks(picktype='auto')
|
self.drawPicks(picktype='auto')
|
||||||
@ -1919,8 +1946,18 @@ class MainWindow(QMainWindow):
|
|||||||
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()
|
||||||
|
# TODO: Quick and dirty, improve this on later iteration
|
||||||
|
if self.obspy_dmt:
|
||||||
|
invpath = os.path.join(self.get_current_event_path(), 'resp')
|
||||||
|
if not invpath in self.metadata.inventories:
|
||||||
|
self.metadata.add_inventory(invpath)
|
||||||
|
# check if directory is empty
|
||||||
|
if os.listdir(invpath):
|
||||||
|
self.init_map_button.setEnabled(True)
|
||||||
|
self.initMapAction.setEnabled(True)
|
||||||
|
|
||||||
def checkEvent4comparison(self, event):
|
@staticmethod
|
||||||
|
def checkEvent4comparison(event):
|
||||||
if event.pylot_picks and event.pylot_autopicks:
|
if event.pylot_picks and event.pylot_autopicks:
|
||||||
for station in event.pylot_picks:
|
for station in event.pylot_picks:
|
||||||
if station in event.pylot_autopicks:
|
if station in event.pylot_autopicks:
|
||||||
@ -1972,6 +2009,9 @@ class MainWindow(QMainWindow):
|
|||||||
self.openEventAction.setEnabled(False)
|
self.openEventAction.setEnabled(False)
|
||||||
self.openEventsAutoAction.setEnabled(False)
|
self.openEventsAutoAction.setEnabled(False)
|
||||||
self.loadpilotevent.setEnabled(False)
|
self.loadpilotevent.setEnabled(False)
|
||||||
|
self.compare_action.setEnabled(False)
|
||||||
|
self.qualities_action.setEnabled(False)
|
||||||
|
self.locateEventAction.setEnabled(False)
|
||||||
if not refresh_plot:
|
if not refresh_plot:
|
||||||
self.wf_scroll_area.setVisible(False)
|
self.wf_scroll_area.setVisible(False)
|
||||||
self.no_data_label.setVisible(True)
|
self.no_data_label.setVisible(True)
|
||||||
@ -2081,7 +2121,8 @@ class MainWindow(QMainWindow):
|
|||||||
elif self.filterActionS.isChecked():
|
elif self.filterActionS.isChecked():
|
||||||
phase = 'S'
|
phase = 'S'
|
||||||
if self.getFilterOptions():
|
if self.getFilterOptions():
|
||||||
if (phase == 'P' and self.filterActionP.isChecked()) or (phase == 'S' and self.filterActionS.isChecked()):
|
if (phase == 'P' and self.filterActionP.isChecked()) or (
|
||||||
|
phase == 'S' and self.filterActionS.isChecked()):
|
||||||
kwargs = self.getFilterOptions()[phase].parseFilterOptions()
|
kwargs = self.getFilterOptions()[phase].parseFilterOptions()
|
||||||
self.pushFilterWF(kwargs)
|
self.pushFilterWF(kwargs)
|
||||||
else:
|
else:
|
||||||
@ -2321,14 +2362,12 @@ class MainWindow(QMainWindow):
|
|||||||
if pickDlg._dirty:
|
if pickDlg._dirty:
|
||||||
self.setDirty(True)
|
self.setDirty(True)
|
||||||
self.update_status('picks accepted ({0})'.format(station))
|
self.update_status('picks accepted ({0})'.format(station))
|
||||||
replot1 = self.addPicks(station, pickDlg.getPicks(picktype='manual'), type='manual')
|
self.addPicks(station, pickDlg.getPicks(picktype='manual'), type='manual')
|
||||||
replot2 = self.addPicks(station, pickDlg.getPicks(picktype='auto'), type='auto')
|
self.addPicks(station, pickDlg.getPicks(picktype='auto'), type='auto')
|
||||||
self.enableSaveEventAction()
|
self.enableSaveEventAction()
|
||||||
if replot1 or replot2:
|
self.comparable = self.checkEvents4comparison()
|
||||||
self.plotWaveformDataThread()
|
if True in self.comparable.values():
|
||||||
|
self.compare_action.setEnabled(True)
|
||||||
self.draw()
|
|
||||||
else:
|
|
||||||
self.drawPicks(station)
|
self.drawPicks(station)
|
||||||
self.draw()
|
self.draw()
|
||||||
if self.nextStation:
|
if self.nextStation:
|
||||||
@ -2336,7 +2375,7 @@ class MainWindow(QMainWindow):
|
|||||||
else:
|
else:
|
||||||
self.update_status('picks discarded ({0})'.format(station))
|
self.update_status('picks discarded ({0})'.format(station))
|
||||||
if not self.get_loc_flag() and self.check4Loc():
|
if not self.get_loc_flag() and self.check4Loc():
|
||||||
self.locateEvent.setEnabled(True)
|
self.locateEventAction.setEnabled(True)
|
||||||
self.set_loc_flag(True)
|
self.set_loc_flag(True)
|
||||||
elif self.get_loc_flag() and not self.check4Loc():
|
elif self.get_loc_flag() and not self.check4Loc():
|
||||||
self.set_loc_flag(False)
|
self.set_loc_flag(False)
|
||||||
@ -2425,7 +2464,7 @@ class MainWindow(QMainWindow):
|
|||||||
# else:
|
# else:
|
||||||
# self.update_autopicker()
|
# self.update_autopicker()
|
||||||
# self.tap.fill_eventbox()
|
# self.tap.fill_eventbox()
|
||||||
self.tap.show()
|
self.tap.showMaximized()
|
||||||
|
|
||||||
def update_autopicker(self):
|
def update_autopicker(self):
|
||||||
'''
|
'''
|
||||||
@ -2437,11 +2476,13 @@ class MainWindow(QMainWindow):
|
|||||||
canvas.setZoomBorders2content()
|
canvas.setZoomBorders2content()
|
||||||
if self.tap.pylot_picks:
|
if self.tap.pylot_picks:
|
||||||
station = self.tap.get_current_station()
|
station = self.tap.get_current_station()
|
||||||
p_pick = self.tap.pylot_picks[station]['P']
|
p_pick = self.tap.pylot_picks[station].get('P')
|
||||||
s_pick = self.tap.pylot_picks[station]['S']
|
if p_pick:
|
||||||
self.tap.pickDlg.autopicks['P_tuning'] = p_pick
|
self.tap.pickDlg.autopicks['P_tuning'] = p_pick
|
||||||
self.tap.pickDlg.autopicks['S_tuning'] = s_pick
|
|
||||||
self.tap.pickDlg.drawPicks(phase='P_tuning', picktype='auto', picks=p_pick)
|
self.tap.pickDlg.drawPicks(phase='P_tuning', picktype='auto', picks=p_pick)
|
||||||
|
s_pick = self.tap.pylot_picks[station].get('S')
|
||||||
|
if s_pick:
|
||||||
|
self.tap.pickDlg.autopicks['S_tuning'] = s_pick
|
||||||
self.tap.pickDlg.drawPicks(phase='S_tuning', picktype='auto', picks=s_pick)
|
self.tap.pickDlg.drawPicks(phase='S_tuning', picktype='auto', picks=s_pick)
|
||||||
|
|
||||||
def autoPick(self):
|
def autoPick(self):
|
||||||
@ -2495,7 +2536,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.apw.enable(False)
|
self.apw.enable(False)
|
||||||
|
|
||||||
# export current picks etc.
|
# export current picks etc.
|
||||||
self.exportAllEvents(['.xml'])
|
self.exportEvents(['.xml'], events=events)
|
||||||
|
|
||||||
wfpath = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else ''
|
wfpath = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else ''
|
||||||
# define arguments for picker
|
# define arguments for picker
|
||||||
@ -2554,13 +2595,15 @@ class MainWindow(QMainWindow):
|
|||||||
if event.pylot_id == eventID:
|
if event.pylot_id == eventID:
|
||||||
return event
|
return event
|
||||||
|
|
||||||
def get_event_paths(self, eventlist):
|
@staticmethod
|
||||||
|
def get_event_paths(eventlist):
|
||||||
eventPaths = []
|
eventPaths = []
|
||||||
for event in eventlist:
|
for event in eventlist:
|
||||||
eventPaths.append(event.path)
|
eventPaths.append(event.path)
|
||||||
return eventPaths
|
return eventPaths
|
||||||
|
|
||||||
def get_event_ids(self, eventlist):
|
@staticmethod
|
||||||
|
def get_event_ids(eventlist):
|
||||||
eventIDs = []
|
eventIDs = []
|
||||||
for event in eventlist:
|
for event in eventlist:
|
||||||
eventIDs.append(event.pylot_id)
|
eventIDs.append(event.pylot_id)
|
||||||
@ -2647,12 +2690,25 @@ class MainWindow(QMainWindow):
|
|||||||
self.drawPicks(station, 'auto', stime)
|
self.drawPicks(station, 'auto', stime)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not picktype in ['manual', 'auto']:
|
||||||
|
raise TypeError('Unknown picktype {0}'.format(picktype))
|
||||||
|
|
||||||
# if picks to draw not specified, draw all picks available
|
# if picks to draw not specified, draw all picks available
|
||||||
if not station:
|
if not station:
|
||||||
for station in self.getPicks(type=picktype):
|
for station in self.getPicks(type=picktype):
|
||||||
self.drawPicks(station, picktype=picktype, stime=stime)
|
self.drawPicks(station, picktype=picktype, stime=stime)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self.pg:
|
||||||
|
pw = self.getPlotWidget().plotWidget
|
||||||
|
else:
|
||||||
|
ax = self.getPlotWidget().axes[0]
|
||||||
|
|
||||||
|
if station in self.drawnPicks[picktype].keys():
|
||||||
|
for item in self.drawnPicks[picktype][station]:
|
||||||
|
pw.removeItem(item)
|
||||||
|
self.drawnPicks[picktype][station] = []
|
||||||
|
|
||||||
# check for station key in dictionary, else return
|
# check for station key in dictionary, else return
|
||||||
if not station in self.getPicks(type=picktype):
|
if not station in self.getPicks(type=picktype):
|
||||||
return
|
return
|
||||||
@ -2661,13 +2717,10 @@ class MainWindow(QMainWindow):
|
|||||||
plotID = self.getStationID(station)
|
plotID = self.getStationID(station)
|
||||||
if plotID is None:
|
if plotID is None:
|
||||||
return
|
return
|
||||||
if self.pg:
|
|
||||||
pw = self.getPlotWidget().plotWidget
|
|
||||||
else:
|
|
||||||
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]
|
||||||
|
settings = QSettings()
|
||||||
|
|
||||||
for phase in stat_picks:
|
for phase in stat_picks:
|
||||||
if phase == 'SPt': continue # wadati SP time
|
if phase == 'SPt': continue # wadati SP time
|
||||||
@ -2675,13 +2728,16 @@ class MainWindow(QMainWindow):
|
|||||||
if type(stat_picks[phase]) is not dict and type(stat_picks[phase]) is not AttribDict:
|
if type(stat_picks[phase]) is not dict and type(stat_picks[phase]) is not AttribDict:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
phaseID = self.getPhaseID(phase)
|
||||||
# get quality classes
|
# get quality classes
|
||||||
if self.getPhaseID(phase) == 'P':
|
if phaseID == 'P':
|
||||||
quality = get_quality_class(picks['spe'], self._inputs['timeerrorsP'])
|
quality = getQualityFromUncertainty(picks['spe'], self._inputs['timeerrorsP'])
|
||||||
phaseID = 'P'
|
elif phaseID == 'S':
|
||||||
elif self.getPhaseID(phase) == 'S':
|
quality = getQualityFromUncertainty(picks['spe'], self._inputs['timeerrorsS'])
|
||||||
quality = get_quality_class(picks['spe'], self._inputs['timeerrorsS'])
|
|
||||||
phaseID = 'S'
|
# quality = getPickQuality(self.get_data().getWFData(),
|
||||||
|
# stat_picks, self._inputs, phaseID,
|
||||||
|
# compclass)
|
||||||
|
|
||||||
mpp = picks['mpp'] - stime
|
mpp = picks['mpp'] - stime
|
||||||
if picks['epp'] and picks['lpp']:
|
if picks['epp'] and picks['lpp']:
|
||||||
@ -2692,44 +2748,32 @@ class MainWindow(QMainWindow):
|
|||||||
lpp = None
|
lpp = None
|
||||||
spe = picks['spe']
|
spe = picks['spe']
|
||||||
|
|
||||||
if not spe and epp and lpp:
|
|
||||||
spe = symmetrize_error(mpp - epp, lpp - mpp)
|
|
||||||
|
|
||||||
if self.pg:
|
if self.pg:
|
||||||
if picktype == 'manual':
|
if spe:
|
||||||
if picks['epp'] and picks['lpp']:
|
if picks['epp'] and picks['lpp']:
|
||||||
pen = make_pen(picktype, phaseID, 'epp', quality)
|
pen = make_pen(picktype, phaseID, 'epp', quality)
|
||||||
pw.plot([epp, epp], ylims,
|
self.drawnPicks[picktype][station].append(pw.plot([epp, epp], ylims,
|
||||||
alpha=.25, pen=pen, name='EPP')
|
alpha=.25, pen=pen, name='EPP'))
|
||||||
pen = make_pen(picktype, phaseID, 'lpp', quality)
|
pen = make_pen(picktype, phaseID, 'lpp', quality)
|
||||||
pw.plot([lpp, lpp], ylims,
|
self.drawnPicks[picktype][station].append(pw.plot([lpp, lpp], ylims,
|
||||||
alpha=.25, pen=pen, name='LPP')
|
alpha=.25, pen=pen, name='LPP'))
|
||||||
|
pen = make_pen(picktype, phaseID, 'spe', quality)
|
||||||
|
spe_l = pg.PlotDataItem([mpp - spe, mpp - spe], ylims, pen=pen,
|
||||||
|
name='{}-SPE'.format(phase))
|
||||||
|
spe_r = pg.PlotDataItem([mpp + spe, mpp + spe], ylims, pen=pen)
|
||||||
|
try:
|
||||||
|
color = pen.color()
|
||||||
|
color.setAlpha(100.)
|
||||||
|
brush = pen.brush()
|
||||||
|
brush.setColor(color)
|
||||||
|
fill = pg.FillBetweenItem(spe_l, spe_r, brush=brush)
|
||||||
|
fb = pw.addItem(fill)
|
||||||
|
self.drawnPicks[picktype][station].append(fill)
|
||||||
|
except:
|
||||||
|
print('Warning: drawPicks: Could not create fill for symmetric pick error.')
|
||||||
pen = make_pen(picktype, phaseID, 'mpp', quality)
|
pen = make_pen(picktype, phaseID, 'mpp', quality)
|
||||||
if spe:
|
self.drawnPicks[picktype][station].append(
|
||||||
# pen = make_pen(picktype, phaseID, 'spe', quality)
|
pw.plot([mpp, mpp], ylims, pen=pen, name='{}-Pick'.format(phase)))
|
||||||
# spe_l = pg.PlotDataItem([mpp - spe, mpp - spe], ylims, pen=pen,
|
|
||||||
# name='{}-SPE'.format(phase))
|
|
||||||
# spe_r = pg.PlotDataItem([mpp + spe, mpp + spe], ylims, pen=pen)
|
|
||||||
# pw.addItem(spe_l)
|
|
||||||
# pw.addItem(spe_r)
|
|
||||||
# try:
|
|
||||||
# color = pen.color()
|
|
||||||
# color.setAlpha(100.)
|
|
||||||
# brush = pen.brush()
|
|
||||||
# brush.setColor(color)
|
|
||||||
# fill = pg.FillBetweenItem(spe_l, spe_r, brush=brush)
|
|
||||||
# fb = pw.addItem(fill)
|
|
||||||
# except:
|
|
||||||
# print('Warning: drawPicks: Could not create fill for symmetric pick error.')
|
|
||||||
pw.plot([mpp, mpp], ylims, pen=pen, name='{}-Pick'.format(phase))
|
|
||||||
else:
|
|
||||||
pw.plot([mpp, mpp], ylims, pen=pen, name='{}-Pick (NO PICKERROR)'.format(phase))
|
|
||||||
elif picktype == 'auto':
|
|
||||||
if quality < 4:
|
|
||||||
pen = make_pen(picktype, phaseID, 'mpp', quality)
|
|
||||||
pw.plot([mpp, mpp], ylims, pen=pen)
|
|
||||||
else:
|
|
||||||
raise TypeError('Unknown picktype {0}'.format(picktype))
|
|
||||||
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')
|
||||||
@ -2817,7 +2861,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
self.inventory_label = QLabel('No inventory set...')
|
self.inventory_label = QLabel('No inventory set...')
|
||||||
# init inventory button
|
# init inventory button
|
||||||
self.new_inv_button = QPushButton('Set inventory file')
|
self.new_inv_button = QPushButton('Manage inventory files')
|
||||||
self.new_inv_button.setIcon(self.inventoryIcon)
|
self.new_inv_button.setIcon(self.inventoryIcon)
|
||||||
self.new_inv_button.clicked.connect(self.inventoryAction.trigger)
|
self.new_inv_button.clicked.connect(self.inventoryAction.trigger)
|
||||||
|
|
||||||
@ -2830,7 +2874,6 @@ class MainWindow(QMainWindow):
|
|||||||
grid_layout.addWidget(self.new_inv_button, 2, 1)
|
grid_layout.addWidget(self.new_inv_button, 2, 1)
|
||||||
grid_layout.addWidget(self.init_map_button, 3, 1)
|
grid_layout.addWidget(self.init_map_button, 3, 1)
|
||||||
|
|
||||||
self.metadata = None
|
|
||||||
self.metadata_widget.setLayout(grid_layout)
|
self.metadata_widget.setLayout(grid_layout)
|
||||||
self.array_layout.addWidget(self.metadata_widget)
|
self.array_layout.addWidget(self.metadata_widget)
|
||||||
|
|
||||||
@ -2984,6 +3027,8 @@ class MainWindow(QMainWindow):
|
|||||||
'auto': event.pylot_autopicks}
|
'auto': event.pylot_autopicks}
|
||||||
ma_count = {'manual': 0,
|
ma_count = {'manual': 0,
|
||||||
'auto': 0}
|
'auto': 0}
|
||||||
|
ma_count_total = {'manual': 0,
|
||||||
|
'auto': 0}
|
||||||
|
|
||||||
for ma in ma_props.keys():
|
for ma in ma_props.keys():
|
||||||
if ma_props[ma]:
|
if ma_props[ma]:
|
||||||
@ -2991,8 +3036,9 @@ class MainWindow(QMainWindow):
|
|||||||
for phasename, pick in picks.items():
|
for phasename, pick in picks.items():
|
||||||
if not type(pick) in [dict, AttribDict]:
|
if not type(pick) in [dict, AttribDict]:
|
||||||
continue
|
continue
|
||||||
if get_quality_class(has_spe(pick), phaseErrors[self.getPhaseID(phasename)]) < 4:
|
if pick.get('spe'):
|
||||||
ma_count[ma] += 1
|
ma_count[ma] += 1
|
||||||
|
ma_count_total[ma] += 1
|
||||||
|
|
||||||
# init table items for current row
|
# init table items for current row
|
||||||
item_delete = QtGui.QTableWidgetItem()
|
item_delete = QtGui.QTableWidgetItem()
|
||||||
@ -3003,15 +3049,19 @@ class MainWindow(QMainWindow):
|
|||||||
item_lon = QtGui.QTableWidgetItem()
|
item_lon = QtGui.QTableWidgetItem()
|
||||||
item_depth = QtGui.QTableWidgetItem()
|
item_depth = QtGui.QTableWidgetItem()
|
||||||
item_mag = QtGui.QTableWidgetItem()
|
item_mag = QtGui.QTableWidgetItem()
|
||||||
item_nmp = QtGui.QTableWidgetItem(str(ma_count['manual']))
|
item_nmp = QtGui.QTableWidgetItem('{}({})'.format(ma_count['manual'], ma_count_total['manual']))
|
||||||
item_nmp.setIcon(self.manupicksicon_small)
|
item_nmp.setIcon(self.manupicksicon_small)
|
||||||
item_nap = QtGui.QTableWidgetItem(str(ma_count['auto']))
|
item_nap = QtGui.QTableWidgetItem('{}({})'.format(ma_count['auto'], ma_count_total['auto']))
|
||||||
item_nap.setIcon(self.autopicksicon_small)
|
item_nap.setIcon(self.autopicksicon_small)
|
||||||
item_ref = QtGui.QTableWidgetItem()
|
item_ref = QtGui.QTableWidgetItem()
|
||||||
item_test = QtGui.QTableWidgetItem()
|
item_test = QtGui.QTableWidgetItem()
|
||||||
item_notes = QtGui.QTableWidgetItem()
|
item_notes = QtGui.QTableWidgetItem()
|
||||||
|
|
||||||
item_path.setText(event.path)
|
event_str = event.path
|
||||||
|
if event.dirty:
|
||||||
|
event_str += '*'
|
||||||
|
|
||||||
|
item_path.setText(event_str)
|
||||||
if hasattr(event, 'origins'):
|
if hasattr(event, 'origins'):
|
||||||
if event.origins:
|
if event.origins:
|
||||||
origin = event.origins[0]
|
origin = event.origins[0]
|
||||||
@ -3089,66 +3139,23 @@ class MainWindow(QMainWindow):
|
|||||||
if event == current_event:
|
if event == current_event:
|
||||||
set_background_color(item_list, QtGui.QColor(*(0, 143, 143, 255)))
|
set_background_color(item_list, QtGui.QColor(*(0, 143, 143, 255)))
|
||||||
|
|
||||||
def read_metadata_thread(self, fninv):
|
|
||||||
self.rm_thread = Thread(self, read_metadata, arg=fninv, progressText='Reading metadata...',
|
|
||||||
pb_widget=self.mainProgressBarWidget)
|
|
||||||
self.rm_thread.finished.connect(self.set_metadata)
|
|
||||||
self.rm_thread.start()
|
|
||||||
|
|
||||||
def set_metadata(self):
|
def set_metadata(self):
|
||||||
settings = QSettings()
|
self.project.inventories = self.metadata.inventories
|
||||||
self.metadata = self.rm_thread.data
|
if self.metadata.inventories:
|
||||||
if settings.value('saveMetadata'):
|
|
||||||
self.project.metadata = self.rm_thread.data
|
|
||||||
self.project.inv_path = settings.value("inventoryFile")
|
|
||||||
self.init_map_button.setEnabled(True)
|
self.init_map_button.setEnabled(True)
|
||||||
self.initMapAction.setEnabled(True)
|
self.initMapAction.setEnabled(True)
|
||||||
self.inventory_label.setText('Inventory set!')
|
self.inventory_label.setText('Inventory set!')
|
||||||
self.new_inv_button.setText('Set another inventory file')
|
self.setDirty(True)
|
||||||
|
|
||||||
def get_new_metadata(self):
|
def add_metadata(self):
|
||||||
self.init_metadata(new=True)
|
self.add_metadata_widget = AddMetadataWidget(self, metadata=self.metadata)
|
||||||
|
self.add_metadata_widget.close_button.clicked.connect(self.set_metadata)
|
||||||
|
|
||||||
def init_metadata(self, new=False, ask_default=True):
|
def init_metadata(self, new=False, ask_default=True):
|
||||||
def set_inv(settings):
|
if hasattr(self.project, 'inventories'):
|
||||||
fninv, _ = QFileDialog.getOpenFileName(self, self.tr(
|
self.metadata = Metadata()
|
||||||
"Select inventory..."), self.tr("Select file"))
|
for inventory in self.project.inventories:
|
||||||
if not fninv:
|
self.metadata.add_inventory(inventory)
|
||||||
return False
|
|
||||||
ans = QMessageBox.question(self, self.tr("Make default..."),
|
|
||||||
self.tr(
|
|
||||||
"New inventory filename set.\n" + \
|
|
||||||
"Do you want to make it the default value?"),
|
|
||||||
QMessageBox.Yes | QMessageBox.No,
|
|
||||||
QMessageBox.No)
|
|
||||||
if ans == QMessageBox.Yes:
|
|
||||||
settings.setValue("inventoryFile", fninv)
|
|
||||||
settings.sync()
|
|
||||||
self.read_metadata_thread(fninv)
|
|
||||||
return True
|
|
||||||
|
|
||||||
settings = QSettings()
|
|
||||||
|
|
||||||
if hasattr(self.project, 'metadata') and not new:
|
|
||||||
self.metadata = self.project.metadata
|
|
||||||
return True
|
|
||||||
if self.metadata and not new:
|
|
||||||
return True
|
|
||||||
if hasattr(self.project, 'inv_path') and not new:
|
|
||||||
settings.setValue("inventoryFile", self.project.inv_path)
|
|
||||||
|
|
||||||
fninv = settings.value("inventoryFile", None)
|
|
||||||
if (fninv and ask_default) and not new:
|
|
||||||
ans = QMessageBox.question(self, self.tr("Use default metadata..."),
|
|
||||||
self.tr(
|
|
||||||
"Do you want to use the default value for metadata?\n({})".format(fninv)),
|
|
||||||
QMessageBox.Yes | QMessageBox.No,
|
|
||||||
QMessageBox.Yes)
|
|
||||||
if ans == QMessageBox.Yes:
|
|
||||||
self.read_metadata_thread(fninv)
|
|
||||||
return
|
|
||||||
set_inv(settings)
|
|
||||||
|
|
||||||
|
|
||||||
def calc_magnitude(self, type='ML'):
|
def calc_magnitude(self, type='ML'):
|
||||||
self.init_metadata()
|
self.init_metadata()
|
||||||
@ -3161,7 +3168,7 @@ class MainWindow(QMainWindow):
|
|||||||
# raise ProcessingError('Restitution of waveform data failed!')
|
# raise ProcessingError('Restitution of waveform data failed!')
|
||||||
if type == 'ML':
|
if type == 'ML':
|
||||||
local_mag = LocalMagnitude(corr_wf, self.get_data().get_evt_data(), self.inputs.get('sstop'),
|
local_mag = LocalMagnitude(corr_wf, self.get_data().get_evt_data(), self.inputs.get('sstop'),
|
||||||
verbosity=True) ## MP MP missing parameter wascaling in function call!
|
self.inputs.get('WAScaling'), verbosity=True)
|
||||||
return local_mag.updated_event()
|
return local_mag.updated_event()
|
||||||
elif type == 'Mw':
|
elif type == 'Mw':
|
||||||
moment_mag = MomentMagnitude(corr_wf, self.get_data().get_evt_data(), self.inputs.get('vp'),
|
moment_mag = MomentMagnitude(corr_wf, self.get_data().get_evt_data(), self.inputs.get('vp'),
|
||||||
@ -3268,20 +3275,17 @@ class MainWindow(QMainWindow):
|
|||||||
if self.project.parameter:
|
if self.project.parameter:
|
||||||
self._inputs = self.project.parameter
|
self._inputs = self.project.parameter
|
||||||
self.updateFilteroptions()
|
self.updateFilteroptions()
|
||||||
|
# added for backwards compatibility with older events not having a 'dirty' attribute
|
||||||
|
for event in self.project.eventlist:
|
||||||
|
if not hasattr(event, 'dirty'):
|
||||||
|
event.dirty = False
|
||||||
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)
|
||||||
if hasattr(self.project, 'metadata'):
|
self.init_metadata()
|
||||||
if self.project.metadata:
|
|
||||||
self.init_metadata(ask_default=False)
|
|
||||||
#self.init_array_map(index=0)
|
|
||||||
return
|
|
||||||
if hasattr(self.project, 'inv_path'):
|
|
||||||
self.init_metadata(ask_default=False)
|
|
||||||
#self.init_array_map(index=0)
|
|
||||||
return
|
|
||||||
|
|
||||||
self.init_array_tab()
|
self.init_array_tab()
|
||||||
|
self.set_metadata()
|
||||||
|
|
||||||
def saveProjectAs(self, exists=False):
|
def saveProjectAs(self, exists=False):
|
||||||
'''
|
'''
|
||||||
@ -3295,10 +3299,10 @@ class MainWindow(QMainWindow):
|
|||||||
if not filename.split('.')[-1] == 'plp':
|
if not filename.split('.')[-1] == 'plp':
|
||||||
filename = fnm[0] + '.plp'
|
filename = fnm[0] + '.plp'
|
||||||
self.project.parameter = self._inputs
|
self.project.parameter = self._inputs
|
||||||
|
self.exportEvents()
|
||||||
self.project.save(filename)
|
self.project.save(filename)
|
||||||
self.setDirty(False)
|
self.setDirty(False)
|
||||||
self.saveProjectAsAction.setEnabled(True)
|
self.saveProjectAsAction.setEnabled(True)
|
||||||
self.exportAllEvents()
|
|
||||||
self.update_status('Saved new project to {}'.format(filename), duration=5000)
|
self.update_status('Saved new project to {}'.format(filename), duration=5000)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -3313,11 +3317,11 @@ class MainWindow(QMainWindow):
|
|||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.project.parameter = self._inputs
|
self.project.parameter = self._inputs
|
||||||
|
self.exportEvents()
|
||||||
self.project.save()
|
self.project.save()
|
||||||
self.exportAllEvents()
|
|
||||||
if not self.project.dirty:
|
if not self.project.dirty:
|
||||||
self.update_status('Saved back project to file:\n{}'.format(self.project.location), duration=5000)
|
|
||||||
self.setDirty(False)
|
self.setDirty(False)
|
||||||
|
self.update_status('Saved back project to file:\n{}'.format(self.project.location), duration=5000)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
# if still dirty because saving failed
|
# if still dirty because saving failed
|
||||||
@ -3335,7 +3339,6 @@ class MainWindow(QMainWindow):
|
|||||||
self.dataPlot.setPermText(1)
|
self.dataPlot.setPermText(1)
|
||||||
self.dataPlot.setPermText(0, '| Number of traces: {} |'.format(len(self.getPlotWidget().getPlotDict())))
|
self.dataPlot.setPermText(0, '| Number of traces: {} |'.format(len(self.getPlotWidget().getPlotDict())))
|
||||||
|
|
||||||
|
|
||||||
def _setDirty(self):
|
def _setDirty(self):
|
||||||
self.setDirty(True)
|
self.setDirty(True)
|
||||||
|
|
||||||
@ -3344,6 +3347,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.saveProjectAsAction.setEnabled(True)
|
self.saveProjectAsAction.setEnabled(True)
|
||||||
self.project.setDirty(value)
|
self.project.setDirty(value)
|
||||||
self.dirty = value
|
self.dirty = value
|
||||||
|
self.fill_eventbox()
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
if self.okToContinue():
|
if self.okToContinue():
|
||||||
|
37
autoPyLoT.py
37
autoPyLoT.py
@ -7,6 +7,7 @@ import argparse
|
|||||||
import datetime
|
import datetime
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
import pylot.core.loc.focmec as focmec
|
import pylot.core.loc.focmec as focmec
|
||||||
import pylot.core.loc.hash as hash
|
import pylot.core.loc.hash as hash
|
||||||
@ -22,7 +23,7 @@ from pylot.core.analysis.magnitude import MomentMagnitude, LocalMagnitude
|
|||||||
from pylot.core.io.data import Data
|
from pylot.core.io.data import Data
|
||||||
from pylot.core.io.inputs import PylotParameter
|
from pylot.core.io.inputs import PylotParameter
|
||||||
from pylot.core.pick.autopick import autopickevent, iteratepicker
|
from pylot.core.pick.autopick import autopickevent, iteratepicker
|
||||||
from pylot.core.util.dataprocessing import restitute_data, read_metadata
|
from pylot.core.util.dataprocessing import restitute_data, read_metadata, Metadata
|
||||||
from pylot.core.util.defaults import SEPARATOR
|
from pylot.core.util.defaults import SEPARATOR
|
||||||
from pylot.core.util.event import Event
|
from pylot.core.util.event import Event
|
||||||
from pylot.core.util.structure import DATASTRUCTURE
|
from pylot.core.util.structure import DATASTRUCTURE
|
||||||
@ -38,6 +39,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
"""
|
"""
|
||||||
Determine phase onsets automatically utilizing the automatic picking
|
Determine phase onsets automatically utilizing the automatic picking
|
||||||
algorithms by Kueperkoch et al. 2010/2012.
|
algorithms by Kueperkoch et al. 2010/2012.
|
||||||
|
:param obspyDMT_wfpath: if obspyDMT is used, name of data directory ("raw" or "processed")
|
||||||
:param input_dict:
|
:param input_dict:
|
||||||
:type input_dict:
|
:type input_dict:
|
||||||
:param parameter: PylotParameter object containing parameters used for automatic picking
|
:param parameter: PylotParameter object containing parameters used for automatic picking
|
||||||
@ -53,7 +55,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
:type savepath: str
|
:type savepath: str
|
||||||
:param savexml: export results in XML file if True
|
:param savexml: export results in XML file if True
|
||||||
:type savexml: bool
|
:type savexml: bool
|
||||||
:param station: list of station names or 'all' to pick all stations
|
:param station: choose specific station name or 'all' to pick all stations
|
||||||
:type station: str
|
:type station: str
|
||||||
:param iplot: logical variable for plotting: 0=none, 1=partial, 2=all
|
:param iplot: logical variable for plotting: 0=none, 1=partial, 2=all
|
||||||
:type iplot: int
|
:type iplot: int
|
||||||
@ -149,8 +151,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
datastructure.modifyFields(**dsfields)
|
datastructure.modifyFields(**dsfields)
|
||||||
datastructure.setExpandFields(exf)
|
datastructure.setExpandFields(exf)
|
||||||
|
|
||||||
# check if default location routine NLLoc is available
|
# check if default location routine NLLoc is available and all stations are used
|
||||||
if real_None(parameter['nllocbin']):
|
if real_None(parameter['nllocbin']) and station == 'all':
|
||||||
locflag = 1
|
locflag = 1
|
||||||
# get NLLoc-root path
|
# get NLLoc-root path
|
||||||
nllocroot = parameter.get('nllocroot')
|
nllocroot = parameter.get('nllocroot')
|
||||||
@ -200,8 +202,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
events.append(os.path.join(datapath, eventID))
|
events.append(os.path.join(datapath, eventID))
|
||||||
else:
|
else:
|
||||||
# autoPyLoT was initialized from GUI
|
# autoPyLoT was initialized from GUI
|
||||||
events = []
|
events = [eventid]
|
||||||
events.append(eventid)
|
|
||||||
evID = os.path.split(eventid)[-1]
|
evID = os.path.split(eventid)[-1]
|
||||||
locflag = 2
|
locflag = 2
|
||||||
else:
|
else:
|
||||||
@ -271,24 +272,26 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
if not wfdat:
|
if not wfdat:
|
||||||
print('Could not find station {}. STOP!'.format(station))
|
print('Could not find station {}. STOP!'.format(station))
|
||||||
return
|
return
|
||||||
wfdat = remove_underscores(wfdat)
|
#wfdat = remove_underscores(wfdat)
|
||||||
# trim components for each station to avoid problems with different trace starttimes for one station
|
# trim components for each station to avoid problems with different trace starttimes for one station
|
||||||
wfdat = check4gaps(wfdat)
|
wfdat = check4gaps(wfdat)
|
||||||
wfdat = check4doubled(wfdat)
|
wfdat = check4doubled(wfdat)
|
||||||
wfdat = trim_station_components(wfdat, trim_start=True, trim_end=False)
|
wfdat = trim_station_components(wfdat, trim_start=True, trim_end=False)
|
||||||
metadata = read_metadata(parameter.get('invdir'))
|
if not wfpath_extension:
|
||||||
# TODO: (idea) read metadata from obspy_dmt database
|
metadata = Metadata(parameter.get('invdir'))
|
||||||
# if not wfpath_extension:
|
else:
|
||||||
# metadata = read_metadata(parameter.get('invdir'))
|
metadata = Metadata(os.path.join(eventpath, 'resp'))
|
||||||
# else:
|
|
||||||
# metadata = None
|
|
||||||
corr_dat = None
|
corr_dat = None
|
||||||
if metadata:
|
if metadata:
|
||||||
# rotate stations to ZNE
|
# rotate stations to ZNE
|
||||||
|
try:
|
||||||
wfdat = check4rotated(wfdat, metadata)
|
wfdat = check4rotated(wfdat, metadata)
|
||||||
|
except Exception as e:
|
||||||
|
print('Could not rotate station {} to ZNE:\n{}'.format(wfdat[0].stats.station,
|
||||||
|
traceback.format_exc()))
|
||||||
if locflag:
|
if locflag:
|
||||||
print("Restitute data ...")
|
print("Restitute data ...")
|
||||||
corr_dat = restitute_data(wfdat.copy(), *metadata, ncores=ncores)
|
corr_dat = restitute_data(wfdat.copy(), metadata, ncores=ncores)
|
||||||
if not corr_dat and locflag:
|
if not corr_dat and locflag:
|
||||||
locflag = 2
|
locflag = 2
|
||||||
print('Working on event %s. Stations: %s' % (eventpath, station))
|
print('Working on event %s. Stations: %s' % (eventpath, station))
|
||||||
@ -363,8 +366,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
WAscaling[2]))
|
WAscaling[2]))
|
||||||
evt = local_mag.updated_event(magscaling)
|
evt = local_mag.updated_event(magscaling)
|
||||||
net_ml = local_mag.net_magnitude(magscaling)
|
net_ml = local_mag.net_magnitude(magscaling)
|
||||||
|
if net_ml:
|
||||||
print("Network local magnitude: %4.1f" % net_ml.mag)
|
print("Network local magnitude: %4.1f" % net_ml.mag)
|
||||||
if magscaling == None:
|
if magscaling is None:
|
||||||
scaling = False
|
scaling = False
|
||||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||||
scaling = False
|
scaling = False
|
||||||
@ -447,8 +451,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
WAscaling[2]))
|
WAscaling[2]))
|
||||||
evt = local_mag.updated_event(magscaling)
|
evt = local_mag.updated_event(magscaling)
|
||||||
net_ml = local_mag.net_magnitude(magscaling)
|
net_ml = local_mag.net_magnitude(magscaling)
|
||||||
|
if net_ml:
|
||||||
print("Network local magnitude: %4.1f" % net_ml.mag)
|
print("Network local magnitude: %4.1f" % net_ml.mag)
|
||||||
if magscaling == None:
|
if magscaling is None:
|
||||||
scaling = False
|
scaling = False
|
||||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||||
scaling = False
|
scaling = False
|
||||||
|
@ -17,6 +17,7 @@ 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,
|
||||||
@ -122,7 +123,7 @@ class Magnitude(object):
|
|||||||
|
|
||||||
def net_magnitude(self, magscaling=None):
|
def net_magnitude(self, magscaling=None):
|
||||||
if self:
|
if self:
|
||||||
if magscaling == None:
|
if magscaling is None:
|
||||||
scaling = False
|
scaling = False
|
||||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||||
scaling = False
|
scaling = False
|
||||||
@ -261,11 +262,12 @@ class LocalMagnitude(Magnitude):
|
|||||||
ax.set_xlabel('Time [s]')
|
ax.set_xlabel('Time [s]')
|
||||||
ax.set_ylabel('Displacement [mm]')
|
ax.set_ylabel('Displacement [mm]')
|
||||||
fig.show()
|
fig.show()
|
||||||
try: input()
|
try:
|
||||||
except SyntaxError: pass
|
input()
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
|
|
||||||
|
|
||||||
return wapp, fig
|
return wapp, fig
|
||||||
|
|
||||||
def calc(self):
|
def calc(self):
|
||||||
@ -510,6 +512,9 @@ def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
|
|||||||
|
|
||||||
zdat = select_for_phase(wfstream, "P")
|
zdat = select_for_phase(wfstream, "P")
|
||||||
|
|
||||||
|
if len(zdat) == 0:
|
||||||
|
raise IOError('No vertical component found in stream:\n{}'.format(wfstream))
|
||||||
|
|
||||||
dt = zdat[0].stats.delta
|
dt = zdat[0].stats.delta
|
||||||
|
|
||||||
freq = zdat[0].stats.sampling_rate
|
freq = zdat[0].stats.sampling_rate
|
||||||
|
@ -17,6 +17,7 @@ from pylot.core.util.utils import fnConstructor, full_range, remove_underscores,
|
|||||||
import pylot.core.loc.velest as velest
|
import pylot.core.loc.velest as velest
|
||||||
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
||||||
|
|
||||||
|
|
||||||
class Data(object):
|
class Data(object):
|
||||||
"""
|
"""
|
||||||
Data container with attributes wfdata holding ~obspy.core.stream.
|
Data container with attributes wfdata holding ~obspy.core.stream.
|
||||||
@ -299,7 +300,7 @@ class Data(object):
|
|||||||
for i in range(len(picks_copy)):
|
for i in range(len(picks_copy)):
|
||||||
if picks_copy[i].phase_hint[0] == 'P':
|
if picks_copy[i].phase_hint[0] == 'P':
|
||||||
if (picks_copy[i].time_errors['upper_uncertainty'] >= upperErrors[0]) or \
|
if (picks_copy[i].time_errors['upper_uncertainty'] >= upperErrors[0]) or \
|
||||||
(picks_copy[i].time_errors['uncertainty'] == None):
|
(picks_copy[i].time_errors['uncertainty'] is None):
|
||||||
print("Uncertainty exceeds or equal adjusted upper time error!")
|
print("Uncertainty exceeds or equal adjusted upper time error!")
|
||||||
print("Adjusted uncertainty: {}".format(upperErrors[0]))
|
print("Adjusted uncertainty: {}".format(upperErrors[0]))
|
||||||
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
||||||
@ -311,7 +312,7 @@ class Data(object):
|
|||||||
break
|
break
|
||||||
if picks_copy[i].phase_hint[0] == 'S':
|
if picks_copy[i].phase_hint[0] == 'S':
|
||||||
if (picks_copy[i].time_errors['upper_uncertainty'] >= upperErrors[1]) or \
|
if (picks_copy[i].time_errors['upper_uncertainty'] >= upperErrors[1]) or \
|
||||||
(picks_copy[i].time_errors['uncertainty'] == None):
|
(picks_copy[i].time_errors['uncertainty'] is None):
|
||||||
print("Uncertainty exceeds or equal adjusted upper time error!")
|
print("Uncertainty exceeds or equal adjusted upper time error!")
|
||||||
print("Adjusted uncertainty: {}".format(upperErrors[1]))
|
print("Adjusted uncertainty: {}".format(upperErrors[1]))
|
||||||
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
||||||
@ -404,7 +405,7 @@ class Data(object):
|
|||||||
|
|
||||||
# various pre-processing steps:
|
# various pre-processing steps:
|
||||||
# remove possible underscores in station names
|
# remove possible underscores in station names
|
||||||
self.wfdata = remove_underscores(self.wfdata)
|
#self.wfdata = remove_underscores(self.wfdata)
|
||||||
# check for stations with rotated components
|
# check for stations with rotated components
|
||||||
if checkRotated and metadata is not None:
|
if checkRotated and metadata is not None:
|
||||||
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
|
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
|
||||||
@ -416,7 +417,6 @@ class Data(object):
|
|||||||
self.dirty = False
|
self.dirty = False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def appendWFData(self, fnames, synthetic=False):
|
def appendWFData(self, fnames, synthetic=False):
|
||||||
"""
|
"""
|
||||||
Read waveform data from fnames and append it to current wf data
|
Read waveform data from fnames and append it to current wf data
|
||||||
@ -506,8 +506,10 @@ class Data(object):
|
|||||||
# check for automatic picks
|
# check for automatic picks
|
||||||
print("Writing phases to ObsPy-quakeml file")
|
print("Writing phases to ObsPy-quakeml file")
|
||||||
for key in picks:
|
for key in picks:
|
||||||
|
if not picks[key].get('P'):
|
||||||
|
continue
|
||||||
if picks[key]['P']['picker'] == 'auto':
|
if picks[key]['P']['picker'] == 'auto':
|
||||||
print("Existing picks will be overwritten!")
|
print("Existing auto-picks will be overwritten in pick-dictionary!")
|
||||||
picks = picks_from_picksdict(picks)
|
picks = picks_from_picksdict(picks)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -346,6 +346,7 @@ 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
|
||||||
|
|
||||||
@ -499,7 +500,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
print(e)
|
print(e)
|
||||||
fm = None
|
fm = None
|
||||||
if fm == None:
|
if fm is None:
|
||||||
fm = '?'
|
fm = '?'
|
||||||
onset = arrivals[key]['P']['mpp']
|
onset = arrivals[key]['P']['mpp']
|
||||||
year = onset.year
|
year = onset.year
|
||||||
@ -965,7 +966,7 @@ def getQualitiesfromxml(xmlnames, ErrorsP, ErrorsS, plotflag=1):
|
|||||||
arrivals_copy = cat_copy.events[0].picks
|
arrivals_copy = cat_copy.events[0].picks
|
||||||
# Prefere manual picks if qualities are sufficient!
|
# Prefere manual picks if qualities are sufficient!
|
||||||
for Pick in arrivals:
|
for Pick in arrivals:
|
||||||
if (Pick.method_id.id).split('/')[1] == 'manual':
|
if Pick.method_id.id.split('/')[1] == 'manual':
|
||||||
mstation = Pick.waveform_id.station_code
|
mstation = Pick.waveform_id.station_code
|
||||||
mstation_ext = mstation + '_'
|
mstation_ext = mstation + '_'
|
||||||
for mpick in arrivals_copy:
|
for mpick in arrivals_copy:
|
||||||
@ -973,14 +974,14 @@ def getQualitiesfromxml(xmlnames, ErrorsP, ErrorsS, plotflag=1):
|
|||||||
if phase == 'P':
|
if phase == 'P':
|
||||||
if ((mpick.waveform_id.station_code == mstation) or
|
if ((mpick.waveform_id.station_code == mstation) or
|
||||||
(mpick.waveform_id.station_code == mstation_ext)) and \
|
(mpick.waveform_id.station_code == mstation_ext)) and \
|
||||||
((mpick.method_id).split('/')[1] == 'auto') and \
|
(mpick.method_id.split('/')[1] == 'auto') and \
|
||||||
(mpick.time_errors['uncertainty'] <= ErrorsP[3]):
|
(mpick.time_errors['uncertainty'] <= ErrorsP[3]):
|
||||||
del mpick
|
del mpick
|
||||||
break
|
break
|
||||||
elif phase == 'S':
|
elif phase == 'S':
|
||||||
if ((mpick.waveform_id.station_code == mstation) or
|
if ((mpick.waveform_id.station_code == mstation) or
|
||||||
(mpick.waveform_id.station_code == mstation_ext)) and \
|
(mpick.waveform_id.station_code == mstation_ext)) and \
|
||||||
((mpick.method_id).split('/')[1] == 'auto') and \
|
(mpick.method_id.split('/')[1] == 'auto') and \
|
||||||
(mpick.time_errors['uncertainty'] <= ErrorsS[3]):
|
(mpick.time_errors['uncertainty'] <= ErrorsS[3]):
|
||||||
del mpick
|
del mpick
|
||||||
break
|
break
|
||||||
|
@ -76,6 +76,7 @@ def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn):
|
|||||||
def locate(fnin, parameter=None):
|
def locate(fnin, parameter=None):
|
||||||
"""
|
"""
|
||||||
takes an external program name and tries to run it
|
takes an external program name and tries to run it
|
||||||
|
:param parameter: PyLoT Parameter object
|
||||||
:param fnin: external program name
|
:param fnin: external program name
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
@ -8,6 +8,7 @@ function conglomerate utils.
|
|||||||
|
|
||||||
:author: MAGS2 EP3 working group / Ludger Kueperkoch
|
:author: MAGS2 EP3 working group / Ludger Kueperkoch
|
||||||
"""
|
"""
|
||||||
|
import traceback
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -71,42 +72,34 @@ def autopickevent(data, param, iplot=0, fig_dict=None, fig_dict_wadatijack=None,
|
|||||||
|
|
||||||
for station in stations:
|
for station in stations:
|
||||||
topick = data.select(station=station)
|
topick = data.select(station=station)
|
||||||
|
input_tuples.append((topick, param, apverbose, iplot, fig_dict, metadata, origin))
|
||||||
if iplot is None or iplot == 'None' or iplot == 0:
|
|
||||||
input_tuples.append((topick, param, apverbose, metadata, origin))
|
|
||||||
if iplot > 0:
|
|
||||||
all_onsets[station] = autopickstation(topick, param, verbose=apverbose,
|
|
||||||
iplot=iplot, fig_dict=fig_dict,
|
|
||||||
metadata=metadata, origin=origin)
|
|
||||||
|
|
||||||
if iplot > 0:
|
if iplot > 0:
|
||||||
print('iPlot Flag active: NO MULTIPROCESSING possible.')
|
print('iPlot Flag active: NO MULTIPROCESSING possible.')
|
||||||
return all_onsets
|
ncores = 1
|
||||||
|
|
||||||
# rename str for ncores in case ncores == 0 (use all cores)
|
# rename ncores for string representation in case ncores == 0 (use all cores)
|
||||||
ncores_str = ncores if ncores != 0 else 'all available'
|
ncores_str = ncores if ncores != 0 else 'all available'
|
||||||
|
|
||||||
print('Autopickstation: Distribute autopicking for {} '
|
print('Autopickstation: Distribute autopicking for {} '
|
||||||
'stations on {} cores.'.format(len(input_tuples), ncores_str))
|
'stations on {} cores.'.format(len(input_tuples), ncores_str))
|
||||||
|
|
||||||
pool = gen_Pool(ncores)
|
if ncores == 1:
|
||||||
results = pool.map(call_autopickstation, input_tuples)
|
results = serial_picking(input_tuples)
|
||||||
pool.close()
|
else:
|
||||||
|
results = parallel_picking(input_tuples, ncores)
|
||||||
|
|
||||||
for result, wfstream in results:
|
for result, station in results:
|
||||||
if type(result) == dict:
|
if type(result) == dict:
|
||||||
station = result['station']
|
|
||||||
result.pop('station')
|
|
||||||
all_onsets[station] = result
|
all_onsets[station] = result
|
||||||
else:
|
else:
|
||||||
if result == None:
|
if result is None:
|
||||||
result = 'Picker exited unexpectedly.'
|
result = 'Picker exited unexpectedly.'
|
||||||
if len(wfstream) > 0:
|
|
||||||
station = wfstream[0].stats.station
|
|
||||||
else:
|
|
||||||
station = None
|
|
||||||
print('Could not pick a station: {}\nReason: {}'.format(station, result))
|
print('Could not pick a station: {}\nReason: {}'.format(station, result))
|
||||||
|
|
||||||
|
# no Wadati/JK for single station (also valid for tuning mode)
|
||||||
|
if len(stations) == 1:
|
||||||
|
return all_onsets
|
||||||
|
|
||||||
# quality control
|
# quality control
|
||||||
# median check and jackknife on P-onset times
|
# median check and jackknife on P-onset times
|
||||||
jk_checked_onsets = checkPonsets(all_onsets, mdttolerance, jackfactor, iplot, fig_dict_wadatijack)
|
jk_checked_onsets = checkPonsets(all_onsets, mdttolerance, jackfactor, iplot, fig_dict_wadatijack)
|
||||||
@ -115,6 +108,20 @@ def autopickevent(data, param, iplot=0, fig_dict=None, fig_dict_wadatijack=None,
|
|||||||
return wadationsets
|
return wadationsets
|
||||||
|
|
||||||
|
|
||||||
|
def serial_picking(input_tuples):
|
||||||
|
result = []
|
||||||
|
for input_tuple in input_tuples:
|
||||||
|
result.append(call_autopickstation(input_tuple))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def parallel_picking(input_tuples, ncores):
|
||||||
|
pool = gen_Pool(ncores)
|
||||||
|
result = pool.imap_unordered(call_autopickstation, input_tuples)
|
||||||
|
pool.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def call_autopickstation(input_tuple):
|
def call_autopickstation(input_tuple):
|
||||||
"""
|
"""
|
||||||
helper function used for multiprocessing
|
helper function used for multiprocessing
|
||||||
@ -123,12 +130,16 @@ def call_autopickstation(input_tuple):
|
|||||||
:return: dictionary containing P pick, S pick and station name
|
:return: dictionary containing P pick, S pick and station name
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
"""
|
"""
|
||||||
wfstream, pickparam, verbose, metadata, origin = input_tuple
|
wfstream, pickparam, verbose, iplot, fig_dict, metadata, origin = input_tuple
|
||||||
|
if fig_dict:
|
||||||
|
print('Running in interactive mode')
|
||||||
# multiprocessing not possible with interactive plotting
|
# multiprocessing not possible with interactive plotting
|
||||||
try:
|
try:
|
||||||
return autopickstation(wfstream, pickparam, verbose, iplot=0, metadata=metadata, origin=origin), wfstream
|
return autopickstation(wfstream, pickparam, verbose, fig_dict=fig_dict, iplot=iplot, metadata=metadata,
|
||||||
|
origin=origin)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return e, wfstream
|
tbe = traceback.format_exc()
|
||||||
|
return tbe, wfstream[0].stats.station
|
||||||
|
|
||||||
|
|
||||||
def get_source_coords(parser, station_id):
|
def get_source_coords(parser, station_id):
|
||||||
@ -1312,9 +1323,12 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
|||||||
# split components
|
# split components
|
||||||
zdat, ndat, edat = get_components_from_waveformstream(wfstream)
|
zdat, ndat, edat = get_components_from_waveformstream(wfstream)
|
||||||
|
|
||||||
|
picks = {}
|
||||||
|
station = wfstream[0].stats.station
|
||||||
|
|
||||||
if not zdat:
|
if not zdat:
|
||||||
print('No z-component found for station {}. STOP'.format(wfstream[0].stats.station))
|
print('No z-component found for station {}. STOP'.format(station))
|
||||||
return
|
return picks, station
|
||||||
|
|
||||||
if p_params['algoP'] == 'HOS' or p_params['algoP'] == 'ARZ' and zdat is not None:
|
if p_params['algoP'] == 'HOS' or p_params['algoP'] == 'ARZ' and zdat is not None:
|
||||||
msg = '##################################################\nautopickstation:' \
|
msg = '##################################################\nautopickstation:' \
|
||||||
@ -1331,13 +1345,10 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
|||||||
Lc = np.inf
|
Lc = np.inf
|
||||||
print('autopickstation: use_taup flag active.')
|
print('autopickstation: use_taup flag active.')
|
||||||
if not metadata:
|
if not metadata:
|
||||||
metadata = [None, None]
|
|
||||||
if not metadata[1]:
|
|
||||||
print('Warning: Could not use TauPy to estimate onsets as there are no metadata given.')
|
print('Warning: Could not use TauPy to estimate onsets as there are no metadata given.')
|
||||||
else:
|
else:
|
||||||
station_id = wfstream[0].get_id()
|
station_id = wfstream[0].get_id()
|
||||||
parser = metadata[1]
|
station_coords = metadata.get_coordinates(station_id, time=wfstream[0].stats.starttime)
|
||||||
station_coords = get_source_coords(parser, station_id)
|
|
||||||
if station_coords and origin:
|
if station_coords and origin:
|
||||||
source_origin = origin[0]
|
source_origin = origin[0]
|
||||||
model = TauPyModel(p_params['taup_model'])
|
model = TauPyModel(p_params['taup_model'])
|
||||||
@ -1377,7 +1388,7 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
|||||||
Lwf = zdat[0].stats.endtime - zdat[0].stats.starttime
|
Lwf = zdat[0].stats.endtime - zdat[0].stats.starttime
|
||||||
if not Lwf > 0:
|
if not Lwf > 0:
|
||||||
print('autopickstation: empty trace! Return!')
|
print('autopickstation: empty trace! Return!')
|
||||||
return
|
return picks, station
|
||||||
|
|
||||||
Ldiff = Lwf - abs(Lc)
|
Ldiff = Lwf - abs(Lc)
|
||||||
if Ldiff <= 0 or pstop <= pstart or pstop - pstart <= thosmw:
|
if Ldiff <= 0 or pstop <= pstart or pstop - pstart <= thosmw:
|
||||||
@ -1574,7 +1585,7 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
|||||||
msg = "autopickstation: P-weight: {0}, " \
|
msg = "autopickstation: P-weight: {0}, " \
|
||||||
"SNR: {1}, SNR[dB]: {2}, Polarity: {3}".format(Pweight, SNRP, SNRPdB, FM)
|
"SNR: {1}, SNR[dB]: {2}, Polarity: {3}".format(Pweight, SNRP, SNRPdB, FM)
|
||||||
print(msg)
|
print(msg)
|
||||||
msg = 'autopickstation: Refind P-Pick: {} s | P-Error: {} s'.format(zdat[0].stats.starttime \
|
msg = 'autopickstation: Refined P-Pick: {} s | P-Error: {} s'.format(zdat[0].stats.starttime \
|
||||||
+ mpickP, Perror)
|
+ mpickP, Perror)
|
||||||
print(msg)
|
print(msg)
|
||||||
Sflag = 1
|
Sflag = 1
|
||||||
@ -1956,15 +1967,14 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
|||||||
ax1.set_ylim([-1.5, 1.5])
|
ax1.set_ylim([-1.5, 1.5])
|
||||||
ax1.set_ylabel('Normalized Counts')
|
ax1.set_ylabel('Normalized Counts')
|
||||||
# fig.suptitle(tr_filt.stats.starttime)
|
# fig.suptitle(tr_filt.stats.starttime)
|
||||||
try:
|
# only continue if one horizontal stream exists
|
||||||
len(edat[0])
|
if (ndat or edat) and Sflag == 1:
|
||||||
except:
|
# mirror components in case one does not exist
|
||||||
|
if not edat:
|
||||||
edat = ndat
|
edat = ndat
|
||||||
try:
|
if not ndat:
|
||||||
len(ndat[0])
|
|
||||||
except:
|
|
||||||
ndat = edat
|
ndat = edat
|
||||||
if len(edat[0]) > 1 and len(ndat[0]) > 1 and Sflag == 1:
|
if len(edat[0]) > 1 and len(ndat[0]) > 1:
|
||||||
# plot horizontal traces
|
# plot horizontal traces
|
||||||
ax2 = fig.add_subplot(3, 1, 2, sharex=ax1)
|
ax2 = fig.add_subplot(3, 1, 2, sharex=ax1)
|
||||||
th1data = np.arange(0,
|
th1data = np.arange(0,
|
||||||
@ -2082,12 +2092,22 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
|||||||
epickP = zdat[0].stats.starttime - p_params['timeerrorsP'][3]
|
epickP = zdat[0].stats.starttime - p_params['timeerrorsP'][3]
|
||||||
mpickP = zdat[0].stats.starttime
|
mpickP = zdat[0].stats.starttime
|
||||||
|
|
||||||
|
# create dictionary
|
||||||
|
# for P phase
|
||||||
|
ccode = zdat[0].stats.channel
|
||||||
|
ncode = zdat[0].stats.network
|
||||||
|
ppick = dict(channel=ccode, network=ncode, lpp=lpickP, epp=epickP, mpp=mpickP, spe=Perror, snr=SNRP,
|
||||||
|
snrdb=SNRPdB, weight=Pweight, fm=FM, w0=None, fc=None, Mo=None,
|
||||||
|
Mw=None, picker=picker, marked=Pmarker)
|
||||||
|
|
||||||
if edat:
|
if edat:
|
||||||
hdat = edat[0]
|
hdat = edat[0]
|
||||||
elif ndat:
|
elif ndat:
|
||||||
hdat = ndat[0]
|
hdat = ndat[0]
|
||||||
else:
|
else:
|
||||||
return
|
# no horizontal components given
|
||||||
|
picks = dict(P=ppick)
|
||||||
|
return picks, station
|
||||||
|
|
||||||
if lpickS is not None and lpickS == mpickS:
|
if lpickS is not None and lpickS == mpickS:
|
||||||
lpickS += hdat.stats.delta
|
lpickS += hdat.stats.delta
|
||||||
@ -2104,21 +2124,14 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
|||||||
epickS = hdat.stats.starttime - s_params['timeerrorsS'][3]
|
epickS = hdat.stats.starttime - s_params['timeerrorsS'][3]
|
||||||
mpickS = hdat.stats.starttime
|
mpickS = hdat.stats.starttime
|
||||||
|
|
||||||
# create dictionary
|
|
||||||
# for P phase
|
|
||||||
ccode = zdat[0].stats.channel
|
|
||||||
ncode = zdat[0].stats.network
|
|
||||||
ppick = dict(channel=ccode, network=ncode, lpp=lpickP, epp=epickP, mpp=mpickP, spe=Perror, snr=SNRP,
|
|
||||||
snrdb=SNRPdB, weight=Pweight, fm=FM, w0=None, fc=None, Mo=None,
|
|
||||||
Mw=None, picker=picker, marked=Pmarker)
|
|
||||||
# add S phase
|
# add S phase
|
||||||
ccode = hdat.stats.channel
|
ccode = hdat.stats.channel
|
||||||
ncode = hdat.stats.network
|
ncode = hdat.stats.network
|
||||||
spick = dict(channel=ccode, network=ncode, lpp=lpickS, epp=epickS, mpp=mpickS, spe=Serror, snr=SNRS,
|
spick = dict(channel=ccode, network=ncode, lpp=lpickS, epp=epickS, mpp=mpickS, spe=Serror, snr=SNRS,
|
||||||
snrdb=SNRSdB, weight=Sweight, fm=None, picker=picker, Ao=Ao)
|
snrdb=SNRSdB, weight=Sweight, fm=None, picker=picker, Ao=Ao)
|
||||||
# merge picks into returning dictionary
|
# merge picks into returning dictionary
|
||||||
picks = dict(P=ppick, S=spick, station=zdat[0].stats.station)
|
picks = dict(P=ppick, S=spick)
|
||||||
return picks
|
return picks, station
|
||||||
|
|
||||||
|
|
||||||
def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter, fig_dict=None):
|
def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter, fig_dict=None):
|
||||||
@ -2203,7 +2216,7 @@ def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter, fig_dict=None):
|
|||||||
print("zfac: %f => %f" % (zfac_old, pickparameter.get('zfac')))
|
print("zfac: %f => %f" % (zfac_old, pickparameter.get('zfac')))
|
||||||
|
|
||||||
# repick station
|
# repick station
|
||||||
newpicks = autopickstation(wf2pick, pickparameter, fig_dict=fig_dict)
|
newpicks, _ = autopickstation(wf2pick, pickparameter, fig_dict=fig_dict)
|
||||||
|
|
||||||
# replace old dictionary with new one
|
# replace old dictionary with new one
|
||||||
picks[badpicks[i][0]] = newpicks
|
picks[badpicks[i][0]] = newpicks
|
||||||
|
@ -506,7 +506,8 @@ class PDFstatistics(object):
|
|||||||
|
|
||||||
return rlist
|
return rlist
|
||||||
|
|
||||||
def writeThetaToFile(self, array, out_dir):
|
@staticmethod
|
||||||
|
def writeThetaToFile(array, out_dir):
|
||||||
"""
|
"""
|
||||||
Method to write array like data to file. Useful since acquiring can take
|
Method to write array like data to file. Useful since acquiring can take
|
||||||
serious amount of time when dealing with large databases.
|
serious amount of time when dealing with large databases.
|
||||||
|
@ -191,9 +191,24 @@ class AICPicker(AutoPicker):
|
|||||||
# remove offset in AIC function
|
# remove offset in AIC function
|
||||||
offset = abs(min(aic) - min(aicsmooth))
|
offset = abs(min(aic) - min(aicsmooth))
|
||||||
aicsmooth = aicsmooth - offset
|
aicsmooth = aicsmooth - offset
|
||||||
|
cf = self.Data[0].data
|
||||||
# get maximum of HOS/AR-CF as startimg point for searching
|
# get maximum of HOS/AR-CF as startimg point for searching
|
||||||
# minimum in AIC function
|
# minimum in AIC function
|
||||||
icfmax = np.argmax(self.Data[0].data)
|
icfmax = np.argmax(cf)
|
||||||
|
|
||||||
|
# MP MP testing threshold
|
||||||
|
thresh_hit = False
|
||||||
|
thresh_factor = 0.7
|
||||||
|
thresh = thresh_factor * cf[icfmax]
|
||||||
|
for index, sample in enumerate(cf):
|
||||||
|
if sample >= thresh:
|
||||||
|
thresh_hit = True
|
||||||
|
# go on searching for the following maximum
|
||||||
|
if index > 0 and thresh_hit:
|
||||||
|
if sample <= cf[index - 1]:
|
||||||
|
icfmax = index - 1
|
||||||
|
break
|
||||||
|
# MP MP ---
|
||||||
|
|
||||||
# find minimum in AIC-CF front of maximum of HOS/AR-CF
|
# find minimum in AIC-CF front of maximum of HOS/AR-CF
|
||||||
lpickwindow = int(round(self.PickWindow / self.dt))
|
lpickwindow = int(round(self.PickWindow / self.dt))
|
||||||
@ -233,14 +248,14 @@ class AICPicker(AutoPicker):
|
|||||||
ii = min([isignal[len(isignal) - 1], len(self.Tcf)])
|
ii = min([isignal[len(isignal) - 1], len(self.Tcf)])
|
||||||
isignal = isignal[0:ii]
|
isignal = isignal[0:ii]
|
||||||
try:
|
try:
|
||||||
self.Data[0].data[isignal]
|
cf[isignal]
|
||||||
except IndexError as e:
|
except IndexError as e:
|
||||||
msg = "Time series out of bounds! {}".format(e)
|
msg = "Time series out of bounds! {}".format(e)
|
||||||
print(msg)
|
print(msg)
|
||||||
return
|
return
|
||||||
# calculate SNR from CF
|
# calculate SNR from CF
|
||||||
self.SNR = max(abs(self.Data[0].data[isignal])) / \
|
self.SNR = max(abs(cf[isignal])) / \
|
||||||
abs(np.mean(self.Data[0].data[inoise]))
|
abs(np.mean(cf[inoise]))
|
||||||
# calculate slope from CF after initial pick
|
# calculate slope from CF after initial pick
|
||||||
# get slope window
|
# get slope window
|
||||||
tslope = self.TSNR[3] # slope determination window
|
tslope = self.TSNR[3] # slope determination window
|
||||||
@ -249,11 +264,12 @@ class AICPicker(AutoPicker):
|
|||||||
& (self.Tcf >= self.Pick)) # TODO: put this in a seperate function like getsignalwin
|
& (self.Tcf >= self.Pick)) # TODO: put this in a seperate function like getsignalwin
|
||||||
else:
|
else:
|
||||||
islope = np.where((self.Tcf <= min([self.Pick + tslope, self.Tcf[-1]])) \
|
islope = np.where((self.Tcf <= min([self.Pick + tslope, self.Tcf[-1]])) \
|
||||||
& (self.Tcf >= self.Pick + tsafety)) # TODO: put this in a seperate function like getsignalwin
|
& (
|
||||||
|
self.Tcf >= self.Pick + tsafety)) # TODO: put this in a seperate function like getsignalwin
|
||||||
# find maximum within slope determination window
|
# find maximum within slope determination window
|
||||||
# 'cause slope should be calculated up to first local minimum only!
|
# 'cause slope should be calculated up to first local minimum only!
|
||||||
try:
|
try:
|
||||||
dataslope = self.Data[0].data[islope[0][0:-1]]
|
dataslope = cf[islope[0][0:-1]]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
print("Slope Calculation: empty array islope, check signal window")
|
print("Slope Calculation: empty array islope, check signal window")
|
||||||
return
|
return
|
||||||
@ -263,7 +279,7 @@ class AICPicker(AutoPicker):
|
|||||||
try:
|
try:
|
||||||
imaxs, = argrelmax(dataslope)
|
imaxs, = argrelmax(dataslope)
|
||||||
imax = imaxs[0]
|
imax = imaxs[0]
|
||||||
except ValueError as e:
|
except (ValueError, IndexError) as e:
|
||||||
print(e, 'picker: argrelmax not working!')
|
print(e, 'picker: argrelmax not working!')
|
||||||
imax = np.argmax(dataslope)
|
imax = np.argmax(dataslope)
|
||||||
iislope = islope[0][0:imax + 1]
|
iislope = islope[0][0:imax + 1]
|
||||||
@ -276,14 +292,14 @@ class AICPicker(AutoPicker):
|
|||||||
print("AICPicker: Maximum for slope determination right at the beginning of the window!")
|
print("AICPicker: Maximum for slope determination right at the beginning of the window!")
|
||||||
print("Choose longer slope determination window!")
|
print("Choose longer slope determination window!")
|
||||||
if self.iplot > 1:
|
if self.iplot > 1:
|
||||||
if self.fig == None or self.fig == 'None':
|
if self.fig is None or self.fig == 'None':
|
||||||
fig = plt.figure()
|
fig = plt.figure()
|
||||||
plt_flag = iplot
|
plt_flag = iplot
|
||||||
else:
|
else:
|
||||||
fig = self.fig
|
fig = self.fig
|
||||||
ax = fig.add_subplot(111)
|
ax = fig.add_subplot(111)
|
||||||
x = self.Data[0].data
|
cf = cf
|
||||||
ax.plot(self.Tcf, x / max(x), color=self._linecolor, linewidth=0.7, label='(HOS-/AR-) Data')
|
ax.plot(self.Tcf, cf / max(cf), color=self._linecolor, linewidth=0.7, label='(HOS-/AR-) Data')
|
||||||
ax.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', label='Smoothed AIC-CF')
|
ax.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', label='Smoothed AIC-CF')
|
||||||
ax.legend(loc=1)
|
ax.legend(loc=1)
|
||||||
ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
|
ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
|
||||||
@ -291,12 +307,23 @@ class AICPicker(AutoPicker):
|
|||||||
ax.set_title(self.Data[0].stats.station)
|
ax.set_title(self.Data[0].stats.station)
|
||||||
if plt_flag in [1, 2]:
|
if plt_flag in [1, 2]:
|
||||||
fig.show()
|
fig.show()
|
||||||
try: input()
|
try:
|
||||||
except SyntaxError: pass
|
input()
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
return
|
return
|
||||||
iislope = islope[0][0:imax + 1]
|
iislope = islope[0][0:imax + 1]
|
||||||
dataslope = self.Data[0].data[iislope]
|
# MP MP change slope calculation
|
||||||
|
# get all maxima of aicsmooth
|
||||||
|
iaicmaxima = argrelmax(aicsmooth)[0]
|
||||||
|
# get first index of maximum after pickindex (indices saved in iaicmaxima)
|
||||||
|
aicmax = iaicmaxima[np.where(iaicmaxima > pickindex)[0]]
|
||||||
|
if len(aicmax) > 0:
|
||||||
|
iaicmax = aicmax[0]
|
||||||
|
else:
|
||||||
|
iaicmax = -1
|
||||||
|
dataslope = aicsmooth[pickindex: iaicmax]
|
||||||
# calculate slope as polynomal fit of order 1
|
# calculate slope as polynomal fit of order 1
|
||||||
xslope = np.arange(0, len(dataslope), 1)
|
xslope = np.arange(0, len(dataslope), 1)
|
||||||
P = np.polyfit(xslope, dataslope, 1)
|
P = np.polyfit(xslope, dataslope, 1)
|
||||||
@ -306,24 +333,23 @@ class AICPicker(AutoPicker):
|
|||||||
else:
|
else:
|
||||||
self.slope = 1 / (len(dataslope) * self.Data[0].stats.delta) * (datafit[-1] - datafit[0])
|
self.slope = 1 / (len(dataslope) * self.Data[0].stats.delta) * (datafit[-1] - datafit[0])
|
||||||
# normalize slope to maximum of cf to make it unit independent
|
# normalize slope to maximum of cf to make it unit independent
|
||||||
self.slope /= self.Data[0].data[icfmax]
|
self.slope /= aicsmooth[iaicmax]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.SNR = None
|
self.SNR = None
|
||||||
self.slope = None
|
self.slope = None
|
||||||
|
|
||||||
if iplot > 1:
|
if iplot > 1:
|
||||||
if self.fig == None or self.fig == 'None':
|
if self.fig is None or self.fig == 'None':
|
||||||
fig = plt.figure() # self.iplot)
|
fig = plt.figure() # self.iplot)
|
||||||
plt_flag = iplot
|
plt_flag = iplot
|
||||||
else:
|
else:
|
||||||
fig = self.fig
|
fig = self.fig
|
||||||
fig._tight = True
|
fig._tight = True
|
||||||
ax1 = fig.add_subplot(211)
|
ax1 = fig.add_subplot(211)
|
||||||
x = self.Data[0].data
|
if len(self.Tcf) > len(cf): # why? LK
|
||||||
if len(self.Tcf) > len(self.Data[0].data): # why? LK
|
|
||||||
self.Tcf = self.Tcf[0:len(self.Tcf) - 1]
|
self.Tcf = self.Tcf[0:len(self.Tcf) - 1]
|
||||||
ax1.plot(self.Tcf, x / max(x), color=self._linecolor, linewidth=0.7, label='(HOS-/AR-) Data')
|
ax1.plot(self.Tcf, cf / max(cf), color=self._linecolor, linewidth=0.7, label='(HOS-/AR-) Data')
|
||||||
ax1.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', label='Smoothed AIC-CF')
|
ax1.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', label='Smoothed AIC-CF')
|
||||||
if self.Pick is not None:
|
if self.Pick is not None:
|
||||||
ax1.plot([self.Pick, self.Pick], [-0.1, 0.5], 'b', linewidth=2, label='AIC-Pick')
|
ax1.plot([self.Pick, self.Pick], [-0.1, 0.5], 'b', linewidth=2, label='AIC-Pick')
|
||||||
@ -333,7 +359,7 @@ class AICPicker(AutoPicker):
|
|||||||
|
|
||||||
if self.Pick is not None:
|
if self.Pick is not None:
|
||||||
ax2 = fig.add_subplot(2, 1, 2, sharex=ax1)
|
ax2 = fig.add_subplot(2, 1, 2, sharex=ax1)
|
||||||
ax2.plot(self.Tcf, x, color=self._linecolor, linewidth=0.7, label='Data')
|
ax2.plot(self.Tcf, aicsmooth, color='r', linewidth=0.7, label='Data')
|
||||||
ax1.axvspan(self.Tcf[inoise[0]], self.Tcf[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window')
|
ax1.axvspan(self.Tcf[inoise[0]], self.Tcf[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window')
|
||||||
ax1.axvspan(self.Tcf[isignal[0]], self.Tcf[isignal[-1]], color='b', alpha=0.2, lw=0,
|
ax1.axvspan(self.Tcf[isignal[0]], self.Tcf[isignal[-1]], color='b', alpha=0.2, lw=0,
|
||||||
label='Signal Window')
|
label='Signal Window')
|
||||||
@ -345,7 +371,8 @@ class AICPicker(AutoPicker):
|
|||||||
label='Signal Window')
|
label='Signal Window')
|
||||||
ax2.axvspan(self.Tcf[iislope[0]], self.Tcf[iislope[-1]], color='g', alpha=0.2, lw=0,
|
ax2.axvspan(self.Tcf[iislope[0]], self.Tcf[iislope[-1]], color='g', alpha=0.2, lw=0,
|
||||||
label='Slope Window')
|
label='Slope Window')
|
||||||
ax2.plot(self.Tcf[iislope], datafit, 'g', linewidth=2, label='Slope')
|
ax2.plot(self.Tcf[pickindex: iaicmax], datafit, 'g', linewidth=2,
|
||||||
|
label='Slope') # MP MP changed temporarily!
|
||||||
|
|
||||||
if self.slope is not None:
|
if self.slope is not None:
|
||||||
ax1.set_title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station,
|
ax1.set_title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station,
|
||||||
@ -361,15 +388,17 @@ class AICPicker(AutoPicker):
|
|||||||
|
|
||||||
if plt_flag in [1, 2]:
|
if plt_flag in [1, 2]:
|
||||||
fig.show()
|
fig.show()
|
||||||
try: input()
|
try:
|
||||||
except SyntaxError: pass
|
input()
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
if plt_flag == 3:
|
if plt_flag == 3:
|
||||||
stats = self.Data[0].stats
|
stats = self.Data[0].stats
|
||||||
netstlc = '{}.{}.{}'.format(stats.network, stats.station, stats.location)
|
netstlc = '{}.{}.{}'.format(stats.network, stats.station, stats.location)
|
||||||
fig.savefig('aicfig_{}_{}.png'.format(netstlc, stats.channel))
|
fig.savefig('aicfig_{}_{}.png'.format(netstlc, stats.channel))
|
||||||
|
|
||||||
if self.Pick == None:
|
if self.Pick is None:
|
||||||
print('AICPicker: Could not find minimum, picking window too short?')
|
print('AICPicker: Could not find minimum, picking window too short?')
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -486,7 +515,7 @@ class PragPicker(AutoPicker):
|
|||||||
pickflag = 0
|
pickflag = 0
|
||||||
|
|
||||||
if iplot > 1:
|
if iplot > 1:
|
||||||
if self.fig == None or self.fig == 'None':
|
if self.fig is None or self.fig == 'None':
|
||||||
fig = plt.figure() # self.getiplot())
|
fig = plt.figure() # self.getiplot())
|
||||||
plt_flag = 1
|
plt_flag = 1
|
||||||
else:
|
else:
|
||||||
@ -496,15 +525,18 @@ class PragPicker(AutoPicker):
|
|||||||
ax.plot(Tcfpick, cfipick, color=self._linecolor, linewidth=0.7, label='CF')
|
ax.plot(Tcfpick, cfipick, color=self._linecolor, linewidth=0.7, label='CF')
|
||||||
ax.plot(Tcfpick, cfsmoothipick, 'r', label='Smoothed CF')
|
ax.plot(Tcfpick, cfsmoothipick, 'r', label='Smoothed CF')
|
||||||
if pickflag > 0:
|
if pickflag > 0:
|
||||||
ax.plot([self.Pick, self.Pick], [min(cfipick), max(cfipick)], self._pickcolor_p, linewidth=2, label='Pick')
|
ax.plot([self.Pick, self.Pick], [min(cfipick), max(cfipick)], self._pickcolor_p, linewidth=2,
|
||||||
|
label='Pick')
|
||||||
ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
|
ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
|
||||||
ax.set_yticks([])
|
ax.set_yticks([])
|
||||||
ax.set_title(self.Data[0].stats.station)
|
ax.set_title(self.Data[0].stats.station)
|
||||||
ax.legend(loc=1)
|
ax.legend(loc=1)
|
||||||
if plt_flag == 1:
|
if plt_flag == 1:
|
||||||
fig.show()
|
fig.show()
|
||||||
try: input()
|
try:
|
||||||
except SyntaxError: pass
|
input()
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -14,8 +14,7 @@ import matplotlib.pyplot as plt
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from scipy.signal import argrelmax
|
from scipy.signal import argrelmax
|
||||||
from obspy.core import Stream, UTCDateTime
|
from obspy.core import Stream, UTCDateTime
|
||||||
from pylot.core.util.utils import real_Bool, real_None
|
from pylot.core.util.utils import real_Bool, real_None, SetChannelComponents
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecolor='k'):
|
def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecolor='k'):
|
||||||
@ -144,13 +143,16 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecol
|
|||||||
ax.plot(t, x, color=linecolor, linewidth=0.7, label='Data')
|
ax.plot(t, x, color=linecolor, linewidth=0.7, label='Data')
|
||||||
ax.axvspan(t[inoise[0]], t[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window')
|
ax.axvspan(t[inoise[0]], t[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window')
|
||||||
ax.axvspan(t[isignal[0]], t[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window')
|
ax.axvspan(t[isignal[0]], t[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window')
|
||||||
ax.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], color=linecolor, linewidth=0.7, linestyle='dashed', label='Noise Level')
|
ax.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], color=linecolor, linewidth=0.7, linestyle='dashed',
|
||||||
|
label='Noise Level')
|
||||||
ax.plot(t[pis[zc]], np.zeros(len(zc)), '*g',
|
ax.plot(t[pis[zc]], np.zeros(len(zc)), '*g',
|
||||||
markersize=14, label='Zero Crossings')
|
markersize=14, label='Zero Crossings')
|
||||||
ax.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], color=linecolor, linewidth=0.7, linestyle='dashed')
|
ax.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], color=linecolor, linewidth=0.7, linestyle='dashed')
|
||||||
ax.plot([Pick1, Pick1], [max(x), -max(x)], 'b', linewidth=2, label='mpp')
|
ax.plot([Pick1, Pick1], [max(x), -max(x)], 'b', linewidth=2, label='mpp')
|
||||||
ax.plot([LPick, LPick], [max(x) / 2, -max(x) / 2], color=linecolor, linewidth=0.7, linestyle='dashed', label='lpp')
|
ax.plot([LPick, LPick], [max(x) / 2, -max(x) / 2], color=linecolor, linewidth=0.7, linestyle='dashed',
|
||||||
ax.plot([EPick, EPick], [max(x) / 2, -max(x) / 2], color=linecolor, linewidth=0.7, linestyle='dashed', label='epp')
|
label='lpp')
|
||||||
|
ax.plot([EPick, EPick], [max(x) / 2, -max(x) / 2], color=linecolor, linewidth=0.7, linestyle='dashed',
|
||||||
|
label='epp')
|
||||||
ax.plot([Pick1 + PickError, Pick1 + PickError],
|
ax.plot([Pick1 + PickError, Pick1 + PickError],
|
||||||
[max(x) / 2, -max(x) / 2], 'r--', label='spe')
|
[max(x) / 2, -max(x) / 2], 'r--', label='spe')
|
||||||
ax.plot([Pick1 - PickError, Pick1 - PickError],
|
ax.plot([Pick1 - PickError, Pick1 - PickError],
|
||||||
@ -163,8 +165,10 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecol
|
|||||||
ax.legend(loc=1)
|
ax.legend(loc=1)
|
||||||
if plt_flag == 1:
|
if plt_flag == 1:
|
||||||
fig.show()
|
fig.show()
|
||||||
try: input()
|
try:
|
||||||
except SyntaxError: pass
|
input()
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
|
|
||||||
return EPick, LPick, PickError
|
return EPick, LPick, PickError
|
||||||
@ -227,8 +231,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None, linecolor='k'):
|
|||||||
# get zero crossings after most likely pick
|
# get zero crossings after most likely pick
|
||||||
# initial onset is assumed to be the first zero crossing
|
# initial onset is assumed to be the first zero crossing
|
||||||
# first from unfiltered trace
|
# first from unfiltered trace
|
||||||
zc1 = []
|
zc1 = [Pick]
|
||||||
zc1.append(Pick)
|
|
||||||
index1 = []
|
index1 = []
|
||||||
i = 0
|
i = 0
|
||||||
for j in range(ipick[0][1], ipick[0][len(t[ipick]) - 1]):
|
for j in range(ipick[0][1], ipick[0][len(t[ipick]) - 1]):
|
||||||
@ -273,8 +276,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None, linecolor='k'):
|
|||||||
|
|
||||||
# now using filterd trace
|
# now using filterd trace
|
||||||
# next zero crossings after most likely pick
|
# next zero crossings after most likely pick
|
||||||
zc2 = []
|
zc2 = [Pick]
|
||||||
zc2.append(Pick)
|
|
||||||
index2 = []
|
index2 = []
|
||||||
i = 0
|
i = 0
|
||||||
for j in range(ipick[0][1], ipick[0][len(t[ipick]) - 1]):
|
for j in range(ipick[0][1], ipick[0][len(t[ipick]) - 1]):
|
||||||
@ -362,8 +364,10 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None, linecolor='k'):
|
|||||||
ax2.set_yticks([])
|
ax2.set_yticks([])
|
||||||
if plt_flag == 1:
|
if plt_flag == 1:
|
||||||
fig.show()
|
fig.show()
|
||||||
try: input()
|
try:
|
||||||
except SyntaxError: pass
|
input()
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
|
|
||||||
return FM
|
return FM
|
||||||
@ -573,8 +577,6 @@ def select_for_phase(st, phase):
|
|||||||
:rtype: `~obspy.core.stream.Stream`
|
:rtype: `~obspy.core.stream.Stream`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pylot.core.util.defaults import SetChannelComponents
|
|
||||||
|
|
||||||
sel_st = Stream()
|
sel_st = Stream()
|
||||||
compclass = SetChannelComponents()
|
compclass = SetChannelComponents()
|
||||||
if phase.upper() == 'P':
|
if phase.upper() == 'P':
|
||||||
@ -623,14 +625,18 @@ def wadaticheck(pickdic, dttolerance, iplot=0, fig_dict=None):
|
|||||||
ibad = 0
|
ibad = 0
|
||||||
|
|
||||||
for key in list(pickdic.keys()):
|
for key in list(pickdic.keys()):
|
||||||
if pickdic[key]['P']['weight'] < 4 and pickdic[key]['S']['weight'] < 4:
|
ppick = pickdic[key].get('P')
|
||||||
|
spick = pickdic[key].get('S')
|
||||||
|
if not ppick or not spick:
|
||||||
|
continue
|
||||||
|
if ppick['weight'] < 4 and spick['weight'] < 4:
|
||||||
# calculate S-P time
|
# calculate S-P time
|
||||||
spt = pickdic[key]['S']['mpp'] - pickdic[key]['P']['mpp']
|
spt = spick['mpp'] - ppick['mpp']
|
||||||
# add S-P time to dictionary
|
# add S-P time to dictionary
|
||||||
pickdic[key]['SPt'] = spt
|
pickdic[key]['SPt'] = spt
|
||||||
# add P onsets and corresponding S-P times to list
|
# add P onsets and corresponding S-P times to list
|
||||||
UTCPpick = UTCDateTime(pickdic[key]['P']['mpp'])
|
UTCPpick = UTCDateTime(ppick['mpp'])
|
||||||
UTCSpick = UTCDateTime(pickdic[key]['S']['mpp'])
|
UTCSpick = UTCDateTime(spick['mpp'])
|
||||||
Ppicks.append(UTCPpick.timestamp)
|
Ppicks.append(UTCPpick.timestamp)
|
||||||
Spicks.append(UTCSpick.timestamp)
|
Spicks.append(UTCSpick.timestamp)
|
||||||
SPtimes.append(spt)
|
SPtimes.append(spt)
|
||||||
@ -660,11 +666,11 @@ def wadaticheck(pickdic, dttolerance, iplot=0, fig_dict=None):
|
|||||||
# check, if deviation is larger than adjusted
|
# check, if deviation is larger than adjusted
|
||||||
if wddiff > dttolerance:
|
if wddiff > dttolerance:
|
||||||
# remove pick from dictionary
|
# remove pick from dictionary
|
||||||
pickdic.pop(key)
|
# # mark onset and downgrade S-weight to 9, also set SPE to None (disregarded in GUI)
|
||||||
# # mark onset and downgrade S-weight to 9
|
|
||||||
# # (not used anymore)
|
# # (not used anymore)
|
||||||
# marker = 'badWadatiCheck'
|
marker = 'badWadatiCheck'
|
||||||
# pickdic[key]['S']['weight'] = 9
|
pickdic[key]['S']['weight'] = 9
|
||||||
|
pickdic[key]['S']['spe'] = None
|
||||||
badstations.append(key)
|
badstations.append(key)
|
||||||
ibad += 1
|
ibad += 1
|
||||||
else:
|
else:
|
||||||
@ -677,7 +683,6 @@ def wadaticheck(pickdic, dttolerance, iplot=0, fig_dict=None):
|
|||||||
checkedSPtimes.append(checkedSPtime)
|
checkedSPtimes.append(checkedSPtime)
|
||||||
|
|
||||||
pickdic[key]['S']['marked'] = marker
|
pickdic[key]['S']['marked'] = marker
|
||||||
#pickdic[key]['S']['marked'] = marker
|
|
||||||
print("wadaticheck: the following stations failed the check:")
|
print("wadaticheck: the following stations failed the check:")
|
||||||
print(badstations)
|
print(badstations)
|
||||||
|
|
||||||
@ -851,8 +856,10 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fi
|
|||||||
ax.set_yticks([])
|
ax.set_yticks([])
|
||||||
if plt_flag == 1:
|
if plt_flag == 1:
|
||||||
fig.show()
|
fig.show()
|
||||||
try: input()
|
try:
|
||||||
except SyntaxError: pass
|
input()
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
|
|
||||||
return returnflag
|
return returnflag
|
||||||
@ -886,9 +893,12 @@ def checkPonsets(pickdic, dttolerance, jackfactor=5, iplot=0, fig_dict=None):
|
|||||||
Ppicks = []
|
Ppicks = []
|
||||||
stations = []
|
stations = []
|
||||||
for station in pickdic:
|
for station in pickdic:
|
||||||
if pickdic[station]['P']['weight'] < 4:
|
pick = pickdic[station].get('P')
|
||||||
|
if not pick:
|
||||||
|
continue
|
||||||
|
if pick['weight'] < 4:
|
||||||
# add P onsets to list
|
# add P onsets to list
|
||||||
UTCPpick = UTCDateTime(pickdic[station]['P']['mpp'])
|
UTCPpick = UTCDateTime(pick['mpp'])
|
||||||
Ppicks.append(UTCPpick.timestamp)
|
Ppicks.append(UTCPpick.timestamp)
|
||||||
stations.append(station)
|
stations.append(station)
|
||||||
|
|
||||||
@ -1087,7 +1097,6 @@ def checkZ4S(X, pick, zfac, checkwin, iplot, fig=None, linecolor='k'):
|
|||||||
else:
|
else:
|
||||||
iplot = 0
|
iplot = 0
|
||||||
|
|
||||||
|
|
||||||
assert isinstance(X, Stream), "%s is not a stream object" % str(X)
|
assert isinstance(X, Stream), "%s is not a stream object" % str(X)
|
||||||
|
|
||||||
print("Check for spuriously picked S onset instead of P onset ...")
|
print("Check for spuriously picked S onset instead of P onset ...")
|
||||||
@ -1188,12 +1197,81 @@ def checkZ4S(X, pick, zfac, checkwin, iplot, fig=None, linecolor='k'):
|
|||||||
ax.set_xlabel('Time [s] since %s' % zdat[0].stats.starttime)
|
ax.set_xlabel('Time [s] since %s' % zdat[0].stats.starttime)
|
||||||
if plt_flag == 1:
|
if plt_flag == 1:
|
||||||
fig.show()
|
fig.show()
|
||||||
try: input()
|
try:
|
||||||
except SyntaxError: pass
|
input()
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
return returnflag
|
return returnflag
|
||||||
|
|
||||||
|
|
||||||
|
def getPickQuality(wfdata, picks, inputs, phase, compclass=None):
|
||||||
|
quality = 4
|
||||||
|
components4phases = {'P': ['Z'],
|
||||||
|
'S': ['N', 'E']}
|
||||||
|
timeErrors4phases = {'P': 'timeerrorsP',
|
||||||
|
'S': 'timeerrorsS'}
|
||||||
|
tsnr4phases = {'P': 'tsnrz',
|
||||||
|
'S': 'tsnrh'}
|
||||||
|
|
||||||
|
if not phase in components4phases.keys():
|
||||||
|
raise IOError('getPickQuality: Could not understand phase: {}'.format(phase))
|
||||||
|
|
||||||
|
if not compclass:
|
||||||
|
print('Warning: No settings for channel components found. Using default')
|
||||||
|
compclass = SetChannelComponents()
|
||||||
|
|
||||||
|
picks = picks[phase]
|
||||||
|
mpp = picks.get('mpp')
|
||||||
|
uncertainty = picks.get('spe')
|
||||||
|
if not mpp:
|
||||||
|
print('getPickQuality: No pick found!')
|
||||||
|
return quality
|
||||||
|
if not uncertainty:
|
||||||
|
print('getPickQuality: No pick uncertainty (spe) found!')
|
||||||
|
return quality
|
||||||
|
|
||||||
|
tsnr = inputs[tsnr4phases[phase]]
|
||||||
|
timeErrors = inputs[timeErrors4phases[phase]]
|
||||||
|
snrdb_final = 0
|
||||||
|
|
||||||
|
for component in components4phases[phase]:
|
||||||
|
alter_comp = compclass.getCompPosition(component)
|
||||||
|
st_select = wfdata.select(component=component)
|
||||||
|
st_select += wfdata.select(component=alter_comp)
|
||||||
|
if st_select:
|
||||||
|
trace = st_select[0]
|
||||||
|
_, snrdb, _ = getSNR(st_select, tsnr,
|
||||||
|
mpp - trace.stats.starttime)
|
||||||
|
if snrdb > snrdb_final:
|
||||||
|
snrdb_final = snrdb
|
||||||
|
|
||||||
|
quality = getQualityFromUncertainty(uncertainty, timeErrors)
|
||||||
|
quality += getQualityFromSNR(snrdb_final)
|
||||||
|
|
||||||
|
return quality
|
||||||
|
|
||||||
|
|
||||||
|
def getQualityFromSNR(snrdb):
|
||||||
|
quality_modifier = 4
|
||||||
|
if not snrdb:
|
||||||
|
print('getQualityFromSNR: No snrdb!')
|
||||||
|
return quality_modifier
|
||||||
|
# MP MP ++++ experimental,
|
||||||
|
# raise pick quality by x classes if snrdb is lower than corresponding key
|
||||||
|
quality4snrdb = {3: 4,
|
||||||
|
5: 3,
|
||||||
|
7: 2,
|
||||||
|
9: 1,
|
||||||
|
11: 0}
|
||||||
|
# MP MP ---
|
||||||
|
# iterate over all thresholds and check whether snrdb is larger, if so, set new quality_modifier
|
||||||
|
for snrdb_threshold in sorted(list(quality4snrdb.keys())):
|
||||||
|
if snrdb > snrdb_threshold:
|
||||||
|
quality_modifier = quality4snrdb[snrdb_threshold]
|
||||||
|
return quality_modifier
|
||||||
|
|
||||||
|
|
||||||
def get_quality_class(uncertainty, weight_classes):
|
def get_quality_class(uncertainty, weight_classes):
|
||||||
"""
|
"""
|
||||||
Script to transform uncertainty into quality classes 0-4 regarding adjusted time errors
|
Script to transform uncertainty into quality classes 0-4 regarding adjusted time errors
|
||||||
@ -1378,6 +1456,26 @@ def get_pickparams(pickparam):
|
|||||||
|
|
||||||
return p_params, s_params, first_motion_params, signal_length_params
|
return p_params, s_params, first_motion_params, signal_length_params
|
||||||
|
|
||||||
|
def getQualityFromUncertainty(uncertainty, Errors):
|
||||||
|
# set initial quality to 4 (worst) and change only if one condition is hit
|
||||||
|
quality = 4
|
||||||
|
|
||||||
|
if real_None(uncertainty) is None:
|
||||||
|
return quality
|
||||||
|
|
||||||
|
if uncertainty <= Errors[0]:
|
||||||
|
quality = 0
|
||||||
|
elif (uncertainty > Errors[0]) and \
|
||||||
|
(uncertainty <= Errors[1]):
|
||||||
|
quality = 1
|
||||||
|
elif (uncertainty > Errors[1]) and \
|
||||||
|
(uncertainty <= Errors[2]):
|
||||||
|
quality = 2
|
||||||
|
elif (uncertainty > Errors[2]) and \
|
||||||
|
(uncertainty <= Errors[3]):
|
||||||
|
quality = 3
|
||||||
|
elif uncertainty > Errors[3]:
|
||||||
|
quality = 4
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
|
@ -23,8 +23,7 @@ class Array_map(QtGui.QWidget):
|
|||||||
'''
|
'''
|
||||||
QtGui.QWidget.__init__(self)
|
QtGui.QWidget.__init__(self)
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self.metadata_type = parent.metadata[0]
|
self.metadata = parent.metadata
|
||||||
self.metadata = parent.metadata[1]
|
|
||||||
self.picks = None
|
self.picks = None
|
||||||
self.picks_dict = None
|
self.picks_dict = None
|
||||||
self.autopicks_dict = None
|
self.autopicks_dict = None
|
||||||
@ -74,13 +73,9 @@ class Array_map(QtGui.QWidget):
|
|||||||
if pickDlg.exec_():
|
if pickDlg.exec_():
|
||||||
pyl_mw.setDirty(True)
|
pyl_mw.setDirty(True)
|
||||||
pyl_mw.update_status('picks accepted ({0})'.format(station))
|
pyl_mw.update_status('picks accepted ({0})'.format(station))
|
||||||
replot = pyl_mw.get_current_event().setPick(station, pickDlg.getPicks())
|
pyl_mw.addPicks(station, pickDlg.getPicks(picktype='manual'), type='manual')
|
||||||
|
pyl_mw.addPicks(station, pickDlg.getPicks(picktype='auto'), type='auto')
|
||||||
self._refresh_drawings()
|
self._refresh_drawings()
|
||||||
if replot:
|
|
||||||
pyl_mw.plotWaveformData()
|
|
||||||
pyl_mw.drawPicks()
|
|
||||||
pyl_mw.draw()
|
|
||||||
else:
|
|
||||||
pyl_mw.drawPicks(station)
|
pyl_mw.drawPicks(station)
|
||||||
pyl_mw.draw()
|
pyl_mw.draw()
|
||||||
else:
|
else:
|
||||||
@ -159,35 +154,8 @@ class Array_map(QtGui.QWidget):
|
|||||||
self.main_box.addWidget(self.canvas, 1)
|
self.main_box.addWidget(self.canvas, 1)
|
||||||
self.main_box.addWidget(self.status_label, 0)
|
self.main_box.addWidget(self.status_label, 0)
|
||||||
|
|
||||||
|
|
||||||
def init_stations(self):
|
def init_stations(self):
|
||||||
def stat_info_from_parser(parser):
|
self.stations_dict = self.metadata.get_all_coordinates()
|
||||||
stations_dict = {}
|
|
||||||
for station in parser.stations:
|
|
||||||
station_name = station[0].station_call_letters
|
|
||||||
network_name = station[0].network_code
|
|
||||||
if not station_name in stations_dict.keys():
|
|
||||||
st_id = network_name + '.' + station_name
|
|
||||||
stations_dict[st_id] = {'latitude': station[0].latitude,
|
|
||||||
'longitude': station[0].longitude}
|
|
||||||
return stations_dict
|
|
||||||
|
|
||||||
def stat_info_from_inventory(inventory):
|
|
||||||
stations_dict = {}
|
|
||||||
for network in inventory.networks:
|
|
||||||
for station in network.stations:
|
|
||||||
station_name = station.code
|
|
||||||
network_name = network_name.code
|
|
||||||
if not station_name in stations_dict.keys():
|
|
||||||
st_id = network_name + '.' + station_name
|
|
||||||
stations_dict[st_id] = {'latitude': station[0].latitude,
|
|
||||||
'longitude': station[0].longitude}
|
|
||||||
return stations_dict
|
|
||||||
|
|
||||||
read_stat = {'xml': stat_info_from_inventory,
|
|
||||||
'dless': stat_info_from_parser}
|
|
||||||
|
|
||||||
self.stations_dict = read_stat[self.metadata_type](self.metadata)
|
|
||||||
self.latmin = self.get_min_from_stations('latitude')
|
self.latmin = self.get_min_from_stations('latitude')
|
||||||
self.lonmin = self.get_min_from_stations('longitude')
|
self.lonmin = self.get_min_from_stations('longitude')
|
||||||
self.latmax = self.get_max_from_stations('latitude')
|
self.latmax = self.get_max_from_stations('latitude')
|
||||||
@ -196,13 +164,15 @@ class Array_map(QtGui.QWidget):
|
|||||||
def init_picks(self):
|
def init_picks(self):
|
||||||
def get_picks(station_dict):
|
def get_picks(station_dict):
|
||||||
picks = {}
|
picks = {}
|
||||||
|
# selected phase
|
||||||
phase = self.comboBox_phase.currentText()
|
phase = self.comboBox_phase.currentText()
|
||||||
for st_id in station_dict.keys():
|
for st_id in station_dict.keys():
|
||||||
try:
|
try:
|
||||||
station_name = st_id.split('.')[-1]
|
station_name = st_id.split('.')[-1]
|
||||||
|
# current_picks_dict: auto or manual
|
||||||
pick = self.current_picks_dict()[station_name][phase]
|
pick = self.current_picks_dict()[station_name][phase]
|
||||||
if pick['picker'] == 'auto':
|
if pick['picker'] == 'auto':
|
||||||
if pick['weight'] > 3:
|
if not pick['spe']:
|
||||||
continue
|
continue
|
||||||
picks[st_id] = pick['mpp']
|
picks[st_id] = pick['mpp']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -217,6 +187,7 @@ class Array_map(QtGui.QWidget):
|
|||||||
for pick in picks.values():
|
for pick in picks.values():
|
||||||
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
||||||
picks_utc.append(pick)
|
picks_utc.append(pick)
|
||||||
|
if picks_utc:
|
||||||
self._earliest_picktime = min(picks_utc)
|
self._earliest_picktime = min(picks_utc)
|
||||||
for st_id, pick in picks.items():
|
for st_id, pick in picks.items():
|
||||||
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
||||||
@ -331,6 +302,8 @@ class Array_map(QtGui.QWidget):
|
|||||||
|
|
||||||
def scatter_picked_stations(self):
|
def scatter_picked_stations(self):
|
||||||
picks, lats, lons = self.get_picks_lat_lon()
|
picks, lats, lons = self.get_picks_lat_lon()
|
||||||
|
if len(lons) < 1 and len(lats) < 1:
|
||||||
|
return
|
||||||
# workaround because of an issue with latlon transformation of arrays with len <3
|
# workaround because of an issue with latlon transformation of arrays with len <3
|
||||||
if len(lons) <= 2 and len(lats) <= 2:
|
if len(lons) <= 2 and len(lats) <= 2:
|
||||||
self.sc_picked = self.basemap.scatter(lons[0], lats[0], s=50, facecolor='white',
|
self.sc_picked = self.basemap.scatter(lons[0], lats[0], s=50, facecolor='white',
|
||||||
@ -375,13 +348,16 @@ class Array_map(QtGui.QWidget):
|
|||||||
self.draw_everything()
|
self.draw_everything()
|
||||||
|
|
||||||
def draw_everything(self):
|
def draw_everything(self):
|
||||||
if self.picks_dict or self.autopicks_dict:
|
picktype = self.comboBox_am.currentText()
|
||||||
|
if (self.picks_dict and picktype == 'manual') \
|
||||||
|
or (self.autopicks_dict and picktype == 'auto'):
|
||||||
self.init_picks()
|
self.init_picks()
|
||||||
if len(self.picks) >= 3:
|
if len(self.picks) >= 3:
|
||||||
self.init_picksgrid()
|
self.init_picksgrid()
|
||||||
self.draw_contour_filled()
|
self.draw_contour_filled()
|
||||||
self.scatter_all_stations()
|
self.scatter_all_stations()
|
||||||
if self.picks_dict or self.autopicks_dict:
|
if (self.picks_dict and picktype == 'manual') \
|
||||||
|
or (self.autopicks_dict and picktype == 'auto'):
|
||||||
self.scatter_picked_stations()
|
self.scatter_picked_stations()
|
||||||
self.cbar = self.add_cbar(label='Time relative to first onset ({}) [s]'.format(self._earliest_picktime))
|
self.cbar = self.add_cbar(label='Time relative to first onset ({}) [s]'.format(self._earliest_picktime))
|
||||||
self.comboBox_phase.setEnabled(True)
|
self.comboBox_phase.setEnabled(True)
|
||||||
@ -397,16 +373,16 @@ class Array_map(QtGui.QWidget):
|
|||||||
del (self.cbar, self.cbax_bg)
|
del (self.cbar, self.cbax_bg)
|
||||||
if hasattr(self, 'sc_picked'):
|
if hasattr(self, 'sc_picked'):
|
||||||
self.sc_picked.remove()
|
self.sc_picked.remove()
|
||||||
del (self.sc_picked)
|
del self.sc_picked
|
||||||
if hasattr(self, 'sc_event'):
|
if hasattr(self, 'sc_event'):
|
||||||
self.sc_event.remove()
|
self.sc_event.remove()
|
||||||
del (self.sc_event)
|
del self.sc_event
|
||||||
if hasattr(self, 'contourf'):
|
if hasattr(self, 'contourf'):
|
||||||
self.remove_contourf()
|
self.remove_contourf()
|
||||||
del (self.contourf)
|
del self.contourf
|
||||||
if hasattr(self, 'cid'):
|
if hasattr(self, 'cid'):
|
||||||
self.canvas.mpl_disconnect(self.cid)
|
self.canvas.mpl_disconnect(self.cid)
|
||||||
del (self.cid)
|
del self.cid
|
||||||
try:
|
try:
|
||||||
self.sc.remove()
|
self.sc.remove()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -13,19 +13,21 @@ from pylot.core.util.utils import key_for_set_value, find_in_list, \
|
|||||||
|
|
||||||
|
|
||||||
class Metadata(object):
|
class Metadata(object):
|
||||||
|
|
||||||
def __init__(self, inventory=None):
|
def __init__(self, inventory=None):
|
||||||
self.inventories = []
|
self.inventories = []
|
||||||
# saves read metadata objects (Parser/inventory) for a filename
|
# saves read metadata objects (Parser/inventory) for a filename
|
||||||
self.inventory_files = {}
|
self.inventory_files = {}
|
||||||
# saves filenames holding metadata for a seed_id
|
# saves filenames holding metadata for a seed_id
|
||||||
|
# seed id as key, path to file as value
|
||||||
self.seed_ids = {}
|
self.seed_ids = {}
|
||||||
|
self.stations_dict = {}
|
||||||
if inventory:
|
if inventory:
|
||||||
if os.path.isdir(inventory):
|
if os.path.isdir(inventory):
|
||||||
self.add_inventory(inventory)
|
self.add_inventory(inventory)
|
||||||
if os.path.isfile(inventory):
|
if os.path.isfile(inventory):
|
||||||
self.add_inventory_file(inventory)
|
self.add_inventory_file(inventory)
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
repr = 'PyLoT Metadata object including the following inventories:\n\n'
|
repr = 'PyLoT Metadata object including the following inventories:\n\n'
|
||||||
ntotal = len(self.inventories)
|
ntotal = len(self.inventories)
|
||||||
@ -38,48 +40,40 @@ class Metadata(object):
|
|||||||
repr += '\nTotal of {} inventories. Use Metadata.inventories to see all.'.format(ntotal)
|
repr += '\nTotal of {} inventories. Use Metadata.inventories to see all.'.format(ntotal)
|
||||||
return repr
|
return repr
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.__str__()
|
return self.__str__()
|
||||||
|
|
||||||
|
|
||||||
def add_inventory(self, path_to_inventory):
|
def add_inventory(self, path_to_inventory):
|
||||||
'''
|
"""
|
||||||
add paths to list of inventories
|
Add path to list of inventories.
|
||||||
|
:param path_to_inventory: Path to a folder
|
||||||
:param path_to_inventory:
|
:type path_to_inventory: str
|
||||||
:return:
|
:return: None
|
||||||
'''
|
"""
|
||||||
assert (os.path.isdir(path_to_inventory)), '{} is no directory'.format(path_to_inventory)
|
assert (os.path.isdir(path_to_inventory)), '{} is no directory'.format(path_to_inventory)
|
||||||
if not path_to_inventory in self.inventories:
|
if not path_to_inventory in self.inventories:
|
||||||
self.inventories.append(path_to_inventory)
|
self.inventories.append(path_to_inventory)
|
||||||
|
|
||||||
|
|
||||||
def add_inventory_file(self, path_to_inventory_file):
|
def add_inventory_file(self, path_to_inventory_file):
|
||||||
'''
|
"""
|
||||||
add a single file to inventory files
|
Add the folder in which the file exists to the list of inventories.
|
||||||
|
:param path_to_inventory_file: full path including filename
|
||||||
:param path_to_inventory_file:
|
:type path_to_inventory_file: str
|
||||||
:return:
|
:return: None
|
||||||
|
"""
|
||||||
'''
|
|
||||||
assert (os.path.isfile(path_to_inventory_file)), '{} is no file'.format(path_to_inventory_file)
|
assert (os.path.isfile(path_to_inventory_file)), '{} is no file'.format(path_to_inventory_file)
|
||||||
self.add_inventory(os.path.split(path_to_inventory_file)[0])
|
self.add_inventory(os.path.split(path_to_inventory_file)[0])
|
||||||
if not path_to_inventory_file in self.inventory_files.keys():
|
if not path_to_inventory_file in self.inventory_files.keys():
|
||||||
self.read_single_file(path_to_inventory_file)
|
self.read_single_file(path_to_inventory_file)
|
||||||
|
|
||||||
|
|
||||||
def remove_all_inventories(self):
|
def remove_all_inventories(self):
|
||||||
self.__init__()
|
self.__init__()
|
||||||
|
|
||||||
|
|
||||||
def remove_inventory(self, path_to_inventory):
|
def remove_inventory(self, path_to_inventory):
|
||||||
'''
|
"""
|
||||||
remove a path from inventories list
|
Remove a path from inventories list. If path is not in inventories list, do nothing.
|
||||||
|
:param path_to_inventory: Path to a folder
|
||||||
:param path_to_inventory:
|
"""
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
if not path_to_inventory in self.inventories:
|
if not path_to_inventory in self.inventories:
|
||||||
print('Path {} not in inventories list.'.format(path_to_inventory))
|
print('Path {} not in inventories list.'.format(path_to_inventory))
|
||||||
return
|
return
|
||||||
@ -91,8 +85,23 @@ class Metadata(object):
|
|||||||
if self.seed_ids[seed_id].startswith(path_to_inventory):
|
if self.seed_ids[seed_id].startswith(path_to_inventory):
|
||||||
del (self.seed_ids[seed_id])
|
del (self.seed_ids[seed_id])
|
||||||
|
|
||||||
|
def get_metadata(self, seed_id, time=None):
|
||||||
def get_metadata(self, seed_id):
|
"""
|
||||||
|
Get metadata for seed id at time. When time is not specified, metadata for current time is fetched.
|
||||||
|
:param seed_id: Seed id such as BW.WETR..HHZ (Network.Station.Location.Channel)
|
||||||
|
:type seed_id: str
|
||||||
|
:param time: Time for which the metadata should be returned
|
||||||
|
:type time: UTCDateTime
|
||||||
|
:return: Dictionary with keys data and invtype.
|
||||||
|
data is a obspy.io.xseed.parser.Parser or an obspy.core.inventory.inventory.Inventory depending on the metadata
|
||||||
|
file.
|
||||||
|
invtype is a string denoting of which type the value of the data key is. It can take the values 'dless',
|
||||||
|
'dseed', 'xml', 'resp', according to the filetype of the metadata.
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
|
# try most recent data if no time is specified
|
||||||
|
if not time:
|
||||||
|
time = UTCDateTime()
|
||||||
# get metadata for a specific seed_id, if not already read, try to read from inventories
|
# get metadata for a specific seed_id, if not already read, try to read from inventories
|
||||||
if not seed_id in self.seed_ids.keys():
|
if not seed_id in self.seed_ids.keys():
|
||||||
self._read_inventory_data(seed_id)
|
self._read_inventory_data(seed_id)
|
||||||
@ -100,12 +109,13 @@ class Metadata(object):
|
|||||||
if not seed_id in self.seed_ids.keys():
|
if not seed_id in self.seed_ids.keys():
|
||||||
print('No data found for seed id {}. Trying to find it in all known inventories...'.format(seed_id))
|
print('No data found for seed id {}. Trying to find it in all known inventories...'.format(seed_id))
|
||||||
self.read_all()
|
self.read_all()
|
||||||
for inv_fname, metadata in self.inventory_files.items():
|
for inv_fname, metadata_dict in self.inventory_files.items():
|
||||||
# use get_coordinates to check for seed_id
|
# use get_coordinates to check for seed_id
|
||||||
try:
|
try:
|
||||||
metadata['data'].get_coordinates(seed_id)
|
metadata_dict['data'].get_coordinates(seed_id, time)
|
||||||
self.seed_ids[seed_id] = inv_fname
|
self.seed_ids[seed_id] = inv_fname
|
||||||
return metadata
|
print('Found metadata for station {}!'.format(seed_id))
|
||||||
|
return metadata_dict
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
continue
|
continue
|
||||||
print('Could not find metadata for station {}'.format(seed_id))
|
print('Could not find metadata for station {}'.format(seed_id))
|
||||||
@ -113,30 +123,30 @@ class Metadata(object):
|
|||||||
fname = self.seed_ids[seed_id]
|
fname = self.seed_ids[seed_id]
|
||||||
return self.inventory_files[fname]
|
return self.inventory_files[fname]
|
||||||
|
|
||||||
|
|
||||||
def read_all(self):
|
def read_all(self):
|
||||||
'''
|
"""
|
||||||
read all metadata files found in all inventories
|
Read all metadata files found in all inventories
|
||||||
:return:
|
"""
|
||||||
'''
|
|
||||||
for inventory in self.inventories:
|
for inventory in self.inventories:
|
||||||
for inv_fname in os.listdir(inventory):
|
for inv_fname in os.listdir(inventory):
|
||||||
inv_fname = os.path.join(inventory, inv_fname)
|
inv_fname = os.path.join(inventory, inv_fname)
|
||||||
if not self.read_single_file(inv_fname):
|
if not self.read_single_file(inv_fname):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
def read_single_file(self, inv_fname):
|
def read_single_file(self, inv_fname):
|
||||||
if not inv_fname in self.inventory_files.keys():
|
"""
|
||||||
pass
|
Try to read a single file as Parser/Inventory and add its dictionary to inventory files if reading sudceeded.
|
||||||
else:
|
:param inv_fname: path/filename of inventory file
|
||||||
if not self.inventory_files[inv_fname]:
|
:type inv_fname: str
|
||||||
pass
|
:rtype: None
|
||||||
else:
|
"""
|
||||||
|
# return if it was read already
|
||||||
|
if self.inventory_files.get(inv_fname, None):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
invtype, robj = self._read_metadata_file(inv_fname)
|
invtype, robj = self._read_metadata_file(inv_fname)
|
||||||
if robj == None:
|
if robj is None:
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Could not read file {}'.format(inv_fname))
|
print('Could not read file {}'.format(inv_fname))
|
||||||
@ -145,15 +155,64 @@ class Metadata(object):
|
|||||||
'data': robj}
|
'data': robj}
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_coordinates(self, seed_id, time=None):
|
||||||
def get_coordinates(self, seed_id):
|
"""
|
||||||
metadata = self.get_metadata(seed_id)
|
Get coordinates of given seed id.
|
||||||
|
:param seed_id: Seed id such as BW.WETR..HHZ (Network.Station.Location.Channel)
|
||||||
|
:type seed_id: str
|
||||||
|
:param time: Used when a station has data available at multiple time intervals
|
||||||
|
:type time: UTCDateTime
|
||||||
|
:return: dict containing position information of the station
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
|
# try most recent data if no time is specified
|
||||||
|
if not time:
|
||||||
|
time = UTCDateTime()
|
||||||
|
metadata = self.get_metadata(seed_id, time)
|
||||||
if not metadata:
|
if not metadata:
|
||||||
return
|
return
|
||||||
return metadata['data'].get_coordinates(seed_id)
|
return metadata['data'].get_coordinates(seed_id, time)
|
||||||
|
|
||||||
|
def get_all_coordinates(self):
|
||||||
|
def stat_info_from_parser(parser):
|
||||||
|
for station in parser.stations:
|
||||||
|
station_name = station[0].station_call_letters
|
||||||
|
network_name = station[0].network_code
|
||||||
|
if not station_name in self.stations_dict.keys():
|
||||||
|
st_id = network_name + '.' + station_name
|
||||||
|
self.stations_dict[st_id] = {'latitude': station[0].latitude,
|
||||||
|
'longitude': station[0].longitude}
|
||||||
|
|
||||||
|
def stat_info_from_inventory(inventory):
|
||||||
|
for network in inventory.networks:
|
||||||
|
for station in network.stations:
|
||||||
|
station_name = station.code
|
||||||
|
network_name = network_name.code
|
||||||
|
if not station_name in self.stations_dict.keys():
|
||||||
|
st_id = network_name + '.' + station_name
|
||||||
|
self.stations_dict[st_id] = {'latitude': station[0].latitude,
|
||||||
|
'longitude': station[0].longitude}
|
||||||
|
|
||||||
|
read_stat = {'xml': stat_info_from_inventory,
|
||||||
|
'dless': stat_info_from_parser}
|
||||||
|
|
||||||
|
self.read_all()
|
||||||
|
for item in self.inventory_files.values():
|
||||||
|
inventory = item['data']
|
||||||
|
invtype = item['invtype']
|
||||||
|
read_stat[invtype](inventory)
|
||||||
|
|
||||||
|
return self.stations_dict
|
||||||
|
|
||||||
def get_paz(self, seed_id, time):
|
def get_paz(self, seed_id, time):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param seed_id: Seed id such as BW.WETR..HHZ (Network.Station.Location.Channel)
|
||||||
|
:type seed_id: str
|
||||||
|
:param time: Used when a station has data available at multiple time intervals
|
||||||
|
:type time: UTCDateTime
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
metadata = self.get_metadata(seed_id)
|
metadata = self.get_metadata(seed_id)
|
||||||
if not metadata:
|
if not metadata:
|
||||||
return
|
return
|
||||||
@ -163,18 +222,17 @@ class Metadata(object):
|
|||||||
resp = metadata['data'].get_response(seed_id, time)
|
resp = metadata['data'].get_response(seed_id, time)
|
||||||
return resp.get_paz(seed_id)
|
return resp.get_paz(seed_id)
|
||||||
|
|
||||||
|
|
||||||
def _read_inventory_data(self, seed_id=None):
|
def _read_inventory_data(self, seed_id=None):
|
||||||
for inventory in self.inventories:
|
for inventory in self.inventories:
|
||||||
if self._read_metadata_iterator(path_to_inventory=inventory, station_seed_id=seed_id):
|
if self._read_metadata_iterator(path_to_inventory=inventory, station_seed_id=seed_id):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def _read_metadata_iterator(self, path_to_inventory, station_seed_id):
|
def _read_metadata_iterator(self, path_to_inventory, station_seed_id):
|
||||||
'''
|
"""
|
||||||
search for metadata for a specific station iteratively
|
Search for metadata for a specific station iteratively.
|
||||||
'''
|
"""
|
||||||
station, network, location, channel = station_seed_id.split('.')
|
station, network, location, channel = station_seed_id.split('.')
|
||||||
|
# seach for station seed id in filenames in invetory
|
||||||
fnames = glob.glob(os.path.join(path_to_inventory, '*' + station_seed_id + '*'))
|
fnames = glob.glob(os.path.join(path_to_inventory, '*' + station_seed_id + '*'))
|
||||||
if not fnames:
|
if not fnames:
|
||||||
# search for station name in filename
|
# search for station name in filename
|
||||||
@ -203,13 +261,13 @@ class Metadata(object):
|
|||||||
continue
|
continue
|
||||||
print('Could not find metadata for station_seed_id {} in path {}'.format(station_seed_id, path_to_inventory))
|
print('Could not find metadata for station_seed_id {} in path {}'.format(station_seed_id, path_to_inventory))
|
||||||
|
|
||||||
|
|
||||||
def _read_metadata_file(self, path_to_inventory_filename):
|
def _read_metadata_file(self, path_to_inventory_filename):
|
||||||
'''
|
"""
|
||||||
function reading metadata files (either dataless seed, xml or resp)
|
function reading metadata files (either dataless seed, xml or resp)
|
||||||
:param path_to_inventory_filename:
|
:param path_to_inventory_filename:
|
||||||
:return: file type/ending, inventory object (Parser or Inventory)
|
:return: file type/ending, inventory object (Parser or Inventory)
|
||||||
'''
|
:rtype: (str, obspy.io.xseed.Parser or obspy.core.inventory.inventory.Inventory)
|
||||||
|
"""
|
||||||
# functions used to read metadata for different file endings (or file types)
|
# functions used to read metadata for different file endings (or file types)
|
||||||
read_functions = {'dless': self._read_dless,
|
read_functions = {'dless': self._read_dless,
|
||||||
'dseed': self._read_dless,
|
'dseed': self._read_dless,
|
||||||
@ -228,8 +286,8 @@ class Metadata(object):
|
|||||||
return file_type, robj
|
return file_type, robj
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def _read_dless(self, path_to_inventory):
|
def _read_dless(path_to_inventory):
|
||||||
exc = None
|
exc = None
|
||||||
try:
|
try:
|
||||||
parser = Parser(path_to_inventory)
|
parser = Parser(path_to_inventory)
|
||||||
@ -237,8 +295,8 @@ class Metadata(object):
|
|||||||
parser = None
|
parser = None
|
||||||
return parser, exc
|
return parser, exc
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def _read_inventory_file(self, path_to_inventory):
|
def _read_inventory_file(path_to_inventory):
|
||||||
exc = None
|
exc = None
|
||||||
try:
|
try:
|
||||||
inv = read_inventory(path_to_inventory)
|
inv = read_inventory(path_to_inventory)
|
||||||
@ -247,7 +305,6 @@ class Metadata(object):
|
|||||||
return inv, exc
|
return inv, exc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def time_from_header(header):
|
def time_from_header(header):
|
||||||
"""
|
"""
|
||||||
Function takes in the second line from a .gse file and takes out the date and time from that line.
|
Function takes in the second line from a .gse file and takes out the date and time from that line.
|
||||||
@ -458,15 +515,22 @@ def read_metadata(path_to_inventory):
|
|||||||
# return metadata_objects
|
# return metadata_objects
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def restitute_trace(input_tuple):
|
def restitute_trace(input_tuple):
|
||||||
|
def no_metadata(tr, seed_id):
|
||||||
|
print('no metadata file found '
|
||||||
|
'for trace {0}'.format(seed_id))
|
||||||
|
return tr, True
|
||||||
|
|
||||||
tr, metadata, unit, force = input_tuple
|
tr, metadata, unit, force = input_tuple
|
||||||
|
|
||||||
remove_trace = False
|
remove_trace = False
|
||||||
|
|
||||||
seed_id = tr.get_id()
|
seed_id = tr.get_id()
|
||||||
|
|
||||||
mdata = metadata.get_metadata(seed_id)
|
mdata = metadata.get_metadata(seed_id, time=tr.stats.starttime)
|
||||||
|
if not mdata:
|
||||||
|
return no_metadata(tr, seed_id)
|
||||||
|
|
||||||
invtype = mdata['invtype']
|
invtype = mdata['invtype']
|
||||||
inobj = mdata['data']
|
inobj = mdata['data']
|
||||||
|
|
||||||
@ -481,8 +545,7 @@ def restitute_trace(input_tuple):
|
|||||||
if invtype == 'resp':
|
if invtype == 'resp':
|
||||||
fresp = find_in_list(inobj, seed_id)
|
fresp = find_in_list(inobj, seed_id)
|
||||||
if not fresp:
|
if not fresp:
|
||||||
raise IOError('no response file found '
|
return no_metadata(tr, seed_id)
|
||||||
'for trace {0}'.format(seed_id))
|
|
||||||
fname = fresp
|
fname = fresp
|
||||||
seedresp = dict(filename=fname,
|
seedresp = dict(filename=fname,
|
||||||
date=stime,
|
date=stime,
|
||||||
@ -504,9 +567,8 @@ def restitute_trace(input_tuple):
|
|||||||
else:
|
else:
|
||||||
finv = invlist[0]
|
finv = invlist[0]
|
||||||
inventory = read_inventory(finv, format='STATIONXML')
|
inventory = read_inventory(finv, format='STATIONXML')
|
||||||
elif invtype == None:
|
elif invtype is None:
|
||||||
print("No restitution possible, as there are no station-meta data available!")
|
return no_metadata(tr, seed_id)
|
||||||
return tr, True
|
|
||||||
else:
|
else:
|
||||||
remove_trace = True
|
remove_trace = True
|
||||||
# apply restitution to data
|
# apply restitution to data
|
||||||
@ -542,9 +604,6 @@ def restitute_data(data, metadata, unit='VEL', force=False, ncores=0):
|
|||||||
takes a data stream and a path_to_inventory and returns the corrected
|
takes a data stream and a path_to_inventory and returns the corrected
|
||||||
waveform data stream
|
waveform data stream
|
||||||
:param data: seismic data stream
|
:param data: seismic data stream
|
||||||
:param invtype: type of found metadata
|
|
||||||
:param inobj: either list of metadata files or `obspy.io.xseed.Parser`
|
|
||||||
object
|
|
||||||
:param unit: unit to correct for (default: 'VEL')
|
:param unit: unit to correct for (default: 'VEL')
|
||||||
:param force: force restitution for already corrected traces (default:
|
:param force: force restitution for already corrected traces (default:
|
||||||
False)
|
False)
|
||||||
@ -553,7 +612,7 @@ def restitute_data(data, metadata, unit='VEL', force=False, ncores=0):
|
|||||||
|
|
||||||
restflag = list()
|
restflag = list()
|
||||||
|
|
||||||
data = remove_underscores(data)
|
#data = remove_underscores(data)
|
||||||
|
|
||||||
# loop over traces
|
# loop over traces
|
||||||
input_tuples = []
|
input_tuples = []
|
||||||
@ -562,7 +621,7 @@ def restitute_data(data, metadata, unit='VEL', force=False, ncores=0):
|
|||||||
data.remove(tr)
|
data.remove(tr)
|
||||||
|
|
||||||
pool = gen_Pool(ncores)
|
pool = gen_Pool(ncores)
|
||||||
result = pool.map(restitute_trace, input_tuples)
|
result = pool.imap_unordered(restitute_trace, input_tuples)
|
||||||
pool.close()
|
pool.close()
|
||||||
|
|
||||||
for tr, remove_trace in result:
|
for tr, remove_trace in result:
|
||||||
@ -612,7 +671,7 @@ def get_prefilt(trace, tlow=(0.5, 0.9), thi=(5., 2.), verbosity=0):
|
|||||||
fny = trace.stats.sampling_rate / 2
|
fny = trace.stats.sampling_rate / 2
|
||||||
fc21 = fny - (fny * thi[0] / 100.)
|
fc21 = fny - (fny * thi[0] / 100.)
|
||||||
fc22 = fny - (fny * thi[1] / 100.)
|
fc22 = fny - (fny * thi[1] / 100.)
|
||||||
return (tlow[0], tlow[1], fc21, fc22)
|
return tlow[0], tlow[1], fc21, fc22
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -16,7 +16,6 @@ from pylot.core.loc import hyposat
|
|||||||
from pylot.core.loc import nll
|
from pylot.core.loc import nll
|
||||||
from pylot.core.loc import velest
|
from pylot.core.loc import velest
|
||||||
|
|
||||||
|
|
||||||
# determine system dependent path separator
|
# determine system dependent path separator
|
||||||
system_name = platform.system()
|
system_name = platform.system()
|
||||||
if system_name in ["Linux", "Darwin"]:
|
if system_name in ["Linux", "Darwin"]:
|
||||||
@ -42,54 +41,3 @@ OUTPUTFORMATS = {'.xml': 'QUAKEML',
|
|||||||
LOCTOOLS = dict(nll=nll, hyposat=hyposat, velest=velest, hypo71=hypo71, hypodd=hypodd)
|
LOCTOOLS = dict(nll=nll, hyposat=hyposat, velest=velest, hypo71=hypo71, hypodd=hypodd)
|
||||||
|
|
||||||
|
|
||||||
class SetChannelComponents(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.setDefaultCompPosition()
|
|
||||||
|
|
||||||
def setDefaultCompPosition(self):
|
|
||||||
# default component order
|
|
||||||
self.compPosition_Map = dict(Z=2, N=1, E=0)
|
|
||||||
self.compName_Map = {'3': 'Z',
|
|
||||||
'1': 'N',
|
|
||||||
'2': 'E'}
|
|
||||||
|
|
||||||
def _getCurrentPosition(self, component):
|
|
||||||
for key, value in self.compName_Map.items():
|
|
||||||
if value == component:
|
|
||||||
return key, value
|
|
||||||
errMsg = 'getCurrentPosition: Could not find former position of component {}.'.format(component)
|
|
||||||
raise ValueError(errMsg)
|
|
||||||
|
|
||||||
def _switch(self, component, component_alter):
|
|
||||||
# Without switching, multiple definitions of the same alter_comp are possible
|
|
||||||
old_alter_comp, _ = self._getCurrentPosition(component)
|
|
||||||
old_comp = self.compName_Map[component_alter]
|
|
||||||
if not old_alter_comp == component_alter and not old_comp == component:
|
|
||||||
self.compName_Map[old_alter_comp] = old_comp
|
|
||||||
print('switch: Automatically switched component {} to {}'.format(old_alter_comp, old_comp))
|
|
||||||
|
|
||||||
def setCompPosition(self, component_alter, component, switch=True):
|
|
||||||
component_alter = str(component_alter)
|
|
||||||
if not component_alter in self.compName_Map.keys():
|
|
||||||
errMsg = 'setCompPosition: Unrecognized alternative component {}. Expecting one of {}.'
|
|
||||||
raise ValueError(errMsg.format(component_alter, self.compName_Map.keys()))
|
|
||||||
if not component in self.compPosition_Map.keys():
|
|
||||||
errMsg = 'setCompPosition: Unrecognized target component {}. Expecting one of {}.'
|
|
||||||
raise ValueError(errMsg.format(component, self.compPosition_Map.keys()))
|
|
||||||
print('setCompPosition: set component {} to {}'.format(component_alter, component))
|
|
||||||
if switch:
|
|
||||||
self._switch(component, component_alter)
|
|
||||||
self.compName_Map[component_alter] = component
|
|
||||||
|
|
||||||
def getCompPosition(self, component):
|
|
||||||
return self._getCurrentPosition(component)[0]
|
|
||||||
|
|
||||||
def getPlotPosition(self, component):
|
|
||||||
component = str(component)
|
|
||||||
if component in self.compPosition_Map.keys():
|
|
||||||
return self.compPosition_Map[component]
|
|
||||||
elif component in self.compName_Map.keys():
|
|
||||||
return self.compPosition_Map[self.compName_Map[component]]
|
|
||||||
else:
|
|
||||||
errMsg = 'getCompPosition: Unrecognized component {}. Expecting one of {} or {}.'
|
|
||||||
raise ValueError(errMsg.format(component, self.compPosition_Map.keys(), self.compName_Map.keys()))
|
|
||||||
|
@ -35,6 +35,7 @@ class Event(ObsPyEvent):
|
|||||||
self._refEvent = False
|
self._refEvent = False
|
||||||
self.get_notes()
|
self.get_notes()
|
||||||
self.get_obspy_event_info()
|
self.get_obspy_event_info()
|
||||||
|
self.dirty = False
|
||||||
|
|
||||||
def get_notes_path(self):
|
def get_notes_path(self):
|
||||||
"""
|
"""
|
||||||
@ -143,6 +144,7 @@ class Event(ObsPyEvent):
|
|||||||
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)
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
def addPicks(self, picks):
|
def addPicks(self, picks):
|
||||||
"""
|
"""
|
||||||
@ -157,12 +159,12 @@ class Event(ObsPyEvent):
|
|||||||
# 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)
|
||||||
self.clearObsPyPicks('manual')
|
self.clearObsPyPicks('manual')
|
||||||
self.picks += picks_from_picksdict(self.pylot_picks)
|
self.picks += picks_from_picksdict(self.pylot_picks)
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
def addAutopicks(self, autopicks):
|
def addAutopicks(self, autopicks):
|
||||||
"""
|
"""
|
||||||
Add automatic picks to event
|
Add automatic picks to event
|
||||||
:param autopicks: automatic picks to add to event
|
:param autopicks: automatic picks to add to event
|
||||||
:type autopicks dict:
|
|
||||||
:return:
|
:return:
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
@ -171,6 +173,7 @@ class Event(ObsPyEvent):
|
|||||||
# 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)
|
||||||
self.clearObsPyPicks('auto')
|
self.clearObsPyPicks('auto')
|
||||||
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
def setPick(self, station, pick):
|
def setPick(self, station, pick):
|
||||||
"""
|
"""
|
||||||
@ -186,11 +189,13 @@ class Event(ObsPyEvent):
|
|||||||
self.pylot_picks[station] = pick
|
self.pylot_picks[station] = pick
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
if station in self.pylot_picks:
|
||||||
self.pylot_picks.pop(station)
|
self.pylot_picks.pop(station)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Could not remove pick {} from station {}: {}'.format(pick, station, e))
|
print('Could not remove pick {} from station {}: {}'.format(pick, station, e))
|
||||||
self.clearObsPyPicks('manual')
|
self.clearObsPyPicks('manual')
|
||||||
self.picks += picks_from_picksdict(self.pylot_picks)
|
self.picks += picks_from_picksdict(self.pylot_picks)
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
def setPicks(self, picks):
|
def setPicks(self, picks):
|
||||||
"""
|
"""
|
||||||
@ -203,6 +208,7 @@ class Event(ObsPyEvent):
|
|||||||
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)
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
def getPick(self, station):
|
def getPick(self, station):
|
||||||
"""
|
"""
|
||||||
@ -237,11 +243,13 @@ class Event(ObsPyEvent):
|
|||||||
self.pylot_autopicks[station] = pick
|
self.pylot_autopicks[station] = pick
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
if station in self.pylot_autopicks:
|
||||||
self.pylot_autopicks.pop(station)
|
self.pylot_autopicks.pop(station)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Could not remove pick {} from station {}: {}'.format(pick, station, e))
|
print('Could not remove pick {} from station {}: {}'.format(pick, station, e))
|
||||||
self.clearObsPyPicks('auto')
|
self.clearObsPyPicks('auto')
|
||||||
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
def setAutopicks(self, picks):
|
def setAutopicks(self, picks):
|
||||||
"""
|
"""
|
||||||
@ -254,6 +262,7 @@ class Event(ObsPyEvent):
|
|||||||
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)
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
def getAutopick(self, station):
|
def getAutopick(self, station):
|
||||||
"""
|
"""
|
||||||
@ -292,6 +301,7 @@ class Event(ObsPyEvent):
|
|||||||
try:
|
try:
|
||||||
outfile = open(filename, 'wb')
|
outfile = open(filename, 'wb')
|
||||||
cPickle.dump(self, outfile, -1)
|
cPickle.dump(self, outfile, -1)
|
||||||
|
self.dirty = False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Could not pickle PyLoT event. Reason: {}'.format(e))
|
print('Could not pickle PyLoT event. Reason: {}'.format(e))
|
||||||
|
|
||||||
@ -310,5 +320,6 @@ class Event(ObsPyEvent):
|
|||||||
import _pickle as cPickle
|
import _pickle as cPickle
|
||||||
infile = open(filename, 'rb')
|
infile = open(filename, 'rb')
|
||||||
event = cPickle.load(infile)
|
event = cPickle.load(infile)
|
||||||
|
event.dirty = False
|
||||||
print('Loaded %s' % filename)
|
print('Loaded %s' % filename)
|
||||||
return event
|
return event
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import os
|
import os
|
||||||
from obspy import UTCDateTime
|
from obspy import UTCDateTime
|
||||||
|
|
||||||
|
|
||||||
def check_obspydmt_structure(path):
|
def check_obspydmt_structure(path):
|
||||||
'''
|
'''
|
||||||
Check path for obspyDMT event structure.
|
Check path for obspyDMT event structure.
|
||||||
@ -16,6 +17,7 @@ def check_obspydmt_structure(path):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def check_obspydmt_eventfolder(folder):
|
def check_obspydmt_eventfolder(folder):
|
||||||
try:
|
try:
|
||||||
time = folder.split('.')[0]
|
time = folder.split('.')[0]
|
||||||
@ -25,6 +27,7 @@ def check_obspydmt_eventfolder(folder):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return False, e
|
return False, e
|
||||||
|
|
||||||
|
|
||||||
def qml_from_obspyDMT(path):
|
def qml_from_obspyDMT(path):
|
||||||
import pickle
|
import pickle
|
||||||
from obspy.core.event import Event, Magnitude, Origin
|
from obspy.core.event import Event, Magnitude, Origin
|
||||||
@ -41,4 +44,3 @@ def qml_from_obspyDMT(path):
|
|||||||
ev.magnitudes.append(mag)
|
ev.magnitudes.append(mag)
|
||||||
ev.origins.append(origin)
|
ev.origins.append(origin)
|
||||||
return ev
|
return ev
|
||||||
|
|
||||||
|
@ -41,23 +41,13 @@ class Thread(QThread):
|
|||||||
def showProgressbar(self):
|
def showProgressbar(self):
|
||||||
if self.progressText:
|
if self.progressText:
|
||||||
|
|
||||||
# generate widget if not given in init
|
# # generate widget if not given in init
|
||||||
if not self.pb_widget:
|
# if not self.pb_widget:
|
||||||
self.pb_widget = QDialog(self.parent())
|
# self.pb_widget = ProgressBarWidget(self.parent())
|
||||||
self.pb_widget.setWindowFlags(Qt.SplashScreen)
|
# self.pb_widget.setWindowFlags(Qt.SplashScreen)
|
||||||
self.pb_widget.setModal(True)
|
# self.pb_widget.setModal(True)
|
||||||
|
|
||||||
# add button
|
self.pb_widget.label.setText(self.progressText)
|
||||||
delete_button = QPushButton('X')
|
|
||||||
delete_button.clicked.connect(self.exit)
|
|
||||||
hl = QHBoxLayout()
|
|
||||||
pb = QProgressBar()
|
|
||||||
pb.setRange(0, 0)
|
|
||||||
hl.addWidget(pb)
|
|
||||||
hl.addWidget(QLabel(self.progressText))
|
|
||||||
if self.abortButton:
|
|
||||||
hl.addWidget(delete_button)
|
|
||||||
self.pb_widget.setLayout(hl)
|
|
||||||
self.pb_widget.show()
|
self.pb_widget.show()
|
||||||
|
|
||||||
def hideProgressbar(self):
|
def hideProgressbar(self):
|
||||||
@ -75,6 +65,7 @@ class Worker(QRunnable):
|
|||||||
'''
|
'''
|
||||||
Worker class to be run by MultiThread(QThread).
|
Worker class to be run by MultiThread(QThread).
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, fun, args,
|
def __init__(self, fun, args,
|
||||||
progressText=None,
|
progressText=None,
|
||||||
pb_widget=None,
|
pb_widget=None,
|
||||||
|
@ -22,11 +22,7 @@ from pylot.styles import style_settings
|
|||||||
from scipy.interpolate import splrep, splev
|
from scipy.interpolate import splrep, splev
|
||||||
from PySide import QtCore, QtGui
|
from PySide import QtCore, QtGui
|
||||||
|
|
||||||
try:
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
except Exception as e:
|
|
||||||
print('PyLoT: Could not import pyqtgraph. {}'.format(e))
|
|
||||||
pg = None
|
|
||||||
|
|
||||||
def _pickle_method(m):
|
def _pickle_method(m):
|
||||||
if m.im_self is None:
|
if m.im_self is None:
|
||||||
@ -34,6 +30,7 @@ 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):
|
def getAutoFilteroptions(phase, parameter):
|
||||||
filtername = {'P': 'bpz2',
|
filtername = {'P': 'bpz2',
|
||||||
'S': 'bph2'}
|
'S': 'bph2'}
|
||||||
@ -44,6 +41,7 @@ def getAutoFilteroptions(phase, parameter):
|
|||||||
filteroptions = FilterOptions(type='bandpass', freq=[freqmin, freqmax], order=4) # order=4 default from obspy
|
filteroptions = FilterOptions(type='bandpass', freq=[freqmin, freqmax], order=4) # order=4 default from obspy
|
||||||
return filteroptions
|
return filteroptions
|
||||||
|
|
||||||
|
|
||||||
def readDefaultFilterInformation(fname):
|
def readDefaultFilterInformation(fname):
|
||||||
"""
|
"""
|
||||||
Read default filter information from pylot.in file
|
Read default filter information from pylot.in file
|
||||||
@ -118,8 +116,12 @@ def gen_Pool(ncores=0):
|
|||||||
"""
|
"""
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
|
||||||
if ncores == 0:
|
ncores_max = multiprocessing.cpu_count()
|
||||||
ncores = multiprocessing.cpu_count()
|
|
||||||
|
if ncores == 0 or ncores > ncores_max:
|
||||||
|
ncores = ncores_max
|
||||||
|
if ncores > ncores_max:
|
||||||
|
print('Reduced number of requested CPU slots to available number: {}'.format(ncores))
|
||||||
|
|
||||||
print('gen_Pool: Generated multiprocessing Pool with {} cores\n'.format(ncores))
|
print('gen_Pool: Generated multiprocessing Pool with {} cores\n'.format(ncores))
|
||||||
|
|
||||||
@ -397,6 +399,10 @@ def full_range(stream):
|
|||||||
:return: minimum start time and maximum end time
|
:return: minimum start time and maximum end time
|
||||||
:rtype: (`~maximum start time and minimum end time`, maximum start time and minimum end time)
|
:rtype: (`~maximum start time and minimum end time`, maximum start time and minimum end time)
|
||||||
"""
|
"""
|
||||||
|
if not stream:
|
||||||
|
print('full_range: Empty Stream!')
|
||||||
|
return None, None
|
||||||
|
|
||||||
min_start = min([trace.stats.starttime for trace in stream])
|
min_start = min([trace.stats.starttime for trace in stream])
|
||||||
max_end = max([trace.stats.endtime for trace in stream])
|
max_end = max([trace.stats.endtime for trace in stream])
|
||||||
|
|
||||||
@ -537,7 +543,7 @@ def isSorted(iterable):
|
|||||||
False
|
False
|
||||||
"""
|
"""
|
||||||
assert isIterable(iterable), 'object is not iterable; object: {' \
|
assert isIterable(iterable), 'object is not iterable; object: {' \
|
||||||
'0}'.format(iterable)
|
'}'.format(iterable)
|
||||||
if type(iterable) is str:
|
if type(iterable) is str:
|
||||||
iterable = [s for s in iterable]
|
iterable = [s for s in iterable]
|
||||||
return sorted(iterable) == iterable
|
return sorted(iterable) == iterable
|
||||||
@ -787,6 +793,7 @@ def base_phase_colors(picktype, phase):
|
|||||||
phasecolors = style_settings.phasecolors
|
phasecolors = style_settings.phasecolors
|
||||||
return phasecolors[picktype][phase]
|
return phasecolors[picktype][phase]
|
||||||
|
|
||||||
|
|
||||||
def transform_colors_mpl_str(colors, no_alpha=False):
|
def transform_colors_mpl_str(colors, no_alpha=False):
|
||||||
"""
|
"""
|
||||||
Transforms rgba color values to a matplotlib string of color values with a range of [0, 1]
|
Transforms rgba color values to a matplotlib string of color values with a range of [0, 1]
|
||||||
@ -805,6 +812,7 @@ def transform_colors_mpl_str(colors, no_alpha=False):
|
|||||||
colors_mpl = '({}, {}, {}, {})'.format(*colors_mpl)
|
colors_mpl = '({}, {}, {}, {})'.format(*colors_mpl)
|
||||||
return colors_mpl
|
return colors_mpl
|
||||||
|
|
||||||
|
|
||||||
def transform_colors_mpl(colors):
|
def transform_colors_mpl(colors):
|
||||||
"""
|
"""
|
||||||
Transform rgba colors from [0, 255] to [0, 1]
|
Transform rgba colors from [0, 255] to [0, 1]
|
||||||
@ -817,6 +825,7 @@ def transform_colors_mpl(colors):
|
|||||||
colors_mpl = tuple([color / 255. for color in colors])
|
colors_mpl = tuple([color / 255. for color in colors])
|
||||||
return colors_mpl
|
return colors_mpl
|
||||||
|
|
||||||
|
|
||||||
def remove_underscores(data):
|
def remove_underscores(data):
|
||||||
"""
|
"""
|
||||||
takes a `obspy.core.stream.Stream` object and removes all underscores
|
takes a `obspy.core.stream.Stream` object and removes all underscores
|
||||||
@ -826,9 +835,9 @@ def remove_underscores(data):
|
|||||||
:return: data stream
|
:return: data stream
|
||||||
:rtype: `~obspy.core.stream.Stream`
|
:rtype: `~obspy.core.stream.Stream`
|
||||||
"""
|
"""
|
||||||
for tr in data:
|
#for tr in data:
|
||||||
# remove underscores
|
# # remove underscores
|
||||||
tr.stats.station = tr.stats.station.strip('_')
|
# tr.stats.station = tr.stats.station.strip('_')
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@ -926,7 +935,10 @@ def get_stations(data):
|
|||||||
|
|
||||||
def check4rotated(data, metadata=None, verbosity=1):
|
def check4rotated(data, metadata=None, verbosity=1):
|
||||||
"""
|
"""
|
||||||
|
Check all traces in data. If a trace is not in ZNE rotation (last symbol of channel code is numeric) and the trace
|
||||||
|
is in the metadata with azimuth and dip, rotate it to classical ZNE orientation.
|
||||||
|
Rotating the traces requires them to be of the same length, so, all traces will be trimmed to a common length as a
|
||||||
|
side effect.
|
||||||
:param data: stream object containing seismic traces
|
:param data: stream object containing seismic traces
|
||||||
:type data: `~obspy.core.stream.Stream`
|
:type data: `~obspy.core.stream.Stream`
|
||||||
:param metadata: tuple containing metadata type string and metadata parser object
|
:param metadata: tuple containing metadata type string and metadata parser object
|
||||||
@ -943,86 +955,44 @@ def check4rotated(data, metadata=None, verbosity=1):
|
|||||||
|
|
||||||
Azimut and dip are fetched from metadata. To be rotated, traces of a station have to be cut to the same length.
|
Azimut and dip are fetched from metadata. To be rotated, traces of a station have to be cut to the same length.
|
||||||
Returns unrotated traces of no metadata is provided
|
Returns unrotated traces of no metadata is provided
|
||||||
:param wfstream: stream containing seismic traces
|
:param wfstream: stream containing seismic traces of a station
|
||||||
:type wfstream: `~obspy.core.stream.Stream`
|
:type wfstream: `~obspy.core.stream.Stream`
|
||||||
:param metadata: tuple containing metadata type string and metadata parser object
|
:param metadata: tuple containing metadata type string and metadata parser object
|
||||||
:type metadata: (str, `~obspy.io.xseed.parser.Parser`)
|
:type metadata: (str, `~obspy.io.xseed.parser.Parser`)
|
||||||
:return: stream object with traditionally oriented traces (ZNE)
|
:return: stream object with traditionally oriented traces (ZNE)
|
||||||
:rtype: `~obspy.core.stream.Stream`
|
:rtype: `~obspy.core.stream.Stream`
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
# indexing fails if metadata is None
|
|
||||||
metadata[0]
|
|
||||||
except TypeError:
|
|
||||||
if verbosity:
|
|
||||||
msg = 'Warning: could not rotate traces since no metadata was given\nset Inventory file!'
|
|
||||||
print(msg)
|
|
||||||
return wfstream
|
|
||||||
if metadata[0] is None:
|
|
||||||
# sometimes metadata is (None, (None,))
|
|
||||||
if verbosity:
|
|
||||||
msg = 'Warning: could not rotate traces since no metadata was given\nCheck inventory directory!'
|
|
||||||
print(msg)
|
|
||||||
return wfstream
|
|
||||||
else:
|
|
||||||
parser = metadata[1]
|
|
||||||
|
|
||||||
def get_dip_azimut(parser, trace_id):
|
|
||||||
"""
|
|
||||||
Gets azimuth and dip by trace id out of the metadata parser
|
|
||||||
:param parser: metadata parser object
|
|
||||||
:type parser: `~obspy.io.xseed.parser.Parser`
|
|
||||||
:param trace_id: eg. 'BW.RJOB..EHZ',
|
|
||||||
:type trace_id: str
|
|
||||||
:return: tuple containing dip and azimuth of the trace corresponding to trace_id
|
|
||||||
:rtype: (float, float)
|
|
||||||
"""
|
|
||||||
dip = None
|
|
||||||
azimut = None
|
|
||||||
try:
|
|
||||||
blockettes = parser._select(trace_id)
|
|
||||||
except SEEDParserException as e:
|
|
||||||
print(e)
|
|
||||||
raise ValueError
|
|
||||||
for blockette_ in blockettes:
|
|
||||||
if blockette_.id != 52:
|
|
||||||
continue
|
|
||||||
dip = blockette_.dip
|
|
||||||
azimut = blockette_.azimuth
|
|
||||||
break
|
|
||||||
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
|
|
||||||
|
|
||||||
|
# check if any traces in this station need to be rotated
|
||||||
trace_ids = [trace.id for trace in wfstream]
|
trace_ids = [trace.id for trace in wfstream]
|
||||||
for trace_id in trace_ids:
|
orientations = [trace_id[-1] for trace_id in trace_ids]
|
||||||
orientation = trace_id[-1] # last letter if trace id is orientation code, ZNE or 123
|
rotation_required = [orientation.isnumeric() for orientation in orientations]
|
||||||
if orientation.isnumeric():
|
if any(rotation_required):
|
||||||
# misaligned channels have a number as orientation
|
t_start = full_range(wfstream)
|
||||||
azimuts = []
|
|
||||||
dips = []
|
|
||||||
for trace_id in trace_ids:
|
|
||||||
try:
|
try:
|
||||||
dip, azimut = get_dip_azimut(parser, trace_id)
|
azimuts = [metadata.get_coordinates(tr_id, t_start)['azimuth'] for tr_id in trace_ids]
|
||||||
except ValueError as e:
|
dips = [metadata.get_coordinates(tr_id, t_start)['dip'] for tr_id in trace_ids]
|
||||||
print(e)
|
except (KeyError, TypeError) as e:
|
||||||
print('Failed to rotate station {}, no azimuth or dip available in metadata'.format(trace_id))
|
print('Failed to rotate trace {}, no azimuth or dip available in metadata'.format(trace_id))
|
||||||
return wfstream
|
return wfstream
|
||||||
azimuts.append(azimut)
|
if len(wfstream) < 3:
|
||||||
dips.append(dip)
|
print('Failed to rotate Stream {}, not enough components available.'.format(wfstream))
|
||||||
# to rotate all traces must have same length
|
return wfstream
|
||||||
|
# to rotate all traces must have same length, so trim them
|
||||||
wfstream = trim_station_components(wfstream, trim_start=True, trim_end=True)
|
wfstream = trim_station_components(wfstream, trim_start=True, trim_end=True)
|
||||||
z, n, e = rotate2zne(wfstream[0], azimuts[0], dips[0],
|
z, n, e = rotate2zne(wfstream[0], azimuts[0], dips[0],
|
||||||
wfstream[1], azimuts[1], dips[1],
|
wfstream[1], azimuts[1], dips[1],
|
||||||
wfstream[2], azimuts[2], dips[2])
|
wfstream[2], azimuts[2], dips[2])
|
||||||
print('check4rotated: rotated station {} to ZNE'.format(trace_id))
|
print('check4rotated: rotated trace {} to ZNE'.format(trace_id))
|
||||||
z_index = dips.index(min(dips)) # get z-trace index (dip is measured from 0 to -90)
|
# replace old data with rotated data, change the channel code to ZNE
|
||||||
|
z_index = dips.index(min(
|
||||||
|
dips)) # get z-trace index, z has minimum dip of -90 (dip is measured from 0 to -90, with -90 being vertical)
|
||||||
wfstream[z_index].data = z
|
wfstream[z_index].data = z
|
||||||
wfstream[z_index].stats.channel = wfstream[z_index].stats.channel[0:-1] + 'Z'
|
wfstream[z_index].stats.channel = wfstream[z_index].stats.channel[0:-1] + 'Z'
|
||||||
del trace_ids[z_index]
|
del trace_ids[z_index]
|
||||||
for trace_id in trace_ids:
|
for trace_id in trace_ids:
|
||||||
dip, az = get_dip_azimut(parser, trace_id)
|
coordinates = metadata.get_coordinates(trace_id, t_start)
|
||||||
|
dip, az = coordinates['dip'], coordinates['azimuth']
|
||||||
trace = wfstream.select(id=trace_id)[0]
|
trace = wfstream.select(id=trace_id)[0]
|
||||||
if az > 315 or az <= 45 or az > 135 and az <= 225:
|
if az > 315 or az <= 45 or az > 135 and az <= 225:
|
||||||
trace.data = n
|
trace.data = n
|
||||||
@ -1030,13 +1000,14 @@ def check4rotated(data, metadata=None, verbosity=1):
|
|||||||
elif az > 45 and az <= 135 or az > 225 and az <= 315:
|
elif az > 45 and az <= 135 or az > 225 and az <= 315:
|
||||||
trace.data = e
|
trace.data = e
|
||||||
trace.stats.channel = trace.stats.channel[0:-1] + 'E'
|
trace.stats.channel = trace.stats.channel[0:-1] + 'E'
|
||||||
break
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
return wfstream
|
return wfstream
|
||||||
|
|
||||||
|
if metadata is None:
|
||||||
|
if verbosity:
|
||||||
|
msg = 'Warning: could not rotate traces since no metadata was given\nset Inventory file!'
|
||||||
|
print(msg)
|
||||||
|
return data
|
||||||
stations = get_stations(data)
|
stations = get_stations(data)
|
||||||
|
|
||||||
for station in stations: # loop through all stations and rotate data if neccessary
|
for station in stations: # loop through all stations and rotate data if neccessary
|
||||||
wf_station = data.select(station=station)
|
wf_station = data.select(station=station)
|
||||||
rotate_components(wf_station, metadata)
|
rotate_components(wf_station, metadata)
|
||||||
@ -1149,7 +1120,7 @@ def loopIdentifyPhase(phase):
|
|||||||
"""
|
"""
|
||||||
from pylot.core.util.defaults import ALTSUFFIX
|
from pylot.core.util.defaults import ALTSUFFIX
|
||||||
|
|
||||||
if phase == None:
|
if phase is None:
|
||||||
raise NameError('Can not identify phase that is None')
|
raise NameError('Can not identify phase that is None')
|
||||||
|
|
||||||
phase_copy = phase
|
phase_copy = phase
|
||||||
@ -1199,20 +1170,6 @@ def identifyPhaseID(phase):
|
|||||||
return identifyPhase(loopIdentifyPhase(phase))
|
return identifyPhase(loopIdentifyPhase(phase))
|
||||||
|
|
||||||
|
|
||||||
def has_spe(pick):
|
|
||||||
"""
|
|
||||||
Check for 'spe' key (symmetric picking error) in dict and return its value if found, else return None
|
|
||||||
:param pick: pick dictionary
|
|
||||||
:type pick: dict
|
|
||||||
:return: value of 'spe' key
|
|
||||||
:rtype: float or None
|
|
||||||
"""
|
|
||||||
if not 'spe' in pick.keys():
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return pick['spe']
|
|
||||||
|
|
||||||
|
|
||||||
def check_all_obspy(eventlist):
|
def check_all_obspy(eventlist):
|
||||||
ev_type = 'obspydmt'
|
ev_type = 'obspydmt'
|
||||||
return check_event_folders(eventlist, ev_type)
|
return check_event_folders(eventlist, ev_type)
|
||||||
@ -1276,3 +1233,56 @@ if __name__ == "__main__":
|
|||||||
import doctest
|
import doctest
|
||||||
|
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
|
||||||
|
|
||||||
|
class SetChannelComponents(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.setDefaultCompPosition()
|
||||||
|
|
||||||
|
def setDefaultCompPosition(self):
|
||||||
|
# default component order
|
||||||
|
self.compPosition_Map = dict(Z=2, N=1, E=0)
|
||||||
|
self.compName_Map = {'3': 'Z',
|
||||||
|
'1': 'N',
|
||||||
|
'2': 'E'}
|
||||||
|
|
||||||
|
def _getCurrentPosition(self, component):
|
||||||
|
for key, value in self.compName_Map.items():
|
||||||
|
if value == component:
|
||||||
|
return key, value
|
||||||
|
errMsg = 'getCurrentPosition: Could not find former position of component {}.'.format(component)
|
||||||
|
raise ValueError(errMsg)
|
||||||
|
|
||||||
|
def _switch(self, component, component_alter):
|
||||||
|
# Without switching, multiple definitions of the same alter_comp are possible
|
||||||
|
old_alter_comp, _ = self._getCurrentPosition(component)
|
||||||
|
old_comp = self.compName_Map[component_alter]
|
||||||
|
if not old_alter_comp == component_alter and not old_comp == component:
|
||||||
|
self.compName_Map[old_alter_comp] = old_comp
|
||||||
|
print('switch: Automatically switched component {} to {}'.format(old_alter_comp, old_comp))
|
||||||
|
|
||||||
|
def setCompPosition(self, component_alter, component, switch=True):
|
||||||
|
component_alter = str(component_alter)
|
||||||
|
if not component_alter in self.compName_Map.keys():
|
||||||
|
errMsg = 'setCompPosition: Unrecognized alternative component {}. Expecting one of {}.'
|
||||||
|
raise ValueError(errMsg.format(component_alter, self.compName_Map.keys()))
|
||||||
|
if not component in self.compPosition_Map.keys():
|
||||||
|
errMsg = 'setCompPosition: Unrecognized target component {}. Expecting one of {}.'
|
||||||
|
raise ValueError(errMsg.format(component, self.compPosition_Map.keys()))
|
||||||
|
print('setCompPosition: set component {} to {}'.format(component_alter, component))
|
||||||
|
if switch:
|
||||||
|
self._switch(component, component_alter)
|
||||||
|
self.compName_Map[component_alter] = component
|
||||||
|
|
||||||
|
def getCompPosition(self, component):
|
||||||
|
return self._getCurrentPosition(component)[0]
|
||||||
|
|
||||||
|
def getPlotPosition(self, component):
|
||||||
|
component = str(component)
|
||||||
|
if component in self.compPosition_Map.keys():
|
||||||
|
return self.compPosition_Map[component]
|
||||||
|
elif component in self.compName_Map.keys():
|
||||||
|
return self.compPosition_Map[self.compName_Map[component]]
|
||||||
|
else:
|
||||||
|
errMsg = 'getCompPosition: Unrecognized component {}. Expecting one of {} or {}.'
|
||||||
|
raise ValueError(errMsg.format(component, self.compPosition_Map.keys(), self.compName_Map.keys()))
|
@ -17,6 +17,7 @@ import time
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import matplotlib
|
import matplotlib
|
||||||
|
|
||||||
matplotlib.use('QT4Agg')
|
matplotlib.use('QT4Agg')
|
||||||
|
|
||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
@ -48,15 +49,15 @@ from pylot.core.io.inputs import FilterOptions, PylotParameter
|
|||||||
from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \
|
from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \
|
||||||
getResolutionWindow, get_quality_class
|
getResolutionWindow, get_quality_class
|
||||||
from pylot.core.pick.compare import Comparison
|
from pylot.core.pick.compare import Comparison
|
||||||
from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS, \
|
from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS
|
||||||
SetChannelComponents
|
|
||||||
from pylot.core.util.utils import prepTimeAxis, full_range, scaleWFData, \
|
from pylot.core.util.utils import prepTimeAxis, full_range, scaleWFData, \
|
||||||
demeanTrace, isSorted, findComboBoxIndex, clims, pick_linestyle_plt, pick_color_plt, \
|
demeanTrace, isSorted, findComboBoxIndex, clims, pick_linestyle_plt, pick_color_plt, \
|
||||||
check4rotated, check4doubled, check4gaps, remove_underscores, find_horizontals, identifyPhase, \
|
check4rotated, check4doubled, check4gaps, remove_underscores, find_horizontals, identifyPhase, \
|
||||||
loopIdentifyPhase, trim_station_components, transformFilteroptions2String, \
|
loopIdentifyPhase, trim_station_components, transformFilteroptions2String, \
|
||||||
identifyPhaseID, real_Bool, pick_color, getAutoFilteroptions
|
identifyPhaseID, real_Bool, pick_color, getAutoFilteroptions, SetChannelComponents
|
||||||
from autoPyLoT import autoPyLoT
|
from autoPyLoT import autoPyLoT
|
||||||
from pylot.core.util.thread import Thread
|
from pylot.core.util.thread import Thread
|
||||||
|
from pylot.core.util.dataprocessing import Metadata
|
||||||
|
|
||||||
if sys.version_info.major == 3:
|
if sys.version_info.major == 3:
|
||||||
import icons_rc_3 as icons_rc
|
import icons_rc_3 as icons_rc
|
||||||
@ -118,6 +119,139 @@ def createAction(parent, text, slot=None, shortcut=None, icon=None,
|
|||||||
return action
|
return action
|
||||||
|
|
||||||
|
|
||||||
|
class ProgressBarWidget(QtGui.QWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(ProgressBarWidget, self).__init__(parent)
|
||||||
|
self.hlayout = QtGui.QHBoxLayout()
|
||||||
|
self.pb = QtGui.QProgressBar()
|
||||||
|
self.pb.setRange(0, 0)
|
||||||
|
self.label = QLabel()
|
||||||
|
self.hlayout.addWidget(self.pb)
|
||||||
|
self.hlayout.addWidget(self.label)
|
||||||
|
self.setLayout(self.hlayout)
|
||||||
|
self.hide()
|
||||||
|
|
||||||
|
|
||||||
|
class AddMetadataWidget(QWidget):
|
||||||
|
def __init__(self, parent=None, metadata=None, windowflag=1):
|
||||||
|
super(AddMetadataWidget, self).__init__(parent, windowflag)
|
||||||
|
self.inventories = {}
|
||||||
|
|
||||||
|
self.main_layout = QVBoxLayout()
|
||||||
|
self.setLayout(self.main_layout)
|
||||||
|
self.setupUI()
|
||||||
|
self.connect_signals()
|
||||||
|
self.resize(600, 800)
|
||||||
|
|
||||||
|
self.metadata = metadata if metadata else Metadata()
|
||||||
|
self.from_metadata()
|
||||||
|
|
||||||
|
self.center()
|
||||||
|
self.show()
|
||||||
|
#self.__test__()
|
||||||
|
|
||||||
|
def __test__(self):
|
||||||
|
self.add_item(r'/rscratch/minos14/marcel/git/pylot/tests')
|
||||||
|
self.add_item(r'/rscratch/minos14/marcel/git/pylot/inputs')
|
||||||
|
self.add_item(r'/rscratch/minos14/marcel/git/pylot/pylot')
|
||||||
|
self.add_item(r'/rscratch/minos14/marcel/git/pylot/pylot_not_existing')
|
||||||
|
|
||||||
|
def center(self):
|
||||||
|
fm = self.frameGeometry()
|
||||||
|
screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos())
|
||||||
|
centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center()
|
||||||
|
fm.moveCenter(centerPoint)
|
||||||
|
self.move(fm.topLeft())
|
||||||
|
|
||||||
|
def setupUI(self):
|
||||||
|
self.init_selection_layout()
|
||||||
|
self.init_add_remove_layout()
|
||||||
|
self.init_list_widget()
|
||||||
|
self.init_close()
|
||||||
|
|
||||||
|
def init_selection_layout(self):
|
||||||
|
self.selection_layout = QHBoxLayout()
|
||||||
|
self.selection_box = QtGui.QLineEdit()
|
||||||
|
self.selection_button = QtGui.QPushButton('...')
|
||||||
|
self.selection_layout.addWidget(self.selection_box, 1)
|
||||||
|
self.selection_layout.addWidget(self.selection_button, 0)
|
||||||
|
self.main_layout.insertLayout(0, self.selection_layout, 0)
|
||||||
|
|
||||||
|
def init_add_remove_layout(self):
|
||||||
|
self.add_remove_layout = QHBoxLayout()
|
||||||
|
self.add_button = QtGui.QPushButton('+')
|
||||||
|
self.add_button.setShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Return))
|
||||||
|
self.remove_button = QtGui.QPushButton('-')
|
||||||
|
self.remove_button.setShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Delete))
|
||||||
|
self.add_remove_layout.addWidget(self.add_button, 1)
|
||||||
|
self.add_remove_layout.addWidget(self.remove_button, 1)
|
||||||
|
self.main_layout.insertLayout(1, self.add_remove_layout, 0)
|
||||||
|
|
||||||
|
def init_list_widget(self):
|
||||||
|
self.list_view = QtGui.QListView()
|
||||||
|
self.list_view.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||||
|
self.list_model = QtGui.QStandardItemModel(self.list_view)
|
||||||
|
self.list_view.setModel(self.list_model)
|
||||||
|
self.main_layout.insertWidget(2, self.list_view, 1)
|
||||||
|
|
||||||
|
def init_close(self):
|
||||||
|
self.close_button = QPushButton('Update')
|
||||||
|
self.close_button.setShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Escape))
|
||||||
|
self.main_layout.addWidget(self.close_button)
|
||||||
|
|
||||||
|
def from_metadata(self):
|
||||||
|
for inventory_path in self.metadata.inventories:
|
||||||
|
self.add_item(inventory_path, from_metadata=True)
|
||||||
|
|
||||||
|
def refresh_list(self):
|
||||||
|
self.clear_list()
|
||||||
|
for inventory_path in self.inventories.keys():
|
||||||
|
self.add_item(inventory_path)
|
||||||
|
|
||||||
|
def connect_signals(self):
|
||||||
|
self.selection_button.clicked.connect(self.open_directory)
|
||||||
|
self.add_button.clicked.connect(self.add_item_from_box)
|
||||||
|
self.remove_button.clicked.connect(self.remove_item)
|
||||||
|
self.close_button.clicked.connect(self.hide)
|
||||||
|
|
||||||
|
def open_directory(self):
|
||||||
|
fninv = QFileDialog.getExistingDirectory(self, self.tr(
|
||||||
|
"Select inventory..."), self.tr("Select folder"))
|
||||||
|
if not fninv:
|
||||||
|
return
|
||||||
|
self.selection_box.setText(fninv)
|
||||||
|
|
||||||
|
def add_item_from_box(self):
|
||||||
|
inventory_path = self.selection_box.text()
|
||||||
|
self.add_item(inventory_path)
|
||||||
|
self.selection_box.setText('')
|
||||||
|
|
||||||
|
def add_item(self, inventory_path, from_metadata=False):
|
||||||
|
if not inventory_path:
|
||||||
|
return
|
||||||
|
if inventory_path in self.inventories.keys():
|
||||||
|
QMessageBox.warning(self, 'Info', 'Path already in list!')
|
||||||
|
return
|
||||||
|
if not os.path.isdir(inventory_path):
|
||||||
|
QMessageBox.warning(self, 'Warning', 'Path is no directory!')
|
||||||
|
return
|
||||||
|
item = QtGui.QStandardItem(inventory_path)
|
||||||
|
item.setEditable(False)
|
||||||
|
self.inventories[inventory_path] = item
|
||||||
|
self.list_model.appendRow(item)
|
||||||
|
|
||||||
|
if not from_metadata:
|
||||||
|
self.metadata.add_inventory(inventory_path)
|
||||||
|
|
||||||
|
def remove_item(self):
|
||||||
|
for index in reversed(self.list_view.selectionModel().selectedIndexes()):
|
||||||
|
item = self.list_model.itemData(index)
|
||||||
|
inventory_path = item[0]
|
||||||
|
del (self.inventories[inventory_path])
|
||||||
|
self.metadata.remove_inventory(inventory_path)
|
||||||
|
self.list_model.removeRow(index.row())
|
||||||
|
|
||||||
|
|
||||||
class ComparisonWidget(QWidget):
|
class ComparisonWidget(QWidget):
|
||||||
def __init__(self, c, parent=None, windowflag=1):
|
def __init__(self, c, parent=None, windowflag=1):
|
||||||
self._data = c
|
self._data = c
|
||||||
@ -132,6 +266,14 @@ class ComparisonWidget(QWidget):
|
|||||||
self.setupUI()
|
self.setupUI()
|
||||||
self.resize(1280, 720)
|
self.resize(1280, 720)
|
||||||
self.plotcomparison()
|
self.plotcomparison()
|
||||||
|
self.center()
|
||||||
|
|
||||||
|
def center(self):
|
||||||
|
fm = self.frameGeometry()
|
||||||
|
screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos())
|
||||||
|
centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center()
|
||||||
|
fm.moveCenter(centerPoint)
|
||||||
|
self.move(fm.topLeft())
|
||||||
|
|
||||||
def setupUI(self):
|
def setupUI(self):
|
||||||
|
|
||||||
@ -242,7 +384,8 @@ class ComparisonWidget(QWidget):
|
|||||||
def clf(self):
|
def clf(self):
|
||||||
self.canvas.figure.clf()
|
self.canvas.figure.clf()
|
||||||
|
|
||||||
def hasvalue(self, sender):
|
@staticmethod
|
||||||
|
def hasvalue(sender):
|
||||||
text = sender.currentText()
|
text = sender.currentText()
|
||||||
index = sender.findText(text.upper())
|
index = sender.findText(text.upper())
|
||||||
return index
|
return index
|
||||||
@ -503,8 +646,17 @@ class WaveformWidgetPG(QtGui.QWidget):
|
|||||||
self.label_layout.addWidget(self.status_label)
|
self.label_layout.addWidget(self.status_label)
|
||||||
for label in self.perm_labels:
|
for label in self.perm_labels:
|
||||||
self.label_layout.addWidget(label)
|
self.label_layout.addWidget(label)
|
||||||
self.label_layout.addWidget(self.syn_checkbox)
|
mid_widget = QWidget()
|
||||||
self.label_layout.addWidget(self.qcombo_processed)
|
right_widget = QWidget()
|
||||||
|
# use widgets as placeholder, so that child widgets keep position when others are hidden
|
||||||
|
mid_layout = QHBoxLayout()
|
||||||
|
right_layout = QHBoxLayout()
|
||||||
|
mid_layout.addWidget(self.syn_checkbox)
|
||||||
|
right_layout.addWidget(self.qcombo_processed)
|
||||||
|
mid_widget.setLayout(mid_layout)
|
||||||
|
right_widget.setLayout(right_layout)
|
||||||
|
self.label_layout.addWidget(mid_widget)
|
||||||
|
self.label_layout.addWidget(right_widget)
|
||||||
self.syn_checkbox.setLayoutDirection(Qt.RightToLeft)
|
self.syn_checkbox.setLayoutDirection(Qt.RightToLeft)
|
||||||
self.label_layout.setStretch(0, 4)
|
self.label_layout.setStretch(0, 4)
|
||||||
self.label_layout.setStretch(1, 0)
|
self.label_layout.setStretch(1, 0)
|
||||||
@ -644,7 +796,8 @@ class WaveformWidgetPG(QtGui.QWidget):
|
|||||||
trace_syn.normalize(np.max(np.abs(trace_syn.data)) * 2)
|
trace_syn.normalize(np.max(np.abs(trace_syn.data)) * 2)
|
||||||
# TODO: change this to numpy operations instead of lists?
|
# TODO: change this to numpy operations instead of lists?
|
||||||
times = np.array([time for index, time in enumerate(time_ax) if not index % nth_sample])
|
times = np.array([time for index, time in enumerate(time_ax) if not index % nth_sample])
|
||||||
times_syn = np.array([time for index, time in enumerate(time_ax_syn) if not index % nth_sample] if st_syn else [])
|
times_syn = np.array(
|
||||||
|
[time for index, time in enumerate(time_ax_syn) if not index % nth_sample] if st_syn else [])
|
||||||
trace.data = np.array([datum + n for index, datum in enumerate(trace.data) if not index % nth_sample])
|
trace.data = np.array([datum + n for index, datum in enumerate(trace.data) if not index % nth_sample])
|
||||||
trace_syn.data = np.array([datum + n for index, datum in enumerate(trace_syn.data)
|
trace_syn.data = np.array([datum + n for index, datum in enumerate(trace_syn.data)
|
||||||
if not index % nth_sample] if st_syn else [])
|
if not index % nth_sample] if st_syn else [])
|
||||||
@ -873,6 +1026,7 @@ class PylotCanvas(FigureCanvas):
|
|||||||
new_ylim = self.calcPanZoom(self.ypress, y_bot, y_top, factor, (ydiff > 0))
|
new_ylim = self.calcPanZoom(self.ypress, y_bot, y_top, factor, (ydiff > 0))
|
||||||
self.setYLims(ax, new_ylim)
|
self.setYLims(ax, new_ylim)
|
||||||
|
|
||||||
|
self.refreshPickDlgText()
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def set_frame_color(self, color='k'):
|
def set_frame_color(self, color='k'):
|
||||||
@ -895,7 +1049,8 @@ class PylotCanvas(FigureCanvas):
|
|||||||
fname += '.png'
|
fname += '.png'
|
||||||
self.figure.savefig(fname)
|
self.figure.savefig(fname)
|
||||||
|
|
||||||
def calcPanZoom(self, origin, lower_b, upper_b, factor, positive):
|
@staticmethod
|
||||||
|
def calcPanZoom(origin, lower_b, upper_b, factor, positive):
|
||||||
d_lower = abs(origin - lower_b)
|
d_lower = abs(origin - lower_b)
|
||||||
d_upper = abs(origin - upper_b)
|
d_upper = abs(origin - upper_b)
|
||||||
|
|
||||||
@ -1029,7 +1184,8 @@ class PylotCanvas(FigureCanvas):
|
|||||||
def clearPlotDict(self):
|
def clearPlotDict(self):
|
||||||
self.plotdict = dict()
|
self.plotdict = dict()
|
||||||
|
|
||||||
def calcPlotPositions(self, wfdata, compclass):
|
@staticmethod
|
||||||
|
def calcPlotPositions(wfdata, compclass):
|
||||||
possible_plot_pos = list(range(len(wfdata)))
|
possible_plot_pos = list(range(len(wfdata)))
|
||||||
plot_positions = {}
|
plot_positions = {}
|
||||||
for trace in wfdata:
|
for trace in wfdata:
|
||||||
@ -1173,16 +1329,20 @@ class PylotCanvas(FigureCanvas):
|
|||||||
self.setYLims(ax, zoomy)
|
self.setYLims(ax, zoomy)
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def getXLims(self, ax):
|
@staticmethod
|
||||||
|
def getXLims(ax):
|
||||||
return ax.get_xlim()
|
return ax.get_xlim()
|
||||||
|
|
||||||
def getYLims(self, ax):
|
@staticmethod
|
||||||
|
def getYLims(ax):
|
||||||
return ax.get_ylim()
|
return ax.get_ylim()
|
||||||
|
|
||||||
def setXLims(self, ax, lims):
|
@staticmethod
|
||||||
|
def setXLims(ax, lims):
|
||||||
ax.set_xlim(lims)
|
ax.set_xlim(lims)
|
||||||
|
|
||||||
def setYLims(self, ax, lims):
|
@staticmethod
|
||||||
|
def setYLims(ax, lims):
|
||||||
ax.set_ylim(lims)
|
ax.set_ylim(lims)
|
||||||
|
|
||||||
def setYTickLabels(self, pos, labels):
|
def setYTickLabels(self, pos, labels):
|
||||||
@ -1298,7 +1458,8 @@ class PhaseDefaults(QtGui.QDialog):
|
|||||||
checkbox.setChecked(bool(phase in self.current_phases))
|
checkbox.setChecked(bool(phase in self.current_phases))
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
def create_phase_box(self, phase_name):
|
@staticmethod
|
||||||
|
def create_phase_box(phase_name):
|
||||||
checkbox = QtGui.QCheckBox(phase_name)
|
checkbox = QtGui.QCheckBox(phase_name)
|
||||||
return checkbox
|
return checkbox
|
||||||
|
|
||||||
@ -1433,7 +1594,6 @@ class PickDlg(QDialog):
|
|||||||
self.multicompfig.draw()
|
self.multicompfig.draw()
|
||||||
self.multicompfig.setFocus()
|
self.multicompfig.setFocus()
|
||||||
|
|
||||||
|
|
||||||
# set plot labels
|
# set plot labels
|
||||||
self.setPlotLabels()
|
self.setPlotLabels()
|
||||||
|
|
||||||
@ -1459,7 +1619,6 @@ class PickDlg(QDialog):
|
|||||||
self.setWindowTitle('Pickwindow on station: {}'.format(self.getStation()))
|
self.setWindowTitle('Pickwindow on station: {}'.format(self.getStation()))
|
||||||
self.setWindowState(QtCore.Qt.WindowMaximized)
|
self.setWindowState(QtCore.Qt.WindowMaximized)
|
||||||
|
|
||||||
|
|
||||||
def setupUi(self):
|
def setupUi(self):
|
||||||
menuBar = QtGui.QMenuBar(self)
|
menuBar = QtGui.QMenuBar(self)
|
||||||
if not self._embedded:
|
if not self._embedded:
|
||||||
@ -1683,9 +1842,10 @@ class PickDlg(QDialog):
|
|||||||
func = {True: self.model.get_ray_paths_geo,
|
func = {True: self.model.get_ray_paths_geo,
|
||||||
False: self.model.get_travel_times_geo}
|
False: self.model.get_travel_times_geo}
|
||||||
phases = self.prepare_phases()
|
phases = self.prepare_phases()
|
||||||
station_id = self.data.traces[0].get_id()
|
trace = self.data.traces[0]
|
||||||
parser = self.metadata[1]
|
station_id = trace.get_id()
|
||||||
station_coords = parser.get_coordinates(station_id)
|
starttime = trace.stats.starttime
|
||||||
|
station_coords = self.metadata.get_coordinates(station_id, starttime)
|
||||||
origins = self.pylot_event.origins
|
origins = self.pylot_event.origins
|
||||||
if origins:
|
if origins:
|
||||||
source_origin = origins[0]
|
source_origin = origins[0]
|
||||||
@ -1699,7 +1859,8 @@ class PickDlg(QDialog):
|
|||||||
phases)
|
phases)
|
||||||
self.arrivals = arrivals
|
self.arrivals = arrivals
|
||||||
|
|
||||||
def prepare_phases(self):
|
@staticmethod
|
||||||
|
def prepare_phases():
|
||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
p_phases = settings.value('p_phases')
|
p_phases = settings.value('p_phases')
|
||||||
s_phases = settings.value('s_phases')
|
s_phases = settings.value('s_phases')
|
||||||
@ -1805,7 +1966,6 @@ class PickDlg(QDialog):
|
|||||||
filterMenu.addAction(self.autoFilterAction)
|
filterMenu.addAction(self.autoFilterAction)
|
||||||
filterMenu.addAction(filterOptionsAction)
|
filterMenu.addAction(filterOptionsAction)
|
||||||
|
|
||||||
|
|
||||||
def filterOptions(self):
|
def filterOptions(self):
|
||||||
if self.orig_parent.adjustFilterOptions():
|
if self.orig_parent.adjustFilterOptions():
|
||||||
phase = None
|
phase = None
|
||||||
@ -1875,7 +2035,8 @@ class PickDlg(QDialog):
|
|||||||
self.currentPhase = str(self.s_button.text())
|
self.currentPhase = str(self.s_button.text())
|
||||||
self.activatePicking()
|
self.activatePicking()
|
||||||
|
|
||||||
def getPhaseID(self, phase):
|
@staticmethod
|
||||||
|
def getPhaseID(phase):
|
||||||
return identifyPhaseID(phase)
|
return identifyPhaseID(phase)
|
||||||
|
|
||||||
def set_button_border_color(self, button, color=None):
|
def set_button_border_color(self, button, color=None):
|
||||||
@ -1936,10 +2097,10 @@ class PickDlg(QDialog):
|
|||||||
self.zoomAction.trigger()
|
self.zoomAction.trigger()
|
||||||
self.multicompfig.disconnectEvents()
|
self.multicompfig.disconnectEvents()
|
||||||
self.cidpress = self.multicompfig.connectPressEvent(self.setIniPick)
|
self.cidpress = self.multicompfig.connectPressEvent(self.setIniPick)
|
||||||
if not self.filterActionP.isChecked() and not self.filterActionS.isChecked():
|
|
||||||
if self.autoFilterAction.isChecked():
|
if self.autoFilterAction.isChecked():
|
||||||
|
for filteraction in [self.filterActionP, self.filterActionS]:
|
||||||
|
filteraction.setChecked(False)
|
||||||
self.filterWFData()
|
self.filterWFData()
|
||||||
else:
|
|
||||||
self.draw()
|
self.draw()
|
||||||
else:
|
else:
|
||||||
self.draw()
|
self.draw()
|
||||||
@ -2087,7 +2248,8 @@ class PickDlg(QDialog):
|
|||||||
st += data.select(channel=action.text())
|
st += data.select(channel=action.text())
|
||||||
return st
|
return st
|
||||||
|
|
||||||
def calcNoiseScaleFactor(self, noiselevel, zoomfactor=5., norm=1):
|
@staticmethod
|
||||||
|
def calcNoiseScaleFactor(noiselevel, zoomfactor=5., norm=1):
|
||||||
# calculate factor to upscale a trace normed to 'norm' in a way that all values
|
# calculate factor to upscale a trace normed to 'norm' in a way that all values
|
||||||
# zoomfactor*noiselevel are found within -0.5*norm and 0.5*norm
|
# zoomfactor*noiselevel are found within -0.5*norm and 0.5*norm
|
||||||
scaleFactor = (norm / 2.) / (zoomfactor * noiselevel)
|
scaleFactor = (norm / 2.) / (zoomfactor * noiselevel)
|
||||||
@ -2349,43 +2511,38 @@ class PickDlg(QDialog):
|
|||||||
lpp = picks['lpp'] - self.getStartTime()
|
lpp = picks['lpp'] - self.getStartTime()
|
||||||
spe = picks['spe']
|
spe = picks['spe']
|
||||||
|
|
||||||
|
if not picktype in ['auto', 'manual']:
|
||||||
|
raise TypeError('Unknown picktype {0}'.format(picktype))
|
||||||
|
|
||||||
if picktype == 'manual':
|
if picktype == 'manual':
|
||||||
|
baseorder = 5
|
||||||
|
elif picktype == 'auto':
|
||||||
|
baseorder = 0
|
||||||
|
|
||||||
color = pick_color_plt(picktype, phaseID, quality)
|
color = pick_color_plt(picktype, phaseID, quality)
|
||||||
if not textOnly:
|
if not textOnly:
|
||||||
linestyle_mpp, width_mpp = pick_linestyle_plt(picktype, 'mpp')
|
linestyle_mpp, width_mpp = pick_linestyle_plt(picktype, 'mpp')
|
||||||
vl = ax.axvline(mpp, ylims[0], ylims[1], color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
vl = ax.axvline(mpp, ylims[0], ylims[1], color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
||||||
label='{}-Pick (quality: {})'.format(phase, quality), picker=5)
|
label='{}-{}-Pick (quality: {})'.format(phase, picktype, quality), picker=5,
|
||||||
self.phaseLines[phase] = vl
|
zorder=baseorder+9)
|
||||||
|
phaseLineKey = '{}-{}'.format(phase, picktype)
|
||||||
|
self.phaseLines[phaseLineKey] = vl
|
||||||
if spe:
|
if spe:
|
||||||
ax.fill_between([mpp - spe, mpp + spe], ylims[0], ylims[1],
|
ax.fill_between([mpp - spe, mpp + spe], ylims[0], ylims[1],
|
||||||
alpha=.25, color=color, label='{}-SPE'.format(phase))
|
alpha=.25, color=color, label='{}-{}-SPE'.format(phase, picktype), zorder=baseorder+1)
|
||||||
if picks['epp']:
|
if picks['epp']:
|
||||||
linestyle_epp, width_epp = pick_linestyle_plt(picktype, 'epp')
|
linestyle_epp, width_epp = pick_linestyle_plt(picktype, 'epp')
|
||||||
ax.axvline(epp, ylims[0], ylims[1], color=color, linestyle=linestyle_epp,
|
ax.axvline(epp, ylims[0], ylims[1], color=color, linestyle=linestyle_epp,
|
||||||
linewidth=width_epp, label='{}-EPP'.format(phase))
|
linewidth=width_epp, label='{}-{}-EPP'.format(phase, picktype), zorder=baseorder+2)
|
||||||
if picks['lpp']:
|
if picks['lpp']:
|
||||||
linestyle_lpp, width_lpp = pick_linestyle_plt(picktype, 'lpp')
|
linestyle_lpp, width_lpp = pick_linestyle_plt(picktype, 'lpp')
|
||||||
ax.axvline(lpp, ylims[0], ylims[1], color=color, linestyle=linestyle_lpp,
|
ax.axvline(lpp, ylims[0], ylims[1], color=color, linestyle=linestyle_lpp,
|
||||||
linewidth=width_lpp, label='{}-LPP'.format(phase))
|
linewidth=width_lpp, label='{}-{}-LPP'.format(phase, picktype), zorder=baseorder+2)
|
||||||
# else:
|
if picktype == 'auto':
|
||||||
# ax.plot([mpp, mpp], ylims, color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
ax.plot(mpp, ylims[1], color=color, marker='v', zorder=baseorder+3)
|
||||||
# label='{}-Pick (NO PICKERROR)'.format(phase), picker=5)
|
ax.plot(mpp, ylims[0], color=color, marker='^', zorder=baseorder+3)
|
||||||
# append phase text (if textOnly: draw with current ylims)
|
# append phase text (if textOnly: draw with current ylims)
|
||||||
self.phaseText.append(ax.text(mpp, ylims[1], phase, color=color))
|
self.phaseText.append(ax.text(mpp, ylims[1], phase, color=color, zorder=baseorder+10))
|
||||||
elif picktype == 'auto':
|
|
||||||
color = pick_color_plt(picktype, phaseID, quality)
|
|
||||||
linestyle_mpp, width_mpp = pick_linestyle_plt(picktype, 'mpp')
|
|
||||||
if not textOnly:
|
|
||||||
ax.plot(mpp, ylims[1], color=color, marker='v')
|
|
||||||
ax.plot(mpp, ylims[0], color=color, marker='^')
|
|
||||||
vl = ax.axvline(mpp, ylims[0], ylims[1], color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
|
||||||
picker=5, label='{}-Autopick (quality: {})'.format(phase, quality))
|
|
||||||
self.phaseLines[phase] = vl
|
|
||||||
# append phase text (if textOnly: draw with current ylims)
|
|
||||||
self.phaseText.append(ax.text(mpp, ylims[1], phase, color=color))
|
|
||||||
else:
|
|
||||||
raise TypeError('Unknown picktype {0}'.format(picktype))
|
|
||||||
|
|
||||||
ax.legend(loc=1)
|
ax.legend(loc=1)
|
||||||
|
|
||||||
def connect_mouse_motion(self):
|
def connect_mouse_motion(self):
|
||||||
@ -2421,7 +2578,7 @@ class PickDlg(QDialog):
|
|||||||
if not x:
|
if not x:
|
||||||
return
|
return
|
||||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||||
if pick_rel == None:
|
if pick_rel is None:
|
||||||
return
|
return
|
||||||
pick = allpicks[picktype][phase]
|
pick = allpicks[picktype][phase]
|
||||||
message = '{} {}-pick'.format(picktype, phase)
|
message = '{} {}-pick'.format(picktype, phase)
|
||||||
@ -2442,7 +2599,7 @@ class PickDlg(QDialog):
|
|||||||
return
|
return
|
||||||
x = event.mouseevent.xdata
|
x = event.mouseevent.xdata
|
||||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||||
if pick_rel == None:
|
if pick_rel is None:
|
||||||
return
|
return
|
||||||
pick = allpicks[picktype][phase]
|
pick = allpicks[picktype][phase]
|
||||||
message = '{} {}-pick'.format(picktype, phase)
|
message = '{} {}-pick'.format(picktype, phase)
|
||||||
@ -2499,7 +2656,7 @@ class PickDlg(QDialog):
|
|||||||
if not self.picks and not self.autopicks:
|
if not self.picks and not self.autopicks:
|
||||||
return
|
return
|
||||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||||
if pick_rel == None:
|
if pick_rel is None:
|
||||||
return
|
return
|
||||||
# delete the value from corresponding dictionary
|
# delete the value from corresponding dictionary
|
||||||
allpicks[picktype].pop(phase)
|
allpicks[picktype].pop(phase)
|
||||||
@ -2507,8 +2664,9 @@ class PickDlg(QDialog):
|
|||||||
if phase in self.phaseLines.keys():
|
if phase in self.phaseLines.keys():
|
||||||
del (self.phaseLines[phase])
|
del (self.phaseLines[phase])
|
||||||
# information output
|
# information output
|
||||||
msg = 'Deleted {} pick for phase {}, at timestamp {} (relative time: {} s)'
|
msg = 'Deleted {} pick for phase {}, station {} at timestamp {} (relative time: {} s)'
|
||||||
print(msg.format(picktype, phase, self.getStartTime()+pick_rel, pick_rel))
|
print(msg.format(picktype, phase, '{}.{}'.format(self.network, self.station),
|
||||||
|
self.getStartTime() + pick_rel, pick_rel))
|
||||||
self.setDirty(True)
|
self.setDirty(True)
|
||||||
|
|
||||||
def identify_selected_picks(self, x):
|
def identify_selected_picks(self, x):
|
||||||
@ -2534,8 +2692,6 @@ class PickDlg(QDialog):
|
|||||||
pick_rel, phase, picktype = X[index]
|
pick_rel, phase, picktype = X[index]
|
||||||
return allpicks, pick_rel, phase, picktype
|
return allpicks, pick_rel, phase, picktype
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def drawPhaseText(self):
|
def drawPhaseText(self):
|
||||||
self.drawPicks(picktype='manual', textOnly=True)
|
self.drawPicks(picktype='manual', textOnly=True)
|
||||||
self.drawPicks(picktype='auto', textOnly=True)
|
self.drawPicks(picktype='auto', textOnly=True)
|
||||||
@ -2626,15 +2782,18 @@ class PickDlg(QDialog):
|
|||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
settings.setValue('autoFilter', self.autoFilterAction.isChecked())
|
settings.setValue('autoFilter', self.autoFilterAction.isChecked())
|
||||||
|
|
||||||
def updateChannelSettingsP(self, action):
|
@staticmethod
|
||||||
|
def updateChannelSettingsP(action):
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
settings.setValue('p_channel_{}'.format(action.text()), action.isChecked())
|
settings.setValue('p_channel_{}'.format(action.text()), action.isChecked())
|
||||||
|
|
||||||
def updateChannelSettingsS(self, action):
|
@staticmethod
|
||||||
|
def updateChannelSettingsS(action):
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
settings.setValue('s_channel_{}'.format(action.text()), action.isChecked())
|
settings.setValue('s_channel_{}'.format(action.text()), action.isChecked())
|
||||||
|
|
||||||
def getChannelSettingsP(self, channel):
|
@staticmethod
|
||||||
|
def getChannelSettingsP(channel):
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
rval = real_Bool(settings.value('p_channel_{}'.format(channel)))
|
rval = real_Bool(settings.value('p_channel_{}'.format(channel)))
|
||||||
compclass = settings.value('compclass')
|
compclass = settings.value('compclass')
|
||||||
@ -2648,7 +2807,8 @@ class PickDlg(QDialog):
|
|||||||
rval = False
|
rval = False
|
||||||
return rval
|
return rval
|
||||||
|
|
||||||
def getChannelSettingsS(self, channel):
|
@staticmethod
|
||||||
|
def getChannelSettingsS(channel):
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
rval = real_Bool(settings.value('s_channel_{}'.format(channel)))
|
rval = real_Bool(settings.value('s_channel_{}'.format(channel)))
|
||||||
compclass = settings.value('compclass')
|
compclass = settings.value('compclass')
|
||||||
@ -2662,7 +2822,6 @@ class PickDlg(QDialog):
|
|||||||
rval = False
|
rval = False
|
||||||
return rval
|
return rval
|
||||||
|
|
||||||
|
|
||||||
def resetPlot(self):
|
def resetPlot(self):
|
||||||
self.resetZoom()
|
self.resetZoom()
|
||||||
self.refreshPlot()
|
self.refreshPlot()
|
||||||
@ -2777,6 +2936,7 @@ class MultiEventWidget(QWidget):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, options=None, parent=None, windowflag=1):
|
def __init__(self, options=None, parent=None, windowflag=1):
|
||||||
QtGui.QWidget.__init__(self, parent, windowflag)
|
QtGui.QWidget.__init__(self, parent, windowflag)
|
||||||
|
|
||||||
@ -2784,6 +2944,14 @@ class MultiEventWidget(QWidget):
|
|||||||
self.setupUi()
|
self.setupUi()
|
||||||
# set initial size
|
# set initial size
|
||||||
self.resize(1280, 720)
|
self.resize(1280, 720)
|
||||||
|
self.center()
|
||||||
|
|
||||||
|
def center(self):
|
||||||
|
fm = self.frameGeometry()
|
||||||
|
screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos())
|
||||||
|
centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center()
|
||||||
|
fm.moveCenter(centerPoint)
|
||||||
|
self.move(fm.topLeft())
|
||||||
|
|
||||||
def setupUi(self):
|
def setupUi(self):
|
||||||
# init main layout
|
# init main layout
|
||||||
@ -2870,13 +3038,13 @@ class MultiEventWidget(QWidget):
|
|||||||
for rb in self.rb_dict.values():
|
for rb in self.rb_dict.values():
|
||||||
if rb.isChecked():
|
if rb.isChecked():
|
||||||
check_events = (rb.toolTip() == 'No events for this selection')
|
check_events = (rb.toolTip() == 'No events for this selection')
|
||||||
self.start_button.setEnabled(not(check_events))
|
self.start_button.setEnabled(not check_events)
|
||||||
|
|
||||||
def enable(self, bool):
|
def enable(self, bool):
|
||||||
for rb in self.rb_dict.values():
|
for rb in self.rb_dict.values():
|
||||||
rb.setEnabled(bool)
|
rb.setEnabled(bool)
|
||||||
self.start_button.setEnabled(bool)
|
self.start_button.setEnabled(bool)
|
||||||
self.pb.setVisible(not(bool))
|
self.pb.setVisible(not bool)
|
||||||
self._pb_space.setVisible(bool)
|
self._pb_space.setVisible(bool)
|
||||||
self.eventbox.setEnabled(bool)
|
self.eventbox.setEnabled(bool)
|
||||||
self.button_clear.setEnabled(bool)
|
self.button_clear.setEnabled(bool)
|
||||||
@ -2958,7 +3126,7 @@ class AutoPickWidget(MultiEventWidget):
|
|||||||
def reinitEvents2plot(self):
|
def reinitEvents2plot(self):
|
||||||
for eventID, eventDict in self.events2plot.items():
|
for eventID, eventDict in self.events2plot.items():
|
||||||
for widget_key, widget in eventDict.items():
|
for widget_key, widget in eventDict.items():
|
||||||
del(widget)
|
del widget
|
||||||
self.events2plot = {}
|
self.events2plot = {}
|
||||||
self.eventbox.clear()
|
self.eventbox.clear()
|
||||||
self.refresh_plot_tabs()
|
self.refresh_plot_tabs()
|
||||||
@ -2986,6 +3154,14 @@ class CompareEventsWidget(MultiEventWidget):
|
|||||||
self.connect_buttons()
|
self.connect_buttons()
|
||||||
self.setWindowTitle('Compare events')
|
self.setWindowTitle('Compare events')
|
||||||
self.set_main_stretch()
|
self.set_main_stretch()
|
||||||
|
self.center()
|
||||||
|
|
||||||
|
def center(self):
|
||||||
|
fm = self.frameGeometry()
|
||||||
|
screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos())
|
||||||
|
centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center()
|
||||||
|
fm.moveCenter(centerPoint)
|
||||||
|
self.move(fm.topLeft())
|
||||||
|
|
||||||
def connect_buttons(self):
|
def connect_buttons(self):
|
||||||
self.start_button.clicked.connect(self.run)
|
self.start_button.clicked.connect(self.run)
|
||||||
@ -3062,6 +3238,7 @@ class TuneAutopicker(QWidget):
|
|||||||
self.add_log()
|
self.add_log()
|
||||||
self.set_stretch()
|
self.set_stretch()
|
||||||
self.resize(1280, 720)
|
self.resize(1280, 720)
|
||||||
|
self.center()
|
||||||
self._manual_pick_plots = []
|
self._manual_pick_plots = []
|
||||||
if hasattr(self.parent(), 'metadata'):
|
if hasattr(self.parent(), 'metadata'):
|
||||||
self.metadata = self.parent().metadata
|
self.metadata = self.parent().metadata
|
||||||
@ -3070,6 +3247,13 @@ class TuneAutopicker(QWidget):
|
|||||||
# self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
# self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||||
# self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
|
# self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
|
||||||
|
|
||||||
|
def center(self):
|
||||||
|
fm = self.frameGeometry()
|
||||||
|
screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos())
|
||||||
|
centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center()
|
||||||
|
fm.moveCenter(centerPoint)
|
||||||
|
self.move(fm.topLeft())
|
||||||
|
|
||||||
def set_fig_dict(self, fig_dict):
|
def set_fig_dict(self, fig_dict):
|
||||||
for key, value in fig_dict.items():
|
for key, value in fig_dict.items():
|
||||||
if key is not 'mainFig':
|
if key is not 'mainFig':
|
||||||
@ -3147,7 +3331,7 @@ class TuneAutopicker(QWidget):
|
|||||||
self.data.setWFData(fnames)
|
self.data.setWFData(fnames)
|
||||||
wfdat = self.data.getWFData() # all available streams
|
wfdat = self.data.getWFData() # all available streams
|
||||||
# remove possible underscores in station names
|
# remove possible underscores in station names
|
||||||
wfdat = remove_underscores(wfdat)
|
#wfdat = remove_underscores(wfdat)
|
||||||
# rotate misaligned stations to ZNE
|
# rotate misaligned stations to ZNE
|
||||||
# check for gaps and doubled channels
|
# check for gaps and doubled channels
|
||||||
check4gaps(wfdat)
|
check4gaps(wfdat)
|
||||||
@ -3161,7 +3345,7 @@ class TuneAutopicker(QWidget):
|
|||||||
self.fill_figure_tabs()
|
self.fill_figure_tabs()
|
||||||
|
|
||||||
def init_pbwidget(self):
|
def init_pbwidget(self):
|
||||||
self.pb_widget = QtGui.QWidget()
|
self.pb_widget = ProgressBarWidget()
|
||||||
|
|
||||||
def init_tab_names(self):
|
def init_tab_names(self):
|
||||||
self.ptb_names = ['aicFig', 'slength', 'checkZ4s', 'refPpick', 'el_Ppick', 'fm_picker']
|
self.ptb_names = ['aicFig', 'slength', 'checkZ4s', 'refPpick', 'el_Ppick', 'fm_picker']
|
||||||
@ -3201,7 +3385,7 @@ class TuneAutopicker(QWidget):
|
|||||||
return self.eventBox.currentText().split('/')[-1]
|
return self.eventBox.currentText().split('/')[-1]
|
||||||
|
|
||||||
def get_current_event_fp(self):
|
def get_current_event_fp(self):
|
||||||
return self.eventBox.currentText()
|
return self.eventBox.currentText().split('*')[0]
|
||||||
|
|
||||||
def get_current_event_picks(self, station):
|
def get_current_event_picks(self, station):
|
||||||
event = self.get_current_event()
|
event = self.get_current_event()
|
||||||
@ -3220,7 +3404,8 @@ class TuneAutopicker(QWidget):
|
|||||||
def get_current_station_id(self):
|
def get_current_station_id(self):
|
||||||
return str(self.stationBox.currentText())
|
return str(self.stationBox.currentText())
|
||||||
|
|
||||||
def gen_tab_widget(self, name, canvas):
|
@staticmethod
|
||||||
|
def gen_tab_widget(name, canvas):
|
||||||
widget = QtGui.QWidget()
|
widget = QtGui.QWidget()
|
||||||
v_layout = QtGui.QVBoxLayout()
|
v_layout = QtGui.QVBoxLayout()
|
||||||
v_layout.addWidget(canvas)
|
v_layout.addWidget(canvas)
|
||||||
@ -3398,7 +3583,7 @@ class TuneAutopicker(QWidget):
|
|||||||
if index == -1:
|
if index == -1:
|
||||||
index += 1
|
index += 1
|
||||||
nevents = self.eventBox.model().rowCount()
|
nevents = self.eventBox.model().rowCount()
|
||||||
path = self.eventBox.itemText(index)
|
path = self.eventBox.itemText(index).split('*')[0]
|
||||||
if project.getEventFromPath(path).isTestEvent():
|
if project.getEventFromPath(path).isTestEvent():
|
||||||
for index in range(nevents):
|
for index in range(nevents):
|
||||||
path = self.eventBox.itemText(index)
|
path = self.eventBox.itemText(index)
|
||||||
@ -3491,7 +3676,7 @@ class TuneAutopicker(QWidget):
|
|||||||
if hasattr(self, 'pdlg_widget'):
|
if hasattr(self, 'pdlg_widget'):
|
||||||
if self.pdlg_widget:
|
if self.pdlg_widget:
|
||||||
self.pdlg_widget.setParent(None)
|
self.pdlg_widget.setParent(None)
|
||||||
del(self.pdlg_widget)
|
del self.pdlg_widget
|
||||||
if hasattr(self, 'overview'):
|
if hasattr(self, 'overview'):
|
||||||
self.overview.setParent(None)
|
self.overview.setParent(None)
|
||||||
if hasattr(self, 'p_tabs'):
|
if hasattr(self, 'p_tabs'):
|
||||||
@ -3546,10 +3731,18 @@ class PylotParaBox(QtGui.QWidget):
|
|||||||
self.params_to_gui()
|
self.params_to_gui()
|
||||||
self._toggle_advanced_settings()
|
self._toggle_advanced_settings()
|
||||||
self.resize(720, 860)
|
self.resize(720, 860)
|
||||||
|
self.center()
|
||||||
self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||||
self.accepted.connect(self.params_from_gui)
|
self.accepted.connect(self.params_from_gui)
|
||||||
self.rejected.connect(self.params_to_gui)
|
self.rejected.connect(self.params_to_gui)
|
||||||
|
|
||||||
|
def center(self):
|
||||||
|
fm = self.frameGeometry()
|
||||||
|
screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos())
|
||||||
|
centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center()
|
||||||
|
fm.moveCenter(centerPoint)
|
||||||
|
self.move(fm.topLeft())
|
||||||
|
|
||||||
def _init_sublayouts(self):
|
def _init_sublayouts(self):
|
||||||
self._main_layout = QtGui.QVBoxLayout()
|
self._main_layout = QtGui.QVBoxLayout()
|
||||||
self._advanced_layout = QtGui.QVBoxLayout()
|
self._advanced_layout = QtGui.QVBoxLayout()
|
||||||
@ -3650,7 +3843,8 @@ class PylotParaBox(QtGui.QWidget):
|
|||||||
grid.addWidget(box, index1, 2)
|
grid.addWidget(box, index1, 2)
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
def create_box(self, typ, tooltip):
|
@staticmethod
|
||||||
|
def create_box(typ, tooltip):
|
||||||
if typ == str:
|
if typ == str:
|
||||||
box = QtGui.QLineEdit()
|
box = QtGui.QLineEdit()
|
||||||
elif typ == float:
|
elif typ == float:
|
||||||
@ -3665,7 +3859,8 @@ class PylotParaBox(QtGui.QWidget):
|
|||||||
raise TypeError('Unrecognized type {}'.format(typ))
|
raise TypeError('Unrecognized type {}'.format(typ))
|
||||||
return box
|
return box
|
||||||
|
|
||||||
def create_multi_box(self, boxes, headline=None):
|
@staticmethod
|
||||||
|
def create_multi_box(boxes, headline=None):
|
||||||
box = QtGui.QWidget()
|
box = QtGui.QWidget()
|
||||||
gl = QtGui.QGridLayout()
|
gl = QtGui.QGridLayout()
|
||||||
column = 0
|
column = 0
|
||||||
@ -3993,7 +4188,7 @@ class AutoPickDlg(QDialog):
|
|||||||
self.gb.setLayout(self.jobLayout)
|
self.gb.setLayout(self.jobLayout)
|
||||||
|
|
||||||
def exportParameter(self):
|
def exportParameter(self):
|
||||||
self.parent().exportAllEvents()
|
self.parent().exportEvents()
|
||||||
pylot_params = self.parent()._inputs
|
pylot_params = self.parent()._inputs
|
||||||
self.addEvents2pp(pylot_params)
|
self.addEvents2pp(pylot_params)
|
||||||
pylot_params.export2File(self.pp_export)
|
pylot_params.export2File(self.pp_export)
|
||||||
@ -4366,7 +4561,8 @@ class PhasesTab(PropTab):
|
|||||||
self.PphasesEdit.setText(p_phases)
|
self.PphasesEdit.setText(p_phases)
|
||||||
self.SphasesEdit.setText(s_phases)
|
self.SphasesEdit.setText(s_phases)
|
||||||
|
|
||||||
def sortPhases(self, phases):
|
@staticmethod
|
||||||
|
def sortPhases(phases):
|
||||||
sorted_phases = {'P': [],
|
sorted_phases = {'P': [],
|
||||||
'S': []}
|
'S': []}
|
||||||
for phase in phases:
|
for phase in phases:
|
||||||
@ -4393,7 +4589,7 @@ class GraphicsTab(PropTab):
|
|||||||
super(GraphicsTab, self).__init__(parent)
|
super(GraphicsTab, self).__init__(parent)
|
||||||
self.pylot_mainwindow = parent._pylot_mainwindow
|
self.pylot_mainwindow = parent._pylot_mainwindow
|
||||||
self.init_layout()
|
self.init_layout()
|
||||||
self.add_pg_cb()
|
#self.add_pg_cb()
|
||||||
self.add_nth_sample()
|
self.add_nth_sample()
|
||||||
self.add_style_settings()
|
self.add_style_settings()
|
||||||
self.setLayout(self.main_layout)
|
self.setLayout(self.main_layout)
|
||||||
@ -4429,36 +4625,16 @@ class GraphicsTab(PropTab):
|
|||||||
self.main_layout.addWidget(label, 1, 0)
|
self.main_layout.addWidget(label, 1, 0)
|
||||||
self.main_layout.addWidget(self.spinbox_nth_sample, 1, 1)
|
self.main_layout.addWidget(self.spinbox_nth_sample, 1, 1)
|
||||||
|
|
||||||
def add_pg_cb(self):
|
|
||||||
try:
|
|
||||||
import pyqtgraph as pg
|
|
||||||
pg = True
|
|
||||||
except:
|
|
||||||
pg = False
|
|
||||||
|
|
||||||
text = {True: 'Use pyqtgraphic library for plotting',
|
|
||||||
False: 'Cannot use library: pyqtgraphic not found on system'}
|
|
||||||
label = QLabel('PyQt graphic')
|
|
||||||
label.setToolTip(text[bool(pg)])
|
|
||||||
label.setEnabled(bool(pg))
|
|
||||||
self.checkbox_pg = QtGui.QCheckBox()
|
|
||||||
self.checkbox_pg.setEnabled(bool(pg))
|
|
||||||
self.checkbox_pg.setChecked(bool(pg))
|
|
||||||
self.main_layout.addWidget(label, 0, 0)
|
|
||||||
self.main_layout.addWidget(self.checkbox_pg, 0, 1)
|
|
||||||
|
|
||||||
def set_current_style(self):
|
def set_current_style(self):
|
||||||
selected_style = self.style_cb.currentText()
|
selected_style = self.style_cb.currentText()
|
||||||
self.pylot_mainwindow.set_style(selected_style)
|
self.pylot_mainwindow.set_style(selected_style)
|
||||||
|
|
||||||
def getValues(self):
|
def getValues(self):
|
||||||
values = {'nth_sample': self.spinbox_nth_sample.value(),
|
values = {'nth_sample': self.spinbox_nth_sample.value()}
|
||||||
'pyqtgraphic': self.checkbox_pg.isChecked()}
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def resetValues(self, infile=None):
|
def resetValues(self, infile=None):
|
||||||
values = {'nth_sample': self.spinbox_nth_sample.setValue(1),
|
values = {'nth_sample': self.spinbox_nth_sample.setValue(1)}
|
||||||
'pyqtgraphic': self.checkbox_pg.setChecked(True)}
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
@ -4607,7 +4783,8 @@ class LocalisationTab(PropTab):
|
|||||||
self.rootlabel.setText("{0} root directory".format(curtool))
|
self.rootlabel.setText("{0} root directory".format(curtool))
|
||||||
self.binlabel.setText("{0} bin directory".format(curtool))
|
self.binlabel.setText("{0} bin directory".format(curtool))
|
||||||
|
|
||||||
def selectDirectory(self, edit):
|
@staticmethod
|
||||||
|
def selectDirectory(edit):
|
||||||
selected_directory = QFileDialog.getExistingDirectory()
|
selected_directory = QFileDialog.getExistingDirectory()
|
||||||
# check if string is empty
|
# check if string is empty
|
||||||
if selected_directory:
|
if selected_directory:
|
||||||
@ -4705,7 +4882,8 @@ class FilterOptionsDialog(QDialog):
|
|||||||
'S': FilterOptions()}
|
'S': FilterOptions()}
|
||||||
|
|
||||||
self.setWindowTitle(titleString)
|
self.setWindowTitle(titleString)
|
||||||
self.filterOptionWidgets = {'P': FilterOptionsWidget(self.filterOptions['P'], self.parent().getAutoFilteroptions('P')),
|
self.filterOptionWidgets = {
|
||||||
|
'P': FilterOptionsWidget(self.filterOptions['P'], self.parent().getAutoFilteroptions('P')),
|
||||||
'S': FilterOptionsWidget(self.filterOptions['S'], self.parent().getAutoFilteroptions('S'))}
|
'S': FilterOptionsWidget(self.filterOptions['S'], self.parent().getAutoFilteroptions('S'))}
|
||||||
self.setupUi()
|
self.setupUi()
|
||||||
self.updateUi()
|
self.updateUi()
|
||||||
@ -4773,6 +4951,9 @@ class FilterOptionsDialog(QDialog):
|
|||||||
def checkMinMax(self):
|
def checkMinMax(self):
|
||||||
returnvals = []
|
returnvals = []
|
||||||
for foWidget in self.filterOptionWidgets.values():
|
for foWidget in self.filterOptionWidgets.values():
|
||||||
|
if foWidget.filterOptions._filtertype in ['highpass', 'lowpass']:
|
||||||
|
returnvals.append(True)
|
||||||
|
continue
|
||||||
returnvals.append(foWidget.checkMin())
|
returnvals.append(foWidget.checkMin())
|
||||||
returnvals.append(foWidget.checkMax())
|
returnvals.append(foWidget.checkMax())
|
||||||
if all(returnvals):
|
if all(returnvals):
|
||||||
@ -4831,7 +5012,7 @@ class FilterOptionsWidget(QWidget):
|
|||||||
# self.getFilterOptions().getFreq()[1])
|
# self.getFilterOptions().getFreq()[1])
|
||||||
# else:
|
# else:
|
||||||
|
|
||||||
self.typeOptions = [None, "bandpass", "bandstop", "lowpass", "highpass"]
|
self.typeOptions = ["bandpass", "bandstop", "lowpass", "highpass"]
|
||||||
|
|
||||||
self.resetButton = QPushButton('Reset')
|
self.resetButton = QPushButton('Reset')
|
||||||
self.resetButton.setToolTip('Reset filter settings to settings for automatic picking.')
|
self.resetButton.setToolTip('Reset filter settings to settings for automatic picking.')
|
||||||
@ -4900,6 +5081,8 @@ class FilterOptionsWidget(QWidget):
|
|||||||
self.freqmaxSpinBox.valueChanged.connect(self.checkAutoManu)
|
self.freqmaxSpinBox.valueChanged.connect(self.checkAutoManu)
|
||||||
self.checkAutoManu()
|
self.checkAutoManu()
|
||||||
|
|
||||||
|
self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||||
|
|
||||||
def checkAutoManu(self):
|
def checkAutoManu(self):
|
||||||
self.updateMFfromWidget()
|
self.updateMFfromWidget()
|
||||||
|
|
||||||
|
@ -67,4 +67,3 @@ stylecolors = {
|
|||||||
'filename': 'bright.qss'}
|
'filename': 'bright.qss'}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
setup.py
2
setup.py
@ -8,7 +8,7 @@ setup(
|
|||||||
packages=['pylot', 'pylot.core', 'pylot.core.loc', 'pylot.core.pick',
|
packages=['pylot', 'pylot.core', 'pylot.core.loc', 'pylot.core.pick',
|
||||||
'pylot.core.io', 'pylot.core.util', 'pylot.core.active',
|
'pylot.core.io', 'pylot.core.util', 'pylot.core.active',
|
||||||
'pylot.core.analysis', 'pylot.testing'],
|
'pylot.core.analysis', 'pylot.testing'],
|
||||||
requires=['obspy', 'PySide', 'matplotlib', 'numpy'],
|
requires=['obspy', 'PySide', 'matplotlib', 'numpy', 'scipy', 'pyqtgraph'],
|
||||||
url='dummy',
|
url='dummy',
|
||||||
license='LGPLv3',
|
license='LGPLv3',
|
||||||
author='Sebastian Wehling-Benatelli',
|
author='Sebastian Wehling-Benatelli',
|
||||||
|
27
tests/__init__.py
Normal file
27
tests/__init__.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# Purpose: Convience imports for PyLoT
|
||||||
|
#
|
||||||
|
'''
|
||||||
|
================================================
|
||||||
|
PyLoT - the Python picking and Localization Tool
|
||||||
|
================================================
|
||||||
|
|
||||||
|
This python library contains a graphical user interfaces for picking
|
||||||
|
seismic phases. This software needs ObsPy (http://github.com/obspy/obspy/wiki)
|
||||||
|
and the Qt4 libraries to be installed first.
|
||||||
|
|
||||||
|
PILOT has been developed in Mathworks' MatLab. In order to distribute
|
||||||
|
PILOT without facing portability problems, it has been decided to re-
|
||||||
|
develop the software package in Python. The great work of the ObsPy
|
||||||
|
group allows easy handling of a bunch of seismic data and PyLoT will
|
||||||
|
benefit a lot compared to the former MatLab version.
|
||||||
|
|
||||||
|
The development of PyLoT is part of the joint research project MAGS2.
|
||||||
|
|
||||||
|
:copyright:
|
||||||
|
The PyLoT Development Team
|
||||||
|
:license:
|
||||||
|
GNU Lesser General Public License, Version 3
|
||||||
|
(http://www.gnu.org/copyleft/lesser.html)
|
||||||
|
'''
|
@ -1,32 +1,59 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from obspy import UTCDateTime
|
||||||
|
from obspy.io.xseed.utils import SEEDParserException
|
||||||
|
from obspy.io.xseed import Parser
|
||||||
from pylot.core.util.dataprocessing import Metadata
|
from pylot.core.util.dataprocessing import Metadata
|
||||||
|
from tests.utils import HidePrints
|
||||||
|
|
||||||
|
|
||||||
class TestMetadata(unittest.TestCase):
|
class TestMetadata(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.station_id = 'BW.WETR..HH'
|
self.station_id = 'BW.WETR..HH'
|
||||||
metadata_folder = 'metadata1'
|
self.time = UTCDateTime('2012-08-01')
|
||||||
|
metadata_folder = os.path.join('test_data', 'dless_multiple_files', 'metadata1')
|
||||||
self.m = Metadata(metadata_folder)
|
self.m = Metadata(metadata_folder)
|
||||||
|
|
||||||
def test_get_coordinates_sucess(self):
|
def test_get_coordinates_sucess(self):
|
||||||
expected = {'Z': {u'elevation': 607.0, u'longitude': 12.87571, u'local_depth': 0.0, u'azimuth': 0.0, u'latitude': 49.14502, u'dip': -90.0},
|
expected = {'Z': {u'elevation': 607.0, u'longitude': 12.87571, u'local_depth': 0.0, u'azimuth': 0.0,
|
||||||
'E': {u'azimuth': 90.0, u'dip': 0.0, u'elevation': 607.0, u'latitude': 49.14502, u'local_depth': 0.0, u'longitude': 12.87571},
|
u'latitude': 49.14502, u'dip': -90.0},
|
||||||
'N': {u'azimuth': 0.0, u'dip': 0.0, u'elevation': 607.0, u'latitude': 49.14502, u'local_depth': 0.0, u'longitude': 12.87571}
|
'E': {u'azimuth': 90.0, u'dip': 0.0, u'elevation': 607.0, u'latitude': 49.14502,
|
||||||
|
u'local_depth': 0.0, u'longitude': 12.87571},
|
||||||
|
'N': {u'azimuth': 0.0, u'dip': 0.0, u'elevation': 607.0, u'latitude': 49.14502, u'local_depth': 0.0,
|
||||||
|
u'longitude': 12.87571}
|
||||||
}
|
}
|
||||||
result = {}
|
result = {}
|
||||||
for channel in ('Z', 'N', 'E'):
|
for channel in ('Z', 'N', 'E'):
|
||||||
|
with HidePrints():
|
||||||
|
coords = self.m.get_coordinates(self.station_id+channel, time=self.time)
|
||||||
|
result[channel] = coords
|
||||||
|
self.assertDictEqual(result[channel], expected[channel])
|
||||||
|
|
||||||
|
def test_get_coordinates_sucess_no_time(self):
|
||||||
|
expected = {'Z': {u'elevation': 607.0, u'longitude': 12.87571, u'local_depth': 0.0, u'azimuth': 0.0,
|
||||||
|
u'latitude': 49.14502, u'dip': -90.0},
|
||||||
|
'E': {u'azimuth': 90.0, u'dip': 0.0, u'elevation': 607.0, u'latitude': 49.14502,
|
||||||
|
u'local_depth': 0.0, u'longitude': 12.87571},
|
||||||
|
'N': {u'azimuth': 0.0, u'dip': 0.0, u'elevation': 607.0, u'latitude': 49.14502, u'local_depth': 0.0,
|
||||||
|
u'longitude': 12.87571}
|
||||||
|
}
|
||||||
|
result = {}
|
||||||
|
for channel in ('Z', 'N', 'E'):
|
||||||
|
with HidePrints():
|
||||||
coords = self.m.get_coordinates(self.station_id+channel)
|
coords = self.m.get_coordinates(self.station_id+channel)
|
||||||
result[channel] = coords
|
result[channel] = coords
|
||||||
self.assertDictEqual(result[channel], expected[channel])
|
self.assertDictEqual(result[channel], expected[channel])
|
||||||
|
|
||||||
|
|
||||||
class TestMetadataAdding(unittest.TestCase):
|
class TestMetadataAdding(unittest.TestCase):
|
||||||
"""Tests if adding files and directories to a metadata object works."""
|
"""Tests if adding files and directories to a metadata object works."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.station_id = 'BW.WETR..HH'
|
self.station_id = 'BW.WETR..HH'
|
||||||
self.metadata_folders = ('metadata1', 'metadata2')
|
self.metadata_folders = (os.path.join('test_data', 'dless_multiple_files', 'metadata1'),
|
||||||
|
os.path.join('test_data', 'dless_multiple_files', 'metadata2'))
|
||||||
self.m = Metadata()
|
self.m = Metadata()
|
||||||
|
|
||||||
def test_add_inventory_folder(self):
|
def test_add_inventory_folder(self):
|
||||||
@ -43,8 +70,10 @@ class TestMetadataAdding(unittest.TestCase):
|
|||||||
fpath = os.path.join(self.metadata_folders[0], 'DATALESS.BW.WETR..HHZ')
|
fpath = os.path.join(self.metadata_folders[0], 'DATALESS.BW.WETR..HHZ')
|
||||||
self.m.add_inventory_file(fpath)
|
self.m.add_inventory_file(fpath)
|
||||||
# adding an inventory file should append its folder to the list of inventories and the file to the
|
# adding an inventory file should append its folder to the list of inventories and the file to the
|
||||||
self.assertEqual(['metadata1/DATALESS.BW.WETR..HHZ'], self.m.inventory_files.keys()) # does the filename exist in inventory files?
|
self.assertEqual([os.path.join(self.metadata_folders[0], 'DATALESS.BW.WETR..HHZ')],
|
||||||
self.assertEqual(['data', 'invtype'], self.m.inventory_files['metadata1/DATALESS.BW.WETR..HHZ'].keys()) # is the required information attacht to the filename?
|
self.m.inventory_files.keys()) # does the filename exist in inventory files?
|
||||||
|
self.assertEqual(['data', 'invtype'], self.m.inventory_files[os.path.join(self.metadata_folders[0],
|
||||||
|
'DATALESS.BW.WETR..HHZ')].keys()) # is the required information attacht to the filename?
|
||||||
self.assertDictEqual({}, self.m.seed_ids)
|
self.assertDictEqual({}, self.m.seed_ids)
|
||||||
self.assertEqual([self.metadata_folders[0]], self.m.inventories)
|
self.assertEqual([self.metadata_folders[0]], self.m.inventories)
|
||||||
|
|
||||||
@ -66,7 +95,8 @@ class TestMetadataRemoval(unittest.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.station_id = 'BW.WETR..HH'
|
self.station_id = 'BW.WETR..HH'
|
||||||
self.metadata_folders = ('metadata1', 'metadata2')
|
self.metadata_folders = (os.path.join('test_data', 'dless_multiple_files', 'metadata1'),
|
||||||
|
os.path.join('test_data', 'dless_multiple_files', 'metadata2'))
|
||||||
self.m = Metadata()
|
self.m = Metadata()
|
||||||
|
|
||||||
def test_remove_all_inventories(self):
|
def test_remove_all_inventories(self):
|
||||||
@ -93,6 +123,7 @@ class TestMetadataRemoval(unittest.TestCase):
|
|||||||
exist in the instance."""
|
exist in the instance."""
|
||||||
# add multiple inventories
|
# add multiple inventories
|
||||||
self.m.add_inventory(self.metadata_folders[0])
|
self.m.add_inventory(self.metadata_folders[0])
|
||||||
|
with HidePrints():
|
||||||
self.m.remove_inventory('metadata_not_existing')
|
self.m.remove_inventory('metadata_not_existing')
|
||||||
self.assertIn(self.metadata_folders[0], self.m.inventories)
|
self.assertIn(self.metadata_folders[0], self.m.inventories)
|
||||||
|
|
||||||
@ -102,3 +133,202 @@ class TestMetadataRemoval(unittest.TestCase):
|
|||||||
self.assertDictEqual({}, metadata.seed_ids)
|
self.assertDictEqual({}, metadata.seed_ids)
|
||||||
self.assertEqual([], metadata.inventories)
|
self.assertEqual([], metadata.inventories)
|
||||||
|
|
||||||
|
|
||||||
|
class TestMetadata_read_single_file(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.station_id = 'BW.WETR..HHZ'
|
||||||
|
self.metadata_folders = (os.path.join('test_data', 'dless_multiple_files', 'metadata1'),
|
||||||
|
os.path.join('test_data', 'dless_multiple_files', 'metadata2'))
|
||||||
|
self.metadata_paths = []
|
||||||
|
self.m = Metadata()
|
||||||
|
|
||||||
|
def test_read_single_file(self):
|
||||||
|
"""Test if reading a single file works"""
|
||||||
|
fname = os.path.join(self.metadata_folders[0], 'DATALESS.'+self.station_id)
|
||||||
|
with HidePrints():
|
||||||
|
res = self.m.read_single_file(fname)
|
||||||
|
# method should return true if file is successfully read
|
||||||
|
self.assertTrue(res)
|
||||||
|
# list of inventories (folders) should be empty
|
||||||
|
self.assertEqual([], self.m.inventories)
|
||||||
|
# list of inventory files should contain the added file
|
||||||
|
self.assertIn(fname, self.m.inventory_files.keys())
|
||||||
|
self.assertEqual({}, self.m.seed_ids)
|
||||||
|
|
||||||
|
def test_read_single_file_invalid_path(self):
|
||||||
|
"""Test if reading from a non existing file fails. The filename should not be
|
||||||
|
added to the metadata object"""
|
||||||
|
fname = os.path.join("this", "path", "doesnt", "exist")
|
||||||
|
with HidePrints():
|
||||||
|
res = self.m.read_single_file(fname)
|
||||||
|
# method should return None if file reading fails
|
||||||
|
self.assertIsNone(res)
|
||||||
|
# list of inventories (folders) should be empty
|
||||||
|
self.assertEqual([], self.m.inventories)
|
||||||
|
# list of inventory files should not contain the added file
|
||||||
|
self.assertNotIn(fname, self.m.inventory_files.keys())
|
||||||
|
self.assertEqual({}, self.m.seed_ids)
|
||||||
|
|
||||||
|
def test_read_single_file_multiple_times(self):
|
||||||
|
"""Test if reading a file twice doesnt add it twice to the metadata object"""
|
||||||
|
fname = os.path.join(self.metadata_folders[0], 'DATALESS.'+self.station_id)
|
||||||
|
with HidePrints():
|
||||||
|
res1 = self.m.read_single_file(fname)
|
||||||
|
res2 = self.m.read_single_file(fname)
|
||||||
|
self.assertTrue(res1)
|
||||||
|
self.assertIsNone(res2)
|
||||||
|
self.assertItemsEqual([fname], self.m.inventory_files.keys())
|
||||||
|
|
||||||
|
|
||||||
|
class TestMetadataMultipleTime(unittest.TestCase):
|
||||||
|
"""Test if stations with multiple metadata entries in a single file are handled correctly.
|
||||||
|
The user must specify the time where he wants to get metadata.
|
||||||
|
|
||||||
|
The station ROTT changed has metadata available at multiple times
|
||||||
|
LE.ROTT..HNE | 200.00 Hz | Titan 4g-EDR-209, Very Low gain, 200 sps | 2015-01-08 - 2015-03-19 | Lat: 49.1, Lng: 8.1
|
||||||
|
LE.ROTT..HNE | 200.00 Hz | Titan 4g-EDR-209, Very Low gain, 200 sps | 2015-03-19 - | Lat: 49.1, Lng: 8.1
|
||||||
|
LE.ROTT..HNN | 200.00 Hz | Titan 4g-EDR-209, Very Low gain, 200 sps | 2015-01-08 - 2015-03-19 | Lat: 49.1, Lng: 8.1
|
||||||
|
LE.ROTT..HNN | 200.00 Hz | Titan 4g-EDR-209, Very Low gain, 200 sps | 2015-03-19 - | Lat: 49.1, Lng: 8.1
|
||||||
|
LE.ROTT..HNZ | 200.00 Hz | Titan 4g-EDR-209, Very Low gain, 200 sps | 2015-01-08 - 2015-03-19 | Lat: 49.1, Lng: 8.1
|
||||||
|
LE.ROTT..HNZ | 200.00 Hz | Titan 4g-EDR-209, Very Low gain, 200 sps | 2015-03-19 - | Lat: 49.1, Lng: 8.1
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.seed_id = 'LE.ROTT..HN'
|
||||||
|
path = os.path.dirname(__file__) # gets path to currently running script
|
||||||
|
metadata = os.path.join('test_data', 'dless_multiple_times', 'MAGS2_LE_ROTT.dless') # specific subfolder of test data
|
||||||
|
metadata_path = os.path.join(path, metadata)
|
||||||
|
self.m = Metadata(metadata_path)
|
||||||
|
self.p = Parser(metadata_path)
|
||||||
|
|
||||||
|
def test_get_metadata_works_without_datetime(self):
|
||||||
|
"""Test if get_metadata works if multiple metadata entries are available but no time is
|
||||||
|
specified."""
|
||||||
|
for channel in ('Z', 'N', 'E'):
|
||||||
|
with HidePrints():
|
||||||
|
md = self.m.get_metadata(self.seed_id + channel)
|
||||||
|
self.assertDictEqual(md['data'].get_inventory(), self.p.get_inventory())
|
||||||
|
|
||||||
|
def test_get_metadata_works_with_first_datetime(self):
|
||||||
|
"""Test if get_metadata works if multiple metadata entries are available and the older time is specified."""
|
||||||
|
t = UTCDateTime('2015-02-08')
|
||||||
|
for channel in ('Z', 'N', 'E'):
|
||||||
|
with HidePrints():
|
||||||
|
md = self.m.get_metadata(self.seed_id + channel, t)
|
||||||
|
self.assertDictEqual(md['data'].get_inventory(), self.p.get_inventory())
|
||||||
|
|
||||||
|
def test_get_metadata_fails_when_time_before_starttime(self):
|
||||||
|
"""Tests if get_metadata returns None when given a data that is before the start date
|
||||||
|
of the metadata"""
|
||||||
|
with HidePrints():
|
||||||
|
md = self.m.get_metadata(self.seed_id, UTCDateTime('1960-07-20'))
|
||||||
|
self.assertIs(md, None)
|
||||||
|
|
||||||
|
def test_get_metadata_invalid_seed_id(self):
|
||||||
|
"""Tes if get metadata returns none when asked for a seed id that does not exist"""
|
||||||
|
with HidePrints():
|
||||||
|
res = self.m.get_metadata("this.doesnt..exist")
|
||||||
|
self.assertIsNone(res)
|
||||||
|
|
||||||
|
|
||||||
|
class TestMetadataMultipleEntries(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
The station KB.TMO07 has changed instruments multiple times.
|
||||||
|
Networks:
|
||||||
|
KB (KB network)
|
||||||
|
Stations:
|
||||||
|
KB.TMO07 (Karlsruhe GPI)
|
||||||
|
Channels:
|
||||||
|
KB.TMO07.00.BHE | 50.00 Hz | Streckeisen KABBA-STS-2 | 2004-12-06 - 2005-04-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHE | 50.00 Hz | Streckeisen KABBA-STS-2 | 2005-04-18 - 2006-07-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHE | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2006-10-10 - 2006-11-14 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHE | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2006-11-24 - 2007-01-12 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHE | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-01-18 - 2007-03-15 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHE | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-10-25 - 2007-11-21 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHE | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-11-21 - 2008-01-17 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHN | 50.00 Hz | Streckeisen KABBA-STS-2 | 2004-12-06 - 2005-04-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHN | 50.00 Hz | Streckeisen KABBA-STS-2 | 2005-04-18 - 2006-07-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHN | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2006-10-10 - 2006-11-14 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHN | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2006-11-24 - 2007-01-12 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHN | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-01-18 - 2007-03-15 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHN | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-10-25 - 2007-11-21 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHN | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-11-21 - 2008-01-17 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHZ | 50.00 Hz | Streckeisen KABBA-STS-2 | 2004-12-06 - 2005-04-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHZ | 50.00 Hz | Streckeisen KABBA-STS-2 | 2005-04-18 - 2006-07-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHZ | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2006-10-10 - 2006-11-14 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHZ | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2006-11-24 - 2007-01-12 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHZ | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-01-18 - 2007-03-15 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHZ | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-10-25 - 2007-11-21 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.BHZ | 50.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-11-21 - 2008-01-17 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 100.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-01-12 - 2007-01-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 100.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-10-10 - 2007-10-25 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 100.00 Hz | Streckeisen KABBA-STS-2 | 2008-07-11 - 2008-12-05 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 100.00 Hz | Streckeisen KABBA-STS-2 | 2009-05-12 - 2010-02-15 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 100.00 Hz | Streckeisen KABBA-STS-2 | 2010-02-15 - 2010-04-07 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 100.00 Hz | Lennartz KABBA-LE-3D/1 | 2010-04-07 - 2010-08-03 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 200.00 Hz | Streckeisen KABBA-STS-2 | 2010-08-05 - 2010-12-20 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 100.00 Hz | Streckeisen KABBA-STS-2 | 2010-12-20 - 2010-12-22 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 200.00 Hz | Streckeisen KABBA-STS-2 | 2010-12-22 - 2011-04-02 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 200.00 Hz | Streckeisen KABBA-STS-2 | 2011-04-15 - 2012-05-07 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHE | 200.00 Hz | Streckeisen KABBA-STS-2 | 2012-05-07 - | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 100.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-01-12 - 2007-01-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 100.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-10-10 - 2007-10-25 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 100.00 Hz | Streckeisen KABBA-STS-2 | 2008-07-11 - 2008-12-05 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 100.00 Hz | Streckeisen KABBA-STS-2 | 2009-05-12 - 2010-02-15 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 100.00 Hz | Streckeisen KABBA-STS-2 | 2010-02-15 - 2010-04-07 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 100.00 Hz | Lennartz KABBA-LE-3D/1 | 2010-04-07 - 2010-08-03 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 200.00 Hz | Streckeisen KABBA-STS-2 | 2010-08-05 - 2010-12-20 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 100.00 Hz | Streckeisen KABBA-STS-2 | 2010-12-20 - 2010-12-22 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 200.00 Hz | Streckeisen KABBA-STS-2 | 2010-12-22 - 2011-04-02 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 200.00 Hz | Streckeisen KABBA-STS-2 | 2011-04-15 - 2012-05-07 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHN | 200.00 Hz | Streckeisen KABBA-STS-2 | 2012-05-07 - | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 100.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-01-12 - 2007-01-18 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 100.00 Hz | Lennartz KABBA-LE-3D/5 | 2007-10-10 - 2007-10-25 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 100.00 Hz | Streckeisen KABBA-STS-2 | 2008-07-11 - 2008-12-05 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 100.00 Hz | Streckeisen KABBA-STS-2 | 2009-05-12 - 2010-02-15 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 100.00 Hz | Streckeisen KABBA-STS-2 | 2010-02-15 - 2010-04-07 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 100.00 Hz | Lennartz KABBA-LE-3D/1 | 2010-04-07 - 2010-08-03 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 200.00 Hz | Streckeisen KABBA-STS-2 | 2010-08-05 - 2010-12-20 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 100.00 Hz | Streckeisen KABBA-STS-2 | 2010-12-20 - 2010-12-22 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 200.00 Hz | Streckeisen KABBA-STS-2 | 2010-12-22 - 2011-04-02 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 200.00 Hz | Streckeisen KABBA-STS-2 | 2011-04-15 - 2012-05-07 | Lat: 49.0, Lng: 8.4
|
||||||
|
KB.TMO07.00.HHZ | 200.00 Hz | Streckeisen KABBA-STS-2 | 2012-05-07 - | Lat: 49.0, Lng: 8.4
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.seed_id = 'KB.TMO07.00.HHZ'
|
||||||
|
path = os.path.dirname(__file__) # gets path to currently running script
|
||||||
|
metadata = os.path.join('test_data', 'dless_multiple_instruments', 'MAGS2_KB_TMO07.dless') # specific subfolder of test data
|
||||||
|
metadata_path = os.path.join(path, metadata)
|
||||||
|
self.m = Metadata(metadata_path)
|
||||||
|
self.p = Parser(metadata_path)
|
||||||
|
|
||||||
|
def test_get_paz_current_time(self):
|
||||||
|
"""Test if getting the paz from the metadata object with the current time works"""
|
||||||
|
t = UTCDateTime()
|
||||||
|
with HidePrints():
|
||||||
|
pazm = self.m.get_paz(self.seed_id, t)
|
||||||
|
pazp = self.p.get_paz(self.seed_id, t)
|
||||||
|
self.assertEqual(pazm, pazp)
|
||||||
|
|
||||||
|
def test_get_paz_past(self):
|
||||||
|
"""Test if getting paz from metadata object with a time in the past works"""
|
||||||
|
t = UTCDateTime('2007-01-13')
|
||||||
|
with HidePrints():
|
||||||
|
pazm = self.m.get_paz(self.seed_id, t)
|
||||||
|
pazp = self.p.get_paz(self.seed_id, t)
|
||||||
|
self.assertEqual(pazm, pazp)
|
||||||
|
|
||||||
|
def test_get_paz_time_not_exisiting(self):
|
||||||
|
"""Test if getting paz from metadata at a time where there is no metadata
|
||||||
|
available fails correctly"""
|
||||||
|
with self.assertRaises(SEEDParserException):
|
||||||
|
with HidePrints():
|
||||||
|
self.m.get_paz(self.seed_id, UTCDateTime('1990-1-1'))
|
||||||
|
|
||||||
|
def test_get_paz_seed_id_not_existing(self):
|
||||||
|
"""Test if getting paz from a non existing seed id returns None as expected."""
|
||||||
|
with HidePrints():
|
||||||
|
res = self.m.get_paz('This.doesnt..exist', UTCDateTime)
|
||||||
|
self.assertIsNone(res)
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
52
tests/utils.py
Normal file
52
tests/utils.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Utilities/helpers for testing"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class HidePrints:
|
||||||
|
"""
|
||||||
|
Context manager that hides all standard output within its body.
|
||||||
|
The optional hide_prints argument can be used to quickly enable printing during debugging of tests.
|
||||||
|
|
||||||
|
|
||||||
|
Use (This will result in all console output of noisy_function to be suppressed):
|
||||||
|
from tests.utils import HidePrints
|
||||||
|
with HidePrints():
|
||||||
|
noise_function()
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hide(func, *args, **kwargs):
|
||||||
|
"""Decorator that hides all prints of the decorated function.
|
||||||
|
|
||||||
|
Use:
|
||||||
|
from tests.utils import HidePrints
|
||||||
|
@HidePrints.hide
|
||||||
|
def noise()
|
||||||
|
print("NOISE")
|
||||||
|
"""
|
||||||
|
|
||||||
|
def silencer(*args, **kwargs):
|
||||||
|
with HidePrints():
|
||||||
|
func(*args, **kwargs)
|
||||||
|
return silencer
|
||||||
|
|
||||||
|
def __init__(self, hide_prints=True):
|
||||||
|
"""Create object with hide_prints=False to disable print hiding"""
|
||||||
|
self.hide = hide_prints
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
"""Redirect stdout to /dev/null, save old stdout"""
|
||||||
|
if self.hide:
|
||||||
|
self._original_stdout = sys.stdout
|
||||||
|
devnull = open(os.devnull, "w")
|
||||||
|
sys.stdout = devnull
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
"""Reinstate old stdout"""
|
||||||
|
if self.hide:
|
||||||
|
sys.stdout = self._original_stdout
|
Loading…
Reference in New Issue
Block a user