Compare commits
38 Commits
feature/da
...
cb457fc7ec
| Author | SHA1 | Date | |
|---|---|---|---|
| cb457fc7ec | |||
| eb077e4bd6 | |||
| 2b01e8207e | |||
| 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 | |||
| b3fdbc811e | |||
| 9fce4998d3 | |||
| c468bfbe84 | |||
| 4861d33e9a | |||
| f5f4635c3d | |||
| b12d92eebb | |||
| e9da81376e | |||
| e68fc849f0 | |||
| efb117177c |
125
PyLoT.py
125
PyLoT.py
@@ -25,6 +25,7 @@ https://www.iconfinder.com/iconsets/flavour
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
@@ -60,7 +61,7 @@ except ImportError:
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
from pylot.core.analysis.magnitude import LocalMagnitude, MomentMagnitude, calcsourcespec
|
||||
from pylot.core.analysis.magnitude import LocalMagnitude, MomentMagnitude
|
||||
from pylot.core.io.data import Data
|
||||
from pylot.core.io.inputs import FilterOptions, PylotParameter
|
||||
from autoPyLoT import autoPyLoT
|
||||
@@ -72,11 +73,11 @@ from pylot.core.util.errors import DatastructureError, \
|
||||
OverwriteError
|
||||
from pylot.core.util.connection import checkurl
|
||||
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, \
|
||||
pick_linestyle_plt, identifyPhaseID, excludeQualityClasses, \
|
||||
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.event import Event
|
||||
from pylot.core.io.location import create_creation_info, create_event
|
||||
@@ -84,7 +85,7 @@ from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
|
||||
SourceSpecWindow, ChooseWaveFormWindow, SpectrogramTab
|
||||
SpectrogramTab, SearchFileByExtensionDialog
|
||||
from pylot.core.util.array_map import Array_map
|
||||
from pylot.core.util.structure import DATASTRUCTURE
|
||||
from pylot.core.util.thread import Thread, Worker
|
||||
@@ -113,11 +114,7 @@ class MainWindow(QMainWindow):
|
||||
def __init__(self, parent=None, infile=None, reset_qsettings=False):
|
||||
super(MainWindow, self).__init__(parent)
|
||||
|
||||
# check for default pylot.in-file
|
||||
if not infile:
|
||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
||||
print('Using default input file {}'.format(infile))
|
||||
if os.path.isfile(infile) is False:
|
||||
if infile and os.path.isfile(infile) is False:
|
||||
infile = QFileDialog().getOpenFileName(caption='Choose PyLoT-input file')[0]
|
||||
|
||||
if not os.path.exists(infile):
|
||||
@@ -197,7 +194,7 @@ class MainWindow(QMainWindow):
|
||||
if settings.value("user/FullName", None) is None:
|
||||
fulluser = QInputDialog.getText(self, "Enter Name:", "Full name")
|
||||
settings.setValue("user/FullName", fulluser)
|
||||
settings.setValue("user/Login", getLogin())
|
||||
settings.setValue("user/Login", get_login())
|
||||
if settings.value("agency_id", None) is None:
|
||||
agency = QInputDialog.getText(self,
|
||||
"Enter authority/institution name:",
|
||||
@@ -254,7 +251,7 @@ class MainWindow(QMainWindow):
|
||||
self._inputs.reset_defaults()
|
||||
# check for default pylot.in-file
|
||||
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.infile = infile
|
||||
|
||||
@@ -1007,18 +1004,17 @@ class MainWindow(QMainWindow):
|
||||
return
|
||||
refresh = False
|
||||
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_():
|
||||
return
|
||||
fext = sld.lineEdit.text()
|
||||
# fext = '.xml'
|
||||
|
||||
filenames = sld.getChecked()
|
||||
for event in events:
|
||||
path = event.path
|
||||
eventname = path.split('/')[-1] # or event.pylot_id
|
||||
filename = os.path.join(path, 'PyLoT_' + eventname + fext)
|
||||
if os.path.isfile(filename):
|
||||
self.load_data(filename, draw=False, event=event, overwrite=True)
|
||||
refresh = True
|
||||
for filename in filenames:
|
||||
if os.path.isfile(filename) and event.pylot_id in filename:
|
||||
self.load_data(filename, draw=False, event=event, ask_user=True, merge_strategy=sld.merge_strategy)
|
||||
refresh = True
|
||||
if not refresh:
|
||||
return
|
||||
if self.get_current_event().pylot_picks:
|
||||
@@ -1026,8 +1022,8 @@ class MainWindow(QMainWindow):
|
||||
self.fill_eventbox()
|
||||
self.setDirty(True)
|
||||
|
||||
def load_data(self, fname=None, loc=False, draw=True, event=None, overwrite=False):
|
||||
if not overwrite:
|
||||
def load_data(self, fname=None, loc=False, draw=True, event=None, ask_user=False, merge_strategy='Overwrite'):
|
||||
if not ask_user:
|
||||
if not self.okToContinue():
|
||||
return
|
||||
if fname is None:
|
||||
@@ -1041,9 +1037,12 @@ class MainWindow(QMainWindow):
|
||||
data = Data(self, event)
|
||||
try:
|
||||
data_new = Data(self, evtdata=str(fname))
|
||||
# MP MP commented because adding several picks might cause inconsistencies
|
||||
data = data_new
|
||||
# data += data_new
|
||||
if merge_strategy == 'Overwrite':
|
||||
data = data_new
|
||||
elif merge_strategy == 'Merge':
|
||||
data += data_new
|
||||
else:
|
||||
raise NotImplementedError(f'Unknown merge strategy: {merge_strategy}')
|
||||
except ValueError:
|
||||
qmb = QMessageBox(self, icon=QMessageBox.Question,
|
||||
text='Warning: Missmatch in event identifiers {} and {}. Continue?'.format(
|
||||
@@ -1408,25 +1407,28 @@ class MainWindow(QMainWindow):
|
||||
|
||||
for id, event in enumerate(self.project.eventlist):
|
||||
event_path = event.path
|
||||
phaseErrors = {'P': self._inputs['timeerrorsP'],
|
||||
'S': self._inputs['timeerrorsS']}
|
||||
#phaseErrors = {'P': self._inputs['timeerrorsP'],
|
||||
# 'S': self._inputs['timeerrorsS']}
|
||||
|
||||
ma_props = {'manual': event.pylot_picks,
|
||||
'auto': event.pylot_autopicks}
|
||||
ma_count = {'manual': 0,
|
||||
'auto': 0}
|
||||
ma_count_total = {'manual': 0,
|
||||
'auto': 0}
|
||||
man_au_picks = {'manual': event.pylot_picks,
|
||||
'auto': event.pylot_autopicks}
|
||||
npicks = {'manual': {'P': 0, 'S': 0},
|
||||
'auto': {'P': 0, 'S': 0}}
|
||||
npicks_total = {'manual': {'P': 0, 'S': 0},
|
||||
'auto': {'P': 0, 'S': 0}}
|
||||
|
||||
for ma in ma_props.keys():
|
||||
if ma_props[ma]:
|
||||
for picks in ma_props[ma].values():
|
||||
for ma in man_au_picks.keys():
|
||||
if man_au_picks[ma]:
|
||||
for picks in man_au_picks[ma].values():
|
||||
for phasename, pick in picks.items():
|
||||
if not type(pick) in [dict, AttribDict]:
|
||||
continue
|
||||
phase_ID = identifyPhaseID(phasename)
|
||||
if not phase_ID in npicks[ma].keys():
|
||||
continue
|
||||
if pick.get('spe'):
|
||||
ma_count[ma] += 1
|
||||
ma_count_total[ma] += 1
|
||||
npicks[ma][phase_ID] += 1
|
||||
npicks_total[ma][phase_ID] += 1
|
||||
|
||||
event_ref = event.isRefEvent()
|
||||
event_test = event.isTestEvent()
|
||||
@@ -1461,16 +1463,23 @@ class MainWindow(QMainWindow):
|
||||
if event.dirty:
|
||||
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_lon = QStandardItem('{}'.format(lon))
|
||||
item_depth = QStandardItem('{}'.format(depth))
|
||||
item_localmag = QStandardItem('{}'.format(localmag))
|
||||
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_nap = QStandardItem('{}({})'.format(ma_count['auto'], ma_count_total['auto']))
|
||||
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_test = QStandardItem() # str(event_test))
|
||||
if event_ref:
|
||||
@@ -1891,6 +1900,7 @@ class MainWindow(QMainWindow):
|
||||
# which will read in data input twice. Therefore current tab is changed to 0
|
||||
# in loadProject before calling this function.
|
||||
self.fill_eventbox()
|
||||
#print(f'{self.get_current_event()=}')
|
||||
plotted = False
|
||||
if self.tabs.currentIndex() == 2:
|
||||
self.init_event_table()
|
||||
@@ -1925,7 +1935,6 @@ class MainWindow(QMainWindow):
|
||||
self.spectro_layout.addWidget(newSpectroWidget)
|
||||
self.spectroWidget = newSpectroWidget
|
||||
|
||||
|
||||
def newWF(self, event=None, plot=True):
|
||||
'''
|
||||
Load new data and plot if necessary.
|
||||
@@ -1983,6 +1992,8 @@ class MainWindow(QMainWindow):
|
||||
# ans = False
|
||||
|
||||
settings = QSettings()
|
||||
# process application events to wait for event items to appear in event box
|
||||
QApplication.processEvents()
|
||||
curr_event = self.get_current_event()
|
||||
if not curr_event:
|
||||
print('Could not find current event. Try reload?')
|
||||
@@ -1990,8 +2001,8 @@ class MainWindow(QMainWindow):
|
||||
|
||||
if len(curr_event.origins) > 0:
|
||||
origin_time = curr_event.origins[0].time
|
||||
tstart = settings.value('tstart') if get_None(settings.value('tstart')) else 0
|
||||
tstop = settings.value('tstop') if get_None(settings.value('tstop')) 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
|
||||
tstart = origin_time + float(tstart)
|
||||
tstop = origin_time + float(tstop)
|
||||
else:
|
||||
@@ -2138,7 +2149,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def finish_pg_plot(self):
|
||||
self.getPlotWidget().updateWidget()
|
||||
plots, gaps = self.wfp_thread.data
|
||||
plots = self.wfp_thread.data
|
||||
# do not show plot if no data are given
|
||||
self.wf_scroll_area.setVisible(len(plots) > 0)
|
||||
self.no_data_label.setVisible(not len(plots) > 0)
|
||||
@@ -2306,14 +2317,14 @@ class MainWindow(QMainWindow):
|
||||
# wfst += self.get_data().getWFData().select(component=alter_comp)
|
||||
plotWidget = self.getPlotWidget()
|
||||
self.adjustPlotHeight()
|
||||
if get_bool(settings.value('large_dataset')):
|
||||
if get_bool(settings.value('large_dataset')) == True:
|
||||
self.plot_method = 'fast'
|
||||
else:
|
||||
self.plot_method = 'normal'
|
||||
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)
|
||||
plots, gaps = rval if rval else ([], [])
|
||||
return plots, gaps
|
||||
plots = rval if rval else []
|
||||
return plots
|
||||
|
||||
def adjustPlotHeight(self):
|
||||
if self.pg:
|
||||
@@ -3002,10 +3013,16 @@ class MainWindow(QMainWindow):
|
||||
event = self.get_current_event()
|
||||
event.pylot_picks = {}
|
||||
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.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):
|
||||
# if picktype not specified, draw both
|
||||
if not stime:
|
||||
@@ -3647,7 +3664,7 @@ class MainWindow(QMainWindow):
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_status(self, message, duration=5000):
|
||||
def update_status(self, message, duration=10000):
|
||||
self.statusBar().showMessage(message, duration)
|
||||
if self.get_data() is not None:
|
||||
if not self.get_current_event() or not self.project.location:
|
||||
@@ -3700,10 +3717,13 @@ class MainWindow(QMainWindow):
|
||||
if not self.okToContinue():
|
||||
return
|
||||
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]
|
||||
if not fnm:
|
||||
return
|
||||
settings.setValue('current_project_path', os.path.split(fnm)[0])
|
||||
if not os.path.exists(fnm):
|
||||
QMessageBox.warning(self, 'Could not open file',
|
||||
'Could not open project file {}. File does not exist.'.format(fnm))
|
||||
@@ -3821,7 +3841,8 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.okToContinue():
|
||||
self.logwidget.close()
|
||||
if hasattr(self, 'logwidget'):
|
||||
self.logwidget.close()
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
20
autoPyLoT.py
20
autoPyLoT.py
@@ -28,7 +28,7 @@ from pylot.core.util.dataprocessing import restitute_data, Metadata
|
||||
from pylot.core.util.defaults import SEPARATOR
|
||||
from pylot.core.util.event import Event
|
||||
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
|
||||
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)
|
||||
print(splash)
|
||||
|
||||
parameter = get_None(parameter)
|
||||
inputfile = get_None(inputfile)
|
||||
eventid = get_None(eventid)
|
||||
parameter = get_none(parameter)
|
||||
inputfile = get_none(inputfile)
|
||||
eventid = get_none(eventid)
|
||||
|
||||
fig_dict = 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']
|
||||
|
||||
if not parameter:
|
||||
if 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)
|
||||
if not inputfile:
|
||||
print('Using default input parameter')
|
||||
parameter = PylotParameter(inputfile)
|
||||
else:
|
||||
if not type(parameter) == PylotParameter:
|
||||
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)
|
||||
|
||||
# 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
|
||||
# get NLLoc-root path
|
||||
nllocroot = parameter.get('nllocroot')
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
#$ -l low
|
||||
#$ -cwd
|
||||
#$ -pe smp 40
|
||||
#$ -l mem=2G
|
||||
#$ -l h_vmem=2G
|
||||
##$ -l mem=3G
|
||||
#$ -l h_vmem=6G
|
||||
#$ -l os=*stretch
|
||||
|
||||
conda activate pylot_38
|
||||
conda activate pylot_311
|
||||
|
||||
python ./autoPyLoT.py -i /home/marcel/.pylot/pylot_janis_noisy.in -c $NSLOTS
|
||||
python ./autoPyLoT.py -i /home/marcel/.pylot/pylot_adriaarray.in -c 20 -dmt processed
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import copy
|
||||
import logging
|
||||
import os
|
||||
|
||||
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.obspyDMT_interface import qml_from_obspyDMT
|
||||
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):
|
||||
@@ -64,7 +65,7 @@ class Data(object):
|
||||
elif 'LOC' in evtdata:
|
||||
raise NotImplementedError('PILOT location information '
|
||||
'read support not yet '
|
||||
'implemeted.')
|
||||
'implemented.')
|
||||
elif 'event.pkl' in evtdata:
|
||||
evtdata = qml_from_obspyDMT(evtdata)
|
||||
else:
|
||||
@@ -408,18 +409,16 @@ class Data(object):
|
||||
not implemented: {1}'''.format(evtformat, e))
|
||||
if fnext == '_focmec.in':
|
||||
try:
|
||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
||||
print('Using default input file {}'.format(infile))
|
||||
parameter = PylotParameter(infile)
|
||||
parameter = PylotParameter()
|
||||
logging.warning('Using default input parameter')
|
||||
focmec.export(picks_copy, fnout + fnext, parameter, eventinfo=self.get_evt_data())
|
||||
except KeyError as e:
|
||||
raise KeyError('''{0} export format
|
||||
not implemented: {1}'''.format(evtformat, e))
|
||||
if fnext == '.pha':
|
||||
try:
|
||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
||||
print('Using default input file {}'.format(infile))
|
||||
parameter = PylotParameter(infile)
|
||||
parameter = PylotParameter()
|
||||
logging.warning('Using default input parameter')
|
||||
hypodd.export(picks_copy, fnout + fnext, parameter, eventinfo=self.get_evt_data())
|
||||
except KeyError as e:
|
||||
raise KeyError('''{0} export format
|
||||
@@ -458,6 +457,11 @@ class Data(object):
|
||||
:param fnames_alt: alternative data to show (e.g. synthetic/processed)
|
||||
: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.wforiginal = None
|
||||
self.wf_alt = Stream()
|
||||
@@ -467,8 +471,8 @@ class Data(object):
|
||||
self.tstop = tstop
|
||||
|
||||
# remove directories
|
||||
fnames = [fname for fname in fnames if not os.path.isdir(fname)]
|
||||
fnames_alt = [fname for fname in fnames_alt if not os.path.isdir(fname)]
|
||||
fnames = check_fname_exists(fnames)
|
||||
fnames_alt = check_fname_exists(fnames_alt)
|
||||
|
||||
# if obspy_dmt:
|
||||
# wfdir = 'raw'
|
||||
@@ -496,7 +500,9 @@ class Data(object):
|
||||
# remove possible underscores in station names
|
||||
# self.wfdata = remove_underscores(self.wfdata)
|
||||
# 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
|
||||
if checkRotated and metadata is not None:
|
||||
self.wfdata = check4rotated(self.wfdata, metadata, verbosity=0)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from obspy import UTCDateTime
|
||||
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):
|
||||
@@ -61,7 +61,7 @@ def create_creation_info(agency_id=None, creation_time=None, author=None):
|
||||
:return:
|
||||
'''
|
||||
if author is None:
|
||||
author = getLogin()
|
||||
author = get_login()
|
||||
if creation_time is None:
|
||||
creation_time = UTCDateTime()
|
||||
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" \
|
||||
"UTCDateTime object"
|
||||
hid = getHash(timetohash)
|
||||
hid = get_hash(timetohash)
|
||||
if hrstr is None:
|
||||
resID = ope.ResourceIdentifier(restype + '/' + hid[0:6])
|
||||
else:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
|
||||
@@ -16,29 +17,10 @@ from pylot.core.io.inputs import PylotParameter
|
||||
from pylot.core.io.location import create_event, \
|
||||
create_magnitude
|
||||
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, loopIdentifyPhase, identifyPhase
|
||||
|
||||
|
||||
def add_amplitudes(event, amplitudes):
|
||||
amplitude_list = []
|
||||
for pick in event.picks:
|
||||
try:
|
||||
a0 = amplitudes[pick.waveform_id.station_code]
|
||||
amplitude = ope.Amplitude(generic_amplitude=a0 * 1e-3)
|
||||
amplitude.unit = 'm'
|
||||
amplitude.category = 'point'
|
||||
amplitude.waveform_id = pick.waveform_id
|
||||
amplitude.magnitude_hint = 'ML'
|
||||
amplitude.pick_id = pick.resource_id
|
||||
amplitude.type = 'AML'
|
||||
amplitude_list.append(amplitude)
|
||||
except KeyError:
|
||||
continue
|
||||
event.amplitudes = amplitude_list
|
||||
return event
|
||||
|
||||
|
||||
def readPILOTEvent(phasfn=None, locfn=None, authority_id='RUB', **kwargs):
|
||||
"""
|
||||
readPILOTEvent - function
|
||||
@@ -58,7 +40,7 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id='RUB', **kwargs):
|
||||
if phasfn is not None and os.path.isfile(phasfn):
|
||||
phases = sio.loadmat(phasfn)
|
||||
phasctime = UTCDateTime(os.path.getmtime(phasfn))
|
||||
phasauthor = getOwner(phasfn)
|
||||
phasauthor = get_owner(phasfn)
|
||||
else:
|
||||
phases = None
|
||||
phasctime = None
|
||||
@@ -66,7 +48,7 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id='RUB', **kwargs):
|
||||
if locfn is not None and os.path.isfile(locfn):
|
||||
loc = sio.loadmat(locfn)
|
||||
locctime = UTCDateTime(os.path.getmtime(locfn))
|
||||
locauthor = getOwner(locfn)
|
||||
locauthor = get_owner(locfn)
|
||||
else:
|
||||
loc = None
|
||||
locctime = None
|
||||
@@ -192,32 +174,7 @@ def convert_pilot_times(time_array):
|
||||
return UTCDateTime(*times)
|
||||
|
||||
|
||||
def picksdict_from_obs(fn):
|
||||
"""
|
||||
create pick dictionary from obs file
|
||||
:param fn: filename
|
||||
:type fn:
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
picks = dict()
|
||||
station_name = str()
|
||||
for line in open(fn, 'r'):
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
else:
|
||||
phase_line = line.split()
|
||||
if not station_name == phase_line[0]:
|
||||
phase = dict()
|
||||
station_name = phase_line[0]
|
||||
phase_name = phase_line[4].upper()
|
||||
pick = UTCDateTime(phase_line[6] + phase_line[7] + phase_line[8])
|
||||
phase[phase_name] = dict(mpp=pick, fm=phase_line[5])
|
||||
picks[station_name] = phase
|
||||
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
|
||||
PyLoT
|
||||
@@ -230,6 +187,7 @@ def picksdict_from_picks(evt):
|
||||
'auto': {}
|
||||
}
|
||||
for pick in evt.picks:
|
||||
errors = None
|
||||
phase = {}
|
||||
station = pick.waveform_id.station_code
|
||||
if pick.waveform_id.channel_code is None:
|
||||
@@ -273,32 +231,28 @@ def picksdict_from_picks(evt):
|
||||
phase['epp'] = epp
|
||||
phase['lpp'] = lpp
|
||||
phase['spe'] = spe
|
||||
try:
|
||||
phase['weight'] = weight
|
||||
except:
|
||||
# get onset weight from uncertainty
|
||||
infile = os.path.join(os.path.expanduser('~'), '.pylot', 'pylot.in')
|
||||
print('Using default input file {}'.format(infile))
|
||||
parameter = PylotParameter(infile)
|
||||
weight = phase.get('weight')
|
||||
if not weight:
|
||||
if not parameter:
|
||||
logging.warning('Using ')
|
||||
logging.warning('Using default input parameter')
|
||||
parameter = PylotParameter()
|
||||
pick.phase_hint = identifyPhase(pick.phase_hint)
|
||||
if pick.phase_hint == 'P':
|
||||
errors = parameter['timeerrorsP']
|
||||
elif pick.phase_hint == 'S':
|
||||
errors = parameter['timeerrorsS']
|
||||
weight = get_quality_class(spe, errors)
|
||||
phase['weight'] = weight
|
||||
if errors:
|
||||
weight = get_quality_class(spe, errors)
|
||||
phase['weight'] = weight
|
||||
phase['channel'] = channel
|
||||
phase['network'] = network
|
||||
phase['picker'] = pick_method
|
||||
try:
|
||||
if pick.polarity == 'positive':
|
||||
phase['fm'] = 'U'
|
||||
elif pick.polarity == 'negative':
|
||||
phase['fm'] = 'D'
|
||||
else:
|
||||
phase['fm'] = 'N'
|
||||
except:
|
||||
print("No FM info available!")
|
||||
if pick.polarity == 'positive':
|
||||
phase['fm'] = 'U'
|
||||
elif pick.polarity == 'negative':
|
||||
phase['fm'] = 'D'
|
||||
else:
|
||||
phase['fm'] = 'N'
|
||||
phase['filter_id'] = filter_id if filter_id is not None else ''
|
||||
|
||||
@@ -375,636 +329,228 @@ def picks_from_picksdict(picks, creation_info=None):
|
||||
return picks_list
|
||||
|
||||
|
||||
def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0):
|
||||
# TODO: change root to datapath
|
||||
db_root = os.path.join(root_dir, db_dir)
|
||||
evt_list = glob.glob1(db_root, 'e????.???.??')
|
||||
|
||||
for evt in evt_list:
|
||||
if verbosity > 0:
|
||||
print('Reassessing event {0}'.format(evt))
|
||||
reassess_pilot_event(root_dir, db_dir, evt, out_dir, fn_param, verbosity)
|
||||
|
||||
|
||||
def reassess_pilot_event(root_dir, db_dir, event_id, out_dir=None, fn_param=None, verbosity=0):
|
||||
from obspy import read
|
||||
|
||||
from pylot.core.io.inputs import PylotParameter
|
||||
from pylot.core.pick.utils import earllatepicker
|
||||
# TODO: change root to datapath
|
||||
|
||||
default = PylotParameter(fn_param, verbosity)
|
||||
|
||||
search_base = os.path.join(root_dir, db_dir, event_id)
|
||||
phases_file = glob.glob(os.path.join(search_base, 'PHASES.mat'))
|
||||
if not phases_file:
|
||||
return
|
||||
if verbosity > 1:
|
||||
print('Opening PILOT phases file: {fn}'.format(fn=phases_file[0]))
|
||||
picks_dict = picksdict_from_pilot(phases_file[0])
|
||||
if verbosity > 0:
|
||||
print('Dictionary read from PHASES.mat:\n{0}'.format(picks_dict))
|
||||
datacheck = list()
|
||||
info = None
|
||||
for station in picks_dict.keys():
|
||||
fn_pattern = os.path.join(search_base, '{0}*'.format(station))
|
||||
try:
|
||||
st = read(fn_pattern)
|
||||
except TypeError as e:
|
||||
if 'Unknown format for file' in e.message:
|
||||
try:
|
||||
st = read(fn_pattern, format='GSE2')
|
||||
except ValueError as e:
|
||||
if e.message == 'second must be in 0..59':
|
||||
info = 'A known Error was raised. Please find the list of corrupted files and double-check these files.'
|
||||
datacheck.append(fn_pattern + ' (time info)\n')
|
||||
continue
|
||||
else:
|
||||
raise ValueError(e.message)
|
||||
except Exception as e:
|
||||
if 'No file matching file pattern:' in e.message:
|
||||
if verbosity > 0:
|
||||
warnings.warn('no waveform data found for station {station}'.format(station=station),
|
||||
RuntimeWarning)
|
||||
datacheck.append(fn_pattern + ' (no data)\n')
|
||||
continue
|
||||
else:
|
||||
raise e
|
||||
else:
|
||||
raise e
|
||||
for phase in picks_dict[station].keys():
|
||||
try:
|
||||
mpp = picks_dict[station][phase]['mpp']
|
||||
except KeyError as e:
|
||||
print(e.message, station)
|
||||
continue
|
||||
sel_st = select_for_phase(st, phase)
|
||||
if not sel_st:
|
||||
msg = 'no waveform data found for station {station}'.format(station=station)
|
||||
warnings.warn(msg, RuntimeWarning)
|
||||
continue
|
||||
stime, etime = full_range(sel_st)
|
||||
rel_pick = mpp - stime
|
||||
epp, lpp, spe = earllatepicker(sel_st,
|
||||
default.get('nfac{0}'.format(phase)),
|
||||
default.get('tsnrz' if phase == 'P' else 'tsnrh'),
|
||||
Pick1=rel_pick,
|
||||
iplot=0,
|
||||
verbosity=0)
|
||||
if epp is None or lpp is None:
|
||||
continue
|
||||
epp = stime + epp
|
||||
lpp = stime + lpp
|
||||
min_diff = 3 * st[0].stats.delta
|
||||
if lpp - mpp < min_diff:
|
||||
lpp = mpp + min_diff
|
||||
if mpp - epp < min_diff:
|
||||
epp = mpp - min_diff
|
||||
picks_dict[station][phase] = dict(epp=epp, mpp=mpp, lpp=lpp, spe=spe)
|
||||
if datacheck:
|
||||
if info:
|
||||
if verbosity > 0:
|
||||
print(info + ': {0}'.format(search_base))
|
||||
fncheck = open(os.path.join(search_base, 'datacheck_list'), 'w')
|
||||
fncheck.writelines(datacheck)
|
||||
fncheck.close()
|
||||
del datacheck
|
||||
# create Event object for export
|
||||
evt = ope.Event(resource_id=event_id)
|
||||
evt.picks = picks_from_picksdict(picks_dict)
|
||||
# write phase information to file
|
||||
if not out_dir:
|
||||
fnout_prefix = os.path.join(root_dir, db_dir, event_id, 'PyLoT_{0}.'.format(event_id))
|
||||
else:
|
||||
out_dir = os.path.join(out_dir, db_dir)
|
||||
if not os.path.isdir(out_dir):
|
||||
os.makedirs(out_dir)
|
||||
fnout_prefix = os.path.join(out_dir, 'PyLoT_{0}.'.format(event_id))
|
||||
evt.write(fnout_prefix + 'xml', format='QUAKEML')
|
||||
|
||||
|
||||
def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
||||
def write_phases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
||||
"""
|
||||
Function of methods to write phases to the following standard file
|
||||
formats used for locating earthquakes:
|
||||
Writes earthquake phase data to different file formats.
|
||||
|
||||
HYPO71, NLLoc, VELEST, HYPOSAT, FOCMEC, and hypoDD
|
||||
|
||||
:param arrivals:dictionary containing all phase information including
|
||||
station ID, phase, first motion, weight (uncertainty), ...
|
||||
:param arrivals: Dictionary containing phase information (station ID, phase, first motion, weight, etc.)
|
||||
:type arrivals: dict
|
||||
|
||||
:param fformat: chosen file format (location routine),
|
||||
choose between NLLoc, HYPO71, HYPOSAT, VELEST,
|
||||
HYPOINVERSE, FOCMEC, and hypoDD
|
||||
:param fformat: File format to write to (e.g., 'NLLoc', 'HYPO71', 'HYPOSAT', 'VELEST', 'HYPODD', 'FOCMEC')
|
||||
:type fformat: str
|
||||
|
||||
:param filename: full path and name of phase file
|
||||
:type filename: string
|
||||
|
||||
:param parameter: all input information
|
||||
:type parameter: object
|
||||
|
||||
:param eventinfo: optional, needed for VELEST-cnv file
|
||||
and FOCMEC- and HASH-input files
|
||||
:type eventinfo: `obspy.core.event.Event` object
|
||||
:param filename: Path and name of the output phase file
|
||||
:type filename: str
|
||||
:param parameter: Additional parameters for writing the phase data
|
||||
:type parameter: object
|
||||
:param eventinfo: Event information needed for specific formats like VELEST, FOCMEC, and HASH
|
||||
:type eventinfo: obspy.core.event.Event
|
||||
"""
|
||||
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) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||
for key in arrivals:
|
||||
# P onsets
|
||||
if 'P' in arrivals[key]:
|
||||
try:
|
||||
fm = arrivals[key]['P']['fm']
|
||||
except KeyError as e:
|
||||
print(e)
|
||||
fm = None
|
||||
if fm is None:
|
||||
fm = '?'
|
||||
onset = arrivals[key]['P']['mpp']
|
||||
year = onset.year
|
||||
month = onset.month
|
||||
day = onset.day
|
||||
hh = onset.hour
|
||||
mm = onset.minute
|
||||
ss = onset.second
|
||||
ms = onset.microsecond
|
||||
ss_ms = ss + ms / 1000000.0
|
||||
pweight = 1 # use pick
|
||||
try:
|
||||
if arrivals[key]['P']['weight'] >= 4:
|
||||
pweight = 0 # do not use pick
|
||||
print("Station {}: Uncertain pick, do not use it!".format(key))
|
||||
except KeyError as e:
|
||||
print(e.message + '; no weight set during processing')
|
||||
fid.write('%s ? ? ? P %s %d%02d%02d %02d%02d %7.4f GAU 0 0 0 0 %d \n' % (key,
|
||||
fm,
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hh,
|
||||
mm,
|
||||
ss_ms,
|
||||
pweight))
|
||||
# S onsets
|
||||
if 'S' in arrivals[key] and arrivals[key]['S']['mpp'] is not None:
|
||||
fm = '?'
|
||||
onset = arrivals[key]['S']['mpp']
|
||||
year = onset.year
|
||||
month = onset.month
|
||||
day = onset.day
|
||||
hh = onset.hour
|
||||
mm = onset.minute
|
||||
ss = onset.second
|
||||
ms = onset.microsecond
|
||||
ss_ms = ss + ms / 1000000.0
|
||||
sweight = 1 # use pick
|
||||
try:
|
||||
if arrivals[key]['S']['weight'] >= 4:
|
||||
sweight = 0 # do not use pick
|
||||
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,
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hh,
|
||||
mm,
|
||||
ss_ms,
|
||||
Ao,
|
||||
sweight))
|
||||
|
||||
fid.close()
|
||||
elif fformat == 'HYPO71':
|
||||
print("Writing phases to %s for HYPO71" % filename)
|
||||
fid = open("%s" % filename, 'w')
|
||||
# write header
|
||||
fid.write(' %s\n' %
|
||||
parameter.get('eventID'))
|
||||
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||
for key in arrivals:
|
||||
if arrivals[key]['P']['weight'] < 4:
|
||||
stat = key
|
||||
if len(stat) > 4: # HYPO71 handles only 4-string station IDs
|
||||
stat = stat[1:5]
|
||||
Ponset = arrivals[key]['P']['mpp']
|
||||
Sonset = arrivals[key]['S']['mpp']
|
||||
pweight = arrivals[key]['P']['weight']
|
||||
sweight = arrivals[key]['S']['weight']
|
||||
fm = arrivals[key]['P']['fm']
|
||||
if fm is None:
|
||||
fm = '-'
|
||||
Ao = arrivals[key]['S']['Ao']
|
||||
if Ao is None:
|
||||
Ao = ''
|
||||
else:
|
||||
Ao = str('%7.2f' % Ao)
|
||||
year = Ponset.year
|
||||
if year >= 2000:
|
||||
year = year - 2000
|
||||
else:
|
||||
year = year - 1900
|
||||
month = Ponset.month
|
||||
day = Ponset.day
|
||||
hh = Ponset.hour
|
||||
mm = Ponset.minute
|
||||
ss = Ponset.second
|
||||
ms = Ponset.microsecond
|
||||
ss_ms = ss + ms / 1000000.0
|
||||
if pweight < 2:
|
||||
pstr = 'I'
|
||||
elif pweight >= 2:
|
||||
pstr = 'E'
|
||||
if arrivals[key]['S']['weight'] < 4:
|
||||
Sss = Sonset.second
|
||||
Sms = Sonset.microsecond
|
||||
Sss_ms = Sss + Sms / 1000000.0
|
||||
Sss_ms = str('%5.02f' % Sss_ms)
|
||||
if sweight < 2:
|
||||
sstr = 'I'
|
||||
elif sweight >= 2:
|
||||
sstr = 'E'
|
||||
fid.write('%-4s%sP%s%d %02d%02d%02d%02d%02d%5.2f %s%sS %d %s\n' % (stat,
|
||||
pstr,
|
||||
fm,
|
||||
pweight,
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hh,
|
||||
mm,
|
||||
ss_ms,
|
||||
Sss_ms,
|
||||
sstr,
|
||||
sweight,
|
||||
Ao))
|
||||
else:
|
||||
fid.write('%-4s%sP%s%d %02d%02d%02d%02d%02d%5.2f %s\n' % (stat,
|
||||
pstr,
|
||||
fm,
|
||||
pweight,
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hh,
|
||||
mm,
|
||||
ss_ms,
|
||||
Ao))
|
||||
def write_nlloc():
|
||||
with open(filename, 'w') as fid:
|
||||
fid.write('# EQEVENT: {} Label: EQ{} Loc: X 0.00 Y 0.00 Z 10.00 OT 0.00 \n'.format(
|
||||
parameter.get('database'), parameter.get('eventID')))
|
||||
for key, value in arrivals.items():
|
||||
for phase in ['P', 'S']:
|
||||
if phase in value:
|
||||
fm = value[phase].get('fm', '?')
|
||||
onset = value[phase]['mpp']
|
||||
ss_ms = onset.second + onset.microsecond / 1000000.0
|
||||
weight = 1 if value[phase].get('weight', 0) < 4 else 0
|
||||
amp = value[phase].get('Ao', 0.0) if phase == 'S' else ''
|
||||
fid.write('{} ? ? ? {} {}{}{} {}{} {:7.4f} GAU 0 {} 0 0 {}\n'.format(
|
||||
key, phase, fm, onset.year, onset.month, onset.day, onset.hour, onset.minute, ss_ms, amp,
|
||||
weight))
|
||||
|
||||
fid.close()
|
||||
def write_hypo71():
|
||||
with open(filename, 'w') as fid:
|
||||
fid.write(
|
||||
' {}\n'.format(parameter.get('eventID')))
|
||||
for key, value in arrivals.items():
|
||||
if value['P'].get('weight', 0) < 4:
|
||||
stat = key[:4]
|
||||
Ponset = value['P']['mpp']
|
||||
Sonset = value.get('S', {}).get('mpp')
|
||||
pweight = value['P'].get('weight', 0)
|
||||
sweight = value.get('S', {}).get('weight', 0)
|
||||
fm = value['P'].get('fm', '-')
|
||||
Ao = value.get('S', {}).get('Ao', '')
|
||||
year = Ponset.year - 2000 if Ponset.year >= 2000 else Ponset.year - 1900
|
||||
ss_ms = Ponset.second + Ponset.microsecond / 1000000.0
|
||||
if Sonset:
|
||||
Sss_ms = Sonset.second + Sonset.microsecond / 1000000.0
|
||||
fid.write('{}P{}{}{} {}{}{}{}{} {:5.2f} {}{}S {} {}\n'.format(
|
||||
stat, 'I' if pweight < 2 else 'E', fm, pweight, year, Ponset.month, Ponset.day,
|
||||
Ponset.hour, Ponset.minute, ss_ms, Sss_ms, 'I' if sweight < 2 else 'E', sweight, Ao))
|
||||
else:
|
||||
fid.write('{}P{}{}{} {}{}{}{}{} {:5.2f} {}\n'.format(
|
||||
stat, 'I' if pweight < 2 else 'E', fm, pweight, year, Ponset.month, Ponset.day,
|
||||
Ponset.hour, Ponset.minute, ss_ms, Ao))
|
||||
|
||||
elif fformat == 'HYPOSAT':
|
||||
print("Writing phases to %s for HYPOSAT" % filename)
|
||||
fid = open("%s" % filename, 'w')
|
||||
# write header
|
||||
fid.write('%s, event %s \n' % (parameter.get('database'), parameter.get('eventID')))
|
||||
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||
for key in arrivals:
|
||||
# P onsets
|
||||
if 'P' in arrivals[key] and arrivals[key]['P']['mpp'] is not None:
|
||||
if arrivals[key]['P']['weight'] < 4:
|
||||
Ponset = arrivals[key]['P']['mpp']
|
||||
pyear = Ponset.year
|
||||
pmonth = Ponset.month
|
||||
pday = Ponset.day
|
||||
phh = Ponset.hour
|
||||
pmm = Ponset.minute
|
||||
pss = Ponset.second
|
||||
pms = Ponset.microsecond
|
||||
Pss = pss + pms / 1000000.0
|
||||
# use symmetrized picking error as std
|
||||
# (read the HYPOSAT manual)
|
||||
pstd = arrivals[key]['P']['spe']
|
||||
if pstd is None:
|
||||
errorsP = parameter.get('timeerrorsP')
|
||||
if arrivals[key]['P']['weight'] == 0:
|
||||
pstd = errorsP[0]
|
||||
elif arrivals[key]['P']['weight'] == 1:
|
||||
pstd = errorsP[1]
|
||||
elif arrivals[key]['P']['weight'] == 2:
|
||||
pstd = errorsP[2]
|
||||
elif arrivals[key]['P']['weight'] == 3:
|
||||
psrd = errorsP[3]
|
||||
else:
|
||||
pstd = errorsP[4]
|
||||
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))
|
||||
# S onsets
|
||||
if 'S' in arrivals[key] and arrivals[key]['S']['mpp'] is not None:
|
||||
if arrivals[key]['S']['weight'] < 4:
|
||||
Sonset = arrivals[key]['S']['mpp']
|
||||
syear = Sonset.year
|
||||
smonth = Sonset.month
|
||||
sday = Sonset.day
|
||||
shh = Sonset.hour
|
||||
smm = Sonset.minute
|
||||
sss = Sonset.second
|
||||
sms = Sonset.microsecond
|
||||
Sss = sss + sms / 1000000.0
|
||||
sstd = arrivals[key]['S']['spe']
|
||||
if pstd is None:
|
||||
errorsS = parameter.get('timeerrorsS')
|
||||
if arrivals[key]['S']['weight'] == 0:
|
||||
pstd = errorsS[0]
|
||||
elif arrivals[key]['S']['weight'] == 1:
|
||||
pstd = errorsS[1]
|
||||
elif arrivals[key]['S']['weight'] == 2:
|
||||
pstd = errorsS[2]
|
||||
elif arrivals[key]['S']['weight'] == 3:
|
||||
psrd = errorsS[3]
|
||||
else:
|
||||
pstd = errorsP[4]
|
||||
fid.write('%-5s S1 %4.0f %02d %02d %02d %02d %05.02f %5.3f -999. 0.00 -999. 0.00\n'
|
||||
% (key, syear, smonth, sday, shh, smm, Sss, sstd))
|
||||
fid.close()
|
||||
def write_hyposat():
|
||||
with open(filename, 'w') as fid:
|
||||
fid.write('{}, event {} \n'.format(parameter.get('database'), parameter.get('eventID')))
|
||||
for key, value in arrivals.items():
|
||||
for phase in ['P', 'S']:
|
||||
if phase in value and value[phase].get('weight', 0) < 4:
|
||||
onset = value[phase]['mpp']
|
||||
ss_ms = onset.second + onset.microsecond / 1000000.0
|
||||
std = value[phase].get('spe', parameter.get('timeerrorsP')[value[phase].get('weight', 0)])
|
||||
fid.write(
|
||||
'{:<5} {}1 {:4} {:02} {:02} {:02} {:02} {:05.02f} {:5.3f} -999. 0.00 -999. 0.00\n'.format(
|
||||
key, phase, onset.year, onset.month, onset.day, onset.hour, onset.minute, ss_ms, std))
|
||||
|
||||
elif fformat == 'VELEST':
|
||||
print("Writing phases to %s for VELEST" % filename)
|
||||
fid = open("%s" % filename, 'w')
|
||||
# get informations needed in cnv-file
|
||||
# check, whether latitude is N or S and longitude is E or W
|
||||
try:
|
||||
eventsource = eventinfo.origins[0]
|
||||
except:
|
||||
def write_velest():
|
||||
if not eventinfo:
|
||||
print("No source origin calculated yet, thus no cnv-file creation possible!")
|
||||
return
|
||||
if eventsource['latitude'] < 0:
|
||||
cns = 'S'
|
||||
else:
|
||||
cns = 'N'
|
||||
if eventsource['longitude'] < 0:
|
||||
cew = 'W'
|
||||
else:
|
||||
cew = 'E'
|
||||
# get last two integers of origin year
|
||||
stime = eventsource['time']
|
||||
if stime.year - 2000 >= 0:
|
||||
syear = stime.year - 2000
|
||||
else:
|
||||
syear = stime.year - 1900
|
||||
ifx = 0 # default value, see VELEST manual, pp. 22-23
|
||||
# write header
|
||||
fid.write('%s%02d%02d %02d%02d %05.2f %7.4f%c %8.4f%c %7.2f %6.2f %02.0f 0.0 0.03 1.0 1.0\n' % (
|
||||
syear, stime.month, stime.day, stime.hour, stime.minute, stime.second, eventsource['latitude'],
|
||||
cns, eventsource['longitude'], cew, eventsource['depth'], eventinfo.magnitudes[0]['mag'], ifx))
|
||||
n = 0
|
||||
# check whether arrivals are dictionaries (autoPyLoT) or pick object (PyLoT)
|
||||
if isinstance(arrivals, dict) == False:
|
||||
# convert pick object (PyLoT) into dictionary
|
||||
evt = ope.Event(resource_id=eventinfo['resource_id'])
|
||||
evt.picks = arrivals
|
||||
arrivals = picksdict_from_picks(evt)
|
||||
# check for automatic and manual picks
|
||||
# prefer manual picks
|
||||
usedarrivals = chooseArrivals(arrivals)
|
||||
for key in usedarrivals:
|
||||
# P onsets
|
||||
if 'P' in usedarrivals[key]:
|
||||
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 = 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 'S' in usedarrivals[key]:
|
||||
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 = 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))
|
||||
else:
|
||||
fid.write('%-4sS%d%6.2f\n' % (stat, Sweight, Srt))
|
||||
fid.close()
|
||||
with open(filename, 'w') as fid:
|
||||
origin = eventinfo.origins[0]
|
||||
lat_dir = 'S' if origin.latitude < 0 else 'N'
|
||||
lon_dir = 'W' if origin.longitude < 0 else 'E'
|
||||
year = origin.time.year - 2000 if origin.time.year >= 2000 else origin.time.year - 1900
|
||||
fid.write(
|
||||
'{}{}{} {}{} {} {:05.2f} {:7.4f}{} {:8.4f}{} {:7.2f} {:6.2f} {:02.0f} 0.0 0.03 1.0 1.0\n'.format(
|
||||
year, origin.time.month, origin.time.day, origin.time.hour, origin.time.minute, origin.time.second,
|
||||
origin.latitude, lat_dir, origin.longitude, lon_dir, origin.depth, eventinfo.magnitudes[0].mag, 0))
|
||||
for key, value in arrivals.items():
|
||||
for phase in ['P', 'S']:
|
||||
if phase in value and value[phase].get('weight', 0) < 4:
|
||||
onset = value[phase]['mpp']
|
||||
rt = (onset - origin.time).total_seconds()
|
||||
fid.write('{:<4}{}{}{:6.2f}\n'.format(key[:4], phase, value[phase].get('weight', 0), rt))
|
||||
|
||||
elif fformat == 'HYPODD':
|
||||
print("Writing phases to %s for hypoDD" % filename)
|
||||
fid = open("%s" % filename, 'w')
|
||||
# get event information needed for hypoDD-phase file
|
||||
try:
|
||||
eventsource = eventinfo.origins[0]
|
||||
except:
|
||||
def write_hypodd():
|
||||
if not eventinfo:
|
||||
print("No source origin calculated yet, thus no hypoDD-infile creation possible!")
|
||||
return
|
||||
stime = eventsource['time']
|
||||
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,
|
||||
eventsource['latitude'], eventsource['longitude'], eventsource['depth'] / 1000,
|
||||
eventinfo.magnitudes[0]['mag'], eventsource['quality']['standard_error'], hddID))
|
||||
# check whether arrivals are dictionaries (autoPyLoT) or pick object (PyLoT)
|
||||
if isinstance(arrivals, dict) == False:
|
||||
# convert pick object (PyLoT) into dictionary
|
||||
evt = ope.Event(resource_id=eventinfo['resource_id'])
|
||||
evt.picks = arrivals
|
||||
arrivals = picksdict_from_picks(evt)
|
||||
# check for automatic and manual picks
|
||||
# prefer manual picks
|
||||
usedarrivals = chooseArrivals(arrivals)
|
||||
for key in usedarrivals:
|
||||
if 'P' in usedarrivals[key]:
|
||||
# P onsets
|
||||
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 'S' in usedarrivals[key]:
|
||||
# S onsets
|
||||
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))
|
||||
with open(filename, 'w') as fid:
|
||||
origin = eventinfo.origins[0]
|
||||
stime = origin.time
|
||||
fid.write('# {} {} {} {} {} {} {:7.4f} +{:6.4f} {:7.4f} {:4.2f} 0.1 0.5 {:4.2f} {}\n'.format(
|
||||
stime.year, stime.month, stime.day, stime.hour, stime.minute, stime.second,
|
||||
origin.latitude, origin.longitude, origin.depth / 1000, eventinfo.magnitudes[0].mag,
|
||||
origin.quality.standard_error, "00000"))
|
||||
for key, value in arrivals.items():
|
||||
for phase in ['P', 'S']:
|
||||
if phase in value and value[phase].get('weight', 0) < 4:
|
||||
onset = value[phase]['mpp']
|
||||
rt = (onset - stime).total_seconds()
|
||||
fid.write('{} {:6.3f} 1 {}\n'.format(key, rt, phase))
|
||||
|
||||
fid.close()
|
||||
|
||||
elif fformat == 'FOCMEC':
|
||||
print("Writing phases to %s for FOCMEC" % filename)
|
||||
fid = open("%s" % filename, 'w')
|
||||
# get event information needed for FOCMEC-input file
|
||||
try:
|
||||
eventsource = eventinfo.origins[0]
|
||||
except:
|
||||
def write_focmec():
|
||||
if not eventinfo:
|
||||
print("No source origin calculated yet, thus no FOCMEC-infile creation possible!")
|
||||
return
|
||||
stime = eventsource['time']
|
||||
|
||||
# avoid printing '*' in focmec-input file
|
||||
if parameter.get('eventid') == '*' or parameter.get('eventid') is None:
|
||||
evID = 'e0000'
|
||||
else:
|
||||
evID = parameter.get('eventid')
|
||||
|
||||
# write header line including event information
|
||||
fid.write('%s %d%02d%02d%02d%02d%02.0f %7.4f %6.4f %3.1f %3.1f\n' % (evID,
|
||||
stime.year, stime.month, stime.day,
|
||||
stime.hour, stime.minute, stime.second,
|
||||
eventsource['latitude'],
|
||||
eventsource['longitude'],
|
||||
eventsource['depth'] / 1000,
|
||||
eventinfo.magnitudes[0]['mag']))
|
||||
picks = eventinfo.picks
|
||||
# check whether arrivals are dictionaries (autoPyLoT) or pick object (PyLoT)
|
||||
if isinstance(arrivals, dict) == False:
|
||||
# convert pick object (PyLoT) into dictionary
|
||||
evt = ope.Event(resource_id=eventinfo['resource_id'])
|
||||
evt.picks = arrivals
|
||||
arrivals = picksdict_from_picks(evt)
|
||||
# check for automatic and manual picks
|
||||
# prefer manual picks
|
||||
usedarrivals = chooseArrivals(arrivals)
|
||||
for key in usedarrivals:
|
||||
if 'P' in usedarrivals[key]:
|
||||
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
|
||||
if station == stat:
|
||||
# get resource ID
|
||||
resid_picks = picks[i].get('resource_id')
|
||||
# find same ID in eventinfo
|
||||
# there it is the pick_id!!
|
||||
for j in range(len(eventinfo.origins[0].arrivals)):
|
||||
resid_eventinfo = eventinfo.origins[0].arrivals[j].get('pick_id')
|
||||
if resid_eventinfo == resid_picks and eventinfo.origins[0].arrivals[j].phase == 'P':
|
||||
if len(stat) > 4: # FOCMEC handles only 4-string station IDs
|
||||
stat = stat[1:5]
|
||||
az = eventinfo.origins[0].arrivals[j].get('azimuth')
|
||||
inz = eventinfo.origins[0].arrivals[j].get('takeoff_angle')
|
||||
fid.write('%-4s %6.2f %6.2f%s \n' % (stat,
|
||||
az,
|
||||
inz,
|
||||
usedarrivals[key]['P']['fm']))
|
||||
with open(filename, 'w') as fid:
|
||||
origin = eventinfo.origins[0]
|
||||
stime = origin.time
|
||||
fid.write('{} {}{:02d}{:02d}{:02d}{:02d}{:02.0f} {:7.4f} {:6.4f} {:3.1f} {:3.1f}\n'.format(
|
||||
parameter.get('eventid', 'e0000'), stime.year, stime.month, stime.day, stime.hour, stime.minute,
|
||||
stime.second, origin.latitude, origin.longitude, origin.depth / 1000, eventinfo.magnitudes[0].mag))
|
||||
for key, value in arrivals.items():
|
||||
if 'P' in value and value['P'].get('weight', 0) < 4 and value['P'].get('fm'):
|
||||
for pick in eventinfo.picks:
|
||||
if pick.waveform_id.station_code == key:
|
||||
for arrival in origin.arrivals:
|
||||
if arrival.pick_id == pick.resource_id and arrival.phase == 'P':
|
||||
stat = key[:4]
|
||||
az = arrival.azimuth
|
||||
inz = arrival.takeoff_angle
|
||||
fid.write('{:<4} {:6.2f} {:6.2f}{}\n'.format(stat, az, inz, value['P']['fm']))
|
||||
break
|
||||
|
||||
fid.close()
|
||||
def write_hash():
|
||||
# Define filenames for HASH driver 1 and 2
|
||||
filename1 = f"{filename}drv1.phase"
|
||||
filename2 = f"{filename}drv2.phase"
|
||||
|
||||
print(f"Writing phases to {filename1} for HASH-driver 1")
|
||||
print(f"Writing phases to {filename2} for HASH-driver 2")
|
||||
|
||||
# Open files for writing
|
||||
with open(filename1, 'w') as fid1, open(filename2, 'w') as fid2:
|
||||
# Get event information needed for HASH-input file
|
||||
try:
|
||||
eventsource = eventinfo.origins[0]
|
||||
except IndexError:
|
||||
print("No source origin calculated yet, thus no cnv-file creation possible!")
|
||||
return
|
||||
|
||||
event = parameter.get('eventID')
|
||||
hashID = event.split('.')[0][1:5]
|
||||
latdeg = eventsource['latitude']
|
||||
latmin = (eventsource['latitude'] * 60) / 10000
|
||||
londeg = eventsource['longitude']
|
||||
lonmin = (eventsource['longitude'] * 60) / 10000
|
||||
|
||||
erh = (eventsource.origin_uncertainty['min_horizontal_uncertainty'] +
|
||||
eventsource.origin_uncertainty['max_horizontal_uncertainty']) / 2000
|
||||
erz = eventsource.depth_errors['uncertainty']
|
||||
|
||||
stime = eventsource['time']
|
||||
syear = stime.year % 100 # Calculate two-digit year
|
||||
|
||||
picks = eventinfo.picks
|
||||
|
||||
# Write header line including event information for HASH-driver 1
|
||||
fid1.write(f"{syear:02d}{stime.month:02d}{stime.day:02d}{stime.hour:02d}{stime.minute:02d}"
|
||||
f"{stime.second:05.2f}{latdeg:2d}N{latmin:05.2f}{londeg:3d}E{lonmin:05.2f}"
|
||||
f"{eventsource['depth']:6.2f}{eventinfo.magnitudes[0]['mag']:4.2f}{erh:5.2f}{erz:5.2f}{hashID}\n")
|
||||
|
||||
# Write header line including event information for HASH-driver 2
|
||||
fid2.write(f"{syear:02d}{stime.month:02d}{stime.day:02d}{stime.hour:02d}{stime.minute:02d}"
|
||||
f"{stime.second:05.2f}{latdeg}N{latmin:05.2f}{londeg}E{lonmin:6.2f}{eventsource['depth']:5.2f}"
|
||||
f"{eventsource['quality']['used_phase_count']:3d}{erh:5.2f}{erz:5.2f}"
|
||||
f"{eventinfo.magnitudes[0]['mag']:4.2f}{hashID}\n")
|
||||
|
||||
# Write phase lines
|
||||
for key, arrival in arrivals.items():
|
||||
if 'P' in arrival and arrival['P']['weight'] < 4 and arrival['P']['fm'] is not None:
|
||||
stat = key
|
||||
ccode = arrival['P']['channel']
|
||||
ncode = arrival['P']['network']
|
||||
Pqual = 'I' if arrival['P']['weight'] < 2 else 'E'
|
||||
|
||||
for pick in picks:
|
||||
if pick.waveform_id.station_code == stat:
|
||||
resid_picks = pick.get('resource_id')
|
||||
for origin_arrival in eventinfo.origins[0].arrivals:
|
||||
if (origin_arrival.get('pick_id') == resid_picks and
|
||||
origin_arrival.phase == 'P'):
|
||||
if len(stat) > 4: # HASH handles only 4-character station IDs
|
||||
stat = stat[1:5]
|
||||
|
||||
az = origin_arrival.get('azimuth')
|
||||
inz = origin_arrival.get('takeoff_angle')
|
||||
dist = origin_arrival.get('distance')
|
||||
|
||||
# Write phase line for HASH-driver 1
|
||||
fid1.write(f"{stat:<4}{Pqual}P{arrival['P']['fm']}{arrival['P']['weight']:d}"
|
||||
f"{dist:3.1f}{inz:03d}{az:03d}{ccode}\n")
|
||||
|
||||
# Write phase line for HASH-driver 2
|
||||
fid2.write(f"{stat:<4} {ncode} {ccode} {Pqual} {arrival['P']['fm']}\n")
|
||||
break
|
||||
|
||||
fid1.write(f"{'':<36}{hashID}")
|
||||
|
||||
# Prefer Manual Picks over automatic ones if possible
|
||||
arrivals = chooseArrivals(arrivals) # Function not defined, assumed to exist
|
||||
|
||||
if fformat == 'NLLoc':
|
||||
write_nlloc()
|
||||
elif fformat == 'HYPO71':
|
||||
write_hypo71()
|
||||
elif fformat == 'HYPOSAT':
|
||||
write_hyposat()
|
||||
elif fformat == 'VELEST':
|
||||
write_velest()
|
||||
elif fformat == 'HYPODD':
|
||||
write_hypodd()
|
||||
elif fformat == 'FOCMEC':
|
||||
write_focmec()
|
||||
elif fformat == 'HASH':
|
||||
# two different input files for
|
||||
# HASH-driver 1 and 2 (see HASH manual!)
|
||||
filename1 = filename + 'drv1' + '.phase'
|
||||
filename2 = filename + 'drv2' + '.phase'
|
||||
print("Writing phases to %s for HASH for HASH-driver 1" % filename1)
|
||||
fid1 = open("%s" % filename1, 'w')
|
||||
print("Writing phases to %s for HASH for HASH-driver 2" % filename2)
|
||||
fid2 = open("%s" % filename2, 'w')
|
||||
# get event information needed for HASH-input file
|
||||
try:
|
||||
eventsource = eventinfo.origins[0]
|
||||
except:
|
||||
print("No source origin calculated yet, thus no cnv-file creation possible!")
|
||||
return
|
||||
eventsource = eventinfo.origins[0]
|
||||
event = parameter.get('eventID')
|
||||
hashID = event.split('.')[0][1:5]
|
||||
latdeg = eventsource['latitude']
|
||||
latmin = eventsource['latitude'] * 60 / 10000
|
||||
londeg = eventsource['longitude']
|
||||
lonmin = eventsource['longitude'] * 60 / 10000
|
||||
erh = 1 / 2 * (eventsource.origin_uncertainty['min_horizontal_uncertainty'] +
|
||||
eventsource.origin_uncertainty['max_horizontal_uncertainty']) / 1000
|
||||
erz = eventsource.depth_errors['uncertainty']
|
||||
stime = eventsource['time']
|
||||
if stime.year - 2000 >= 0:
|
||||
syear = stime.year - 2000
|
||||
else:
|
||||
syear = stime.year - 1900
|
||||
picks = eventinfo.picks
|
||||
# write header line including event information
|
||||
# for HASH-driver 1
|
||||
fid1.write('%s%02d%02d%02d%02d%5.2f%2dN%5.2f%3dE%5.2f%6.3f%4.2f%5.2f%5.2f%s\n' % (syear,
|
||||
stime.month, stime.day,
|
||||
stime.hour, stime.minute,
|
||||
stime.second,
|
||||
latdeg, latmin, londeg,
|
||||
lonmin, eventsource['depth'],
|
||||
eventinfo.magnitudes[0][
|
||||
'mag'], erh, erz,
|
||||
hashID))
|
||||
# write header line including event information
|
||||
# for HASH-driver 2
|
||||
fid2.write(
|
||||
'%d%02d%02d%02d%02d%5.2f%dN%5.2f%3dE%6.2f%5.2f %d %5.2f %5.2f %4.2f %s \n' % (
|
||||
syear, stime.month, stime.day,
|
||||
stime.hour, stime.minute, stime.second,
|
||||
latdeg, latmin, londeg, lonmin,
|
||||
eventsource['depth'],
|
||||
eventsource['quality']['used_phase_count'],
|
||||
erh, erz, eventinfo.magnitudes[0]['mag'],
|
||||
hashID))
|
||||
# Prefer Manual Picks over automatic ones if possible
|
||||
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||
# write phase lines
|
||||
for key in arrivals:
|
||||
if 'P' in arrivals[key]:
|
||||
if arrivals[key]['P']['weight'] < 4 and arrivals[key]['P']['fm'] is not None:
|
||||
stat = key
|
||||
ccode = arrivals[key]['P']['channel']
|
||||
ncode = arrivals[key]['P']['network']
|
||||
|
||||
if arrivals[key]['P']['weight'] < 2:
|
||||
Pqual = 'I'
|
||||
else:
|
||||
Pqual = 'E'
|
||||
|
||||
for i in range(len(picks)):
|
||||
station = picks[i].waveform_id.station_code
|
||||
if station == stat:
|
||||
# get resource ID
|
||||
resid_picks = picks[i].get('resource_id')
|
||||
# find same ID in eventinfo
|
||||
# there it is the pick_id!!
|
||||
for j in range(len(eventinfo.origins[0].arrivals)):
|
||||
resid_eventinfo = eventinfo.origins[0].arrivals[j].get('pick_id')
|
||||
if resid_eventinfo == resid_picks and eventinfo.origins[0].arrivals[j].phase == 'P':
|
||||
if len(stat) > 4: # HASH handles only 4-string station IDs
|
||||
stat = stat[1:5]
|
||||
az = eventinfo.origins[0].arrivals[j].get('azimuth')
|
||||
inz = eventinfo.origins[0].arrivals[j].get('takeoff_angle')
|
||||
dist = eventinfo.origins[0].arrivals[j].get('distance')
|
||||
# write phase line for HASH-driver 1
|
||||
fid1.write(
|
||||
'%-4s%sP%s%d 0 %3.1f %03d %03d 2 1 %s\n' % (
|
||||
stat, Pqual, arrivals[key]['P']['fm'], arrivals[key]['P']['weight'],
|
||||
dist, inz, az, ccode))
|
||||
# write phase line for HASH-driver 2
|
||||
fid2.write('%-4s %s %s %s %s \n' % (
|
||||
stat,
|
||||
ncode,
|
||||
ccode,
|
||||
Pqual,
|
||||
arrivals[key]['P']['fm']))
|
||||
break
|
||||
|
||||
fid1.write(' %s' % hashID)
|
||||
fid1.close()
|
||||
fid2.close()
|
||||
write_hash()
|
||||
|
||||
|
||||
def chooseArrivals(arrivals):
|
||||
@@ -1124,7 +670,7 @@ def getQualitiesfromxml(path, errorsP, errorsS, plotflag=1, figure=None, verbosi
|
||||
mstation = pick.waveform_id.station_code
|
||||
mstation_ext = mstation + '_'
|
||||
for mpick in arrivals_copy:
|
||||
phase = identifyPhase(loopIdentifyPhase(pick.phase_hint)) # MP MP catch if this fails?
|
||||
phase = identifyPhase(loopIdentifyPhase(pick.phase_hint)) # MP MP catch if this fails?
|
||||
if ((mpick.waveform_id.station_code == mstation) or
|
||||
(mpick.waveform_id.station_code == mstation_ext)) and \
|
||||
(mpick.method_id.id.split('/')[1] == 'auto') and \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pylot.core.io.phases import writephases
|
||||
from pylot.core.io.phases import write_phases
|
||||
from pylot.core.util.version import get_git_version as _getVersionString
|
||||
|
||||
__version__ = _getVersionString()
|
||||
@@ -25,4 +25,4 @@ def export(picks, fnout, parameter, eventinfo):
|
||||
:type eventinfo: list object
|
||||
'''
|
||||
# write phases to FOCMEC-phase file
|
||||
writephases(picks, 'FOCMEC', fnout, parameter, eventinfo)
|
||||
write_phases(picks, 'FOCMEC', fnout, parameter, eventinfo)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pylot.core.io.phases import writephases
|
||||
from pylot.core.io.phases import write_phases
|
||||
from pylot.core.util.version import get_git_version as _getVersionString
|
||||
|
||||
__version__ = _getVersionString()
|
||||
@@ -25,4 +25,4 @@ def export(picks, fnout, parameter, eventinfo):
|
||||
:type eventinfo: list object
|
||||
'''
|
||||
# write phases to HASH-phase file
|
||||
writephases(picks, 'HASH', fnout, parameter, eventinfo)
|
||||
write_phases(picks, 'HASH', fnout, parameter, eventinfo)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pylot.core.io.phases import writephases
|
||||
from pylot.core.io.phases import write_phases
|
||||
from pylot.core.util.version import get_git_version as _getVersionString
|
||||
|
||||
__version__ = _getVersionString()
|
||||
@@ -22,4 +22,4 @@ def export(picks, fnout, parameter):
|
||||
:type parameter: object
|
||||
'''
|
||||
# write phases to HYPO71-phase file
|
||||
writephases(picks, 'HYPO71', fnout, parameter)
|
||||
write_phases(picks, 'HYPO71', fnout, parameter)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pylot.core.io.phases import writephases
|
||||
from pylot.core.io.phases import write_phases
|
||||
from pylot.core.util.version import get_git_version as _getVersionString
|
||||
|
||||
__version__ = _getVersionString()
|
||||
@@ -25,4 +25,4 @@ def export(picks, fnout, parameter, eventinfo):
|
||||
:type eventinfo: list object
|
||||
'''
|
||||
# write phases to hypoDD-phase file
|
||||
writephases(picks, 'HYPODD', fnout, parameter, eventinfo)
|
||||
write_phases(picks, 'HYPODD', fnout, parameter, eventinfo)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pylot.core.io.phases import writephases
|
||||
from pylot.core.io.phases import write_phases
|
||||
from pylot.core.util.version import get_git_version as _getVersionString
|
||||
|
||||
__version__ = _getVersionString()
|
||||
@@ -22,4 +22,4 @@ def export(picks, fnout, parameter):
|
||||
:type parameter: object
|
||||
'''
|
||||
# write phases to HYPOSAT-phase file
|
||||
writephases(picks, 'HYPOSAT', fnout, parameter)
|
||||
write_phases(picks, 'HYPOSAT', fnout, parameter)
|
||||
|
||||
@@ -7,7 +7,7 @@ import subprocess
|
||||
|
||||
from obspy import read_events
|
||||
|
||||
from pylot.core.io.phases import writephases
|
||||
from pylot.core.io.phases import write_phases
|
||||
from pylot.core.util.gui import which
|
||||
from pylot.core.util.utils import getPatternLine, runProgram
|
||||
from pylot.core.util.version import get_git_version as _getVersionString
|
||||
@@ -34,7 +34,7 @@ def export(picks, fnout, parameter):
|
||||
:type parameter: object
|
||||
'''
|
||||
# write phases to NLLoc-phase file
|
||||
writephases(picks, 'NLLoc', fnout, parameter)
|
||||
write_phases(picks, 'NLLoc', fnout, parameter)
|
||||
|
||||
|
||||
def modify_inputs(ctrfn, root, nllocoutn, phasefn, tttn):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from pylot.core.io.phases import writephases
|
||||
from pylot.core.io.phases import write_phases
|
||||
from pylot.core.util.version import get_git_version as _getVersionString
|
||||
|
||||
__version__ = _getVersionString()
|
||||
@@ -25,4 +25,4 @@ def export(picks, fnout, eventinfo, parameter=None):
|
||||
:type parameter: object
|
||||
'''
|
||||
# write phases to VELEST-phase file
|
||||
writephases(picks, 'VELEST', fnout, parameter, eventinfo)
|
||||
write_phases(picks, 'VELEST', fnout, parameter, eventinfo)
|
||||
|
||||
@@ -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.picker import AICPicker, PragPicker
|
||||
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, \
|
||||
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):
|
||||
@@ -232,20 +232,6 @@ class PickingContainer:
|
||||
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):
|
||||
|
||||
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.verbose = verbose
|
||||
self.iplot = correct_iplot(iplot)
|
||||
self.fig_dict = get_None(fig_dict)
|
||||
self.fig_dict = get_none(fig_dict)
|
||||
self.metadata = metadata
|
||||
self.origin = origin
|
||||
|
||||
@@ -660,7 +646,7 @@ class AutopickStation(object):
|
||||
ax1.set_ylim([-1.5, 1.5])
|
||||
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
|
||||
ax2 = fig.add_subplot(3, 1, 2, sharex=ax1)
|
||||
th1data = np.linspace(0, self.etrace.stats.endtime - self.etrace.stats.starttime,
|
||||
|
||||
@@ -20,6 +20,8 @@ import numpy as np
|
||||
from scipy import signal
|
||||
from obspy.core import Stream
|
||||
|
||||
from pylot.core.pick.utils import PickingFailedException
|
||||
|
||||
|
||||
class CharacteristicFunction(object):
|
||||
"""
|
||||
@@ -293,7 +295,7 @@ class HOScf(CharacteristicFunction):
|
||||
if j < 4:
|
||||
LTA[j] = 0
|
||||
STA[j] = 0
|
||||
elif j <= ista:
|
||||
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
|
||||
@@ -488,6 +490,9 @@ class ARHcf(CharacteristicFunction):
|
||||
print('Calculating AR-prediction error from both horizontal traces ...')
|
||||
|
||||
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)
|
||||
if len(n0) > 1:
|
||||
xnp[0].data[n0] = 0
|
||||
|
||||
@@ -178,7 +178,9 @@ class AICPicker(AutoPicker):
|
||||
aic = tap * self.cf + max(abs(self.cf))
|
||||
# smooth AIC-CF
|
||||
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:
|
||||
print('AICPicker: Tsmooth larger than CF!')
|
||||
return
|
||||
@@ -188,7 +190,7 @@ class AICPicker(AutoPicker):
|
||||
ii1 = i - ismooth
|
||||
aicsmooth[i] = aicsmooth[i - 1] + (aic[i] - aic[ii1]) / ismooth
|
||||
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
|
||||
offset = abs(min(aic) - min(aicsmooth))
|
||||
aicsmooth = aicsmooth - offset
|
||||
@@ -197,7 +199,7 @@ class AICPicker(AutoPicker):
|
||||
# minimum in AIC function
|
||||
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_factor = 0.7
|
||||
thresh = thresh_factor * cf[icfmax]
|
||||
@@ -209,7 +211,6 @@ class AICPicker(AutoPicker):
|
||||
if sample <= cf[index - 1]:
|
||||
icfmax = index - 1
|
||||
break
|
||||
# MP MP ---
|
||||
|
||||
# find minimum in AIC-CF front of maximum of HOS/AR-CF
|
||||
lpickwindow = int(round(self.PickWindow / self.dt))
|
||||
|
||||
@@ -15,7 +15,7 @@ import numpy as np
|
||||
from obspy.core import Stream, UTCDateTime
|
||||
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'):
|
||||
@@ -136,7 +136,7 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecol
|
||||
PickError = symmetrize_error(diffti_te, diffti_tl)
|
||||
|
||||
if iplot > 1:
|
||||
if get_None(fig) is None:
|
||||
if get_none(fig) is None:
|
||||
fig = plt.figure() # iplot)
|
||||
plt_flag = 1
|
||||
fig._tight = True
|
||||
@@ -275,7 +275,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None, linecolor='k'):
|
||||
try:
|
||||
P1 = np.polyfit(xslope1, xraw[islope1], 1)
|
||||
datafit1 = np.polyval(P1, xslope1)
|
||||
except Exception as e:
|
||||
except ValueError as e:
|
||||
print("fmpicker: Problems with data fit! {}".format(e))
|
||||
print("Skip first motion determination!")
|
||||
return FM
|
||||
@@ -321,7 +321,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None, linecolor='k'):
|
||||
try:
|
||||
P2 = np.polyfit(xslope2, xfilt[islope2], 1)
|
||||
datafit2 = np.polyval(P2, xslope2)
|
||||
except Exception as e:
|
||||
except ValueError as e:
|
||||
emsg = 'fmpicker: polyfit failed: {}'.format(e)
|
||||
print(emsg)
|
||||
return FM
|
||||
@@ -344,7 +344,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None, linecolor='k'):
|
||||
print("fmpicker: Found polarity %s" % FM)
|
||||
|
||||
if iplot > 1:
|
||||
if get_None(fig) is None:
|
||||
if get_none(fig) is None:
|
||||
fig = plt.figure() # iplot)
|
||||
plt_flag = 1
|
||||
fig._tight = True
|
||||
@@ -868,7 +868,7 @@ def checksignallength(X, pick, minsiglength, pickparams, iplot=0, fig=None, line
|
||||
returnflag = 0
|
||||
|
||||
if iplot > 1:
|
||||
if get_None(fig) is None:
|
||||
if get_none(fig) is None:
|
||||
fig = plt.figure() # iplot)
|
||||
plt_flag = 1
|
||||
fig._tight = True
|
||||
@@ -890,6 +890,8 @@ def checksignallength(X, pick, minsiglength, pickparams, iplot=0, fig=None, line
|
||||
input()
|
||||
except SyntaxError:
|
||||
pass
|
||||
except EOFError:
|
||||
pass
|
||||
plt.close(fig)
|
||||
|
||||
return returnflag
|
||||
@@ -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],
|
||||
trace.stats.npts)
|
||||
if i == 0:
|
||||
if get_None(fig) is None:
|
||||
if get_none(fig) is None:
|
||||
fig = plt.figure() # self.iplot) ### WHY? MP MP
|
||||
plt_flag = 1
|
||||
ax1 = fig.add_subplot(3, 1, i + 1)
|
||||
ax = ax1
|
||||
ax.set_title('CheckZ4S, Station %s' % zdat[0].stats.station)
|
||||
else:
|
||||
if get_None(fig) is None:
|
||||
if get_none(fig) is None:
|
||||
fig = plt.figure() # self.iplot) ### WHY? MP MP
|
||||
plt_flag = 1
|
||||
ax = fig.add_subplot(3, 1, i + 1, sharex=ax1)
|
||||
@@ -1332,22 +1334,6 @@ def get_quality_class(uncertainty, weight_classes):
|
||||
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):
|
||||
"""
|
||||
Taper cf data to get rid off of side maximas
|
||||
@@ -1508,7 +1494,7 @@ def getQualityFromUncertainty(uncertainty, Errors):
|
||||
# set initial quality to 4 (worst) and change only if one condition is hit
|
||||
quality = 4
|
||||
|
||||
if get_None(uncertainty) is None:
|
||||
if get_none(uncertainty) is None:
|
||||
return quality
|
||||
|
||||
if uncertainty <= Errors[0]:
|
||||
@@ -1532,3 +1518,17 @@ if __name__ == '__main__':
|
||||
import doctest
|
||||
|
||||
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 matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
||||
from pylot.core.util.utils import identifyPhaseID
|
||||
from scipy.interpolate import griddata
|
||||
|
||||
from pylot.core.pick.utils import get_quality_class
|
||||
@@ -123,8 +124,8 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.cmaps_box = QtWidgets.QComboBox()
|
||||
self.cmaps_box.setMaxVisibleItems(20)
|
||||
[self.cmaps_box.addItem(map_name) for map_name in sorted(plt.colormaps())]
|
||||
# try to set to hsv as default
|
||||
self.cmaps_box.setCurrentIndex(self.cmaps_box.findText('hsv'))
|
||||
# try to set to viridis as default
|
||||
self.cmaps_box.setCurrentIndex(self.cmaps_box.findText('viridis'))
|
||||
|
||||
self.top_row.addWidget(QtWidgets.QLabel('Select a phase: '))
|
||||
self.top_row.addWidget(self.comboBox_phase)
|
||||
@@ -279,9 +280,12 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.canvas.axes.figure.canvas.draw_idle()
|
||||
|
||||
def onpick(self, event):
|
||||
btn_msg = {1: ' in selection. Aborted', 2: ' to delete a pick on. Aborted', 3: ' to display info.'}
|
||||
ind = event.ind
|
||||
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
|
||||
if button == 1:
|
||||
self.openPickDlg(ind)
|
||||
@@ -384,7 +388,14 @@ class Array_map(QtWidgets.QWidget):
|
||||
try:
|
||||
station_name = st_id.split('.')[-1]
|
||||
# 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 not pick['spe']:
|
||||
continue
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -189,7 +190,11 @@ class Metadata(object):
|
||||
metadata = self.get_metadata(seed_id, time)
|
||||
if not metadata:
|
||||
return
|
||||
return metadata['data'].get_coordinates(seed_id, time)
|
||||
try:
|
||||
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 stat_info_from_parser(parser):
|
||||
|
||||
@@ -42,7 +42,7 @@ def main(project_file_path, manual=False, auto=True, file_format='png', f_ext=''
|
||||
for item in input_list:
|
||||
array_map_worker(item)
|
||||
else:
|
||||
pool = multiprocessing.Pool(ncores)
|
||||
pool = multiprocessing.Pool(ncores, maxtasksperchild=1000)
|
||||
pool.map(array_map_worker, input_list)
|
||||
pool.close()
|
||||
pool.join()
|
||||
|
||||
@@ -160,7 +160,7 @@ class MultiThread(QThread):
|
||||
try:
|
||||
if not self.ncores:
|
||||
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.apply_async(self.func, self.shotlist, callback=self.emitDone) #emit each time returned
|
||||
pool.close()
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import glob
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import subprocess
|
||||
import warnings
|
||||
from typing import Literal, Tuple, Type
|
||||
from functools import lru_cache
|
||||
|
||||
import numpy as np
|
||||
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.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):
|
||||
if m.im_self is None:
|
||||
@@ -81,25 +88,6 @@ def fit_curve(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):
|
||||
"""
|
||||
Generate mulitprocessing pool object utilizing ncores amount of cores
|
||||
@@ -119,7 +107,7 @@ def gen_Pool(ncores=0):
|
||||
|
||||
print('gen_Pool: Generated multiprocessing Pool with {} cores\n'.format(ncores))
|
||||
|
||||
pool = multiprocessing.Pool(ncores)
|
||||
pool = multiprocessing.Pool(ncores, maxtasksperchild=100)
|
||||
return pool
|
||||
|
||||
|
||||
@@ -165,11 +153,11 @@ def clims(lim1, lim2):
|
||||
"""
|
||||
takes two pairs of limits and returns one pair of common limts
|
||||
:param lim1: limit 1
|
||||
:type lim1: int
|
||||
:type lim1: List[int]
|
||||
:param lim2: limit 2
|
||||
:type lim2: int
|
||||
:type lim2: List[int]
|
||||
:return: new upper and lower limit common to both given limits
|
||||
:rtype: [int, int]
|
||||
:rtype: List[int]
|
||||
|
||||
>>> clims([0, 4], [1, 3])
|
||||
[0, 4]
|
||||
@@ -301,7 +289,7 @@ def fnConstructor(s):
|
||||
if type(s) is str:
|
||||
s = s.split(':')[-1]
|
||||
else:
|
||||
s = getHash(UTCDateTime())
|
||||
s = get_hash(UTCDateTime())
|
||||
|
||||
badchars = re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
|
||||
badsuffix = re.compile(r'(aux|com[1-9]|con|lpt[1-9]|prn)(\.|$)')
|
||||
@@ -313,15 +301,32 @@ def fnConstructor(s):
|
||||
return fn
|
||||
|
||||
|
||||
def get_None(value):
|
||||
def get_none(value):
|
||||
"""
|
||||
Convert "None" to None
|
||||
:param value:
|
||||
:type value: str, bool
|
||||
:type value: str, NoneType
|
||||
: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
|
||||
else:
|
||||
return value
|
||||
@@ -329,11 +334,32 @@ def get_None(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:
|
||||
:type value: str, bool
|
||||
:type value: str, bool, int, float
|
||||
:return: true boolean value
|
||||
: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
|
||||
>>> get_bool('Stream')
|
||||
'Stream'
|
||||
"""
|
||||
if type(value) is bool:
|
||||
return value
|
||||
@@ -341,8 +367,14 @@ def get_bool(value):
|
||||
return True
|
||||
elif value in ['False', 'false']:
|
||||
return False
|
||||
elif isinstance(value, float) or isinstance(value, int):
|
||||
if value > 0. or value > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return bool(value)
|
||||
return value
|
||||
|
||||
|
||||
def four_digits(year):
|
||||
"""
|
||||
@@ -353,8 +385,8 @@ def four_digits(year):
|
||||
:return: four digit year correspondent
|
||||
:rtype: int
|
||||
|
||||
>>> four_digits(20)
|
||||
1920
|
||||
>>> four_digits(75)
|
||||
1975
|
||||
>>> four_digits(16)
|
||||
2016
|
||||
>>> four_digits(00)
|
||||
@@ -436,36 +468,53 @@ def backtransformFilterString(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
|
||||
:param time: time object for which a hash should be calculated
|
||||
:type time: `~obspy.core.utcdatetime.UTCDateTime`
|
||||
:return: SHA1 hash
|
||||
: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.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()
|
||||
|
||||
|
||||
def getLogin():
|
||||
def get_login():
|
||||
"""
|
||||
returns the actual user's login ID
|
||||
:return: login ID
|
||||
returns the actual user's name
|
||||
:return: login name
|
||||
:rtype: str
|
||||
"""
|
||||
import getpass
|
||||
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
|
||||
:param fn: filename of the file tested
|
||||
:type fn: str
|
||||
:return: login ID of the file's owner
|
||||
: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()
|
||||
if system_name in ["Linux", "Darwin"]:
|
||||
@@ -511,6 +560,11 @@ def is_executable(fn):
|
||||
:param fn: path to the file to be tested
|
||||
:return: True or False
|
||||
: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)
|
||||
|
||||
@@ -537,24 +591,36 @@ def isSorted(iterable):
|
||||
>>> isSorted([2,3,1,4])
|
||||
False
|
||||
"""
|
||||
assert isIterable(iterable), 'object is not iterable; object: {' \
|
||||
'}'.format(iterable)
|
||||
assert is_iterable(iterable), "object is not iterable; object: {}".format(iterable)
|
||||
if type(iterable) is str:
|
||||
iterable = [s for s in 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
|
||||
False otherwise
|
||||
:param obj: a python object
|
||||
:type obj: object
|
||||
:type obj: obj
|
||||
:return: True of False
|
||||
: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:
|
||||
iterator = iter(obj)
|
||||
iter(obj)
|
||||
except TypeError as te:
|
||||
return False
|
||||
return True
|
||||
@@ -563,13 +629,19 @@ def isIterable(obj):
|
||||
def key_for_set_value(d):
|
||||
"""
|
||||
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
|
||||
:type d: dict
|
||||
:return: key to the first non-False value found; None if no value's
|
||||
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
|
||||
for k, v in d.items():
|
||||
if v:
|
||||
@@ -577,32 +649,53 @@ def key_for_set_value(d):
|
||||
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
|
||||
:param stime: start time of the actual seismogram as UTCDateTime
|
||||
:type stime: `~obspy.core.utcdatetime.UTCDateTime`
|
||||
:param offset: offset of the actual seismogram on plotting axis
|
||||
:type offset: float or int
|
||||
:param trace: seismic trace object
|
||||
:type trace: `~obspy.core.trace.Trace`
|
||||
:param verbosity: if != 0, debug output will be written to console
|
||||
:type verbosity: int
|
||||
:return: valid numpy array with time stamps for plotting
|
||||
: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
|
||||
srate = trace.stats.sampling_rate
|
||||
tincr = trace.stats.delta
|
||||
etime = stime + nsamp / srate
|
||||
time_ax = np.linspace(stime, etime, nsamp)
|
||||
etime = offset + nsamp / srate
|
||||
time_ax = np.linspace(offset, etime, nsamp)
|
||||
if len(time_ax) < nsamp:
|
||||
if verbosity:
|
||||
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:
|
||||
if verbosity:
|
||||
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:
|
||||
print('Station {0}, {1} samples of data \n '
|
||||
'{2} length of time vector \n'
|
||||
@@ -618,13 +711,13 @@ def find_horizontals(data):
|
||||
:param data: waveform data
|
||||
:type data: `obspy.core.stream.Stream`
|
||||
:return: components list
|
||||
:rtype: list
|
||||
:rtype: List(str)
|
||||
|
||||
..example::
|
||||
|
||||
>>> st = read()
|
||||
>>> find_horizontals(st)
|
||||
[u'N', u'E']
|
||||
['N', 'E']
|
||||
"""
|
||||
rval = []
|
||||
for tr in data:
|
||||
@@ -635,7 +728,7 @@ def find_horizontals(data):
|
||||
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.
|
||||
|
||||
@@ -648,7 +741,7 @@ def pick_color(picktype, phase, quality=0):
|
||||
:param quality: quality of pick. Decides the new intensity of the modifier color
|
||||
:type quality: int
|
||||
:return: tuple containing modified rgba color values
|
||||
:rtype: (int, int, int, int)
|
||||
:rtype: Rgba
|
||||
"""
|
||||
min_quality = 3
|
||||
bpc = base_phase_colors(picktype, phase) # returns dict like {'modifier': 'g', 'rgba': (0, 0, 255, 255)}
|
||||
@@ -704,17 +797,17 @@ def pick_linestyle_plt(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
|
||||
:param rgba: tuple containing rgba values
|
||||
:type rgba: (int, int, int, int)
|
||||
:param modifier: which color should be modified, eg. 'r', 'g', 'b'
|
||||
:type modifier: str
|
||||
:type rgba: Rgba
|
||||
:param modifier: which color should be modified; options: 'r', 'g', 'b'
|
||||
:type modifier: Literal['r', 'g', 'b']
|
||||
:param intensity: intensity to be added to selected color
|
||||
:type intensity: float
|
||||
:return: tuple containing rgba values
|
||||
:rtype: (int, int, int, int)
|
||||
:rtype: Rgba
|
||||
"""
|
||||
rgba = list(rgba)
|
||||
index = {'r': 0,
|
||||
@@ -748,18 +841,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]
|
||||
:param colors: tuple of rgba color values ranging from [0, 255]
|
||||
: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
|
||||
:return: String containing r, g, b values and alpha value if no_alpha is False (default)
|
||||
: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:
|
||||
colors_mpl = '({}, {}, {})'.format(*colors_mpl)
|
||||
return '({}, {}, {})'.format(*transform_colors_mpl(colors))
|
||||
else:
|
||||
colors_mpl = '({}, {}, {}, {})'.format(*colors_mpl)
|
||||
return colors_mpl
|
||||
return '({}, {}, {}, {})'.format(*transform_colors_mpl(colors))
|
||||
|
||||
|
||||
def transform_colors_mpl(colors):
|
||||
@@ -769,27 +864,16 @@ def transform_colors_mpl(colors):
|
||||
:type colors: (float, float, float, float)
|
||||
:return: tuple of rgba color values ranging from [0, 1]
|
||||
: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_mpl = tuple([color / 255. for color in colors])
|
||||
return colors_mpl
|
||||
|
||||
|
||||
def remove_underscores(data):
|
||||
"""
|
||||
takes a `obspy.core.stream.Stream` object and removes all underscores
|
||||
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):
|
||||
"""
|
||||
cut a stream so only the part common to all three traces is kept to avoid dealing with offsets
|
||||
@@ -818,19 +902,6 @@ def trim_station_components(data, trim_start=True, trim_end=True):
|
||||
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):
|
||||
"""
|
||||
check for gaps in Stream and remove them
|
||||
@@ -851,12 +922,12 @@ def check4gapsAndRemove(data):
|
||||
return data
|
||||
|
||||
|
||||
def check4gapsAndMerge(data):
|
||||
def check_for_gaps_and_merge(data):
|
||||
"""
|
||||
check for gaps in Stream and merge if gaps are found
|
||||
:param data: stream of seismic data
|
||||
:type data: `~obspy.core.stream.Stream`
|
||||
:return: data stream
|
||||
:return: data stream, gaps returned from obspy get_gaps
|
||||
:rtype: `~obspy.core.stream.Stream`
|
||||
"""
|
||||
gaps = data.get_gaps()
|
||||
@@ -867,7 +938,7 @@ def check4gapsAndMerge(data):
|
||||
for merged_station in merged:
|
||||
print(merged_station)
|
||||
|
||||
return data
|
||||
return data, gaps
|
||||
|
||||
|
||||
def check4doubled(data):
|
||||
@@ -897,13 +968,53 @@ def check4doubled(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):
|
||||
"""
|
||||
Get list of all station names in data stream
|
||||
Get list of all station names in data-stream
|
||||
:param data: stream containing seismic traces
|
||||
:type data: `~obspy.core.stream.Stream`
|
||||
:return: list of all station names in data, no duplicates
|
||||
:rtype: list of str
|
||||
:rtype: List(str)
|
||||
"""
|
||||
stations = []
|
||||
for tr in data:
|
||||
@@ -930,66 +1041,87 @@ def check4rotated(data, metadata=None, verbosity=1):
|
||||
: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).
|
||||
|
||||
Azimut and dip are fetched from metadata. To be rotated, traces of a station have to be cut to the same length.
|
||||
Returns unrotated traces of no metadata is provided
|
||||
:param wfstream: stream containing seismic traces of a station
|
||||
:type wfstream: `~obspy.core.stream.Stream`
|
||||
:param wfs_in: stream containing seismic traces of a station
|
||||
:type wfs_in: `~obspy.core.stream.Stream`
|
||||
:param metadata: tuple containing metadata type string and metadata parser object
|
||||
:type metadata: (str, `~obspy.io.xseed.parser.Parser`)
|
||||
:return: stream object with traditionally oriented traces (ZNE)
|
||||
:rtype: `~obspy.core.stream.Stream`
|
||||
"""
|
||||
|
||||
# check if any traces in this station need to be rotated
|
||||
trace_ids = [trace.id for trace in wfstream]
|
||||
orientations = [trace_id[-1] for trace_id in trace_ids]
|
||||
rotation_required = [orientation.isnumeric() for orientation in orientations]
|
||||
if any(rotation_required):
|
||||
t_start = full_range(wfstream)
|
||||
try:
|
||||
azimuts = []
|
||||
dips = []
|
||||
for tr_id in trace_ids:
|
||||
azimuts.append(metadata.get_coordinates(tr_id, t_start)['azimuth'])
|
||||
dips.append(metadata.get_coordinates(tr_id, t_start)['dip'])
|
||||
except (KeyError, TypeError) as e:
|
||||
print('Failed to rotate trace {}, no azimuth or dip available in metadata'.format(tr_id))
|
||||
return wfstream
|
||||
if len(wfstream) < 3:
|
||||
print('Failed to rotate Stream {}, not enough components available.'.format(wfstream))
|
||||
return wfstream
|
||||
# to rotate all traces must have same length, so trim them
|
||||
wfstream = trim_station_components(wfstream, trim_start=True, trim_end=True)
|
||||
try:
|
||||
z, n, e = rotate2zne(wfstream[0], azimuts[0], dips[0],
|
||||
wfstream[1], azimuts[1], dips[1],
|
||||
wfstream[2], azimuts[2], dips[2])
|
||||
print('check4rotated: rotated trace {} to ZNE'.format(trace_ids))
|
||||
# replace old data with rotated data, change the channel code to ZNE
|
||||
z_index = dips.index(min(
|
||||
dips)) # get z-trace index, z has minimum dip of -90 (dip is measured from 0 to -90, with -90 being vertical)
|
||||
wfstream[z_index].data = z
|
||||
wfstream[z_index].stats.channel = wfstream[z_index].stats.channel[0:-1] + 'Z'
|
||||
del trace_ids[z_index]
|
||||
for trace_id in trace_ids:
|
||||
coordinates = metadata.get_coordinates(trace_id, t_start)
|
||||
dip, az = coordinates['dip'], coordinates['azimuth']
|
||||
trace = wfstream.select(id=trace_id)[0]
|
||||
if az > 315 or az <= 45 or az > 135 and az <= 225:
|
||||
trace.data = n
|
||||
trace.stats.channel = trace.stats.channel[0:-1] + 'N'
|
||||
elif az > 45 and az <= 135 or az > 225 and az <= 315:
|
||||
trace.data = e
|
||||
trace.stats.channel = trace.stats.channel[0:-1] + 'E'
|
||||
except (ValueError) as e:
|
||||
print(e)
|
||||
return wfstream
|
||||
if len(wfs_in) < 3:
|
||||
print(f"Stream {wfs_in=}, has not enough components to rotate.")
|
||||
return wfs_in
|
||||
|
||||
return wfstream
|
||||
# check if any traces in this station need to be rotated
|
||||
trace_ids = [trace.id for trace in wfs_in]
|
||||
if not rotation_required(trace_ids):
|
||||
logging.debug(f"Stream does not need any rotation: Traces are {trace_ids=}")
|
||||
return wfs_in
|
||||
|
||||
# check metadata quality
|
||||
t_start = full_range(wfs_in)
|
||||
try:
|
||||
azimuths = []
|
||||
dips = []
|
||||
for tr_id in trace_ids:
|
||||
azimuths.append(metadata.get_coordinates(tr_id, t_start)['azimuth'])
|
||||
dips.append(metadata.get_coordinates(tr_id, t_start)['dip'])
|
||||
except (KeyError, TypeError) as err:
|
||||
logging.error(f"{type(err)=} occurred: {err=} Rotating not possible, not all azimuth and dip information "
|
||||
f"available in metadata. Stream remains unchanged.")
|
||||
return wfs_in
|
||||
except Exception as err:
|
||||
print(f"Unexpected {err=}, {type(err)=}")
|
||||
raise
|
||||
|
||||
# to rotate all traces must have same length, so trim them
|
||||
wfs_out = trim_station_components(wfs_in, trim_start=True, trim_end=True)
|
||||
try:
|
||||
z, n, e = rotate2zne(wfs_out[0], azimuths[0], dips[0],
|
||||
wfs_out[1], azimuths[1], dips[1],
|
||||
wfs_out[2], azimuths[2], dips[2])
|
||||
print('check4rotated: rotated trace {} to ZNE'.format(trace_ids))
|
||||
# replace old data with rotated data, change the channel code to ZNE
|
||||
z_index = dips.index(min(
|
||||
dips)) # get z-trace index, z has minimum dip of -90 (dip is measured from 0 to -90, with -90
|
||||
# being vertical)
|
||||
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]
|
||||
for trace_id in trace_ids:
|
||||
coordinates = metadata.get_coordinates(trace_id, t_start)
|
||||
dip, az = coordinates['dip'], coordinates['azimuth']
|
||||
trace = wfs_out.select(id=trace_id)[0]
|
||||
if az > 315 or az <= 45 or 135 < az <= 225:
|
||||
trace.data = n
|
||||
trace.stats.channel = trace.stats.channel[0:-1] + 'N'
|
||||
elif 45 < az <= 135 or 225 < az <= 315:
|
||||
trace.data = e
|
||||
trace.stats.channel = trace.stats.channel[0:-1] + 'E'
|
||||
except ValueError as err:
|
||||
print(f"{err=} Rotation failed. Stream remains unchanged.")
|
||||
return wfs_in
|
||||
|
||||
return wfs_out
|
||||
|
||||
if metadata is None:
|
||||
if verbosity:
|
||||
@@ -1003,38 +1135,6 @@ def check4rotated(data, metadata=None, verbosity=1):
|
||||
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):
|
||||
"""
|
||||
run an external program specified by cmd with parameters input returning the
|
||||
@@ -1106,6 +1206,7 @@ def identifyPhase(phase):
|
||||
return False
|
||||
|
||||
|
||||
@lru_cache
|
||||
def identifyPhaseID(phase):
|
||||
"""
|
||||
Returns phase id (capital P or S)
|
||||
|
||||
@@ -7,6 +7,7 @@ Created on Wed Mar 19 11:27:35 2014
|
||||
import copy
|
||||
import datetime
|
||||
import getpass
|
||||
import glob
|
||||
import multiprocessing
|
||||
import os
|
||||
import subprocess
|
||||
@@ -16,6 +17,7 @@ import traceback
|
||||
|
||||
import matplotlib
|
||||
import numpy as np
|
||||
from pylot.core.io.phases import getQualitiesfromxml
|
||||
|
||||
matplotlib.use('QT5Agg')
|
||||
|
||||
@@ -36,7 +38,7 @@ from PySide2.QtWidgets import QAction, QApplication, QCheckBox, QComboBox, \
|
||||
QGridLayout, QLabel, QLineEdit, QMessageBox, \
|
||||
QTabWidget, QToolBar, QVBoxLayout, QHBoxLayout, QWidget, \
|
||||
QPushButton, QFileDialog, QInputDialog
|
||||
from PySide2.QtCore import QSettings, Qt, QUrl, Signal
|
||||
from PySide2.QtCore import QSettings, Qt, QUrl, Signal, QTimer
|
||||
from PySide2.QtWebEngineWidgets import QWebEngineView as QWebView
|
||||
from obspy import Stream, Trace, UTCDateTime
|
||||
from obspy.core.util import AttribDict
|
||||
@@ -49,12 +51,12 @@ from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \
|
||||
from pylot.core.pick.compare import Comparison
|
||||
from pylot.core.pick.autopick import fmpicker
|
||||
from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS
|
||||
from pylot.core.util.utils import prepTimeAxis, full_range, demeanTrace, isSorted, findComboBoxIndex, clims, \
|
||||
from pylot.core.util.utils import prep_time_axis, full_range, demeanTrace, isSorted, findComboBoxIndex, clims, \
|
||||
pick_linestyle_plt, pick_color_plt, \
|
||||
check4rotated, check4doubled, merge_stream, identifyPhase, \
|
||||
check4rotated, check4doubled, check_for_gaps_and_merge, check_for_nan, identifyPhase, \
|
||||
loopIdentifyPhase, trim_station_components, transformFilteroptions2String, \
|
||||
identifyPhaseID, get_bool, get_None, pick_color, getAutoFilteroptions, SetChannelComponents, \
|
||||
station_id_remove_channel
|
||||
identifyPhaseID, get_bool, get_none, pick_color, getAutoFilteroptions, SetChannelComponents, \
|
||||
station_id_remove_channel, get_pylot_eventfile_with_extension, get_possible_pylot_eventfile_extensions
|
||||
from autoPyLoT import autoPyLoT
|
||||
from pylot.core.util.thread import Thread
|
||||
from pylot.core.util.dataprocessing import Metadata
|
||||
@@ -864,9 +866,24 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
|
||||
def plotWFData(self, wfdata, wfsyn=None, title=None, scaleddata=False, mapping=True,
|
||||
component='*', nth_sample=1, verbosity=0, method='normal', gain=1., shift_syn=0.2):
|
||||
def station_sort(nslc):
|
||||
"""Try to sort after station integer in case of a line array (e.g. active seismics)"""
|
||||
try:
|
||||
rval = sorted(nslc, key=lambda x: int(x.split('.')[1]))
|
||||
return rval
|
||||
except ValueError as e:
|
||||
# this is the standard case for seismological stations
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f'Sorting by station integer failed with unknown exception: {e}')
|
||||
|
||||
# fallback to default sorting
|
||||
return sorted(nslc)
|
||||
|
||||
if not wfdata:
|
||||
print('Nothing to plot.')
|
||||
return
|
||||
|
||||
self.title = title
|
||||
self.clearPlotDict()
|
||||
self.wfstart, self.wfend = full_range(wfdata)
|
||||
@@ -884,14 +901,14 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
else:
|
||||
st_select = wfdata
|
||||
|
||||
st_select, gaps = merge_stream(st_select)
|
||||
# st_select, gaps = check_for_gaps_and_merge(st_select) #MP MP commented because probably done twice
|
||||
|
||||
# list containing tuples of network, station, channel (for sorting)
|
||||
nslc = []
|
||||
for trace in st_select:
|
||||
nslc.append(
|
||||
trace.get_id()) # (trace.stats.network, trace.stats.station, trace.stats.location trace.stats.channel))
|
||||
nslc.sort()
|
||||
nslc = station_sort(nslc)
|
||||
nslc.reverse()
|
||||
plots = []
|
||||
|
||||
@@ -923,10 +940,10 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
msg = 'plotting %s channel of station %s' % (channel, station)
|
||||
print(msg)
|
||||
stime = trace.stats.starttime - self.wfstart
|
||||
time_ax = prepTimeAxis(stime, trace)
|
||||
time_ax = prep_time_axis(stime, trace)
|
||||
if st_syn:
|
||||
stime_syn = trace_syn.stats.starttime - self.wfstart
|
||||
time_ax_syn = prepTimeAxis(stime_syn, trace_syn)
|
||||
time_ax_syn = prep_time_axis(stime_syn, trace_syn)
|
||||
|
||||
if method == 'fast':
|
||||
trace.data, time_ax = self.minMax(trace, time_ax)
|
||||
@@ -955,7 +972,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
self.ylabel = ''
|
||||
self.setXLims([0, self.wfend - self.wfstart])
|
||||
self.setYLims([0.5, nmax + 0.5])
|
||||
return plots, gaps
|
||||
return plots
|
||||
|
||||
def minMax(self, trace, time_ax):
|
||||
'''
|
||||
@@ -977,7 +994,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
min_ = data.min(axis=1)
|
||||
max_ = data.max(axis=1)
|
||||
if remaining_samples:
|
||||
extreme_values = np.empty((npixel + 1, 2), dtype=np.float)
|
||||
extreme_values = np.empty((npixel + 1, 2), dtype=float)
|
||||
extreme_values[:-1, 0] = min_
|
||||
extreme_values[:-1, 1] = max_
|
||||
extreme_values[-1, 0] = \
|
||||
@@ -985,7 +1002,7 @@ class WaveformWidgetPG(QtWidgets.QWidget):
|
||||
extreme_values[-1, 1] = \
|
||||
trace.data[-remaining_samples:].max()
|
||||
else:
|
||||
extreme_values = np.empty((npixel, 2), dtype=np.float)
|
||||
extreme_values = np.empty((npixel, 2), dtype=float)
|
||||
extreme_values[:, 0] = min_
|
||||
extreme_values[:, 1] = max_
|
||||
data = extreme_values.flatten()
|
||||
@@ -1395,7 +1412,7 @@ class PylotCanvas(FigureCanvas):
|
||||
plot_streams['wfdata']['data'] = wfdata
|
||||
if wfdata_compare:
|
||||
plot_streams['wfdata_comp']['data'] = wfdata_compare
|
||||
|
||||
|
||||
st_main = plot_streams['wfdata']['data']
|
||||
|
||||
if mapping:
|
||||
@@ -1427,7 +1444,7 @@ class PylotCanvas(FigureCanvas):
|
||||
msg = 'plotting %s channel of station %s' % (channel, station)
|
||||
print(msg)
|
||||
stime = trace.stats.starttime - wfstart
|
||||
time_ax = prepTimeAxis(stime, trace)
|
||||
time_ax = prep_time_axis(stime, trace)
|
||||
if time_ax is not None:
|
||||
if scaleToChannel:
|
||||
st_scale = wfdata.select(channel=scaleToChannel)
|
||||
@@ -1467,7 +1484,7 @@ class PylotCanvas(FigureCanvas):
|
||||
if not scaleddata:
|
||||
trace.detrend('constant')
|
||||
trace.normalize(np.max(np.abs(trace.data)) * 2)
|
||||
time_ax = prepTimeAxis(stime, trace)
|
||||
time_ax = prep_time_axis(stime, trace)
|
||||
times = [time for index, time in enumerate(time_ax) if not index % nth_sample]
|
||||
p_data = compare_stream[0].data
|
||||
# #normalize
|
||||
@@ -1575,6 +1592,178 @@ class PylotCanvas(FigureCanvas):
|
||||
self.draw()
|
||||
|
||||
|
||||
class SearchFileByExtensionDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None, label='Text: ', default_text='.xml', events=None):
|
||||
super(SearchFileByExtensionDialog, self).__init__(parent)
|
||||
self.events = events
|
||||
self.filepaths = []
|
||||
self.file_extensions = []
|
||||
self.check_all_state = True
|
||||
self.merge_strategy = None
|
||||
self.default_text = default_text
|
||||
self.label = label
|
||||
self.setButtons()
|
||||
self.setupUi()
|
||||
self.connectSignals()
|
||||
self.showPaths()
|
||||
self.refreshSelectionBox()
|
||||
# self.refresh_timer = QTimer(self)
|
||||
# self.refresh_timer.timeout.connect(self.showPaths)
|
||||
# self.refresh_timer.start(10000)
|
||||
|
||||
self.resize(800, 450)
|
||||
|
||||
def setupUi(self):
|
||||
ncol = 4
|
||||
self.main_layout = QtWidgets.QVBoxLayout()
|
||||
self.header_layout = QtWidgets.QHBoxLayout()
|
||||
self.footer_layout = QtWidgets.QHBoxLayout()
|
||||
#
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
# widgets inside the dialog
|
||||
self.textLabel = QtWidgets.QLabel(self.label)
|
||||
self.comboBox = QtWidgets.QComboBox()
|
||||
self.comboBox.addItem(self.default_text)
|
||||
self.comboBox.setEditable(True)
|
||||
|
||||
# optional search button, currently disabled. List refreshed when text changes
|
||||
self.searchButton = QtWidgets.QPushButton('Search')
|
||||
self.searchButton.setVisible(False)
|
||||
|
||||
# check/uncheck button for table
|
||||
self.checkAllButton = QtWidgets.QPushButton('Check/Uncheck all')
|
||||
|
||||
# radiobutton for merge selection
|
||||
self.mergeRadioButtonGroup = QtWidgets.QButtonGroup()
|
||||
self.merge_button = QtWidgets.QRadioButton('Merge')
|
||||
self.overwrite_button = QtWidgets.QRadioButton('Overwrite')
|
||||
self.mergeRadioButtonGroup.addButton(self.merge_button)
|
||||
self.mergeRadioButtonGroup.addButton(self.overwrite_button)
|
||||
self.merge_button.setChecked(True)
|
||||
self.merge_strategy = self.merge_button.text()
|
||||
|
||||
# table
|
||||
self.tableWidget = QtWidgets.QTableWidget()
|
||||
tableWidget = self.tableWidget
|
||||
tableWidget.setColumnCount(ncol)
|
||||
tableWidget.setRowCount(len(self.events))
|
||||
tableWidget.setHorizontalHeaderLabels(('', 'Event ID', 'Filename', 'Last modified'))
|
||||
tableWidget.setEditTriggers(tableWidget.NoEditTriggers)
|
||||
tableWidget.setSortingEnabled(True)
|
||||
header = tableWidget.horizontalHeader()
|
||||
header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||
header.setStretchLastSection(True)
|
||||
|
||||
self.statusText = QtWidgets.QLabel()
|
||||
|
||||
self.header_layout.addWidget(self.textLabel)
|
||||
self.header_layout.addWidget(self.comboBox)
|
||||
self.header_layout.addWidget(self.searchButton)
|
||||
|
||||
self.footer_layout.addWidget(self.checkAllButton)
|
||||
self.footer_layout.addWidget(self.statusText)
|
||||
self.footer_layout.addWidget(self.merge_button)
|
||||
self.footer_layout.addWidget(self.overwrite_button)
|
||||
|
||||
self.footer_layout.setStretch(0, 0)
|
||||
self.footer_layout.setStretch(1, 1)
|
||||
|
||||
self.main_layout.addLayout(self.header_layout)
|
||||
self.main_layout.addWidget(self.tableWidget)
|
||||
self.main_layout.addLayout(self.footer_layout)
|
||||
self.main_layout.addWidget(self._buttonbox)
|
||||
|
||||
def showPaths(self):
|
||||
self.filepaths = []
|
||||
fext = self.comboBox.currentText()
|
||||
self.tableWidget.clearContents()
|
||||
for index, event in enumerate(self.events):
|
||||
filename = get_pylot_eventfile_with_extension(event, fext)
|
||||
pf_selected_item = QtWidgets.QTableWidgetItem()
|
||||
check_state = QtCore.Qt.Checked if filename else QtCore.Qt.Unchecked
|
||||
pf_selected_item.setCheckState(check_state)
|
||||
self.tableWidget.setItem(index, 0, pf_selected_item)
|
||||
self.tableWidget.setItem(index, 1, QtWidgets.QTableWidgetItem(f'{event.pylot_id}'))
|
||||
if filename:
|
||||
self.filepaths.append(filename)
|
||||
ts = int(os.path.getmtime(filename))
|
||||
|
||||
# create QTableWidgetItems of filepath and last modification time
|
||||
fname_item = QtWidgets.QTableWidgetItem(f'{os.path.split(filename)[-1]}')
|
||||
fname_item.setData(3, filename)
|
||||
ts_item = QtWidgets.QTableWidgetItem(f'{datetime.datetime.fromtimestamp(ts)}')
|
||||
self.tableWidget.setItem(index, 2, fname_item)
|
||||
self.tableWidget.setItem(index, 3, ts_item)
|
||||
|
||||
self.update_status()
|
||||
|
||||
def refreshSelectionBox(self):
|
||||
fext = self.comboBox.currentText()
|
||||
self.file_extensions = [fext]
|
||||
|
||||
for event in self.events:
|
||||
extensions = get_possible_pylot_eventfile_extensions(event, '*.xml')
|
||||
for ext in extensions:
|
||||
if not ext in self.file_extensions:
|
||||
self.file_extensions.append(ext)
|
||||
|
||||
self.comboBox.clear()
|
||||
for ext in sorted(self.file_extensions):
|
||||
self.comboBox.addItem(ext)
|
||||
|
||||
def setButtons(self):
|
||||
self._buttonbox = QDialogButtonBox(QDialogButtonBox.Ok |
|
||||
QDialogButtonBox.Cancel)
|
||||
|
||||
def toggleCheckAll(self):
|
||||
self.check_all_state = not self.check_all_state
|
||||
self.checkAll(self.check_all_state)
|
||||
|
||||
def checkAll(self, state):
|
||||
state = QtCore.Qt.Checked if state else QtCore.Qt.Unchecked
|
||||
for row_ind in range(self.tableWidget.rowCount()):
|
||||
item = self.tableWidget.item(row_ind, 0)
|
||||
item.setCheckState(state)
|
||||
|
||||
def getChecked(self):
|
||||
filepaths = []
|
||||
for row_ind in range(self.tableWidget.rowCount()):
|
||||
item_check = self.tableWidget.item(row_ind, 0)
|
||||
if item_check.checkState() == QtCore.Qt.Checked:
|
||||
item_fname = self.tableWidget.item(row_ind, 2)
|
||||
if item_fname:
|
||||
filepath = item_fname.data(3)
|
||||
filepaths.append(filepath)
|
||||
return filepaths
|
||||
|
||||
def update_status(self, row=None, col=None):
|
||||
if col is not None and col != 0:
|
||||
return
|
||||
filepaths = self.getChecked()
|
||||
if len(filepaths) > 0:
|
||||
status_text = f"Found {len(filepaths)} eventfile{'s' if len(filepaths) > 1 else ''}. Do you want to load them?"
|
||||
else:
|
||||
status_text = 'Did not find/select any files for specified file mask.'
|
||||
self.statusText.setText(status_text)
|
||||
|
||||
def update_merge_strategy(self):
|
||||
for button in (self.merge_button, self.overwrite_button):
|
||||
if button.isChecked():
|
||||
self.merge_strategy = button.text()
|
||||
|
||||
def connectSignals(self):
|
||||
self._buttonbox.accepted.connect(self.accept)
|
||||
self._buttonbox.rejected.connect(self.reject)
|
||||
self.comboBox.editTextChanged.connect(self.showPaths)
|
||||
self.searchButton.clicked.connect(self.showPaths)
|
||||
self.checkAllButton.clicked.connect(self.toggleCheckAll)
|
||||
self.checkAllButton.clicked.connect(self.update_status)
|
||||
self.tableWidget.cellClicked.connect(self.update_status)
|
||||
self.merge_button.clicked.connect(self.update_merge_strategy)
|
||||
self.overwrite_button.clicked.connect(self.update_merge_strategy)
|
||||
|
||||
|
||||
class SingleTextLineDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None, label='Text: ', default_text='.xml'):
|
||||
super(SingleTextLineDialog, self).__init__(parent)
|
||||
@@ -2064,10 +2253,12 @@ class PickDlg(QDialog):
|
||||
station_id = trace.get_id()
|
||||
starttime = trace.stats.starttime
|
||||
station_coords = self.metadata.get_coordinates(station_id, starttime)
|
||||
if not station_coords:
|
||||
print('get_arrivals: No station coordinates found. Return!')
|
||||
return
|
||||
origins = self.pylot_event.origins
|
||||
if phases == ['None', 'None']:
|
||||
print("get_arrivals: Creation info (manual or auto) not available!")
|
||||
print("Return!")
|
||||
print("get_arrivals: Creation info (manual or auto) not available! Return!")
|
||||
return
|
||||
if origins:
|
||||
source_origin = origins[0]
|
||||
@@ -2179,7 +2370,7 @@ class PickDlg(QDialog):
|
||||
|
||||
# create action and add to menu
|
||||
# phase name transferred using lambda function
|
||||
slot = lambda phase=phase, phaseID=phaseID: phaseSelect[phaseID](phase)
|
||||
slot = lambda ph=phase, phID=phaseID: phaseSelect[phID](ph)
|
||||
picksAction = createAction(parent=self, text=phase,
|
||||
slot=slot,
|
||||
shortcut=shortcut)
|
||||
@@ -2598,7 +2789,7 @@ class PickDlg(QDialog):
|
||||
for wfd in [wfdata, wfdata_comp]:
|
||||
if wfd:
|
||||
for trace in wfd:
|
||||
t = prepTimeAxis(trace.stats.starttime - stime, trace)
|
||||
t = prep_time_axis(trace.stats.starttime - stime, trace)
|
||||
inoise = getnoisewin(t, ini_pick, noise_win, gap_win)
|
||||
trace = demeanTrace(trace, inoise)
|
||||
# upscale trace wfdata in a way that each trace is vertically zoomed to noiselevel*factor
|
||||
@@ -3624,8 +3815,9 @@ class TuneAutopicker(QWidget):
|
||||
# wfdat = remove_underscores(wfdat)
|
||||
# rotate misaligned stations to ZNE
|
||||
# check for gaps and doubled channels
|
||||
wfdat, gaps = merge_stream(wfdat)
|
||||
# check4gaps(wfdat)
|
||||
wfdat, _ = check_for_gaps_and_merge(wfdat)
|
||||
# check for nans
|
||||
check_for_nan(wfdat)
|
||||
check4doubled(wfdat)
|
||||
wfdat = check4rotated(wfdat, self.parent().metadata, verbosity=0)
|
||||
# trim station components to same start value
|
||||
@@ -3782,6 +3974,7 @@ class TuneAutopicker(QWidget):
|
||||
st = self.data.getWFData()
|
||||
tr = st.select(station=self.get_current_station())[0]
|
||||
starttime = tr.stats.starttime
|
||||
# create two lists with figure names and subindices (for subplots) to get the correct axes
|
||||
p_axes = [
|
||||
('mainFig', 0),
|
||||
('aicFig', 0),
|
||||
@@ -4729,8 +4922,8 @@ class InputsTab(PropTab):
|
||||
self.tstopBox = QSpinBox()
|
||||
for spinbox in [self.tstartBox, self.tstopBox]:
|
||||
spinbox.setRange(-99999, 99999)
|
||||
self.tstartBox.setValue(float(settings.value('tstart')) if get_None(settings.value('tstart')) else 0)
|
||||
self.tstopBox.setValue(float(settings.value('tstop')) if get_None(settings.value('tstop')) else 1e6)
|
||||
self.tstartBox.setValue(float(settings.value('tstart')) if get_none(settings.value('tstart')) else 0)
|
||||
self.tstopBox.setValue(float(settings.value('tstop')) if get_none(settings.value('tstop')) else 1e6)
|
||||
self.cuttimesLayout.addWidget(self.tstartBox, 10)
|
||||
self.cuttimesLayout.addWidget(QLabel('[s] and'), 0)
|
||||
self.cuttimesLayout.addWidget(self.tstopBox, 10)
|
||||
@@ -5726,7 +5919,7 @@ class ChooseWaveFormWindow(QWidget):
|
||||
#self.currentSpectro = self.traces[
|
||||
# self.chooseBoxTraces.currentText()[3:]][self.chooseBoxComponent.currentText()].spectrogram(show=False, title=t)
|
||||
#self.currentSpectro.show()
|
||||
applyFFT()
|
||||
self.applyFFT()
|
||||
|
||||
def applyFFT(self, trace):
|
||||
tra = self.traces[self.chooseBoxTraces.currentText()[3:]]['Z']
|
||||
|
||||
Reference in New Issue
Block a user