Merge branch 'feature/port-to-py3' of git.geophysik.ruhr-uni-bochum.de:marcel/pylot into feature/port-to-py3

This commit is contained in:
Kaan Cökerim 2022-03-08 12:45:49 +01:00
commit 7c926327dd
8 changed files with 1785 additions and 7615 deletions

1
.gitignore vendored
View File

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

View File

@ -91,6 +91,8 @@ from pylot.core.util.array_map import Array_map
from pylot.core.util.structure import DATASTRUCTURE
from pylot.core.util.thread import Thread, Worker
from pylot.core.util.version import get_git_version as _getVersionString
from pylot.core.io.getEventListFromXML import geteventlistfromxml
from pylot.core.io.getQualitiesfromxml import getQualitiesfromxml
from pylot.styles import style_settings
@ -346,6 +348,9 @@ class MainWindow(QMainWindow):
compare_icon.addPixmap(QPixmap(':/icons/compare_button.png'))
qualities_icon = QIcon()
qualities_icon.addPixmap(QPixmap(':/icons/pick_qualities_button.png'))
eventlist_xml_icon = QIcon()
eventlist_xml_icon.addPixmap(QPixmap(':/icons/eventlist_xml_button.png'))
self.newProjectAction = self.createAction(self, "&New project ...",
self.createNewProject,
QKeySequence.New, newIcon,
@ -486,6 +491,11 @@ class MainWindow(QMainWindow):
# LK will be implemented soon, basic script has already (03/2021) been finished
self.qualities_action.setVisible(True)
self.eventlist_xml_action = self.createAction(parent=self, text='Create Eventlist from XML',
slot=self.eventlistXml, shortcut='Alt+X',
icon=eventlist_xml_icon, tip='Create an Eventlist from a XML File')
self.eventlist_xml_action.setEnabled(False)
printAction = self.createAction(self, "&Print event ...",
self.show_event_information, QKeySequence.Print,
print_icon,
@ -549,7 +559,7 @@ class MainWindow(QMainWindow):
' the complete project on grid engine.')
self.auto_pick_sge.setEnabled(False)
pickActions = (self.auto_tune, self.auto_pick, self.compare_action, self.qualities_action)
pickActions = (self.auto_tune, self.auto_pick, self.compare_action, self.qualities_action, self.eventlist_xml_action)
# pickToolBar = self.addToolBar("PickTools")
# pickToolActions = (selectStation, )
@ -1646,6 +1656,14 @@ class MainWindow(QMainWindow):
self.cmpw.show()
def pickQualities(self):
path = self._inputs['rootpath'] + '/' + self._inputs['datapath'] + '/' + self._inputs['database']
getQualitiesfromxml(path)
return
def eventlistXml(self):
path = self._inputs['rootpath'] + '/' + self._inputs['datapath'] + '/' + self._inputs['database']
outpath = self.project.location[:self.project.location.rfind('/')]
geteventlistfromxml(path, outpath)
return
def compareMulti(self):
@ -2089,6 +2107,7 @@ class MainWindow(QMainWindow):
if event.pylot_picks or event.pylot_autopicks:
self.locateEventAction.setEnabled(True)
self.qualities_action.setEnabled(True)
self.eventlist_xml_action.setEnabled(True)
if True in self.comparable.values():
self.compare_action.setEnabled(True)
self.draw()
@ -2161,6 +2180,7 @@ class MainWindow(QMainWindow):
self.loadpilotevent.setEnabled(False)
self.compare_action.setEnabled(False)
self.qualities_action.setEnabled(False)
self.eventlist_xml_action.setEnabled(False)
self.locateEventAction.setEnabled(False)
if not refresh_plot:
self.wf_scroll_area.setVisible(False)
@ -2541,7 +2561,13 @@ class MainWindow(QMainWindow):
self.drawPicks(station)
self.draw()
if self.nextStation:
if not self.get_loc_flag() and self.check4Loc():
self.locateEventAction.setEnabled(True)
self.set_loc_flag(True)
elif self.get_loc_flag() and not self.check4Loc():
self.set_loc_flag(False)
self.pickDialog(wfID - 1)
else:
self.update_status('picks discarded ({0})'.format(station))
if not self.get_loc_flag() and self.check4Loc():

View File

@ -30,6 +30,7 @@
<file>icons/openloc.png</file>
<file>icons/compare_button.png</file>
<file>icons/pick_qualities_button.png</file>
<file>icons/eventlist_xml_button.png</file>
<file>icons/locate_button.png</file>
<file>icons/Matlab_PILOT_icon.png</file>
<file>icons/printer.png</file>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Script to get event parameters from PyLoT-xml file to write
them into eventlist.
LK, igem, 03/2021
Edited for use in PyLoT
JG, igem, 01/2022
"""
import pdb
import os
import argparse
import numpy as np
import matplotlib.pyplot as plt
from obspy.core.event import read_events
from pyproj import Proj
import glob
"""
Creates an eventlist file summarizing all events found in a certain folder. Only called by pressing UI Button eventlis_xml_action
:rtype:
:param path: Path to root folder where single Event folder are to found
"""
def geteventlistfromxml(path, outpath):
p = Proj(proj='utm', zone=32, ellps='WGS84')
# open eventlist file and write header
evlist = outpath + '/eventlist'
evlistobj = open(evlist, 'w')
evlistobj.write('EventID Date To Lat Lon EAST NORTH Dep Ml NoP NoS RMS errH errZ Gap \n')
# 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 location parameters from {}".format(names))
cat = read_events(names)
try:
st = cat.events[0].origins[0].time
Lat = cat.events[0].origins[0].latitude
Lon = cat.events[0].origins[0].longitude
EAST, NORTH = p(Lon, Lat)
Dep = cat.events[0].origins[0].depth / 1000
Ml = cat.events[0].magnitudes[1].mag
NoP = []
NoS = []
except IndexError:
print ('Insufficient data found for event (not localised): ' + names.split('/')[-1].split('_')[-1][:-4] + ' Skipping event for eventlist.' )
continue
for i in range(len(cat.events[0].origins[0].arrivals)):
if cat.events[0].origins[0].arrivals[i].phase == 'P':
NoP.append(cat.events[0].origins[0].arrivals[i].phase)
elif cat.events[0].origins[0].arrivals[i].phase == 'S':
NoS.append(cat.events[0].origins[0].arrivals[i].phase)
#NoP = cat.events[0].origins[0].quality.used_station_count
errH = cat.events[0].origins[0].origin_uncertainty.max_horizontal_uncertainty
errZ = cat.events[0].origins[0].depth_errors.uncertainty
Gap = cat.events[0].origins[0].quality.azimuthal_gap
#evID = names.split('/')[6]
evID = names.split('/')[-1].split('_')[-1][:-4]
Date = str(st.year) + str('%02d' % st.month) + str('%02d' % st.day)
To = str('%02d' % st.hour) + str('%02d' % st.minute) + str('%02d' % st.second) + \
'.' + str('%06d' % st.microsecond)
# write into eventlist
evlistobj.write('%s %s %s %9.6f %9.6f %13.6f %13.6f %8.6f %3.1f %d %d NaN %d %d %d\n' %(evID, \
Date, To, Lat, Lon, EAST, NORTH, Dep, Ml, len(NoP), len(NoS), errH, errZ, Gap))
print ('Adding Event ' + names.split('/')[-1].split('_')[-1][:-4] + ' to eventlist')
print('Eventlist created and saved in: ' + outpath)
evlistobj.close()

View File

@ -0,0 +1,139 @@
#!/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 argparse
import numpy as np
import matplotlib.pyplot as plt
from obspy.core.event import read_events
import glob
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()

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pdb
import glob
import matplotlib.pyplot as plt
import numpy as np
@ -511,14 +511,14 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
:param eventinfo: optional, needed for VELEST-cnv file
and FOCMEC- and HASH-input files
:type eventinfo: `obspy.core.event.Event` object
"""
"""
if fformat == 'NLLoc':
print("Writing phases to %s for NLLoc" % filename)
fid = open("%s" % filename, 'w')
# write header
fid.write('# EQEVENT: %s Label: EQ%s Loc: X 0.00 Y 0.00 Z 10.00 OT 0.00 \n' %
(parameter.get('database'), parameter.get('eventID')))
arrivals = chooseArrivals(arrivals)
for key in arrivals:
# P onsets
if arrivals[key].has_key('P'):
@ -573,6 +573,8 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
except KeyError as e:
print(str(e) + '; no weight set during processing')
Ao = arrivals[key]['S']['Ao'] # peak-to-peak amplitude
if Ao == None:
Ao = 0.0
#fid.write('%s ? ? ? S %s %d%02d%02d %02d%02d %7.4f GAU 0 0 0 0 %d \n' % (key,
fid.write('%s ? ? ? S %s %d%02d%02d %02d%02d %7.4f GAU 0 %9.2f 0 0 %d \n' % (key,
fm,
@ -592,6 +594,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
# write header
fid.write(' %s\n' %
parameter.get('eventID'))
arrivals = chooseArrivals(arrivals)
for key in arrivals:
if arrivals[key]['P']['weight'] < 4:
stat = key
@ -668,6 +671,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
fid = open("%s" % filename, 'w')
# write header
fid.write('%s, event %s \n' % (parameter.get('database'), parameter.get('eventID')))
arrivals = chooseArrivals(arrivals)
for key in arrivals:
# P onsets
if arrivals[key].has_key('P') and arrivals[key]['P']['mpp'] is not None:
@ -763,30 +767,33 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
evt = ope.Event(resource_id=eventinfo['resource_id'])
evt.picks = arrivals
arrivals = picksdict_from_picks(evt)
for key in arrivals:
# check for automatic and manual picks
# prefer manual picks
usedarrivals = chooseArrival(arrivals)
for key in usedarrivals:
# P onsets
if arrivals[key].has_key('P'):
if arrivals[key]['P']['weight'] < 4:
if usedarrivals[key].has_key('P'):
if usedarrivals[key]['P']['weight'] < 4:
n += 1
stat = key
if len(stat) > 4: # VELEST handles only 4-string station IDs
stat = stat[1:5]
Ponset = arrivals[key]['P']['mpp']
Pweight = arrivals[key]['P']['weight']
Ponset = usedarrivals[key]['P']['mpp']
Pweight = usedarrivals[key]['P']['weight']
Prt = Ponset - stime # onset time relative to source time
if n % 6 != 0:
fid.write('%-4sP%d%6.2f' % (stat, Pweight, Prt))
else:
fid.write('%-4sP%d%6.2f\n' % (stat, Pweight, Prt))
# S onsets
if arrivals[key].has_key('S'):
if arrivals[key]['S']['weight'] < 4:
if usedarrivals[key].has_key('S'):
if usedarrivals[key]['S']['weight'] < 4:
n += 1
stat = key
if len(stat) > 4: # VELEST handles only 4-string station IDs
stat = stat[1:5]
Sonset = arrivals[key]['S']['mpp']
Sweight = arrivals[key]['S']['weight']
Sonset = usedarrivals[key]['S']['mpp']
Sweight = usedarrivals[key]['S']['weight']
Srt = Ponset - stime # onset time relative to source time
if n % 6 != 0:
fid.write('%-4sS%d%6.2f' % (stat, Sweight, Srt))
@ -804,8 +811,12 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
print("No source origin calculated yet, thus no hypoDD-infile creation possible!")
return
stime = eventsource['time']
event = parameter.get('eventID')
hddID = event.split('.')[0][1:5]
try:
event = eventinfo['pylot_id']
hddID = event.split('.')[0][1:5]
except:
print ("Error 1111111!")
hddID = "00000"
# write header
fid.write('# %d %d %d %d %d %5.2f %7.4f +%6.4f %7.4f %4.2f 0.1 0.5 %4.2f %s\n' % (
stime.year, stime.month, stime.day, stime.hour, stime.minute, stime.second,
@ -817,17 +828,20 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
evt = ope.Event(resource_id=eventinfo['resource_id'])
evt.picks = arrivals
arrivals = picksdict_from_picks(evt)
for key in arrivals:
if arrivals[key].has_key('P'):
# check for automatic and manual picks
# prefer manual picks
usedarrivals = chooseArrival(arrivals)
for key in usedarrivals:
if usedarrivals[key].has_key('P'):
# P onsets
if arrivals[key]['P']['weight'] < 4:
Ponset = arrivals[key]['P']['mpp']
if usedarrivals[key]['P']['weight'] < 4:
Ponset = usedarrivals[key]['P']['mpp']
Prt = Ponset - stime # onset time relative to source time
fid.write('%s %6.3f 1 P\n' % (key, Prt))
if arrivals[key].has_key('S'):
if usedarrivals[key].has_key('S'):
# S onsets
if arrivals[key]['S']['weight'] < 4:
Sonset = arrivals[key]['S']['mpp']
if usedarrivals[key]['S']['weight'] < 4:
Sonset = usedarrivals[key]['S']['mpp']
Srt = Sonset - stime # onset time relative to source time
fid.write('%-5s %6.3f 1 S\n' % (key, Srt))
@ -865,9 +879,12 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
evt = ope.Event(resource_id=eventinfo['resource_id'])
evt.picks = arrivals
arrivals = picksdict_from_picks(evt)
for key in arrivals:
if arrivals[key].has_key('P'):
if arrivals[key]['P']['weight'] < 4 and arrivals[key]['P']['fm'] is not None:
# check for automatic and manual picks
# prefer manual picks
usedarrivals = chooseArrival(arrivals)
for key in usedarrivals:
if usedarrivals[key].has_key('P'):
if usedarrivals[key]['P']['weight'] < 4 and usedarrivals[key]['P']['fm'] is not None:
stat = key
for i in range(len(picks)):
station = picks[i].waveform_id.station_code
@ -886,7 +903,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
fid.write('%-4s %6.2f %6.2f%s \n' % (stat,
az,
inz,
arrivals[key]['P']['fm']))
usedarrivals[key]['P']['fm']))
break
fid.close()
@ -944,7 +961,8 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
eventsource['quality']['used_phase_count'],
erh, erz, eventinfo.magnitudes[0]['mag'],
hashID))
# Prefer Manual Picks over automatic ones if possible
arrivals = chooseArrivals(arrivals)
# write phase lines
for key in arrivals:
if arrivals[key].has_key('P'):
@ -991,6 +1009,25 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
fid1.close()
fid2.close()
def chooseArrival(arrivals):
"""
takes arrivals and returns the manual picks if manual and automatic ones are there
returns automatic picks if only automatic picks are there
:param arrivals: 'dictionary' with automatic and or manual arrivals
: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
print("=== CHOOSE ===")
if len(arrivals) > 2:
return arrivals
if arrivals['auto'] and arrivals['manual']:
usedarrivals = arrivals['manual']
elif arrivals['auto']:
usedarrivals = arrivals['auto']
elif arrivals['manual']:
usedarrivals = arrivals['manual']
return usedarrivals
def merge_picks(event, picks):
"""

View File

@ -34,7 +34,7 @@ from PySide2.QtGui import QIcon, QPixmap, QKeySequence
from PySide2.QtWidgets import QAction, QApplication, QCheckBox, QComboBox, \
QDateTimeEdit, QDialog, QDialogButtonBox, QDoubleSpinBox, QGroupBox, \
QGridLayout, QLabel, QLineEdit, QMessageBox, \
QSpinBox, QTabWidget, QToolBar, QVBoxLayout, QHBoxLayout, QWidget, \
QTabWidget, QToolBar, QVBoxLayout, QHBoxLayout, QWidget, \
QPushButton, QFileDialog, QInputDialog
from PySide2.QtCore import QSettings, Qt, QUrl, Signal, Slot
from PySide2.QtWebEngineWidgets import QWebEngineView as QWebView
@ -70,6 +70,18 @@ else:
# icons_rc = icons_rc
class QSpinBox(QtWidgets.QSpinBox):
''' Custom SpinBox, insensitive to Mousewheel (prevents accidental changes when scrolling through parameters) '''
def wheelEvent(self, event):
event.ignore()
class QDoubleSpinBox(QtWidgets.QDoubleSpinBox):
''' Custom DoubleSpinBox, insensitive to Mousewheel (prevents accidental changes when scrolling through parameters) '''
def wheelEvent(self, event):
event.ignore()
def getDataType(parent):
type = QInputDialog().getItem(parent, "Select phases type", "Type:",
["manual", "automatic"])
@ -4027,11 +4039,11 @@ class PylotParaBox(QtWidgets.QWidget):
if typ == str:
box = QtWidgets.QLineEdit()
elif typ == float:
box = QtWidgets.QDoubleSpinBox()
box = QDoubleSpinBox()
box.setDecimals(4)
box.setRange(-10e4, 10e4)
elif typ == int:
box = QtWidgets.QSpinBox()
box = QSpinBox()
elif typ == bool:
box = QtWidgets.QCheckBox()
else:
@ -4224,7 +4236,7 @@ class PylotParaBox(QtWidgets.QWidget):
def setValue(self, box, value):
if type(box) == QtWidgets.QLineEdit:
box.setText(str(value))
elif type(box) == QtWidgets.QSpinBox or type(box) == QtWidgets.QDoubleSpinBox:
elif type(box) == QSpinBox or type(box) == QDoubleSpinBox:
if not value:
value = 0.
box.setValue(value)
@ -4241,7 +4253,7 @@ class PylotParaBox(QtWidgets.QWidget):
def getValue(self, box):
if type(box) == QtWidgets.QLineEdit:
value = str(box.text())
elif type(box) == QtWidgets.QSpinBox or type(box) == QtWidgets.QDoubleSpinBox:
elif type(box) == QSpinBox or type(box) == QDoubleSpinBox:
value = box.value()
elif type(box) == QtWidgets.QCheckBox:
value = box.isChecked()
@ -4839,7 +4851,7 @@ class GraphicsTab(PropTab):
if not nth_sample:
nth_sample = 1
self.spinbox_nth_sample = QtWidgets.QSpinBox()
self.spinbox_nth_sample = QSpinBox()
label = QLabel('nth sample')
label.setToolTip('Plot every nth sample (to speed up plotting)')
self.spinbox_nth_sample.setMinimum(1)