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.rcParams['backend.qt4'] = 'PySide'
|
||||
matplotlib.rcParams['savefig.dpi'] = 300
|
||||
|
||||
|
||||
from PySide import QtGui, QtCore
|
||||
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
|
||||
|
||||
|
||||
try:
|
||||
import pyqtgraph as pg
|
||||
except Exception as e:
|
||||
print('PyLoT: Could not import pyqtgraph. {}'.format(e))
|
||||
pg = None
|
||||
|
||||
try:
|
||||
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 autoPyLoT import autoPyLoT
|
||||
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
|
||||
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, \
|
||||
OverwriteError
|
||||
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, \
|
||||
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, \
|
||||
check_all_pylot, real_Bool
|
||||
check_all_pylot, real_Bool, SetChannelComponents
|
||||
from pylot.core.util.event import Event
|
||||
from pylot.core.io.location import create_creation_info, create_event
|
||||
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||
getDataType, ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||
CompareEventsWidget
|
||||
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget
|
||||
from pylot.core.util.array_map import Array_map
|
||||
from pylot.core.util.structure import DATASTRUCTURE
|
||||
from pylot.core.util.thread import Thread, Worker
|
||||
@ -121,7 +118,7 @@ class MainWindow(QMainWindow):
|
||||
self.apw = None
|
||||
self.paraBox = None
|
||||
self.array_map = None
|
||||
self._metadata = None
|
||||
self._metadata = Metadata()
|
||||
self._eventChanged = [False, False]
|
||||
self.apd_local = None
|
||||
self.apd_sge = None
|
||||
@ -135,6 +132,9 @@ class MainWindow(QMainWindow):
|
||||
self._ctrl = False # control key pressed
|
||||
self._shift = False # shift key pressed
|
||||
|
||||
self.drawnPicks = {'auto': {},
|
||||
'manual': {}}
|
||||
|
||||
# default factor for dataplot e.g. enabling/disabling scrollarea
|
||||
self.height_factor = 12
|
||||
self.plot_method = 'normal'
|
||||
@ -155,6 +155,8 @@ class MainWindow(QMainWindow):
|
||||
self.data._new = False
|
||||
self.autodata = Data(self)
|
||||
|
||||
while True:
|
||||
try:
|
||||
if settings.value("user/FullName", None) is None:
|
||||
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
|
||||
settings.setValue("user/FullName", fulluser)
|
||||
@ -164,6 +166,21 @@ class MainWindow(QMainWindow):
|
||||
"Enter authority/institution name:",
|
||||
"Authority")
|
||||
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._stime = None
|
||||
structure_setting = settings.value("data/Structure", "PILOT")
|
||||
@ -195,7 +212,6 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.loc = False
|
||||
|
||||
|
||||
def init_config_files(self, infile):
|
||||
pylot_config_dir = os.path.join(os.path.expanduser('~'), '.pylot')
|
||||
if not os.path.exists(pylot_config_dir):
|
||||
@ -210,7 +226,6 @@ class MainWindow(QMainWindow):
|
||||
self._inputs.export2File(infile)
|
||||
self.infile = infile
|
||||
|
||||
|
||||
def setupUi(self):
|
||||
try:
|
||||
self.startTime = min(
|
||||
@ -339,7 +354,7 @@ class MainWindow(QMainWindow):
|
||||
"Ctrl+A",
|
||||
openEventsIcon,
|
||||
"Load event data automatically "
|
||||
"for for all events.")
|
||||
"for all events.")
|
||||
self.openEventsAutoAction.setEnabled(False)
|
||||
self.openEventsAutoAction.setData(None)
|
||||
|
||||
@ -398,10 +413,10 @@ class MainWindow(QMainWindow):
|
||||
self.adjustFilterOptions,
|
||||
"Ctrl+F", self.filter_icon,
|
||||
"""Adjust filter parameters.""")
|
||||
self.inventoryAction = self.createAction(self, "Select &Inventory ...",
|
||||
self.get_new_metadata,
|
||||
self.inventoryAction = self.createAction(self, "Manage &Inventories ...",
|
||||
self.add_metadata,
|
||||
"Ctrl+I", self.inventoryIcon,
|
||||
"""Select metadata for current project""",
|
||||
"""Manage metadata for current project""",
|
||||
False)
|
||||
self.initMapAction = self.createAction(self, "Init array map ...",
|
||||
self.init_array_map,
|
||||
@ -428,6 +443,8 @@ class MainWindow(QMainWindow):
|
||||
slot=self.pickQualities, shortcut='Alt+Q',
|
||||
icon=qualities_icon, tip='Histogram of pick qualities')
|
||||
self.qualities_action.setEnabled(False)
|
||||
# MP MP not yet implemented, therefore hide:
|
||||
self.qualities_action.setVisible(False)
|
||||
|
||||
printAction = self.createAction(self, "&Print event ...",
|
||||
self.show_event_information, QKeySequence.Print,
|
||||
@ -471,7 +488,6 @@ class MainWindow(QMainWindow):
|
||||
checkable=True)
|
||||
self.e_action.setEnabled(False)
|
||||
|
||||
|
||||
componentActions = (self.z_action, self.n_action, self.e_action)
|
||||
|
||||
self.auto_tune = self.createAction(parent=self, text='autoTune',
|
||||
@ -504,15 +520,15 @@ class MainWindow(QMainWindow):
|
||||
# pickToolActions = (selectStation, )
|
||||
# pickToolBar.setObjectName("PickTools")
|
||||
# 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,
|
||||
shortcut='Alt+Ctrl+L',
|
||||
icon=locate_icon,
|
||||
tip='Locate the event using '
|
||||
'the displayed manual arrivals.')
|
||||
self.locateEvent.setEnabled(False)
|
||||
self.locateEventAction.setEnabled(False)
|
||||
|
||||
locationToolActions = (self.locateEvent,)
|
||||
locationToolActions = (self.locateEventAction,)
|
||||
|
||||
# add top menu
|
||||
self.fileMenu = self.menuBar().addMenu('&File')
|
||||
@ -546,13 +562,11 @@ class MainWindow(QMainWindow):
|
||||
self.openProjectAction, self.saveProjectAction,
|
||||
self.saveProjectAsAction)
|
||||
|
||||
|
||||
eventToolActions = (self.addEventDataAction,
|
||||
self.openEventAction, self.openEventsAutoAction,
|
||||
self.saveEventAction, self.loadlocationaction,
|
||||
self.loadpilotevent)
|
||||
|
||||
|
||||
toolbars_keys = [
|
||||
"FileTools",
|
||||
"EventTools",
|
||||
@ -616,7 +630,7 @@ class MainWindow(QMainWindow):
|
||||
self.tabs.currentChanged.connect(self.refreshTabs)
|
||||
|
||||
# add progressbar
|
||||
self.mainProgressBarWidget = QtGui.QWidget()
|
||||
self.mainProgressBarWidget = ProgressBarWidget(self)
|
||||
self._main_layout.addWidget(self.mainProgressBarWidget)
|
||||
|
||||
# add scroll area used in case number of traces gets too high
|
||||
@ -672,15 +686,9 @@ class MainWindow(QMainWindow):
|
||||
self.setCentralWidget(_widget)
|
||||
|
||||
def init_wfWidget(self):
|
||||
settings = QSettings()
|
||||
xlab = self.startTime.strftime('seconds since %Y/%m/%d %H:%M:%S (%Z)')
|
||||
plottitle = None # "Overview: {0} components ".format(self.getComponent())
|
||||
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.dataPlot = WaveformWidgetPG(parent=self,
|
||||
title=plottitle)
|
||||
@ -860,7 +868,8 @@ class MainWindow(QMainWindow):
|
||||
def inputs(self):
|
||||
return self._inputs
|
||||
|
||||
def getRoot(self):
|
||||
@staticmethod
|
||||
def getRoot():
|
||||
settings = QSettings()
|
||||
return settings.value("data/dataRoot")
|
||||
|
||||
@ -900,6 +909,7 @@ class MainWindow(QMainWindow):
|
||||
return
|
||||
if self.get_current_event().pylot_picks:
|
||||
self.refreshEvents()
|
||||
self.fill_eventbox()
|
||||
self.setDirty(True)
|
||||
|
||||
def load_data(self, fname=None, loc=False, draw=True, event=None, overwrite=False):
|
||||
@ -934,7 +944,9 @@ class MainWindow(QMainWindow):
|
||||
return
|
||||
|
||||
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:
|
||||
self.updatePicks(type='auto', event=event)
|
||||
self.updatePicks(type='manual', event=event)
|
||||
@ -1019,7 +1031,8 @@ class MainWindow(QMainWindow):
|
||||
raise DatastructureError('not specified')
|
||||
return fnames
|
||||
|
||||
def getPhaseID(self, phase):
|
||||
@staticmethod
|
||||
def getPhaseID(phase):
|
||||
return identifyPhaseID(phase)
|
||||
|
||||
def get_current_event(self, eventbox=None):
|
||||
@ -1028,7 +1041,7 @@ class MainWindow(QMainWindow):
|
||||
'''
|
||||
if not eventbox:
|
||||
eventbox = self.eventBox
|
||||
path = eventbox.currentText()
|
||||
path = eventbox.currentText().split('*')[0]
|
||||
return self.project.getEventFromPath(path)
|
||||
|
||||
def get_current_event_path(self, eventbox=None):
|
||||
@ -1065,7 +1078,7 @@ class MainWindow(QMainWindow):
|
||||
self.dataStructure = DATASTRUCTURE['obspyDMT']()
|
||||
eventlist = check_all_obspy(eventlist)
|
||||
else:
|
||||
print('Settings Datastructure to PILOT')
|
||||
print('Setting Datastructure to PILOT')
|
||||
self.dataStructure = DATASTRUCTURE['PILOT']()
|
||||
eventlist = check_all_pylot(eventlist)
|
||||
if not eventlist:
|
||||
@ -1147,7 +1160,8 @@ class MainWindow(QMainWindow):
|
||||
self.project.remove_event(event)
|
||||
self.init_events(True)
|
||||
|
||||
def createEventBox(self):
|
||||
@staticmethod
|
||||
def createEventBox():
|
||||
'''
|
||||
Eventbox generator.
|
||||
'''
|
||||
@ -1257,6 +1271,8 @@ class MainWindow(QMainWindow):
|
||||
'auto': event.pylot_autopicks}
|
||||
ma_count = {'manual': 0,
|
||||
'auto': 0}
|
||||
ma_count_total = {'manual': 0,
|
||||
'auto': 0}
|
||||
|
||||
for ma in ma_props.keys():
|
||||
if ma_props[ma]:
|
||||
@ -1264,8 +1280,9 @@ class MainWindow(QMainWindow):
|
||||
for phasename, pick in picks.items():
|
||||
if not type(pick) in [dict, AttribDict]:
|
||||
continue
|
||||
if get_quality_class(has_spe(pick), phaseErrors[self.getPhaseID(phasename)]) < 4:
|
||||
if pick.get('spe'):
|
||||
ma_count[ma] += 1
|
||||
ma_count_total[ma] += 1
|
||||
|
||||
event_ref = event.isRefEvent()
|
||||
event_test = event.isTestEvent()
|
||||
@ -1287,15 +1304,18 @@ class MainWindow(QMainWindow):
|
||||
# p=event_npicks,
|
||||
# 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_lat = QtGui.QStandardItem('{}'.format(lat))
|
||||
item_lon = QtGui.QStandardItem('{}'.format(lon))
|
||||
item_depth = QtGui.QStandardItem('{}'.format(depth))
|
||||
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_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_ref = QtGui.QStandardItem() # str(event_ref))
|
||||
item_test = QtGui.QStandardItem() # str(event_test))
|
||||
@ -1330,7 +1350,7 @@ class MainWindow(QMainWindow):
|
||||
self.setItemColor(itemlist, id, event, current_event)
|
||||
|
||||
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'
|
||||
'{} unequal {}.'
|
||||
.format(event.path, self.eventBox.itemText(id)))
|
||||
@ -1429,15 +1449,24 @@ class MainWindow(QMainWindow):
|
||||
self.update_status(msg)
|
||||
print(msg)
|
||||
|
||||
event.dirty = False
|
||||
self.fill_eventbox()
|
||||
return True
|
||||
|
||||
def exportAllEvents(self, outformats=['.xml']):
|
||||
for event in self.project.eventlist:
|
||||
def exportEvents(self, outformats=['.xml'], events='all'):
|
||||
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)
|
||||
try:
|
||||
self.saveData(event, event.path, outformats)
|
||||
event.dirty = False
|
||||
except Exception as e:
|
||||
print('WARNING! Could not save event {}. Reason: {}'.format(event.path, e))
|
||||
self.fill_eventbox()
|
||||
|
||||
def enableSaveEventAction(self):
|
||||
self.saveEventAction.setEnabled(True)
|
||||
@ -1485,7 +1514,6 @@ class MainWindow(QMainWindow):
|
||||
if len(eventdict) < 1:
|
||||
return
|
||||
|
||||
|
||||
# init event selection options for autopick
|
||||
self.compareoptions = [('tune events', self.get_ref_events, self._style['ref']['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.show()
|
||||
|
||||
|
||||
def buildMultiCompareWidget(self, eventlist):
|
||||
global_comparison = Comparison(eventlist=eventlist)
|
||||
compare_widget = ComparisonWidget(global_comparison, self)
|
||||
@ -1911,7 +1938,7 @@ class MainWindow(QMainWindow):
|
||||
event = self.get_current_event()
|
||||
if event.pylot_picks:
|
||||
self.drawPicks(picktype='manual')
|
||||
self.locateEvent.setEnabled(True)
|
||||
self.locateEventAction.setEnabled(True)
|
||||
self.qualities_action.setEnabled(True)
|
||||
if event.pylot_autopicks:
|
||||
self.drawPicks(picktype='auto')
|
||||
@ -1919,8 +1946,18 @@ class MainWindow(QMainWindow):
|
||||
if True in self.comparable.values():
|
||||
self.compare_action.setEnabled(True)
|
||||
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:
|
||||
for station in event.pylot_picks:
|
||||
if station in event.pylot_autopicks:
|
||||
@ -1972,6 +2009,9 @@ class MainWindow(QMainWindow):
|
||||
self.openEventAction.setEnabled(False)
|
||||
self.openEventsAutoAction.setEnabled(False)
|
||||
self.loadpilotevent.setEnabled(False)
|
||||
self.compare_action.setEnabled(False)
|
||||
self.qualities_action.setEnabled(False)
|
||||
self.locateEventAction.setEnabled(False)
|
||||
if not refresh_plot:
|
||||
self.wf_scroll_area.setVisible(False)
|
||||
self.no_data_label.setVisible(True)
|
||||
@ -2081,7 +2121,8 @@ class MainWindow(QMainWindow):
|
||||
elif self.filterActionS.isChecked():
|
||||
phase = 'S'
|
||||
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()
|
||||
self.pushFilterWF(kwargs)
|
||||
else:
|
||||
@ -2321,14 +2362,12 @@ class MainWindow(QMainWindow):
|
||||
if pickDlg._dirty:
|
||||
self.setDirty(True)
|
||||
self.update_status('picks accepted ({0})'.format(station))
|
||||
replot1 = 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='manual'), type='manual')
|
||||
self.addPicks(station, pickDlg.getPicks(picktype='auto'), type='auto')
|
||||
self.enableSaveEventAction()
|
||||
if replot1 or replot2:
|
||||
self.plotWaveformDataThread()
|
||||
|
||||
self.draw()
|
||||
else:
|
||||
self.comparable = self.checkEvents4comparison()
|
||||
if True in self.comparable.values():
|
||||
self.compare_action.setEnabled(True)
|
||||
self.drawPicks(station)
|
||||
self.draw()
|
||||
if self.nextStation:
|
||||
@ -2336,7 +2375,7 @@ class MainWindow(QMainWindow):
|
||||
else:
|
||||
self.update_status('picks discarded ({0})'.format(station))
|
||||
if not self.get_loc_flag() and self.check4Loc():
|
||||
self.locateEvent.setEnabled(True)
|
||||
self.locateEventAction.setEnabled(True)
|
||||
self.set_loc_flag(True)
|
||||
elif self.get_loc_flag() and not self.check4Loc():
|
||||
self.set_loc_flag(False)
|
||||
@ -2425,7 +2464,7 @@ class MainWindow(QMainWindow):
|
||||
# else:
|
||||
# self.update_autopicker()
|
||||
# self.tap.fill_eventbox()
|
||||
self.tap.show()
|
||||
self.tap.showMaximized()
|
||||
|
||||
def update_autopicker(self):
|
||||
'''
|
||||
@ -2437,11 +2476,13 @@ class MainWindow(QMainWindow):
|
||||
canvas.setZoomBorders2content()
|
||||
if self.tap.pylot_picks:
|
||||
station = self.tap.get_current_station()
|
||||
p_pick = self.tap.pylot_picks[station]['P']
|
||||
s_pick = self.tap.pylot_picks[station]['S']
|
||||
p_pick = self.tap.pylot_picks[station].get('P')
|
||||
if 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)
|
||||
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)
|
||||
|
||||
def autoPick(self):
|
||||
@ -2495,7 +2536,7 @@ class MainWindow(QMainWindow):
|
||||
self.apw.enable(False)
|
||||
|
||||
# export current picks etc.
|
||||
self.exportAllEvents(['.xml'])
|
||||
self.exportEvents(['.xml'], events=events)
|
||||
|
||||
wfpath = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else ''
|
||||
# define arguments for picker
|
||||
@ -2554,13 +2595,15 @@ class MainWindow(QMainWindow):
|
||||
if event.pylot_id == eventID:
|
||||
return event
|
||||
|
||||
def get_event_paths(self, eventlist):
|
||||
@staticmethod
|
||||
def get_event_paths(eventlist):
|
||||
eventPaths = []
|
||||
for event in eventlist:
|
||||
eventPaths.append(event.path)
|
||||
return eventPaths
|
||||
|
||||
def get_event_ids(self, eventlist):
|
||||
@staticmethod
|
||||
def get_event_ids(eventlist):
|
||||
eventIDs = []
|
||||
for event in eventlist:
|
||||
eventIDs.append(event.pylot_id)
|
||||
@ -2647,12 +2690,25 @@ class MainWindow(QMainWindow):
|
||||
self.drawPicks(station, 'auto', stime)
|
||||
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 not station:
|
||||
for station in self.getPicks(type=picktype):
|
||||
self.drawPicks(station, picktype=picktype, stime=stime)
|
||||
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
|
||||
if not station in self.getPicks(type=picktype):
|
||||
return
|
||||
@ -2661,13 +2717,10 @@ class MainWindow(QMainWindow):
|
||||
plotID = self.getStationID(station)
|
||||
if plotID is None:
|
||||
return
|
||||
if self.pg:
|
||||
pw = self.getPlotWidget().plotWidget
|
||||
else:
|
||||
ax = self.getPlotWidget().axes[0]
|
||||
ylims = np.array([-.5, +.5]) + plotID
|
||||
|
||||
stat_picks = self.getPicks(type=picktype)[station]
|
||||
settings = QSettings()
|
||||
|
||||
for phase in stat_picks:
|
||||
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:
|
||||
return
|
||||
|
||||
phaseID = self.getPhaseID(phase)
|
||||
# get quality classes
|
||||
if self.getPhaseID(phase) == 'P':
|
||||
quality = get_quality_class(picks['spe'], self._inputs['timeerrorsP'])
|
||||
phaseID = 'P'
|
||||
elif self.getPhaseID(phase) == 'S':
|
||||
quality = get_quality_class(picks['spe'], self._inputs['timeerrorsS'])
|
||||
phaseID = 'S'
|
||||
if phaseID == 'P':
|
||||
quality = getQualityFromUncertainty(picks['spe'], self._inputs['timeerrorsP'])
|
||||
elif phaseID == 'S':
|
||||
quality = getQualityFromUncertainty(picks['spe'], self._inputs['timeerrorsS'])
|
||||
|
||||
# quality = getPickQuality(self.get_data().getWFData(),
|
||||
# stat_picks, self._inputs, phaseID,
|
||||
# compclass)
|
||||
|
||||
mpp = picks['mpp'] - stime
|
||||
if picks['epp'] and picks['lpp']:
|
||||
@ -2692,44 +2748,32 @@ class MainWindow(QMainWindow):
|
||||
lpp = None
|
||||
spe = picks['spe']
|
||||
|
||||
if not spe and epp and lpp:
|
||||
spe = symmetrize_error(mpp - epp, lpp - mpp)
|
||||
|
||||
if self.pg:
|
||||
if picktype == 'manual':
|
||||
if spe:
|
||||
if picks['epp'] and picks['lpp']:
|
||||
pen = make_pen(picktype, phaseID, 'epp', quality)
|
||||
pw.plot([epp, epp], ylims,
|
||||
alpha=.25, pen=pen, name='EPP')
|
||||
self.drawnPicks[picktype][station].append(pw.plot([epp, epp], ylims,
|
||||
alpha=.25, pen=pen, name='EPP'))
|
||||
pen = make_pen(picktype, phaseID, 'lpp', quality)
|
||||
pw.plot([lpp, lpp], ylims,
|
||||
alpha=.25, pen=pen, name='LPP')
|
||||
self.drawnPicks[picktype][station].append(pw.plot([lpp, lpp], ylims,
|
||||
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)
|
||||
if spe:
|
||||
# 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)
|
||||
# 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))
|
||||
self.drawnPicks[picktype][station].append(
|
||||
pw.plot([mpp, mpp], ylims, pen=pen, name='{}-Pick'.format(phase)))
|
||||
else:
|
||||
if picktype == 'manual':
|
||||
linestyle_mpp, width_mpp = pick_linestyle_plt(picktype, 'mpp')
|
||||
@ -2817,7 +2861,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.inventory_label = QLabel('No inventory set...')
|
||||
# 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.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.init_map_button, 3, 1)
|
||||
|
||||
self.metadata = None
|
||||
self.metadata_widget.setLayout(grid_layout)
|
||||
self.array_layout.addWidget(self.metadata_widget)
|
||||
|
||||
@ -2984,6 +3027,8 @@ class MainWindow(QMainWindow):
|
||||
'auto': event.pylot_autopicks}
|
||||
ma_count = {'manual': 0,
|
||||
'auto': 0}
|
||||
ma_count_total = {'manual': 0,
|
||||
'auto': 0}
|
||||
|
||||
for ma in ma_props.keys():
|
||||
if ma_props[ma]:
|
||||
@ -2991,8 +3036,9 @@ class MainWindow(QMainWindow):
|
||||
for phasename, pick in picks.items():
|
||||
if not type(pick) in [dict, AttribDict]:
|
||||
continue
|
||||
if get_quality_class(has_spe(pick), phaseErrors[self.getPhaseID(phasename)]) < 4:
|
||||
if pick.get('spe'):
|
||||
ma_count[ma] += 1
|
||||
ma_count_total[ma] += 1
|
||||
|
||||
# init table items for current row
|
||||
item_delete = QtGui.QTableWidgetItem()
|
||||
@ -3003,15 +3049,19 @@ class MainWindow(QMainWindow):
|
||||
item_lon = QtGui.QTableWidgetItem()
|
||||
item_depth = 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_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_ref = QtGui.QTableWidgetItem()
|
||||
item_test = 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 event.origins:
|
||||
origin = event.origins[0]
|
||||
@ -3089,66 +3139,23 @@ class MainWindow(QMainWindow):
|
||||
if event == current_event:
|
||||
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):
|
||||
settings = QSettings()
|
||||
self.metadata = self.rm_thread.data
|
||||
if settings.value('saveMetadata'):
|
||||
self.project.metadata = self.rm_thread.data
|
||||
self.project.inv_path = settings.value("inventoryFile")
|
||||
self.project.inventories = self.metadata.inventories
|
||||
if self.metadata.inventories:
|
||||
self.init_map_button.setEnabled(True)
|
||||
self.initMapAction.setEnabled(True)
|
||||
self.inventory_label.setText('Inventory set!')
|
||||
self.new_inv_button.setText('Set another inventory file')
|
||||
self.setDirty(True)
|
||||
|
||||
def get_new_metadata(self):
|
||||
self.init_metadata(new=True)
|
||||
def add_metadata(self):
|
||||
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 set_inv(settings):
|
||||
fninv, _ = QFileDialog.getOpenFileName(self, self.tr(
|
||||
"Select inventory..."), self.tr("Select file"))
|
||||
if not fninv:
|
||||
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)
|
||||
|
||||
if hasattr(self.project, 'inventories'):
|
||||
self.metadata = Metadata()
|
||||
for inventory in self.project.inventories:
|
||||
self.metadata.add_inventory(inventory)
|
||||
|
||||
def calc_magnitude(self, type='ML'):
|
||||
self.init_metadata()
|
||||
@ -3161,7 +3168,7 @@ class MainWindow(QMainWindow):
|
||||
# raise ProcessingError('Restitution of waveform data failed!')
|
||||
if type == 'ML':
|
||||
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()
|
||||
elif type == 'Mw':
|
||||
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:
|
||||
self._inputs = self.project.parameter
|
||||
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.init_events(new=True)
|
||||
self.setDirty(False)
|
||||
if hasattr(self.project, '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_metadata()
|
||||
|
||||
self.init_array_tab()
|
||||
self.set_metadata()
|
||||
|
||||
def saveProjectAs(self, exists=False):
|
||||
'''
|
||||
@ -3295,10 +3299,10 @@ class MainWindow(QMainWindow):
|
||||
if not filename.split('.')[-1] == 'plp':
|
||||
filename = fnm[0] + '.plp'
|
||||
self.project.parameter = self._inputs
|
||||
self.exportEvents()
|
||||
self.project.save(filename)
|
||||
self.setDirty(False)
|
||||
self.saveProjectAsAction.setEnabled(True)
|
||||
self.exportAllEvents()
|
||||
self.update_status('Saved new project to {}'.format(filename), duration=5000)
|
||||
return True
|
||||
|
||||
@ -3313,11 +3317,11 @@ class MainWindow(QMainWindow):
|
||||
return False
|
||||
else:
|
||||
self.project.parameter = self._inputs
|
||||
self.exportEvents()
|
||||
self.project.save()
|
||||
self.exportAllEvents()
|
||||
if not self.project.dirty:
|
||||
self.update_status('Saved back project to file:\n{}'.format(self.project.location), duration=5000)
|
||||
self.setDirty(False)
|
||||
self.update_status('Saved back project to file:\n{}'.format(self.project.location), duration=5000)
|
||||
return True
|
||||
else:
|
||||
# if still dirty because saving failed
|
||||
@ -3335,7 +3339,6 @@ class MainWindow(QMainWindow):
|
||||
self.dataPlot.setPermText(1)
|
||||
self.dataPlot.setPermText(0, '| Number of traces: {} |'.format(len(self.getPlotWidget().getPlotDict())))
|
||||
|
||||
|
||||
def _setDirty(self):
|
||||
self.setDirty(True)
|
||||
|
||||
@ -3344,6 +3347,7 @@ class MainWindow(QMainWindow):
|
||||
self.saveProjectAsAction.setEnabled(True)
|
||||
self.project.setDirty(value)
|
||||
self.dirty = value
|
||||
self.fill_eventbox()
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.okToContinue():
|
||||
|
37
autoPyLoT.py
37
autoPyLoT.py
@ -7,6 +7,7 @@ import argparse
|
||||
import datetime
|
||||
import glob
|
||||
import os
|
||||
import traceback
|
||||
|
||||
import pylot.core.loc.focmec as focmec
|
||||
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.inputs import PylotParameter
|
||||
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.event import Event
|
||||
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
|
||||
algorithms by Kueperkoch et al. 2010/2012.
|
||||
:param obspyDMT_wfpath: if obspyDMT is used, name of data directory ("raw" or "processed")
|
||||
:param input_dict:
|
||||
:type input_dict:
|
||||
: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
|
||||
:param savexml: export results in XML file if True
|
||||
: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
|
||||
:param iplot: logical variable for plotting: 0=none, 1=partial, 2=all
|
||||
:type iplot: int
|
||||
@ -149,8 +151,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
datastructure.modifyFields(**dsfields)
|
||||
datastructure.setExpandFields(exf)
|
||||
|
||||
# check if default location routine NLLoc is available
|
||||
if real_None(parameter['nllocbin']):
|
||||
# check if default location routine NLLoc is available and all stations are used
|
||||
if real_None(parameter['nllocbin']) and station == 'all':
|
||||
locflag = 1
|
||||
# get NLLoc-root path
|
||||
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))
|
||||
else:
|
||||
# autoPyLoT was initialized from GUI
|
||||
events = []
|
||||
events.append(eventid)
|
||||
events = [eventid]
|
||||
evID = os.path.split(eventid)[-1]
|
||||
locflag = 2
|
||||
else:
|
||||
@ -271,24 +272,26 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
if not wfdat:
|
||||
print('Could not find station {}. STOP!'.format(station))
|
||||
return
|
||||
wfdat = remove_underscores(wfdat)
|
||||
#wfdat = remove_underscores(wfdat)
|
||||
# trim components for each station to avoid problems with different trace starttimes for one station
|
||||
wfdat = check4gaps(wfdat)
|
||||
wfdat = check4doubled(wfdat)
|
||||
wfdat = trim_station_components(wfdat, trim_start=True, trim_end=False)
|
||||
metadata = read_metadata(parameter.get('invdir'))
|
||||
# TODO: (idea) read metadata from obspy_dmt database
|
||||
# if not wfpath_extension:
|
||||
# metadata = read_metadata(parameter.get('invdir'))
|
||||
# else:
|
||||
# metadata = None
|
||||
if not wfpath_extension:
|
||||
metadata = Metadata(parameter.get('invdir'))
|
||||
else:
|
||||
metadata = Metadata(os.path.join(eventpath, 'resp'))
|
||||
corr_dat = None
|
||||
if metadata:
|
||||
# rotate stations to ZNE
|
||||
try:
|
||||
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:
|
||||
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:
|
||||
locflag = 2
|
||||
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]))
|
||||
evt = local_mag.updated_event(magscaling)
|
||||
net_ml = local_mag.net_magnitude(magscaling)
|
||||
if net_ml:
|
||||
print("Network local magnitude: %4.1f" % net_ml.mag)
|
||||
if magscaling == None:
|
||||
if magscaling is None:
|
||||
scaling = False
|
||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||
scaling = False
|
||||
@ -447,8 +451,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
WAscaling[2]))
|
||||
evt = local_mag.updated_event(magscaling)
|
||||
net_ml = local_mag.net_magnitude(magscaling)
|
||||
if net_ml:
|
||||
print("Network local magnitude: %4.1f" % net_ml.mag)
|
||||
if magscaling == None:
|
||||
if magscaling is None:
|
||||
scaling = False
|
||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||
scaling = False
|
||||
|
@ -17,6 +17,7 @@ from pylot.core.util.utils import common_range, fit_curve
|
||||
from scipy import integrate, signal
|
||||
from scipy.optimize import curve_fit
|
||||
|
||||
|
||||
def richter_magnitude_scaling(delta):
|
||||
distance = np.array([0, 10, 20, 25, 30, 35, 40, 45, 50, 60, 70, 75, 85, 90, 100, 110,
|
||||
120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 230, 240, 250,
|
||||
@ -122,7 +123,7 @@ class Magnitude(object):
|
||||
|
||||
def net_magnitude(self, magscaling=None):
|
||||
if self:
|
||||
if magscaling == None:
|
||||
if magscaling is None:
|
||||
scaling = False
|
||||
elif magscaling[0] != 0 and magscaling[1] != 0:
|
||||
scaling = False
|
||||
@ -261,11 +262,12 @@ class LocalMagnitude(Magnitude):
|
||||
ax.set_xlabel('Time [s]')
|
||||
ax.set_ylabel('Displacement [mm]')
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
try:
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
return wapp, fig
|
||||
|
||||
def calc(self):
|
||||
@ -510,6 +512,9 @@ def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
||||
|
||||
|
||||
class Data(object):
|
||||
"""
|
||||
Data container with attributes wfdata holding ~obspy.core.stream.
|
||||
@ -299,7 +300,7 @@ class Data(object):
|
||||
for i in range(len(picks_copy)):
|
||||
if picks_copy[i].phase_hint[0] == 'P':
|
||||
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("Adjusted uncertainty: {}".format(upperErrors[0]))
|
||||
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
||||
@ -311,7 +312,7 @@ class Data(object):
|
||||
break
|
||||
if picks_copy[i].phase_hint[0] == 'S':
|
||||
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("Adjusted uncertainty: {}".format(upperErrors[1]))
|
||||
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
||||
@ -404,7 +405,7 @@ class Data(object):
|
||||
|
||||
# various pre-processing steps:
|
||||
# remove possible underscores in station names
|
||||
self.wfdata = remove_underscores(self.wfdata)
|
||||
#self.wfdata = remove_underscores(self.wfdata)
|
||||
# check for stations with rotated components
|
||||
if checkRotated and metadata is not None:
|
||||
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
|
||||
@ -416,7 +417,6 @@ class Data(object):
|
||||
self.dirty = False
|
||||
return True
|
||||
|
||||
|
||||
def appendWFData(self, fnames, synthetic=False):
|
||||
"""
|
||||
Read waveform data from fnames and append it to current wf data
|
||||
@ -506,8 +506,10 @@ class Data(object):
|
||||
# check for automatic picks
|
||||
print("Writing phases to ObsPy-quakeml file")
|
||||
for key in picks:
|
||||
if not picks[key].get('P'):
|
||||
continue
|
||||
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)
|
||||
break
|
||||
else:
|
||||
|
@ -346,6 +346,7 @@ def picks_from_picksdict(picks, creation_info=None):
|
||||
picks_list.append(pick)
|
||||
return picks_list
|
||||
|
||||
|
||||
def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0):
|
||||
import glob
|
||||
|
||||
@ -499,7 +500,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
||||
except KeyError as e:
|
||||
print(e)
|
||||
fm = None
|
||||
if fm == None:
|
||||
if fm is None:
|
||||
fm = '?'
|
||||
onset = arrivals[key]['P']['mpp']
|
||||
year = onset.year
|
||||
@ -965,7 +966,7 @@ def getQualitiesfromxml(xmlnames, ErrorsP, ErrorsS, plotflag=1):
|
||||
arrivals_copy = cat_copy.events[0].picks
|
||||
# Prefere manual picks if qualities are sufficient!
|
||||
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_ext = mstation + '_'
|
||||
for mpick in arrivals_copy:
|
||||
@ -973,14 +974,14 @@ def getQualitiesfromxml(xmlnames, ErrorsP, ErrorsS, plotflag=1):
|
||||
if phase == 'P':
|
||||
if ((mpick.waveform_id.station_code == mstation) or
|
||||
(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]):
|
||||
del mpick
|
||||
break
|
||||
elif phase == 'S':
|
||||
if ((mpick.waveform_id.station_code == mstation) or
|
||||
(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]):
|
||||
del mpick
|
||||
break
|
||||
|
@ -76,6 +76,7 @@ def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn):
|
||||
def locate(fnin, parameter=None):
|
||||
"""
|
||||
takes an external program name and tries to run it
|
||||
:param parameter: PyLoT Parameter object
|
||||
:param fnin: external program name
|
||||
:return: None
|
||||
"""
|
||||
|
@ -8,6 +8,7 @@ function conglomerate utils.
|
||||
|
||||
:author: MAGS2 EP3 working group / Ludger Kueperkoch
|
||||
"""
|
||||
import traceback
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
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:
|
||||
topick = data.select(station=station)
|
||||
|
||||
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)
|
||||
input_tuples.append((topick, param, apverbose, iplot, fig_dict, metadata, origin))
|
||||
|
||||
if iplot > 0:
|
||||
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'
|
||||
|
||||
print('Autopickstation: Distribute autopicking for {} '
|
||||
'stations on {} cores.'.format(len(input_tuples), ncores_str))
|
||||
|
||||
pool = gen_Pool(ncores)
|
||||
results = pool.map(call_autopickstation, input_tuples)
|
||||
pool.close()
|
||||
if ncores == 1:
|
||||
results = serial_picking(input_tuples)
|
||||
else:
|
||||
results = parallel_picking(input_tuples, ncores)
|
||||
|
||||
for result, wfstream in results:
|
||||
for result, station in results:
|
||||
if type(result) == dict:
|
||||
station = result['station']
|
||||
result.pop('station')
|
||||
all_onsets[station] = result
|
||||
else:
|
||||
if result == None:
|
||||
if result is None:
|
||||
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))
|
||||
|
||||
# no Wadati/JK for single station (also valid for tuning mode)
|
||||
if len(stations) == 1:
|
||||
return all_onsets
|
||||
|
||||
# quality control
|
||||
# median check and jackknife on P-onset times
|
||||
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
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
helper function used for multiprocessing
|
||||
@ -123,12 +130,16 @@ def call_autopickstation(input_tuple):
|
||||
:return: dictionary containing P pick, S pick and station name
|
||||
: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
|
||||
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:
|
||||
return e, wfstream
|
||||
tbe = traceback.format_exc()
|
||||
return tbe, wfstream[0].stats.station
|
||||
|
||||
|
||||
def get_source_coords(parser, station_id):
|
||||
@ -1312,9 +1323,12 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
# split components
|
||||
zdat, ndat, edat = get_components_from_waveformstream(wfstream)
|
||||
|
||||
picks = {}
|
||||
station = wfstream[0].stats.station
|
||||
|
||||
if not zdat:
|
||||
print('No z-component found for station {}. STOP'.format(wfstream[0].stats.station))
|
||||
return
|
||||
print('No z-component found for station {}. STOP'.format(station))
|
||||
return picks, station
|
||||
|
||||
if p_params['algoP'] == 'HOS' or p_params['algoP'] == 'ARZ' and zdat is not None:
|
||||
msg = '##################################################\nautopickstation:' \
|
||||
@ -1331,13 +1345,10 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
Lc = np.inf
|
||||
print('autopickstation: use_taup flag active.')
|
||||
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.')
|
||||
else:
|
||||
station_id = wfstream[0].get_id()
|
||||
parser = metadata[1]
|
||||
station_coords = get_source_coords(parser, station_id)
|
||||
station_coords = metadata.get_coordinates(station_id, time=wfstream[0].stats.starttime)
|
||||
if station_coords and origin:
|
||||
source_origin = origin[0]
|
||||
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
|
||||
if not Lwf > 0:
|
||||
print('autopickstation: empty trace! Return!')
|
||||
return
|
||||
return picks, station
|
||||
|
||||
Ldiff = Lwf - abs(Lc)
|
||||
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}, " \
|
||||
"SNR: {1}, SNR[dB]: {2}, Polarity: {3}".format(Pweight, SNRP, SNRPdB, FM)
|
||||
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)
|
||||
print(msg)
|
||||
Sflag = 1
|
||||
@ -1956,15 +1967,14 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
ax1.set_ylim([-1.5, 1.5])
|
||||
ax1.set_ylabel('Normalized Counts')
|
||||
# fig.suptitle(tr_filt.stats.starttime)
|
||||
try:
|
||||
len(edat[0])
|
||||
except:
|
||||
# only continue if one horizontal stream exists
|
||||
if (ndat or edat) and Sflag == 1:
|
||||
# mirror components in case one does not exist
|
||||
if not edat:
|
||||
edat = ndat
|
||||
try:
|
||||
len(ndat[0])
|
||||
except:
|
||||
if not ndat:
|
||||
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
|
||||
ax2 = fig.add_subplot(3, 1, 2, sharex=ax1)
|
||||
th1data = np.arange(0,
|
||||
@ -2082,12 +2092,22 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
epickP = zdat[0].stats.starttime - p_params['timeerrorsP'][3]
|
||||
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:
|
||||
hdat = edat[0]
|
||||
elif ndat:
|
||||
hdat = ndat[0]
|
||||
else:
|
||||
return
|
||||
# no horizontal components given
|
||||
picks = dict(P=ppick)
|
||||
return picks, station
|
||||
|
||||
if lpickS is not None and lpickS == mpickS:
|
||||
lpickS += hdat.stats.delta
|
||||
@ -2104,21 +2124,14 @@ def nautopickstation(wfstream, pickparam, verbose=False,
|
||||
epickS = hdat.stats.starttime - s_params['timeerrorsS'][3]
|
||||
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
|
||||
ccode = hdat.stats.channel
|
||||
ncode = hdat.stats.network
|
||||
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)
|
||||
# merge picks into returning dictionary
|
||||
picks = dict(P=ppick, S=spick, station=zdat[0].stats.station)
|
||||
return picks
|
||||
picks = dict(P=ppick, S=spick)
|
||||
return picks, station
|
||||
|
||||
|
||||
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')))
|
||||
|
||||
# repick station
|
||||
newpicks = autopickstation(wf2pick, pickparameter, fig_dict=fig_dict)
|
||||
newpicks, _ = autopickstation(wf2pick, pickparameter, fig_dict=fig_dict)
|
||||
|
||||
# replace old dictionary with new one
|
||||
picks[badpicks[i][0]] = newpicks
|
||||
|
@ -506,7 +506,8 @@ class PDFstatistics(object):
|
||||
|
||||
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
|
||||
serious amount of time when dealing with large databases.
|
||||
|
@ -191,9 +191,24 @@ class AICPicker(AutoPicker):
|
||||
# remove offset in AIC function
|
||||
offset = abs(min(aic) - min(aicsmooth))
|
||||
aicsmooth = aicsmooth - offset
|
||||
cf = self.Data[0].data
|
||||
# get maximum of HOS/AR-CF as startimg point for searching
|
||||
# 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
|
||||
lpickwindow = int(round(self.PickWindow / self.dt))
|
||||
@ -233,14 +248,14 @@ class AICPicker(AutoPicker):
|
||||
ii = min([isignal[len(isignal) - 1], len(self.Tcf)])
|
||||
isignal = isignal[0:ii]
|
||||
try:
|
||||
self.Data[0].data[isignal]
|
||||
cf[isignal]
|
||||
except IndexError as e:
|
||||
msg = "Time series out of bounds! {}".format(e)
|
||||
print(msg)
|
||||
return
|
||||
# calculate SNR from CF
|
||||
self.SNR = max(abs(self.Data[0].data[isignal])) / \
|
||||
abs(np.mean(self.Data[0].data[inoise]))
|
||||
self.SNR = max(abs(cf[isignal])) / \
|
||||
abs(np.mean(cf[inoise]))
|
||||
# calculate slope from CF after initial pick
|
||||
# get slope 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
|
||||
else:
|
||||
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
|
||||
# 'cause slope should be calculated up to first local minimum only!
|
||||
try:
|
||||
dataslope = self.Data[0].data[islope[0][0:-1]]
|
||||
dataslope = cf[islope[0][0:-1]]
|
||||
except IndexError:
|
||||
print("Slope Calculation: empty array islope, check signal window")
|
||||
return
|
||||
@ -263,7 +279,7 @@ class AICPicker(AutoPicker):
|
||||
try:
|
||||
imaxs, = argrelmax(dataslope)
|
||||
imax = imaxs[0]
|
||||
except ValueError as e:
|
||||
except (ValueError, IndexError) as e:
|
||||
print(e, 'picker: argrelmax not working!')
|
||||
imax = np.argmax(dataslope)
|
||||
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("Choose longer slope determination window!")
|
||||
if self.iplot > 1:
|
||||
if self.fig == None or self.fig == 'None':
|
||||
if self.fig is None or self.fig == 'None':
|
||||
fig = plt.figure()
|
||||
plt_flag = iplot
|
||||
else:
|
||||
fig = self.fig
|
||||
ax = fig.add_subplot(111)
|
||||
x = self.Data[0].data
|
||||
ax.plot(self.Tcf, x / max(x), color=self._linecolor, linewidth=0.7, label='(HOS-/AR-) Data')
|
||||
cf = cf
|
||||
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.legend(loc=1)
|
||||
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)
|
||||
if plt_flag in [1, 2]:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
try:
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
return
|
||||
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
|
||||
xslope = np.arange(0, len(dataslope), 1)
|
||||
P = np.polyfit(xslope, dataslope, 1)
|
||||
@ -306,24 +333,23 @@ class AICPicker(AutoPicker):
|
||||
else:
|
||||
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
|
||||
self.slope /= self.Data[0].data[icfmax]
|
||||
self.slope /= aicsmooth[iaicmax]
|
||||
|
||||
else:
|
||||
self.SNR = None
|
||||
self.slope = None
|
||||
|
||||
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)
|
||||
plt_flag = iplot
|
||||
else:
|
||||
fig = self.fig
|
||||
fig._tight = True
|
||||
ax1 = fig.add_subplot(211)
|
||||
x = self.Data[0].data
|
||||
if len(self.Tcf) > len(self.Data[0].data): # why? LK
|
||||
if len(self.Tcf) > len(cf): # why? LK
|
||||
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')
|
||||
if self.Pick is not None:
|
||||
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:
|
||||
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[isignal[0]], self.Tcf[isignal[-1]], color='b', alpha=0.2, lw=0,
|
||||
label='Signal Window')
|
||||
@ -345,7 +371,8 @@ class AICPicker(AutoPicker):
|
||||
label='Signal Window')
|
||||
ax2.axvspan(self.Tcf[iislope[0]], self.Tcf[iislope[-1]], color='g', alpha=0.2, lw=0,
|
||||
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:
|
||||
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]:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
try:
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
if plt_flag == 3:
|
||||
stats = self.Data[0].stats
|
||||
netstlc = '{}.{}.{}'.format(stats.network, stats.station, stats.location)
|
||||
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?')
|
||||
|
||||
return
|
||||
@ -486,7 +515,7 @@ class PragPicker(AutoPicker):
|
||||
pickflag = 0
|
||||
|
||||
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())
|
||||
plt_flag = 1
|
||||
else:
|
||||
@ -496,15 +525,18 @@ class PragPicker(AutoPicker):
|
||||
ax.plot(Tcfpick, cfipick, color=self._linecolor, linewidth=0.7, label='CF')
|
||||
ax.plot(Tcfpick, cfsmoothipick, 'r', label='Smoothed CF')
|
||||
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_yticks([])
|
||||
ax.set_title(self.Data[0].stats.station)
|
||||
ax.legend(loc=1)
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
try:
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
return
|
||||
|
||||
|
@ -14,8 +14,7 @@ import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from scipy.signal import argrelmax
|
||||
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'):
|
||||
@ -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.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.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',
|
||||
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([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([EPick, EPick], [max(x) / 2, -max(x) / 2], color=linecolor, linewidth=0.7, linestyle='dashed', label='epp')
|
||||
ax.plot([LPick, LPick], [max(x) / 2, -max(x) / 2], color=linecolor, linewidth=0.7, linestyle='dashed',
|
||||
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],
|
||||
[max(x) / 2, -max(x) / 2], 'r--', label='spe')
|
||||
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)
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
try:
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
|
||||
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
|
||||
# initial onset is assumed to be the first zero crossing
|
||||
# first from unfiltered trace
|
||||
zc1 = []
|
||||
zc1.append(Pick)
|
||||
zc1 = [Pick]
|
||||
index1 = []
|
||||
i = 0
|
||||
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
|
||||
# next zero crossings after most likely pick
|
||||
zc2 = []
|
||||
zc2.append(Pick)
|
||||
zc2 = [Pick]
|
||||
index2 = []
|
||||
i = 0
|
||||
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([])
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
try:
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
|
||||
return FM
|
||||
@ -573,8 +577,6 @@ def select_for_phase(st, phase):
|
||||
:rtype: `~obspy.core.stream.Stream`
|
||||
"""
|
||||
|
||||
from pylot.core.util.defaults import SetChannelComponents
|
||||
|
||||
sel_st = Stream()
|
||||
compclass = SetChannelComponents()
|
||||
if phase.upper() == 'P':
|
||||
@ -623,14 +625,18 @@ def wadaticheck(pickdic, dttolerance, iplot=0, fig_dict=None):
|
||||
ibad = 0
|
||||
|
||||
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
|
||||
spt = pickdic[key]['S']['mpp'] - pickdic[key]['P']['mpp']
|
||||
spt = spick['mpp'] - ppick['mpp']
|
||||
# add S-P time to dictionary
|
||||
pickdic[key]['SPt'] = spt
|
||||
# add P onsets and corresponding S-P times to list
|
||||
UTCPpick = UTCDateTime(pickdic[key]['P']['mpp'])
|
||||
UTCSpick = UTCDateTime(pickdic[key]['S']['mpp'])
|
||||
UTCPpick = UTCDateTime(ppick['mpp'])
|
||||
UTCSpick = UTCDateTime(spick['mpp'])
|
||||
Ppicks.append(UTCPpick.timestamp)
|
||||
Spicks.append(UTCSpick.timestamp)
|
||||
SPtimes.append(spt)
|
||||
@ -660,11 +666,11 @@ def wadaticheck(pickdic, dttolerance, iplot=0, fig_dict=None):
|
||||
# check, if deviation is larger than adjusted
|
||||
if wddiff > dttolerance:
|
||||
# remove pick from dictionary
|
||||
pickdic.pop(key)
|
||||
# # mark onset and downgrade S-weight to 9
|
||||
# # mark onset and downgrade S-weight to 9, also set SPE to None (disregarded in GUI)
|
||||
# # (not used anymore)
|
||||
# marker = 'badWadatiCheck'
|
||||
# pickdic[key]['S']['weight'] = 9
|
||||
marker = 'badWadatiCheck'
|
||||
pickdic[key]['S']['weight'] = 9
|
||||
pickdic[key]['S']['spe'] = None
|
||||
badstations.append(key)
|
||||
ibad += 1
|
||||
else:
|
||||
@ -677,7 +683,6 @@ def wadaticheck(pickdic, dttolerance, iplot=0, fig_dict=None):
|
||||
checkedSPtimes.append(checkedSPtime)
|
||||
|
||||
pickdic[key]['S']['marked'] = marker
|
||||
#pickdic[key]['S']['marked'] = marker
|
||||
print("wadaticheck: the following stations failed the check:")
|
||||
print(badstations)
|
||||
|
||||
@ -851,8 +856,10 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fi
|
||||
ax.set_yticks([])
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
try:
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
|
||||
return returnflag
|
||||
@ -886,9 +893,12 @@ def checkPonsets(pickdic, dttolerance, jackfactor=5, iplot=0, fig_dict=None):
|
||||
Ppicks = []
|
||||
stations = []
|
||||
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
|
||||
UTCPpick = UTCDateTime(pickdic[station]['P']['mpp'])
|
||||
UTCPpick = UTCDateTime(pick['mpp'])
|
||||
Ppicks.append(UTCPpick.timestamp)
|
||||
stations.append(station)
|
||||
|
||||
@ -1087,7 +1097,6 @@ def checkZ4S(X, pick, zfac, checkwin, iplot, fig=None, linecolor='k'):
|
||||
else:
|
||||
iplot = 0
|
||||
|
||||
|
||||
assert isinstance(X, Stream), "%s is not a stream object" % str(X)
|
||||
|
||||
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)
|
||||
if plt_flag == 1:
|
||||
fig.show()
|
||||
try: input()
|
||||
except SyntaxError: pass
|
||||
try:
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
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):
|
||||
"""
|
||||
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
|
||||
|
||||
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__':
|
||||
import doctest
|
||||
|
@ -23,8 +23,7 @@ class Array_map(QtGui.QWidget):
|
||||
'''
|
||||
QtGui.QWidget.__init__(self)
|
||||
self._parent = parent
|
||||
self.metadata_type = parent.metadata[0]
|
||||
self.metadata = parent.metadata[1]
|
||||
self.metadata = parent.metadata
|
||||
self.picks = None
|
||||
self.picks_dict = None
|
||||
self.autopicks_dict = None
|
||||
@ -74,13 +73,9 @@ class Array_map(QtGui.QWidget):
|
||||
if pickDlg.exec_():
|
||||
pyl_mw.setDirty(True)
|
||||
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()
|
||||
if replot:
|
||||
pyl_mw.plotWaveformData()
|
||||
pyl_mw.drawPicks()
|
||||
pyl_mw.draw()
|
||||
else:
|
||||
pyl_mw.drawPicks(station)
|
||||
pyl_mw.draw()
|
||||
else:
|
||||
@ -159,35 +154,8 @@ class Array_map(QtGui.QWidget):
|
||||
self.main_box.addWidget(self.canvas, 1)
|
||||
self.main_box.addWidget(self.status_label, 0)
|
||||
|
||||
|
||||
def init_stations(self):
|
||||
def stat_info_from_parser(parser):
|
||||
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.stations_dict = self.metadata.get_all_coordinates()
|
||||
self.latmin = self.get_min_from_stations('latitude')
|
||||
self.lonmin = self.get_min_from_stations('longitude')
|
||||
self.latmax = self.get_max_from_stations('latitude')
|
||||
@ -196,13 +164,15 @@ class Array_map(QtGui.QWidget):
|
||||
def init_picks(self):
|
||||
def get_picks(station_dict):
|
||||
picks = {}
|
||||
# selected phase
|
||||
phase = self.comboBox_phase.currentText()
|
||||
for st_id in station_dict.keys():
|
||||
try:
|
||||
station_name = st_id.split('.')[-1]
|
||||
# current_picks_dict: auto or manual
|
||||
pick = self.current_picks_dict()[station_name][phase]
|
||||
if pick['picker'] == 'auto':
|
||||
if pick['weight'] > 3:
|
||||
if not pick['spe']:
|
||||
continue
|
||||
picks[st_id] = pick['mpp']
|
||||
except KeyError:
|
||||
@ -217,6 +187,7 @@ class Array_map(QtGui.QWidget):
|
||||
for pick in picks.values():
|
||||
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
||||
picks_utc.append(pick)
|
||||
if picks_utc:
|
||||
self._earliest_picktime = min(picks_utc)
|
||||
for st_id, pick in picks.items():
|
||||
if type(pick) is obspy.core.utcdatetime.UTCDateTime:
|
||||
@ -331,6 +302,8 @@ class Array_map(QtGui.QWidget):
|
||||
|
||||
def scatter_picked_stations(self):
|
||||
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
|
||||
if len(lons) <= 2 and len(lats) <= 2:
|
||||
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()
|
||||
|
||||
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()
|
||||
if len(self.picks) >= 3:
|
||||
self.init_picksgrid()
|
||||
self.draw_contour_filled()
|
||||
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.cbar = self.add_cbar(label='Time relative to first onset ({}) [s]'.format(self._earliest_picktime))
|
||||
self.comboBox_phase.setEnabled(True)
|
||||
@ -397,16 +373,16 @@ class Array_map(QtGui.QWidget):
|
||||
del (self.cbar, self.cbax_bg)
|
||||
if hasattr(self, 'sc_picked'):
|
||||
self.sc_picked.remove()
|
||||
del (self.sc_picked)
|
||||
del self.sc_picked
|
||||
if hasattr(self, 'sc_event'):
|
||||
self.sc_event.remove()
|
||||
del (self.sc_event)
|
||||
del self.sc_event
|
||||
if hasattr(self, 'contourf'):
|
||||
self.remove_contourf()
|
||||
del (self.contourf)
|
||||
del self.contourf
|
||||
if hasattr(self, 'cid'):
|
||||
self.canvas.mpl_disconnect(self.cid)
|
||||
del (self.cid)
|
||||
del self.cid
|
||||
try:
|
||||
self.sc.remove()
|
||||
except Exception as e:
|
||||
|
@ -13,19 +13,21 @@ from pylot.core.util.utils import key_for_set_value, find_in_list, \
|
||||
|
||||
|
||||
class Metadata(object):
|
||||
|
||||
def __init__(self, inventory=None):
|
||||
self.inventories = []
|
||||
# saves read metadata objects (Parser/inventory) for a filename
|
||||
self.inventory_files = {}
|
||||
# saves filenames holding metadata for a seed_id
|
||||
# seed id as key, path to file as value
|
||||
self.seed_ids = {}
|
||||
self.stations_dict = {}
|
||||
if inventory:
|
||||
if os.path.isdir(inventory):
|
||||
self.add_inventory(inventory)
|
||||
if os.path.isfile(inventory):
|
||||
self.add_inventory_file(inventory)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
repr = 'PyLoT Metadata object including the following inventories:\n\n'
|
||||
ntotal = len(self.inventories)
|
||||
@ -38,48 +40,40 @@ class Metadata(object):
|
||||
repr += '\nTotal of {} inventories. Use Metadata.inventories to see all.'.format(ntotal)
|
||||
return repr
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
|
||||
def add_inventory(self, path_to_inventory):
|
||||
'''
|
||||
add paths to list of inventories
|
||||
|
||||
:param path_to_inventory:
|
||||
:return:
|
||||
'''
|
||||
"""
|
||||
Add path to list of inventories.
|
||||
:param path_to_inventory: Path to a folder
|
||||
:type path_to_inventory: str
|
||||
:return: None
|
||||
"""
|
||||
assert (os.path.isdir(path_to_inventory)), '{} is no directory'.format(path_to_inventory)
|
||||
if not path_to_inventory in self.inventories:
|
||||
self.inventories.append(path_to_inventory)
|
||||
|
||||
|
||||
def add_inventory_file(self, path_to_inventory_file):
|
||||
'''
|
||||
add a single file to inventory files
|
||||
|
||||
:param path_to_inventory_file:
|
||||
:return:
|
||||
|
||||
'''
|
||||
"""
|
||||
Add the folder in which the file exists to the list of inventories.
|
||||
:param path_to_inventory_file: full path including filename
|
||||
:type path_to_inventory_file: str
|
||||
:return: None
|
||||
"""
|
||||
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])
|
||||
if not path_to_inventory_file in self.inventory_files.keys():
|
||||
self.read_single_file(path_to_inventory_file)
|
||||
|
||||
|
||||
def remove_all_inventories(self):
|
||||
self.__init__()
|
||||
|
||||
|
||||
def remove_inventory(self, path_to_inventory):
|
||||
'''
|
||||
remove a path from inventories list
|
||||
|
||||
:param path_to_inventory:
|
||||
:return:
|
||||
'''
|
||||
"""
|
||||
Remove a path from inventories list. If path is not in inventories list, do nothing.
|
||||
:param path_to_inventory: Path to a folder
|
||||
"""
|
||||
if not path_to_inventory in self.inventories:
|
||||
print('Path {} not in inventories list.'.format(path_to_inventory))
|
||||
return
|
||||
@ -91,8 +85,23 @@ class Metadata(object):
|
||||
if self.seed_ids[seed_id].startswith(path_to_inventory):
|
||||
del (self.seed_ids[seed_id])
|
||||
|
||||
|
||||
def get_metadata(self, seed_id):
|
||||
def get_metadata(self, seed_id, time=None):
|
||||
"""
|
||||
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
|
||||
if not seed_id in self.seed_ids.keys():
|
||||
self._read_inventory_data(seed_id)
|
||||
@ -100,12 +109,13 @@ class Metadata(object):
|
||||
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))
|
||||
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
|
||||
try:
|
||||
metadata['data'].get_coordinates(seed_id)
|
||||
metadata_dict['data'].get_coordinates(seed_id, time)
|
||||
self.seed_ids[seed_id] = inv_fname
|
||||
return metadata
|
||||
print('Found metadata for station {}!'.format(seed_id))
|
||||
return metadata_dict
|
||||
except Exception as e:
|
||||
continue
|
||||
print('Could not find metadata for station {}'.format(seed_id))
|
||||
@ -113,30 +123,30 @@ class Metadata(object):
|
||||
fname = self.seed_ids[seed_id]
|
||||
return self.inventory_files[fname]
|
||||
|
||||
|
||||
def read_all(self):
|
||||
'''
|
||||
read all metadata files found in all inventories
|
||||
:return:
|
||||
'''
|
||||
"""
|
||||
Read all metadata files found in all inventories
|
||||
"""
|
||||
for inventory in self.inventories:
|
||||
for inv_fname in os.listdir(inventory):
|
||||
inv_fname = os.path.join(inventory, inv_fname)
|
||||
if not self.read_single_file(inv_fname):
|
||||
continue
|
||||
|
||||
|
||||
def read_single_file(self, inv_fname):
|
||||
if not inv_fname in self.inventory_files.keys():
|
||||
pass
|
||||
else:
|
||||
if not self.inventory_files[inv_fname]:
|
||||
pass
|
||||
else:
|
||||
"""
|
||||
Try to read a single file as Parser/Inventory and add its dictionary to inventory files if reading sudceeded.
|
||||
:param inv_fname: path/filename of inventory file
|
||||
:type inv_fname: str
|
||||
:rtype: None
|
||||
"""
|
||||
# return if it was read already
|
||||
if self.inventory_files.get(inv_fname, None):
|
||||
return
|
||||
|
||||
try:
|
||||
invtype, robj = self._read_metadata_file(inv_fname)
|
||||
if robj == None:
|
||||
if robj is None:
|
||||
return
|
||||
except Exception as e:
|
||||
print('Could not read file {}'.format(inv_fname))
|
||||
@ -145,15 +155,64 @@ class Metadata(object):
|
||||
'data': robj}
|
||||
return True
|
||||
|
||||
|
||||
def get_coordinates(self, seed_id):
|
||||
metadata = self.get_metadata(seed_id)
|
||||
def get_coordinates(self, seed_id, time=None):
|
||||
"""
|
||||
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:
|
||||
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):
|
||||
"""
|
||||
|
||||
: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)
|
||||
if not metadata:
|
||||
return
|
||||
@ -163,18 +222,17 @@ class Metadata(object):
|
||||
resp = metadata['data'].get_response(seed_id, time)
|
||||
return resp.get_paz(seed_id)
|
||||
|
||||
|
||||
def _read_inventory_data(self, seed_id=None):
|
||||
for inventory in self.inventories:
|
||||
if self._read_metadata_iterator(path_to_inventory=inventory, station_seed_id=seed_id):
|
||||
return
|
||||
|
||||
|
||||
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('.')
|
||||
# seach for station seed id in filenames in invetory
|
||||
fnames = glob.glob(os.path.join(path_to_inventory, '*' + station_seed_id + '*'))
|
||||
if not fnames:
|
||||
# search for station name in filename
|
||||
@ -203,13 +261,13 @@ class Metadata(object):
|
||||
continue
|
||||
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):
|
||||
'''
|
||||
"""
|
||||
function reading metadata files (either dataless seed, xml or resp)
|
||||
:param path_to_inventory_filename:
|
||||
: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)
|
||||
read_functions = {'dless': self._read_dless,
|
||||
'dseed': self._read_dless,
|
||||
@ -228,8 +286,8 @@ class Metadata(object):
|
||||
return file_type, robj
|
||||
return None, None
|
||||
|
||||
|
||||
def _read_dless(self, path_to_inventory):
|
||||
@staticmethod
|
||||
def _read_dless(path_to_inventory):
|
||||
exc = None
|
||||
try:
|
||||
parser = Parser(path_to_inventory)
|
||||
@ -237,8 +295,8 @@ class Metadata(object):
|
||||
parser = None
|
||||
return parser, exc
|
||||
|
||||
|
||||
def _read_inventory_file(self, path_to_inventory):
|
||||
@staticmethod
|
||||
def _read_inventory_file(path_to_inventory):
|
||||
exc = None
|
||||
try:
|
||||
inv = read_inventory(path_to_inventory)
|
||||
@ -247,7 +305,6 @@ class Metadata(object):
|
||||
return inv, exc
|
||||
|
||||
|
||||
|
||||
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.
|
||||
@ -458,15 +515,22 @@ def read_metadata(path_to_inventory):
|
||||
# return metadata_objects
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
remove_trace = False
|
||||
|
||||
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']
|
||||
inobj = mdata['data']
|
||||
|
||||
@ -481,8 +545,7 @@ def restitute_trace(input_tuple):
|
||||
if invtype == 'resp':
|
||||
fresp = find_in_list(inobj, seed_id)
|
||||
if not fresp:
|
||||
raise IOError('no response file found '
|
||||
'for trace {0}'.format(seed_id))
|
||||
return no_metadata(tr, seed_id)
|
||||
fname = fresp
|
||||
seedresp = dict(filename=fname,
|
||||
date=stime,
|
||||
@ -504,9 +567,8 @@ def restitute_trace(input_tuple):
|
||||
else:
|
||||
finv = invlist[0]
|
||||
inventory = read_inventory(finv, format='STATIONXML')
|
||||
elif invtype == None:
|
||||
print("No restitution possible, as there are no station-meta data available!")
|
||||
return tr, True
|
||||
elif invtype is None:
|
||||
return no_metadata(tr, seed_id)
|
||||
else:
|
||||
remove_trace = True
|
||||
# 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
|
||||
waveform 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 force: force restitution for already corrected traces (default:
|
||||
False)
|
||||
@ -553,7 +612,7 @@ def restitute_data(data, metadata, unit='VEL', force=False, ncores=0):
|
||||
|
||||
restflag = list()
|
||||
|
||||
data = remove_underscores(data)
|
||||
#data = remove_underscores(data)
|
||||
|
||||
# loop over traces
|
||||
input_tuples = []
|
||||
@ -562,7 +621,7 @@ def restitute_data(data, metadata, unit='VEL', force=False, ncores=0):
|
||||
data.remove(tr)
|
||||
|
||||
pool = gen_Pool(ncores)
|
||||
result = pool.map(restitute_trace, input_tuples)
|
||||
result = pool.imap_unordered(restitute_trace, input_tuples)
|
||||
pool.close()
|
||||
|
||||
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
|
||||
fc21 = fny - (fny * thi[0] / 100.)
|
||||
fc22 = fny - (fny * thi[1] / 100.)
|
||||
return (tlow[0], tlow[1], fc21, fc22)
|
||||
return tlow[0], tlow[1], fc21, fc22
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -16,7 +16,6 @@ from pylot.core.loc import hyposat
|
||||
from pylot.core.loc import nll
|
||||
from pylot.core.loc import velest
|
||||
|
||||
|
||||
# determine system dependent path separator
|
||||
system_name = platform.system()
|
||||
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)
|
||||
|
||||
|
||||
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.get_notes()
|
||||
self.get_obspy_event_info()
|
||||
self.dirty = False
|
||||
|
||||
def get_notes_path(self):
|
||||
"""
|
||||
@ -143,6 +144,7 @@ class Event(ObsPyEvent):
|
||||
for index, pick in reversed(list(enumerate(self.picks))):
|
||||
if picktype in str(pick.method_id):
|
||||
self.picks.pop(index)
|
||||
self.dirty = True
|
||||
|
||||
def addPicks(self, picks):
|
||||
"""
|
||||
@ -157,12 +159,12 @@ class Event(ObsPyEvent):
|
||||
# add ObsPy picks (clear old manual and copy all new manual from pylot)
|
||||
self.clearObsPyPicks('manual')
|
||||
self.picks += picks_from_picksdict(self.pylot_picks)
|
||||
self.dirty = True
|
||||
|
||||
def addAutopicks(self, autopicks):
|
||||
"""
|
||||
Add automatic picks to event
|
||||
:param autopicks: automatic picks to add to event
|
||||
:type autopicks dict:
|
||||
:return:
|
||||
:rtype: None
|
||||
"""
|
||||
@ -171,6 +173,7 @@ class Event(ObsPyEvent):
|
||||
# add ObsPy picks (clear old auto and copy all new auto from pylot)
|
||||
self.clearObsPyPicks('auto')
|
||||
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
||||
self.dirty = True
|
||||
|
||||
def setPick(self, station, pick):
|
||||
"""
|
||||
@ -186,11 +189,13 @@ class Event(ObsPyEvent):
|
||||
self.pylot_picks[station] = pick
|
||||
else:
|
||||
try:
|
||||
if station in self.pylot_picks:
|
||||
self.pylot_picks.pop(station)
|
||||
except Exception as e:
|
||||
print('Could not remove pick {} from station {}: {}'.format(pick, station, e))
|
||||
self.clearObsPyPicks('manual')
|
||||
self.picks += picks_from_picksdict(self.pylot_picks)
|
||||
self.dirty = True
|
||||
|
||||
def setPicks(self, picks):
|
||||
"""
|
||||
@ -203,6 +208,7 @@ class Event(ObsPyEvent):
|
||||
self.pylot_picks = picks
|
||||
self.clearObsPyPicks('manual')
|
||||
self.picks += picks_from_picksdict(self.pylot_picks)
|
||||
self.dirty = True
|
||||
|
||||
def getPick(self, station):
|
||||
"""
|
||||
@ -237,11 +243,13 @@ class Event(ObsPyEvent):
|
||||
self.pylot_autopicks[station] = pick
|
||||
else:
|
||||
try:
|
||||
if station in self.pylot_autopicks:
|
||||
self.pylot_autopicks.pop(station)
|
||||
except Exception as e:
|
||||
print('Could not remove pick {} from station {}: {}'.format(pick, station, e))
|
||||
self.clearObsPyPicks('auto')
|
||||
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
||||
self.dirty = True
|
||||
|
||||
def setAutopicks(self, picks):
|
||||
"""
|
||||
@ -254,6 +262,7 @@ class Event(ObsPyEvent):
|
||||
self.pylot_autopicks = picks
|
||||
self.clearObsPyPicks('auto')
|
||||
self.picks += picks_from_picksdict(self.pylot_autopicks)
|
||||
self.dirty = True
|
||||
|
||||
def getAutopick(self, station):
|
||||
"""
|
||||
@ -292,6 +301,7 @@ class Event(ObsPyEvent):
|
||||
try:
|
||||
outfile = open(filename, 'wb')
|
||||
cPickle.dump(self, outfile, -1)
|
||||
self.dirty = False
|
||||
except Exception as e:
|
||||
print('Could not pickle PyLoT event. Reason: {}'.format(e))
|
||||
|
||||
@ -310,5 +320,6 @@ class Event(ObsPyEvent):
|
||||
import _pickle as cPickle
|
||||
infile = open(filename, 'rb')
|
||||
event = cPickle.load(infile)
|
||||
event.dirty = False
|
||||
print('Loaded %s' % filename)
|
||||
return event
|
||||
|
@ -4,6 +4,7 @@
|
||||
import os
|
||||
from obspy import UTCDateTime
|
||||
|
||||
|
||||
def check_obspydmt_structure(path):
|
||||
'''
|
||||
Check path for obspyDMT event structure.
|
||||
@ -16,6 +17,7 @@ def check_obspydmt_structure(path):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def check_obspydmt_eventfolder(folder):
|
||||
try:
|
||||
time = folder.split('.')[0]
|
||||
@ -25,6 +27,7 @@ def check_obspydmt_eventfolder(folder):
|
||||
except Exception as e:
|
||||
return False, e
|
||||
|
||||
|
||||
def qml_from_obspyDMT(path):
|
||||
import pickle
|
||||
from obspy.core.event import Event, Magnitude, Origin
|
||||
@ -41,4 +44,3 @@ def qml_from_obspyDMT(path):
|
||||
ev.magnitudes.append(mag)
|
||||
ev.origins.append(origin)
|
||||
return ev
|
||||
|
||||
|
@ -41,23 +41,13 @@ class Thread(QThread):
|
||||
def showProgressbar(self):
|
||||
if self.progressText:
|
||||
|
||||
# generate widget if not given in init
|
||||
if not self.pb_widget:
|
||||
self.pb_widget = QDialog(self.parent())
|
||||
self.pb_widget.setWindowFlags(Qt.SplashScreen)
|
||||
self.pb_widget.setModal(True)
|
||||
# # generate widget if not given in init
|
||||
# if not self.pb_widget:
|
||||
# self.pb_widget = ProgressBarWidget(self.parent())
|
||||
# self.pb_widget.setWindowFlags(Qt.SplashScreen)
|
||||
# self.pb_widget.setModal(True)
|
||||
|
||||
# add button
|
||||
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.label.setText(self.progressText)
|
||||
self.pb_widget.show()
|
||||
|
||||
def hideProgressbar(self):
|
||||
@ -75,6 +65,7 @@ class Worker(QRunnable):
|
||||
'''
|
||||
Worker class to be run by MultiThread(QThread).
|
||||
'''
|
||||
|
||||
def __init__(self, fun, args,
|
||||
progressText=None,
|
||||
pb_widget=None,
|
||||
|
@ -22,11 +22,7 @@ from pylot.styles import style_settings
|
||||
from scipy.interpolate import splrep, splev
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
try:
|
||||
import pyqtgraph as pg
|
||||
except Exception as e:
|
||||
print('PyLoT: Could not import pyqtgraph. {}'.format(e))
|
||||
pg = None
|
||||
|
||||
def _pickle_method(m):
|
||||
if m.im_self is None:
|
||||
@ -34,6 +30,7 @@ def _pickle_method(m):
|
||||
else:
|
||||
return getattr, (m.im_self, m.im_func.func_name)
|
||||
|
||||
|
||||
def getAutoFilteroptions(phase, parameter):
|
||||
filtername = {'P': 'bpz2',
|
||||
'S': 'bph2'}
|
||||
@ -44,6 +41,7 @@ def getAutoFilteroptions(phase, parameter):
|
||||
filteroptions = FilterOptions(type='bandpass', freq=[freqmin, freqmax], order=4) # order=4 default from obspy
|
||||
return filteroptions
|
||||
|
||||
|
||||
def readDefaultFilterInformation(fname):
|
||||
"""
|
||||
Read default filter information from pylot.in file
|
||||
@ -118,8 +116,12 @@ def gen_Pool(ncores=0):
|
||||
"""
|
||||
import multiprocessing
|
||||
|
||||
if ncores == 0:
|
||||
ncores = multiprocessing.cpu_count()
|
||||
ncores_max = 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))
|
||||
|
||||
@ -397,6 +399,10 @@ def full_range(stream):
|
||||
:return: minimum start time and maximum 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])
|
||||
max_end = max([trace.stats.endtime for trace in stream])
|
||||
|
||||
@ -537,7 +543,7 @@ def isSorted(iterable):
|
||||
False
|
||||
"""
|
||||
assert isIterable(iterable), 'object is not iterable; object: {' \
|
||||
'0}'.format(iterable)
|
||||
'}'.format(iterable)
|
||||
if type(iterable) is str:
|
||||
iterable = [s for s in iterable]
|
||||
return sorted(iterable) == iterable
|
||||
@ -787,6 +793,7 @@ def base_phase_colors(picktype, phase):
|
||||
phasecolors = style_settings.phasecolors
|
||||
return phasecolors[picktype][phase]
|
||||
|
||||
|
||||
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]
|
||||
@ -805,6 +812,7 @@ def transform_colors_mpl_str(colors, no_alpha=False):
|
||||
colors_mpl = '({}, {}, {}, {})'.format(*colors_mpl)
|
||||
return colors_mpl
|
||||
|
||||
|
||||
def transform_colors_mpl(colors):
|
||||
"""
|
||||
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])
|
||||
return colors_mpl
|
||||
|
||||
|
||||
def remove_underscores(data):
|
||||
"""
|
||||
takes a `obspy.core.stream.Stream` object and removes all underscores
|
||||
@ -826,9 +835,9 @@ def remove_underscores(data):
|
||||
:return: data stream
|
||||
:rtype: `~obspy.core.stream.Stream`
|
||||
"""
|
||||
for tr in data:
|
||||
# remove underscores
|
||||
tr.stats.station = tr.stats.station.strip('_')
|
||||
#for tr in data:
|
||||
# # remove underscores
|
||||
# tr.stats.station = tr.stats.station.strip('_')
|
||||
return data
|
||||
|
||||
|
||||
@ -926,7 +935,10 @@ def get_stations(data):
|
||||
|
||||
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
|
||||
:type data: `~obspy.core.stream.Stream`
|
||||
: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.
|
||||
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`
|
||||
:param metadata: tuple containing metadata type string and metadata parser object
|
||||
:type metadata: (str, `~obspy.io.xseed.parser.Parser`)
|
||||
:return: stream object with traditionally oriented traces (ZNE)
|
||||
: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]
|
||||
for trace_id in trace_ids:
|
||||
orientation = trace_id[-1] # last letter if trace id is orientation code, ZNE or 123
|
||||
if orientation.isnumeric():
|
||||
# misaligned channels have a number as orientation
|
||||
azimuts = []
|
||||
dips = []
|
||||
for trace_id in trace_ids:
|
||||
orientations = [trace_id[-1] for trace_id in trace_ids]
|
||||
rotation_required = [orientation.isnumeric() for orientation in orientations]
|
||||
if any(rotation_required):
|
||||
t_start = full_range(wfstream)
|
||||
try:
|
||||
dip, azimut = get_dip_azimut(parser, trace_id)
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
print('Failed to rotate station {}, no azimuth or dip available in metadata'.format(trace_id))
|
||||
azimuts = [metadata.get_coordinates(tr_id, t_start)['azimuth'] for tr_id in trace_ids]
|
||||
dips = [metadata.get_coordinates(tr_id, t_start)['dip'] for tr_id in trace_ids]
|
||||
except (KeyError, TypeError) as e:
|
||||
print('Failed to rotate trace {}, no azimuth or dip available in metadata'.format(trace_id))
|
||||
return wfstream
|
||||
azimuts.append(azimut)
|
||||
dips.append(dip)
|
||||
# to rotate all traces must have same length
|
||||
if len(wfstream) < 3:
|
||||
print('Failed to rotate Stream {}, not enough components available.'.format(wfstream))
|
||||
return wfstream
|
||||
# to rotate all traces must have same length, so trim them
|
||||
wfstream = trim_station_components(wfstream, trim_start=True, trim_end=True)
|
||||
z, n, e = rotate2zne(wfstream[0], azimuts[0], dips[0],
|
||||
wfstream[1], azimuts[1], dips[1],
|
||||
wfstream[2], azimuts[2], dips[2])
|
||||
print('check4rotated: rotated station {} to ZNE'.format(trace_id))
|
||||
z_index = dips.index(min(dips)) # get z-trace index (dip is measured from 0 to -90)
|
||||
print('check4rotated: rotated trace {} to ZNE'.format(trace_id))
|
||||
# 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].stats.channel = wfstream[z_index].stats.channel[0:-1] + 'Z'
|
||||
del trace_ids[z_index]
|
||||
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]
|
||||
if az > 315 or az <= 45 or az > 135 and az <= 225:
|
||||
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:
|
||||
trace.data = e
|
||||
trace.stats.channel = trace.stats.channel[0:-1] + 'E'
|
||||
break
|
||||
else:
|
||||
continue
|
||||
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)
|
||||
|
||||
for station in stations: # loop through all stations and rotate data if neccessary
|
||||
wf_station = data.select(station=station)
|
||||
rotate_components(wf_station, metadata)
|
||||
@ -1149,7 +1120,7 @@ def loopIdentifyPhase(phase):
|
||||
"""
|
||||
from pylot.core.util.defaults import ALTSUFFIX
|
||||
|
||||
if phase == None:
|
||||
if phase is None:
|
||||
raise NameError('Can not identify phase that is None')
|
||||
|
||||
phase_copy = phase
|
||||
@ -1199,20 +1170,6 @@ def identifyPhaseID(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):
|
||||
ev_type = 'obspydmt'
|
||||
return check_event_folders(eventlist, ev_type)
|
||||
@ -1276,3 +1233,56 @@ if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
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 matplotlib
|
||||
|
||||
matplotlib.use('QT4Agg')
|
||||
|
||||
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, \
|
||||
getResolutionWindow, get_quality_class
|
||||
from pylot.core.pick.compare import Comparison
|
||||
from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS, \
|
||||
SetChannelComponents
|
||||
from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS
|
||||
from pylot.core.util.utils import prepTimeAxis, full_range, scaleWFData, \
|
||||
demeanTrace, isSorted, findComboBoxIndex, clims, pick_linestyle_plt, pick_color_plt, \
|
||||
check4rotated, check4doubled, check4gaps, remove_underscores, find_horizontals, identifyPhase, \
|
||||
loopIdentifyPhase, trim_station_components, transformFilteroptions2String, \
|
||||
identifyPhaseID, real_Bool, pick_color, getAutoFilteroptions
|
||||
identifyPhaseID, real_Bool, pick_color, getAutoFilteroptions, SetChannelComponents
|
||||
from autoPyLoT import autoPyLoT
|
||||
from pylot.core.util.thread import Thread
|
||||
from pylot.core.util.dataprocessing import Metadata
|
||||
|
||||
if sys.version_info.major == 3:
|
||||
import icons_rc_3 as icons_rc
|
||||
@ -118,6 +119,139 @@ def createAction(parent, text, slot=None, shortcut=None, icon=None,
|
||||
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):
|
||||
def __init__(self, c, parent=None, windowflag=1):
|
||||
self._data = c
|
||||
@ -132,6 +266,14 @@ class ComparisonWidget(QWidget):
|
||||
self.setupUI()
|
||||
self.resize(1280, 720)
|
||||
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):
|
||||
|
||||
@ -242,7 +384,8 @@ class ComparisonWidget(QWidget):
|
||||
def clf(self):
|
||||
self.canvas.figure.clf()
|
||||
|
||||
def hasvalue(self, sender):
|
||||
@staticmethod
|
||||
def hasvalue(sender):
|
||||
text = sender.currentText()
|
||||
index = sender.findText(text.upper())
|
||||
return index
|
||||
@ -503,8 +646,17 @@ class WaveformWidgetPG(QtGui.QWidget):
|
||||
self.label_layout.addWidget(self.status_label)
|
||||
for label in self.perm_labels:
|
||||
self.label_layout.addWidget(label)
|
||||
self.label_layout.addWidget(self.syn_checkbox)
|
||||
self.label_layout.addWidget(self.qcombo_processed)
|
||||
mid_widget = QWidget()
|
||||
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.label_layout.setStretch(0, 4)
|
||||
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)
|
||||
# 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_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_syn.data = np.array([datum + n for index, datum in enumerate(trace_syn.data)
|
||||
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))
|
||||
self.setYLims(ax, new_ylim)
|
||||
|
||||
self.refreshPickDlgText()
|
||||
self.draw()
|
||||
|
||||
def set_frame_color(self, color='k'):
|
||||
@ -895,7 +1049,8 @@ class PylotCanvas(FigureCanvas):
|
||||
fname += '.png'
|
||||
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_upper = abs(origin - upper_b)
|
||||
|
||||
@ -1029,7 +1184,8 @@ class PylotCanvas(FigureCanvas):
|
||||
def clearPlotDict(self):
|
||||
self.plotdict = dict()
|
||||
|
||||
def calcPlotPositions(self, wfdata, compclass):
|
||||
@staticmethod
|
||||
def calcPlotPositions(wfdata, compclass):
|
||||
possible_plot_pos = list(range(len(wfdata)))
|
||||
plot_positions = {}
|
||||
for trace in wfdata:
|
||||
@ -1173,16 +1329,20 @@ class PylotCanvas(FigureCanvas):
|
||||
self.setYLims(ax, zoomy)
|
||||
self.draw()
|
||||
|
||||
def getXLims(self, ax):
|
||||
@staticmethod
|
||||
def getXLims(ax):
|
||||
return ax.get_xlim()
|
||||
|
||||
def getYLims(self, ax):
|
||||
@staticmethod
|
||||
def getYLims(ax):
|
||||
return ax.get_ylim()
|
||||
|
||||
def setXLims(self, ax, lims):
|
||||
@staticmethod
|
||||
def setXLims(ax, lims):
|
||||
ax.set_xlim(lims)
|
||||
|
||||
def setYLims(self, ax, lims):
|
||||
@staticmethod
|
||||
def setYLims(ax, lims):
|
||||
ax.set_ylim(lims)
|
||||
|
||||
def setYTickLabels(self, pos, labels):
|
||||
@ -1298,7 +1458,8 @@ class PhaseDefaults(QtGui.QDialog):
|
||||
checkbox.setChecked(bool(phase in self.current_phases))
|
||||
row += 1
|
||||
|
||||
def create_phase_box(self, phase_name):
|
||||
@staticmethod
|
||||
def create_phase_box(phase_name):
|
||||
checkbox = QtGui.QCheckBox(phase_name)
|
||||
return checkbox
|
||||
|
||||
@ -1433,7 +1594,6 @@ class PickDlg(QDialog):
|
||||
self.multicompfig.draw()
|
||||
self.multicompfig.setFocus()
|
||||
|
||||
|
||||
# set plot labels
|
||||
self.setPlotLabels()
|
||||
|
||||
@ -1459,7 +1619,6 @@ class PickDlg(QDialog):
|
||||
self.setWindowTitle('Pickwindow on station: {}'.format(self.getStation()))
|
||||
self.setWindowState(QtCore.Qt.WindowMaximized)
|
||||
|
||||
|
||||
def setupUi(self):
|
||||
menuBar = QtGui.QMenuBar(self)
|
||||
if not self._embedded:
|
||||
@ -1683,9 +1842,10 @@ class PickDlg(QDialog):
|
||||
func = {True: self.model.get_ray_paths_geo,
|
||||
False: self.model.get_travel_times_geo}
|
||||
phases = self.prepare_phases()
|
||||
station_id = self.data.traces[0].get_id()
|
||||
parser = self.metadata[1]
|
||||
station_coords = parser.get_coordinates(station_id)
|
||||
trace = self.data.traces[0]
|
||||
station_id = trace.get_id()
|
||||
starttime = trace.stats.starttime
|
||||
station_coords = self.metadata.get_coordinates(station_id, starttime)
|
||||
origins = self.pylot_event.origins
|
||||
if origins:
|
||||
source_origin = origins[0]
|
||||
@ -1699,7 +1859,8 @@ class PickDlg(QDialog):
|
||||
phases)
|
||||
self.arrivals = arrivals
|
||||
|
||||
def prepare_phases(self):
|
||||
@staticmethod
|
||||
def prepare_phases():
|
||||
settings = QtCore.QSettings()
|
||||
p_phases = settings.value('p_phases')
|
||||
s_phases = settings.value('s_phases')
|
||||
@ -1805,7 +1966,6 @@ class PickDlg(QDialog):
|
||||
filterMenu.addAction(self.autoFilterAction)
|
||||
filterMenu.addAction(filterOptionsAction)
|
||||
|
||||
|
||||
def filterOptions(self):
|
||||
if self.orig_parent.adjustFilterOptions():
|
||||
phase = None
|
||||
@ -1875,7 +2035,8 @@ class PickDlg(QDialog):
|
||||
self.currentPhase = str(self.s_button.text())
|
||||
self.activatePicking()
|
||||
|
||||
def getPhaseID(self, phase):
|
||||
@staticmethod
|
||||
def getPhaseID(phase):
|
||||
return identifyPhaseID(phase)
|
||||
|
||||
def set_button_border_color(self, button, color=None):
|
||||
@ -1936,10 +2097,10 @@ class PickDlg(QDialog):
|
||||
self.zoomAction.trigger()
|
||||
self.multicompfig.disconnectEvents()
|
||||
self.cidpress = self.multicompfig.connectPressEvent(self.setIniPick)
|
||||
if not self.filterActionP.isChecked() and not self.filterActionS.isChecked():
|
||||
if self.autoFilterAction.isChecked():
|
||||
for filteraction in [self.filterActionP, self.filterActionS]:
|
||||
filteraction.setChecked(False)
|
||||
self.filterWFData()
|
||||
else:
|
||||
self.draw()
|
||||
else:
|
||||
self.draw()
|
||||
@ -2087,7 +2248,8 @@ class PickDlg(QDialog):
|
||||
st += data.select(channel=action.text())
|
||||
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
|
||||
# zoomfactor*noiselevel are found within -0.5*norm and 0.5*norm
|
||||
scaleFactor = (norm / 2.) / (zoomfactor * noiselevel)
|
||||
@ -2349,43 +2511,38 @@ class PickDlg(QDialog):
|
||||
lpp = picks['lpp'] - self.getStartTime()
|
||||
spe = picks['spe']
|
||||
|
||||
if not picktype in ['auto', 'manual']:
|
||||
raise TypeError('Unknown picktype {0}'.format(picktype))
|
||||
|
||||
if picktype == 'manual':
|
||||
baseorder = 5
|
||||
elif picktype == 'auto':
|
||||
baseorder = 0
|
||||
|
||||
color = pick_color_plt(picktype, phaseID, quality)
|
||||
if not textOnly:
|
||||
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,
|
||||
label='{}-Pick (quality: {})'.format(phase, quality), picker=5)
|
||||
self.phaseLines[phase] = vl
|
||||
label='{}-{}-Pick (quality: {})'.format(phase, picktype, quality), picker=5,
|
||||
zorder=baseorder+9)
|
||||
phaseLineKey = '{}-{}'.format(phase, picktype)
|
||||
self.phaseLines[phaseLineKey] = vl
|
||||
if spe:
|
||||
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']:
|
||||
linestyle_epp, width_epp = pick_linestyle_plt(picktype, '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']:
|
||||
linestyle_lpp, width_lpp = pick_linestyle_plt(picktype, 'lpp')
|
||||
ax.axvline(lpp, ylims[0], ylims[1], color=color, linestyle=linestyle_lpp,
|
||||
linewidth=width_lpp, label='{}-LPP'.format(phase))
|
||||
# else:
|
||||
# ax.plot([mpp, mpp], ylims, color=color, linestyle=linestyle_mpp, linewidth=width_mpp,
|
||||
# label='{}-Pick (NO PICKERROR)'.format(phase), picker=5)
|
||||
linewidth=width_lpp, label='{}-{}-LPP'.format(phase, picktype), zorder=baseorder+2)
|
||||
if picktype == 'auto':
|
||||
ax.plot(mpp, ylims[1], color=color, marker='v', zorder=baseorder+3)
|
||||
ax.plot(mpp, ylims[0], color=color, marker='^', zorder=baseorder+3)
|
||||
# append phase text (if textOnly: draw with current ylims)
|
||||
self.phaseText.append(ax.text(mpp, ylims[1], phase, color=color))
|
||||
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))
|
||||
|
||||
self.phaseText.append(ax.text(mpp, ylims[1], phase, color=color, zorder=baseorder+10))
|
||||
ax.legend(loc=1)
|
||||
|
||||
def connect_mouse_motion(self):
|
||||
@ -2421,7 +2578,7 @@ class PickDlg(QDialog):
|
||||
if not x:
|
||||
return
|
||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||
if pick_rel == None:
|
||||
if pick_rel is None:
|
||||
return
|
||||
pick = allpicks[picktype][phase]
|
||||
message = '{} {}-pick'.format(picktype, phase)
|
||||
@ -2442,7 +2599,7 @@ class PickDlg(QDialog):
|
||||
return
|
||||
x = event.mouseevent.xdata
|
||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||
if pick_rel == None:
|
||||
if pick_rel is None:
|
||||
return
|
||||
pick = allpicks[picktype][phase]
|
||||
message = '{} {}-pick'.format(picktype, phase)
|
||||
@ -2499,7 +2656,7 @@ class PickDlg(QDialog):
|
||||
if not self.picks and not self.autopicks:
|
||||
return
|
||||
allpicks, pick_rel, phase, picktype = self.identify_selected_picks(x)
|
||||
if pick_rel == None:
|
||||
if pick_rel is None:
|
||||
return
|
||||
# delete the value from corresponding dictionary
|
||||
allpicks[picktype].pop(phase)
|
||||
@ -2507,8 +2664,9 @@ class PickDlg(QDialog):
|
||||
if phase in self.phaseLines.keys():
|
||||
del (self.phaseLines[phase])
|
||||
# information output
|
||||
msg = 'Deleted {} pick for phase {}, at timestamp {} (relative time: {} s)'
|
||||
print(msg.format(picktype, phase, self.getStartTime()+pick_rel, pick_rel))
|
||||
msg = 'Deleted {} pick for phase {}, station {} at timestamp {} (relative time: {} s)'
|
||||
print(msg.format(picktype, phase, '{}.{}'.format(self.network, self.station),
|
||||
self.getStartTime() + pick_rel, pick_rel))
|
||||
self.setDirty(True)
|
||||
|
||||
def identify_selected_picks(self, x):
|
||||
@ -2534,8 +2692,6 @@ class PickDlg(QDialog):
|
||||
pick_rel, phase, picktype = X[index]
|
||||
return allpicks, pick_rel, phase, picktype
|
||||
|
||||
|
||||
|
||||
def drawPhaseText(self):
|
||||
self.drawPicks(picktype='manual', textOnly=True)
|
||||
self.drawPicks(picktype='auto', textOnly=True)
|
||||
@ -2626,15 +2782,18 @@ class PickDlg(QDialog):
|
||||
settings = QSettings()
|
||||
settings.setValue('autoFilter', self.autoFilterAction.isChecked())
|
||||
|
||||
def updateChannelSettingsP(self, action):
|
||||
@staticmethod
|
||||
def updateChannelSettingsP(action):
|
||||
settings = QSettings()
|
||||
settings.setValue('p_channel_{}'.format(action.text()), action.isChecked())
|
||||
|
||||
def updateChannelSettingsS(self, action):
|
||||
@staticmethod
|
||||
def updateChannelSettingsS(action):
|
||||
settings = QSettings()
|
||||
settings.setValue('s_channel_{}'.format(action.text()), action.isChecked())
|
||||
|
||||
def getChannelSettingsP(self, channel):
|
||||
@staticmethod
|
||||
def getChannelSettingsP(channel):
|
||||
settings = QSettings()
|
||||
rval = real_Bool(settings.value('p_channel_{}'.format(channel)))
|
||||
compclass = settings.value('compclass')
|
||||
@ -2648,7 +2807,8 @@ class PickDlg(QDialog):
|
||||
rval = False
|
||||
return rval
|
||||
|
||||
def getChannelSettingsS(self, channel):
|
||||
@staticmethod
|
||||
def getChannelSettingsS(channel):
|
||||
settings = QSettings()
|
||||
rval = real_Bool(settings.value('s_channel_{}'.format(channel)))
|
||||
compclass = settings.value('compclass')
|
||||
@ -2662,7 +2822,6 @@ class PickDlg(QDialog):
|
||||
rval = False
|
||||
return rval
|
||||
|
||||
|
||||
def resetPlot(self):
|
||||
self.resetZoom()
|
||||
self.refreshPlot()
|
||||
@ -2777,6 +2936,7 @@ class MultiEventWidget(QWidget):
|
||||
'''
|
||||
|
||||
'''
|
||||
|
||||
def __init__(self, options=None, parent=None, windowflag=1):
|
||||
QtGui.QWidget.__init__(self, parent, windowflag)
|
||||
|
||||
@ -2784,6 +2944,14 @@ class MultiEventWidget(QWidget):
|
||||
self.setupUi()
|
||||
# set initial size
|
||||
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):
|
||||
# init main layout
|
||||
@ -2870,13 +3038,13 @@ class MultiEventWidget(QWidget):
|
||||
for rb in self.rb_dict.values():
|
||||
if rb.isChecked():
|
||||
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):
|
||||
for rb in self.rb_dict.values():
|
||||
rb.setEnabled(bool)
|
||||
self.start_button.setEnabled(bool)
|
||||
self.pb.setVisible(not(bool))
|
||||
self.pb.setVisible(not bool)
|
||||
self._pb_space.setVisible(bool)
|
||||
self.eventbox.setEnabled(bool)
|
||||
self.button_clear.setEnabled(bool)
|
||||
@ -2958,7 +3126,7 @@ class AutoPickWidget(MultiEventWidget):
|
||||
def reinitEvents2plot(self):
|
||||
for eventID, eventDict in self.events2plot.items():
|
||||
for widget_key, widget in eventDict.items():
|
||||
del(widget)
|
||||
del widget
|
||||
self.events2plot = {}
|
||||
self.eventbox.clear()
|
||||
self.refresh_plot_tabs()
|
||||
@ -2986,6 +3154,14 @@ class CompareEventsWidget(MultiEventWidget):
|
||||
self.connect_buttons()
|
||||
self.setWindowTitle('Compare events')
|
||||
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):
|
||||
self.start_button.clicked.connect(self.run)
|
||||
@ -3062,6 +3238,7 @@ class TuneAutopicker(QWidget):
|
||||
self.add_log()
|
||||
self.set_stretch()
|
||||
self.resize(1280, 720)
|
||||
self.center()
|
||||
self._manual_pick_plots = []
|
||||
if hasattr(self.parent(), 'metadata'):
|
||||
self.metadata = self.parent().metadata
|
||||
@ -3070,6 +3247,13 @@ class TuneAutopicker(QWidget):
|
||||
# self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||
# 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):
|
||||
for key, value in fig_dict.items():
|
||||
if key is not 'mainFig':
|
||||
@ -3147,7 +3331,7 @@ class TuneAutopicker(QWidget):
|
||||
self.data.setWFData(fnames)
|
||||
wfdat = self.data.getWFData() # all available streams
|
||||
# remove possible underscores in station names
|
||||
wfdat = remove_underscores(wfdat)
|
||||
#wfdat = remove_underscores(wfdat)
|
||||
# rotate misaligned stations to ZNE
|
||||
# check for gaps and doubled channels
|
||||
check4gaps(wfdat)
|
||||
@ -3161,7 +3345,7 @@ class TuneAutopicker(QWidget):
|
||||
self.fill_figure_tabs()
|
||||
|
||||
def init_pbwidget(self):
|
||||
self.pb_widget = QtGui.QWidget()
|
||||
self.pb_widget = ProgressBarWidget()
|
||||
|
||||
def init_tab_names(self):
|
||||
self.ptb_names = ['aicFig', 'slength', 'checkZ4s', 'refPpick', 'el_Ppick', 'fm_picker']
|
||||
@ -3201,7 +3385,7 @@ class TuneAutopicker(QWidget):
|
||||
return self.eventBox.currentText().split('/')[-1]
|
||||
|
||||
def get_current_event_fp(self):
|
||||
return self.eventBox.currentText()
|
||||
return self.eventBox.currentText().split('*')[0]
|
||||
|
||||
def get_current_event_picks(self, station):
|
||||
event = self.get_current_event()
|
||||
@ -3220,7 +3404,8 @@ class TuneAutopicker(QWidget):
|
||||
def get_current_station_id(self):
|
||||
return str(self.stationBox.currentText())
|
||||
|
||||
def gen_tab_widget(self, name, canvas):
|
||||
@staticmethod
|
||||
def gen_tab_widget(name, canvas):
|
||||
widget = QtGui.QWidget()
|
||||
v_layout = QtGui.QVBoxLayout()
|
||||
v_layout.addWidget(canvas)
|
||||
@ -3398,7 +3583,7 @@ class TuneAutopicker(QWidget):
|
||||
if index == -1:
|
||||
index += 1
|
||||
nevents = self.eventBox.model().rowCount()
|
||||
path = self.eventBox.itemText(index)
|
||||
path = self.eventBox.itemText(index).split('*')[0]
|
||||
if project.getEventFromPath(path).isTestEvent():
|
||||
for index in range(nevents):
|
||||
path = self.eventBox.itemText(index)
|
||||
@ -3491,7 +3676,7 @@ class TuneAutopicker(QWidget):
|
||||
if hasattr(self, 'pdlg_widget'):
|
||||
if self.pdlg_widget:
|
||||
self.pdlg_widget.setParent(None)
|
||||
del(self.pdlg_widget)
|
||||
del self.pdlg_widget
|
||||
if hasattr(self, 'overview'):
|
||||
self.overview.setParent(None)
|
||||
if hasattr(self, 'p_tabs'):
|
||||
@ -3546,10 +3731,18 @@ class PylotParaBox(QtGui.QWidget):
|
||||
self.params_to_gui()
|
||||
self._toggle_advanced_settings()
|
||||
self.resize(720, 860)
|
||||
self.center()
|
||||
self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||
self.accepted.connect(self.params_from_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):
|
||||
self._main_layout = QtGui.QVBoxLayout()
|
||||
self._advanced_layout = QtGui.QVBoxLayout()
|
||||
@ -3650,7 +3843,8 @@ class PylotParaBox(QtGui.QWidget):
|
||||
grid.addWidget(box, index1, 2)
|
||||
return grid
|
||||
|
||||
def create_box(self, typ, tooltip):
|
||||
@staticmethod
|
||||
def create_box(typ, tooltip):
|
||||
if typ == str:
|
||||
box = QtGui.QLineEdit()
|
||||
elif typ == float:
|
||||
@ -3665,7 +3859,8 @@ class PylotParaBox(QtGui.QWidget):
|
||||
raise TypeError('Unrecognized type {}'.format(typ))
|
||||
return box
|
||||
|
||||
def create_multi_box(self, boxes, headline=None):
|
||||
@staticmethod
|
||||
def create_multi_box(boxes, headline=None):
|
||||
box = QtGui.QWidget()
|
||||
gl = QtGui.QGridLayout()
|
||||
column = 0
|
||||
@ -3993,7 +4188,7 @@ class AutoPickDlg(QDialog):
|
||||
self.gb.setLayout(self.jobLayout)
|
||||
|
||||
def exportParameter(self):
|
||||
self.parent().exportAllEvents()
|
||||
self.parent().exportEvents()
|
||||
pylot_params = self.parent()._inputs
|
||||
self.addEvents2pp(pylot_params)
|
||||
pylot_params.export2File(self.pp_export)
|
||||
@ -4366,7 +4561,8 @@ class PhasesTab(PropTab):
|
||||
self.PphasesEdit.setText(p_phases)
|
||||
self.SphasesEdit.setText(s_phases)
|
||||
|
||||
def sortPhases(self, phases):
|
||||
@staticmethod
|
||||
def sortPhases(phases):
|
||||
sorted_phases = {'P': [],
|
||||
'S': []}
|
||||
for phase in phases:
|
||||
@ -4393,7 +4589,7 @@ class GraphicsTab(PropTab):
|
||||
super(GraphicsTab, self).__init__(parent)
|
||||
self.pylot_mainwindow = parent._pylot_mainwindow
|
||||
self.init_layout()
|
||||
self.add_pg_cb()
|
||||
#self.add_pg_cb()
|
||||
self.add_nth_sample()
|
||||
self.add_style_settings()
|
||||
self.setLayout(self.main_layout)
|
||||
@ -4429,36 +4625,16 @@ class GraphicsTab(PropTab):
|
||||
self.main_layout.addWidget(label, 1, 0)
|
||||
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):
|
||||
selected_style = self.style_cb.currentText()
|
||||
self.pylot_mainwindow.set_style(selected_style)
|
||||
|
||||
def getValues(self):
|
||||
values = {'nth_sample': self.spinbox_nth_sample.value(),
|
||||
'pyqtgraphic': self.checkbox_pg.isChecked()}
|
||||
values = {'nth_sample': self.spinbox_nth_sample.value()}
|
||||
return values
|
||||
|
||||
def resetValues(self, infile=None):
|
||||
values = {'nth_sample': self.spinbox_nth_sample.setValue(1),
|
||||
'pyqtgraphic': self.checkbox_pg.setChecked(True)}
|
||||
values = {'nth_sample': self.spinbox_nth_sample.setValue(1)}
|
||||
return values
|
||||
|
||||
|
||||
@ -4607,7 +4783,8 @@ class LocalisationTab(PropTab):
|
||||
self.rootlabel.setText("{0} root directory".format(curtool))
|
||||
self.binlabel.setText("{0} bin directory".format(curtool))
|
||||
|
||||
def selectDirectory(self, edit):
|
||||
@staticmethod
|
||||
def selectDirectory(edit):
|
||||
selected_directory = QFileDialog.getExistingDirectory()
|
||||
# check if string is empty
|
||||
if selected_directory:
|
||||
@ -4705,7 +4882,8 @@ class FilterOptionsDialog(QDialog):
|
||||
'S': FilterOptions()}
|
||||
|
||||
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'))}
|
||||
self.setupUi()
|
||||
self.updateUi()
|
||||
@ -4773,6 +4951,9 @@ class FilterOptionsDialog(QDialog):
|
||||
def checkMinMax(self):
|
||||
returnvals = []
|
||||
for foWidget in self.filterOptionWidgets.values():
|
||||
if foWidget.filterOptions._filtertype in ['highpass', 'lowpass']:
|
||||
returnvals.append(True)
|
||||
continue
|
||||
returnvals.append(foWidget.checkMin())
|
||||
returnvals.append(foWidget.checkMax())
|
||||
if all(returnvals):
|
||||
@ -4831,7 +5012,7 @@ class FilterOptionsWidget(QWidget):
|
||||
# self.getFilterOptions().getFreq()[1])
|
||||
# else:
|
||||
|
||||
self.typeOptions = [None, "bandpass", "bandstop", "lowpass", "highpass"]
|
||||
self.typeOptions = ["bandpass", "bandstop", "lowpass", "highpass"]
|
||||
|
||||
self.resetButton = QPushButton('Reset')
|
||||
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.checkAutoManu()
|
||||
|
||||
self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||
|
||||
def checkAutoManu(self):
|
||||
self.updateMFfromWidget()
|
||||
|
||||
|
@ -67,4 +67,3 @@ stylecolors = {
|
||||
'filename': 'bright.qss'}
|
||||
}
|
||||
}
|
||||
|
||||
|
2
setup.py
2
setup.py
@ -8,7 +8,7 @@ setup(
|
||||
packages=['pylot', 'pylot.core', 'pylot.core.loc', 'pylot.core.pick',
|
||||
'pylot.core.io', 'pylot.core.util', 'pylot.core.active',
|
||||
'pylot.core.analysis', 'pylot.testing'],
|
||||
requires=['obspy', 'PySide', 'matplotlib', 'numpy'],
|
||||
requires=['obspy', 'PySide', 'matplotlib', 'numpy', 'scipy', 'pyqtgraph'],
|
||||
url='dummy',
|
||||
license='LGPLv3',
|
||||
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 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 tests.utils import HidePrints
|
||||
|
||||
|
||||
class TestMetadata(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
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)
|
||||
|
||||
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},
|
||||
'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}
|
||||
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, 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)
|
||||
result[channel] = coords
|
||||
self.assertDictEqual(result[channel], expected[channel])
|
||||
|
||||
|
||||
class TestMetadataAdding(unittest.TestCase):
|
||||
"""Tests if adding files and directories to a metadata object works."""
|
||||
|
||||
def setUp(self):
|
||||
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()
|
||||
|
||||
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')
|
||||
self.m.add_inventory_file(fpath)
|
||||
# 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(['data', 'invtype'], self.m.inventory_files['metadata1/DATALESS.BW.WETR..HHZ'].keys()) # is the required information attacht to the filename?
|
||||
self.assertEqual([os.path.join(self.metadata_folders[0], 'DATALESS.BW.WETR..HHZ')],
|
||||
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.assertEqual([self.metadata_folders[0]], self.m.inventories)
|
||||
|
||||
@ -66,7 +95,8 @@ class TestMetadataRemoval(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
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()
|
||||
|
||||
def test_remove_all_inventories(self):
|
||||
@ -93,6 +123,7 @@ class TestMetadataRemoval(unittest.TestCase):
|
||||
exist in the instance."""
|
||||
# add multiple inventories
|
||||
self.m.add_inventory(self.metadata_folders[0])
|
||||
with HidePrints():
|
||||
self.m.remove_inventory('metadata_not_existing')
|
||||
self.assertIn(self.metadata_folders[0], self.m.inventories)
|
||||
|
||||
@ -102,3 +133,202 @@ class TestMetadataRemoval(unittest.TestCase):
|
||||
self.assertDictEqual({}, metadata.seed_ids)
|
||||
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