Compare commits

...

5 Commits

Author SHA1 Message Date
93b7de3baa [update] raising PickingFailedException when CF cannot be calculated due to missing signal (too short waveform)
[update] raising PickingFailedException when CF cannot be calculated due to missing signal (too short waveform)
2024-06-05 14:31:09 +02:00
05642e775b [minor] some tweaks (convenience)
[update] raising PickingFailedException when CF cannot be calculated due to missing signal (too short waveform)
2024-06-05 14:31:07 +02:00
47205ca493 [update] improved calculation of smoothed AIC. Old code always created an artificial value and a np.nan at the array start 2024-06-05 14:31:07 +02:00
5c7f0b56eb [update] improved SearchFileByExtensionDialog widget 2024-06-05 14:19:17 +02:00
c574031931 [bugfix] the implementation approach of STA/LTA inside characteristic function calculation (skewness/kurtosis) corrupted the old, working code due to a mistake in the logic 2024-06-05 14:17:57 +02:00
6 changed files with 37 additions and 25 deletions

View File

@ -3687,10 +3687,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))

View File

@ -20,7 +20,7 @@ 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
@ -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):

View File

@ -20,6 +20,8 @@ import numpy as np
from scipy import signal from scipy import signal
from obspy.core import Stream from obspy.core import Stream
from pylot.core.pick.utils import PickingFailedException
class CharacteristicFunction(object): class CharacteristicFunction(object):
""" """
@ -293,7 +295,7 @@ class HOScf(CharacteristicFunction):
if j < 4: if j < 4:
LTA[j] = 0 LTA[j] = 0
STA[j] = 0 STA[j] = 0
elif j <= ista: elif j <= ista and self.getOrder() == 2:
lta = (y[j] + lta * (j - 1)) / j lta = (y[j] + lta * (j - 1)) / j
if self.getOrder() == 2: if self.getOrder() == 2:
sta = (y[j] + sta * (j - 1)) / j sta = (y[j] + sta * (j - 1)) / j
@ -488,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

View File

@ -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))

View File

@ -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
@ -1516,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

View File

@ -1602,9 +1602,9 @@ class SearchFileByExtensionDialog(QtWidgets.QDialog):
self.tableWidget = QtWidgets.QTableWidget() self.tableWidget = QtWidgets.QTableWidget()
tableWidget = self.tableWidget tableWidget = self.tableWidget
tableWidget.setColumnCount(2) tableWidget.setColumnCount(3)
tableWidget.setRowCount(len(self.events)) tableWidget.setRowCount(len(self.events))
tableWidget.setHorizontalHeaderLabels(('Filename', 'Last modified')) tableWidget.setHorizontalHeaderLabels(('Event ID', 'Filename', 'Last modified'))
tableWidget.setEditTriggers(tableWidget.NoEditTriggers) tableWidget.setEditTriggers(tableWidget.NoEditTriggers)
tableWidget.setSortingEnabled(True) tableWidget.setSortingEnabled(True)
header = tableWidget.horizontalHeader() header = tableWidget.horizontalHeader()
@ -1628,6 +1628,7 @@ class SearchFileByExtensionDialog(QtWidgets.QDialog):
self.tableWidget.clearContents() self.tableWidget.clearContents()
for index, event in enumerate(self.events): for index, event in enumerate(self.events):
filename = get_pylot_eventfile_with_extension(event, fext) filename = get_pylot_eventfile_with_extension(event, fext)
self.tableWidget.setItem(index, 0, QtWidgets.QTableWidgetItem(f'{event.pylot_id}'))
if filename: if filename:
self.filepaths.append(filename) self.filepaths.append(filename)
ts = int(os.path.getmtime(filename)) ts = int(os.path.getmtime(filename))
@ -1635,8 +1636,8 @@ class SearchFileByExtensionDialog(QtWidgets.QDialog):
# create QTableWidgetItems of filepath and last modification time # create QTableWidgetItems of filepath and last modification time
fname_item = QtWidgets.QTableWidgetItem(f'{filename}') fname_item = QtWidgets.QTableWidgetItem(f'{filename}')
ts_item = QtWidgets.QTableWidgetItem(f'{datetime.datetime.fromtimestamp(ts)}') ts_item = QtWidgets.QTableWidgetItem(f'{datetime.datetime.fromtimestamp(ts)}')
self.tableWidget.setItem(index, 0, fname_item) self.tableWidget.setItem(index, 1, fname_item)
self.tableWidget.setItem(index, 1, ts_item) self.tableWidget.setItem(index, 2, ts_item)
# TODO: Idea -> only refresh if table contents changed. Use selection to load only a subset of files # TODO: Idea -> only refresh if table contents changed. Use selection to load only a subset of files
if len(self.filepaths) > 0: if len(self.filepaths) > 0: