Compare commits
33 Commits
improve-ut
...
466f19eb2e
| Author | SHA1 | Date | |
|---|---|---|---|
| 466f19eb2e | |||
| 5d90904838 | |||
| 7a13288c85 | |||
| 3f97097bf6 | |||
| 29107ee40c | |||
| fa310461d0 | |||
| 42a7d12292 | |||
| 2e49813292 | |||
| 5d6f4619cc | |||
| db11e125c0 | |||
| b59232d77b | |||
| 176e93d833 | |||
| 759e7bb848 | |||
| 61c3f40063 | |||
| 213819c702 | |||
| 67f34cc871 | |||
| f4f48a930f | |||
| b41e2b2de6 | |||
| a068bb8457 | |||
| 452f2a2e18 | |||
| c3a2ef5022 | |||
| 8e7bd87711 | |||
| d5817adc46 | |||
| 14f01ec46d | |||
| 1b074d14ff | |||
| ce71c549ca | |||
| c4220b389e | |||
| 0f29d0e20d | |||
| e1e0913e3a | |||
| cdcd226c87 | |||
| 5f53cc5365 | |||
| 31ca0d7a85 | |||
| c7f9ad4c6f |
39
.mailmap
Normal file
39
.mailmap
Normal file
@@ -0,0 +1,39 @@
|
||||
Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> <Darius_A@web.de>
|
||||
Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> <darius.arnold@rub.de>
|
||||
Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> <darius.arnold@ruhr-uni-bochum.de>
|
||||
Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> <mail@dariusarnold.de>
|
||||
|
||||
Dennis Wlecklik <dennisw@minos02.geophysik.ruhr-uni-bochum.de>
|
||||
|
||||
Jeldrik Gaal <jeldrikgaal@gmail.com>
|
||||
|
||||
Kaan Coekerim <kaan.coekerim@ruhr-uni-bochum.de>
|
||||
Kaan Coekerim <kaan.coekerim@ruhr-uni-bochum.de> <kaan.coekerim@rub.de>
|
||||
|
||||
Ludger Kueperkoch <kueperkoch@igem-energie.de> <kueperkoch@bestec-for-nature.com>
|
||||
Ludger Kueperkoch <kueperkoch@igem-energie.de> <ludger@quake2.(none)>
|
||||
Ludger Kueperkoch <kueperkoch@igem-energie.de> <ludger@sauron.bestec-for-nature>
|
||||
|
||||
Marc S. Boxberg <marc.boxberg@rub.de>
|
||||
|
||||
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel.paffrath@rub.de>
|
||||
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel@minos01.geophysik.ruhr-uni-bochum.de>
|
||||
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel@minos02.geophysik.ruhr-uni-bochum.de>
|
||||
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel@minos25.geophysik.ruhr-uni-bochum.de>
|
||||
Marcel Paffrath <marcel.paffrath@ruhr-uni-bochum.de> <marcel@email.com>
|
||||
|
||||
Sally Zimmermann <sally.zimmermann@ruhr-uni-bochum.de>
|
||||
|
||||
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastianw@minos01.geophysik.ruhr-uni-bochum.de>
|
||||
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastianw@minos02.geophysik.ruhr-uni-bochum.de>
|
||||
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastianw@minos22.geophysik.ruhr-uni-bochum.de>
|
||||
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastian.wehling-benatelli@scisys.de>
|
||||
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastian.wehling@rub.de>
|
||||
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <sebastian.wehling@rub.de>
|
||||
Sebastian Wehling-Benatelli <sebastian.wehling-benatelli@cgi.com> <DarkBeQst@users.noreply.github.com>
|
||||
|
||||
Thomas Moeller <thomas.moeller@rub.de>
|
||||
|
||||
Ann-Christin Koch <ann-christin.koch@ruhr-uni-bochum.de> <Ann-Christin.Koch@ruhr-uni-bochum.de>
|
||||
|
||||
Sebastian Priebe <sebastian.priebe@rub.de>
|
||||
105
PyLoT.py
105
PyLoT.py
@@ -83,7 +83,7 @@ from pylot.core.util.event import Event
|
||||
from pylot.core.io.location import create_creation_info, create_event
|
||||
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
|
||||
PylotCanvas, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
|
||||
ComparisonWidget, TuneAutopicker, PylotParaBox, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||
ComparisonWidget, TuneAutopicker, PylotParameterWidget, AutoPickDlg, CanvasWidget, AutoPickWidget, \
|
||||
CompareEventsWidget, ProgressBarWidget, AddMetadataWidget, SingleTextLineDialog, LogWidget, PickQualitiesFromXml, \
|
||||
SpectrogramTab, SearchFileByExtensionDialog
|
||||
from pylot.core.util.array_map import Array_map
|
||||
@@ -136,7 +136,7 @@ class MainWindow(QMainWindow):
|
||||
self.project.parameter = self._inputs
|
||||
self.tap = None
|
||||
self.apw = None
|
||||
self.paraBox = None
|
||||
self.parameterWidget = None
|
||||
self.array_map = None
|
||||
self._metadata = Metadata(verbosity=0)
|
||||
self._eventChanged = [False, False]
|
||||
@@ -188,7 +188,6 @@ class MainWindow(QMainWindow):
|
||||
self.table_headers = ['', 'Event', 'Time', 'Lat', 'Lon', 'Depth', 'Ml', 'Mw', '[N] MP', '[N] AP', 'Tuning Set',
|
||||
'Test Set', 'Notes']
|
||||
|
||||
# TODO: refactor rootpath to datapath
|
||||
while True:
|
||||
try:
|
||||
if settings.value("user/FullName", None) is None:
|
||||
@@ -686,10 +685,9 @@ class MainWindow(QMainWindow):
|
||||
# add scroll area used in case number of traces gets too high
|
||||
self.wf_scroll_area = QtWidgets.QScrollArea(self)
|
||||
self.wf_scroll_area.setVisible(False)
|
||||
self.no_data_label = QLabel('No Data')
|
||||
self.no_data_label = QLabel('No Data. If data were already loaded, try to select the event again in the eventbox.')
|
||||
self.no_data_label.setStyleSheet('color: red')
|
||||
self.no_data_label.setAlignment(Qt.AlignCenter)
|
||||
|
||||
# create central matplotlib figure canvas widget
|
||||
self.init_wfWidget()
|
||||
|
||||
@@ -1032,6 +1030,21 @@ class MainWindow(QMainWindow):
|
||||
fname = self.filename_from_action(action)
|
||||
if not fname:
|
||||
return
|
||||
|
||||
qmb = QMessageBox(self, icon=QMessageBox.Question,
|
||||
text='Do you want to overwrite this data?',)
|
||||
overwrite_button = qmb.addButton('Overwrite', QMessageBox.YesRole)
|
||||
merge_button = qmb.addButton('Merge', QMessageBox.NoRole)
|
||||
|
||||
qmb.exec_()
|
||||
|
||||
if qmb.clickedButton() == overwrite_button:
|
||||
merge_strategy = 'Overwrite'
|
||||
elif qmb.clickedButton() == merge_button:
|
||||
merge_strategy = 'Merge'
|
||||
else:
|
||||
return
|
||||
|
||||
if not event:
|
||||
event = self.get_current_event()
|
||||
data = Data(self, event)
|
||||
@@ -1196,7 +1209,7 @@ class MainWindow(QMainWindow):
|
||||
with open(eventlist_file, 'r') as infile:
|
||||
eventlist_subset = [os.path.join(basepath, filename.split('\n')[0]) for filename in
|
||||
infile.readlines()]
|
||||
msg = 'Found file "eventlist.txt" in database path. WILL ONLY USE SELECTED EVENTS out of {} events ' \
|
||||
msg = 'Found file "eventlist.txt" in datapath. WILL ONLY USE SELECTED EVENTS out of {} events ' \
|
||||
'contained in this subset'
|
||||
print(msg.format(len(eventlist_subset)))
|
||||
eventlist = [eventname for eventname in eventlist if eventname in eventlist_subset]
|
||||
@@ -1221,49 +1234,34 @@ class MainWindow(QMainWindow):
|
||||
# get path from first event in list and split them
|
||||
path = eventlist[0]
|
||||
try:
|
||||
system_name = platform.system()
|
||||
if system_name in ["Linux", "Darwin"]:
|
||||
dirs = {
|
||||
'database': path.split('/')[-2],
|
||||
'datapath': os.path.split(path)[0], # path.split('/')[-3],
|
||||
'rootpath': '/' + os.path.join(*path.split('/')[:-3])
|
||||
}
|
||||
elif system_name == "Windows":
|
||||
rootpath = path.split('/')[:-3]
|
||||
rootpath[0] += '/'
|
||||
dirs = {
|
||||
# TODO: Arrange path to meet Win standards
|
||||
'database': path.split('/')[-2],
|
||||
'datapath': path.split('/')[-3],
|
||||
'rootpath': os.path.join(*rootpath)
|
||||
}
|
||||
datapath = os.path.split(path)[0]
|
||||
dirs = {
|
||||
'datapath': datapath,
|
||||
}
|
||||
except Exception as e:
|
||||
dirs = {
|
||||
'database': '',
|
||||
'datapath': '',
|
||||
'rootpath': ''
|
||||
}
|
||||
print('Warning: Could not automatically init folder structure. ({})'.format(e))
|
||||
|
||||
settings = QSettings()
|
||||
settings.setValue("data/dataRoot", dirs['datapath']) # d irs['rootpath'])
|
||||
settings.setValue("data/dataRoot", dirs['datapath'])
|
||||
settings.sync()
|
||||
|
||||
if not self.project.eventlist:
|
||||
# init parameter object
|
||||
self.setParameter(show=False)
|
||||
# hide all parameter (show all needed parameter later)
|
||||
self.paraBox.hide_parameter()
|
||||
self.parameterWidget.hide_parameter()
|
||||
for directory in dirs.keys():
|
||||
# set parameter
|
||||
box = self.paraBox.boxes[directory]
|
||||
self.paraBox.setValue(box, dirs[directory])
|
||||
box = self.parameterWidget.boxes[directory]
|
||||
self.parameterWidget.setValue(box, dirs[directory])
|
||||
# show needed parameter in box
|
||||
self.paraBox.show_parameter(directory)
|
||||
dirs_box = self.paraBox.get_groupbox_dialog('Directories')
|
||||
self.parameterWidget.show_parameter(directory)
|
||||
dirs_box = self.parameterWidget.get_groupbox_dialog('Directories')
|
||||
if not dirs_box.exec_():
|
||||
return
|
||||
self.project.rootpath = dirs['rootpath']
|
||||
self.project.datapath = dirs['datapath']
|
||||
else:
|
||||
if hasattr(self.project, 'datapath'):
|
||||
@@ -1272,7 +1270,6 @@ class MainWindow(QMainWindow):
|
||||
'Datapath missmatch to current project!')
|
||||
return
|
||||
else:
|
||||
self.project.rootpath = dirs['rootpath']
|
||||
self.project.datapath = dirs['datapath']
|
||||
|
||||
self.project.add_eventlist(eventlist)
|
||||
@@ -1360,11 +1357,10 @@ class MainWindow(QMainWindow):
|
||||
return True
|
||||
|
||||
def modify_project_path(self, new_rootpath):
|
||||
# TODO: change root to datapath
|
||||
self.project.rootpath = new_rootpath
|
||||
self.project.datapath = new_rootpath
|
||||
for event in self.project.eventlist:
|
||||
event.rootpath = new_rootpath
|
||||
event.path = os.path.join(event.rootpath, event.datapath, event.database, event.pylot_id)
|
||||
event.datapath = new_rootpath
|
||||
event.path = os.path.join(event.datapath, event.pylot_id)
|
||||
event.path = event.path.replace('\\', '/')
|
||||
event.path = event.path.replace('//', '/')
|
||||
|
||||
@@ -1558,7 +1554,7 @@ class MainWindow(QMainWindow):
|
||||
self.set_fname(self.get_data().getEventFileName(), type)
|
||||
return self.get_fnames(type)
|
||||
|
||||
def saveData(self, event=None, directory=None, outformats=['.xml', '.cnv', '.obs', '_focmec.in', '.pha']):
|
||||
def saveData(self, event=None, directory=None, outformats=None):
|
||||
'''
|
||||
Save event data to directory with specified output formats.
|
||||
:param event: PyLoT Event, if not set current event will be used
|
||||
@@ -1566,6 +1562,8 @@ class MainWindow(QMainWindow):
|
||||
:param outformats: str/list of output formats
|
||||
:return:
|
||||
'''
|
||||
if outformats is None:
|
||||
outformats = ['.xml', '.cnv', '.obs', '_focmec.in', '.pha']
|
||||
if not event:
|
||||
event = self.get_current_event()
|
||||
if not type(outformats) == list:
|
||||
@@ -1701,7 +1699,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# WIP JG
|
||||
def eventlistXml(self):
|
||||
path = self._inputs['rootpath'] + '/' + self._inputs['datapath'] + '/' + self._inputs['database']
|
||||
path = self._inputs['datapath']
|
||||
outpath = self.project.location[:self.project.location.rfind('/')]
|
||||
geteventlistfromxml(path, outpath)
|
||||
return
|
||||
@@ -2197,7 +2195,8 @@ class MainWindow(QMainWindow):
|
||||
if event.pylot_autopicks:
|
||||
self.drawPicks(picktype='auto')
|
||||
if event.pylot_picks or event.pylot_autopicks:
|
||||
self.locateEventAction.setEnabled(True)
|
||||
if not self._inputs.get('extent') == 'global':
|
||||
self.locateEventAction.setEnabled(True)
|
||||
self.qualities_action.setEnabled(True)
|
||||
self.eventlist_xml_action.setEnabled(True)
|
||||
|
||||
@@ -2427,7 +2426,7 @@ class MainWindow(QMainWindow):
|
||||
filterS = filteroptions['S']
|
||||
minP, maxP = filterP.getFreq()
|
||||
minS, maxS = filterS.getFreq()
|
||||
self.paraBox.params_to_gui()
|
||||
self.parameterWidget.params_to_gui()
|
||||
|
||||
def getFilterOptions(self):
|
||||
return self.filteroptions
|
||||
@@ -2632,7 +2631,6 @@ class MainWindow(QMainWindow):
|
||||
picks=self.getPicksOnStation(station, 'manual'),
|
||||
autopicks=self.getPicksOnStation(station, 'auto'),
|
||||
metadata=self.metadata, event=event,
|
||||
model=self.inputs.get('taup_model'),
|
||||
filteroptions=self.filteroptions, wftype=wftype,
|
||||
show_comp_data=self.dataPlot.comp_checkbox.isChecked())
|
||||
if self.filterActionP.isChecked():
|
||||
@@ -3176,8 +3174,8 @@ class MainWindow(QMainWindow):
|
||||
ttt = parameter['ttpatter']
|
||||
outfile = parameter['outpatter']
|
||||
eventname = self.get_current_event_name()
|
||||
obsdir = os.path.join(self._inputs['rootpath'], self._inputs['datapath'], self._inputs['database'], eventname)
|
||||
self.saveData(event=self.get_current_event(), directory=obsdir, outformats='.obs')
|
||||
obsdir = os.path.join(self._inputs['datapath'], eventname)
|
||||
self.saveData(event=self.get_current_event(), directory=obsdir, outformats=['.obs'])
|
||||
filename = 'PyLoT_' + eventname
|
||||
locpath = os.path.join(locroot, 'loc', filename)
|
||||
phasefile = os.path.join(obsdir, filename + '.obs')
|
||||
@@ -3734,6 +3732,7 @@ class MainWindow(QMainWindow):
|
||||
if self.project.parameter:
|
||||
# do this step to update default parameter on older PyLoT projects
|
||||
self.project.parameter.reinit_default_parameters()
|
||||
PylotParameter.check_deprecated_parameters(self.project.parameter)
|
||||
|
||||
self._inputs = self.project.parameter
|
||||
self.updateFilteroptions()
|
||||
@@ -3851,13 +3850,13 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def setParameter(self, checked=0, show=True):
|
||||
if checked: pass # dummy argument to receive trigger signal (checked) if called by QAction
|
||||
if not self.paraBox:
|
||||
self.paraBox = PylotParaBox(self._inputs, parent=self, windowflag=Qt.Window)
|
||||
self.paraBox.accepted.connect(self._setDirty)
|
||||
self.paraBox.accepted.connect(self.filterOptionsFromParameter)
|
||||
if not self.parameterWidget:
|
||||
self.parameterWidget = PylotParameterWidget(self._inputs, parent=self, windowflag=Qt.Window)
|
||||
self.parameterWidget.accepted.connect(self._setDirty)
|
||||
self.parameterWidget.accepted.connect(self.filterOptionsFromParameter)
|
||||
if show:
|
||||
self.paraBox.params_to_gui()
|
||||
self.paraBox.show()
|
||||
self.parameterWidget.params_to_gui()
|
||||
self.parameterWidget.show()
|
||||
|
||||
def deleteAllAutopicks(self):
|
||||
qmb = QMessageBox(self, icon=QMessageBox.Question,
|
||||
@@ -3904,16 +3903,18 @@ class Project(object):
|
||||
Pickable class containing information of a PyLoT project, like event lists and file locations.
|
||||
'''
|
||||
|
||||
# TODO: remove rootpath
|
||||
def __init__(self):
|
||||
self.eventlist = []
|
||||
self.location = None
|
||||
self.rootpath = None
|
||||
self.datapath = None
|
||||
self.dirty = False
|
||||
self.parameter = None
|
||||
self._table = None
|
||||
|
||||
@property
|
||||
def rootpath(self):
|
||||
return self.datapath
|
||||
|
||||
def add_eventlist(self, eventlist):
|
||||
'''
|
||||
Add events from an eventlist containing paths to event directories.
|
||||
@@ -3923,8 +3924,6 @@ class Project(object):
|
||||
return
|
||||
for item in eventlist:
|
||||
event = Event(item)
|
||||
event.rootpath = self.parameter['rootpath']
|
||||
event.database = self.parameter['database']
|
||||
event.datapath = self.parameter['datapath']
|
||||
if not event.path in self.getPaths():
|
||||
self.eventlist.append(event)
|
||||
|
||||
20
README.md
20
README.md
@@ -11,7 +11,7 @@ PILOT has originally been developed in Mathworks' MatLab. In order to distribute
|
||||
problems, it has been decided to redevelop the software package in Python. The great work of the ObsPy group allows easy
|
||||
handling of a bunch of seismic data and PyLoT will benefit a lot compared to the former MatLab version.
|
||||
|
||||
The development of PyLoT is part of the joint research project MAGS2 and AlpArray.
|
||||
The development of PyLoT is part of the joint research project MAGS2, AlpArray and AdriaArray.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -27,28 +27,30 @@ Afterwards run (from the PyLoT main directory where the files *requirements.txt*
|
||||
conda env create -f pylot.yml
|
||||
or
|
||||
|
||||
conda create --name pylot_38 --file requirements.txt
|
||||
conda create -c conda-forge --name pylot_311 python=3.11 --file requirements.txt
|
||||
|
||||
to create a new Anaconda environment called "pylot_38".
|
||||
to create a new Anaconda environment called *pylot_311*.
|
||||
|
||||
Afterwards activate the environment by typing
|
||||
|
||||
conda activate pylot_38
|
||||
conda activate pylot_311
|
||||
|
||||
#### Prerequisites:
|
||||
|
||||
In order to run PyLoT you need to install:
|
||||
|
||||
- Python 3
|
||||
- obspy
|
||||
- pyside2
|
||||
- pyqtgraph
|
||||
- cartopy
|
||||
- joblib
|
||||
- obspy
|
||||
- pyaml
|
||||
- pyqtgraph
|
||||
- pyside2
|
||||
|
||||
(the following are already dependencies of the above packages):
|
||||
- scipy
|
||||
- numpy
|
||||
- matplotlib <= 3.3.x
|
||||
- matplotlib
|
||||
|
||||
#### Some handwork:
|
||||
|
||||
@@ -108,4 +110,4 @@ Others: A. Bruestle, T. Meier, W. Friederich
|
||||
|
||||
[ObsPy]: http://github.com/obspy/obspy/wiki
|
||||
|
||||
April 2022
|
||||
August 2024
|
||||
|
||||
10
autoPyLoT.py
10
autoPyLoT.py
@@ -136,11 +136,9 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
if parameter.hasParam('datastructure'):
|
||||
# getting information on data structure
|
||||
datastructure = DATASTRUCTURE[parameter.get('datastructure')]()
|
||||
dsfields = {'root': parameter.get('rootpath'),
|
||||
'dpath': parameter.get('datapath'),
|
||||
'dbase': parameter.get('database')}
|
||||
dsfields = {'dpath': parameter.get('datapath'),}
|
||||
|
||||
exf = ['root', 'dpath', 'dbase']
|
||||
exf = ['dpath']
|
||||
|
||||
if parameter['eventID'] != '*' and fnames == 'None':
|
||||
dsfields['eventID'] = parameter['eventID']
|
||||
@@ -206,12 +204,10 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
|
||||
locflag = 2
|
||||
else:
|
||||
# started in tune or interactive mode
|
||||
datapath = os.path.join(parameter['rootpath'],
|
||||
parameter['datapath'])
|
||||
datapath = parameter['datapath']
|
||||
events = []
|
||||
for eventID in eventid:
|
||||
events.append(os.path.join(datapath,
|
||||
parameter['database'],
|
||||
eventID))
|
||||
|
||||
if not events:
|
||||
|
||||
@@ -203,8 +203,6 @@ The meaning of the header entries is:
|
||||
PyLoT GUI starts with an empty project. To add events, use the add event data button. Select one or multiple folders
|
||||
containing events.
|
||||
|
||||
[//]: <> (TODO: explain _Directories: Root path, Data path, Database path_)
|
||||
|
||||
### Saving projects
|
||||
|
||||
Save the current project from the menu with File->Save project or File->Save project as. PyLoT uses ``.plp`` files to
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
%Parameters are optimized for %extent data sets!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#main settings#
|
||||
#rootpath# %project path
|
||||
#datapath# %data path
|
||||
#database# %name of data base
|
||||
#eventID# %event ID for single event processing (* for all events found in database)
|
||||
#datapath# %data path
|
||||
#eventID# %event ID for single event processing (* for all events found in datapath)
|
||||
#invdir# %full path to inventory or dataless-seed file
|
||||
PILOT #datastructure# %choose data structure
|
||||
True #apverbose# %choose 'True' or 'False' for terminal output
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
%Parameters are optimized for %extent data sets!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#main settings#
|
||||
/DATA/Insheim #rootpath# %project path
|
||||
EVENT_DATA/LOCAL #datapath# %data path
|
||||
2018.02_Insheim #database# %name of data base
|
||||
e0006.038.18 #eventID# %event ID for single event processing (* for all events found in database)
|
||||
/DATA/Insheim/EVENT_DATA/LOCAL/2018.02_Insheim #datapath# %data path
|
||||
e0006.038.18 #eventID# %event ID for single event processing (* for all events found in datapath)
|
||||
/DATA/Insheim/STAT_INFO #invdir# %full path to inventory or dataless-seed file
|
||||
PILOT #datastructure# %choose data structure
|
||||
True #apverbose# %choose 'True' or 'False' for terminal output
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
%Parameters are optimized for %extent data sets!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#main settings#
|
||||
#rootpath# %project path
|
||||
#datapath# %data path
|
||||
#database# %name of data base
|
||||
#eventID# %event ID for single event processing (* for all events found in database)
|
||||
#datapath# %data path
|
||||
#eventID# %event ID for single event processing (* for all events found in datapath)
|
||||
#invdir# %full path to inventory or dataless-seed file
|
||||
PILOT #datastructure# %choose data structure
|
||||
True #apverbose# %choose 'True' or 'False' for terminal output
|
||||
|
||||
18
pylot.yml
18
pylot.yml
@@ -1,14 +1,12 @@
|
||||
name: pylot_38
|
||||
name: pylot_311
|
||||
channels:
|
||||
- conda-forge
|
||||
- defaults
|
||||
dependencies:
|
||||
- cartopy=0.20.2
|
||||
- matplotlib-base=3.3.4
|
||||
- numpy=1.22.3
|
||||
- obspy=1.3.0
|
||||
- pyqtgraph=0.12.4
|
||||
- pyside2>=5.13.2
|
||||
- python=3.8.12
|
||||
- qt>=5.12.9
|
||||
- scipy=1.8.0
|
||||
- cartopy=0.23.0=py311hcf9f919_1
|
||||
- joblib=1.4.2=pyhd8ed1ab_0
|
||||
- obspy=1.4.1=py311he736701_3
|
||||
- pyaml=24.7.0=pyhd8ed1ab_0
|
||||
- pyqtgraph=0.13.7=pyhd8ed1ab_0
|
||||
- pyside2=5.15.8=py311h3d699ce_4
|
||||
- pytest=8.3.2=pyhd8ed1ab_0
|
||||
@@ -9,7 +9,7 @@ PyLoT - the Python picking and Localization Tool
|
||||
|
||||
This python library contains a graphical user interfaces for picking
|
||||
seismic phases. This software needs ObsPy (http://github.com/obspy/obspy/wiki)
|
||||
and the Qt4 libraries to be installed first.
|
||||
and the Qt libraries to be installed first.
|
||||
|
||||
PILOT has been developed in Mathworks' MatLab. In order to distribute
|
||||
PILOT without facing portability problems, it has been decided to re-
|
||||
|
||||
@@ -6,24 +6,14 @@ import numpy as np
|
||||
Default parameters used for picking
|
||||
"""
|
||||
|
||||
defaults = {'rootpath': {'type': str,
|
||||
'tooltip': 'project path',
|
||||
'value': '',
|
||||
'namestring': 'Root path'},
|
||||
|
||||
'datapath': {'type': str,
|
||||
'tooltip': 'data path',
|
||||
defaults = {'datapath': {'type': str,
|
||||
'tooltip': 'path to eventfolders',
|
||||
'value': '',
|
||||
'namestring': 'Data path'},
|
||||
|
||||
'database': {'type': str,
|
||||
'tooltip': 'name of data base',
|
||||
'value': '',
|
||||
'namestring': 'Database path'},
|
||||
|
||||
'eventID': {'type': str,
|
||||
'tooltip': 'event ID for single event processing (* for all events found in database)',
|
||||
'value': '',
|
||||
'tooltip': 'event ID for single event processing (* for all events found in datapath)',
|
||||
'value': '*',
|
||||
'namestring': 'Event ID'},
|
||||
|
||||
'extent': {'type': str,
|
||||
@@ -511,7 +501,7 @@ defaults = {'rootpath': {'type': str,
|
||||
|
||||
'taup_model': {'type': str,
|
||||
'tooltip': 'Define TauPy model for traveltime estimation. Possible values: 1066a, 1066b, ak135, ak135f, herrin, iasp91, jb, prem, pwdk, sp6',
|
||||
'value': None,
|
||||
'value': 'iasp91',
|
||||
'namestring': 'TauPy model'},
|
||||
|
||||
'taup_phases': {'type': str,
|
||||
@@ -522,9 +512,7 @@ defaults = {'rootpath': {'type': str,
|
||||
|
||||
settings_main = {
|
||||
'dirs': [
|
||||
'rootpath',
|
||||
'datapath',
|
||||
'database',
|
||||
'eventID',
|
||||
'invdir',
|
||||
'datastructure',
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import os
|
||||
|
||||
from pylot.core.io import default_parameters
|
||||
from pylot.core.util.errors import ParameterError
|
||||
@@ -88,10 +90,10 @@ class PylotParameter(object):
|
||||
return bool(self.__parameter)
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
if key in self.__parameter:
|
||||
return self.__parameter[key]
|
||||
except:
|
||||
return None
|
||||
else:
|
||||
logging.warning(f'{key} not found in PylotParameter')
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
try:
|
||||
@@ -418,6 +420,28 @@ class PylotParameter(object):
|
||||
line = value + name + ttip
|
||||
fid.write(line)
|
||||
|
||||
@staticmethod
|
||||
def check_deprecated_parameters(parameters):
|
||||
if parameters.hasParam('database') and parameters.hasParam('rootpath'):
|
||||
parameters['datapath'] = os.path.join(parameters['rootpath'], parameters['datapath'],
|
||||
parameters['database'])
|
||||
logging.warning(
|
||||
f'Parameters database and rootpath are deprecated. '
|
||||
f'Tried to merge them to now path: {parameters["datapath"]}.'
|
||||
)
|
||||
|
||||
remove_keys = []
|
||||
for key in parameters:
|
||||
if not key in default_parameters.defaults.keys():
|
||||
remove_keys.append(key)
|
||||
logging.warning(f'Removing deprecated parameter: {key}')
|
||||
|
||||
for key in remove_keys:
|
||||
del parameters[key]
|
||||
|
||||
parameters._settings_main = default_parameters.settings_main
|
||||
parameters._settings_special_pick = default_parameters.settings_special_pick
|
||||
|
||||
|
||||
class FilterOptions(object):
|
||||
'''
|
||||
|
||||
@@ -512,7 +512,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
||||
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')))
|
||||
(parameter.get('datapath'), parameter.get('eventID')))
|
||||
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||
for key in arrivals:
|
||||
# P onsets
|
||||
@@ -665,7 +665,7 @@ def writephases(arrivals, fformat, filename, parameter=None, eventinfo=None):
|
||||
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')))
|
||||
fid.write('%s, event %s \n' % (parameter.get('datapath'), parameter.get('eventID')))
|
||||
arrivals = chooseArrivals(arrivals) # MP MP what is chooseArrivals? It is not defined anywhere
|
||||
for key in arrivals:
|
||||
# P onsets
|
||||
|
||||
@@ -17,7 +17,11 @@ autoregressive prediction: application ot local and regional distances, Geophys.
|
||||
:author: MAGS2 EP3 working group
|
||||
"""
|
||||
import numpy as np
|
||||
from scipy import signal
|
||||
try:
|
||||
from scipy.signal import tukey
|
||||
except ImportError:
|
||||
from scipy.signal.windows import tukey
|
||||
|
||||
from obspy.core import Stream
|
||||
|
||||
from pylot.core.pick.utils import PickingFailedException
|
||||
|
||||
@@ -5,12 +5,13 @@ import traceback
|
||||
|
||||
import cartopy.crs as ccrs
|
||||
import cartopy.feature as cf
|
||||
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
|
||||
import matplotlib
|
||||
import matplotlib.patheffects as PathEffects
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import obspy
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2 import QtWidgets, QtGui
|
||||
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
|
||||
@@ -24,10 +25,10 @@ matplotlib.use('Qt5Agg')
|
||||
|
||||
class MplCanvas(FigureCanvas):
|
||||
|
||||
def __init__(self, parent=None, extern_axes=None, width=5, height=4, dpi=100):
|
||||
def __init__(self, extern_axes=None, projection=None, width=15, height=5, dpi=100):
|
||||
if extern_axes is None:
|
||||
self.fig = plt.figure(figsize=(width, height), dpi=dpi)
|
||||
self.axes = self.fig.add_subplot(111)
|
||||
self.axes = self.fig.add_subplot(111, projection=projection)
|
||||
else:
|
||||
self.fig = extern_axes.figure
|
||||
self.axes = extern_axes
|
||||
@@ -63,20 +64,25 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.highlighted_stations = []
|
||||
|
||||
# call functions to draw everything
|
||||
self.projection = ccrs.PlateCarree()
|
||||
self.init_graphics()
|
||||
self.ax = self.canvas.axes
|
||||
self.ax.set_adjustable('datalim')
|
||||
|
||||
self.init_stations()
|
||||
self.init_crtpyMap()
|
||||
self.init_map()
|
||||
|
||||
# set original map limits to fall back on when home button is pressed
|
||||
self.org_xlim = self.canvas.axes.get_xlim()
|
||||
self.org_ylim = self.canvas.axes.get_ylim()
|
||||
self.org_xlim = self.ax.get_xlim()
|
||||
self.org_ylim = self.ax.get_ylim()
|
||||
|
||||
# initial map without event
|
||||
self.canvas.axes.set_xlim(self.org_xlim[0], self.org_xlim[1])
|
||||
self.canvas.axes.set_ylim(self.org_ylim[0], self.org_ylim[1])
|
||||
self.ax.set_xlim(self.org_xlim[0], self.org_xlim[1])
|
||||
self.ax.set_ylim(self.org_ylim[0], self.org_ylim[1])
|
||||
|
||||
self._style = None if not hasattr(parent, '_style') else parent._style
|
||||
|
||||
|
||||
def init_map(self):
|
||||
self.init_colormap()
|
||||
self.connectSignals()
|
||||
@@ -89,11 +95,11 @@ class Array_map(QtWidgets.QWidget):
|
||||
# initialize figure elements
|
||||
|
||||
if self.extern_plot_axes is None:
|
||||
self.canvas = MplCanvas(self)
|
||||
self.plotWidget = FigureCanvas(self.canvas.fig)
|
||||
self.canvas = MplCanvas(projection=self.projection)
|
||||
else:
|
||||
self.canvas = MplCanvas(self, extern_axes=self.extern_plot_axes)
|
||||
self.plotWidget = FigureCanvas(self.canvas.fig)
|
||||
self.canvas = MplCanvas(extern_axes=self.extern_plot_axes)
|
||||
|
||||
self.plotWidget = self.canvas
|
||||
|
||||
# initialize GUI elements
|
||||
self.status_label = QtWidgets.QLabel()
|
||||
@@ -105,7 +111,7 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.setLayout(self.main_box)
|
||||
|
||||
self.top_row = QtWidgets.QHBoxLayout()
|
||||
self.main_box.addLayout(self.top_row, 1)
|
||||
self.main_box.addLayout(self.top_row, 0)
|
||||
|
||||
self.comboBox_phase = QtWidgets.QComboBox()
|
||||
self.comboBox_phase.insertItem(0, 'P')
|
||||
@@ -138,10 +144,10 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.top_row.addWidget(self.auto_refresh_box)
|
||||
self.top_row.addWidget(self.refresh_button)
|
||||
|
||||
self.main_box.addWidget(self.plotWidget, 1)
|
||||
self.main_box.addWidget(self.plotWidget, 10)
|
||||
|
||||
self.bot_row = QtWidgets.QHBoxLayout()
|
||||
self.main_box.addLayout(self.bot_row, 0.3)
|
||||
self.main_box.addLayout(self.bot_row, 0)
|
||||
self.bot_row.addWidget(QtWidgets.QLabel(''), 5)
|
||||
self.bot_row.addWidget(self.map_reset_button, 2)
|
||||
self.bot_row.addWidget(self.go2eq_button, 2)
|
||||
@@ -153,14 +159,12 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.init_lat_lon_grid()
|
||||
|
||||
def init_crtpyMap(self):
|
||||
self.canvas.axes.cla()
|
||||
self.canvas.axes = plt.axes(projection=ccrs.PlateCarree())
|
||||
self.canvas.axes.add_feature(cf.LAND)
|
||||
self.canvas.axes.add_feature(cf.OCEAN)
|
||||
self.canvas.axes.add_feature(cf.COASTLINE, linewidth=1, edgecolor='gray')
|
||||
self.canvas.axes.add_feature(cf.BORDERS, alpha=0.7)
|
||||
self.canvas.axes.add_feature(cf.LAKES, alpha=0.7)
|
||||
self.canvas.axes.add_feature(cf.RIVERS, linewidth=1)
|
||||
self.ax.add_feature(cf.LAND)
|
||||
self.ax.add_feature(cf.OCEAN)
|
||||
self.ax.add_feature(cf.COASTLINE, linewidth=1, edgecolor='gray')
|
||||
self.ax.add_feature(cf.BORDERS, alpha=0.7)
|
||||
self.ax.add_feature(cf.LAKES, alpha=0.7)
|
||||
self.ax.add_feature(cf.RIVERS, linewidth=1)
|
||||
|
||||
# parallels and meridians
|
||||
self.add_merid_paral()
|
||||
@@ -168,12 +172,8 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.canvas.fig.tight_layout()
|
||||
|
||||
def add_merid_paral(self):
|
||||
self.gridlines = self.canvas.axes.gridlines(draw_labels=False, alpha=0.6, color='gray',
|
||||
linewidth=self.linewidth / 2, zorder=7)
|
||||
# TODO: current cartopy version does not support label removal. Devs are working on it.
|
||||
# Should be fixed in coming cartopy versions
|
||||
# self.gridlines.xformatter = LONGITUDE_FORMATTER
|
||||
# self.gridlines.yformatter = LATITUDE_FORMATTER
|
||||
self.gridlines = self.ax.gridlines(draw_labels=False, alpha=0.6, color='gray',
|
||||
linewidth=self.linewidth / 2, zorder=7, crs=ccrs.PlateCarree())
|
||||
|
||||
def remove_merid_paral(self):
|
||||
if len(self.gridlines.xline_artists):
|
||||
@@ -181,24 +181,24 @@ class Array_map(QtWidgets.QWidget):
|
||||
self.gridlines.yline_artists[0].remove()
|
||||
|
||||
def org_map_view(self):
|
||||
self.canvas.axes.set_xlim(self.org_xlim[0], self.org_xlim[1])
|
||||
self.canvas.axes.set_ylim(self.org_ylim[0], self.org_ylim[1])
|
||||
self.ax.set_xlim(self.org_xlim[0], self.org_xlim[1])
|
||||
self.ax.set_ylim(self.org_ylim[0], self.org_ylim[1])
|
||||
# parallels and meridians
|
||||
self.remove_merid_paral()
|
||||
self.add_merid_paral()
|
||||
#self.remove_merid_paral()
|
||||
#self.add_merid_paral()
|
||||
|
||||
self.canvas.axes.figure.canvas.draw_idle()
|
||||
self.canvas.draw_idle()
|
||||
|
||||
def go2eq(self):
|
||||
if self.eventLoc:
|
||||
lats, lons = self.eventLoc
|
||||
self.canvas.axes.set_xlim(lons - 10, lons + 10)
|
||||
self.canvas.axes.set_ylim(lats - 5, lats + 5)
|
||||
self.ax.set_xlim(lons - 10, lons + 10)
|
||||
self.ax.set_ylim(lats - 5, lats + 5)
|
||||
# parallels and meridians
|
||||
self.remove_merid_paral()
|
||||
self.add_merid_paral()
|
||||
#self.remove_merid_paral()
|
||||
#self.add_merid_paral()
|
||||
|
||||
self.canvas.axes.figure.canvas.draw_idle()
|
||||
self.canvas.draw_idle()
|
||||
|
||||
else:
|
||||
self.status_label.setText('No event information available')
|
||||
@@ -220,21 +220,32 @@ class Array_map(QtWidgets.QWidget):
|
||||
|
||||
# set mouse events -----------------------------------------------------
|
||||
def mouse_moved(self, event):
|
||||
if not event.inaxes == self.canvas.axes:
|
||||
if not event.inaxes == self.ax:
|
||||
return
|
||||
else:
|
||||
cont, inds = self.sc.contains(event)
|
||||
lat = event.ydata
|
||||
lon = event.xdata
|
||||
self.status_label.setText('Latitude: {:3.5f}, Longitude: {:3.5f}'.format(lat, lon))
|
||||
text = f'Longitude: {lon:3.3f}, Latitude: {lat:3.3f}'
|
||||
|
||||
if cont:
|
||||
indices = inds['ind']
|
||||
text += ' | Station: ' if len(indices) == 1 else ' | Stations: '
|
||||
text += ' - '.join([self._station_onpick_ids[index] for index in indices[:5]])
|
||||
if len(indices) > 5:
|
||||
text += '...'
|
||||
|
||||
self.status_label.setText(text)
|
||||
|
||||
def mouse_scroll(self, event):
|
||||
if not event.inaxes == self.canvas.axes:
|
||||
if not event.inaxes == self.ax:
|
||||
return
|
||||
|
||||
zoom = {'up': 1. / 2., 'down': 2.}
|
||||
|
||||
if event.button in zoom:
|
||||
xlim = self.canvas.axes.get_xlim()
|
||||
ylim = self.canvas.axes.get_ylim()
|
||||
xlim = self.ax.get_xlim()
|
||||
ylim = self.ax.get_ylim()
|
||||
|
||||
x, y = event.xdata, event.ydata
|
||||
|
||||
@@ -246,24 +257,24 @@ class Array_map(QtWidgets.QWidget):
|
||||
yb = y - 0.5 * ydiff
|
||||
yt = y + 0.5 * ydiff
|
||||
|
||||
self.canvas.axes.set_xlim(xl, xr)
|
||||
self.canvas.axes.set_ylim(yb, yt)
|
||||
self.ax.set_xlim(xl, xr)
|
||||
self.ax.set_ylim(yb, yt)
|
||||
# parallels and meridians
|
||||
self.remove_merid_paral()
|
||||
self.add_merid_paral()
|
||||
#self.remove_merid_paral()
|
||||
#self.add_merid_paral()
|
||||
|
||||
self.canvas.axes.figure.canvas.draw_idle()
|
||||
self.ax.figure.canvas.draw_idle()
|
||||
|
||||
def mouseLeftPress(self, event):
|
||||
if not event.inaxes == self.canvas.axes:
|
||||
if not event.inaxes == self.ax:
|
||||
return
|
||||
self.map_x = event.xdata
|
||||
self.map_y = event.ydata
|
||||
self.map_xlim = self.canvas.axes.get_xlim()
|
||||
self.map_ylim = self.canvas.axes.get_ylim()
|
||||
self.map_xlim = self.ax.get_xlim()
|
||||
self.map_ylim = self.ax.get_ylim()
|
||||
|
||||
def mouseLeftRelease(self, event):
|
||||
if not event.inaxes == self.canvas.axes:
|
||||
if not event.inaxes == self.ax:
|
||||
return
|
||||
new_x = event.xdata
|
||||
new_y = event.ydata
|
||||
@@ -271,13 +282,13 @@ class Array_map(QtWidgets.QWidget):
|
||||
dx = new_x - self.map_x
|
||||
dy = new_y - self.map_y
|
||||
|
||||
self.canvas.axes.set_xlim((self.map_xlim[0] - dx, self.map_xlim[1] - dx))
|
||||
self.canvas.axes.set_ylim(self.map_ylim[0] - dy, self.map_ylim[1] - dy)
|
||||
self.ax.set_xlim((self.map_xlim[0] - dx, self.map_xlim[1] - dx))
|
||||
self.ax.set_ylim(self.map_ylim[0] - dy, self.map_ylim[1] - dy)
|
||||
# parallels and meridians
|
||||
self.remove_merid_paral()
|
||||
self.add_merid_paral()
|
||||
#self.remove_merid_paral()
|
||||
#self.add_merid_paral()
|
||||
|
||||
self.canvas.axes.figure.canvas.draw_idle()
|
||||
self.ax.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.'}
|
||||
@@ -421,6 +432,9 @@ class Array_map(QtWidgets.QWidget):
|
||||
picks_rel[st_id] = pick
|
||||
return picks_rel
|
||||
|
||||
def get_picks_rel_mean_corr(picks):
|
||||
return get_picks_rel(picks, func=np.nanmean)
|
||||
|
||||
self.picks, self.uncertainties = get_picks(self.stations_dict)
|
||||
self.picks_rel = get_picks_rel(self.picks)
|
||||
|
||||
@@ -469,13 +483,20 @@ class Array_map(QtWidgets.QWidget):
|
||||
stat_dict = self.stations_dict['{}.{}'.format(network, station)]
|
||||
lat = stat_dict['latitude']
|
||||
lon = stat_dict['longitude']
|
||||
self.highlighted_stations.append(self.canvas.axes.scatter(lon, lat, s=self.pointsize, edgecolors=color,
|
||||
facecolors='none', zorder=12,
|
||||
transform=ccrs.PlateCarree(), label='deleted'))
|
||||
self.highlighted_stations.append(self.ax.scatter(lon, lat, s=self.pointsize, edgecolors=color,
|
||||
facecolors='none', zorder=12,
|
||||
transform=ccrs.PlateCarree(), label='deleted'))
|
||||
|
||||
def openPickDlg(self, ind):
|
||||
wfdata = self._parent.get_data().getWFData()
|
||||
wfdata_comp = self._parent.get_data().getWFDataComp()
|
||||
try:
|
||||
wfdata = self._parent.get_data().getWFData()
|
||||
except AttributeError:
|
||||
QtWidgets.QMessageBox.warning(
|
||||
self, "PyLoT Warning",
|
||||
"No waveform data found. Check if they were already loaded in Waveform plot tab."
|
||||
)
|
||||
return
|
||||
wfdata_comp = self._parent.get_data().getAltWFdata()
|
||||
for index in ind:
|
||||
network, station = self._station_onpick_ids[index].split('.')[:2]
|
||||
pyl_mw = self._parent
|
||||
@@ -490,7 +511,6 @@ class Array_map(QtWidgets.QWidget):
|
||||
picks=self._parent.get_current_event().getPick(station),
|
||||
autopicks=self._parent.get_current_event().getAutopick(station),
|
||||
filteroptions=self._parent.filteroptions, metadata=self.metadata,
|
||||
model=self.parameter.get('taup_model'),
|
||||
event=pyl_mw.get_current_event())
|
||||
except Exception as e:
|
||||
message = 'Could not generate Plot for station {st}.\n {er}'.format(st=station, er=e)
|
||||
@@ -521,9 +541,9 @@ class Array_map(QtWidgets.QWidget):
|
||||
def draw_contour_filled(self, nlevel=50):
|
||||
levels = np.linspace(self.get_min_from_picks(), self.get_max_from_picks(), nlevel)
|
||||
|
||||
self.contourf = self.canvas.axes.contourf(self.longrid, self.latgrid, self.picksgrid_active, levels,
|
||||
linewidths=self.linewidth * 5, transform=ccrs.PlateCarree(),
|
||||
alpha=0.4, zorder=8, cmap=self.get_colormap())
|
||||
self.contourf = self.ax.contourf(self.longrid, self.latgrid, self.picksgrid_active, levels,
|
||||
linewidths=self.linewidth * 5, transform=ccrs.PlateCarree(),
|
||||
alpha=0.4, zorder=8, cmap=self.get_colormap())
|
||||
|
||||
def get_colormap(self):
|
||||
return plt.get_cmap(self.cmaps_box.currentText())
|
||||
@@ -531,18 +551,18 @@ class Array_map(QtWidgets.QWidget):
|
||||
def scatter_all_stations(self):
|
||||
stations, lats, lons = self.get_st_lat_lon_for_plot()
|
||||
|
||||
self.sc = self.canvas.axes.scatter(lons, lats, s=self.pointsize * 3, facecolor='none', marker='.',
|
||||
zorder=10, picker=True, edgecolor='0.5', label='Not Picked',
|
||||
transform=ccrs.PlateCarree())
|
||||
self.sc = self.ax.scatter(lons, lats, s=self.pointsize * 3, facecolor='none', marker='.',
|
||||
zorder=10, picker=True, edgecolor='0.5', label='Not Picked',
|
||||
transform=ccrs.PlateCarree())
|
||||
|
||||
self.cid = self.plotWidget.mpl_connect('pick_event', self.onpick)
|
||||
self._station_onpick_ids = stations
|
||||
if self.eventLoc:
|
||||
lats, lons = self.eventLoc
|
||||
self.sc_event = self.canvas.axes.scatter(lons, lats, s=5 * self.pointsize, facecolor='red', zorder=11,
|
||||
label='Event (might be outside map region)', marker='*',
|
||||
edgecolors='black',
|
||||
transform=ccrs.PlateCarree())
|
||||
self.sc_event = self.ax.scatter(lons, lats, s=5 * self.pointsize, facecolor='red', zorder=11,
|
||||
label='Event (might be outside map region)', marker='*',
|
||||
edgecolors='black',
|
||||
transform=ccrs.PlateCarree())
|
||||
|
||||
def scatter_picked_stations(self):
|
||||
picks, uncertainties, lats, lons = self.get_picks_lat_lon()
|
||||
@@ -555,8 +575,8 @@ class Array_map(QtWidgets.QWidget):
|
||||
for uncertainty in uncertainties])
|
||||
|
||||
cmap = self.get_colormap()
|
||||
self.sc_picked = self.canvas.axes.scatter(lons, lats, s=sizes, edgecolors='white', cmap=cmap,
|
||||
c=picks, zorder=11, label='Picked', transform=ccrs.PlateCarree())
|
||||
self.sc_picked = self.ax.scatter(lons, lats, s=sizes, edgecolors='white', cmap=cmap,
|
||||
c=picks, zorder=11, label='Picked', transform=ccrs.PlateCarree())
|
||||
|
||||
def annotate_ax(self):
|
||||
self.annotations = []
|
||||
@@ -574,20 +594,20 @@ class Array_map(QtWidgets.QWidget):
|
||||
if st in self.marked_stations:
|
||||
color = 'red'
|
||||
self.annotations.append(
|
||||
self.canvas.axes.annotate(' %s' % st, xy=(x + 0.003, y + 0.003), fontsize=self.pointsize / 4.,
|
||||
fontweight='semibold', color=color, alpha=0.8,
|
||||
transform=ccrs.PlateCarree(), zorder=14,
|
||||
path_effects=[PathEffects.withStroke(
|
||||
linewidth=self.pointsize / 15., foreground='k')]))
|
||||
self.ax.annotate(f'{st}', xy=(x + 0.003, y + 0.003), fontsize=self.pointsize / 4.,
|
||||
fontweight='semibold', color=color, alpha=0.8,
|
||||
transform=ccrs.PlateCarree(), zorder=14,
|
||||
path_effects=[PathEffects.withStroke(
|
||||
linewidth=self.pointsize / 15., foreground='k')]))
|
||||
|
||||
self.legend = self.canvas.axes.legend(loc=1, framealpha=1)
|
||||
self.legend = self.ax.legend(loc=1, framealpha=1)
|
||||
self.legend.set_zorder(100)
|
||||
self.legend.get_frame().set_facecolor((1, 1, 1, 0.95))
|
||||
|
||||
def add_cbar(self, label):
|
||||
self.cbax_bg = inset_axes(self.canvas.axes, width="6%", height="75%", loc=5)
|
||||
cbax = inset_axes(self.canvas.axes, width='2%', height='70%', loc=5)
|
||||
cbar = self.canvas.axes.figure.colorbar(self.sc_picked, cax=cbax)
|
||||
self.cbax_bg = inset_axes(self.ax, width="6%", height="75%", loc=5)
|
||||
cbax = inset_axes(self.ax, width='2%', height='70%', loc=5)
|
||||
cbar = self.ax.figure.colorbar(self.sc_picked, cax=cbax)
|
||||
cbar.set_label(label)
|
||||
cbax.yaxis.tick_left()
|
||||
cbax.yaxis.set_label_position('left')
|
||||
|
||||
@@ -22,14 +22,11 @@ class Event(ObsPyEvent):
|
||||
:param path: path to event directory
|
||||
:type path: str
|
||||
"""
|
||||
# TODO: remove rootpath and database
|
||||
self.pylot_id = path.split('/')[-1]
|
||||
# initialize super class
|
||||
super(Event, self).__init__(resource_id=ResourceIdentifier('smi:local/' + self.pylot_id))
|
||||
self.path = path
|
||||
self.database = path.split('/')[-2]
|
||||
self.datapath = os.path.split(path)[0] # path.split('/')[-3]
|
||||
self.rootpath = '/' + os.path.join(*path.split('/')[:-3])
|
||||
self.pylot_autopicks = {}
|
||||
self.pylot_picks = {}
|
||||
self.notes = ''
|
||||
|
||||
@@ -1084,8 +1084,9 @@ def check4rotated(data, metadata=None, verbosity=1):
|
||||
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.")
|
||||
logging.warning(f"Rotating not possible, not all azimuth and dip information "
|
||||
f"available in metadata. Stream remains unchanged.")
|
||||
logging.debug(f"Rotating not possible, {err=}, {type(err)=}")
|
||||
return wfs_in
|
||||
except Exception as err:
|
||||
print(f"Unexpected {err=}, {type(err)=}")
|
||||
|
||||
@@ -8,6 +8,7 @@ import copy
|
||||
import datetime
|
||||
import getpass
|
||||
import glob
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import subprocess
|
||||
@@ -1870,13 +1871,14 @@ class PickDlg(QDialog):
|
||||
|
||||
def __init__(self, parent=None, data=None, data_compare=None, station=None, network=None, location=None, picks=None,
|
||||
autopicks=None, rotate=False, parameter=None, embedded=False, metadata=None, show_comp_data=False,
|
||||
event=None, filteroptions=None, model=None, wftype=None):
|
||||
event=None, filteroptions=None, wftype=None):
|
||||
super(PickDlg, self).__init__(parent, Qt.Window)
|
||||
self.orig_parent = parent
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
|
||||
# initialize attributes
|
||||
self.parameter = parameter
|
||||
model = self.parameter.get('taup_model')
|
||||
self._embedded = embedded
|
||||
self.showCompData = show_comp_data
|
||||
self.station = station
|
||||
@@ -2269,8 +2271,8 @@ class PickDlg(QDialog):
|
||||
arrivals = func[plot](source_origin.depth,
|
||||
source_origin.latitude,
|
||||
source_origin.longitude,
|
||||
station_coords['latitude'],
|
||||
station_coords['longitude'],
|
||||
station_coords.get('latitude'),
|
||||
station_coords.get('longitude'),
|
||||
phases)
|
||||
self.arrivals = arrivals
|
||||
|
||||
@@ -3835,7 +3837,7 @@ class TuneAutopicker(QWidget):
|
||||
self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick']
|
||||
|
||||
def add_parameters(self):
|
||||
self.paraBox = PylotParaBox(self.parameter, parent=self, windowflag=Qt.Widget)
|
||||
self.paraBox = PylotParameterWidget(self.parameter, parent=self, windowflag=Qt.Widget)
|
||||
self.paraBox.set_tune_mode(True)
|
||||
self.update_eventID()
|
||||
self.parameter_layout.addWidget(self.paraBox)
|
||||
@@ -4202,7 +4204,7 @@ class TuneAutopicker(QWidget):
|
||||
self.qmb.show()
|
||||
|
||||
|
||||
class PylotParaBox(QtWidgets.QWidget):
|
||||
class PylotParameterWidget(QtWidgets.QWidget):
|
||||
accepted = QtCore.Signal(str)
|
||||
rejected = QtCore.Signal(str)
|
||||
|
||||
@@ -4316,6 +4318,11 @@ class PylotParaBox(QtWidgets.QWidget):
|
||||
grid = QtWidgets.QGridLayout()
|
||||
|
||||
for index1, name in enumerate(parameter_names):
|
||||
if name in ['rootpath', 'database']:
|
||||
logging.warning(
|
||||
f'Deprecated parameter loaded: {name}. Check if datapath is still correct in parameter widget.'
|
||||
)
|
||||
continue
|
||||
default_item = self.parameter.get_defaults()[name]
|
||||
tooltip = default_item['tooltip']
|
||||
tooltip += ' | type: {}'.format(default_item['type'])
|
||||
@@ -4885,7 +4892,7 @@ class PropTab(QWidget):
|
||||
def getValues(self):
|
||||
return None
|
||||
|
||||
def resetValues(self, infile=None):
|
||||
def resetValues(self, infile):
|
||||
return None
|
||||
|
||||
|
||||
@@ -4982,12 +4989,7 @@ class InputsTab(PropTab):
|
||||
else:
|
||||
index = 2
|
||||
datapath = para.get('datapath') if not para.get('datapath') is None else ''
|
||||
rootpath = para.get('rootpath') if not para.get('rootpath') is None else ''
|
||||
database = para.get('database') if not para.get('database') is None else ''
|
||||
if isinstance(database, int):
|
||||
database = str(database)
|
||||
path = os.path.join(os.path.expanduser('~'), rootpath, datapath, database)
|
||||
values = {"data/dataRoot": self.dataDirEdit.setText("%s" % path),
|
||||
values = {"data/dataRoot": self.dataDirEdit.setText("%s" % datapath),
|
||||
"user/FullName": self.fullNameEdit.text(),
|
||||
"data/Structure": self.structureSelect.setCurrentIndex(index),
|
||||
"tstart": self.tstartBox.setValue(0),
|
||||
|
||||
2
pylot/correlation/__init__.py
Normal file
2
pylot/correlation/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
90
pylot/correlation/parameters_adriaarray.yaml
Normal file
90
pylot/correlation/parameters_adriaarray.yaml
Normal file
@@ -0,0 +1,90 @@
|
||||
############################# correlation parameters #####################################
|
||||
# min_corr_stacking: minimum correlation coefficient for building beam trace
|
||||
# min_corr_export: minimum correlation coefficient for pick export
|
||||
# min_stack: minimum number of stations for building beam trace
|
||||
# t_before: correlation window before pick
|
||||
# t_after: correlation window after pick#
|
||||
# cc_maxlag: maximum shift for initial correlation
|
||||
# cc_maxlag2: maximum shift for second (final) correlation (also for calculating pick uncertainty)
|
||||
# initial_pick_outlier_threshold: (hopefully) threshold for excluding large outliers of initial (AIC) picks
|
||||
# export_threshold: automatically exclude all onsets which deviate more than this threshold from corrected taup onsets
|
||||
# min_picks_export: minimum number of correlated picks for export
|
||||
# min_picks_autopylot: minimum number of reference autopicks picks to continue with event
|
||||
# check_RMS: do RMS check to search for restitution errors (very experimental)
|
||||
# use_taupy_onsets: use taupy onsets as reference picks instead of external picks
|
||||
# station_list: use the following stations as reference for stacking
|
||||
# use_stacked_trace: use existing stacked trace if found (spare re-computation)
|
||||
# data_dir: obspyDMT data subdirectory (e.g. 'raw', 'processed')
|
||||
# pickfile_extension: use quakeML files (PyLoT output) with the following extension, e.g. '_autopylot' for pickfiles
|
||||
# such as 'PyLoT_20170501_141822_autopylot.xml'
|
||||
|
||||
logging: info
|
||||
pick_phases: ['P', 'S']
|
||||
|
||||
# P-phase
|
||||
P:
|
||||
min_corr_stacking: 0.8
|
||||
min_corr_export: 0.6
|
||||
min_stack: 20
|
||||
t_before: 30.
|
||||
t_after: 50.
|
||||
cc_maxlag: 50.
|
||||
cc_maxlag2: 5.
|
||||
initial_pick_outlier_threshold: 30.
|
||||
export_threshold: 2.5
|
||||
min_picks_export: 100
|
||||
min_picks_autopylot: 50
|
||||
check_RMS: True
|
||||
use_taupy_onsets: False
|
||||
station_list: ['HU.MORH', 'HU.TIH', 'OX.FUSE', 'OX.BAD']
|
||||
use_stacked_trace: False
|
||||
data_dir: 'processed'
|
||||
pickfile_extension: '_autopylot'
|
||||
dt_stacking: [250, 250]
|
||||
|
||||
# filter for first correlation (rough)
|
||||
filter_options:
|
||||
freqmax: 0.5
|
||||
freqmin: 0.03
|
||||
# filter for second correlation (fine)
|
||||
filter_options_final:
|
||||
freqmax: 0.5
|
||||
freqmin: 0.03
|
||||
|
||||
filter_type: bandpass
|
||||
sampfreq: 20.0
|
||||
|
||||
# S-phase
|
||||
S:
|
||||
min_corr_stacking: 0.7
|
||||
min_corr_export: 0.6
|
||||
min_stack: 20
|
||||
t_before: 60.
|
||||
t_after: 60.
|
||||
cc_maxlag: 100.
|
||||
cc_maxlag2: 25.
|
||||
initial_pick_outlier_threshold: 30.
|
||||
export_threshold: 5.0
|
||||
min_picks_export: 200
|
||||
min_picks_autopylot: 50
|
||||
check_RMS: True
|
||||
use_taupy_onsets: False
|
||||
station_list: ['HU.MORH','HU.TIH', 'OX.FUSE', 'OX.BAD']
|
||||
use_stacked_trace: False
|
||||
data_dir: 'processed'
|
||||
pickfile_extension: '_autopylot'
|
||||
dt_stacking: [250, 250]
|
||||
|
||||
# filter for first correlation (rough)
|
||||
filter_options:
|
||||
freqmax: 0.1
|
||||
freqmin: 0.01
|
||||
|
||||
# filter for second correlation (fine)
|
||||
filter_options_final:
|
||||
freqmax: 0.2
|
||||
freqmin: 0.01
|
||||
|
||||
filter_type: bandpass
|
||||
sampfreq: 20.0
|
||||
|
||||
1987
pylot/correlation/pick_correlation_correction.py
Normal file
1987
pylot/correlation/pick_correlation_correction.py
Normal file
File diff suppressed because it is too large
Load Diff
40
pylot/correlation/submit_pick_corr_correction.sh
Executable file
40
pylot/correlation/submit_pick_corr_correction.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
#ulimit -s 8192
|
||||
#ulimit -v $(ulimit -v | awk '{printf("%d",$1*0.95)}')
|
||||
#ulimit -v
|
||||
|
||||
#655360
|
||||
|
||||
source /opt/anaconda3/etc/profile.d/conda.sh
|
||||
conda activate pylot_311
|
||||
NSLOTS=20
|
||||
|
||||
#qsub -l low -cwd -l "os=*stretch" -pe smp 40 submit_pick_corr_correction.sh
|
||||
#$ -l low
|
||||
#$ -l h_vmem=6G
|
||||
#$ -cwd
|
||||
#$ -pe smp 20
|
||||
#$ -N corr_pick
|
||||
|
||||
|
||||
export PYTHONPATH="$PYTHONPATH:/home/marcel/git/pylot_tools/"
|
||||
export PYTHONPATH="$PYTHONPATH:/home/marcel/git/"
|
||||
export PYTHONPATH="$PYTHONPATH:/home/marcel/git/pylot/"
|
||||
|
||||
#export MKL_NUM_THREADS=${NSLOTS:=1}
|
||||
#export NUMEXPR_NUM_THREADS=${NSLOTS:=1}
|
||||
#export OMP_NUM_THREADS=${NSLOTS:=1}
|
||||
|
||||
#python pick_correlation_correction.py '/data/AlpArray_Data/dmt_database_mantle_M5.8-6.0' '/home/marcel/.pylot/pylot_alparray_mantle_corr_stack_0.03-0.5.in' -pd -n ${NSLOTS:=1} -istart 0 -istop 100
|
||||
#python pick_correlation_correction.py '/data/AlpArray_Data/dmt_database_mantle_M5.8-6.0' '/home/marcel/.pylot/pylot_alparray_mantle_corr_stack_0.03-0.5.in' -pd -n ${NSLOTS:=1} -istart 100 -istop 200
|
||||
#python pick_correlation_correction.py '/data/AlpArray_Data/dmt_database_mantle_M6.0-6.5' '/home/marcel/.pylot/pylot_alparray_mantle_corr_stack_0.03-0.5.in' -pd -n ${NSLOTS:=1} -istart 0 -istop 100
|
||||
#python pick_correlation_correction.py '/data/AlpArray_Data/dmt_database_mantle_M5.8-6.0' '/home/marcel/.pylot/pylot_alparray_mantle_corr_stack_0.03-0.5.in' -pd -n ${NSLOTS:=1} -istart 100 -istop 200
|
||||
#python pick_correlation_correction.py 'H:\sciebo\dmt_database' 'H:\Sciebo\dmt_database\pylot_alparray_mantle_corr_S_0.01-0.2.in' -pd -n 4 -t
|
||||
|
||||
pylot_infile='/home/marcel/.pylot/pylot_alparray_syn_fwi_mk6_it3.in'
|
||||
#pylot_infile='/home/marcel/.pylot/pylot_adriaarray_corr_P_and_S.in'
|
||||
|
||||
# THIS SCRIPT SHOLD BE CALLED BY "submit_to_grid_engine.py" using the following line:
|
||||
python pick_correlation_correction.py $1 $pylot_infile -pd -n ${NSLOTS:=1} -istart $2 --params 'parameters_fwi_mk6_it3.yaml'
|
||||
#--event_blacklist eventlist.txt
|
||||
23
pylot/correlation/submit_to_grid_engine.py
Executable file
23
pylot/correlation/submit_to_grid_engine.py
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import subprocess
|
||||
|
||||
fnames = [
|
||||
('/data/AlpArray_Data/dmt_database_synth_model_mk6_it3_no_rotation', 0),
|
||||
]
|
||||
|
||||
#fnames = [('/data/AlpArray_Data/dmt_database_mantle_0.01-0.2_SKS-phase', 0),
|
||||
# ('/data/AlpArray_Data/dmt_database_mantle_0.01-0.2_S-phase', 0),]
|
||||
|
||||
####
|
||||
script_location = '/home/marcel/VersionCtrl/git/code_base/correlation_picker/submit_pick_corr_correction.sh'
|
||||
####
|
||||
|
||||
for fnin, istart in fnames:
|
||||
input_cmds = f'qsub -q low.q@minos15,low.q@minos14,low.q@minos13,low.q@minos12,low.q@minos11 {script_location} {fnin} {istart}'
|
||||
|
||||
print(input_cmds)
|
||||
print(subprocess.check_output(input_cmds.split()))
|
||||
|
||||
|
||||
|
||||
61
pylot/correlation/utils.py
Normal file
61
pylot/correlation/utils.py
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import glob
|
||||
import json
|
||||
|
||||
from obspy import read_events
|
||||
|
||||
from pylot.core.util.dataprocessing import Metadata
|
||||
from pylot.core.util.obspyDMT_interface import qml_from_obspyDMT
|
||||
|
||||
|
||||
def get_event_obspy_dmt(eventdir):
|
||||
event_pkl_file = os.path.join(eventdir, 'info', 'event.pkl')
|
||||
if not os.path.exists(event_pkl_file):
|
||||
raise IOError('Could not find event path for event: {}'.format(eventdir))
|
||||
event = qml_from_obspyDMT(event_pkl_file)
|
||||
return event
|
||||
|
||||
|
||||
def get_event_pylot(eventdir, extension=''):
|
||||
event_id = get_event_id(eventdir)
|
||||
filename = os.path.join(eventdir, 'PyLoT_{}{}.xml'.format(event_id, extension))
|
||||
if not os.path.isfile(filename):
|
||||
return
|
||||
cat = read_events(filename)
|
||||
return cat[0]
|
||||
|
||||
|
||||
def get_event_id(eventdir):
|
||||
event_id = os.path.split(eventdir)[-1]
|
||||
return event_id
|
||||
|
||||
|
||||
def get_picks(eventdir, extension=''):
|
||||
event_id = get_event_id(eventdir)
|
||||
filename = 'PyLoT_{}{}.xml'
|
||||
filename = filename.format(event_id, extension)
|
||||
fpath = os.path.join(eventdir, filename)
|
||||
fpaths = glob.glob(fpath)
|
||||
if len(fpaths) == 1:
|
||||
cat = read_events(fpaths[0])
|
||||
picks = cat[0].picks
|
||||
return picks
|
||||
elif len(fpaths) == 0:
|
||||
print('get_picks: File not found: {}'.format(fpath))
|
||||
return
|
||||
print(f'WARNING: Ambiguous pick file specification. Found the following pick files {fpaths}\nFilemask: {fpath}')
|
||||
return
|
||||
|
||||
|
||||
def write_json(object, fname):
|
||||
with open(fname, 'w') as outfile:
|
||||
json.dump(object, outfile, sort_keys=True, indent=4)
|
||||
|
||||
|
||||
def get_metadata(eventdir):
|
||||
metadata_path = os.path.join(eventdir, 'resp')
|
||||
metadata = Metadata(inventory=metadata_path, verbosity=0)
|
||||
return metadata
|
||||
@@ -1,12 +1,7 @@
|
||||
# This file may be used to create an environment using:
|
||||
# $ conda create --name <env> --file <this file>
|
||||
# platform: win-64
|
||||
cartopy=0.20.2
|
||||
matplotlib-base=3.3.4
|
||||
numpy=1.22.3
|
||||
obspy=1.3.0
|
||||
pyqtgraph=0.12.4
|
||||
pyside2=5.13.2
|
||||
python=3.8.12
|
||||
qt=5.12.9
|
||||
scipy=1.8.0
|
||||
Cartopy==0.23.0
|
||||
joblib==1.4.2
|
||||
obspy==1.4.1
|
||||
pyaml==24.7.0
|
||||
pyqtgraph==0.13.7
|
||||
PySide2==5.15.8
|
||||
pytest==8.3.2
|
||||
@@ -0,0 +1,101 @@
|
||||
%This is a parameter input file for PyLoT/autoPyLoT.
|
||||
%All main and special settings regarding data handling
|
||||
%and picking are to be set here!
|
||||
%Parameters are optimized for %extent data sets!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#main settings#
|
||||
#rootpath# %project path
|
||||
#datapath# %data path
|
||||
#database# %name of data base
|
||||
20171010_063224.a #eventID# %event ID for single event processing (* for all events found in database)
|
||||
#invdir# %full path to inventory or dataless-seed file
|
||||
PILOT #datastructure# %choose data structure
|
||||
True #apverbose# %choose 'True' or 'False' for terminal output
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#NLLoc settings#
|
||||
None #nllocbin# %path to NLLoc executable
|
||||
None #nllocroot# %root of NLLoc-processing directory
|
||||
None #phasefile# %name of autoPyLoT-output phase file for NLLoc
|
||||
None #ctrfile# %name of autoPyLoT-output control file for NLLoc
|
||||
ttime #ttpatter# %pattern of NLLoc ttimes from grid
|
||||
AUTOLOC_nlloc #outpatter# %pattern of NLLoc-output file
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#parameters for seismic moment estimation#
|
||||
3530.0 #vp# %average P-wave velocity
|
||||
2500.0 #rho# %average rock density [kg/m^3]
|
||||
300.0 0.8 #Qp# %quality factor for P waves (Qp*f^a); list(Qp, a)
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#settings local magnitude#
|
||||
1.0 1.0 1.0 #WAscaling# %Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] If zeros are set, original Richter magnitude is calculated!
|
||||
1.0 1.0 #magscaling# %Scaling relation for derived local magnitude [a*Ml+b]. If zeros are set, no scaling of network magnitude is applied!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#filter settings#
|
||||
0.03 0.03 #minfreq# %Lower filter frequency [P, S]
|
||||
0.5 0.5 #maxfreq# %Upper filter frequency [P, S]
|
||||
4 4 #filter_order# %filter order [P, S]
|
||||
bandpass bandpass #filter_type# %filter type (bandpass, bandstop, lowpass, highpass) [P, S]
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#common settings picker#
|
||||
global #extent# %extent of array ("local", "regional" or "global")
|
||||
-100.0 #pstart# %start time [s] for calculating CF for P-picking (if TauPy: seconds relative to estimated onset)
|
||||
50.0 #pstop# %end time [s] for calculating CF for P-picking (if TauPy: seconds relative to estimated onset)
|
||||
-50.0 #sstart# %start time [s] relative to P-onset for calculating CF for S-picking
|
||||
50.0 #sstop# %end time [s] after P-onset for calculating CF for S-picking
|
||||
True #use_taup# %use estimated traveltimes from TauPy for calculating windows for CF
|
||||
ak135 #taup_model# %Define TauPy model for traveltime estimation. Possible values: 1066a, 1066b, ak135, ak135f, herrin, iasp91, jb, prem, pwdk, sp6
|
||||
P,Pdiff,S,SKS #taup_phases# %Specify possible phases for TauPy (comma separated). See Obspy TauPy documentation for possible values.
|
||||
0.03 0.5 #bpz1# %lower/upper corner freq. of first band pass filter Z-comp. [Hz]
|
||||
0.01 0.5 #bpz2# %lower/upper corner freq. of second band pass filter Z-comp. [Hz]
|
||||
0.03 0.5 #bph1# %lower/upper corner freq. of first band pass filter H-comp. [Hz]
|
||||
0.01 0.5 #bph2# %lower/upper corner freq. of second band pass filter z-comp. [Hz]
|
||||
#special settings for calculating CF#
|
||||
%!!Edit the following only if you know what you are doing!!%
|
||||
#Z-component#
|
||||
HOS #algoP# %choose algorithm for P-onset determination (HOS, ARZ, or AR3)
|
||||
300.0 #tlta# %for HOS-/AR-AIC-picker, length of LTA window [s]
|
||||
4 #hosorder# %for HOS-picker, order of Higher Order Statistics
|
||||
2 #Parorder# %for AR-picker, order of AR process of Z-component
|
||||
16.0 #tdet1z# %for AR-picker, length of AR determination window [s] for Z-component, 1st pick
|
||||
10.0 #tpred1z# %for AR-picker, length of AR prediction window [s] for Z-component, 1st pick
|
||||
12.0 #tdet2z# %for AR-picker, length of AR determination window [s] for Z-component, 2nd pick
|
||||
6.0 #tpred2z# %for AR-picker, length of AR prediction window [s] for Z-component, 2nd pick
|
||||
0.001 #addnoise# %add noise to seismogram for stable AR prediction
|
||||
60.0 5.0 20.0 12.0 #tsnrz# %for HOS/AR, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]
|
||||
50.0 #pickwinP# %for initial AIC pick, length of P-pick window [s]
|
||||
30.0 #Precalcwin# %for HOS/AR, window length [s] for recalculation of CF (relative to 1st pick)
|
||||
2.0 #aictsmooth# %for HOS/AR, take average of samples for smoothing of AIC-function [s]
|
||||
2.0 #tsmoothP# %for HOS/AR, take average of samples in this time window for smoothing CF [s]
|
||||
0.006 #ausP# %for HOS/AR, artificial uplift of samples (aus) of CF (P)
|
||||
2.0 #nfacP# %for HOS/AR, noise factor for noise level determination (P)
|
||||
#H-components#
|
||||
ARH #algoS# %choose algorithm for S-onset determination (ARH or AR3)
|
||||
12.0 #tdet1h# %for HOS/AR, length of AR-determination window [s], H-components, 1st pick
|
||||
6.0 #tpred1h# %for HOS/AR, length of AR-prediction window [s], H-components, 1st pick
|
||||
8.0 #tdet2h# %for HOS/AR, length of AR-determinaton window [s], H-components, 2nd pick
|
||||
4.0 #tpred2h# %for HOS/AR, length of AR-prediction window [s], H-components, 2nd pick
|
||||
4 #Sarorder# %for AR-picker, order of AR process of H-components
|
||||
100.0 #Srecalcwin# %for AR-picker, window length [s] for recalculation of CF (2nd pick) (H)
|
||||
195.0 #pickwinS# %for initial AIC pick, length of S-pick window [s]
|
||||
60.0 10.0 30.0 12.0 #tsnrh# %for ARH/AR3, window lengths for SNR-and slope estimation [tnoise, tsafetey, tsignal, tslope] [s]
|
||||
22.0 #aictsmoothS# %for AIC-picker, take average of samples in this time window for smoothing of AIC-function [s]
|
||||
20.0 #tsmoothS# %for AR-picker, take average of samples for smoothing CF [s] (S)
|
||||
0.001 #ausS# %for HOS/AR, artificial uplift of samples (aus) of CF (S)
|
||||
2.0 #nfacS# %for AR-picker, noise factor for noise level determination (S)
|
||||
#first-motion picker#
|
||||
1 #minfmweight# %minimum required P weight for first-motion determination
|
||||
3.0 #minFMSNR# %miniumum required SNR for first-motion determination
|
||||
10.0 #fmpickwin# %pick window [s] around P onset for calculating zero crossings
|
||||
#quality assessment#
|
||||
0.1 0.2 0.4 0.8 #timeerrorsP# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for P
|
||||
4.0 8.0 16.0 32.0 #timeerrorsS# %discrete time errors [s] corresponding to picking weights [0 1 2 3] for S
|
||||
0.005 #minAICPslope# %below this slope [counts/s] the initial P pick is rejected
|
||||
1.1 #minAICPSNR# %below this SNR the initial P pick is rejected
|
||||
0.002 #minAICSslope# %below this slope [counts/s] the initial S pick is rejected
|
||||
1.3 #minAICSSNR# %below this SNR the initial S pick is rejected
|
||||
20.0 #minsiglength# %length of signal part for which amplitudes must exceed noiselevel [s]
|
||||
1.0 #noisefactor# %noiselevel*noisefactor=threshold
|
||||
10.0 #minpercent# %required percentage of amplitudes exceeding threshold
|
||||
0.1 #zfac# %P-amplitude must exceed at least zfac times RMS-S amplitude
|
||||
100.0 #mdttolerance# %maximum allowed deviation of P picks from median [s]
|
||||
50.0 #wdttolerance# %maximum allowed deviation from Wadati-diagram
|
||||
25.0 #jackfactor# %pick is removed if the variance of the subgroup with the pick removed is larger than the mean variance of all subgroups times safety factor
|
||||
27
tests/test_autopicker/test_autopylot.py
Normal file
27
tests/test_autopicker/test_autopylot.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from autoPyLoT import autoPyLoT
|
||||
|
||||
|
||||
class TestAutopickerGlobal():
|
||||
def init(self):
|
||||
self.params_infile = 'pylot_alparray_mantle_corr_stack_0.03-0.5.in'
|
||||
self.test_event_dir = 'dmt_database_test'
|
||||
|
||||
if not os.path.isfile(self.params_infile):
|
||||
print(f'Test input file {os.path.abspath(self.params_infile)} not found.')
|
||||
return False
|
||||
|
||||
if not os.path.exists(self.test_event_dir):
|
||||
print(
|
||||
f'Test event directory not found at location "{os.path.abspath(self.test_event_dir)}". '
|
||||
f'Make sure to load it from the website first.'
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def test_autopicker(self):
|
||||
assert self.init(), 'Initialization failed due to missing input files.'
|
||||
#autoPyLoT(inputfile=self.params_infile, eventid='20171010_063224.a')
|
||||
@@ -4,10 +4,8 @@
|
||||
%Parameters are optimized for %extent data sets!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#main settings#
|
||||
/home/darius #rootpath# %project path
|
||||
alparray #datapath# %data path
|
||||
waveforms_used #database# %name of data base
|
||||
e0093.173.16 #eventID# %event ID for single event processing (* for all events found in database)
|
||||
/home/darius/alparray/waveforms_used #datapath# %data path
|
||||
e0093.173.16 #eventID# %event ID for single event processing (* for all events found in datapath)
|
||||
/home/darius/alparray/metadata #invdir# %full path to inventory or dataless-seed file
|
||||
PILOT #datastructure# %choose data structure
|
||||
True #apverbose# %choose 'True' or 'False' for terminal output
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
%Parameters are optimized for %extent data sets!
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#main settings#
|
||||
/home/darius #rootpath# %project path
|
||||
alparray #datapath# %data path
|
||||
waveforms_used #database# %name of data base
|
||||
e0093.173.16 #eventID# %event ID for single event processing (* for all events found in database)
|
||||
/home/darius/alparray/waveforms_used #datapath# %data path
|
||||
e0093.173.16 #eventID# %event ID for single event processing (* for all events found in datapath)
|
||||
/home/darius/alparray/metadata #invdir# %full path to inventory or dataless-seed file
|
||||
PILOT #datastructure# %choose data structure
|
||||
True #apverbose# %choose 'True' or 'False' for terminal output
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import pytest
|
||||
from obspy import read, Trace, UTCDateTime
|
||||
|
||||
from pylot.correlation.pick_correlation_correction import XCorrPickCorrection
|
||||
|
||||
|
||||
class TestXCorrPickCorrection():
|
||||
def setup(self):
|
||||
self.make_test_traces()
|
||||
self.make_test_picks()
|
||||
self.t_before = 2.
|
||||
self.t_after = 2.
|
||||
self.cc_maxlag = 0.5
|
||||
|
||||
def make_test_traces(self):
|
||||
# take first trace of test Stream from obspy
|
||||
tr1 = read()[0]
|
||||
# filter trace
|
||||
tr1.filter('bandpass', freqmin=1, freqmax=20)
|
||||
# make a copy and shift the copy by 0.1 s
|
||||
tr2 = tr1.copy()
|
||||
tr2.stats.starttime += 0.1
|
||||
|
||||
self.trace1 = tr1
|
||||
self.trace2 = tr2
|
||||
|
||||
def make_test_picks(self):
|
||||
# create an artificial reference pick on reference trace (trace1) and another one on the 0.1 s shifted trace
|
||||
self.tpick1 = UTCDateTime('2009-08-24T00:20:07.7')
|
||||
# shift the second pick by 0.2 s, the correction should be around 0.1 s now
|
||||
self.tpick2 = self.tpick1 + 0.2
|
||||
|
||||
def test_slice_trace_okay(self):
|
||||
|
||||
self.setup()
|
||||
xcpc = XCorrPickCorrection(UTCDateTime(), Trace(), UTCDateTime(), Trace(),
|
||||
t_before=self.t_before, t_after=self.t_after, cc_maxlag=self.cc_maxlag)
|
||||
|
||||
test_trace = self.trace1
|
||||
pick_time = self.tpick2
|
||||
|
||||
sliced_trace = xcpc.slice_trace(test_trace, pick_time)
|
||||
assert ((sliced_trace.stats.starttime == pick_time - self.t_before - self.cc_maxlag / 2)
|
||||
and (sliced_trace.stats.endtime == pick_time + self.t_after + self.cc_maxlag / 2))
|
||||
|
||||
def test_slice_trace_fails(self):
|
||||
self.setup()
|
||||
|
||||
test_trace = self.trace1
|
||||
pick_time = self.tpick1
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
xcpc = XCorrPickCorrection(UTCDateTime(), Trace(), UTCDateTime(), Trace(),
|
||||
t_before=self.t_before + 20, t_after=self.t_after, cc_maxlag=self.cc_maxlag)
|
||||
xcpc.slice_trace(test_trace, pick_time)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
xcpc = XCorrPickCorrection(UTCDateTime(), Trace(), UTCDateTime(), Trace(),
|
||||
t_before=self.t_before, t_after=self.t_after + 50, cc_maxlag=self.cc_maxlag)
|
||||
xcpc.slice_trace(test_trace, pick_time)
|
||||
|
||||
def test_cross_correlation(self):
|
||||
self.setup()
|
||||
|
||||
# create XCorrPickCorrection object
|
||||
xcpc = XCorrPickCorrection(self.tpick1, self.trace1, self.tpick2, self.trace2, t_before=self.t_before,
|
||||
t_after=self.t_after, cc_maxlag=self.cc_maxlag)
|
||||
|
||||
# execute correlation
|
||||
correction, cc_max, uncert, fwfm = xcpc.cross_correlation(False, '', '')
|
||||
|
||||
# define awaited test result
|
||||
test_result = (-0.09983091718314982, 0.9578431835689154, 0.0015285160561610929, 0.03625786256084631)
|
||||
|
||||
# check results
|
||||
assert pytest.approx(test_result, rel=1e-6) == (correction, cc_max, uncert, fwfm)
|
||||
Reference in New Issue
Block a user