Compare commits
81
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cce05b035 | ||
|
|
7326f061e5 | ||
|
|
1a18401fe3 | ||
|
|
ec930dbc12 | ||
|
|
b991f771af | ||
|
|
2c3b1876ab | ||
|
|
0acd23d4d0 | ||
|
|
f349c8bc7e | ||
|
|
6688ef845d | ||
|
|
5b18e9ab71 | ||
|
|
c79e886d77 | ||
|
|
76f2d5d972 | ||
|
|
2d08fd029d | ||
|
|
8f22d438d3 | ||
|
|
93b7de3baa | ||
|
|
05642e775b | ||
|
|
47205ca493 | ||
|
|
5c7f0b56eb | ||
|
|
c574031931 | ||
|
|
e1a0fde619 | ||
|
|
48d196df11 | ||
|
|
6cc9cb4a96 | ||
|
|
5eab686445 | ||
|
|
b12e7937ac | ||
|
|
78f2dbcab2 | ||
|
|
8b95c7a0fe | ||
|
|
65dbaad446 | ||
|
|
5b97d51517 | ||
|
|
f03ace75e7 | ||
|
|
9c78471d20 | ||
|
|
09d2fb1022 | ||
|
|
3cae6d3a78 | ||
|
|
2e85d083a3 | ||
|
|
ba4e6cfe50 | ||
|
|
1f16d01648 | ||
|
|
3069e7d526 | ||
|
|
a9aeb7aaa3 | ||
|
|
b9adb182ad | ||
|
|
a823eb2440 | ||
|
|
486e3dc9c3 | ||
|
|
8d356050d7 | ||
|
|
43cab3767f | ||
|
|
b3fdbc811e | ||
|
|
a1f6c5ffca | ||
|
|
e4e7afa996 | ||
|
|
9fce4998d3 | ||
|
|
c468bfbe84 | ||
|
|
4861d33e9a | ||
|
|
f5f4635c3d | ||
|
|
b12d92eebb | ||
|
|
e9da81376e | ||
|
|
e68fc849f0 | ||
|
|
efb117177c | ||
|
|
0634d24814 | ||
|
|
43c2b97b3d | ||
|
|
8d94440e77 | ||
|
|
66b7dea706 | ||
|
|
ebf6d4806a | ||
|
|
207d0b3a6f | ||
|
|
3b3bbc29d1 | ||
|
|
0c3fca9299 | ||
|
|
2d33a60421 | ||
|
|
a8c6f4c972 | ||
|
|
0d91f9e3fe | ||
|
|
494d281d61 | ||
|
|
5ef427ec12 | ||
|
|
29cf978782 | ||
|
|
091449819c | ||
|
|
cd9c139349 | ||
|
|
084fb10cea | ||
|
|
dde9520879 | ||
|
|
7847f40a35 | ||
|
|
2c188432a1 | ||
|
|
86dc0f5436 | ||
|
|
83ba63a3fd | ||
|
|
3392100206 | ||
|
|
401265eb3a | ||
|
|
dd685d5d5e | ||
|
|
3cd17ff364 | ||
|
|
d879aa1a8b | ||
|
|
445f1da5ac |
@@ -25,6 +25,7 @@ https://www.iconfinder.com/iconsets/flavour
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
@@ -72,24 +73,25 @@ from pylot.core.util.errors import DatastructureError, \
|
|||||||
OverwriteError
|
OverwriteError
|
||||||
from pylot.core.util.connection import checkurl
|
from pylot.core.util.connection import checkurl
|
||||||
from pylot.core.util.dataprocessing import Metadata, restitute_data
|
from pylot.core.util.dataprocessing import Metadata, restitute_data
|
||||||
from pylot.core.util.utils import fnConstructor, getLogin, \
|
from pylot.core.util.utils import fnConstructor, get_login, \
|
||||||
full_range, readFilterInformation, pick_color_plt, \
|
full_range, readFilterInformation, pick_color_plt, \
|
||||||
pick_linestyle_plt, identifyPhaseID, excludeQualityClasses, \
|
pick_linestyle_plt, identifyPhaseID, excludeQualityClasses, \
|
||||||
transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
transform_colors_mpl, transform_colors_mpl_str, getAutoFilteroptions, check_all_obspy, \
|
||||||
check_all_pylot, get_Bool, get_None
|
check_all_pylot, get_bool, get_none
|
||||||
from pylot.core.util.gui import make_pen
|
from pylot.core.util.gui import make_pen
|
||||||
from pylot.core.util.event import Event
|
from pylot.core.util.event import Event
|
||||||
from pylot.core.io.location import create_creation_info, create_event
|
from pylot.core.io.location import create_creation_info, create_event
|
||||||
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
||||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||||
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||||
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget
|
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
|
||||||
|
SpectrogramTab, SearchFileByExtensionDialog
|
||||||
from pylot.core.util.array_map import Array_map
|
from pylot.core.util.array_map import Array_map
|
||||||
from pylot.core.util.structure import DATASTRUCTURE
|
from pylot.core.util.structure import DATASTRUCTURE
|
||||||
from pylot.core.util.thread import Thread, Worker
|
from pylot.core.util.thread import Thread, Worker
|
||||||
from pylot.core.util.version import get_git_version as _getVersionString
|
from pylot.core.util.version import get_git_version as _getVersionString
|
||||||
from pylot.core.io.getEventListFromXML import geteventlistfromxml
|
from pylot.core.io.getEventListFromXML import geteventlistfromxml
|
||||||
from pylot.core.io.getQualitiesfromxml import getQualitiesfromxml
|
from pylot.core.io.phases import getQualitiesfromxml
|
||||||
|
|
||||||
from pylot.styles import style_settings
|
from pylot.styles import style_settings
|
||||||
|
|
||||||
@@ -112,21 +114,19 @@ class MainWindow(QMainWindow):
|
|||||||
def __init__(self, parent=None, infile=None, reset_qsettings=False):
|
def __init__(self, parent=None, infile=None, reset_qsettings=False):
|
||||||
super(MainWindow, self).__init__(parent)
|
super(MainWindow, self).__init__(parent)
|
||||||
|
|
||||||
# check for default pylot.in-file
|
if infile and os.path.isfile(infile) is False:
|
||||||
if not infile:
|
infile = QFileDialog().getOpenFileName(caption='Choose PyLoT-input file')[0]
|
||||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
|
||||||
print('Using default input file {}'.format(infile))
|
|
||||||
if os.path.isfile(infile) == False:
|
|
||||||
infile = QFileDialog().getOpenFileName(caption='Choose PyLoT-input file')
|
|
||||||
|
|
||||||
if not os.path.exists(infile[0]):
|
if not os.path.exists(infile):
|
||||||
QMessageBox.warning(self, "PyLoT Warning",
|
QMessageBox.warning(self, "PyLoT Warning",
|
||||||
"No PyLoT-input file declared!")
|
"No PyLoT-input file declared! Using default parameters!")
|
||||||
sys.exit(0)
|
infile = None
|
||||||
self.infile = infile[0]
|
|
||||||
else:
|
|
||||||
self.infile = infile
|
|
||||||
self._inputs = PylotParameter(infile)
|
self._inputs = PylotParameter(infile)
|
||||||
|
if not infile:
|
||||||
|
self._inputs.reset_defaults()
|
||||||
|
|
||||||
|
self.infile = infile
|
||||||
self._props = None
|
self._props = None
|
||||||
|
|
||||||
self.gain = 1.
|
self.gain = 1.
|
||||||
@@ -178,6 +178,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.autodata = Data(self)
|
self.autodata = Data(self)
|
||||||
|
|
||||||
self.fnames = None
|
self.fnames = None
|
||||||
|
self.fnames_comp = None
|
||||||
self._stime = None
|
self._stime = None
|
||||||
|
|
||||||
# track deleted picks for logging
|
# track deleted picks for logging
|
||||||
@@ -193,7 +194,7 @@ class MainWindow(QMainWindow):
|
|||||||
if settings.value("user/FullName", None) is None:
|
if settings.value("user/FullName", None) is None:
|
||||||
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
|
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
|
||||||
settings.setValue("user/FullName", fulluser)
|
settings.setValue("user/FullName", fulluser)
|
||||||
settings.setValue("user/Login", getLogin())
|
settings.setValue("user/Login", get_login())
|
||||||
if settings.value("agency_id", None) is None:
|
if settings.value("agency_id", None) is None:
|
||||||
agency = QInputDialog.getText(self,
|
agency = QInputDialog.getText(self,
|
||||||
"Enter authority/institution name:",
|
"Enter authority/institution name:",
|
||||||
@@ -250,11 +251,11 @@ class MainWindow(QMainWindow):
|
|||||||
self._inputs.reset_defaults()
|
self._inputs.reset_defaults()
|
||||||
# check for default pylot.in-file
|
# check for default pylot.in-file
|
||||||
infile = os.path.join(pylot_config_dir, '.pylot.in')
|
infile = os.path.join(pylot_config_dir, '.pylot.in')
|
||||||
print('Using default input file {}'.format(infile))
|
logging.warning('Using default input file {}'.format(infile))
|
||||||
self._inputs.export2File(infile)
|
self._inputs.export2File(infile)
|
||||||
self.infile = infile
|
self.infile = infile
|
||||||
|
|
||||||
def setupUi(self):
|
def setupUi(self, use_logwidget=False):
|
||||||
try:
|
try:
|
||||||
self.startTime = min(
|
self.startTime = min(
|
||||||
[tr.stats.starttime for tr in self.data.wfdata])
|
[tr.stats.starttime for tr in self.data.wfdata])
|
||||||
@@ -480,7 +481,7 @@ class MainWindow(QMainWindow):
|
|||||||
"automatic pick "
|
"automatic pick "
|
||||||
"data.", False)
|
"data.", False)
|
||||||
self.compare_action.setEnabled(False)
|
self.compare_action.setEnabled(False)
|
||||||
self.qualities_action = self.createAction(parent=self, text='Show pick qualitites...',
|
self.qualities_action = self.createAction(parent=self, text='Show pick qualities...',
|
||||||
slot=self.pickQualities, shortcut='Alt+Q',
|
slot=self.pickQualities, shortcut='Alt+Q',
|
||||||
icon=qualities_icon, tip='Histogram of pick qualities')
|
icon=qualities_icon, tip='Histogram of pick qualities')
|
||||||
self.qualities_action.setEnabled(False)
|
self.qualities_action.setEnabled(False)
|
||||||
@@ -493,7 +494,6 @@ class MainWindow(QMainWindow):
|
|||||||
icon=eventlist_xml_icon,
|
icon=eventlist_xml_icon,
|
||||||
tip='Create an Eventlist from a XML File')
|
tip='Create an Eventlist from a XML File')
|
||||||
self.eventlist_xml_action.setEnabled(False)
|
self.eventlist_xml_action.setEnabled(False)
|
||||||
|
|
||||||
printAction = self.createAction(self, "&Print event ...",
|
printAction = self.createAction(self, "&Print event ...",
|
||||||
self.show_event_information, QKeySequence.Print,
|
self.show_event_information, QKeySequence.Print,
|
||||||
print_icon,
|
print_icon,
|
||||||
@@ -506,6 +506,8 @@ class MainWindow(QMainWindow):
|
|||||||
logAction = self.createAction(self, "&Show Log", self.showLogWidget,
|
logAction = self.createAction(self, "&Show Log", self.showLogWidget,
|
||||||
tip="""Display Log""")
|
tip="""Display Log""")
|
||||||
|
|
||||||
|
logAction.setEnabled(use_logwidget)
|
||||||
|
|
||||||
# create button group for component selection
|
# create button group for component selection
|
||||||
|
|
||||||
componentGroup = QActionGroup(self)
|
componentGroup = QActionGroup(self)
|
||||||
@@ -695,14 +697,17 @@ class MainWindow(QMainWindow):
|
|||||||
wf_tab = QtWidgets.QWidget(self)
|
wf_tab = QtWidgets.QWidget(self)
|
||||||
array_tab = QtWidgets.QWidget(self)
|
array_tab = QtWidgets.QWidget(self)
|
||||||
events_tab = QtWidgets.QWidget(self)
|
events_tab = QtWidgets.QWidget(self)
|
||||||
|
spectro_tab = QtWidgets.QWidget(self)
|
||||||
|
|
||||||
# init main widgets layouts
|
# init main widgets layouts
|
||||||
self.wf_layout = QtWidgets.QVBoxLayout()
|
self.wf_layout = QtWidgets.QVBoxLayout()
|
||||||
self.array_layout = QtWidgets.QVBoxLayout()
|
self.array_layout = QtWidgets.QVBoxLayout()
|
||||||
self.events_layout = QtWidgets.QVBoxLayout()
|
self.events_layout = QtWidgets.QVBoxLayout()
|
||||||
|
self.spectro_layout = QtWidgets.QVBoxLayout()
|
||||||
wf_tab.setLayout(self.wf_layout)
|
wf_tab.setLayout(self.wf_layout)
|
||||||
array_tab.setLayout(self.array_layout)
|
array_tab.setLayout(self.array_layout)
|
||||||
events_tab.setLayout(self.events_layout)
|
events_tab.setLayout(self.events_layout)
|
||||||
|
spectro_tab.setLayout(self.spectro_layout)
|
||||||
|
|
||||||
# tighten up layouts inside tabs
|
# tighten up layouts inside tabs
|
||||||
for layout in [self.wf_layout, self.array_layout, self.events_layout]:
|
for layout in [self.wf_layout, self.array_layout, self.events_layout]:
|
||||||
@@ -713,12 +718,14 @@ class MainWindow(QMainWindow):
|
|||||||
self.tabs.addTab(wf_tab, 'Waveform Plot')
|
self.tabs.addTab(wf_tab, 'Waveform Plot')
|
||||||
self.tabs.addTab(array_tab, 'Array Map')
|
self.tabs.addTab(array_tab, 'Array Map')
|
||||||
self.tabs.addTab(events_tab, 'Eventlist')
|
self.tabs.addTab(events_tab, 'Eventlist')
|
||||||
|
self.tabs.addTab(spectro_tab, 'Spectro')
|
||||||
|
|
||||||
self.wf_layout.addWidget(self.no_data_label)
|
self.wf_layout.addWidget(self.no_data_label)
|
||||||
self.wf_layout.addWidget(self.wf_scroll_area)
|
self.wf_layout.addWidget(self.wf_scroll_area)
|
||||||
self.wf_scroll_area.setWidgetResizable(True)
|
self.wf_scroll_area.setWidgetResizable(True)
|
||||||
self.init_array_tab()
|
self.init_array_tab()
|
||||||
self.init_event_table()
|
self.init_event_table()
|
||||||
|
self.init_spectro_tab()
|
||||||
self.tabs.setCurrentIndex(0)
|
self.tabs.setCurrentIndex(0)
|
||||||
|
|
||||||
self.eventLabel = QLabel()
|
self.eventLabel = QLabel()
|
||||||
@@ -731,13 +738,19 @@ class MainWindow(QMainWindow):
|
|||||||
_widget.setLayout(self._main_layout)
|
_widget.setLayout(self._main_layout)
|
||||||
_widget.showFullScreen()
|
_widget.showFullScreen()
|
||||||
|
|
||||||
|
|
||||||
|
if use_logwidget:
|
||||||
self.logwidget = LogWidget(parent=None)
|
self.logwidget = LogWidget(parent=None)
|
||||||
self.logwidget.show()
|
self.logwidget.show()
|
||||||
sys.stdout = self.logwidget.stdout
|
self.stdout = self.logwidget.stdout
|
||||||
sys.stderr = self.logwidget.stderr
|
self.stderr = self.logwidget.stderr
|
||||||
|
|
||||||
self.setCentralWidget(_widget)
|
self.setCentralWidget(_widget)
|
||||||
|
|
||||||
|
# Need to store PickQualities Window somewhere so it doesnt disappear
|
||||||
|
self.pickQualitiesWindow = None
|
||||||
|
|
||||||
|
|
||||||
def init_wfWidget(self):
|
def init_wfWidget(self):
|
||||||
xlab = self.startTime.strftime('seconds since %Y/%m/%d %H:%M:%S (%Z)')
|
xlab = self.startTime.strftime('seconds since %Y/%m/%d %H:%M:%S (%Z)')
|
||||||
plottitle = None # "Overview: {0} components ".format(self.getComponent())
|
plottitle = None # "Overview: {0} components ".format(self.getComponent())
|
||||||
@@ -991,17 +1004,16 @@ class MainWindow(QMainWindow):
|
|||||||
return
|
return
|
||||||
refresh = False
|
refresh = False
|
||||||
events = self.project.eventlist
|
events = self.project.eventlist
|
||||||
sld = SingleTextLineDialog(label='Specify file extension: ', default_text='.xml')
|
sld = SearchFileByExtensionDialog(label='Specify file extension: ', default_text='.xml',
|
||||||
|
events=events)
|
||||||
if not sld.exec_():
|
if not sld.exec_():
|
||||||
return
|
return
|
||||||
fext = sld.lineEdit.text()
|
|
||||||
# fext = '.xml'
|
filenames = sld.getChecked()
|
||||||
for event in events:
|
for event in events:
|
||||||
path = event.path
|
for filename in filenames:
|
||||||
eventname = path.split('/')[-1] # or event.pylot_id
|
if os.path.isfile(filename) and event.pylot_id in filename:
|
||||||
filename = os.path.join(path, 'PyLoT_' + eventname + fext)
|
self.load_data(filename, draw=False, event=event, ask_user=True, merge_strategy=sld.merge_strategy)
|
||||||
if os.path.isfile(filename):
|
|
||||||
self.load_data(filename, draw=False, event=event, overwrite=True)
|
|
||||||
refresh = True
|
refresh = True
|
||||||
if not refresh:
|
if not refresh:
|
||||||
return
|
return
|
||||||
@@ -1010,8 +1022,8 @@ class MainWindow(QMainWindow):
|
|||||||
self.fill_eventbox()
|
self.fill_eventbox()
|
||||||
self.setDirty(True)
|
self.setDirty(True)
|
||||||
|
|
||||||
def load_data(self, fname=None, loc=False, draw=True, event=None, overwrite=False):
|
def load_data(self, fname=None, loc=False, draw=True, event=None, ask_user=False, merge_strategy='Overwrite'):
|
||||||
if not overwrite:
|
if not ask_user:
|
||||||
if not self.okToContinue():
|
if not self.okToContinue():
|
||||||
return
|
return
|
||||||
if fname is None:
|
if fname is None:
|
||||||
@@ -1025,9 +1037,12 @@ class MainWindow(QMainWindow):
|
|||||||
data = Data(self, event)
|
data = Data(self, event)
|
||||||
try:
|
try:
|
||||||
data_new = Data(self, evtdata=str(fname))
|
data_new = Data(self, evtdata=str(fname))
|
||||||
# MP MP commented because adding several picks might cause inconsistencies
|
if merge_strategy == 'Overwrite':
|
||||||
data = data_new
|
data = data_new
|
||||||
# data += data_new
|
elif merge_strategy == 'Merge':
|
||||||
|
data += data_new
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f'Unknown merge strategy: {merge_strategy}')
|
||||||
except ValueError:
|
except ValueError:
|
||||||
qmb = QMessageBox(self, icon=QMessageBox.Question,
|
qmb = QMessageBox(self, icon=QMessageBox.Question,
|
||||||
text='Warning: Missmatch in event identifiers {} and {}. Continue?'.format(
|
text='Warning: Missmatch in event identifiers {} and {}. Continue?'.format(
|
||||||
@@ -1115,16 +1130,19 @@ class MainWindow(QMainWindow):
|
|||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
def getWFFnames_from_eventbox(self, eventbox=None):
|
def getWFFnames_from_eventbox(self, eventbox: str = None, subpath: str = None) -> list:
|
||||||
'''
|
'''
|
||||||
Return waveform filenames from event in eventbox.
|
Return waveform filenames from event in eventbox.
|
||||||
'''
|
'''
|
||||||
# TODO: add dataStructure class for obspyDMT here, this is just a workaround!
|
# TODO: add dataStructure class for obspyDMT here, this is just a workaround!
|
||||||
eventpath = self.get_current_event_path(eventbox)
|
eventpath = self.get_current_event_path(eventbox)
|
||||||
basepath = eventpath.split(os.path.basename(eventpath))[0]
|
if subpath:
|
||||||
|
eventpath = os.path.join(eventpath, subpath)
|
||||||
|
if not os.path.isdir(eventpath):
|
||||||
|
return []
|
||||||
if self.dataStructure:
|
if self.dataStructure:
|
||||||
if not eventpath:
|
if not eventpath:
|
||||||
return
|
return []
|
||||||
fnames = [os.path.join(eventpath, f) for f in os.listdir(eventpath)]
|
fnames = [os.path.join(eventpath, f) for f in os.listdir(eventpath)]
|
||||||
else:
|
else:
|
||||||
raise DatastructureError('not specified')
|
raise DatastructureError('not specified')
|
||||||
@@ -1168,7 +1186,7 @@ class MainWindow(QMainWindow):
|
|||||||
'''
|
'''
|
||||||
if not self.project:
|
if not self.project:
|
||||||
self.createNewProject()
|
self.createNewProject()
|
||||||
ed = getExistingDirectories(self, 'Select event directories...')
|
ed = GetExistingDirectories(self, 'Select event directories...')
|
||||||
if ed.exec_():
|
if ed.exec_():
|
||||||
eventlist = [event for event in ed.selectedFiles() if not event.endswith('EVENTS-INFO')]
|
eventlist = [event for event in ed.selectedFiles() if not event.endswith('EVENTS-INFO')]
|
||||||
basepath = eventlist[0].split(os.path.basename(eventlist[0]))[0]
|
basepath = eventlist[0].split(os.path.basename(eventlist[0]))[0]
|
||||||
@@ -1369,7 +1387,7 @@ class MainWindow(QMainWindow):
|
|||||||
index = eventBox.currentIndex()
|
index = eventBox.currentIndex()
|
||||||
tv = QtWidgets.QTableView()
|
tv = QtWidgets.QTableView()
|
||||||
header = tv.horizontalHeader()
|
header = tv.horizontalHeader()
|
||||||
header.setResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||||
header.setStretchLastSection(True)
|
header.setStretchLastSection(True)
|
||||||
header.hide()
|
header.hide()
|
||||||
tv.verticalHeader().hide()
|
tv.verticalHeader().hide()
|
||||||
@@ -1389,25 +1407,28 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
for id, event in enumerate(self.project.eventlist):
|
for id, event in enumerate(self.project.eventlist):
|
||||||
event_path = event.path
|
event_path = event.path
|
||||||
phaseErrors = {'P': self._inputs['timeerrorsP'],
|
#phaseErrors = {'P': self._inputs['timeerrorsP'],
|
||||||
'S': self._inputs['timeerrorsS']}
|
# 'S': self._inputs['timeerrorsS']}
|
||||||
|
|
||||||
ma_props = {'manual': event.pylot_picks,
|
man_au_picks = {'manual': event.pylot_picks,
|
||||||
'auto': event.pylot_autopicks}
|
'auto': event.pylot_autopicks}
|
||||||
ma_count = {'manual': 0,
|
npicks = {'manual': {'P': 0, 'S': 0},
|
||||||
'auto': 0}
|
'auto': {'P': 0, 'S': 0}}
|
||||||
ma_count_total = {'manual': 0,
|
npicks_total = {'manual': {'P': 0, 'S': 0},
|
||||||
'auto': 0}
|
'auto': {'P': 0, 'S': 0}}
|
||||||
|
|
||||||
for ma in ma_props.keys():
|
for ma in man_au_picks.keys():
|
||||||
if ma_props[ma]:
|
if man_au_picks[ma]:
|
||||||
for picks in ma_props[ma].values():
|
for picks in man_au_picks[ma].values():
|
||||||
for phasename, pick in picks.items():
|
for phasename, pick in picks.items():
|
||||||
if not type(pick) in [dict, AttribDict]:
|
if not type(pick) in [dict, AttribDict]:
|
||||||
continue
|
continue
|
||||||
|
phase_ID = identifyPhaseID(phasename)
|
||||||
|
if not phase_ID in npicks[ma].keys():
|
||||||
|
continue
|
||||||
if pick.get('spe'):
|
if pick.get('spe'):
|
||||||
ma_count[ma] += 1
|
npicks[ma][phase_ID] += 1
|
||||||
ma_count_total[ma] += 1
|
npicks_total[ma][phase_ID] += 1
|
||||||
|
|
||||||
event_ref = event.isRefEvent()
|
event_ref = event.isRefEvent()
|
||||||
event_test = event.isTestEvent()
|
event_test = event.isTestEvent()
|
||||||
@@ -1442,16 +1463,23 @@ class MainWindow(QMainWindow):
|
|||||||
if event.dirty:
|
if event.dirty:
|
||||||
event_str += '*'
|
event_str += '*'
|
||||||
item_path = QStandardItem(event_str)
|
item_path = QStandardItem(event_str)
|
||||||
item_time = QStandardItem('{}'.format(time))
|
item_time = QStandardItem('{}'.format(time.strftime("%Y-%m-%d %H:%M:%S") if time else ''))
|
||||||
item_lat = QStandardItem('{}'.format(lat))
|
item_lat = QStandardItem('{}'.format(lat))
|
||||||
item_lon = QStandardItem('{}'.format(lon))
|
item_lon = QStandardItem('{}'.format(lon))
|
||||||
item_depth = QStandardItem('{}'.format(depth))
|
item_depth = QStandardItem('{}'.format(depth))
|
||||||
item_localmag = QStandardItem('{}'.format(localmag))
|
item_localmag = QStandardItem('{}'.format(localmag))
|
||||||
item_momentmag = QStandardItem('{}'.format(momentmag))
|
item_momentmag = QStandardItem('{}'.format(momentmag))
|
||||||
item_nmp = QStandardItem('{}({})'.format(ma_count['manual'], ma_count_total['manual']))
|
|
||||||
|
item_nmp = QStandardItem()
|
||||||
|
item_nap = QStandardItem()
|
||||||
item_nmp.setIcon(self.manupicksicon_small)
|
item_nmp.setIcon(self.manupicksicon_small)
|
||||||
item_nap = QStandardItem('{}({})'.format(ma_count['auto'], ma_count_total['auto']))
|
|
||||||
item_nap.setIcon(self.autopicksicon_small)
|
item_nap.setIcon(self.autopicksicon_small)
|
||||||
|
|
||||||
|
for picktype, item_np in [('manual', item_nmp), ('auto', item_nap)]:
|
||||||
|
npicks_str = f"{npicks[picktype]['P']}|{npicks[picktype]['S']}"
|
||||||
|
#npicks_str += f"({npicks_total[picktype]['P']}/{npicks_total[picktype]['S']})"
|
||||||
|
item_np.setText(npicks_str)
|
||||||
|
|
||||||
item_ref = QStandardItem() # str(event_ref))
|
item_ref = QStandardItem() # str(event_ref))
|
||||||
item_test = QStandardItem() # str(event_test))
|
item_test = QStandardItem() # str(event_test))
|
||||||
if event_ref:
|
if event_ref:
|
||||||
@@ -1665,16 +1693,55 @@ class MainWindow(QMainWindow):
|
|||||||
self.cmpw.show()
|
self.cmpw.show()
|
||||||
|
|
||||||
def pickQualities(self):
|
def pickQualities(self):
|
||||||
path = self._inputs['rootpath'] + '/' + self._inputs['datapath'] + '/' + self._inputs['database']
|
path = self.get_current_event_path()
|
||||||
getQualitiesfromxml(path)
|
(_, plot) = getQualitiesfromxml(path, self._inputs.get('timeerrorsP'), self._inputs.get('timeerrorsS'),plotflag=1)
|
||||||
|
self.pickQualitiesWindow = PickQualitiesFromXml(figure=plot, path=self.get_current_event_path(),inputVar=self._inputs)
|
||||||
|
self.pickQualitiesWindow.showUI()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# WIP JG
|
||||||
def eventlistXml(self):
|
def eventlistXml(self):
|
||||||
path = self._inputs['rootpath'] + '/' + self._inputs['datapath'] + '/' + self._inputs['database']
|
path = self._inputs['rootpath'] + '/' + self._inputs['datapath'] + '/' + self._inputs['database']
|
||||||
outpath = self.project.location[:self.project.location.rfind('/')]
|
outpath = self.project.location[:self.project.location.rfind('/')]
|
||||||
geteventlistfromxml(path, outpath)
|
geteventlistfromxml(path, outpath)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# WIP JG
|
||||||
|
def spectogramView(self):
|
||||||
|
global test
|
||||||
|
stations = []
|
||||||
|
names = []
|
||||||
|
traces = {}
|
||||||
|
for tr in self.get_data().wfdata.traces:
|
||||||
|
if not tr.stats.station in stations:
|
||||||
|
stations.append(tr.stats.station)
|
||||||
|
names.append(tr.stats.network + '.' + tr.stats.station)
|
||||||
|
for station in stations:
|
||||||
|
traces[station] = {}
|
||||||
|
for ch in ['Z', 'N', 'E']:
|
||||||
|
for tr in self.get_data().wfdata.select(component=ch).traces:
|
||||||
|
traces[tr.stats.station][ch] = tr
|
||||||
|
|
||||||
|
names.sort()
|
||||||
|
a = self.get_current_event()
|
||||||
|
|
||||||
|
print (self.get_data().wfdata.traces[0])
|
||||||
|
|
||||||
|
test = SpectrogramTab(traces, self.get_data().wfdata)
|
||||||
|
height = self.tabs.widget(0).height()
|
||||||
|
width = self.tabs.widget(0).width()
|
||||||
|
self.tabs.setCurrentIndex(3)
|
||||||
|
figCanvas = test.makeSpecFig(direction=self.dispComponent, height = height, width = width, parent = self.tabs.widget)
|
||||||
|
return figCanvas
|
||||||
|
#self.spectro_layout.addWidget()
|
||||||
|
# self.get_data().wfdata.spectrogram()
|
||||||
|
# self.tabs.addTab(figCanvas, 'Spectrogram')
|
||||||
|
# self.tabs[3] = figCanvas
|
||||||
|
# self.refreshTabs()
|
||||||
|
# test.show()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def compareMulti(self):
|
def compareMulti(self):
|
||||||
if not self.compareoptions:
|
if not self.compareoptions:
|
||||||
return
|
return
|
||||||
@@ -1833,6 +1900,7 @@ class MainWindow(QMainWindow):
|
|||||||
# which will read in data input twice. Therefore current tab is changed to 0
|
# which will read in data input twice. Therefore current tab is changed to 0
|
||||||
# in loadProject before calling this function.
|
# in loadProject before calling this function.
|
||||||
self.fill_eventbox()
|
self.fill_eventbox()
|
||||||
|
#print(f'{self.get_current_event()=}')
|
||||||
plotted = False
|
plotted = False
|
||||||
if self.tabs.currentIndex() == 2:
|
if self.tabs.currentIndex() == 2:
|
||||||
self.init_event_table()
|
self.init_event_table()
|
||||||
@@ -1860,6 +1928,12 @@ class MainWindow(QMainWindow):
|
|||||||
self.newWF(plot=False)
|
self.newWF(plot=False)
|
||||||
self.update_obspy_dmt()
|
self.update_obspy_dmt()
|
||||||
self.refresh_array_map()
|
self.refresh_array_map()
|
||||||
|
if self.tabs.currentIndex() == 3:
|
||||||
|
if self.spectroWidget != None:
|
||||||
|
self.spectro_layout.removeWidget(self.spectroWidget)
|
||||||
|
newSpectroWidget = self.spectogramView()
|
||||||
|
self.spectro_layout.addWidget(newSpectroWidget)
|
||||||
|
self.spectroWidget = newSpectroWidget
|
||||||
|
|
||||||
def newWF(self, event=None, plot=True):
|
def newWF(self, event=None, plot=True):
|
||||||
'''
|
'''
|
||||||
@@ -1890,13 +1964,20 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def prepareLoadWaveformData(self):
|
def prepareLoadWaveformData(self):
|
||||||
self.fnames = self.getWFFnames_from_eventbox()
|
self.fnames = self.getWFFnames_from_eventbox()
|
||||||
self.fnames_syn = []
|
self.fnames_comp = []
|
||||||
|
fnames_comp = self.getWFFnames_from_eventbox(subpath='compare')
|
||||||
|
self.dataPlot.activateCompareOptions(bool(fnames_comp))
|
||||||
|
if fnames_comp:
|
||||||
|
if self.dataPlot.comp_checkbox.isChecked():
|
||||||
|
self.fnames_comp = fnames_comp
|
||||||
|
|
||||||
eventpath = self.get_current_event_path()
|
eventpath = self.get_current_event_path()
|
||||||
basepath = eventpath.split(os.path.basename(eventpath))[0]
|
basepath = eventpath.split(os.path.basename(eventpath))[0]
|
||||||
self.obspy_dmt = check_obspydmt_structure(basepath)
|
self.obspy_dmt = check_obspydmt_structure(basepath)
|
||||||
self.dataPlot.activateObspyDMToptions(self.obspy_dmt)
|
self.dataPlot.activateObspyDMToptions(self.obspy_dmt)
|
||||||
if self.obspy_dmt:
|
if self.obspy_dmt:
|
||||||
self.prepareObspyDMT_data(eventpath)
|
self.prepareObspyDMT_data(eventpath)
|
||||||
|
self.dataPlot.activateCompareOptions(True)
|
||||||
|
|
||||||
def loadWaveformData(self):
|
def loadWaveformData(self):
|
||||||
'''
|
'''
|
||||||
@@ -1911,6 +1992,8 @@ class MainWindow(QMainWindow):
|
|||||||
# ans = False
|
# ans = False
|
||||||
|
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
|
# process application events to wait for event items to appear in event box
|
||||||
|
QApplication.processEvents()
|
||||||
curr_event = self.get_current_event()
|
curr_event = self.get_current_event()
|
||||||
if not curr_event:
|
if not curr_event:
|
||||||
print('Could not find current event. Try reload?')
|
print('Could not find current event. Try reload?')
|
||||||
@@ -1918,8 +2001,8 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
if len(curr_event.origins) > 0:
|
if len(curr_event.origins) > 0:
|
||||||
origin_time = curr_event.origins[0].time
|
origin_time = curr_event.origins[0].time
|
||||||
tstart = settings.value('tstart') if get_None(settings.value('tstart')) else 0
|
tstart = settings.value('tstart') if get_none(settings.value('tstart')) else 0
|
||||||
tstop = settings.value('tstop') if get_None(settings.value('tstop')) else 0
|
tstop = settings.value('tstop') if get_none(settings.value('tstop')) else 0
|
||||||
tstart = origin_time + float(tstart)
|
tstart = origin_time + float(tstart)
|
||||||
tstop = origin_time + float(tstop)
|
tstop = origin_time + float(tstop)
|
||||||
else:
|
else:
|
||||||
@@ -1927,7 +2010,7 @@ class MainWindow(QMainWindow):
|
|||||||
tstop = None
|
tstop = None
|
||||||
|
|
||||||
self.data.setWFData(self.fnames,
|
self.data.setWFData(self.fnames,
|
||||||
self.fnames_syn,
|
self.fnames_comp,
|
||||||
checkRotated=True,
|
checkRotated=True,
|
||||||
metadata=self.metadata,
|
metadata=self.metadata,
|
||||||
tstart=tstart,
|
tstart=tstart,
|
||||||
@@ -1935,7 +2018,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def prepareObspyDMT_data(self, eventpath):
|
def prepareObspyDMT_data(self, eventpath):
|
||||||
qcbox_processed = self.dataPlot.qcombo_processed
|
qcbox_processed = self.dataPlot.qcombo_processed
|
||||||
qcheckb_syn = self.dataPlot.syn_checkbox
|
qcheckb_syn = self.dataPlot.comp_checkbox
|
||||||
qcbox_processed.setEnabled(False)
|
qcbox_processed.setEnabled(False)
|
||||||
qcheckb_syn.setEnabled(False)
|
qcheckb_syn.setEnabled(False)
|
||||||
for fpath in os.listdir(eventpath):
|
for fpath in os.listdir(eventpath):
|
||||||
@@ -1943,8 +2026,8 @@ class MainWindow(QMainWindow):
|
|||||||
if 'syngine' in fpath:
|
if 'syngine' in fpath:
|
||||||
eventpath_syn = os.path.join(eventpath, fpath)
|
eventpath_syn = os.path.join(eventpath, fpath)
|
||||||
qcheckb_syn.setEnabled(True)
|
qcheckb_syn.setEnabled(True)
|
||||||
if self.dataPlot.syn_checkbox.isChecked():
|
if self.dataPlot.comp_checkbox.isChecked():
|
||||||
self.fnames_syn = [os.path.join(eventpath_syn, filename) for filename in os.listdir(eventpath_syn)]
|
self.fnames_comp = [os.path.join(eventpath_syn, filename) for filename in os.listdir(eventpath_syn)]
|
||||||
if 'processed' in fpath:
|
if 'processed' in fpath:
|
||||||
qcbox_processed.setEnabled(True)
|
qcbox_processed.setEnabled(True)
|
||||||
if qcbox_processed.isEnabled():
|
if qcbox_processed.isEnabled():
|
||||||
@@ -2066,7 +2149,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def finish_pg_plot(self):
|
def finish_pg_plot(self):
|
||||||
self.getPlotWidget().updateWidget()
|
self.getPlotWidget().updateWidget()
|
||||||
plots, gaps = self.wfp_thread.data
|
plots = self.wfp_thread.data
|
||||||
# do not show plot if no data are given
|
# do not show plot if no data are given
|
||||||
self.wf_scroll_area.setVisible(len(plots) > 0)
|
self.wf_scroll_area.setVisible(len(plots) > 0)
|
||||||
self.no_data_label.setVisible(not len(plots) > 0)
|
self.no_data_label.setVisible(not len(plots) > 0)
|
||||||
@@ -2117,6 +2200,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.locateEventAction.setEnabled(True)
|
self.locateEventAction.setEnabled(True)
|
||||||
self.qualities_action.setEnabled(True)
|
self.qualities_action.setEnabled(True)
|
||||||
self.eventlist_xml_action.setEnabled(True)
|
self.eventlist_xml_action.setEnabled(True)
|
||||||
|
|
||||||
if True in self.comparable.values():
|
if True in self.comparable.values():
|
||||||
self.compare_action.setEnabled(True)
|
self.compare_action.setEnabled(True)
|
||||||
self.draw()
|
self.draw()
|
||||||
@@ -2224,7 +2308,7 @@ class MainWindow(QMainWindow):
|
|||||||
comp = self.getComponent()
|
comp = self.getComponent()
|
||||||
title = 'section: {0} components'.format(zne_text[comp])
|
title = 'section: {0} components'.format(zne_text[comp])
|
||||||
wfst = self.get_data().getWFData()
|
wfst = self.get_data().getWFData()
|
||||||
wfsyn = self.get_data().getSynWFData()
|
wfsyn = self.get_data().getAltWFdata()
|
||||||
if self.filterActionP.isChecked() and filter:
|
if self.filterActionP.isChecked() and filter:
|
||||||
self.filterWaveformData(plot=False, phase='P')
|
self.filterWaveformData(plot=False, phase='P')
|
||||||
elif self.filterActionS.isChecked() and filter:
|
elif self.filterActionS.isChecked() and filter:
|
||||||
@@ -2233,14 +2317,14 @@ class MainWindow(QMainWindow):
|
|||||||
# wfst += self.get_data().getWFData().select(component=alter_comp)
|
# wfst += self.get_data().getWFData().select(component=alter_comp)
|
||||||
plotWidget = self.getPlotWidget()
|
plotWidget = self.getPlotWidget()
|
||||||
self.adjustPlotHeight()
|
self.adjustPlotHeight()
|
||||||
if get_Bool(settings.value('large_dataset')) == True:
|
if get_bool(settings.value('large_dataset')) == True:
|
||||||
self.plot_method = 'fast'
|
self.plot_method = 'fast'
|
||||||
else:
|
else:
|
||||||
self.plot_method = 'normal'
|
self.plot_method = 'normal'
|
||||||
rval = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp,
|
rval = plotWidget.plotWFData(wfdata=wfst, wfsyn=wfsyn, title=title, mapping=False, component=comp,
|
||||||
nth_sample=int(nth_sample), method=self.plot_method, gain=self.gain)
|
nth_sample=int(nth_sample), method=self.plot_method, gain=self.gain)
|
||||||
plots, gaps = rval if rval else ([], [])
|
plots = rval if rval else []
|
||||||
return plots, gaps
|
return plots
|
||||||
|
|
||||||
def adjustPlotHeight(self):
|
def adjustPlotHeight(self):
|
||||||
if self.pg:
|
if self.pg:
|
||||||
@@ -2536,17 +2620,21 @@ class MainWindow(QMainWindow):
|
|||||||
print("Warning! No network, station, and location info available!")
|
print("Warning! No network, station, and location info available!")
|
||||||
return
|
return
|
||||||
self.update_status('picking on station {0}'.format(station))
|
self.update_status('picking on station {0}'.format(station))
|
||||||
data = self.get_data().getOriginalWFData().copy()
|
wfdata = self.get_data().getOriginalWFData().copy()
|
||||||
|
wfdata_comp = self.get_data().getAltWFdata().copy()
|
||||||
event = self.get_current_event()
|
event = self.get_current_event()
|
||||||
wftype = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else None
|
wftype = self.dataPlot.qcombo_processed.currentText() if self.obspy_dmt else None
|
||||||
pickDlg = PickDlg(self, parameter=self._inputs,
|
pickDlg = PickDlg(self, parameter=self._inputs,
|
||||||
data=data.select(station=station),
|
data=wfdata.select(station=station),
|
||||||
|
data_compare=wfdata_comp.select(station=station),
|
||||||
station=station, network=network,
|
station=station, network=network,
|
||||||
location=location,
|
location=location,
|
||||||
picks=self.getPicksOnStation(station, 'manual'),
|
picks=self.getPicksOnStation(station, 'manual'),
|
||||||
autopicks=self.getPicksOnStation(station, 'auto'),
|
autopicks=self.getPicksOnStation(station, 'auto'),
|
||||||
metadata=self.metadata, event=event,
|
metadata=self.metadata, event=event,
|
||||||
filteroptions=self.filteroptions, wftype=wftype)
|
model=self.inputs.get('taup_model'),
|
||||||
|
filteroptions=self.filteroptions, wftype=wftype,
|
||||||
|
show_comp_data=self.dataPlot.comp_checkbox.isChecked())
|
||||||
if self.filterActionP.isChecked():
|
if self.filterActionP.isChecked():
|
||||||
pickDlg.currentPhase = "P"
|
pickDlg.currentPhase = "P"
|
||||||
pickDlg.filterWFData()
|
pickDlg.filterWFData()
|
||||||
@@ -2659,7 +2747,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.init_fig_dict()
|
self.init_fig_dict()
|
||||||
# if not self.tap:
|
# if not self.tap:
|
||||||
# init TuneAutopicker object
|
# init TuneAutopicker object
|
||||||
self.tap = TuneAutopicker(self)
|
self.tap = TuneAutopicker(self, self.obspy_dmt)
|
||||||
# first call of update to init tabs with empty canvas
|
# first call of update to init tabs with empty canvas
|
||||||
self.update_autopicker()
|
self.update_autopicker()
|
||||||
# connect update signal of TuneAutopicker with update function
|
# connect update signal of TuneAutopicker with update function
|
||||||
@@ -2858,7 +2946,9 @@ class MainWindow(QMainWindow):
|
|||||||
self.log_deleted_picks([deleted_pick])
|
self.log_deleted_picks([deleted_pick])
|
||||||
|
|
||||||
def log_deleted_picks(self, deleted_picks, event_path=None):
|
def log_deleted_picks(self, deleted_picks, event_path=None):
|
||||||
''' Log deleted picks to list self.deleted_picks '''
|
'''
|
||||||
|
Log deleted picks to list self.deleted_picks
|
||||||
|
'''
|
||||||
if not event_path:
|
if not event_path:
|
||||||
event_path = self.get_current_event_path()
|
event_path = self.get_current_event_path()
|
||||||
for deleted_pick in deleted_picks:
|
for deleted_pick in deleted_picks:
|
||||||
@@ -2872,7 +2962,9 @@ class MainWindow(QMainWindow):
|
|||||||
self.deleted_picks[event_path].append(deleted_pick)
|
self.deleted_picks[event_path].append(deleted_pick)
|
||||||
|
|
||||||
def dump_deleted_picks(self, event_path):
|
def dump_deleted_picks(self, event_path):
|
||||||
''' Save deleted picks to json file for event in event_path. Load old file before and merge'''
|
'''
|
||||||
|
Save deleted picks to json file for event in event_path. Load old file before and merge
|
||||||
|
'''
|
||||||
try:
|
try:
|
||||||
deleted_picks_from_file = self.load_deleted_picks(event_path)
|
deleted_picks_from_file = self.load_deleted_picks(event_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -2921,10 +3013,16 @@ class MainWindow(QMainWindow):
|
|||||||
event = self.get_current_event()
|
event = self.get_current_event()
|
||||||
event.pylot_picks = {}
|
event.pylot_picks = {}
|
||||||
event.pylot_autopicks = {}
|
event.pylot_autopicks = {}
|
||||||
picksdict = picksdict_from_picks(evt=self.get_data().get_evt_data())
|
picksdict = picksdict_from_picks(evt=self.get_data().get_evt_data(), parameter=self.getParameter())
|
||||||
event.addPicks(picksdict['manual'])
|
event.addPicks(picksdict['manual'])
|
||||||
event.addAutopicks(picksdict['auto'])
|
event.addAutopicks(picksdict['auto'])
|
||||||
|
|
||||||
|
def getParameter(self):
|
||||||
|
if hasattr(self.project, 'parameter') and isinstance(self.project.parameter, PylotParameter):
|
||||||
|
return self.project.parameter
|
||||||
|
else:
|
||||||
|
return self._inputs
|
||||||
|
|
||||||
def drawPicks(self, station=None, picktype=None, stime=None):
|
def drawPicks(self, station=None, picktype=None, stime=None):
|
||||||
# if picktype not specified, draw both
|
# if picktype not specified, draw both
|
||||||
if not stime:
|
if not stime:
|
||||||
@@ -3068,11 +3166,13 @@ class MainWindow(QMainWindow):
|
|||||||
lt = locateTool[loctool]
|
lt = locateTool[loctool]
|
||||||
# get working directory
|
# get working directory
|
||||||
locroot = parameter['nllocroot']
|
locroot = parameter['nllocroot']
|
||||||
|
#locroot = 'E:/NLL/src/Insheim'
|
||||||
if locroot is None:
|
if locroot is None:
|
||||||
self.PyLoTprefs()
|
self.PyLoTprefs()
|
||||||
self.locate_event()
|
self.locate_event()
|
||||||
|
|
||||||
ctrfile = os.path.join(locroot, 'run', parameter['ctrfile'])
|
ctrfile = os.path.join(locroot, 'run', parameter['ctrfile'])
|
||||||
|
#ctrfile = 'E:/NLL/src/Insheim/run/Insheim_min1d032016.in'
|
||||||
ttt = parameter['ttpatter']
|
ttt = parameter['ttpatter']
|
||||||
outfile = parameter['outpatter']
|
outfile = parameter['outpatter']
|
||||||
eventname = self.get_current_event_name()
|
eventname = self.get_current_event_name()
|
||||||
@@ -3083,7 +3183,7 @@ class MainWindow(QMainWindow):
|
|||||||
phasefile = os.path.join(obsdir, filename + '.obs')
|
phasefile = os.path.join(obsdir, filename + '.obs')
|
||||||
lt.modify_inputs(ctrfile, locroot, filename, phasefile, ttt)
|
lt.modify_inputs(ctrfile, locroot, filename, phasefile, ttt)
|
||||||
try:
|
try:
|
||||||
lt.locate(ctrfile)
|
lt.locate(ctrfile, self._inputs)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
print(e.message)
|
print(e.message)
|
||||||
# finally:
|
# finally:
|
||||||
@@ -3137,7 +3237,7 @@ class MainWindow(QMainWindow):
|
|||||||
'''
|
'''
|
||||||
if checked: pass # dummy argument for QAction trigger signal
|
if checked: pass # dummy argument for QAction trigger signal
|
||||||
self.tabs.setCurrentIndex(1)
|
self.tabs.setCurrentIndex(1)
|
||||||
# if there is no metadata (invetories is an empty list), just initialize the default empty tab
|
# if there is no metadata (inventories is an empty list), just initialize the default empty tab
|
||||||
if not self.metadata.inventories:
|
if not self.metadata.inventories:
|
||||||
self.init_array_tab()
|
self.init_array_tab()
|
||||||
return
|
return
|
||||||
@@ -3159,6 +3259,15 @@ class MainWindow(QMainWindow):
|
|||||||
self.tabs.setCurrentIndex(index)
|
self.tabs.setCurrentIndex(index)
|
||||||
self.refresh_array_map()
|
self.refresh_array_map()
|
||||||
|
|
||||||
|
def init_spectro_tab(self):
|
||||||
|
'''
|
||||||
|
Init spectrogram tab with currently selected event.
|
||||||
|
'''
|
||||||
|
self.spectroWidget = None
|
||||||
|
#self.spectro_layout.addWidget( self.spectogramView() )
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def array_map_thread(self):
|
def array_map_thread(self):
|
||||||
'''
|
'''
|
||||||
Start modal thread to init the array_map object.
|
Start modal thread to init the array_map object.
|
||||||
@@ -3381,7 +3490,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.event_table.setCellWidget(r_index, c_index, item)
|
self.event_table.setCellWidget(r_index, c_index, item)
|
||||||
|
|
||||||
header = self.event_table.horizontalHeader()
|
header = self.event_table.horizontalHeader()
|
||||||
header.setResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||||
header.setStretchLastSection(True)
|
header.setStretchLastSection(True)
|
||||||
self.event_table.cellChanged[int, int].connect(cell_changed)
|
self.event_table.cellChanged[int, int].connect(cell_changed)
|
||||||
self.event_table.cellClicked[int, int].connect(cell_clicked)
|
self.event_table.cellClicked[int, int].connect(cell_clicked)
|
||||||
@@ -3488,7 +3597,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
wf_select = Stream()
|
wf_select = Stream()
|
||||||
# restitute only picked traces
|
# restitute only picked traces
|
||||||
for station in np.unique(self.getPicks('manual').keys() + self.getPicks('auto').keys()):
|
for station in np.unique(list(self.getPicks('manual').keys()) + list(self.getPicks('auto').keys())):
|
||||||
wf_select += wf_copy.select(station=station)
|
wf_select += wf_copy.select(station=station)
|
||||||
|
|
||||||
corr_wf = restitute_data(wf_select, self.metadata)
|
corr_wf = restitute_data(wf_select, self.metadata)
|
||||||
@@ -3555,7 +3664,7 @@ class MainWindow(QMainWindow):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def update_status(self, message, duration=5000):
|
def update_status(self, message, duration=10000):
|
||||||
self.statusBar().showMessage(message, duration)
|
self.statusBar().showMessage(message, duration)
|
||||||
if self.get_data() is not None:
|
if self.get_data() is not None:
|
||||||
if not self.get_current_event() or not self.project.location:
|
if not self.get_current_event() or not self.project.location:
|
||||||
@@ -3608,10 +3717,13 @@ class MainWindow(QMainWindow):
|
|||||||
if not self.okToContinue():
|
if not self.okToContinue():
|
||||||
return
|
return
|
||||||
if not fnm:
|
if not fnm:
|
||||||
dlg = QFileDialog(parent=self)
|
settings = QSettings()
|
||||||
|
dir = settings.value('current_project_path')
|
||||||
|
dlg = QFileDialog(parent=self, directory=dir)
|
||||||
fnm = dlg.getOpenFileName(self, 'Open project file...', filter='Pylot project (*.plp)')[0]
|
fnm = dlg.getOpenFileName(self, 'Open project file...', filter='Pylot project (*.plp)')[0]
|
||||||
if not fnm:
|
if not fnm:
|
||||||
return
|
return
|
||||||
|
settings.setValue('current_project_path', os.path.split(fnm)[0])
|
||||||
if not os.path.exists(fnm):
|
if not os.path.exists(fnm):
|
||||||
QMessageBox.warning(self, 'Could not open file',
|
QMessageBox.warning(self, 'Could not open file',
|
||||||
'Could not open project file {}. File does not exist.'.format(fnm))
|
'Could not open project file {}. File does not exist.'.format(fnm))
|
||||||
@@ -3667,7 +3779,7 @@ class MainWindow(QMainWindow):
|
|||||||
filename = fnm[0] + '.plp'
|
filename = fnm[0] + '.plp'
|
||||||
self.project.parameter = self._inputs
|
self.project.parameter = self._inputs
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
autosaveXML = get_Bool(settings.value('autosaveXML', True))
|
autosaveXML = get_bool(settings.value('autosaveXML', True))
|
||||||
if autosaveXML:
|
if autosaveXML:
|
||||||
self.exportEvents()
|
self.exportEvents()
|
||||||
if not self.project.save(filename): return False
|
if not self.project.save(filename): return False
|
||||||
@@ -3691,7 +3803,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.metadata.clear_inventory()
|
self.metadata.clear_inventory()
|
||||||
self.project.parameter = self._inputs
|
self.project.parameter = self._inputs
|
||||||
settings = QSettings()
|
settings = QSettings()
|
||||||
autosaveXML = get_Bool(settings.value('autosaveXML', True))
|
autosaveXML = get_bool(settings.value('autosaveXML', True))
|
||||||
if autosaveXML:
|
if autosaveXML:
|
||||||
self.exportEvents()
|
self.exportEvents()
|
||||||
if not self.project.save(): return False
|
if not self.project.save(): return False
|
||||||
@@ -3729,6 +3841,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
if self.okToContinue():
|
if self.okToContinue():
|
||||||
|
if hasattr(self, 'logwidget'):
|
||||||
self.logwidget.close()
|
self.logwidget.close()
|
||||||
event.accept()
|
event.accept()
|
||||||
else:
|
else:
|
||||||
@@ -3780,7 +3893,7 @@ class MainWindow(QMainWindow):
|
|||||||
def helpHelp(self):
|
def helpHelp(self):
|
||||||
if checkurl():
|
if checkurl():
|
||||||
form = HelpForm(self,
|
form = HelpForm(self,
|
||||||
'https://ariadne.geophysik.ruhr-uni-bochum.de/trac/PyLoT/wiki')
|
'https://github.com/seismology-RUB/PyLoT')
|
||||||
else:
|
else:
|
||||||
form = HelpForm(self, ':/help.html')
|
form = HelpForm(self, ':/help.html')
|
||||||
form.show()
|
form.show()
|
||||||
@@ -3960,13 +4073,13 @@ class Project(object):
|
|||||||
return project
|
return project
|
||||||
|
|
||||||
|
|
||||||
class getExistingDirectories(QFileDialog):
|
class GetExistingDirectories(QFileDialog):
|
||||||
'''
|
'''
|
||||||
File dialog with possibility to select multiple folders.
|
File dialog with possibility to select multiple folders.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
super(getExistingDirectories, self).__init__(*args)
|
super(GetExistingDirectories, self).__init__(*args)
|
||||||
self.setOption(self.DontUseNativeDialog, True)
|
self.setOption(self.DontUseNativeDialog, True)
|
||||||
self.setOption(self.ReadOnly, True)
|
self.setOption(self.ReadOnly, True)
|
||||||
self.setFileMode(self.Directory)
|
self.setFileMode(self.Directory)
|
||||||
@@ -3992,16 +4105,7 @@ def create_window():
|
|||||||
return app, app_created
|
return app, app_created
|
||||||
|
|
||||||
|
|
||||||
def main(args=None):
|
def main(project_filename=None, pylot_infile=None, reset_qsettings=False):
|
||||||
project_filename = None
|
|
||||||
# args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp'
|
|
||||||
pylot_infile = None
|
|
||||||
if args:
|
|
||||||
if args.project_filename:
|
|
||||||
project_filename = args.project_filename
|
|
||||||
if args.input_filename:
|
|
||||||
pylot_infile = args.input_filename
|
|
||||||
reset_qsettings = args.reset_qsettings
|
|
||||||
|
|
||||||
# create the Qt application
|
# create the Qt application
|
||||||
pylot_app, app_created = create_window()
|
pylot_app, app_created = create_window()
|
||||||
@@ -4050,4 +4154,5 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument('--reset_qsettings', default=False, action='store_true',
|
parser.add_argument('--reset_qsettings', default=False, action='store_true',
|
||||||
help='reset qsettings (debug option)')
|
help='reset qsettings (debug option)')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
sys.exit(main(args))
|
sys.exit(main(project_filename=args.project_filename, pylot_infile=args.input_filename,
|
||||||
|
reset_qsettings=args.reset_qsettings))
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ It is highly recommended to use Anaconda for a simple creation of a Python insta
|
|||||||
|
|
||||||
Afterwards run (from the PyLoT main directory where the files *requirements.txt* and *pylot.yml* are located)
|
Afterwards run (from the PyLoT main directory where the files *requirements.txt* and *pylot.yml* are located)
|
||||||
|
|
||||||
conda create --name pylot_38 --file requirements.txt
|
conda env create -f pylot.yml
|
||||||
or
|
or
|
||||||
|
|
||||||
conda env create -f pylot.yml
|
conda create --name pylot_38 --file requirements.txt
|
||||||
|
|
||||||
to create a new Anaconda environment called "pylot_38".
|
to create a new Anaconda environment called "pylot_38".
|
||||||
|
|
||||||
@@ -99,13 +99,13 @@ We hope to solve these with the next release.
|
|||||||
|
|
||||||
## Staff
|
## Staff
|
||||||
|
|
||||||
Original author(s): L. Kueperkoch, S. Wehling-Benatelli, M. Bischoff (PILOT)
|
Original author(s): M. Rische, S. Wehling-Benatelli, L. Kueperkoch, M. Bischoff (PILOT)
|
||||||
|
|
||||||
Developer(s): S. Wehling-Benatelli, L. Kueperkoch, K. Olbert, M. Bischoff, C. Wollin, M. Rische, M. Paffrath
|
Developer(s): S. Wehling-Benatelli, M. Paffrath, L. Kueperkoch, K. Olbert, M. Bischoff, C. Wollin, M. Rische, D. Arnold, K. Cökerim, S. Zimmermann
|
||||||
|
|
||||||
Others: A. Bruestle, T. Meier, W. Friederich
|
Others: A. Bruestle, T. Meier, W. Friederich
|
||||||
|
|
||||||
|
|
||||||
[ObsPy]: http://github.com/obspy/obspy/wiki
|
[ObsPy]: http://github.com/obspy/obspy/wiki
|
||||||
|
|
||||||
September 2017
|
April 2022
|
||||||
|
|||||||
+7
-11
@@ -28,7 +28,7 @@ from pylot.core.util.dataprocessing import restitute_data, Metadata
|
|||||||
from pylot.core.util.defaults import SEPARATOR
|
from pylot.core.util.defaults import SEPARATOR
|
||||||
from pylot.core.util.event import Event
|
from pylot.core.util.event import Event
|
||||||
from pylot.core.util.structure import DATASTRUCTURE
|
from pylot.core.util.structure import DATASTRUCTURE
|
||||||
from pylot.core.util.utils import get_None, trim_station_components, check4gapsAndRemove, check4doubled, \
|
from pylot.core.util.utils import get_none, trim_station_components, check4gapsAndRemove, check4doubled, \
|
||||||
check4rotated
|
check4rotated
|
||||||
from pylot.core.util.version import get_git_version as _getVersionString
|
from pylot.core.util.version import get_git_version as _getVersionString
|
||||||
|
|
||||||
@@ -91,9 +91,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
sp=sp_info)
|
sp=sp_info)
|
||||||
print(splash)
|
print(splash)
|
||||||
|
|
||||||
parameter = get_None(parameter)
|
parameter = get_none(parameter)
|
||||||
inputfile = get_None(inputfile)
|
inputfile = get_none(inputfile)
|
||||||
eventid = get_None(eventid)
|
eventid = get_none(eventid)
|
||||||
|
|
||||||
fig_dict = None
|
fig_dict = None
|
||||||
fig_dict_wadatijack = None
|
fig_dict_wadatijack = None
|
||||||
@@ -119,13 +119,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
obspyDMT_wfpath = input_dict['obspyDMT_wfpath']
|
obspyDMT_wfpath = input_dict['obspyDMT_wfpath']
|
||||||
|
|
||||||
if not parameter:
|
if not parameter:
|
||||||
if inputfile:
|
if not inputfile:
|
||||||
|
print('Using default input parameter')
|
||||||
parameter = PylotParameter(inputfile)
|
parameter = PylotParameter(inputfile)
|
||||||
# iplot = parameter['iplot']
|
|
||||||
else:
|
|
||||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
|
||||||
print('Using default input file {}'.format(infile))
|
|
||||||
parameter = PylotParameter(infile)
|
|
||||||
else:
|
else:
|
||||||
if not type(parameter) == PylotParameter:
|
if not type(parameter) == PylotParameter:
|
||||||
print('Wrong input type for parameter: {}'.format(type(parameter)))
|
print('Wrong input type for parameter: {}'.format(type(parameter)))
|
||||||
@@ -154,7 +150,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
|||||||
datastructure.setExpandFields(exf)
|
datastructure.setExpandFields(exf)
|
||||||
|
|
||||||
# check if default location routine NLLoc is available and all stations are used
|
# check if default location routine NLLoc is available and all stations are used
|
||||||
if get_None(parameter['nllocbin']) and station == 'all':
|
if get_none(parameter['nllocbin']) and station == 'all':
|
||||||
locflag = 1
|
locflag = 1
|
||||||
# get NLLoc-root path
|
# get NLLoc-root path
|
||||||
nllocroot = parameter.get('nllocroot')
|
nllocroot = parameter.get('nllocroot')
|
||||||
|
|||||||
+5
-3
@@ -3,8 +3,10 @@
|
|||||||
#$ -l low
|
#$ -l low
|
||||||
#$ -cwd
|
#$ -cwd
|
||||||
#$ -pe smp 40
|
#$ -pe smp 40
|
||||||
#$ -l mem=2G
|
##$ -l mem=3G
|
||||||
#$ -l h_vmem=2G
|
#$ -l h_vmem=6G
|
||||||
#$ -l os=*stretch
|
#$ -l os=*stretch
|
||||||
|
|
||||||
python ./autoPyLoT.py -i /home/marcel/.pylot/pylot_alparray_mantle_corr_stack_0.03-0.5.in -dmt processed -c $NSLOTS
|
conda activate pylot_311
|
||||||
|
|
||||||
|
python ./autoPyLoT.py -i /home/marcel/.pylot/pylot_adriaarray.in -c 20 -dmt processed
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
+109772
-109081
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ dependencies:
|
|||||||
- numpy=1.22.3
|
- numpy=1.22.3
|
||||||
- obspy=1.3.0
|
- obspy=1.3.0
|
||||||
- pyqtgraph=0.12.4
|
- pyqtgraph=0.12.4
|
||||||
- pyside2=5.13.2
|
- pyside2>=5.13.2
|
||||||
- python=3.8.12
|
- python=3.8.12
|
||||||
- qt=5.12.9
|
- qt>=5.12.9
|
||||||
- scipy=1.8.0
|
- scipy=1.8.0
|
||||||
@@ -144,6 +144,10 @@ class Magnitude(object):
|
|||||||
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
|
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
|
||||||
else:
|
else:
|
||||||
# no scaling necessary
|
# no scaling necessary
|
||||||
|
# Temporary fix needs rework
|
||||||
|
if (len(self.magnitudes.keys()) == 0):
|
||||||
|
print("Error in local magnitude calculation ")
|
||||||
|
return None
|
||||||
mag = ope.Magnitude(
|
mag = ope.Magnitude(
|
||||||
mag=np.median([M.mag for M in self.magnitudes.values()]),
|
mag=np.median([M.mag for M in self.magnitudes.values()]),
|
||||||
magnitude_type=self.type,
|
magnitude_type=self.type,
|
||||||
@@ -414,6 +418,10 @@ class MomentMagnitude(Magnitude):
|
|||||||
distance = degrees2kilometers(a.distance)
|
distance = degrees2kilometers(a.distance)
|
||||||
azimuth = a.azimuth
|
azimuth = a.azimuth
|
||||||
incidence = a.takeoff_angle
|
incidence = a.takeoff_angle
|
||||||
|
if not 0. <= incidence <= 360.:
|
||||||
|
if self.verbose:
|
||||||
|
print(f'WARNING: Incidence angle outside bounds - {incidence}')
|
||||||
|
return
|
||||||
w0, fc = calcsourcespec(scopy, onset, self.p_velocity, distance,
|
w0, fc = calcsourcespec(scopy, onset, self.p_velocity, distance,
|
||||||
azimuth, incidence, self.p_attenuation,
|
azimuth, incidence, self.p_attenuation,
|
||||||
self.plot_flag, self.verbose)
|
self.plot_flag, self.verbose)
|
||||||
@@ -432,6 +440,40 @@ class MomentMagnitude(Magnitude):
|
|||||||
self.event.station_magnitudes.append(magnitude)
|
self.event.station_magnitudes.append(magnitude)
|
||||||
self.magnitudes = (station, magnitude)
|
self.magnitudes = (station, magnitude)
|
||||||
|
|
||||||
|
# WIP JG
|
||||||
|
def getSourceSpec(self):
|
||||||
|
for a in self.arrivals:
|
||||||
|
if a.phase not in 'pP':
|
||||||
|
continue
|
||||||
|
# make sure calculating Mo only from reliable onsets
|
||||||
|
# NLLoc: time_weight = 0 => do not use onset!
|
||||||
|
if a.time_weight == 0:
|
||||||
|
continue
|
||||||
|
pick = a.pick_id.get_referred_object()
|
||||||
|
station = pick.waveform_id.station_code
|
||||||
|
if len(self.stream) <= 2:
|
||||||
|
print("Station:" '{0}'.format(station))
|
||||||
|
print("WARNING: No instrument corrected data available,"
|
||||||
|
" no magnitude calculation possible! Go on.")
|
||||||
|
continue
|
||||||
|
wf = self.stream.select(station=station)
|
||||||
|
if not wf:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
scopy = wf.copy()
|
||||||
|
except AssertionError:
|
||||||
|
print("WARNING: Something's wrong with the data,"
|
||||||
|
"station {},"
|
||||||
|
"no calculation of moment magnitude possible! Go on.".format(station))
|
||||||
|
continue
|
||||||
|
onset = pick.time
|
||||||
|
distance = degrees2kilometers(a.distance)
|
||||||
|
azimuth = a.azimuth
|
||||||
|
incidence = a.takeoff_angle
|
||||||
|
w0, fc, plt = calcsourcespec(scopy, onset, self.p_velocity, distance,
|
||||||
|
azimuth, incidence, self.p_attenuation,
|
||||||
|
3, self.verbose)
|
||||||
|
return w0, fc, plt
|
||||||
|
|
||||||
def calcMoMw(wfstream, w0, rho, vp, delta, verbosity=False):
|
def calcMoMw(wfstream, w0, rho, vp, delta, verbosity=False):
|
||||||
'''
|
'''
|
||||||
@@ -602,7 +644,7 @@ def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
|
|||||||
N = min(int(np.power(m, 2)), 16384)
|
N = min(int(np.power(m, 2)), 16384)
|
||||||
# N = int(np.power(m, 2))
|
# N = int(np.power(m, 2))
|
||||||
y = dt * np.fft.fft(xdat, N)
|
y = dt * np.fft.fft(xdat, N)
|
||||||
Y = abs(y[: N / 2])
|
Y = abs(y[: int(N / 2)])
|
||||||
L = (N - 1) / freq
|
L = (N - 1) / freq
|
||||||
f = np.arange(0, fny, 1 / L)
|
f = np.arange(0, fny, 1 / L)
|
||||||
|
|
||||||
@@ -679,6 +721,8 @@ def calcsourcespec(wfstream, onset, vp, delta, azimuth, incidence,
|
|||||||
plt.xlabel('Frequency [Hz]')
|
plt.xlabel('Frequency [Hz]')
|
||||||
plt.ylabel('Amplitude [m/Hz]')
|
plt.ylabel('Amplitude [m/Hz]')
|
||||||
plt.grid()
|
plt.grid()
|
||||||
|
if iplot == 3:
|
||||||
|
return w0, Fc, plt
|
||||||
plt.show()
|
plt.show()
|
||||||
try:
|
try:
|
||||||
input()
|
input()
|
||||||
|
|||||||
+63
-27
@@ -2,6 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from PySide2.QtWidgets import QMessageBox
|
from PySide2.QtWidgets import QMessageBox
|
||||||
@@ -19,7 +20,7 @@ from pylot.core.util.errors import FormatError, OverwriteError
|
|||||||
from pylot.core.util.event import Event
|
from pylot.core.util.event import Event
|
||||||
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
||||||
from pylot.core.util.utils import fnConstructor, full_range, check4rotated, \
|
from pylot.core.util.utils import fnConstructor, full_range, check4rotated, \
|
||||||
check4gapsAndMerge, trim_station_components
|
check_for_gaps_and_merge, trim_station_components, check_for_nan
|
||||||
|
|
||||||
|
|
||||||
class Data(object):
|
class Data(object):
|
||||||
@@ -64,7 +65,7 @@ class Data(object):
|
|||||||
elif 'LOC' in evtdata:
|
elif 'LOC' in evtdata:
|
||||||
raise NotImplementedError('PILOT location information '
|
raise NotImplementedError('PILOT location information '
|
||||||
'read support not yet '
|
'read support not yet '
|
||||||
'implemeted.')
|
'implemented.')
|
||||||
elif 'event.pkl' in evtdata:
|
elif 'event.pkl' in evtdata:
|
||||||
evtdata = qml_from_obspyDMT(evtdata)
|
evtdata = qml_from_obspyDMT(evtdata)
|
||||||
else:
|
else:
|
||||||
@@ -260,7 +261,6 @@ class Data(object):
|
|||||||
can be a str or a list of strings of ['manual', 'auto', 'origin', 'magnitude']
|
can be a str or a list of strings of ['manual', 'auto', 'origin', 'magnitude']
|
||||||
"""
|
"""
|
||||||
from pylot.core.util.defaults import OUTPUTFORMATS
|
from pylot.core.util.defaults import OUTPUTFORMATS
|
||||||
|
|
||||||
if not type(fcheck) == list:
|
if not type(fcheck) == list:
|
||||||
fcheck = [fcheck]
|
fcheck = [fcheck]
|
||||||
|
|
||||||
@@ -321,35 +321,61 @@ class Data(object):
|
|||||||
if lendiff != 0:
|
if lendiff != 0:
|
||||||
print("Manual as well as automatic picks available. Prefered the {} manual ones!".format(lendiff))
|
print("Manual as well as automatic picks available. Prefered the {} manual ones!".format(lendiff))
|
||||||
|
|
||||||
|
|
||||||
|
no_uncertainties_p = []
|
||||||
|
no_uncertainties_s = []
|
||||||
if upperErrors:
|
if upperErrors:
|
||||||
# check for pick uncertainties exceeding adjusted upper errors
|
# check for pick uncertainties exceeding adjusted upper errors
|
||||||
# Picks with larger uncertainties will not be saved in output file!
|
# Picks with larger uncertainties will not be saved in output file!
|
||||||
for j in range(len(picks)):
|
for j in range(len(picks)):
|
||||||
for i in range(len(picks_copy)):
|
for i in range(len(picks_copy)):
|
||||||
if picks_copy[i].phase_hint[0] == 'P':
|
if picks_copy[i].phase_hint[0] == 'P':
|
||||||
if (picks_copy[i].time_errors['upper_uncertainty'] >= upperErrors[0]) or \
|
# Skipping pick if no upper_uncertainty is found and warning user
|
||||||
(picks_copy[i].time_errors['uncertainty'] is None):
|
if picks_copy[i].time_errors['upper_uncertainty'] is None:
|
||||||
|
#print("{1} P-Pick of station {0} does not have upper_uncertainty and cant be checked".format(
|
||||||
|
# picks_copy[i].waveform_id.station_code,
|
||||||
|
# picks_copy[i].method_id))
|
||||||
|
if not picks_copy[i].waveform_id.station_code in no_uncertainties_p:
|
||||||
|
no_uncertainties_p.append(picks_copy[i].waveform_id.station_code)
|
||||||
|
continue
|
||||||
|
|
||||||
|
#print ("checking for upper_uncertainty")
|
||||||
|
if (picks_copy[i].time_errors['uncertainty'] is None) or \
|
||||||
|
(picks_copy[i].time_errors['upper_uncertainty'] >= upperErrors[0]):
|
||||||
print("Uncertainty exceeds or equal adjusted upper time error!")
|
print("Uncertainty exceeds or equal adjusted upper time error!")
|
||||||
print("Adjusted uncertainty: {}".format(upperErrors[0]))
|
print("Adjusted uncertainty: {}".format(upperErrors[0]))
|
||||||
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
||||||
print("{1} P-Pick of station {0} will not be saved in outputfile".format(
|
print("{1} P-Pick of station {0} will not be saved in outputfile".format(
|
||||||
picks_copy[i].waveform_id.station_code,
|
picks_copy[i].waveform_id.station_code,
|
||||||
picks_copy[i].method_id))
|
picks_copy[i].method_id))
|
||||||
print("#")
|
|
||||||
del picks_copy[i]
|
del picks_copy[i]
|
||||||
break
|
break
|
||||||
if picks_copy[i].phase_hint[0] == 'S':
|
if picks_copy[i].phase_hint[0] == 'S':
|
||||||
if (picks_copy[i].time_errors['upper_uncertainty'] >= upperErrors[1]) or \
|
|
||||||
(picks_copy[i].time_errors['uncertainty'] is None):
|
# Skipping pick if no upper_uncertainty is found and warning user
|
||||||
|
if picks_copy[i].time_errors['upper_uncertainty'] is None:
|
||||||
|
#print("{1} S-Pick of station {0} does not have upper_uncertainty and cant be checked".format(
|
||||||
|
#picks_copy[i].waveform_id.station_code,
|
||||||
|
#picks_copy[i].method_id))
|
||||||
|
if not picks_copy[i].waveform_id.station_code in no_uncertainties_s:
|
||||||
|
no_uncertainties_s.append(picks_copy[i].waveform_id.station_code)
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
if (picks_copy[i].time_errors['uncertainty'] is None) or \
|
||||||
|
(picks_copy[i].time_errors['upper_uncertainty'] >= upperErrors[1]):
|
||||||
print("Uncertainty exceeds or equal adjusted upper time error!")
|
print("Uncertainty exceeds or equal adjusted upper time error!")
|
||||||
print("Adjusted uncertainty: {}".format(upperErrors[1]))
|
print("Adjusted uncertainty: {}".format(upperErrors[1]))
|
||||||
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
print("Pick uncertainty: {}".format(picks_copy[i].time_errors['uncertainty']))
|
||||||
print("{1} S-Pick of station {0} will not be saved in outputfile".format(
|
print("{1} S-Pick of station {0} will not be saved in outputfile".format(
|
||||||
picks_copy[i].waveform_id.station_code,
|
picks_copy[i].waveform_id.station_code,
|
||||||
picks_copy[i].method_id))
|
picks_copy[i].method_id))
|
||||||
print("#")
|
|
||||||
del picks_copy[i]
|
del picks_copy[i]
|
||||||
break
|
break
|
||||||
|
for s in no_uncertainties_p:
|
||||||
|
print("P-Pick of station {0} does not have upper_uncertainty and cant be checked".format(s))
|
||||||
|
for s in no_uncertainties_s:
|
||||||
|
print("S-Pick of station {0} does not have upper_uncertainty and cant be checked".format(s))
|
||||||
|
|
||||||
if fnext == '.obs':
|
if fnext == '.obs':
|
||||||
try:
|
try:
|
||||||
@@ -383,18 +409,16 @@ class Data(object):
|
|||||||
not implemented: {1}'''.format(evtformat, e))
|
not implemented: {1}'''.format(evtformat, e))
|
||||||
if fnext == '_focmec.in':
|
if fnext == '_focmec.in':
|
||||||
try:
|
try:
|
||||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
parameter = PylotParameter()
|
||||||
print('Using default input file {}'.format(infile))
|
logging.warning('Using default input parameter')
|
||||||
parameter = PylotParameter(infile)
|
|
||||||
focmec.export(picks_copy, fnout + fnext, parameter, eventinfo=self.get_evt_data())
|
focmec.export(picks_copy, fnout + fnext, parameter, eventinfo=self.get_evt_data())
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
raise KeyError('''{0} export format
|
raise KeyError('''{0} export format
|
||||||
not implemented: {1}'''.format(evtformat, e))
|
not implemented: {1}'''.format(evtformat, e))
|
||||||
if fnext == '.pha':
|
if fnext == '.pha':
|
||||||
try:
|
try:
|
||||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
parameter = PylotParameter()
|
||||||
print('Using default input file {}'.format(infile))
|
logging.warning('Using default input parameter')
|
||||||
parameter = PylotParameter(infile)
|
|
||||||
hypodd.export(picks_copy, fnout + fnext, parameter, eventinfo=self.get_evt_data())
|
hypodd.export(picks_copy, fnout + fnext, parameter, eventinfo=self.get_evt_data())
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
raise KeyError('''{0} export format
|
raise KeyError('''{0} export format
|
||||||
@@ -426,20 +450,30 @@ class Data(object):
|
|||||||
data.filter(**kwargs)
|
data.filter(**kwargs)
|
||||||
self.dirty = True
|
self.dirty = True
|
||||||
|
|
||||||
def setWFData(self, fnames, fnames_syn=None, checkRotated=False, metadata=None, tstart=0, tstop=0):
|
def setWFData(self, fnames, fnames_alt=None, checkRotated=False, metadata=None, tstart=0, tstop=0):
|
||||||
"""
|
"""
|
||||||
Clear current waveform data and set given waveform data
|
Clear current waveform data and set given waveform data
|
||||||
:param fnames: waveform data names to append
|
:param fnames: waveform data names to append
|
||||||
|
:param fnames_alt: alternative data to show (e.g. synthetic/processed)
|
||||||
:type fnames: list
|
:type fnames: list
|
||||||
"""
|
"""
|
||||||
|
def check_fname_exists(filenames: list) -> list:
|
||||||
|
if filenames:
|
||||||
|
filenames = [fn for fn in filenames if os.path.isfile(fn)]
|
||||||
|
return filenames
|
||||||
|
|
||||||
self.wfdata = Stream()
|
self.wfdata = Stream()
|
||||||
self.wforiginal = None
|
self.wforiginal = None
|
||||||
self.wfsyn = Stream()
|
self.wf_alt = Stream()
|
||||||
if tstart == tstop:
|
if tstart == tstop:
|
||||||
tstart = tstop = None
|
tstart = tstop = None
|
||||||
self.tstart = tstart
|
self.tstart = tstart
|
||||||
self.tstop = tstop
|
self.tstop = tstop
|
||||||
|
|
||||||
|
# remove directories
|
||||||
|
fnames = check_fname_exists(fnames)
|
||||||
|
fnames_alt = check_fname_exists(fnames_alt)
|
||||||
|
|
||||||
# if obspy_dmt:
|
# if obspy_dmt:
|
||||||
# wfdir = 'raw'
|
# wfdir = 'raw'
|
||||||
# self.processed = False
|
# self.processed = False
|
||||||
@@ -457,8 +491,8 @@ class Data(object):
|
|||||||
# wffnames = fnames
|
# wffnames = fnames
|
||||||
if fnames is not None:
|
if fnames is not None:
|
||||||
self.appendWFData(fnames)
|
self.appendWFData(fnames)
|
||||||
if fnames_syn is not None:
|
if fnames_alt is not None:
|
||||||
self.appendWFData(fnames_syn, synthetic=True)
|
self.appendWFData(fnames_alt, alternative=True)
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -466,7 +500,9 @@ class Data(object):
|
|||||||
# remove possible underscores in station names
|
# remove possible underscores in station names
|
||||||
# self.wfdata = remove_underscores(self.wfdata)
|
# self.wfdata = remove_underscores(self.wfdata)
|
||||||
# check for gaps and merge
|
# check for gaps and merge
|
||||||
self.wfdata = check4gapsAndMerge(self.wfdata)
|
self.wfdata, _ = check_for_gaps_and_merge(self.wfdata)
|
||||||
|
# check for nans
|
||||||
|
check_for_nan(self.wfdata)
|
||||||
# check for stations with rotated components
|
# check for stations with rotated components
|
||||||
if checkRotated and metadata is not None:
|
if checkRotated and metadata is not None:
|
||||||
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
|
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
|
||||||
@@ -478,7 +514,7 @@ class Data(object):
|
|||||||
self.dirty = False
|
self.dirty = False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def appendWFData(self, fnames, synthetic=False):
|
def appendWFData(self, fnames, alternative=False):
|
||||||
"""
|
"""
|
||||||
Read waveform data from fnames and append it to current wf data
|
Read waveform data from fnames and append it to current wf data
|
||||||
:param fnames: waveform data to append
|
:param fnames: waveform data to append
|
||||||
@@ -491,19 +527,19 @@ class Data(object):
|
|||||||
if self.dirty:
|
if self.dirty:
|
||||||
self.resetWFData()
|
self.resetWFData()
|
||||||
|
|
||||||
real_or_syn_data = {True: self.wfsyn,
|
orig_or_alternative_data = {True: self.wf_alt,
|
||||||
False: self.wfdata}
|
False: self.wfdata}
|
||||||
|
|
||||||
warnmsg = ''
|
warnmsg = ''
|
||||||
for fname in set(fnames):
|
for fname in set(fnames):
|
||||||
try:
|
try:
|
||||||
real_or_syn_data[synthetic] += read(fname, starttime=self.tstart, endtime=self.tstop)
|
orig_or_alternative_data[alternative] += read(fname, starttime=self.tstart, endtime=self.tstop)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
try:
|
try:
|
||||||
real_or_syn_data[synthetic] += read(fname, format='GSE2', starttime=self.tstart, endtime=self.tstop)
|
orig_or_alternative_data[alternative] += read(fname, format='GSE2', starttime=self.tstart, endtime=self.tstop)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
try:
|
try:
|
||||||
real_or_syn_data[synthetic] += read(fname, format='SEGY', starttime=self.tstart,
|
orig_or_alternative_data[alternative] += read(fname, format='SEGY', starttime=self.tstart,
|
||||||
endtime=self.tstop)
|
endtime=self.tstop)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
warnmsg += '{0}\n{1}\n'.format(fname, e)
|
warnmsg += '{0}\n{1}\n'.format(fname, e)
|
||||||
@@ -519,8 +555,8 @@ class Data(object):
|
|||||||
def getOriginalWFData(self):
|
def getOriginalWFData(self):
|
||||||
return self.wforiginal
|
return self.wforiginal
|
||||||
|
|
||||||
def getSynWFData(self):
|
def getAltWFdata(self):
|
||||||
return self.wfsyn
|
return self.wf_alt
|
||||||
|
|
||||||
def resetWFData(self):
|
def resetWFData(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
Edited for use in PyLoT
|
Edited for use in PyLoT
|
||||||
JG, igem, 01/2022
|
JG, igem, 01/2022
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
from obspy.core.event import read_events
|
from obspy.core.event import read_events
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
Script to get onset uncertainties from Quakeml.xml files created by PyLoT.
|
|
||||||
Uncertainties are tranformed into quality classes and visualized via histogram if desired.
|
|
||||||
Ludger Küperkoch, BESTEC GmbH, 07/2017
|
|
||||||
rev.: Ludger Küperkoch, igem, 10/2020
|
|
||||||
Edited for usage in PyLoT: Jeldrik Gaal, igem, 01/2022
|
|
||||||
"""
|
|
||||||
|
|
||||||
import glob
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import numpy as np
|
|
||||||
from obspy.core.event import read_events
|
|
||||||
|
|
||||||
|
|
||||||
def getQualitiesfromxml(path):
|
|
||||||
# uncertainties
|
|
||||||
ErrorsP = [0.02, 0.04, 0.08, 0.16]
|
|
||||||
ErrorsS = [0.04, 0.08, 0.16, 0.32]
|
|
||||||
|
|
||||||
Pw0 = []
|
|
||||||
Pw1 = []
|
|
||||||
Pw2 = []
|
|
||||||
Pw3 = []
|
|
||||||
Pw4 = []
|
|
||||||
Sw0 = []
|
|
||||||
Sw1 = []
|
|
||||||
Sw2 = []
|
|
||||||
Sw3 = []
|
|
||||||
Sw4 = []
|
|
||||||
|
|
||||||
# data path
|
|
||||||
dp = path + '/e*/*.xml'
|
|
||||||
# list of all available xml-files
|
|
||||||
xmlnames = glob.glob(dp)
|
|
||||||
|
|
||||||
# read all onset weights
|
|
||||||
for names in xmlnames:
|
|
||||||
print("Getting onset weights from {}".format(names))
|
|
||||||
cat = read_events(names)
|
|
||||||
arrivals = cat.events[0].picks
|
|
||||||
for Pick in arrivals:
|
|
||||||
if Pick.phase_hint[0] == 'P':
|
|
||||||
if Pick.time_errors.uncertainty <= ErrorsP[0]:
|
|
||||||
Pw0.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pick.time_errors.uncertainty > ErrorsP[0] and \
|
|
||||||
Pick.time_errors.uncertainty <= ErrorsP[1]:
|
|
||||||
Pw1.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pick.time_errors.uncertainty > ErrorsP[1] and \
|
|
||||||
Pick.time_errors.uncertainty <= ErrorsP[2]:
|
|
||||||
Pw2.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pick.time_errors.uncertainty > ErrorsP[2] and \
|
|
||||||
Pick.time_errors.uncertainty <= ErrorsP[3]:
|
|
||||||
Pw3.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pick.time_errors.uncertainty > ErrorsP[3]:
|
|
||||||
Pw4.append(Pick.time_errors.uncertainty)
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
elif Pick.phase_hint[0] == 'S':
|
|
||||||
if Pick.time_errors.uncertainty <= ErrorsS[0]:
|
|
||||||
Sw0.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pick.time_errors.uncertainty > ErrorsS[0] and \
|
|
||||||
Pick.time_errors.uncertainty <= ErrorsS[1]:
|
|
||||||
Sw1.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pick.time_errors.uncertainty > ErrorsS[1] and \
|
|
||||||
Pick.time_errors.uncertainty <= ErrorsS[2]:
|
|
||||||
Sw2.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pick.time_errors.uncertainty > ErrorsS[2] and \
|
|
||||||
Pick.time_errors.uncertainty <= ErrorsS[3]:
|
|
||||||
Sw3.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pick.time_errors.uncertainty > ErrorsS[3]:
|
|
||||||
Sw4.append(Pick.time_errors.uncertainty)
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
print("Phase hint not defined for picking!")
|
|
||||||
pass
|
|
||||||
# get percentage of weights
|
|
||||||
numPweights = np.sum([len(Pw0), len(Pw1), len(Pw2), len(Pw3), len(Pw4)])
|
|
||||||
numSweights = np.sum([len(Sw0), len(Sw1), len(Sw2), len(Sw3), len(Sw4)])
|
|
||||||
try:
|
|
||||||
P0perc = 100.0 / numPweights * len(Pw0)
|
|
||||||
except:
|
|
||||||
P0perc = 0
|
|
||||||
try:
|
|
||||||
P1perc = 100.0 / numPweights * len(Pw1)
|
|
||||||
except:
|
|
||||||
P1perc = 0
|
|
||||||
try:
|
|
||||||
P2perc = 100.0 / numPweights * len(Pw2)
|
|
||||||
except:
|
|
||||||
P2perc = 0
|
|
||||||
try:
|
|
||||||
P3perc = 100.0 / numPweights * len(Pw3)
|
|
||||||
except:
|
|
||||||
P3perc = 0
|
|
||||||
try:
|
|
||||||
P4perc = 100.0 / numPweights * len(Pw4)
|
|
||||||
except:
|
|
||||||
P4perc = 0
|
|
||||||
try:
|
|
||||||
S0perc = 100.0 / numSweights * len(Sw0)
|
|
||||||
except:
|
|
||||||
Soperc = 0
|
|
||||||
try:
|
|
||||||
S1perc = 100.0 / numSweights * len(Sw1)
|
|
||||||
except:
|
|
||||||
S1perc = 0
|
|
||||||
try:
|
|
||||||
S2perc = 100.0 / numSweights * len(Sw2)
|
|
||||||
except:
|
|
||||||
S2perc = 0
|
|
||||||
try:
|
|
||||||
S3perc = 100.0 / numSweights * len(Sw3)
|
|
||||||
except:
|
|
||||||
S3perc = 0
|
|
||||||
try:
|
|
||||||
S4perc = 100.0 / numSweights * len(Sw4)
|
|
||||||
except:
|
|
||||||
S4perc = 0
|
|
||||||
|
|
||||||
weights = ('0', '1', '2', '3', '4')
|
|
||||||
y_pos = np.arange(len(weights))
|
|
||||||
width = 0.34
|
|
||||||
p1, = plt.bar(0 - width, P0perc, width, color='black')
|
|
||||||
p2, = plt.bar(0, S0perc, width, color='red')
|
|
||||||
plt.bar(y_pos - width, [P0perc, P1perc, P2perc, P3perc, P4perc], width, color='black')
|
|
||||||
plt.bar(y_pos, [S0perc, S1perc, S2perc, S3perc, S4perc], width, color='red')
|
|
||||||
plt.ylabel('%')
|
|
||||||
plt.xticks(y_pos, weights)
|
|
||||||
plt.xlim([-0.5, 4.5])
|
|
||||||
plt.xlabel('Qualities')
|
|
||||||
plt.title('{0} P-Qualities, {1} S-Qualities'.format(numPweights, numSweights))
|
|
||||||
plt.legend([p1, p2], ['P-Weights', 'S-Weights'])
|
|
||||||
plt.show()
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from obspy import UTCDateTime
|
from obspy import UTCDateTime
|
||||||
from obspy.core import event as ope
|
from obspy.core import event as ope
|
||||||
|
|
||||||
from pylot.core.util.utils import getLogin, getHash
|
from pylot.core.util.utils import get_login, get_hash
|
||||||
|
|
||||||
|
|
||||||
def create_amplitude(pickID, amp, unit, category, cinfo):
|
def create_amplitude(pickID, amp, unit, category, cinfo):
|
||||||
@@ -61,7 +61,7 @@ def create_creation_info(agency_id=None, creation_time=None, author=None):
|
|||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
if author is None:
|
if author is None:
|
||||||
author = getLogin()
|
author = get_login()
|
||||||
if creation_time is None:
|
if creation_time is None:
|
||||||
creation_time = UTCDateTime()
|
creation_time = UTCDateTime()
|
||||||
return ope.CreationInfo(agency_id=agency_id, author=author,
|
return ope.CreationInfo(agency_id=agency_id, author=author,
|
||||||
@@ -210,7 +210,7 @@ def create_resourceID(timetohash, restype, authority_id=None, hrstr=None):
|
|||||||
'''
|
'''
|
||||||
assert isinstance(timetohash, UTCDateTime), "'timetohash' is not an ObsPy" \
|
assert isinstance(timetohash, UTCDateTime), "'timetohash' is not an ObsPy" \
|
||||||
"UTCDateTime object"
|
"UTCDateTime object"
|
||||||
hid = getHash(timetohash)
|
hid = get_hash(timetohash)
|
||||||
if hrstr is None:
|
if hrstr is None:
|
||||||
resID = ope.ResourceIdentifier(restype + '/' + hid[0:6])
|
resID = ope.ResourceIdentifier(restype + '/' + hid[0:6])
|
||||||
else:
|
else:
|
||||||
|
|||||||
+111
-145
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import glob
|
import glob
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
@@ -16,8 +17,8 @@ from pylot.core.io.inputs import PylotParameter
|
|||||||
from pylot.core.io.location import create_event, \
|
from pylot.core.io.location import create_event, \
|
||||||
create_magnitude
|
create_magnitude
|
||||||
from pylot.core.pick.utils import select_for_phase, get_quality_class
|
from pylot.core.pick.utils import select_for_phase, get_quality_class
|
||||||
from pylot.core.util.utils import getOwner, full_range, four_digits, transformFilterString4Export, \
|
from pylot.core.util.utils import get_owner, full_range, four_digits, transformFilterString4Export, \
|
||||||
backtransformFilterString
|
backtransformFilterString, loopIdentifyPhase, identifyPhase
|
||||||
|
|
||||||
|
|
||||||
def add_amplitudes(event, amplitudes):
|
def add_amplitudes(event, amplitudes):
|
||||||
@@ -58,7 +59,7 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id='RUB', **kwargs):
|
|||||||
if phasfn is not None and os.path.isfile(phasfn):
|
if phasfn is not None and os.path.isfile(phasfn):
|
||||||
phases = sio.loadmat(phasfn)
|
phases = sio.loadmat(phasfn)
|
||||||
phasctime = UTCDateTime(os.path.getmtime(phasfn))
|
phasctime = UTCDateTime(os.path.getmtime(phasfn))
|
||||||
phasauthor = getOwner(phasfn)
|
phasauthor = get_owner(phasfn)
|
||||||
else:
|
else:
|
||||||
phases = None
|
phases = None
|
||||||
phasctime = None
|
phasctime = None
|
||||||
@@ -66,7 +67,7 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id='RUB', **kwargs):
|
|||||||
if locfn is not None and os.path.isfile(locfn):
|
if locfn is not None and os.path.isfile(locfn):
|
||||||
loc = sio.loadmat(locfn)
|
loc = sio.loadmat(locfn)
|
||||||
locctime = UTCDateTime(os.path.getmtime(locfn))
|
locctime = UTCDateTime(os.path.getmtime(locfn))
|
||||||
locauthor = getOwner(locfn)
|
locauthor = get_owner(locfn)
|
||||||
else:
|
else:
|
||||||
loc = None
|
loc = None
|
||||||
locctime = None
|
locctime = None
|
||||||
@@ -217,7 +218,7 @@ def picksdict_from_obs(fn):
|
|||||||
return picks
|
return picks
|
||||||
|
|
||||||
|
|
||||||
def picksdict_from_picks(evt):
|
def picksdict_from_picks(evt, parameter=None):
|
||||||
"""
|
"""
|
||||||
Takes an Event object and return the pick dictionary commonly used within
|
Takes an Event object and return the pick dictionary commonly used within
|
||||||
PyLoT
|
PyLoT
|
||||||
@@ -230,6 +231,7 @@ def picksdict_from_picks(evt):
|
|||||||
'auto': {}
|
'auto': {}
|
||||||
}
|
}
|
||||||
for pick in evt.picks:
|
for pick in evt.picks:
|
||||||
|
errors = None
|
||||||
phase = {}
|
phase = {}
|
||||||
station = pick.waveform_id.station_code
|
station = pick.waveform_id.station_code
|
||||||
if pick.waveform_id.channel_code is None:
|
if pick.waveform_id.channel_code is None:
|
||||||
@@ -273,32 +275,29 @@ def picksdict_from_picks(evt):
|
|||||||
phase['epp'] = epp
|
phase['epp'] = epp
|
||||||
phase['lpp'] = lpp
|
phase['lpp'] = lpp
|
||||||
phase['spe'] = spe
|
phase['spe'] = spe
|
||||||
try:
|
weight = phase.get('weight')
|
||||||
phase['weight'] = weight
|
if not weight:
|
||||||
except:
|
if not parameter:
|
||||||
# get onset weight from uncertainty
|
logging.warning('Using ')
|
||||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
logging.warning('Using default input parameter')
|
||||||
print('Using default input file {}'.format(infile))
|
parameter = PylotParameter()
|
||||||
parameter = PylotParameter(infile)
|
pick.phase_hint = identifyPhase(pick.phase_hint)
|
||||||
if pick.phase_hint == 'P':
|
if pick.phase_hint == 'P':
|
||||||
errors = parameter['timeerrorsP']
|
errors = parameter['timeerrorsP']
|
||||||
elif pick.phase_hint == 'S':
|
elif pick.phase_hint == 'S':
|
||||||
errors = parameter['timeerrorsS']
|
errors = parameter['timeerrorsS']
|
||||||
|
if errors:
|
||||||
weight = get_quality_class(spe, errors)
|
weight = get_quality_class(spe, errors)
|
||||||
phase['weight'] = weight
|
phase['weight'] = weight
|
||||||
phase['channel'] = channel
|
phase['channel'] = channel
|
||||||
phase['network'] = network
|
phase['network'] = network
|
||||||
phase['picker'] = pick_method
|
phase['picker'] = pick_method
|
||||||
try:
|
|
||||||
if pick.polarity == 'positive':
|
if pick.polarity == 'positive':
|
||||||
phase['fm'] = 'U'
|
phase['fm'] = 'U'
|
||||||
elif pick.polarity == 'negative':
|
elif pick.polarity == 'negative':
|
||||||
phase['fm'] = 'D'
|
phase['fm'] = 'D'
|
||||||
else:
|
else:
|
||||||
phase['fm'] = 'N'
|
phase['fm'] = 'N'
|
||||||
except:
|
|
||||||
print("No FM info available!")
|
|
||||||
phase['fm'] = 'N'
|
|
||||||
phase['filter_id'] = filter_id if filter_id is not None else ''
|
phase['filter_id'] = filter_id if filter_id is not None else ''
|
||||||
|
|
||||||
onsets[pick.phase_hint] = phase.copy()
|
onsets[pick.phase_hint] = phase.copy()
|
||||||
@@ -375,7 +374,6 @@ def picks_from_picksdict(picks, creation_info=None):
|
|||||||
|
|
||||||
|
|
||||||
def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0):
|
def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0):
|
||||||
import glob
|
|
||||||
# TODO: change root to datapath
|
# TODO: change root to datapath
|
||||||
db_root = os.path.join(root_dir, db_dir)
|
db_root = os.path.join(root_dir, db_dir)
|
||||||
evt_list = glob.glob1(db_root, 'e????.???.??')
|
evt_list = glob.glob1(db_root, 'e????.???.??')
|
||||||
@@ -518,7 +516,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||||
for key in arrivals:
|
for key in arrivals:
|
||||||
# P onsets
|
# P onsets
|
||||||
if arrivals[key].has_key('P'):
|
if 'P' in arrivals[key]:
|
||||||
try:
|
try:
|
||||||
fm = arrivals[key]['P']['fm']
|
fm = arrivals[key]['P']['fm']
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
@@ -552,7 +550,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
ss_ms,
|
ss_ms,
|
||||||
pweight))
|
pweight))
|
||||||
# S onsets
|
# S onsets
|
||||||
if arrivals[key].has_key('S') and arrivals[key]['S']['mpp'] is not None:
|
if 'S' in arrivals[key] and arrivals[key]['S']['mpp'] is not None:
|
||||||
fm = '?'
|
fm = '?'
|
||||||
onset = arrivals[key]['S']['mpp']
|
onset = arrivals[key]['S']['mpp']
|
||||||
year = onset.year
|
year = onset.year
|
||||||
@@ -671,7 +669,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||||
for key in arrivals:
|
for key in arrivals:
|
||||||
# P onsets
|
# P onsets
|
||||||
if arrivals[key].has_key('P') and arrivals[key]['P']['mpp'] is not None:
|
if 'P' in arrivals[key] and arrivals[key]['P']['mpp'] is not None:
|
||||||
if arrivals[key]['P']['weight'] < 4:
|
if arrivals[key]['P']['weight'] < 4:
|
||||||
Ponset = arrivals[key]['P']['mpp']
|
Ponset = arrivals[key]['P']['mpp']
|
||||||
pyear = Ponset.year
|
pyear = Ponset.year
|
||||||
@@ -700,7 +698,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
fid.write('%-5s P1 %4.0f %02d %02d %02d %02d %05.02f %5.3f -999. 0.00 -999. 0.00\n'
|
fid.write('%-5s P1 %4.0f %02d %02d %02d %02d %05.02f %5.3f -999. 0.00 -999. 0.00\n'
|
||||||
% (key, pyear, pmonth, pday, phh, pmm, Pss, pstd))
|
% (key, pyear, pmonth, pday, phh, pmm, Pss, pstd))
|
||||||
# S onsets
|
# S onsets
|
||||||
if arrivals[key].has_key('S') and arrivals[key]['S']['mpp'] is not None:
|
if 'S' in arrivals[key] and arrivals[key]['S']['mpp'] is not None:
|
||||||
if arrivals[key]['S']['weight'] < 4:
|
if arrivals[key]['S']['weight'] < 4:
|
||||||
Sonset = arrivals[key]['S']['mpp']
|
Sonset = arrivals[key]['S']['mpp']
|
||||||
syear = Sonset.year
|
syear = Sonset.year
|
||||||
@@ -769,7 +767,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
usedarrivals = chooseArrivals(arrivals)
|
usedarrivals = chooseArrivals(arrivals)
|
||||||
for key in usedarrivals:
|
for key in usedarrivals:
|
||||||
# P onsets
|
# P onsets
|
||||||
if usedarrivals[key].has_key('P'):
|
if 'P' in usedarrivals[key]:
|
||||||
if usedarrivals[key]['P']['weight'] < 4:
|
if usedarrivals[key]['P']['weight'] < 4:
|
||||||
n += 1
|
n += 1
|
||||||
stat = key
|
stat = key
|
||||||
@@ -783,7 +781,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
else:
|
else:
|
||||||
fid.write('%-4sP%d%6.2f\n' % (stat, Pweight, Prt))
|
fid.write('%-4sP%d%6.2f\n' % (stat, Pweight, Prt))
|
||||||
# S onsets
|
# S onsets
|
||||||
if usedarrivals[key].has_key('S'):
|
if 'S' in usedarrivals[key]:
|
||||||
if usedarrivals[key]['S']['weight'] < 4:
|
if usedarrivals[key]['S']['weight'] < 4:
|
||||||
n += 1
|
n += 1
|
||||||
stat = key
|
stat = key
|
||||||
@@ -829,13 +827,13 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
# prefer manual picks
|
# prefer manual picks
|
||||||
usedarrivals = chooseArrivals(arrivals)
|
usedarrivals = chooseArrivals(arrivals)
|
||||||
for key in usedarrivals:
|
for key in usedarrivals:
|
||||||
if usedarrivals[key].has_key('P'):
|
if 'P' in usedarrivals[key]:
|
||||||
# P onsets
|
# P onsets
|
||||||
if usedarrivals[key]['P']['weight'] < 4:
|
if usedarrivals[key]['P']['weight'] < 4:
|
||||||
Ponset = usedarrivals[key]['P']['mpp']
|
Ponset = usedarrivals[key]['P']['mpp']
|
||||||
Prt = Ponset - stime # onset time relative to source time
|
Prt = Ponset - stime # onset time relative to source time
|
||||||
fid.write('%s %6.3f 1 P\n' % (key, Prt))
|
fid.write('%s %6.3f 1 P\n' % (key, Prt))
|
||||||
if usedarrivals[key].has_key('S'):
|
if 'S' in usedarrivals[key]:
|
||||||
# S onsets
|
# S onsets
|
||||||
if usedarrivals[key]['S']['weight'] < 4:
|
if usedarrivals[key]['S']['weight'] < 4:
|
||||||
Sonset = usedarrivals[key]['S']['mpp']
|
Sonset = usedarrivals[key]['S']['mpp']
|
||||||
@@ -880,7 +878,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
# prefer manual picks
|
# prefer manual picks
|
||||||
usedarrivals = chooseArrivals(arrivals)
|
usedarrivals = chooseArrivals(arrivals)
|
||||||
for key in usedarrivals:
|
for key in usedarrivals:
|
||||||
if usedarrivals[key].has_key('P'):
|
if 'P' in usedarrivals[key]:
|
||||||
if usedarrivals[key]['P']['weight'] < 4 and usedarrivals[key]['P']['fm'] is not None:
|
if usedarrivals[key]['P']['weight'] < 4 and usedarrivals[key]['P']['fm'] is not None:
|
||||||
stat = key
|
stat = key
|
||||||
for i in range(len(picks)):
|
for i in range(len(picks)):
|
||||||
@@ -962,7 +960,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
|||||||
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||||
# write phase lines
|
# write phase lines
|
||||||
for key in arrivals:
|
for key in arrivals:
|
||||||
if arrivals[key].has_key('P'):
|
if 'P' in arrivals[key]:
|
||||||
if arrivals[key]['P']['weight'] < 4 and arrivals[key]['P']['fm'] is not None:
|
if arrivals[key]['P']['weight'] < 4 and arrivals[key]['P']['fm'] is not None:
|
||||||
stat = key
|
stat = key
|
||||||
ccode = arrivals[key]['P']['channel']
|
ccode = arrivals[key]['P']['channel']
|
||||||
@@ -1015,7 +1013,6 @@ def chooseArrivals(arrivals):
|
|||||||
:return: arrivals but with the manual picks prefered if possible
|
:return: arrivals but with the manual picks prefered if possible
|
||||||
"""
|
"""
|
||||||
# If len of arrivals is greater than 2 it comes from autopicking so only autopicks are available
|
# If len of arrivals is greater than 2 it comes from autopicking so only autopicks are available
|
||||||
print("=== CHOOSE ===")
|
|
||||||
if len(arrivals) > 2:
|
if len(arrivals) > 2:
|
||||||
return arrivals
|
return arrivals
|
||||||
if arrivals['auto'] and arrivals['manual']:
|
if arrivals['auto'] and arrivals['manual']:
|
||||||
@@ -1056,37 +1053,63 @@ def merge_picks(event, picks):
|
|||||||
return event
|
return event
|
||||||
|
|
||||||
|
|
||||||
def getQualitiesfromxml(xmlnames, ErrorsP, ErrorsS, plotflag=1):
|
def getQualitiesfromxml(path, errorsP, errorsS, plotflag=1, figure=None, verbosity=0):
|
||||||
"""
|
"""
|
||||||
Script to get onset uncertainties from Quakeml.xml files created by PyLoT.
|
Script to get onset uncertainties from Quakeml.xml files created by PyLoT.
|
||||||
Uncertainties are tranformed into quality classes and visualized via histogram if desired.
|
Uncertainties are tranformed into quality classes and visualized via histogram if desired.
|
||||||
Ludger Küperkoch, BESTEC GmbH, 07/2017
|
Ludger Küperkoch, BESTEC GmbH, 07/2017
|
||||||
:param xmlnames: list of xml obspy event files containing picks
|
:param path: path containing xml files
|
||||||
:type xmlnames: list
|
:type path: str
|
||||||
:param ErrorsP: time errors of P waves for the four discrete quality classes
|
:param errorsP: time errors of P waves for the four discrete quality classes
|
||||||
:type ErrorsP:
|
:type errorsP:
|
||||||
:param ErrorsS: time errors of S waves for the four discrete quality classes
|
:param errorsS: time errors of S waves for the four discrete quality classes
|
||||||
:type ErrorsS:
|
:type errorsS:
|
||||||
:param plotflag:
|
:param plotflag:
|
||||||
:type plotflag:
|
:type plotflag:
|
||||||
:return:
|
:return:
|
||||||
:rtype:
|
:rtype:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pylot.core.pick.utils import get_quality_class
|
def calc_perc(uncertainties, ntotal):
|
||||||
from pylot.core.util.utils import loopIdentifyPhase, identifyPhase
|
''' simple function that calculates percentage of number of uncertainties (list length)'''
|
||||||
|
if len(uncertainties) == 0:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return 100. / ntotal * len(uncertainties)
|
||||||
|
|
||||||
|
def calc_weight_perc(psweights, weight_ids):
|
||||||
|
''' calculate percentages of different weights (pick classes!?) of total number of uncertainties of a phase'''
|
||||||
|
# count total number of list items for this phase
|
||||||
|
numWeights = np.sum([len(weight) for weight in psweights.values()])
|
||||||
|
|
||||||
|
# iterate over all available weights to return a list with percentages for plotting
|
||||||
|
plot_list = []
|
||||||
|
for weight_id in weight_ids:
|
||||||
|
plot_list.append(calc_perc(psweights[weight_id], numWeights))
|
||||||
|
|
||||||
|
return plot_list, numWeights
|
||||||
|
|
||||||
|
# get all xmlfiles in path (maybe this should be changed to one xml file for this function, selectable via GUI?)
|
||||||
|
xmlnames = glob.glob(os.path.join(path, '*.xml'))
|
||||||
|
if len(xmlnames) == 0:
|
||||||
|
print(f'No files found in path {path}.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# first define possible phases here
|
||||||
|
phases = ['P', 'S']
|
||||||
|
|
||||||
|
# define possible weights (0-4)
|
||||||
|
weight_ids = list(range(5))
|
||||||
|
|
||||||
|
# put both error lists in a dictionary with P/S key so that amount of code can be halfed by simply using P/S as key
|
||||||
|
errors = dict(P=errorsP, S=errorsS)
|
||||||
|
|
||||||
|
# create dictionaries for each phase (P/S) with a dictionary of empty list for each weight defined in weights
|
||||||
|
# tuple above
|
||||||
|
weights = {}
|
||||||
|
for phase in phases:
|
||||||
|
weights[phase] = {weight_id: [] for weight_id in weight_ids}
|
||||||
|
|
||||||
# read all onset weights
|
|
||||||
Pw0 = []
|
|
||||||
Pw1 = []
|
|
||||||
Pw2 = []
|
|
||||||
Pw3 = []
|
|
||||||
Pw4 = []
|
|
||||||
Sw0 = []
|
|
||||||
Sw1 = []
|
|
||||||
Sw2 = []
|
|
||||||
Sw3 = []
|
|
||||||
Sw4 = []
|
|
||||||
for names in xmlnames:
|
for names in xmlnames:
|
||||||
print("Getting onset weights from {}".format(names))
|
print("Getting onset weights from {}".format(names))
|
||||||
cat = read_events(names)
|
cat = read_events(names)
|
||||||
@@ -1094,117 +1117,60 @@ def getQualitiesfromxml(xmlnames, ErrorsP, ErrorsS, plotflag=1):
|
|||||||
arrivals = cat.events[0].picks
|
arrivals = cat.events[0].picks
|
||||||
arrivals_copy = cat_copy.events[0].picks
|
arrivals_copy = cat_copy.events[0].picks
|
||||||
# Prefere manual picks if qualities are sufficient!
|
# Prefere manual picks if qualities are sufficient!
|
||||||
for Pick in arrivals:
|
for pick in arrivals:
|
||||||
if Pick.method_id.id.split('/')[1] == 'manual':
|
if pick.method_id.id.split('/')[1] == 'manual':
|
||||||
mstation = Pick.waveform_id.station_code
|
mstation = pick.waveform_id.station_code
|
||||||
mstation_ext = mstation + '_'
|
mstation_ext = mstation + '_'
|
||||||
for mpick in arrivals_copy:
|
for mpick in arrivals_copy:
|
||||||
phase = identifyPhase(loopIdentifyPhase(Pick.phase_hint))
|
phase = identifyPhase(loopIdentifyPhase(pick.phase_hint)) # MP MP catch if this fails?
|
||||||
if phase == 'P':
|
|
||||||
if ((mpick.waveform_id.station_code == mstation) or
|
if ((mpick.waveform_id.station_code == mstation) or
|
||||||
(mpick.waveform_id.station_code == mstation_ext)) and \
|
(mpick.waveform_id.station_code == mstation_ext)) and \
|
||||||
(mpick.method_id.split('/')[1] == 'auto') and \
|
(mpick.method_id.id.split('/')[1] == 'auto') and \
|
||||||
(mpick.time_errors['uncertainty'] <= ErrorsP[3]):
|
(mpick.time_errors['uncertainty'] <= errors[phase][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.time_errors['uncertainty'] <= ErrorsS[3]):
|
|
||||||
del mpick
|
del mpick
|
||||||
break
|
break
|
||||||
lendiff = len(arrivals) - len(arrivals_copy)
|
lendiff = len(arrivals) - len(arrivals_copy)
|
||||||
if lendiff != 0:
|
if lendiff != 0:
|
||||||
print("Found manual as well as automatic picks, prefered the {} manual ones!".format(lendiff))
|
print("Found manual as well as automatic picks, prefered the {} manual ones!".format(lendiff))
|
||||||
|
|
||||||
for Pick in arrivals_copy:
|
for pick in arrivals_copy:
|
||||||
phase = identifyPhase(loopIdentifyPhase(Pick.phase_hint))
|
phase = identifyPhase(loopIdentifyPhase(pick.phase_hint))
|
||||||
if phase == 'P':
|
uncertainty = pick.time_errors.uncertainty
|
||||||
Pqual = get_quality_class(Pick.time_errors.uncertainty, ErrorsP)
|
if not uncertainty:
|
||||||
if Pqual == 0:
|
if verbosity > 0:
|
||||||
Pw0.append(Pick.time_errors.uncertainty)
|
print('No uncertainty, pick {} invalid!'.format(pick.method_id.id))
|
||||||
elif Pqual == 1:
|
continue
|
||||||
Pw1.append(Pick.time_errors.uncertainty)
|
# check P/S phase
|
||||||
elif Pqual == 2:
|
if phase not in phases:
|
||||||
Pw2.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pqual == 3:
|
|
||||||
Pw3.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Pqual == 4:
|
|
||||||
Pw4.append(Pick.time_errors.uncertainty)
|
|
||||||
elif phase == 'S':
|
|
||||||
Squal = get_quality_class(Pick.time_errors.uncertainty, ErrorsS)
|
|
||||||
if Squal == 0:
|
|
||||||
Sw0.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Squal == 1:
|
|
||||||
Sw1.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Squal == 2:
|
|
||||||
Sw2.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Squal == 3:
|
|
||||||
Sw3.append(Pick.time_errors.uncertainty)
|
|
||||||
elif Squal == 4:
|
|
||||||
Sw4.append(Pick.time_errors.uncertainty)
|
|
||||||
else:
|
|
||||||
print("Phase hint not defined for picking!")
|
print("Phase hint not defined for picking!")
|
||||||
pass
|
continue
|
||||||
|
|
||||||
|
qual = get_quality_class(uncertainty, errors[phase])
|
||||||
|
weights[phase][qual].append(uncertainty)
|
||||||
|
|
||||||
if plotflag == 0:
|
if plotflag == 0:
|
||||||
Punc = [Pw0, Pw1, Pw2, Pw3, Pw4]
|
p_unc = [weights['P'][weight_id] for weight_id in weight_ids]
|
||||||
Sunc = [Sw0, Sw1, Sw2, Sw3, Sw4]
|
s_unc = [weights['S'][weight_id] for weight_id in weight_ids]
|
||||||
return Punc, Sunc
|
return p_unc, s_unc
|
||||||
else:
|
else:
|
||||||
|
if not figure:
|
||||||
|
fig = plt.figure()
|
||||||
|
ax = fig.add_subplot(111)
|
||||||
# get percentage of weights
|
# get percentage of weights
|
||||||
numPweights = np.sum([len(Pw0), len(Pw1), len(Pw2), len(Pw3), len(Pw4)])
|
listP, numPweights = calc_weight_perc(weights['P'], weight_ids)
|
||||||
numSweights = np.sum([len(Sw0), len(Sw1), len(Sw2), len(Sw3), len(Sw4)])
|
listS, numSweights = calc_weight_perc(weights['S'], weight_ids)
|
||||||
if len(Pw0) > 0:
|
|
||||||
P0perc = 100 / numPweights * len(Pw0)
|
|
||||||
else:
|
|
||||||
P0perc = 0
|
|
||||||
if len(Pw1) > 0:
|
|
||||||
P1perc = 100 / numPweights * len(Pw1)
|
|
||||||
else:
|
|
||||||
P1perc = 0
|
|
||||||
if len(Pw2) > 0:
|
|
||||||
P2perc = 100 / numPweights * len(Pw2)
|
|
||||||
else:
|
|
||||||
P2perc = 0
|
|
||||||
if len(Pw3) > 0:
|
|
||||||
P3perc = 100 / numPweights * len(Pw3)
|
|
||||||
else:
|
|
||||||
P3perc = 0
|
|
||||||
if len(Pw4) > 0:
|
|
||||||
P4perc = 100 / numPweights * len(Pw4)
|
|
||||||
else:
|
|
||||||
P4perc = 0
|
|
||||||
if len(Sw0) > 0:
|
|
||||||
S0perc = 100 / numSweights * len(Sw0)
|
|
||||||
else:
|
|
||||||
S0perc = 0
|
|
||||||
if len(Sw1) > 0:
|
|
||||||
S1perc = 100 / numSweights * len(Sw1)
|
|
||||||
else:
|
|
||||||
S1perc = 0
|
|
||||||
if len(Sw2) > 0:
|
|
||||||
S2perc = 100 / numSweights * len(Sw2)
|
|
||||||
else:
|
|
||||||
S2perc = 0
|
|
||||||
if len(Sw3) > 0:
|
|
||||||
S3perc = 100 / numSweights * len(Sw3)
|
|
||||||
else:
|
|
||||||
S3perc = 0
|
|
||||||
if len(Sw4) > 0:
|
|
||||||
S4perc = 100 / numSweights * len(Sw4)
|
|
||||||
else:
|
|
||||||
S4perc = 0
|
|
||||||
|
|
||||||
weights = ('0', '1', '2', '3', '4')
|
y_pos = np.arange(len(weight_ids))
|
||||||
y_pos = np.arange(len(weights))
|
|
||||||
width = 0.34
|
width = 0.34
|
||||||
plt.bar(y_pos - width, [P0perc, P1perc, P2perc, P3perc, P4perc], width, color='black')
|
ax.bar(y_pos - width, listP, width, color='black')
|
||||||
plt.bar(y_pos, [S0perc, S1perc, S2perc, S3perc, S4perc], width, color='red')
|
ax.bar(y_pos, listS, width, color='red')
|
||||||
plt.ylabel('%')
|
ax.set_ylabel('%')
|
||||||
plt.xticks(y_pos, weights)
|
ax.set_xticks(y_pos, weight_ids)
|
||||||
plt.xlim([-0.5, 4.5])
|
ax.set_xlim([-0.5, 4.5])
|
||||||
plt.xlabel('Qualities')
|
ax.set_xlabel('Qualities')
|
||||||
plt.title('{0} P-Qualities, {1} S-Qualities'.format(numPweights, numSweights))
|
ax.set_title('{0} P-Qualities, {1} S-Qualities'.format(numPweights, numSweights))
|
||||||
plt.show()
|
|
||||||
|
if not figure:
|
||||||
|
fig.show()
|
||||||
|
|
||||||
|
return listP, listS
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ def locate(fnin, parameter=None):
|
|||||||
:param fnin: external program name
|
:param fnin: external program name
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
exe_path = which('NLLoc', parameter)
|
exe_path = os.path.join(parameter['nllocbin'], 'NLLoc')
|
||||||
if exe_path is None:
|
if not os.path.isfile(exe_path):
|
||||||
raise NLLocError('NonLinLoc executable not found; check your '
|
raise NLLocError('NonLinLoc executable not found; check your '
|
||||||
'environment variables')
|
'environment variables')
|
||||||
|
|
||||||
|
|||||||
+47
-38
@@ -20,9 +20,9 @@ from pylot.core.pick.charfuns import CharacteristicFunction
|
|||||||
from pylot.core.pick.charfuns import HOScf, AICcf, ARZcf, ARHcf, AR3Ccf
|
from pylot.core.pick.charfuns import HOScf, AICcf, ARZcf, ARHcf, AR3Ccf
|
||||||
from pylot.core.pick.picker import AICPicker, PragPicker
|
from pylot.core.pick.picker import AICPicker, PragPicker
|
||||||
from pylot.core.pick.utils import checksignallength, checkZ4S, earllatepicker, \
|
from pylot.core.pick.utils import checksignallength, checkZ4S, earllatepicker, \
|
||||||
getSNR, fmpicker, checkPonsets, wadaticheck, get_quality_class
|
getSNR, fmpicker, checkPonsets, wadaticheck, get_quality_class, PickingFailedException, MissingTraceException
|
||||||
from pylot.core.util.utils import getPatternLine, gen_Pool, \
|
from pylot.core.util.utils import getPatternLine, gen_Pool, \
|
||||||
get_Bool, identifyPhaseID, get_None, correct_iplot
|
get_bool, identifyPhaseID, get_none, correct_iplot
|
||||||
|
|
||||||
|
|
||||||
def autopickevent(data, param, iplot=0, fig_dict=None, fig_dict_wadatijack=None, ncores=0, metadata=None, origin=None):
|
def autopickevent(data, param, iplot=0, fig_dict=None, fig_dict_wadatijack=None, ncores=0, metadata=None, origin=None):
|
||||||
@@ -232,20 +232,6 @@ class PickingContainer:
|
|||||||
self.Sflag = 0
|
self.Sflag = 0
|
||||||
|
|
||||||
|
|
||||||
class MissingTraceException(ValueError):
|
|
||||||
"""
|
|
||||||
Used to indicate missing traces in a obspy.core.stream.Stream object
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PickingFailedException(Exception):
|
|
||||||
"""
|
|
||||||
Raised when picking fails due to missing values etc.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class AutopickStation(object):
|
class AutopickStation(object):
|
||||||
|
|
||||||
def __init__(self, wfstream, pickparam, verbose, iplot=0, fig_dict=None, metadata=None, origin=None):
|
def __init__(self, wfstream, pickparam, verbose, iplot=0, fig_dict=None, metadata=None, origin=None):
|
||||||
@@ -272,7 +258,7 @@ class AutopickStation(object):
|
|||||||
self.pickparams = copy.deepcopy(pickparam)
|
self.pickparams = copy.deepcopy(pickparam)
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
self.iplot = correct_iplot(iplot)
|
self.iplot = correct_iplot(iplot)
|
||||||
self.fig_dict = get_None(fig_dict)
|
self.fig_dict = get_none(fig_dict)
|
||||||
self.metadata = metadata
|
self.metadata = metadata
|
||||||
self.origin = origin
|
self.origin = origin
|
||||||
|
|
||||||
@@ -429,7 +415,7 @@ class AutopickStation(object):
|
|||||||
if station_coords is None:
|
if station_coords is None:
|
||||||
exit_taupy()
|
exit_taupy()
|
||||||
raise AttributeError('Warning: Could not find station in metadata')
|
raise AttributeError('Warning: Could not find station in metadata')
|
||||||
# TODO raise when metadata.get_coordinates returns None
|
# TODO: raise when metadata.get_coordinates returns None
|
||||||
source_origin = origin[0]
|
source_origin = origin[0]
|
||||||
model = TauPyModel(taup_model)
|
model = TauPyModel(taup_model)
|
||||||
taup_phases = self.pickparams['taup_phases']
|
taup_phases = self.pickparams['taup_phases']
|
||||||
@@ -471,11 +457,13 @@ class AutopickStation(object):
|
|||||||
"""If taupy failed to calculate theoretical starttimes, picking continues.
|
"""If taupy failed to calculate theoretical starttimes, picking continues.
|
||||||
For this a clean exit is required, since the P starttime is no longer relative to the theoretic onset but
|
For this a clean exit is required, since the P starttime is no longer relative to the theoretic onset but
|
||||||
to the vertical trace starttime, eg. it can't be < 0."""
|
to the vertical trace starttime, eg. it can't be < 0."""
|
||||||
if self.pickparams["pstart"] < 0:
|
|
||||||
# TODO here the pickparams is modified, instead of a copy
|
# TODO here the pickparams is modified, instead of a copy
|
||||||
|
if self.pickparams["pstart"] < 0:
|
||||||
self.pickparams["pstart"] = 0
|
self.pickparams["pstart"] = 0
|
||||||
|
if self.pickparams["sstart"] < 0:
|
||||||
|
self.pickparams["sstart"] = 0
|
||||||
|
|
||||||
if self.pickparams["use_taup"] is False:
|
if get_bool(self.pickparams["use_taup"]) is False:
|
||||||
# correct user mistake where a relative cuttime is selected (pstart < 0) but use of taupy is disabled/ has
|
# correct user mistake where a relative cuttime is selected (pstart < 0) but use of taupy is disabled/ has
|
||||||
# not the required parameters
|
# not the required parameters
|
||||||
exit_taupy()
|
exit_taupy()
|
||||||
@@ -499,6 +487,20 @@ class AutopickStation(object):
|
|||||||
self.pickparams["pstart"] = max(self.pickparams["pstart"], 0)
|
self.pickparams["pstart"] = max(self.pickparams["pstart"], 0)
|
||||||
self.pickparams["pstop"] = min(self.pickparams["pstop"], len(self.ztrace) * self.ztrace.stats.delta)
|
self.pickparams["pstop"] = min(self.pickparams["pstop"], len(self.ztrace) * self.ztrace.stats.delta)
|
||||||
|
|
||||||
|
if self.horizontal_traces_exist():
|
||||||
|
# for the two horizontal components take earliest and latest time to make sure that the s onset is not clipped
|
||||||
|
# if start and endtime of horizontal traces differ, the s windowsize will automatically increase
|
||||||
|
trace_s_start = min([self.etrace.stats.starttime, self.ntrace.stats.starttime])
|
||||||
|
# modifiy sstart and sstop relative to estimated first S arrival (relative to station time axis)
|
||||||
|
self.pickparams["sstart"] += (self.origin[0].time + estFirstS) - trace_s_start
|
||||||
|
self.pickparams["sstop"] += (self.origin[0].time + estFirstS) - trace_s_start
|
||||||
|
print('autopick: CF calculation times respectively:'
|
||||||
|
' sstart: {} s, sstop: {} s'.format(self.pickparams["sstart"], self.pickparams["sstop"]))
|
||||||
|
# make sure pstart and pstop are inside the starttime/endtime of horizontal traces
|
||||||
|
self.pickparams["sstart"] = max(self.pickparams["sstart"], 0)
|
||||||
|
self.pickparams["sstop"] = min(self.pickparams["sstop"], len(self.ntrace) * self.ntrace.stats.delta,
|
||||||
|
len(self.etrace) * self.etrace.stats.delta)
|
||||||
|
|
||||||
def autopickstation(self):
|
def autopickstation(self):
|
||||||
"""
|
"""
|
||||||
Main function of autopickstation, which calculates P and S picks and returns them in a dictionary.
|
Main function of autopickstation, which calculates P and S picks and returns them in a dictionary.
|
||||||
@@ -508,6 +510,17 @@ class AutopickStation(object):
|
|||||||
station's value is the station name on which the picks were calculated.
|
station's value is the station name on which the picks were calculated.
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if get_bool(self.pickparams['use_taup']) is True and self.origin is not None:
|
||||||
|
try:
|
||||||
|
# modify pstart, pstop, sstart, sstop to be around theoretical onset if taupy should be used,
|
||||||
|
# else do nothing
|
||||||
|
self.modify_starttimes_taupy()
|
||||||
|
except AttributeError as ae:
|
||||||
|
print(ae)
|
||||||
|
except MissingTraceException as mte:
|
||||||
|
print(mte)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.pick_p_phase()
|
self.pick_p_phase()
|
||||||
except MissingTraceException as mte:
|
except MissingTraceException as mte:
|
||||||
@@ -515,7 +528,9 @@ class AutopickStation(object):
|
|||||||
except PickingFailedException as pfe:
|
except PickingFailedException as pfe:
|
||||||
print(pfe)
|
print(pfe)
|
||||||
|
|
||||||
if self.horizontal_traces_exist() and self.p_results.weight is not None and self.p_results.weight < 4:
|
if self.horizontal_traces_exist():
|
||||||
|
if (self.p_results.weight is not None and self.p_results.weight < 4) or \
|
||||||
|
get_bool(self.pickparams.get('use_taup')):
|
||||||
try:
|
try:
|
||||||
self.pick_s_phase()
|
self.pick_s_phase()
|
||||||
except MissingTraceException as mte:
|
except MissingTraceException as mte:
|
||||||
@@ -631,7 +646,7 @@ class AutopickStation(object):
|
|||||||
ax1.set_ylim([-1.5, 1.5])
|
ax1.set_ylim([-1.5, 1.5])
|
||||||
ax1.set_ylabel('Normalized Counts')
|
ax1.set_ylabel('Normalized Counts')
|
||||||
|
|
||||||
if self.horizontal_traces_exist() and self.s_data.Sflag == 1:
|
if self.horizontal_traces_exist():# and self.s_data.Sflag == 1:
|
||||||
# plot E trace
|
# plot E trace
|
||||||
ax2 = fig.add_subplot(3, 1, 2, sharex=ax1)
|
ax2 = fig.add_subplot(3, 1, 2, sharex=ax1)
|
||||||
th1data = np.linspace(0, self.etrace.stats.endtime - self.etrace.stats.starttime,
|
th1data = np.linspace(0, self.etrace.stats.endtime - self.etrace.stats.starttime,
|
||||||
@@ -661,13 +676,14 @@ class AutopickStation(object):
|
|||||||
ax2.plot([self.s_results.lpp, self.s_results.lpp], [-1.1, 1.1], 'g--', label='lpp')
|
ax2.plot([self.s_results.lpp, self.s_results.lpp], [-1.1, 1.1], 'g--', label='lpp')
|
||||||
ax2.plot([self.s_results.epp, self.s_results.epp], [-1.1, 1.1], 'g--', label='epp')
|
ax2.plot([self.s_results.epp, self.s_results.epp], [-1.1, 1.1], 'g--', label='epp')
|
||||||
title = '{channel}, S weight={sweight}, SNR={snr:7.2}, SNR[dB]={snrdb:7.2}'
|
title = '{channel}, S weight={sweight}, SNR={snr:7.2}, SNR[dB]={snrdb:7.2}'
|
||||||
ax2.set_title(title.format(channel=self.etrace.stats.channel,
|
ax2.set_title(title.format(channel=str(self.etrace.stats.channel),
|
||||||
sweight=self.s_results.weight,
|
sweight=str(self.s_results.weight),
|
||||||
snr=self.s_results.snr,
|
snr=str(self.s_results.snr),
|
||||||
snrdb=self.s_results.snrdb))
|
snrdb=str(self.s_results.snrdb)))
|
||||||
else:
|
else:
|
||||||
title = '{channel}, S weight={sweight}, SNR=None, SNR[dB]=None'
|
title = '{channel}, S weight={sweight}, SNR=None, SNR[dB]=None'
|
||||||
ax2.set_title(title.format(channel=self.etrace.stats.channel, sweight=self.s_results.weight))
|
ax2.set_title(title.format(channel=str(self.etrace.stats.channel),
|
||||||
|
sweight=str(self.s_results.weight)))
|
||||||
ax2.legend(loc=1)
|
ax2.legend(loc=1)
|
||||||
ax2.set_yticks([])
|
ax2.set_yticks([])
|
||||||
ax2.set_ylim([-1.5, 1.5])
|
ax2.set_ylim([-1.5, 1.5])
|
||||||
@@ -795,15 +811,6 @@ class AutopickStation(object):
|
|||||||
# save filtered trace in instance for later plotting
|
# save filtered trace in instance for later plotting
|
||||||
self.tr_filt_z_bpz2 = tr_filt
|
self.tr_filt_z_bpz2 = tr_filt
|
||||||
|
|
||||||
if get_Bool(self.pickparams['use_taup']) is True and self.origin is not None:
|
|
||||||
try:
|
|
||||||
# modify pstart, pstop to be around theoretical onset if taupy should be used, else does nothing
|
|
||||||
self.modify_starttimes_taupy()
|
|
||||||
except AttributeError as ae:
|
|
||||||
print(ae)
|
|
||||||
except MissingTraceException as mte:
|
|
||||||
print(mte)
|
|
||||||
|
|
||||||
Lc = self.pickparams['pstop'] - self.pickparams['pstart']
|
Lc = self.pickparams['pstop'] - self.pickparams['pstart']
|
||||||
|
|
||||||
Lwf = self.ztrace.stats.endtime - self.ztrace.stats.starttime
|
Lwf = self.ztrace.stats.endtime - self.ztrace.stats.starttime
|
||||||
@@ -915,7 +922,7 @@ class AutopickStation(object):
|
|||||||
"minFMSNR"]:
|
"minFMSNR"]:
|
||||||
# if SNR is high enough, try to determine first motion of onset
|
# if SNR is high enough, try to determine first motion of onset
|
||||||
self.set_current_figure('fm_picker')
|
self.set_current_figure('fm_picker')
|
||||||
self.p_results.fm = fmpicker(self.zstream, z_copy, self.pickparams["fmpickwin"], self.p_results.mpp,
|
self.p_results.fm = fmpicker(self.zstream.copy(), z_copy, self.pickparams["fmpickwin"], self.p_results.mpp,
|
||||||
self.iplot, self.current_figure, self.current_linecolor)
|
self.iplot, self.current_figure, self.current_linecolor)
|
||||||
msg = "autopickstation: P-weight: {}, SNR: {}, SNR[dB]: {}, Polarity: {}"
|
msg = "autopickstation: P-weight: {}, SNR: {}, SNR[dB]: {}, Polarity: {}"
|
||||||
msg = msg.format(self.p_results.weight, self.p_results.snr, self.p_results.snrdb, self.p_results.fm)
|
msg = msg.format(self.p_results.weight, self.p_results.snr, self.p_results.snrdb, self.p_results.fm)
|
||||||
@@ -1127,7 +1134,9 @@ class AutopickStation(object):
|
|||||||
''.format(self.s_results.weight, self.s_results.snr, self.s_results.snrdb))
|
''.format(self.s_results.weight, self.s_results.snr, self.s_results.snrdb))
|
||||||
|
|
||||||
def pick_s_phase(self):
|
def pick_s_phase(self):
|
||||||
|
if get_bool(self.pickparams.get('use_taup')) is True:
|
||||||
|
cuttimesh = (self.pickparams.get('sstart'), self.pickparams.get('sstop'))
|
||||||
|
else:
|
||||||
# determine time window for calculating CF after P onset
|
# determine time window for calculating CF after P onset
|
||||||
cuttimesh = self._calculate_cuttimes(type='S', iteration=1)
|
cuttimesh = self._calculate_cuttimes(type='S', iteration=1)
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,11 @@ autoregressive prediction: application ot local and regional distances, Geophys.
|
|||||||
|
|
||||||
:author: MAGS2 EP3 working group
|
:author: MAGS2 EP3 working group
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from obspy.core import Stream
|
|
||||||
from scipy import signal
|
from scipy import signal
|
||||||
|
from obspy.core import Stream
|
||||||
|
|
||||||
|
from pylot.core.pick.utils import PickingFailedException
|
||||||
|
|
||||||
|
|
||||||
class CharacteristicFunction(object):
|
class CharacteristicFunction(object):
|
||||||
@@ -259,7 +260,7 @@ class HOScf(CharacteristicFunction):
|
|||||||
"""
|
"""
|
||||||
Function to calculate skewness (statistics of order 3) or kurtosis
|
Function to calculate skewness (statistics of order 3) or kurtosis
|
||||||
(statistics of order 4), using one long moving window, as published
|
(statistics of order 4), using one long moving window, as published
|
||||||
in Kueperkoch et al. (2010).
|
in Kueperkoch et al. (2010), or order 2, i.e. STA/LTA.
|
||||||
:param data: data, time series (whether seismogram or CF)
|
:param data: data, time series (whether seismogram or CF)
|
||||||
:type data: tuple
|
:type data: tuple
|
||||||
:return: HOS cf
|
:return: HOS cf
|
||||||
@@ -276,28 +277,47 @@ class HOScf(CharacteristicFunction):
|
|||||||
elif self.getOrder() == 4: # this is kurtosis
|
elif self.getOrder() == 4: # this is kurtosis
|
||||||
y = np.power(xnp, 4)
|
y = np.power(xnp, 4)
|
||||||
y1 = np.power(xnp, 2)
|
y1 = np.power(xnp, 2)
|
||||||
|
elif self.getOrder() == 2: # this is variance, used for STA/LTA processing
|
||||||
|
y = np.power(xnp, 2)
|
||||||
|
y1 = np.power(xnp, 2)
|
||||||
|
|
||||||
# Initialisation
|
# Initialisation
|
||||||
# t2: long term moving window
|
# t2: long term moving window
|
||||||
ilta = int(round(self.getTime2() / self.getIncrement()))
|
ilta = int(round(self.getTime2() / self.getIncrement()))
|
||||||
|
ista = int(round((self.getTime2() / 10) / self.getIncrement())) # TODO: still hard coded!!
|
||||||
lta = y[0]
|
lta = y[0]
|
||||||
lta1 = y1[0]
|
lta1 = y1[0]
|
||||||
|
sta = y[0]
|
||||||
# moving windows
|
# moving windows
|
||||||
LTA = np.zeros(len(xnp))
|
LTA = np.zeros(len(xnp))
|
||||||
|
STA = np.zeros(len(xnp))
|
||||||
for j in range(0, len(xnp)):
|
for j in range(0, len(xnp)):
|
||||||
if j < 4:
|
if j < 4:
|
||||||
LTA[j] = 0
|
LTA[j] = 0
|
||||||
|
STA[j] = 0
|
||||||
|
elif j <= ista and self.getOrder() == 2:
|
||||||
|
lta = (y[j] + lta * (j - 1)) / j
|
||||||
|
if self.getOrder() == 2:
|
||||||
|
sta = (y[j] + sta * (j - 1)) / j
|
||||||
|
# elif j < 4:
|
||||||
elif j <= ilta:
|
elif j <= ilta:
|
||||||
lta = (y[j] + lta * (j - 1)) / j
|
lta = (y[j] + lta * (j - 1)) / j
|
||||||
lta1 = (y1[j] + lta1 * (j - 1)) / j
|
lta1 = (y1[j] + lta1 * (j - 1)) / j
|
||||||
|
if self.getOrder() == 2:
|
||||||
|
sta = (y[j] - y[j - ista]) / ista + sta
|
||||||
else:
|
else:
|
||||||
lta = (y[j] - y[j - ilta]) / ilta + lta
|
lta = (y[j] - y[j - ilta]) / ilta + lta
|
||||||
lta1 = (y1[j] - y1[j - ilta]) / ilta + lta1
|
lta1 = (y1[j] - y1[j - ilta]) / ilta + lta1
|
||||||
|
if self.getOrder() == 2:
|
||||||
|
sta = (y[j] - y[j - ista]) / ista + sta
|
||||||
# define LTA
|
# define LTA
|
||||||
if self.getOrder() == 3:
|
if self.getOrder() == 3:
|
||||||
LTA[j] = lta / np.power(lta1, 1.5)
|
LTA[j] = lta / np.power(lta1, 1.5)
|
||||||
elif self.getOrder() == 4:
|
elif self.getOrder() == 4:
|
||||||
LTA[j] = lta / np.power(lta1, 2)
|
LTA[j] = lta / np.power(lta1, 2)
|
||||||
|
else:
|
||||||
|
LTA[j] = lta
|
||||||
|
STA[j] = sta
|
||||||
|
|
||||||
# remove NaN's with first not-NaN-value,
|
# remove NaN's with first not-NaN-value,
|
||||||
# so autopicker doesnt pick discontinuity at start of the trace
|
# so autopicker doesnt pick discontinuity at start of the trace
|
||||||
@@ -306,7 +326,10 @@ class HOScf(CharacteristicFunction):
|
|||||||
first = ind[0]
|
first = ind[0]
|
||||||
LTA[:first] = LTA[first]
|
LTA[:first] = LTA[first]
|
||||||
|
|
||||||
|
if self.getOrder() > 2:
|
||||||
self.cf = LTA
|
self.cf = LTA
|
||||||
|
else: # order 2 means STA/LTA!
|
||||||
|
self.cf = STA / LTA
|
||||||
self.xcf = x
|
self.xcf = x
|
||||||
|
|
||||||
|
|
||||||
@@ -467,6 +490,9 @@ class ARHcf(CharacteristicFunction):
|
|||||||
print('Calculating AR-prediction error from both horizontal traces ...')
|
print('Calculating AR-prediction error from both horizontal traces ...')
|
||||||
|
|
||||||
xnp = self.getDataArray(self.getCut())
|
xnp = self.getDataArray(self.getCut())
|
||||||
|
if len(xnp[0]) == 0:
|
||||||
|
raise PickingFailedException('calcCF: Found empty data trace for cut times. Return')
|
||||||
|
|
||||||
n0 = np.isnan(xnp[0].data)
|
n0 = np.isnan(xnp[0].data)
|
||||||
if len(n0) > 1:
|
if len(n0) > 1:
|
||||||
xnp[0].data[n0] = 0
|
xnp[0].data[n0] = 0
|
||||||
|
|||||||
@@ -178,7 +178,9 @@ class AICPicker(AutoPicker):
|
|||||||
aic = tap * self.cf + max(abs(self.cf))
|
aic = tap * self.cf + max(abs(self.cf))
|
||||||
# smooth AIC-CF
|
# smooth AIC-CF
|
||||||
ismooth = int(round(self.Tsmooth / self.dt))
|
ismooth = int(round(self.Tsmooth / self.dt))
|
||||||
aicsmooth = np.zeros(len(aic))
|
# MP MP better start with original data than zeros if array shall be smoothed, created artificial value before
|
||||||
|
# when starting with i in range(1...) loop below and subtracting offset afterwards
|
||||||
|
aicsmooth = np.copy(aic)
|
||||||
if len(aic) < ismooth:
|
if len(aic) < ismooth:
|
||||||
print('AICPicker: Tsmooth larger than CF!')
|
print('AICPicker: Tsmooth larger than CF!')
|
||||||
return
|
return
|
||||||
@@ -188,7 +190,7 @@ class AICPicker(AutoPicker):
|
|||||||
ii1 = i - ismooth
|
ii1 = i - ismooth
|
||||||
aicsmooth[i] = aicsmooth[i - 1] + (aic[i] - aic[ii1]) / ismooth
|
aicsmooth[i] = aicsmooth[i - 1] + (aic[i] - aic[ii1]) / ismooth
|
||||||
else:
|
else:
|
||||||
aicsmooth[i] = np.mean(aic[1: i])
|
aicsmooth[i] = np.mean(aic[0: i]) # MP MP created np.nan for i=1
|
||||||
# remove offset in AIC function
|
# remove offset in AIC function
|
||||||
offset = abs(min(aic) - min(aicsmooth))
|
offset = abs(min(aic) - min(aicsmooth))
|
||||||
aicsmooth = aicsmooth - offset
|
aicsmooth = aicsmooth - offset
|
||||||
@@ -197,7 +199,7 @@ class AICPicker(AutoPicker):
|
|||||||
# minimum in AIC function
|
# minimum in AIC function
|
||||||
icfmax = np.argmax(cf)
|
icfmax = np.argmax(cf)
|
||||||
|
|
||||||
# MP MP testing threshold
|
# TODO: If this shall be kept, maybe add thresh_factor to pylot parameters
|
||||||
thresh_hit = False
|
thresh_hit = False
|
||||||
thresh_factor = 0.7
|
thresh_factor = 0.7
|
||||||
thresh = thresh_factor * cf[icfmax]
|
thresh = thresh_factor * cf[icfmax]
|
||||||
@@ -209,7 +211,6 @@ class AICPicker(AutoPicker):
|
|||||||
if sample <= cf[index - 1]:
|
if sample <= cf[index - 1]:
|
||||||
icfmax = index - 1
|
icfmax = index - 1
|
||||||
break
|
break
|
||||||
# MP MP ---
|
|
||||||
|
|
||||||
# find minimum in AIC-CF front of maximum of HOS/AR-CF
|
# find minimum in AIC-CF front of maximum of HOS/AR-CF
|
||||||
lpickwindow = int(round(self.PickWindow / self.dt))
|
lpickwindow = int(round(self.PickWindow / self.dt))
|
||||||
@@ -336,7 +337,7 @@ class AICPicker(AutoPicker):
|
|||||||
self.slope = 1 / (len(dataslope) * self.Data[0].stats.delta) * (datafit[-1] - datafit[0])
|
self.slope = 1 / (len(dataslope) * self.Data[0].stats.delta) * (datafit[-1] - datafit[0])
|
||||||
# normalize slope to maximum of cf to make it unit independent
|
# normalize slope to maximum of cf to make it unit independent
|
||||||
self.slope /= aicsmooth[iaicmax]
|
self.slope /= aicsmooth[iaicmax]
|
||||||
except ValueError as e:
|
except Exception as e:
|
||||||
print("AICPicker: Problems with data fitting! {}".format(e))
|
print("AICPicker: Problems with data fitting! {}".format(e))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|||||||
+29
-29
@@ -15,7 +15,7 @@ import numpy as np
|
|||||||
from obspy.core import Stream, UTCDateTime
|
from obspy.core import Stream, UTCDateTime
|
||||||
from scipy.signal import argrelmax
|
from scipy.signal import argrelmax
|
||||||
|
|
||||||
from pylot.core.util.utils import get_Bool, get_None, SetChannelComponents
|
from pylot.core.util.utils import get_bool, get_none, SetChannelComponents
|
||||||
|
|
||||||
|
|
||||||
def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecolor='k'):
|
def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecolor='k'):
|
||||||
@@ -62,8 +62,8 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecol
|
|||||||
plt_flag = 0
|
plt_flag = 0
|
||||||
try:
|
try:
|
||||||
iplot = int(iplot)
|
iplot = int(iplot)
|
||||||
except:
|
except ValueError:
|
||||||
if get_Bool(iplot):
|
if get_bool(iplot):
|
||||||
iplot = 2
|
iplot = 2
|
||||||
else:
|
else:
|
||||||
iplot = 0
|
iplot = 0
|
||||||
@@ -136,7 +136,7 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecol
|
|||||||
PickError = symmetrize_error(diffti_te, diffti_tl)
|
PickError = symmetrize_error(diffti_te, diffti_tl)
|
||||||
|
|
||||||
if iplot > 1:
|
if iplot > 1:
|
||||||
if get_None(fig) is None:
|
if get_none(fig) is None:
|
||||||
fig = plt.figure() # iplot)
|
fig = plt.figure() # iplot)
|
||||||
plt_flag = 1
|
plt_flag = 1
|
||||||
fig._tight = True
|
fig._tight = True
|
||||||
@@ -344,7 +344,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None, linecolor='k'):
|
|||||||
print("fmpicker: Found polarity %s" % FM)
|
print("fmpicker: Found polarity %s" % FM)
|
||||||
|
|
||||||
if iplot > 1:
|
if iplot > 1:
|
||||||
if get_None(fig) is None:
|
if get_none(fig) is None:
|
||||||
fig = plt.figure() # iplot)
|
fig = plt.figure() # iplot)
|
||||||
plt_flag = 1
|
plt_flag = 1
|
||||||
fig._tight = True
|
fig._tight = True
|
||||||
@@ -816,7 +816,7 @@ def checksignallength(X, pick, minsiglength, pickparams, iplot=0, fig=None, line
|
|||||||
try:
|
try:
|
||||||
iplot = int(iplot)
|
iplot = int(iplot)
|
||||||
except:
|
except:
|
||||||
if get_Bool(iplot):
|
if get_bool(iplot):
|
||||||
iplot = 2
|
iplot = 2
|
||||||
else:
|
else:
|
||||||
iplot = 0
|
iplot = 0
|
||||||
@@ -868,7 +868,7 @@ def checksignallength(X, pick, minsiglength, pickparams, iplot=0, fig=None, line
|
|||||||
returnflag = 0
|
returnflag = 0
|
||||||
|
|
||||||
if iplot > 1:
|
if iplot > 1:
|
||||||
if get_None(fig) is None:
|
if get_none(fig) is None:
|
||||||
fig = plt.figure() # iplot)
|
fig = plt.figure() # iplot)
|
||||||
plt_flag = 1
|
plt_flag = 1
|
||||||
fig._tight = True
|
fig._tight = True
|
||||||
@@ -890,6 +890,8 @@ def checksignallength(X, pick, minsiglength, pickparams, iplot=0, fig=None, line
|
|||||||
input()
|
input()
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
pass
|
pass
|
||||||
|
except EOFError:
|
||||||
|
pass
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
|
|
||||||
return returnflag
|
return returnflag
|
||||||
@@ -1130,7 +1132,7 @@ def checkZ4S(X, pick, pickparams, iplot, fig=None, linecolor='k'):
|
|||||||
try:
|
try:
|
||||||
iplot = int(iplot)
|
iplot = int(iplot)
|
||||||
except:
|
except:
|
||||||
if get_Bool(iplot):
|
if get_bool(iplot):
|
||||||
iplot = 2
|
iplot = 2
|
||||||
else:
|
else:
|
||||||
iplot = 0
|
iplot = 0
|
||||||
@@ -1211,14 +1213,14 @@ def checkZ4S(X, pick, pickparams, iplot, fig=None, linecolor='k'):
|
|||||||
t = np.linspace(diff_dict[key], trace.stats.endtime - trace.stats.starttime + diff_dict[key],
|
t = np.linspace(diff_dict[key], trace.stats.endtime - trace.stats.starttime + diff_dict[key],
|
||||||
trace.stats.npts)
|
trace.stats.npts)
|
||||||
if i == 0:
|
if i == 0:
|
||||||
if get_None(fig) is None:
|
if get_none(fig) is None:
|
||||||
fig = plt.figure() # self.iplot) ### WHY? MP MP
|
fig = plt.figure() # self.iplot) ### WHY? MP MP
|
||||||
plt_flag = 1
|
plt_flag = 1
|
||||||
ax1 = fig.add_subplot(3, 1, i + 1)
|
ax1 = fig.add_subplot(3, 1, i + 1)
|
||||||
ax = ax1
|
ax = ax1
|
||||||
ax.set_title('CheckZ4S, Station %s' % zdat[0].stats.station)
|
ax.set_title('CheckZ4S, Station %s' % zdat[0].stats.station)
|
||||||
else:
|
else:
|
||||||
if get_None(fig) is None:
|
if get_none(fig) is None:
|
||||||
fig = plt.figure() # self.iplot) ### WHY? MP MP
|
fig = plt.figure() # self.iplot) ### WHY? MP MP
|
||||||
plt_flag = 1
|
plt_flag = 1
|
||||||
ax = fig.add_subplot(3, 1, i + 1, sharex=ax1)
|
ax = fig.add_subplot(3, 1, i + 1, sharex=ax1)
|
||||||
@@ -1320,7 +1322,7 @@ def get_quality_class(uncertainty, weight_classes):
|
|||||||
:return: quality of pick (0-4)
|
:return: quality of pick (0-4)
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
if not uncertainty: return max(weight_classes)
|
if not uncertainty: return len(weight_classes)
|
||||||
try:
|
try:
|
||||||
# create generator expression containing all indices of values in weight classes that are >= than uncertainty.
|
# create generator expression containing all indices of values in weight classes that are >= than uncertainty.
|
||||||
# call next on it once to receive first value
|
# call next on it once to receive first value
|
||||||
@@ -1332,22 +1334,6 @@ def get_quality_class(uncertainty, weight_classes):
|
|||||||
return quality
|
return quality
|
||||||
|
|
||||||
|
|
||||||
def set_NaNs_to(data, nan_value):
|
|
||||||
"""
|
|
||||||
Replace all NaNs in data with nan_value
|
|
||||||
:param data: array holding data
|
|
||||||
:type data: `~numpy.ndarray`
|
|
||||||
:param nan_value: value which all NaNs are set to
|
|
||||||
:type nan_value: float, int
|
|
||||||
:return: data array with all NaNs replaced with nan_value
|
|
||||||
:rtype: `~numpy.ndarray`
|
|
||||||
"""
|
|
||||||
nn = np.isnan(data)
|
|
||||||
if np.any(nn):
|
|
||||||
data[nn] = nan_value
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def taper_cf(cf):
|
def taper_cf(cf):
|
||||||
"""
|
"""
|
||||||
Taper cf data to get rid off of side maximas
|
Taper cf data to get rid off of side maximas
|
||||||
@@ -1499,7 +1485,7 @@ def get_pickparams(pickparam):
|
|||||||
first_motion_params = dict(zip(first_motion_names, fm_parameter_values))
|
first_motion_params = dict(zip(first_motion_names, fm_parameter_values))
|
||||||
signal_length_params = dict(zip(signal_length_names, sl_parameter_values))
|
signal_length_params = dict(zip(signal_length_names, sl_parameter_values))
|
||||||
|
|
||||||
p_params['use_taup'] = get_Bool(p_params['use_taup'])
|
p_params['use_taup'] = get_bool(p_params['use_taup'])
|
||||||
|
|
||||||
return p_params, s_params, first_motion_params, signal_length_params
|
return p_params, s_params, first_motion_params, signal_length_params
|
||||||
|
|
||||||
@@ -1508,7 +1494,7 @@ def getQualityFromUncertainty(uncertainty, Errors):
|
|||||||
# set initial quality to 4 (worst) and change only if one condition is hit
|
# set initial quality to 4 (worst) and change only if one condition is hit
|
||||||
quality = 4
|
quality = 4
|
||||||
|
|
||||||
if get_None(uncertainty) is None:
|
if get_none(uncertainty) is None:
|
||||||
return quality
|
return quality
|
||||||
|
|
||||||
if uncertainty <= Errors[0]:
|
if uncertainty <= Errors[0]:
|
||||||
@@ -1532,3 +1518,17 @@ if __name__ == '__main__':
|
|||||||
import doctest
|
import doctest
|
||||||
|
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
|
||||||
|
|
||||||
|
class PickingFailedException(Exception):
|
||||||
|
"""
|
||||||
|
Raised when picking fails due to missing values etc.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MissingTraceException(ValueError):
|
||||||
|
"""
|
||||||
|
Used to indicate missing traces in a obspy.core.stream.Stream object
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import obspy
|
|||||||
from PySide2 import QtWidgets
|
from PySide2 import QtWidgets
|
||||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||||
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
||||||
|
from pylot.core.util.utils import identifyPhaseID
|
||||||
from scipy.interpolate import griddata
|
from scipy.interpolate import griddata
|
||||||
|
|
||||||
from pylot.core.pick.utils import get_quality_class
|
from pylot.core.pick.utils import get_quality_class
|
||||||
@@ -75,7 +76,6 @@ class Array_map(QtWidgets.QWidget):
|
|||||||
|
|
||||||
self._style = None if not hasattr(parent, '_style') else parent._style
|
self._style = None if not hasattr(parent, '_style') else parent._style
|
||||||
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
def init_map(self):
|
def init_map(self):
|
||||||
self.init_colormap()
|
self.init_colormap()
|
||||||
@@ -124,8 +124,8 @@ class Array_map(QtWidgets.QWidget):
|
|||||||
self.cmaps_box = QtWidgets.QComboBox()
|
self.cmaps_box = QtWidgets.QComboBox()
|
||||||
self.cmaps_box.setMaxVisibleItems(20)
|
self.cmaps_box.setMaxVisibleItems(20)
|
||||||
[self.cmaps_box.addItem(map_name) for map_name in sorted(plt.colormaps())]
|
[self.cmaps_box.addItem(map_name) for map_name in sorted(plt.colormaps())]
|
||||||
# try to set to hsv as default
|
# try to set to viridis as default
|
||||||
self.cmaps_box.setCurrentIndex(self.cmaps_box.findText('hsv'))
|
self.cmaps_box.setCurrentIndex(self.cmaps_box.findText('viridis'))
|
||||||
|
|
||||||
self.top_row.addWidget(QtWidgets.QLabel('Select a phase: '))
|
self.top_row.addWidget(QtWidgets.QLabel('Select a phase: '))
|
||||||
self.top_row.addWidget(self.comboBox_phase)
|
self.top_row.addWidget(self.comboBox_phase)
|
||||||
@@ -280,9 +280,12 @@ class Array_map(QtWidgets.QWidget):
|
|||||||
self.canvas.axes.figure.canvas.draw_idle()
|
self.canvas.axes.figure.canvas.draw_idle()
|
||||||
|
|
||||||
def onpick(self, event):
|
def onpick(self, event):
|
||||||
|
btn_msg = {1: ' in selection. Aborted', 2: ' to delete a pick on. Aborted', 3: ' to display info.'}
|
||||||
ind = event.ind
|
ind = event.ind
|
||||||
button = event.mouseevent.button
|
button = event.mouseevent.button
|
||||||
if ind == []:
|
msg_reason = None
|
||||||
|
if len(ind) > 1:
|
||||||
|
self._parent.update_status(f'Found more than one station {btn_msg.get(button)}')
|
||||||
return
|
return
|
||||||
if button == 1:
|
if button == 1:
|
||||||
self.openPickDlg(ind)
|
self.openPickDlg(ind)
|
||||||
@@ -385,7 +388,14 @@ class Array_map(QtWidgets.QWidget):
|
|||||||
try:
|
try:
|
||||||
station_name = st_id.split('.')[-1]
|
station_name = st_id.split('.')[-1]
|
||||||
# current_picks_dict: auto or manual
|
# current_picks_dict: auto or manual
|
||||||
pick = self.current_picks_dict()[station_name][phase]
|
station_picks = self.current_picks_dict().get(station_name)
|
||||||
|
if not station_picks:
|
||||||
|
continue
|
||||||
|
for phase_hint, pick in station_picks.items():
|
||||||
|
if identifyPhaseID(phase_hint) == phase:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
continue
|
||||||
if pick['picker'] == 'auto':
|
if pick['picker'] == 'auto':
|
||||||
if not pick['spe']:
|
if not pick['spe']:
|
||||||
continue
|
continue
|
||||||
@@ -464,20 +474,23 @@ class Array_map(QtWidgets.QWidget):
|
|||||||
transform=ccrs.PlateCarree(), label='deleted'))
|
transform=ccrs.PlateCarree(), label='deleted'))
|
||||||
|
|
||||||
def openPickDlg(self, ind):
|
def openPickDlg(self, ind):
|
||||||
data = self._parent.get_data().getWFData()
|
wfdata = self._parent.get_data().getWFData()
|
||||||
|
wfdata_comp = self._parent.get_data().getWFDataComp()
|
||||||
for index in ind:
|
for index in ind:
|
||||||
network, station = self._station_onpick_ids[index].split('.')[:2]
|
network, station = self._station_onpick_ids[index].split('.')[:2]
|
||||||
pyl_mw = self._parent
|
pyl_mw = self._parent
|
||||||
try:
|
try:
|
||||||
data = data.select(station=station)
|
wfdata = wfdata.select(station=station)
|
||||||
if not data:
|
wfdata_comp = wfdata_comp.select(station=station)
|
||||||
|
if not wfdata:
|
||||||
self._warn('No data for station {}'.format(station))
|
self._warn('No data for station {}'.format(station))
|
||||||
return
|
return
|
||||||
pickDlg = PickDlg(self._parent, parameter=self.parameter,
|
pickDlg = PickDlg(self._parent, parameter=self.parameter,
|
||||||
data=data, network=network, station=station,
|
data=wfdata.copy(), data_compare=wfdata_comp.copy(), network=network, station=station,
|
||||||
picks=self._parent.get_current_event().getPick(station),
|
picks=self._parent.get_current_event().getPick(station),
|
||||||
autopicks=self._parent.get_current_event().getAutopick(station),
|
autopicks=self._parent.get_current_event().getAutopick(station),
|
||||||
filteroptions=self._parent.filteroptions, metadata=self.metadata,
|
filteroptions=self._parent.filteroptions, metadata=self.metadata,
|
||||||
|
model=self.parameter.get('taup_model'),
|
||||||
event=pyl_mw.get_current_event())
|
event=pyl_mw.get_current_event())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
message = 'Could not generate Plot for station {st}.\n {er}'.format(st=station, er=e)
|
message = 'Could not generate Plot for station {st}.\n {er}'.format(st=station, er=e)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -189,7 +190,11 @@ class Metadata(object):
|
|||||||
metadata = self.get_metadata(seed_id, time)
|
metadata = self.get_metadata(seed_id, time)
|
||||||
if not metadata:
|
if not metadata:
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
return metadata['data'].get_coordinates(seed_id, time)
|
return metadata['data'].get_coordinates(seed_id, time)
|
||||||
|
# no specific exception defined in obspy inventory
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning(f'Could not get metadata for {seed_id}')
|
||||||
|
|
||||||
def get_all_coordinates(self):
|
def get_all_coordinates(self):
|
||||||
def stat_info_from_parser(parser):
|
def stat_info_from_parser(parser):
|
||||||
@@ -271,7 +276,7 @@ class Metadata(object):
|
|||||||
continue
|
continue
|
||||||
invtype, robj = self._read_metadata_file(os.path.join(path_to_inventory, fname))
|
invtype, robj = self._read_metadata_file(os.path.join(path_to_inventory, fname))
|
||||||
try:
|
try:
|
||||||
robj.get_coordinates(station_seed_id)
|
# robj.get_coordinates(station_seed_id) # TODO: Commented out, failed with Parser, is this needed?
|
||||||
self.inventory_files[fname] = {'invtype': invtype,
|
self.inventory_files[fname] = {'invtype': invtype,
|
||||||
'data': robj}
|
'data': robj}
|
||||||
if station_seed_id in self.seed_ids.keys():
|
if station_seed_id in self.seed_ids.keys():
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ elif system_name == "Windows":
|
|||||||
# suffix for phase name if not phase identified by last letter (P, p, etc.)
|
# suffix for phase name if not phase identified by last letter (P, p, etc.)
|
||||||
ALTSUFFIX = ['diff', 'n', 'g', '1', '2', '3']
|
ALTSUFFIX = ['diff', 'n', 'g', '1', '2', '3']
|
||||||
|
|
||||||
FILTERDEFAULTS = readDefaultFilterInformation(os.path.join(os.path.expanduser('~'),
|
FILTERDEFAULTS = readDefaultFilterInformation()
|
||||||
'.pylot',
|
|
||||||
'pylot.in'))
|
|
||||||
|
|
||||||
TIMEERROR_DEFAULTS = os.path.join(os.path.expanduser('~'),
|
TIMEERROR_DEFAULTS = os.path.join(os.path.expanduser('~'),
|
||||||
'.pylot',
|
'.pylot',
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ def main(project_file_path, manual=False, auto=True, file_format='png', f_ext=''
|
|||||||
for item in input_list:
|
for item in input_list:
|
||||||
array_map_worker(item)
|
array_map_worker(item)
|
||||||
else:
|
else:
|
||||||
pool = multiprocessing.Pool(ncores)
|
pool = multiprocessing.Pool(ncores, maxtasksperchild=1000)
|
||||||
pool.map(array_map_worker, input_list)
|
pool.map(array_map_worker, input_list)
|
||||||
pool.close()
|
pool.close()
|
||||||
pool.join()
|
pool.join()
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ def which(program, parameter):
|
|||||||
nllocpath = ":" + parameter.get('nllocbin')
|
nllocpath = ":" + parameter.get('nllocbin')
|
||||||
os.environ['PATH'] += nllocpath
|
os.environ['PATH'] += nllocpath
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e.message)
|
print(e)
|
||||||
|
|
||||||
def is_exe(fpath):
|
def is_exe(fpath):
|
||||||
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
|
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ class Thread(QThread):
|
|||||||
self.abortButton = abortButton
|
self.abortButton = abortButton
|
||||||
self.finished.connect(self.hideProgressbar)
|
self.finished.connect(self.hideProgressbar)
|
||||||
self.showProgressbar()
|
self.showProgressbar()
|
||||||
|
self.old_stdout = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.redirect_stdout:
|
if self.redirect_stdout:
|
||||||
|
self.old_stdout = sys.stdout
|
||||||
sys.stdout = self
|
sys.stdout = self
|
||||||
try:
|
try:
|
||||||
if self.arg is not None:
|
if self.arg is not None:
|
||||||
@@ -39,7 +41,8 @@ class Thread(QThread):
|
|||||||
exctype, value = sys.exc_info()[:2]
|
exctype, value = sys.exc_info()[:2]
|
||||||
self._executedErrorInfo = '{} {} {}'. \
|
self._executedErrorInfo = '{} {} {}'. \
|
||||||
format(exctype, value, traceback.format_exc())
|
format(exctype, value, traceback.format_exc())
|
||||||
sys.stdout = sys.__stdout__
|
if self.redirect_stdout:
|
||||||
|
sys.stdout = self.old_stdout
|
||||||
|
|
||||||
def showProgressbar(self):
|
def showProgressbar(self):
|
||||||
if self.progressText:
|
if self.progressText:
|
||||||
@@ -96,10 +99,12 @@ class Worker(QRunnable):
|
|||||||
self.progressText = progressText
|
self.progressText = progressText
|
||||||
self.pb_widget = pb_widget
|
self.pb_widget = pb_widget
|
||||||
self.redirect_stdout = redirect_stdout
|
self.redirect_stdout = redirect_stdout
|
||||||
|
self.old_stdout = None
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.redirect_stdout:
|
if self.redirect_stdout:
|
||||||
|
self.old_stdout = sys.stdout
|
||||||
sys.stdout = self
|
sys.stdout = self
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -112,7 +117,7 @@ class Worker(QRunnable):
|
|||||||
self.signals.result.emit(result)
|
self.signals.result.emit(result)
|
||||||
finally:
|
finally:
|
||||||
self.signals.finished.emit('Done')
|
self.signals.finished.emit('Done')
|
||||||
sys.stdout = sys.__stdout__
|
sys.stdout = self.old_stdout
|
||||||
|
|
||||||
def write(self, text):
|
def write(self, text):
|
||||||
self.signals.message.emit(text)
|
self.signals.message.emit(text)
|
||||||
@@ -144,16 +149,18 @@ class MultiThread(QThread):
|
|||||||
self.progressText = progressText
|
self.progressText = progressText
|
||||||
self.pb_widget = pb_widget
|
self.pb_widget = pb_widget
|
||||||
self.redirect_stdout = redirect_stdout
|
self.redirect_stdout = redirect_stdout
|
||||||
|
self.old_stdout = None
|
||||||
self.finished.connect(self.hideProgressbar)
|
self.finished.connect(self.hideProgressbar)
|
||||||
self.showProgressbar()
|
self.showProgressbar()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.redirect_stdout:
|
if self.redirect_stdout:
|
||||||
|
self.old_stdout = sys.stdout
|
||||||
sys.stdout = self
|
sys.stdout = self
|
||||||
try:
|
try:
|
||||||
if not self.ncores:
|
if not self.ncores:
|
||||||
self.ncores = multiprocessing.cpu_count()
|
self.ncores = multiprocessing.cpu_count()
|
||||||
pool = multiprocessing.Pool(self.ncores)
|
pool = multiprocessing.Pool(self.ncores, maxtasksperchild=1000)
|
||||||
self.data = pool.map_async(self.func, self.args, callback=self.emitDone)
|
self.data = pool.map_async(self.func, self.args, callback=self.emitDone)
|
||||||
# self.data = pool.apply_async(self.func, self.shotlist, callback=self.emitDone) #emit each time returned
|
# self.data = pool.apply_async(self.func, self.shotlist, callback=self.emitDone) #emit each time returned
|
||||||
pool.close()
|
pool.close()
|
||||||
@@ -164,7 +171,7 @@ class MultiThread(QThread):
|
|||||||
exc_type, exc_obj, exc_tb = sys.exc_info()
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
||||||
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
||||||
print('Exception: {}, file: {}, line: {}'.format(exc_type, fname, exc_tb.tb_lineno))
|
print('Exception: {}, file: {}, line: {}'.format(exc_type, fname, exc_tb.tb_lineno))
|
||||||
sys.stdout = sys.__stdout__
|
sys.stdout = self.old_stdout
|
||||||
|
|
||||||
def showProgressbar(self):
|
def showProgressbar(self):
|
||||||
if self.progressText:
|
if self.progressText:
|
||||||
|
|||||||
+270
-171
@@ -1,12 +1,15 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import glob
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import warnings
|
import warnings
|
||||||
|
from typing import Literal, Tuple, Type
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from obspy import UTCDateTime, read
|
from obspy import UTCDateTime, read
|
||||||
@@ -18,6 +21,10 @@ from pylot.core.io.inputs import PylotParameter, FilterOptions
|
|||||||
from pylot.core.util.obspyDMT_interface import check_obspydmt_eventfolder
|
from pylot.core.util.obspyDMT_interface import check_obspydmt_eventfolder
|
||||||
from pylot.styles import style_settings
|
from pylot.styles import style_settings
|
||||||
|
|
||||||
|
Rgba: Type[tuple] = Tuple[int, int, int, int]
|
||||||
|
Mplrgba: Type[tuple] = Tuple[float, float, float, float]
|
||||||
|
Mplrgbastr: Type[tuple] = Tuple[str, str, str, str]
|
||||||
|
|
||||||
|
|
||||||
def _pickle_method(m):
|
def _pickle_method(m):
|
||||||
if m.im_self is None:
|
if m.im_self is None:
|
||||||
@@ -37,15 +44,14 @@ def getAutoFilteroptions(phase, parameter):
|
|||||||
return filteroptions
|
return filteroptions
|
||||||
|
|
||||||
|
|
||||||
def readDefaultFilterInformation(fname):
|
def readDefaultFilterInformation():
|
||||||
"""
|
"""
|
||||||
Read default filter information from pylot.in file
|
Read default filter information from pylot.in file
|
||||||
:param fname: path to pylot.in file
|
|
||||||
:type fname: str
|
|
||||||
:return: dictionary containing the defailt filter information
|
:return: dictionary containing the defailt filter information
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
"""
|
"""
|
||||||
pparam = PylotParameter(fname)
|
pparam = PylotParameter()
|
||||||
|
pparam.reset_defaults()
|
||||||
return readFilterInformation(pparam)
|
return readFilterInformation(pparam)
|
||||||
|
|
||||||
|
|
||||||
@@ -82,25 +88,6 @@ def fit_curve(x, y):
|
|||||||
return splev, splrep(x, y)
|
return splev, splrep(x, y)
|
||||||
|
|
||||||
|
|
||||||
def getindexbounds(f, eta):
|
|
||||||
"""
|
|
||||||
Get indices of values closest below and above maximum value in an array
|
|
||||||
:param f: array
|
|
||||||
:type f: `~numpy.ndarray`
|
|
||||||
:param eta: look for value in array that is closes to max_value * eta
|
|
||||||
:type eta: float
|
|
||||||
:return: tuple containing index of max value, index of value closest below max value,
|
|
||||||
index of value closest above max value
|
|
||||||
:rtype: (int, int, int)
|
|
||||||
"""
|
|
||||||
mi = f.argmax() # get indices of max values
|
|
||||||
m = max(f) # get maximum value
|
|
||||||
b = m * eta #
|
|
||||||
l = find_nearest(f[:mi], b) # find closest value below max value
|
|
||||||
u = find_nearest(f[mi:], b) + mi # find closest value above max value
|
|
||||||
return mi, l, u
|
|
||||||
|
|
||||||
|
|
||||||
def gen_Pool(ncores=0):
|
def gen_Pool(ncores=0):
|
||||||
"""
|
"""
|
||||||
Generate mulitprocessing pool object utilizing ncores amount of cores
|
Generate mulitprocessing pool object utilizing ncores amount of cores
|
||||||
@@ -120,7 +107,7 @@ def gen_Pool(ncores=0):
|
|||||||
|
|
||||||
print('gen_Pool: Generated multiprocessing Pool with {} cores\n'.format(ncores))
|
print('gen_Pool: Generated multiprocessing Pool with {} cores\n'.format(ncores))
|
||||||
|
|
||||||
pool = multiprocessing.Pool(ncores)
|
pool = multiprocessing.Pool(ncores, maxtasksperchild=100)
|
||||||
return pool
|
return pool
|
||||||
|
|
||||||
|
|
||||||
@@ -166,11 +153,11 @@ def clims(lim1, lim2):
|
|||||||
"""
|
"""
|
||||||
takes two pairs of limits and returns one pair of common limts
|
takes two pairs of limits and returns one pair of common limts
|
||||||
:param lim1: limit 1
|
:param lim1: limit 1
|
||||||
:type lim1: int
|
:type lim1: List[int]
|
||||||
:param lim2: limit 2
|
:param lim2: limit 2
|
||||||
:type lim2: int
|
:type lim2: List[int]
|
||||||
:return: new upper and lower limit common to both given limits
|
:return: new upper and lower limit common to both given limits
|
||||||
:rtype: [int, int]
|
:rtype: List[int]
|
||||||
|
|
||||||
>>> clims([0, 4], [1, 3])
|
>>> clims([0, 4], [1, 3])
|
||||||
[0, 4]
|
[0, 4]
|
||||||
@@ -302,7 +289,7 @@ def fnConstructor(s):
|
|||||||
if type(s) is str:
|
if type(s) is str:
|
||||||
s = s.split(':')[-1]
|
s = s.split(':')[-1]
|
||||||
else:
|
else:
|
||||||
s = getHash(UTCDateTime())
|
s = get_hash(UTCDateTime())
|
||||||
|
|
||||||
badchars = re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
|
badchars = re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
|
||||||
badsuffix = re.compile(r'(aux|com[1-9]|con|lpt[1-9]|prn)(\.|$)')
|
badsuffix = re.compile(r'(aux|com[1-9]|con|lpt[1-9]|prn)(\.|$)')
|
||||||
@@ -314,32 +301,75 @@ def fnConstructor(s):
|
|||||||
return fn
|
return fn
|
||||||
|
|
||||||
|
|
||||||
def get_None(value):
|
def get_none(value):
|
||||||
"""
|
"""
|
||||||
Convert "None" to None
|
Convert "None" to None
|
||||||
:param value:
|
:param value:
|
||||||
:type value: str, bool
|
:type value: str, NoneType
|
||||||
:return:
|
:return:
|
||||||
:rtype: bool
|
:rtype: type(value) or NoneType
|
||||||
|
|
||||||
|
>>> st = read()
|
||||||
|
>>> print(get_none(st))
|
||||||
|
3 Trace(s) in Stream:
|
||||||
|
BW.RJOB..EHZ | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.990000Z | 100.0 Hz, 3000 samples
|
||||||
|
BW.RJOB..EHN | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.990000Z | 100.0 Hz, 3000 samples
|
||||||
|
BW.RJOB..EHE | 2009-08-24T00:20:03.000000Z - 2009-08-24T00:20:32.990000Z | 100.0 Hz, 3000 samples
|
||||||
|
>>> get_none('Stream')
|
||||||
|
'Stream'
|
||||||
|
>>> get_none(0)
|
||||||
|
0
|
||||||
|
>>> get_none(0.)
|
||||||
|
0.0
|
||||||
|
>>> print(get_none('None'))
|
||||||
|
None
|
||||||
|
>>> print(get_none(None))
|
||||||
|
None
|
||||||
"""
|
"""
|
||||||
if value == 'None':
|
if value is None or (type(value) is str and value == 'None'):
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def get_Bool(value):
|
def get_bool(value):
|
||||||
"""
|
"""
|
||||||
Convert string representations of bools to their true boolean value
|
Convert string representations of bools to their true boolean value. Return value if it cannot be identified as bool.
|
||||||
:param value:
|
:param value:
|
||||||
:type value: str, bool
|
:type value: str, bool, int, float
|
||||||
:return: true boolean value
|
:return: true boolean value
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
|
|
||||||
|
>>> get_bool(True)
|
||||||
|
True
|
||||||
|
>>> get_bool(False)
|
||||||
|
False
|
||||||
|
>>> get_bool(0)
|
||||||
|
False
|
||||||
|
>>> get_bool(0.)
|
||||||
|
False
|
||||||
|
>>> get_bool(0.1)
|
||||||
|
True
|
||||||
|
>>> get_bool(2)
|
||||||
|
True
|
||||||
|
>>> get_bool(-1)
|
||||||
|
False
|
||||||
|
>>> get_bool(-0.3)
|
||||||
|
False
|
||||||
|
>>> get_bool(None)
|
||||||
|
None
|
||||||
"""
|
"""
|
||||||
if value in ['True', 'true']:
|
if type(value) is bool:
|
||||||
|
return value
|
||||||
|
elif value in ['True', 'true']:
|
||||||
return True
|
return True
|
||||||
elif value in ['False', 'false']:
|
elif value in ['False', 'false']:
|
||||||
return False
|
return False
|
||||||
|
elif isinstance(value, float) or isinstance(value, int):
|
||||||
|
if value > 0. or value > 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -353,8 +383,8 @@ def four_digits(year):
|
|||||||
:return: four digit year correspondent
|
:return: four digit year correspondent
|
||||||
:rtype: int
|
:rtype: int
|
||||||
|
|
||||||
>>> four_digits(20)
|
>>> four_digits(75)
|
||||||
1920
|
1975
|
||||||
>>> four_digits(16)
|
>>> four_digits(16)
|
||||||
2016
|
2016
|
||||||
>>> four_digits(00)
|
>>> four_digits(00)
|
||||||
@@ -436,36 +466,53 @@ def backtransformFilterString(st):
|
|||||||
return st
|
return st
|
||||||
|
|
||||||
|
|
||||||
def getHash(time):
|
def get_hash(time):
|
||||||
"""
|
"""
|
||||||
takes a time object and returns the corresponding SHA1 hash of the formatted date string
|
takes a time object and returns the corresponding SHA1 hash of the formatted date string
|
||||||
:param time: time object for which a hash should be calculated
|
:param time: time object for which a hash should be calculated
|
||||||
:type time: `~obspy.core.utcdatetime.UTCDateTime`
|
:type time: `~obspy.core.utcdatetime.UTCDateTime`
|
||||||
:return: SHA1 hash
|
:return: SHA1 hash
|
||||||
:rtype: str
|
:rtype: str
|
||||||
|
|
||||||
|
>>> time = UTCDateTime(0)
|
||||||
|
>>> get_hash(time)
|
||||||
|
'7627cce3b1b58dd21b005dac008b34d18317dd15'
|
||||||
|
>>> get_hash(0)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
AssertionError: 'time' is not an ObsPy UTCDateTime object
|
||||||
"""
|
"""
|
||||||
|
assert isinstance(time, UTCDateTime), '\'time\' is not an ObsPy UTCDateTime object'
|
||||||
hg = hashlib.sha1()
|
hg = hashlib.sha1()
|
||||||
hg.update(time.strftime('%Y-%m-%d %H:%M:%S.%f'))
|
hg.update(time.strftime('%Y-%m-%d %H:%M:%S.%f').encode('utf-8'))
|
||||||
return hg.hexdigest()
|
return hg.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def getLogin():
|
def get_login():
|
||||||
"""
|
"""
|
||||||
returns the actual user's login ID
|
returns the actual user's name
|
||||||
:return: login ID
|
:return: login name
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
import getpass
|
import getpass
|
||||||
return getpass.getuser()
|
return getpass.getuser()
|
||||||
|
|
||||||
|
|
||||||
def getOwner(fn):
|
def get_owner(fn):
|
||||||
"""
|
"""
|
||||||
takes a filename and return the login ID of the actual owner of the file
|
takes a filename and return the login ID of the actual owner of the file
|
||||||
:param fn: filename of the file tested
|
:param fn: filename of the file tested
|
||||||
:type fn: str
|
:type fn: str
|
||||||
:return: login ID of the file's owner
|
:return: login ID of the file's owner
|
||||||
:rtype: str
|
:rtype: str
|
||||||
|
|
||||||
|
>>> import tempfile
|
||||||
|
>>> with tempfile.NamedTemporaryFile() as tmpfile:
|
||||||
|
... tmpfile.write(b'') and True
|
||||||
|
... tmpfile.flush()
|
||||||
|
... get_owner(tmpfile.name) == os.path.expanduser('~').split('/')[-1]
|
||||||
|
0
|
||||||
|
True
|
||||||
"""
|
"""
|
||||||
system_name = platform.system()
|
system_name = platform.system()
|
||||||
if system_name in ["Linux", "Darwin"]:
|
if system_name in ["Linux", "Darwin"]:
|
||||||
@@ -511,6 +558,11 @@ def is_executable(fn):
|
|||||||
:param fn: path to the file to be tested
|
:param fn: path to the file to be tested
|
||||||
:return: True or False
|
:return: True or False
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
|
|
||||||
|
>>> is_executable('/bin/ls')
|
||||||
|
True
|
||||||
|
>>> is_executable('/var/log/system.log')
|
||||||
|
False
|
||||||
"""
|
"""
|
||||||
return os.path.isfile(fn) and os.access(fn, os.X_OK)
|
return os.path.isfile(fn) and os.access(fn, os.X_OK)
|
||||||
|
|
||||||
@@ -537,24 +589,36 @@ def isSorted(iterable):
|
|||||||
>>> isSorted([2,3,1,4])
|
>>> isSorted([2,3,1,4])
|
||||||
False
|
False
|
||||||
"""
|
"""
|
||||||
assert isIterable(iterable), 'object is not iterable; object: {' \
|
assert is_iterable(iterable), "object is not iterable; object: {}".format(iterable)
|
||||||
'}'.format(iterable)
|
|
||||||
if type(iterable) is str:
|
if type(iterable) is str:
|
||||||
iterable = [s for s in iterable]
|
iterable = [s for s in iterable]
|
||||||
return sorted(iterable) == iterable
|
return sorted(iterable) == iterable
|
||||||
|
|
||||||
|
|
||||||
def isIterable(obj):
|
def is_iterable(obj):
|
||||||
"""
|
"""
|
||||||
takes a python object and returns True is the object is iterable and
|
takes a python object and returns True is the object is iterable and
|
||||||
False otherwise
|
False otherwise
|
||||||
:param obj: a python object
|
:param obj: a python object
|
||||||
:type obj: object
|
:type obj: obj
|
||||||
:return: True of False
|
:return: True of False
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
|
|
||||||
|
>>> is_iterable(1)
|
||||||
|
False
|
||||||
|
>>> is_iterable(True)
|
||||||
|
False
|
||||||
|
>>> is_iterable(0.)
|
||||||
|
False
|
||||||
|
>>> is_iterable((0,1,3,4))
|
||||||
|
True
|
||||||
|
>>> is_iterable([1])
|
||||||
|
True
|
||||||
|
>>> is_iterable('a')
|
||||||
|
True
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
iterator = iter(obj)
|
iter(obj)
|
||||||
except TypeError as te:
|
except TypeError as te:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
@@ -563,13 +627,19 @@ def isIterable(obj):
|
|||||||
def key_for_set_value(d):
|
def key_for_set_value(d):
|
||||||
"""
|
"""
|
||||||
takes a dictionary and returns the first key for which's value the
|
takes a dictionary and returns the first key for which's value the
|
||||||
boolean is True
|
boolean representation is True
|
||||||
:param d: dictionary containing values
|
:param d: dictionary containing values
|
||||||
:type d: dict
|
:type d: dict
|
||||||
:return: key to the first non-False value found; None if no value's
|
:return: key to the first non-False value found; None if no value's
|
||||||
boolean equals True
|
boolean equals True
|
||||||
:rtype:
|
:rtype: bool or NoneType
|
||||||
|
|
||||||
|
>>> key_for_set_value({'one': 0, 'two': 1})
|
||||||
|
'two'
|
||||||
|
>>> print(key_for_set_value({1: 0, 2: False}))
|
||||||
|
None
|
||||||
"""
|
"""
|
||||||
|
assert type(d) is dict, "Function only defined for inputs of type 'dict'."
|
||||||
r = None
|
r = None
|
||||||
for k, v in d.items():
|
for k, v in d.items():
|
||||||
if v:
|
if v:
|
||||||
@@ -577,32 +647,53 @@ def key_for_set_value(d):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def prepTimeAxis(stime, trace, verbosity=0):
|
def prep_time_axis(offset, trace, verbosity=0):
|
||||||
"""
|
"""
|
||||||
takes a starttime and a trace object and returns a valid time axis for
|
takes an offset and a trace object and returns a valid time axis for
|
||||||
plotting
|
plotting
|
||||||
:param stime: start time of the actual seismogram as UTCDateTime
|
:param offset: offset of the actual seismogram on plotting axis
|
||||||
:type stime: `~obspy.core.utcdatetime.UTCDateTime`
|
:type offset: float or int
|
||||||
:param trace: seismic trace object
|
:param trace: seismic trace object
|
||||||
:type trace: `~obspy.core.trace.Trace`
|
:type trace: `~obspy.core.trace.Trace`
|
||||||
:param verbosity: if != 0, debug output will be written to console
|
:param verbosity: if != 0, debug output will be written to console
|
||||||
:type verbosity: int
|
:type verbosity: int
|
||||||
:return: valid numpy array with time stamps for plotting
|
:return: valid numpy array with time stamps for plotting
|
||||||
:rtype: `~numpy.ndarray`
|
:rtype: `~numpy.ndarray`
|
||||||
|
|
||||||
|
>>> tr = read()[0]
|
||||||
|
>>> prep_time_axis(0., tr)
|
||||||
|
array([0.00000000e+00, 1.00033344e-02, 2.00066689e-02, ...,
|
||||||
|
2.99799933e+01, 2.99899967e+01, 3.00000000e+01])
|
||||||
|
>>> prep_time_axis(22.5, tr)
|
||||||
|
array([22.5 , 22.51000333, 22.52000667, ..., 52.47999333,
|
||||||
|
52.48999667, 52.5 ])
|
||||||
|
>>> prep_time_axis(tr.stats.starttime, tr)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
AssertionError: 'offset' is not of type 'float' or 'int'; type: <class 'obspy.core.utcdatetime.UTCDateTime'>
|
||||||
|
>>> tr.stats.npts -= 1
|
||||||
|
>>> prep_time_axis(0, tr)
|
||||||
|
array([0.00000000e+00, 1.00033356e-02, 2.00066711e-02, ...,
|
||||||
|
2.99699933e+01, 2.99799967e+01, 2.99900000e+01])
|
||||||
|
>>> tr.stats.npts += 2
|
||||||
|
>>> prep_time_axis(0, tr)
|
||||||
|
array([0.00000000e+00, 1.00033333e-02, 2.00066667e-02, ...,
|
||||||
|
2.99899933e+01, 2.99999967e+01, 3.00100000e+01])
|
||||||
"""
|
"""
|
||||||
|
assert isinstance(offset, (float, int)), "'offset' is not of type 'float' or 'int'; type: {}".format(type(offset))
|
||||||
nsamp = trace.stats.npts
|
nsamp = trace.stats.npts
|
||||||
srate = trace.stats.sampling_rate
|
srate = trace.stats.sampling_rate
|
||||||
tincr = trace.stats.delta
|
tincr = trace.stats.delta
|
||||||
etime = stime + nsamp / srate
|
etime = offset + nsamp / srate
|
||||||
time_ax = np.linspace(stime, etime, nsamp)
|
time_ax = np.linspace(offset, etime, nsamp)
|
||||||
if len(time_ax) < nsamp:
|
if len(time_ax) < nsamp:
|
||||||
if verbosity:
|
if verbosity:
|
||||||
print('elongate time axes by one datum')
|
print('elongate time axes by one datum')
|
||||||
time_ax = np.arange(stime, etime + tincr, tincr)
|
time_ax = np.arange(offset, etime + tincr, tincr)
|
||||||
elif len(time_ax) > nsamp:
|
elif len(time_ax) > nsamp:
|
||||||
if verbosity:
|
if verbosity:
|
||||||
print('shorten time axes by one datum')
|
print('shorten time axes by one datum')
|
||||||
time_ax = np.arange(stime, etime - tincr, tincr)
|
time_ax = np.arange(offset, etime - tincr, tincr)
|
||||||
if len(time_ax) != nsamp:
|
if len(time_ax) != nsamp:
|
||||||
print('Station {0}, {1} samples of data \n '
|
print('Station {0}, {1} samples of data \n '
|
||||||
'{2} length of time vector \n'
|
'{2} length of time vector \n'
|
||||||
@@ -618,13 +709,13 @@ def find_horizontals(data):
|
|||||||
:param data: waveform data
|
:param data: waveform data
|
||||||
:type data: `obspy.core.stream.Stream`
|
:type data: `obspy.core.stream.Stream`
|
||||||
:return: components list
|
:return: components list
|
||||||
:rtype: list
|
:rtype: List(str)
|
||||||
|
|
||||||
..example::
|
..example::
|
||||||
|
|
||||||
>>> st = read()
|
>>> st = read()
|
||||||
>>> find_horizontals(st)
|
>>> find_horizontals(st)
|
||||||
[u'N', u'E']
|
['N', 'E']
|
||||||
"""
|
"""
|
||||||
rval = []
|
rval = []
|
||||||
for tr in data:
|
for tr in data:
|
||||||
@@ -635,7 +726,7 @@ def find_horizontals(data):
|
|||||||
return rval
|
return rval
|
||||||
|
|
||||||
|
|
||||||
def pick_color(picktype, phase, quality=0):
|
def pick_color(picktype: Literal['manual', 'automatic'], phase: Literal['P', 'S'], quality: int = 0) -> Rgba:
|
||||||
"""
|
"""
|
||||||
Create pick color by modifying the base color by the quality.
|
Create pick color by modifying the base color by the quality.
|
||||||
|
|
||||||
@@ -648,7 +739,7 @@ def pick_color(picktype, phase, quality=0):
|
|||||||
:param quality: quality of pick. Decides the new intensity of the modifier color
|
:param quality: quality of pick. Decides the new intensity of the modifier color
|
||||||
:type quality: int
|
:type quality: int
|
||||||
:return: tuple containing modified rgba color values
|
:return: tuple containing modified rgba color values
|
||||||
:rtype: (int, int, int, int)
|
:rtype: Rgba
|
||||||
"""
|
"""
|
||||||
min_quality = 3
|
min_quality = 3
|
||||||
bpc = base_phase_colors(picktype, phase) # returns dict like {'modifier': 'g', 'rgba': (0, 0, 255, 255)}
|
bpc = base_phase_colors(picktype, phase) # returns dict like {'modifier': 'g', 'rgba': (0, 0, 255, 255)}
|
||||||
@@ -704,17 +795,17 @@ def pick_linestyle_plt(picktype, key):
|
|||||||
return linestyles[picktype][key]
|
return linestyles[picktype][key]
|
||||||
|
|
||||||
|
|
||||||
def modify_rgba(rgba, modifier, intensity):
|
def modify_rgba(rgba: Rgba, modifier: Literal['r', 'g', 'b'], intensity: float) -> Rgba:
|
||||||
"""
|
"""
|
||||||
Modify rgba color by adding the given intensity to the modifier color
|
Modify rgba color by adding the given intensity to the modifier color
|
||||||
:param rgba: tuple containing rgba values
|
:param rgba: tuple containing rgba values
|
||||||
:type rgba: (int, int, int, int)
|
:type rgba: Rgba
|
||||||
:param modifier: which color should be modified, eg. 'r', 'g', 'b'
|
:param modifier: which color should be modified; options: 'r', 'g', 'b'
|
||||||
:type modifier: str
|
:type modifier: Literal['r', 'g', 'b']
|
||||||
:param intensity: intensity to be added to selected color
|
:param intensity: intensity to be added to selected color
|
||||||
:type intensity: float
|
:type intensity: float
|
||||||
:return: tuple containing rgba values
|
:return: tuple containing rgba values
|
||||||
:rtype: (int, int, int, int)
|
:rtype: Rgba
|
||||||
"""
|
"""
|
||||||
rgba = list(rgba)
|
rgba = list(rgba)
|
||||||
index = {'r': 0,
|
index = {'r': 0,
|
||||||
@@ -748,18 +839,20 @@ def transform_colors_mpl_str(colors, no_alpha=False):
|
|||||||
Transforms rgba color values to a matplotlib string of color values with a range of [0, 1]
|
Transforms rgba color values to a matplotlib string of color values with a range of [0, 1]
|
||||||
:param colors: tuple of rgba color values ranging from [0, 255]
|
:param colors: tuple of rgba color values ranging from [0, 255]
|
||||||
:type colors: (float, float, float, float)
|
:type colors: (float, float, float, float)
|
||||||
:param no_alpha: Wether to return a alpha value in the matplotlib color string
|
:param no_alpha: Whether to return an alpha value in the matplotlib color string
|
||||||
:type no_alpha: bool
|
:type no_alpha: bool
|
||||||
:return: String containing r, g, b values and alpha value if no_alpha is False (default)
|
:return: String containing r, g, b values and alpha value if no_alpha is False (default)
|
||||||
:rtype: str
|
:rtype: str
|
||||||
|
|
||||||
|
>>> transform_colors_mpl_str((255., 255., 255., 255.), True)
|
||||||
|
'(1.0, 1.0, 1.0)'
|
||||||
|
>>> transform_colors_mpl_str((255., 255., 255., 255.))
|
||||||
|
'(1.0, 1.0, 1.0, 1.0)'
|
||||||
"""
|
"""
|
||||||
colors = list(colors)
|
|
||||||
colors_mpl = tuple([color / 255. for color in colors])
|
|
||||||
if no_alpha:
|
if no_alpha:
|
||||||
colors_mpl = '({}, {}, {})'.format(*colors_mpl)
|
return '({}, {}, {})'.format(*transform_colors_mpl(colors))
|
||||||
else:
|
else:
|
||||||
colors_mpl = '({}, {}, {}, {})'.format(*colors_mpl)
|
return '({}, {}, {}, {})'.format(*transform_colors_mpl(colors))
|
||||||
return colors_mpl
|
|
||||||
|
|
||||||
|
|
||||||
def transform_colors_mpl(colors):
|
def transform_colors_mpl(colors):
|
||||||
@@ -769,27 +862,16 @@ def transform_colors_mpl(colors):
|
|||||||
:type colors: (float, float, float, float)
|
:type colors: (float, float, float, float)
|
||||||
:return: tuple of rgba color values ranging from [0, 1]
|
:return: tuple of rgba color values ranging from [0, 1]
|
||||||
:rtype: (float, float, float, float)
|
:rtype: (float, float, float, float)
|
||||||
|
|
||||||
|
>>> transform_colors_mpl((127.5, 0., 63.75, 255.))
|
||||||
|
(0.5, 0.0, 0.25, 1.0)
|
||||||
|
>>> transform_colors_mpl(())
|
||||||
"""
|
"""
|
||||||
colors = list(colors)
|
colors = list(colors)
|
||||||
colors_mpl = tuple([color / 255. for color in colors])
|
colors_mpl = tuple([color / 255. for color in colors])
|
||||||
return colors_mpl
|
return colors_mpl
|
||||||
|
|
||||||
|
|
||||||
def remove_underscores(data):
|
|
||||||
"""
|
|
||||||
takes a `obspy.core.stream.Stream` object and removes all underscores
|
|
||||||
from station names
|
|
||||||
:param data: stream of seismic data
|
|
||||||
:type data: `~obspy.core.stream.Stream`
|
|
||||||
:return: data stream
|
|
||||||
:rtype: `~obspy.core.stream.Stream`
|
|
||||||
"""
|
|
||||||
# for tr in data:
|
|
||||||
# # remove underscores
|
|
||||||
# tr.stats.station = tr.stats.station.strip('_')
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def trim_station_components(data, trim_start=True, trim_end=True):
|
def trim_station_components(data, trim_start=True, trim_end=True):
|
||||||
"""
|
"""
|
||||||
cut a stream so only the part common to all three traces is kept to avoid dealing with offsets
|
cut a stream so only the part common to all three traces is kept to avoid dealing with offsets
|
||||||
@@ -818,19 +900,6 @@ def trim_station_components(data, trim_start=True, trim_end=True):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def merge_stream(stream):
|
|
||||||
gaps = stream.get_gaps()
|
|
||||||
if gaps:
|
|
||||||
# list of merged stations (seed_ids)
|
|
||||||
merged = ['{}.{}.{}.{}'.format(*gap[:4]) for gap in gaps]
|
|
||||||
stream.merge(method=1)
|
|
||||||
print('Merged the following stations because of gaps:')
|
|
||||||
for merged_station in merged:
|
|
||||||
print(merged_station)
|
|
||||||
|
|
||||||
return stream, gaps
|
|
||||||
|
|
||||||
|
|
||||||
def check4gapsAndRemove(data):
|
def check4gapsAndRemove(data):
|
||||||
"""
|
"""
|
||||||
check for gaps in Stream and remove them
|
check for gaps in Stream and remove them
|
||||||
@@ -851,12 +920,12 @@ def check4gapsAndRemove(data):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def check4gapsAndMerge(data):
|
def check_for_gaps_and_merge(data):
|
||||||
"""
|
"""
|
||||||
check for gaps in Stream and merge if gaps are found
|
check for gaps in Stream and merge if gaps are found
|
||||||
:param data: stream of seismic data
|
:param data: stream of seismic data
|
||||||
:type data: `~obspy.core.stream.Stream`
|
:type data: `~obspy.core.stream.Stream`
|
||||||
:return: data stream
|
:return: data stream, gaps returned from obspy get_gaps
|
||||||
:rtype: `~obspy.core.stream.Stream`
|
:rtype: `~obspy.core.stream.Stream`
|
||||||
"""
|
"""
|
||||||
gaps = data.get_gaps()
|
gaps = data.get_gaps()
|
||||||
@@ -867,7 +936,7 @@ def check4gapsAndMerge(data):
|
|||||||
for merged_station in merged:
|
for merged_station in merged:
|
||||||
print(merged_station)
|
print(merged_station)
|
||||||
|
|
||||||
return data
|
return data, gaps
|
||||||
|
|
||||||
|
|
||||||
def check4doubled(data):
|
def check4doubled(data):
|
||||||
@@ -897,13 +966,53 @@ def check4doubled(data):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def check_for_nan(data, nan_value=0.):
|
||||||
|
"""
|
||||||
|
Replace all NaNs in data with nan_value (in place)
|
||||||
|
:param data: stream of seismic data
|
||||||
|
:type data: `~obspy.core.stream.Stream`
|
||||||
|
:param nan_value: value which all NaNs are set to
|
||||||
|
:type nan_value: float, int
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
return
|
||||||
|
for trace in data:
|
||||||
|
np.nan_to_num(trace.data, copy=False, nan=nan_value)
|
||||||
|
|
||||||
|
|
||||||
|
def get_pylot_eventfile_with_extension(event, fext):
|
||||||
|
if hasattr(event, 'path'):
|
||||||
|
eventpath = event.path
|
||||||
|
else:
|
||||||
|
logging.warning('No attribute path found for event.')
|
||||||
|
return
|
||||||
|
eventname = event.pylot_id #path.split('/')[-1] # or event.pylot_id
|
||||||
|
filename = os.path.join(eventpath, 'PyLoT_' + eventname + fext)
|
||||||
|
if os.path.isfile(filename):
|
||||||
|
return filename
|
||||||
|
|
||||||
|
|
||||||
|
def get_possible_pylot_eventfile_extensions(event, fext):
|
||||||
|
if hasattr(event, 'path'):
|
||||||
|
eventpath = event.path
|
||||||
|
else:
|
||||||
|
logging.warning('No attribute path found for event.')
|
||||||
|
return []
|
||||||
|
eventname = event.pylot_id
|
||||||
|
filename = os.path.join(eventpath, 'PyLoT_' + eventname + fext)
|
||||||
|
filenames = glob.glob(filename)
|
||||||
|
extensions = [os.path.split(path)[-1].split('PyLoT_' + eventname)[-1] for path in filenames]
|
||||||
|
return extensions
|
||||||
|
|
||||||
|
|
||||||
def get_stations(data):
|
def get_stations(data):
|
||||||
"""
|
"""
|
||||||
Get list of all station names in data stream
|
Get list of all station names in data-stream
|
||||||
:param data: stream containing seismic traces
|
:param data: stream containing seismic traces
|
||||||
:type data: `~obspy.core.stream.Stream`
|
:type data: `~obspy.core.stream.Stream`
|
||||||
:return: list of all station names in data, no duplicates
|
:return: list of all station names in data, no duplicates
|
||||||
:rtype: list of str
|
:rtype: List(str)
|
||||||
"""
|
"""
|
||||||
stations = []
|
stations = []
|
||||||
for tr in data:
|
for tr in data:
|
||||||
@@ -930,66 +1039,87 @@ def check4rotated(data, metadata=None, verbosity=1):
|
|||||||
:rtype: `~obspy.core.stream.Stream`
|
:rtype: `~obspy.core.stream.Stream`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def rotate_components(wfstream, metadata=None):
|
def rotation_required(trace_ids):
|
||||||
|
"""
|
||||||
|
Derive if any rotation is required from the orientation code of the input.
|
||||||
|
|
||||||
|
:param trace_ids: string identifier of waveform data trace
|
||||||
|
:type trace_ids: List(str)
|
||||||
|
:return: boolean representing if rotation is necessary for any of the traces
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
orientations = [trace_id[-1] for trace_id in trace_ids]
|
||||||
|
return any([orientation.isnumeric() for orientation in orientations])
|
||||||
|
|
||||||
|
def rotate_components(wfs_in, metadata=None):
|
||||||
"""
|
"""
|
||||||
Rotate components if orientation code is numeric (= non traditional orientation).
|
Rotate components if orientation code is numeric (= non traditional orientation).
|
||||||
|
|
||||||
Azimut and dip are fetched from metadata. To be rotated, traces of a station have to be cut to the same length.
|
Azimut and dip are fetched from metadata. To be rotated, traces of a station have to be cut to the same length.
|
||||||
Returns unrotated traces of no metadata is provided
|
Returns unrotated traces of no metadata is provided
|
||||||
:param wfstream: stream containing seismic traces of a station
|
:param wfs_in: stream containing seismic traces of a station
|
||||||
:type wfstream: `~obspy.core.stream.Stream`
|
:type wfs_in: `~obspy.core.stream.Stream`
|
||||||
:param metadata: tuple containing metadata type string and metadata parser object
|
:param metadata: tuple containing metadata type string and metadata parser object
|
||||||
:type metadata: (str, `~obspy.io.xseed.parser.Parser`)
|
:type metadata: (str, `~obspy.io.xseed.parser.Parser`)
|
||||||
:return: stream object with traditionally oriented traces (ZNE)
|
:return: stream object with traditionally oriented traces (ZNE)
|
||||||
:rtype: `~obspy.core.stream.Stream`
|
:rtype: `~obspy.core.stream.Stream`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if len(wfs_in) < 3:
|
||||||
|
print(f"Stream {wfs_in=}, has not enough components to rotate.")
|
||||||
|
return wfs_in
|
||||||
|
|
||||||
# check if any traces in this station need to be rotated
|
# check if any traces in this station need to be rotated
|
||||||
trace_ids = [trace.id for trace in wfstream]
|
trace_ids = [trace.id for trace in wfs_in]
|
||||||
orientations = [trace_id[-1] for trace_id in trace_ids]
|
if not rotation_required(trace_ids):
|
||||||
rotation_required = [orientation.isnumeric() for orientation in orientations]
|
logging.debug(f"Stream does not need any rotation: Traces are {trace_ids=}")
|
||||||
if any(rotation_required):
|
return wfs_in
|
||||||
t_start = full_range(wfstream)
|
|
||||||
|
# check metadata quality
|
||||||
|
t_start = full_range(wfs_in)
|
||||||
try:
|
try:
|
||||||
azimuts = []
|
azimuths = []
|
||||||
dips = []
|
dips = []
|
||||||
for tr_id in trace_ids:
|
for tr_id in trace_ids:
|
||||||
azimuts.append(metadata.get_coordinates(tr_id, t_start)['azimuth'])
|
azimuths.append(metadata.get_coordinates(tr_id, t_start)['azimuth'])
|
||||||
dips.append(metadata.get_coordinates(tr_id, t_start)['dip'])
|
dips.append(metadata.get_coordinates(tr_id, t_start)['dip'])
|
||||||
except (KeyError, TypeError) as e:
|
except (KeyError, TypeError) as err:
|
||||||
print('Failed to rotate trace {}, no azimuth or dip available in metadata'.format(tr_id))
|
logging.error(f"{type(err)=} occurred: {err=} Rotating not possible, not all azimuth and dip information "
|
||||||
return wfstream
|
f"available in metadata. Stream remains unchanged.")
|
||||||
if len(wfstream) < 3:
|
return wfs_in
|
||||||
print('Failed to rotate Stream {}, not enough components available.'.format(wfstream))
|
except Exception as err:
|
||||||
return wfstream
|
print(f"Unexpected {err=}, {type(err)=}")
|
||||||
|
raise
|
||||||
|
|
||||||
# to rotate all traces must have same length, so trim them
|
# to rotate all traces must have same length, so trim them
|
||||||
wfstream = trim_station_components(wfstream, trim_start=True, trim_end=True)
|
wfs_out = trim_station_components(wfs_in, trim_start=True, trim_end=True)
|
||||||
try:
|
try:
|
||||||
z, n, e = rotate2zne(wfstream[0], azimuts[0], dips[0],
|
z, n, e = rotate2zne(wfs_out[0], azimuths[0], dips[0],
|
||||||
wfstream[1], azimuts[1], dips[1],
|
wfs_out[1], azimuths[1], dips[1],
|
||||||
wfstream[2], azimuts[2], dips[2])
|
wfs_out[2], azimuths[2], dips[2])
|
||||||
print('check4rotated: rotated trace {} to ZNE'.format(trace_ids))
|
print('check4rotated: rotated trace {} to ZNE'.format(trace_ids))
|
||||||
# replace old data with rotated data, change the channel code to ZNE
|
# replace old data with rotated data, change the channel code to ZNE
|
||||||
z_index = dips.index(min(
|
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)
|
dips)) # get z-trace index, z has minimum dip of -90 (dip is measured from 0 to -90, with -90
|
||||||
wfstream[z_index].data = z
|
# being vertical)
|
||||||
wfstream[z_index].stats.channel = wfstream[z_index].stats.channel[0:-1] + 'Z'
|
wfs_out[z_index].data = z
|
||||||
|
wfs_out[z_index].stats.channel = wfs_out[z_index].stats.channel[0:-1] + 'Z'
|
||||||
del trace_ids[z_index]
|
del trace_ids[z_index]
|
||||||
for trace_id in trace_ids:
|
for trace_id in trace_ids:
|
||||||
coordinates = metadata.get_coordinates(trace_id, t_start)
|
coordinates = metadata.get_coordinates(trace_id, t_start)
|
||||||
dip, az = coordinates['dip'], coordinates['azimuth']
|
dip, az = coordinates['dip'], coordinates['azimuth']
|
||||||
trace = wfstream.select(id=trace_id)[0]
|
trace = wfs_out.select(id=trace_id)[0]
|
||||||
if az > 315 or az <= 45 or az > 135 and az <= 225:
|
if az > 315 or az <= 45 or 135 < az <= 225:
|
||||||
trace.data = n
|
trace.data = n
|
||||||
trace.stats.channel = trace.stats.channel[0:-1] + 'N'
|
trace.stats.channel = trace.stats.channel[0:-1] + 'N'
|
||||||
elif az > 45 and az <= 135 or az > 225 and az <= 315:
|
elif 45 < az <= 135 or 225 < az <= 315:
|
||||||
trace.data = e
|
trace.data = e
|
||||||
trace.stats.channel = trace.stats.channel[0:-1] + 'E'
|
trace.stats.channel = trace.stats.channel[0:-1] + 'E'
|
||||||
except (ValueError) as e:
|
except ValueError as err:
|
||||||
print(e)
|
print(f"{err=} Rotation failed. Stream remains unchanged.")
|
||||||
return wfstream
|
return wfs_in
|
||||||
|
|
||||||
return wfstream
|
return wfs_out
|
||||||
|
|
||||||
if metadata is None:
|
if metadata is None:
|
||||||
if verbosity:
|
if verbosity:
|
||||||
@@ -1003,38 +1133,6 @@ def check4rotated(data, metadata=None, verbosity=1):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def scaleWFData(data, factor=None, components='all'):
|
|
||||||
"""
|
|
||||||
produce scaled waveforms from given waveform data and a scaling factor,
|
|
||||||
waveform may be selected by their components name
|
|
||||||
:param data: waveform data to be scaled
|
|
||||||
:type data: `~obspy.core.stream.Stream` object
|
|
||||||
:param factor: scaling factor
|
|
||||||
:type factor: float
|
|
||||||
:param components: components labels for the traces in data to be scaled by
|
|
||||||
the scaling factor (optional, default: 'all')
|
|
||||||
:type components: tuple
|
|
||||||
:return: scaled waveform data
|
|
||||||
:rtype: `~obspy.core.stream.Stream` object
|
|
||||||
"""
|
|
||||||
if components != 'all':
|
|
||||||
for comp in components:
|
|
||||||
if factor is None:
|
|
||||||
max_val = np.max(np.abs(data.select(component=comp)[0].data))
|
|
||||||
data.select(component=comp)[0].data /= 2 * max_val
|
|
||||||
else:
|
|
||||||
data.select(component=comp)[0].data /= 2 * factor
|
|
||||||
else:
|
|
||||||
for tr in data:
|
|
||||||
if factor is None:
|
|
||||||
max_val = float(np.max(np.abs(tr.data)))
|
|
||||||
tr.data /= 2 * max_val
|
|
||||||
else:
|
|
||||||
tr.data /= 2 * factor
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def runProgram(cmd, parameter=None):
|
def runProgram(cmd, parameter=None):
|
||||||
"""
|
"""
|
||||||
run an external program specified by cmd with parameters input returning the
|
run an external program specified by cmd with parameters input returning the
|
||||||
@@ -1106,6 +1204,7 @@ def identifyPhase(phase):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
def identifyPhaseID(phase):
|
def identifyPhaseID(phase):
|
||||||
"""
|
"""
|
||||||
Returns phase id (capital P or S)
|
Returns phase id (capital P or S)
|
||||||
@@ -1169,7 +1268,7 @@ def correct_iplot(iplot):
|
|||||||
try:
|
try:
|
||||||
iplot = int(iplot)
|
iplot = int(iplot)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
if get_Bool(iplot):
|
if get_bool(iplot):
|
||||||
iplot = 2
|
iplot = 2
|
||||||
else:
|
else:
|
||||||
iplot = 0
|
iplot = 0
|
||||||
|
|||||||
+613
-115
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from pylot.core.io.phases import getQualitiesfromxml
|
||||||
|
|
||||||
|
|
||||||
|
class TestQualityFromXML(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.path = '.'
|
||||||
|
self.ErrorsP = [0.02, 0.04, 0.08, 0.16]
|
||||||
|
self.ErrorsS = [0.04, 0.08, 0.16, 0.32]
|
||||||
|
self.test0_result = [[0.0136956521739, 0.0126, 0.0101612903226, 0.00734848484849, 0.0135069444444,
|
||||||
|
0.00649659863946, 0.0129513888889, 0.0122747747748, 0.0119252873563, 0.0103947368421,
|
||||||
|
0.0092380952381, 0.00916666666667, 0.0104444444444, 0.0125333333333, 0.00904761904762,
|
||||||
|
0.00885714285714, 0.00911616161616, 0.0164166666667, 0.0128787878788, 0.0122756410256,
|
||||||
|
0.013653253667966917], [0.0239333333333, 0.0223791578953, 0.0217974304255],
|
||||||
|
[0.0504861111111, 0.0610833333333], [], [0.171029411765]], [
|
||||||
|
[0.0195, 0.0203623188406, 0.0212121212121, 0.0345833333333, 0.0196180555556,
|
||||||
|
0.0202536231884, 0.0200347222222, 0.0189, 0.0210763888889, 0.018275862069,
|
||||||
|
0.0213888888889, 0.0319791666667, 0.0205303030303, 0.0156388888889, 0.0192,
|
||||||
|
0.0231349206349, 0.023625, 0.02875, 0.0195512820513, 0.0239393939394, 0.0234166666667,
|
||||||
|
0.0174702380952, 0.0204151307995], [0.040314343081226646], [0.148555555556], [], []]
|
||||||
|
self.test1_result = [77.77777777777777, 11.11111111111111, 7.407407407407407, 0, 3.7037037037037037],\
|
||||||
|
[92.0, 4.0, 4.0, 0, 0]
|
||||||
|
|
||||||
|
def test_result_plotflag0(self):
|
||||||
|
self.assertEqual(getQualitiesfromxml(self.path, self.ErrorsP, self.ErrorsS, 0), self.test0_result)
|
||||||
|
|
||||||
|
def test_result_plotflag1(self):
|
||||||
|
self.assertEqual(getQualitiesfromxml(self.path, self.ErrorsP, self.ErrorsS, 1), self.test1_result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user