Merge branch 'develop'

This commit is contained in:
Marcel Paffrath 2017-06-27 15:30:18 +02:00
commit 795733cc5f
13 changed files with 552 additions and 286 deletions

View File

@ -41,6 +41,8 @@ from PySide.QtGui import QMainWindow, QInputDialog, QIcon, QFileDialog, \
QTreeView, QComboBox, QTabWidget, QPushButton, QGridLayout QTreeView, QComboBox, QTabWidget, QPushButton, QGridLayout
import numpy as np import numpy as np
from obspy import UTCDateTime from obspy import UTCDateTime
from obspy.core.event import Magnitude
from obspy.core.util import AttribDict
try: try:
import pyqtgraph as pg import pyqtgraph as pg
@ -70,6 +72,7 @@ from pylot.core.util.connection import checkurl
from pylot.core.util.dataprocessing import read_metadata, restitute_data from pylot.core.util.dataprocessing import read_metadata, restitute_data
from pylot.core.util.utils import fnConstructor, getLogin, \ from pylot.core.util.utils import fnConstructor, getLogin, \
full_range full_range
from pylot.core.util.event import Event
from pylot.core.io.location import create_creation_info, create_event from pylot.core.io.location import create_creation_info, create_event
from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \ from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \
WaveformWidget, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \ WaveformWidget, WaveformWidgetPG, PropertiesDlg, HelpForm, createAction, PickDlg, \
@ -143,6 +146,7 @@ class MainWindow(QMainWindow):
self.data = Data(self, lastEvent) self.data = Data(self, lastEvent)
else: else:
self.data = Data(self) self.data = Data(self)
self.data._new = False
self.autodata = Data(self) self.autodata = Data(self)
if settings.value("user/FullName", None) is None: if settings.value("user/FullName", None) is None:
@ -172,8 +176,8 @@ class MainWindow(QMainWindow):
self.setupUi() self.setupUi()
self.filteroptions = {} self.filteroptions = {}
self.picks = {} self.pylot_picks = {}
self.autopicks = {} self.pylot_autopicks = {}
self.loc = False self.loc = False
def setupUi(self): def setupUi(self):
@ -311,21 +315,21 @@ class MainWindow(QMainWindow):
# self.createNewEvent, # self.createNewEvent,
# QKeySequence.New, newIcon, # QKeySequence.New, newIcon,
# "Create a new event.") # "Create a new event.")
self.openmanualpicksaction = self.createAction(self, "Load &manual picks ...", self.openmanualpicksaction = self.createAction(self, "Load event ...",
self.load_data, self.load_data,
"Ctrl+M", "Ctrl+M",
manupicksicon, manupicksicon,
"Load manual picks for " "Load event information for "
"the displayed event.") "the displayed event.")
self.openmanualpicksaction.setEnabled(False) self.openmanualpicksaction.setEnabled(False)
self.openmanualpicksaction.setData(None) self.openmanualpicksaction.setData(None)
self.openautopicksaction = self.createAction(self, "Load &automatic picks ... ", self.openautopicksaction = self.createAction(self, "Load event information &automatically ... ",
self.load_autopicks, self.load_multiple_data,
"Ctrl+A", "Ctrl+A",
autopicksicon, autopicksicon,
"Load automatic picks " "Load event data automatically "
"for the displayed event.") "for for all events.")
self.openautopicksaction.setEnabled(False) self.openautopicksaction.setEnabled(False)
self.openautopicksaction.setData(None) self.openautopicksaction.setData(None)
@ -637,23 +641,66 @@ class MainWindow(QMainWindow):
fname_dict = dict(phasfn=fn_phases, locfn=fn_loc) fname_dict = dict(phasfn=fn_phases, locfn=fn_loc)
self.load_data(fname_dict, type=type) self.load_data(fname_dict, type=type)
def load_data(self, fname=None, type='manual', loc=False): def load_multiple_data(self, type='manual'):
if not self.okToContinue(): if not self.okToContinue():
return return
refresh=False
events = self.project.eventlist
fext = '.xml'
for event in events:
path = event.path
eventname = path.split('/')[-1]
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
if not refresh:
return
if self.get_current_event().pylot_picks:
self.refreshEvents()
self.setDirty(True)
def load_data(self, fname=None, type='manual', loc=False, draw=True, event=None, overwrite=False):
if not overwrite:
if not self.okToContinue():
return
if fname is None: if fname is None:
action = self.sender() action = self.sender()
if isinstance(action, QAction): if isinstance(action, QAction):
fname = self.filename_from_action(action) fname = self.filename_from_action(action)
if not fname:
return
self.set_fname(fname, type) self.set_fname(fname, type)
data = dict(auto=self.autodata, manual=self.data) #data = dict(auto=self.autodata, manual=self.data)
data[type] += Data(self, evtdata=fname) if not event:
event = self.get_current_event()
data = Data(self, event)
try:
data_new = Data(self, evtdata=fname)
data += data_new
except ValueError:
qmb = QMessageBox(self, icon=QMessageBox.Question,
text='Warning: Missmatch in event identifiers {} and {}. Continue?'.format(
data_new.get_evt_data().resource_id,
data.get_evt_data().resource_id),
windowTitle='PyLoT - Load data warning')
qmb.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
qmb.setDefaultButton(QMessageBox.No)
ret = qmb.exec_()
if ret == qmb.Yes:
data_new.setNew()
data += data_new
else:
return
self.data = data
print('Loading {} picks from file {}.'.format(type, fname))
if not loc: if not loc:
self.updatePicks(type=type) self.updatePicks(type=type, event=event)
if self.get_current_event().picks: if draw:
self.plotWaveformDataThread() if self.get_current_event().pylot_picks:
self.drawPicks(picktype=type) self.refreshEvents()
self.draw() self.setDirty(True)
self.setDirty(True)
def add_recentfile(self, event): def add_recentfile(self, event):
self.recentfiles.insert(0, event) self.recentfiles.insert(0, event)
@ -676,8 +723,8 @@ class MainWindow(QMainWindow):
def getWFFnames(self): def getWFFnames(self):
try: try:
evt = self.get_data().get_evt_data() evt = self.get_data().get_evt_data()
if evt.picks: if evt.pylot_picks:
for pick in evt.picks: for pick in evt.pylot_picks:
try: try:
if pick.waveform_id is not None: if pick.waveform_id is not None:
fname = pick.waveform_id.getSEEDstring() fname = pick.waveform_id.getSEEDstring()
@ -728,8 +775,8 @@ class MainWindow(QMainWindow):
''' '''
if not eventbox: if not eventbox:
eventbox = self.eventBox eventbox = self.eventBox
index = eventbox.currentIndex() path = eventbox.currentText()
return eventbox.itemData(index) return self.project.getEventFromPath(path)
def get_current_event_path(self, eventbox=None): def get_current_event_path(self, eventbox=None):
''' '''
@ -778,7 +825,7 @@ class MainWindow(QMainWindow):
dirs = { dirs = {
'database': path.split('/')[-2], 'database': path.split('/')[-2],
'datapath': path.split('/')[-3], 'datapath': path.split('/')[-3],
'rootpath': os.path.join(*path.split('/')[:-3]) 'rootpath': '/'+os.path.join(*path.split('/')[:-3])
} }
except Exception as e: except Exception as e:
dirs = { dirs = {
@ -788,6 +835,10 @@ class MainWindow(QMainWindow):
} }
print('Warning: Could not automatically init folder structure. ({})'.format(e)) print('Warning: Could not automatically init folder structure. ({})'.format(e))
settings = QSettings()
settings.setValue("data/dataRoot", dirs['rootpath'])
settings.sync()
if not self.project.eventlist: if not self.project.eventlist:
#init parameter object #init parameter object
self.setParameter(show=False) self.setParameter(show=False)
@ -880,10 +931,10 @@ class MainWindow(QMainWindow):
event_path = event.path event_path = event.path
event_npicks = 0 event_npicks = 0
event_nautopicks = 0 event_nautopicks = 0
if event.picks: if event.pylot_picks:
event_npicks = len(event.picks) event_npicks = len(event.pylot_picks)
if event.autopicks: if event.pylot_autopicks:
event_nautopicks = len(event.autopicks) event_nautopicks = len(event.pylot_autopicks)
event_ref = event.isRefEvent() event_ref = event.isRefEvent()
event_test = event.isTestEvent() event_test = event.isTestEvent()
@ -929,7 +980,8 @@ class MainWindow(QMainWindow):
'{} unequal {}.' '{} unequal {}.'
.format(event.path, self.eventBox.itemText(id))) .format(event.path, self.eventBox.itemText(id)))
raise ValueError(message) raise ValueError(message)
eventBox.setItemData(id, event) #not working with obspy events
#eventBox.setItemData(id, event)
eventBox.setCurrentIndex(index) eventBox.setCurrentIndex(index)
self.refreshRefTestButtons() self.refreshRefTestButtons()
@ -940,7 +992,7 @@ class MainWindow(QMainWindow):
caption = "Open an event file" caption = "Open an event file"
fname = QFileDialog().getOpenFileName(self, caption=caption, fname = QFileDialog().getOpenFileName(self, caption=caption,
filter=filt, filter=filt,
dir=self.getRoot()) dir=self.get_current_event_path())
fname = fname[0] fname = fname[0]
else: else:
fname = str(action.data().toString()) fname = str(action.data().toString())
@ -965,7 +1017,7 @@ class MainWindow(QMainWindow):
print('warning: {0}'.format(e)) print('warning: {0}'.format(e))
directory = self.get_current_event_path() directory = self.get_current_event_path()
eventname = self.get_current_event_name() eventname = self.get_current_event_name()
filename = 'picks_'+eventname filename = 'PyLoT_'+eventname
outpath = os.path.join(directory, filename) outpath = os.path.join(directory, filename)
file_filter = "QuakeML file (*.xml);;VELEST observation file " \ file_filter = "QuakeML file (*.xml);;VELEST observation file " \
"format (*.cnv);;NonLinLoc observation file (*.obs)" "format (*.cnv);;NonLinLoc observation file (*.obs)"
@ -986,7 +1038,7 @@ class MainWindow(QMainWindow):
fbasename = self.getEventFileName() fbasename = self.getEventFileName()
exform = settings.value('data/exportFormat', 'QUAKEML') exform = settings.value('data/exportFormat', 'QUAKEML')
try: try:
self.get_data().applyEVTData(self.getPicks()) self.get_data().applyEVTData(self.get_current_event(), typ='event')#getPicks())
except OverwriteError: except OverwriteError:
# msgBox = QMessageBox() # msgBox = QMessageBox()
# msgBox.setText("Picks have been modified!") # msgBox.setText("Picks have been modified!")
@ -1056,7 +1108,7 @@ class MainWindow(QMainWindow):
return self.get_current_event().getPicks() return self.get_current_event().getPicks()
if type == 'auto': if type == 'auto':
return self.get_current_event().getAutopicks() return self.get_current_event().getAutopicks()
# rdict = dict(auto=self.autopicks, manual=self.picks) # rdict = dict(auto=self.pylot_autopicks, manual=self.pylot_picks)
# return rdict[type] # return rdict[type]
def getPicksOnStation(self, station, type='manual'): def getPicksOnStation(self, station, type='manual'):
@ -1130,7 +1182,7 @@ class MainWindow(QMainWindow):
if event: if event:
self.ref_event_button.setChecked(event.isRefEvent()) self.ref_event_button.setChecked(event.isRefEvent())
self.test_event_button.setChecked(event.isTestEvent()) self.test_event_button.setChecked(event.isTestEvent())
self.enableRefTestButtons(bool(self.get_current_event().picks)) self.enableRefTestButtons(bool(self.get_current_event().pylot_picks))
return return
self.ref_event_button.setChecked(False) self.ref_event_button.setChecked(False)
self.test_event_button.setChecked(False) self.test_event_button.setChecked(False)
@ -1189,14 +1241,14 @@ class MainWindow(QMainWindow):
if not event: if not event:
return return
# update picks saved in GUI mainwindow (to be changed in future!!) MP MP # update picks saved in GUI mainwindow (to be changed in future!!) MP MP
if not event.picks: if not event.pylot_picks:
self.picks = {} self.pylot_picks = {}
else: else:
self.picks = event.picks self.pylot_picks = event.pylot_picks
if not event.autopicks: if not event.pylot_autopicks:
self.autopicks = {} self.pylot_autopicks = {}
else: else:
self.autopicks = event.autopicks self.pylot_autopicks = event.pylot_autopicks
# if current tab is waveformPlot-tab and the data in this tab was not yet refreshed # if current tab is waveformPlot-tab and the data in this tab was not yet refreshed
if self.tabs.currentIndex() == 0: if self.tabs.currentIndex() == 0:
if self._eventChanged[0]: if self._eventChanged[0]:
@ -1342,12 +1394,12 @@ class MainWindow(QMainWindow):
self.openautopicksaction.setEnabled(True) self.openautopicksaction.setEnabled(True)
self.loadpilotevent.setEnabled(True) self.loadpilotevent.setEnabled(True)
event = self.get_current_event() event = self.get_current_event()
if event.picks: if event.pylot_picks:
self.picks = event.picks self.pylot_picks = event.pylot_picks
self.drawPicks(picktype='manual') self.drawPicks(picktype='manual')
self.enableSaveManualPicksAction() self.enableSaveManualPicksAction()
if event.autopicks: if event.pylot_autopicks:
self.autopicks = event.autopicks self.pylot_autopicks = event.pylot_autopicks
self.drawPicks(picktype='auto') self.drawPicks(picktype='auto')
self.compare_action.setEnabled(True) self.compare_action.setEnabled(True)
self.draw() self.draw()
@ -1722,14 +1774,16 @@ class MainWindow(QMainWindow):
# raise Exception('FATAL: Should never occur!') # raise Exception('FATAL: Should never occur!')
# MP MP prompt redundant because new picks have to be accepted in the first place closing PickDlg # MP MP prompt redundant because new picks have to be accepted in the first place closing PickDlg
def updatePicks(self, type='manual'): def updatePicks(self, type='manual', event=None):
if not event:
event = self.get_current_event()
picks = picksdict_from_picks(evt=self.get_data(type).get_evt_data()) picks = picksdict_from_picks(evt=self.get_data(type).get_evt_data())
if type == 'manual': if type == 'manual':
self.get_current_event().addPicks(picks) event.addPicks(picks)
self.picks.update(picks) self.pylot_picks.update(picks)
elif type == 'auto': elif type == 'auto':
self.get_current_event().addAutopicks(picks) event.addAutopicks(picks)
self.autopicks.update(picks) self.pylot_autopicks.update(picks)
self.check4Comparison() self.check4Comparison()
def drawPicks(self, station=None, picktype='manual'): def drawPicks(self, station=None, picktype='manual'):
@ -1766,7 +1820,7 @@ class MainWindow(QMainWindow):
for phase in stat_picks: for phase in stat_picks:
picks = stat_picks[phase] picks = stat_picks[phase]
if type(stat_picks[phase]) is not dict: if type(stat_picks[phase]) is not dict and type(stat_picks[phase]) is not AttribDict:
return return
colors = phase_col[phase[0].upper()] colors = phase_col[phase[0].upper()]
@ -1880,8 +1934,8 @@ class MainWindow(QMainWindow):
finally: finally:
os.remove(phasepath) os.remove(phasepath)
self.get_data().applyEVTData(lt.read_location(locpath), type='event') self.get_data().applyEVTData(lt.read_location(locpath), typ='event')
self.get_data().applyEVTData(self.calc_magnitude(), type='event') self.get_data().applyEVTData(self.calc_magnitude(), typ='event')
def init_array_tab(self): def init_array_tab(self):
''' '''
@ -1966,6 +2020,12 @@ class MainWindow(QMainWindow):
if not self.array_map: if not self.array_map:
return return
# refresh with new picks here!!! # refresh with new picks here!!!
event = self.get_current_event()
if hasattr(event, 'origins'):
if event.origins:
lat = event.origins[0].latitude
lon = event.origins[0].longitude
self.array_map.eventLoc = (lat, lon)
self.array_map.refresh_drawings(self.get_current_event().getPicks()) self.array_map.refresh_drawings(self.get_current_event().getPicks())
self._eventChanged[1] = False self._eventChanged[1] = False
@ -1992,19 +2052,19 @@ class MainWindow(QMainWindow):
# changes attributes of the corresponding event # changes attributes of the corresponding event
table = self.project._table table = self.project._table
event = self.project.getEventFromPath(table[row][0].text()) event = self.project.getEventFromPath(table[row][0].text())
if column == 3 or column == 4: if column == 8 or column == 9:
#toggle checked states (exclusive) #toggle checked states (exclusive)
item_ref = table[row][3] item_ref = table[row][8]
item_test = table[row][4] item_test = table[row][9]
if column == 3 and item_ref.checkState(): if column == 8 and item_ref.checkState():
item_test.setCheckState(QtCore.Qt.Unchecked) item_test.setCheckState(QtCore.Qt.Unchecked)
event.setRefEvent(True) event.setRefEvent(True)
elif column == 3 and not item_ref.checkState(): elif column == 8 and not item_ref.checkState():
event.setRefEvent(False) event.setRefEvent(False)
elif column == 4 and item_test.checkState(): elif column == 9 and item_test.checkState():
item_ref.setCheckState(QtCore.Qt.Unchecked) item_ref.setCheckState(QtCore.Qt.Unchecked)
event.setTestEvent(True) event.setTestEvent(True)
elif column == 4 and not item_test.checkState(): elif column == 9 and not item_test.checkState():
event.setTestEvent(False) event.setTestEvent(False)
self.fill_eventbox() self.fill_eventbox()
elif column == 5: elif column == 5:
@ -2020,22 +2080,35 @@ class MainWindow(QMainWindow):
# init new qtable # init new qtable
self.event_table = QtGui.QTableWidget() self.event_table = QtGui.QTableWidget()
self.event_table.setColumnCount(6) self.event_table.setColumnCount(11)
self.event_table.setRowCount(len(eventlist)) self.event_table.setRowCount(len(eventlist))
self.event_table.setHorizontalHeaderLabels(['Event', '[N] MP', self.event_table.setHorizontalHeaderLabels(['Event',
'[N] AP', 'Tuning Set', 'Time',
'Test Set', 'Notes']) 'Lat',
'Lon',
'Depth',
'Mag',
'[N] MP',
'[N] AP',
'Tuning Set',
'Test Set',
'Notes'])
# iterate through eventlist and generate items for table rows # iterate through eventlist and generate items for table rows
self.project._table = [] self.project._table = []
for index, event in enumerate(eventlist): for index, event in enumerate(eventlist):
event_npicks = 0 event_npicks = 0
event_nautopicks = 0 event_nautopicks = 0
if event.picks: if event.pylot_picks:
event_npicks = len(event.picks) event_npicks = len(event.pylot_picks)
if event.autopicks: if event.pylot_autopicks:
event_nautopicks = len(event.autopicks) event_nautopicks = len(event.pylot_autopicks)
item_path = QtGui.QTableWidgetItem() item_path = QtGui.QTableWidgetItem()
item_time = QtGui.QTableWidgetItem()
item_lat = QtGui.QTableWidgetItem()
item_lon = QtGui.QTableWidgetItem()
item_depth = QtGui.QTableWidgetItem()
item_mag = QtGui.QTableWidgetItem()
item_nmp = QtGui.QTableWidgetItem(str(event_npicks)) item_nmp = QtGui.QTableWidgetItem(str(event_npicks))
item_nmp.setIcon(self.manupicksicon_small) item_nmp.setIcon(self.manupicksicon_small)
item_nap = QtGui.QTableWidgetItem(str(event_nautopicks)) item_nap = QtGui.QTableWidgetItem(str(event_nautopicks))
@ -2047,11 +2120,23 @@ class MainWindow(QMainWindow):
item_ref.setBackground(self._colors['ref']) item_ref.setBackground(self._colors['ref'])
item_test.setBackground(self._colors['test']) item_test.setBackground(self._colors['test'])
item_path.setText(event.path) item_path.setText(event.path)
item_notes.setText(event.notes) if hasattr(event, 'origins'):
if event.origins:
origin = event.origins[0]
item_time.setText(str(origin.time).split('.')[0])
item_lon.setText(str(origin.longitude))
item_lat.setText(str(origin.latitude))
item_depth.setText(str(origin.depth))
if hasattr(event, 'magnitudes'):
if event.magnitudes:
magnitude = event.magnitudes[0]
item_mag.setText(str(magnitude.mag))
item_notes.setText(event.notes)
set_enabled(item_path, True, False) set_enabled(item_path, True, False)
set_enabled(item_nmp, True, False) set_enabled(item_nmp, True, False)
set_enabled(item_nap, True, False) set_enabled(item_nap, True, False)
if event.picks: if event.pylot_picks:
set_enabled(item_ref, True, True) set_enabled(item_ref, True, True)
set_enabled(item_test, True, True) set_enabled(item_test, True, True)
else: else:
@ -2067,7 +2152,8 @@ class MainWindow(QMainWindow):
else: else:
item_test.setCheckState(QtCore.Qt.Unchecked) item_test.setCheckState(QtCore.Qt.Unchecked)
column=[item_path, item_nmp, item_nap, item_ref, item_test, item_notes] column=[item_path, item_time, item_lat, item_lon, item_depth, item_mag,
item_nmp, item_nap, item_ref, item_test, item_notes]
self.project._table.append(column) self.project._table.append(column)
for r_index, row in enumerate(self.project._table): for r_index, row in enumerate(self.project._table):
@ -2315,7 +2401,7 @@ class MainWindow(QMainWindow):
self.setDirty(True) self.setDirty(True)
def setDirty(self, value): def setDirty(self, value):
self.saveProjectAction.setEnabled(value) self.saveProjectAction.setEnabled(bool(self.get_current_event().picks))
self.saveProjectAsAction.setEnabled(True) self.saveProjectAsAction.setEnabled(True)
self.project.setDirty(value) self.project.setDirty(value)
self.dirty = value self.dirty = value
@ -2382,6 +2468,63 @@ class Project(object):
self.setDirty() self.setDirty()
else: else:
print('Skipping event with path {}. Already part of project.'.format(event.path)) print('Skipping event with path {}. Already part of project.'.format(event.path))
self.search_eventfile_info()
def read_eventfile_info(self, filename, separator=','):
'''
Try to read event information from file (:param:filename) comparing specific event datetimes.
File structure (each row): event, date, time, magnitude, latitude, longitude, depth
separated by :param:separator each.
'''
infile = open(filename, 'r')
for line in infile.readlines():
event, date, time, mag, lat, lon, depth = line.split(separator)[:7]
#skip first line
try:
month, day, year = date.split('/')
except:
continue
year = int(year)
#hardcoded, if year only consists of 2 digits (e.g. 16 instead of 2016)
if year<100:
year += 2000
datetime = '{}-{}-{}T{}'.format(year, month, day, time)
try:
datetime = UTCDateTime(datetime)
except Exception as e:
print(e, datetime, filename)
continue
for event in self.eventlist:
if not event.origins:
continue
origin = event.origins[0] #should have only one origin
if origin.time == datetime:
origin.latitude = float(lat)
origin.longitude = float(lon)
origin.depth = float(depth)
event.magnitudes.append(Magnitude(resource_id=event.resource_id,
mag=float(mag),
mag_type='M'))
def search_eventfile_info(self):
'''
Search all datapaths in rootpath for filenames with given file extension fext
and try to read event info from it
'''
datapaths = []
fext='.csv'
for event in self.eventlist:
if not event.datapath in datapaths:
datapaths.append(event.datapath)
for datapath in datapaths:
datapath = os.path.join(self.rootpath, datapath)
for filename in os.listdir(datapath):
filename = os.path.join(datapath, filename)
if os.path.isfile(filename) and filename.endswith(fext):
try:
self.read_eventfile_info(filename)
except Exception as e:
print('Failed on reading eventfile info from file {}: {}'.format(filename, e))
def getPaths(self): def getPaths(self):
''' '''
@ -2442,123 +2585,6 @@ class Project(object):
return project return project
class Event(object):
'''
Pickable class containing information on a single event.
'''
def __init__(self, path):
self.path = path
self.database = path.split('/')[-2]
self.datapath = path.split('/')[-3]
self.rootpath = os.path.join(*path.split('/')[:-3])
self.autopicks = {}
self.picks = {}
self.notes = ''
self._testEvent = False
self._refEvent = False
try:
self.get_notes()
except:
pass
def get_notes_path(self):
notesfile = os.path.join(self.path, 'notes.txt')
return notesfile
def get_notes(self):
notesfile = self.get_notes_path()
if os.path.isfile(notesfile):
with open(notesfile) as infile:
text = '[eventInfo: '+str(infile.readlines()[0].split('\n')[0])+']'
self.addNotes(text)
def addNotes(self, notes):
self.notes = str(notes)
def clearNotes(self):
self.notes = None
def isRefEvent(self):
return self._refEvent
def isTestEvent(self):
return self._testEvent
def setRefEvent(self, bool):
self._refEvent = bool
if bool: self._testEvent = False
def setTestEvent(self, bool):
self._testEvent = bool
if bool: self._refEvent = False
def addPicks(self, picks):
for station in picks:
self.picks[station] = picks[station]
def addAutopicks(self, autopicks):
for station in autopicks:
self.autopicks[station] = autopicks[station]
def setPick(self, station, pick):
if pick:
self.picks[station] = pick
def setPicks(self, picks):
self.picks = picks
def getPick(self, station):
if station in self.picks.keys():
return self.picks[station]
def getPicks(self):
return self.picks
def setAutopick(self, station, autopick):
if autopick:
self.autopicks[station] = autopick
def setAutopicks(self, autopicks):
self.autopicks = autopicks
def getAutopick(self, station):
if station in self.autopicks.keys():
return self.autopicks[station]
def getAutopicks(self):
return self.autopicks
def save(self, filename):
'''
Save PyLoT Event to a file.
Can be loaded by using event.load(filename).
'''
try:
import cPickle
except ImportError:
import _pickle as cPickle
try:
outfile = open(filename, 'wb')
cPickle.dump(self, outfile, -1)
except Exception as e:
print('Could not pickle PyLoT event. Reason: {}'.format(e))
@staticmethod
def load(filename):
'''
Load project from filename.
'''
try:
import cPickle
except ImportError:
import _pickle as cPickle
infile = open(filename, 'rb')
event = cPickle.load(infile)
print('Loaded %s' % filename)
return event
class getExistingDirectories(QFileDialog): class getExistingDirectories(QFileDialog):
''' '''
File dialog with possibility to select multiple folders. File dialog with possibility to select multiple folders.

View File

@ -98,8 +98,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
exf = ['root', 'dpath', 'dbase'] exf = ['root', 'dpath', 'dbase']
if parameter.hasParam('eventID') and fnames == 'None': if parameter['eventID'] is not '*' and fnames == 'None':
dsfields['eventID'] = parameter.get('eventID') dsfields['eventID'] = parameter['eventID']
exf.append('eventID') exf.append('eventID')
datastructure.modifyFields(**dsfields) datastructure.modifyFields(**dsfields)
@ -133,13 +133,13 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
if not input_dict: if not input_dict:
# started in production mode # started in production mode
datapath = datastructure.expandDataPath() datapath = datastructure.expandDataPath()
if fnames == 'None' and not parameter['eventID']: if fnames == 'None' and parameter['eventID'] is '*':
# multiple event processing # multiple event processing
# read each event in database # read each event in database
events = [events for events in glob.glob(os.path.join(datapath, '*')) if os.path.isdir(events)] events = [events for events in glob.glob(os.path.join(datapath, '*')) if os.path.isdir(events)]
elif fnames == 'None' and parameter['eventID']: elif fnames == 'None' and parameter['eventID'] is not '*':
# single event processing # single event processing
events = glob.glob(os.path.join(datapath, parameter.get('eventID'))) events = glob.glob(os.path.join(datapath, parameter['eventID']))
else: else:
# autoPyLoT was initialized from GUI # autoPyLoT was initialized from GUI
events = [] events = []
@ -243,7 +243,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
# get latest NLLoc-location file if several are available # get latest NLLoc-location file if several are available
nllocfile = max(glob.glob(locsearch), key=os.path.getctime) nllocfile = max(glob.glob(locsearch), key=os.path.getctime)
evt = read_events(nllocfile)[0] evt = read_events(nllocfile)[0]
# calculating seismic moment Mo and moment magnitude Mw # calculate seismic moment Mo and moment magnitude Mw
moment_mag = MomentMagnitude(corr_dat, evt, parameter.get('vp'), moment_mag = MomentMagnitude(corr_dat, evt, parameter.get('vp'),
parameter.get('Qp'), parameter.get('Qp'),
parameter.get('rho'), True, \ parameter.get('rho'), True, \
@ -252,15 +252,29 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
for station, props in moment_mag.moment_props.items(): for station, props in moment_mag.moment_props.items():
picks[station]['P'].update(props) picks[station]['P'].update(props)
evt = moment_mag.updated_event() evt = moment_mag.updated_event()
net_mw = moment_mag.net_magnitude()
print("Network moment magnitude: %4.1f" % net_mw.mag)
# calculate local (Richter) magntiude
WAscaling = parameter.get('WAscaling')
magscaling = parameter.get('magscaling')
local_mag = LocalMagnitude(corr_dat, evt, local_mag = LocalMagnitude(corr_dat, evt,
parameter.get('sstop'), parameter.get('WAscaling'), \ parameter.get('sstop'),
True, iplot) WAscaling, True, iplot)
for station, amplitude in local_mag.amplitudes.items(): for station, amplitude in local_mag.amplitudes.items():
picks[station]['S']['Ao'] = amplitude.generic_amplitude picks[station]['S']['Ao'] = amplitude.generic_amplitude
evt = local_mag.updated_event() print("Local station magnitudes scaled with:")
print("log(Ao) + %f * log(r) + %f * r + %f" % (WAscaling[0],
WAscaling[1],
WAscaling[2]))
evt = local_mag.updated_event(magscaling)
net_ml = local_mag.net_magnitude(magscaling)
print("Network local magnitude: %4.1f" % net_ml.mag)
print("Network local magnitude scaled with:")
print("%f * Ml + %f" % (magscaling[0], magscaling[1]))
else: else:
print("autoPyLoT: No NLLoc-location file available!") print("autoPyLoT: No NLLoc-location file available!")
print("No source parameter estimation possible!") print("No source parameter estimation possible!")
locflag = 9
else: else:
# get theoretical P-onset times from NLLoc-location file # get theoretical P-onset times from NLLoc-location file
locsearch = '%s/loc/%s.????????.??????.grid?.loc.hyp' % (nllocroot, nllocout) locsearch = '%s/loc/%s.????????.??????.grid?.loc.hyp' % (nllocroot, nllocout)
@ -301,7 +315,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
nlloccounter = maxnumit nlloccounter = maxnumit
evt = read_events(nllocfile)[0] evt = read_events(nllocfile)[0]
if locflag < 2: if locflag < 2:
# calculating seismic moment Mo and moment magnitude Mw # calculate seismic moment Mo and moment magnitude Mw
moment_mag = MomentMagnitude(corr_dat, evt, parameter.get('vp'), moment_mag = MomentMagnitude(corr_dat, evt, parameter.get('vp'),
parameter.get('Qp'), parameter.get('Qp'),
parameter.get('rho'), True, \ parameter.get('rho'), True, \
@ -310,14 +324,25 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
for station, props in moment_mag.moment_props.items(): for station, props in moment_mag.moment_props.items():
picks[station]['P'].update(props) picks[station]['P'].update(props)
evt = moment_mag.updated_event() evt = moment_mag.updated_event()
local_mag = LocalMagnitude(corr_dat, evt,
parameter.get('sstop'), parameter.get('WAscaling'), \
True, iplot)
for station, amplitude in local_mag.amplitudes.items():
picks[station]['S']['Ao'] = amplitude.generic_amplitude
evt = local_mag.updated_event()
net_mw = moment_mag.net_magnitude() net_mw = moment_mag.net_magnitude()
print("Network moment magnitude: %4.1f" % net_mw.mag) print("Network moment magnitude: %4.1f" % net_mw.mag)
# calculate local (Richter) magntiude
WAscaling = parameter.get('WAscaling')
magscaling = parameter.get('magscaling')
local_mag = LocalMagnitude(corr_dat, evt,
parameter.get('sstop'),
WAscaling, True, iplot)
for station, amplitude in local_mag.amplitudes.items():
picks[station]['S']['Ao'] = amplitude.generic_amplitude
print("Local station magnitudes scaled with:")
print("log(Ao) + %f * log(r) + %f * r + %f" % (WAscaling[0],
WAscaling[1],
WAscaling[2]))
evt = local_mag.updated_event(magscaling)
net_ml = local_mag.net_magnitude(magscaling)
print("Network local magnitude: %4.1f" % net_ml.mag)
print("Network local magnitude scaled with:")
print("%f * Ml + %f" % (magscaling[0], magscaling[1]))
else: else:
print("autoPyLoT: No NLLoc-location file available! Stop iteration!") print("autoPyLoT: No NLLoc-location file available! Stop iteration!")
locflag = 9 locflag = 9
@ -328,26 +353,26 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
data.applyEVTData(picks) data.applyEVTData(picks)
if evt is not None: if evt is not None:
data.applyEVTData(evt, 'event') data.applyEVTData(evt, 'event')
fnqml = '%s/autoPyLoT' % event fnqml = '%s/PyLoT_%s' % (event, evID)
data.exportEvent(fnqml) data.exportEvent(fnqml, fnext='.xml', fcheck='manual')
# HYPO71
hypo71file = '%s/autoPyLoT_HYPO71_phases' % event
hypo71.export(picks, hypo71file, parameter)
# HYPOSAT
hyposatfile = '%s/autoPyLoT_HYPOSAT_phases' % event
hyposat.export(picks, hyposatfile, parameter)
if locflag == 1: if locflag == 1:
# HYPO71
hypo71file = '%s/PyLoT_%s_HYPO71_phases' % (event, evID)
hypo71.export(picks, hypo71file, parameter)
# HYPOSAT
hyposatfile = '%s/PyLoT_%s_HYPOSAT_phases' % (event, evID)
hyposat.export(picks, hyposatfile, parameter)
# VELEST # VELEST
velestfile = '%s/autoPyLoT_VELEST_phases.cnv' % event velestfile = '%s/PyLoT_%s_VELEST_phases.cnv' % (event, evID)
velest.export(picks, velestfile, parameter, evt) velest.export(picks, velestfile, parameter, evt)
# hypoDD # hypoDD
hypoddfile = '%s/autoPyLoT_hypoDD_phases.pha' % event hypoddfile = '%s/PyLoT_%s_hypoDD_phases.pha' % (event, evID)
hypodd.export(picks, hypoddfile, parameter, evt) hypodd.export(picks, hypoddfile, parameter, evt)
# FOCMEC # FOCMEC
focmecfile = '%s/autoPyLoT_FOCMEC.in' % event focmecfile = '%s/PyLoT_%s_FOCMEC.in' % (event, evID)
focmec.export(picks, focmecfile, parameter, evt) focmec.export(picks, focmecfile, parameter, evt)
# HASH # HASH
hashfile = '%s/autoPyLoT_HASH' % event hashfile = '%s/PyLoT_%s_HASH' % (event, evID)
hash.export(picks, hashfile, parameter, evt) hash.export(picks, hashfile, parameter, evt)
endsplash = '''------------------------------------------\n' endsplash = '''------------------------------------------\n'

View File

@ -1 +0,0 @@
f91e1-dirty

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Created autumn/winter 2015. Created autumn/winter 2015.
Revised/extended summer 2017.
:author: Ludger Küperkoch / MAGS2 EP3 working group :author: Ludger Küperkoch / MAGS2 EP3 working group
""" """
@ -115,23 +116,30 @@ class Magnitude(object):
def calc(self): def calc(self):
pass pass
def updated_event(self): def updated_event(self, magscaling=None):
self.event.magnitudes.append(self.net_magnitude()) self.event.magnitudes.append(self.net_magnitude(magscaling))
return self.event return self.event
def net_magnitude(self): def net_magnitude(self, magscaling=None):
if self: if self:
# TODO if an average Magnitude instead of the median is calculated if magscaling is not None and str(magscaling) is not '[0.0, 0.0]':
# StationMagnitudeContributions should be added to the returned # scaling necessary
# Magnitude object print("Scaling network magnitude ...")
# mag_error => weights (magnitude error estimate from peak_to_peak, calcsourcespec?) mag = ope.Magnitude(
# weights => StationMagnitdeContribution mag=np.median([M.mag for M in self.magnitudes.values()]) *\
mag = ope.Magnitude( magscaling[0] + magscaling[1],
mag=np.median([M.mag for M in self.magnitudes.values()]), magnitude_type=self.type,
magnitude_type=self.type, origin_id=self.origin_id,
origin_id=self.origin_id, station_count=len(self.magnitudes),
station_count=len(self.magnitudes), azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap) else:
# no saling necessary
mag = ope.Magnitude(
mag=np.median([M.mag for M in self.magnitudes.values()]),
magnitude_type=self.type,
origin_id=self.origin_id,
station_count=len(self.magnitudes),
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
return mag return mag
return None return None
@ -153,7 +161,7 @@ class LocalMagnitude(Magnitude):
_amplitudes = dict() _amplitudes = dict()
def __init__(self, stream, event, calc_win, wascaling=None, verbosity=False, iplot=0): def __init__(self, stream, event, calc_win, wascaling, verbosity=False, iplot=0):
super(LocalMagnitude, self).__init__(stream, event, verbosity, iplot) super(LocalMagnitude, self).__init__(stream, event, verbosity, iplot)
self._calc_win = calc_win self._calc_win = calc_win
@ -207,6 +215,8 @@ class LocalMagnitude(Magnitude):
th = np.arange(0, len(sqH) * dt, dt) th = np.arange(0, len(sqH) * dt, dt)
# get maximum peak within pick window # get maximum peak within pick window
iwin = getsignalwin(th, t0 - stime, self.calc_win) iwin = getsignalwin(th, t0 - stime, self.calc_win)
ii = min([iwin[len(iwin)-1], len(th)])
iwin = iwin[0:ii]
wapp = np.max(sqH[iwin]) wapp = np.max(sqH[iwin])
if self.verbose: if self.verbose:
print("Determined Wood-Anderson peak-to-peak amplitude for station {0}: {1} " print("Determined Wood-Anderson peak-to-peak amplitude for station {0}: {1} "
@ -257,12 +267,13 @@ class LocalMagnitude(Magnitude):
self.amplitudes = (station, amplitude) self.amplitudes = (station, amplitude)
# using standard Gutenberg-Richter relation # using standard Gutenberg-Richter relation
# or scale WA amplitude with given scaling relation # or scale WA amplitude with given scaling relation
if self.wascaling == None: if str(self.wascaling) == '[0.0, 0.0, 0.0]':
print("Calculating original Richter magnitude ...") print("Calculating original Richter magnitude ...")
magnitude = ope.StationMagnitude(mag=np.log10(a0) \ magnitude = ope.StationMagnitude(mag=np.log10(a0) \
+ richter_magnitude_scaling(delta)) + richter_magnitude_scaling(delta))
else: else:
print("Calculating scaled local magnitude ...") print("Calculating scaled local magnitude ...")
a0 = a0 * 1e03 # mm to nm (see Havskov & Ottemöller, 2010)
magnitude = ope.StationMagnitude(mag=np.log10(a0) \ magnitude = ope.StationMagnitude(mag=np.log10(a0) \
+ self.wascaling[0] * np.log10(delta) + self.wascaling[1] + self.wascaling[0] * np.log10(delta) + self.wascaling[1]
* delta + self.wascaling[2]) * delta + self.wascaling[2])

View File

@ -6,11 +6,12 @@ import os
from obspy import read_events from obspy import read_events
from obspy.core import read, Stream, UTCDateTime from obspy.core import read, Stream, UTCDateTime
from obspy.io.sac import SacIOError from obspy.io.sac import SacIOError
from obspy.core.event import Event from obspy.core.event import Event as ObsPyEvent
from pylot.core.io.phases import readPILOTEvent, picks_from_picksdict, \ from pylot.core.io.phases import readPILOTEvent, picks_from_picksdict, \
picksdict_from_pilot, merge_picks picksdict_from_pilot, merge_picks
from pylot.core.util.errors import FormatError, OverwriteError from pylot.core.util.errors import FormatError, OverwriteError
from pylot.core.util.utils import fnConstructor, full_range from pylot.core.util.utils import fnConstructor, full_range
from pylot.core.util.event import Event
class Data(object): class Data(object):
""" """
@ -33,7 +34,7 @@ class Data(object):
self.comp = 'Z' self.comp = 'Z'
self.wfdata = Stream() self.wfdata = Stream()
self._new = False self._new = False
if isinstance(evtdata, Event): if isinstance(evtdata, ObsPyEvent) or isinstance(evtdata, Event):
pass pass
elif isinstance(evtdata, dict): elif isinstance(evtdata, dict):
evt = readPILOTEvent(**evtdata) evt = readPILOTEvent(**evtdata)
@ -49,7 +50,7 @@ class Data(object):
if 'Unknown format for file' in e.message: if 'Unknown format for file' in e.message:
if 'PHASES' in evtdata: if 'PHASES' in evtdata:
picks = picksdict_from_pilot(evtdata) picks = picksdict_from_pilot(evtdata)
evtdata = Event() evtdata = ObsPyEvent()
evtdata.picks = picks_from_picksdict(picks) evtdata.picks = picks_from_picksdict(picks)
elif 'LOC' in evtdata: elif 'LOC' in evtdata:
raise NotImplementedError('PILOT location information ' raise NotImplementedError('PILOT location information '
@ -61,7 +62,7 @@ class Data(object):
raise e raise e
else: # create an empty Event object else: # create an empty Event object
self.setNew() self.setNew()
evtdata = Event() evtdata = ObsPyEvent()
evtdata.picks = [] evtdata.picks = []
self.evtdata = evtdata self.evtdata = evtdata
self.wforiginal = None self.wforiginal = None
@ -73,6 +74,8 @@ class Data(object):
def __add__(self, other): def __add__(self, other):
assert isinstance(other, Data), "operands must be of same type 'Data'" assert isinstance(other, Data), "operands must be of same type 'Data'"
rs_id = self.get_evt_data().get('resource_id')
rs_id_other = other.get_evt_data().get('resource_id')
if other.isNew() and not self.isNew(): if other.isNew() and not self.isNew():
picks_to_add = other.get_evt_data().picks picks_to_add = other.get_evt_data().picks
old_picks = self.get_evt_data().picks old_picks = self.get_evt_data().picks
@ -84,7 +87,7 @@ class Data(object):
self.evtdata = new.get_evt_data() self.evtdata = new.get_evt_data()
elif self.isNew() and other.isNew(): elif self.isNew() and other.isNew():
pass pass
elif self.get_evt_data().get('id') == other.get_evt_data().get('id'): elif rs_id == rs_id_other:
other.setNew() other.setNew()
return self + other return self + other
else: else:
@ -95,7 +98,7 @@ class Data(object):
def getPicksStr(self): def getPicksStr(self):
picks_str = '' picks_str = ''
for pick in self.get_evt_data().picks: for pick in self.get_evt_data().picks:
picks_str += str(pick) + '\n' picks_str += str(PyLoT) + '\n'
return picks_str return picks_str
def getParent(self): def getParent(self):
@ -144,12 +147,13 @@ class Data(object):
# handle forbidden filenames especially on windows systems # handle forbidden filenames especially on windows systems
return fnConstructor(str(ID)) return fnConstructor(str(ID))
def exportEvent(self, fnout, fnext='.xml'): def exportEvent(self, fnout, fnext='.xml', fcheck='auto'):
""" """
:param fnout: :param fnout:
:param fnext: :param fnext:
:param fcheck:
:raise KeyError: :raise KeyError:
""" """
from pylot.core.util.defaults import OUTPUTFORMATS from pylot.core.util.defaults import OUTPUTFORMATS
@ -160,13 +164,35 @@ class Data(object):
errmsg = '{0}; selected file extension {1} not ' \ errmsg = '{0}; selected file extension {1} not ' \
'supported'.format(e, fnext) 'supported'.format(e, fnext)
raise FormatError(errmsg) raise FormatError(errmsg)
# check for already existing xml-file
if fnext == '.xml':
if os.path.isfile(fnout + fnext):
print("xml-file already exists! Check content ...")
cat_old = read_events(fnout + fnext)
checkflag = 0
for j in range(len(cat_old.events[0].picks)):
if cat_old.events[0].picks[j].method_id.id.split('/')[1] == fcheck:
print("Found %s pick(s), append to new catalog." % fcheck)
checkflag = 1
break
if checkflag == 1:
self.get_evt_data().write(fnout + fnext, format=evtformat)
cat_new = read_events(fnout + fnext)
cat_new.append(cat_old.events[0])
cat_new.write(fnout + fnext, format=evtformat)
else:
self.get_evt_data().write(fnout + fnext, format=evtformat)
else:
self.get_evt_data().write(fnout + fnext, format=evtformat)
# try exporting event via ObsPy # try exporting event via ObsPy
try: else:
self.get_evt_data().write(fnout + fnext, format=evtformat) try:
except KeyError as e: self.get_evt_data().write(fnout + fnext, format=evtformat)
raise KeyError('''{0} export format except KeyError as e:
not implemented: {1}'''.format(evtformat, e)) raise KeyError('''{0} export format
not implemented: {1}'''.format(evtformat, e))
def getComp(self): def getComp(self):
""" """
@ -279,12 +305,12 @@ class Data(object):
def setEvtData(self, event): def setEvtData(self, event):
self.evtdata = event self.evtdata = event
def applyEVTData(self, data, type='pick', authority_id='rub'): def applyEVTData(self, data, typ='pick', authority_id='rub'):
""" """
:param data: :param data:
:param type: :param typ:
:param authority_id: :param authority_id:
:raise OverwriteError: :raise OverwriteError:
""" """
@ -326,19 +352,27 @@ class Data(object):
information on the event to the actual data information on the event to the actual data
:param event: :param event:
""" """
if not self.isNew(): if self.isNew():
self.setEvtData(event) self.setEvtData(event)
else: else:
# prevent overwriting original pick information # prevent overwriting original pick information
picks = copy.deepcopy(self.get_evt_data().picks) event_old = self.get_evt_data()
print(event_old.resource_id, event.resource_id)
if not event_old.resource_id == event.resource_id:
print("WARNING: Missmatch in event resource id's: {} and {}".format(
event_old.resource_id,
event.resource_id))
picks = copy.deepcopy(event_old.picks)
event = merge_picks(event, picks) event = merge_picks(event, picks)
# apply event information from location # apply event information from location
self.get_evt_data().update(event) event_old.update(event)
applydata = {'pick': applyPicks, applydata = {'pick': applyPicks,
'event': applyEvent} 'event': applyEvent}
applydata[type](data) applydata[typ](data)
self._new = False
class GenericDataStructure(object): class GenericDataStructure(object):

View File

@ -14,7 +14,7 @@ defaults = {'rootpath': {'type': str,
'value': ''}, 'value': ''},
'eventID': {'type': str, 'eventID': {'type': str,
'tooltip': 'event ID for single event processing', 'tooltip': 'event ID for single event processing (* for all events found in database)',
'value': ''}, 'value': ''},
'extent': {'type': str, 'extent': {'type': str,
@ -278,12 +278,14 @@ defaults = {'rootpath': {'type': str,
'value': 1.0}, 'value': 1.0},
'WAscaling': {'type': (float, float, float), 'WAscaling': {'type': (float, float, float),
'tooltip': 'Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm]', 'tooltip': 'Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] \
'value': (1.0, 1.0, 1.0)}, If zeros are set, original Richter magnitude is calculated!',
'value': (0., 0., 0.)},
'magscaling': {'type': (float, float), 'magscaling': {'type': (float, float),
'tooltip': 'Scaling relation for derived local magnitude [a*Ml+b]', 'tooltip': 'Scaling relation for derived local magnitude [a*Ml+b]. \
'value': (1.0, 1.0)} If zeros are set, no scaling of network magnitude is applied!',
'value': (0., 0.)}
} }
settings_main={ settings_main={

View File

@ -221,24 +221,23 @@ class PylotParameter(object):
# for key, value in self.iteritems(): # for key, value in self.iteritems():
# lines.append('{key}\t{value}\n'.format(key=key, value=value)) # lines.append('{key}\t{value}\n'.format(key=key, value=value))
# fid_out.writelines(lines) # fid_out.writelines(lines)
header = ('%This is a parameter input file for PyLoT/autoPyLoT.\n'+ header = ('%This is a parameter input file for PyLoT/autoPyLoT.\n'+
'%All main and special settings regarding data handling\n'+ '%All main and special settings regarding data handling\n'+
'%and picking are to be set here!\n'+ '%and picking are to be set here!\n'+
'%Parameters are optimized for local data sets!\n') '%Parameters are optimized for %{} data sets!\n'.format(self.get_main_para_names()['pick'][0]))
seperator = '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n' separator = '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n'
fid_out.write(header) fid_out.write(header)
self.write_section(fid_out, self.get_main_para_names()['dirs'], self.write_section(fid_out, self.get_main_para_names()['dirs'],
'main settings', seperator) 'main settings', separator)
self.write_section(fid_out, self.get_main_para_names()['nlloc'], self.write_section(fid_out, self.get_main_para_names()['nlloc'],
'NLLoc settings', seperator) 'NLLoc settings', separator)
self.write_section(fid_out, self.get_main_para_names()['smoment'], self.write_section(fid_out, self.get_main_para_names()['smoment'],
'parameters for seismic moment estimation', seperator) 'parameters for seismic moment estimation', separator)
self.write_section(fid_out, self.get_main_para_names()['localmag'], self.write_section(fid_out, self.get_main_para_names()['localmag'],
'settings local magnitude', seperator) 'settings local magnitude', separator)
self.write_section(fid_out, self.get_main_para_names()['pick'], self.write_section(fid_out, self.get_main_para_names()['pick'],
'common settings picker', seperator) 'common settings picker', separator)
fid_out.write(('#special settings for calculating CF#\n'+ fid_out.write(('#special settings for calculating CF#\n'+
'%!!Edit the following only if you know what you are doing!!%\n')) '%!!Edit the following only if you know what you are doing!!%\n'))
self.write_section(fid_out, self.get_special_para_names()['z'], self.write_section(fid_out, self.get_special_para_names()['z'],
@ -250,9 +249,9 @@ class PylotParameter(object):
self.write_section(fid_out, self.get_special_para_names()['quality'], self.write_section(fid_out, self.get_special_para_names()['quality'],
'quality assessment', None) 'quality assessment', None)
def write_section(self, fid, names, title, seperator): def write_section(self, fid, names, title, separator):
if seperator: if separator:
fid.write(seperator) fid.write(separator)
fid.write('#{}#\n'.format(title)) fid.write('#{}#\n'.format(title))
l_val = 50 l_val = 50
l_name = 15 l_name = 15

View File

@ -7,6 +7,7 @@ import os
import scipy.io as sio import scipy.io as sio
import warnings import warnings
from obspy.core import UTCDateTime from obspy.core import UTCDateTime
from obspy.core.util import AttribDict
from pylot.core.io.inputs import PylotParameter from pylot.core.io.inputs import PylotParameter
from pylot.core.io.location import create_arrival, create_event, \ from pylot.core.io.location import create_arrival, create_event, \
@ -195,6 +196,7 @@ def picksdict_from_picks(evt):
phase = {} phase = {}
station = pick.waveform_id.station_code station = pick.waveform_id.station_code
channel = pick.waveform_id.channel_code channel = pick.waveform_id.channel_code
network = pick.waveform_id.network_code
try: try:
onsets = picks[station] onsets = picks[station]
except KeyError as e: except KeyError as e:
@ -215,6 +217,7 @@ def picksdict_from_picks(evt):
phase['lpp'] = lpp phase['lpp'] = lpp
phase['spe'] = spe phase['spe'] = spe
phase['channel'] = channel phase['channel'] = channel
phase['network'] = network
try: try:
picker = str(pick.method_id) picker = str(pick.method_id)
if picker.startswith('smi:local/'): if picker.startswith('smi:local/'):
@ -231,7 +234,7 @@ def picks_from_picksdict(picks, creation_info=None):
picks_list = list() picks_list = list()
for station, onsets in picks.items(): for station, onsets in picks.items():
for label, phase in onsets.items(): for label, phase in onsets.items():
if not isinstance(phase, dict): if not isinstance(phase, dict) and not isinstance(phase, AttribDict):
continue continue
onset = phase['mpp'] onset = phase['mpp']
try: try:
@ -382,12 +385,12 @@ def reassess_pilot_event(root_dir, db_dir, event_id, out_dir=None, fn_param=None
evt.picks = picks_from_picksdict(picks_dict) evt.picks = picks_from_picksdict(picks_dict)
# write phase information to file # write phase information to file
if not out_dir: if not out_dir:
fnout_prefix = os.path.join(root_dir, db_dir, event_id, '{0}.'.format(event_id)) fnout_prefix = os.path.join(root_dir, db_dir, event_id, 'PyLoT_{0}.'.format(event_id))
else: else:
out_dir = os.path.join(out_dir, db_dir) out_dir = os.path.join(out_dir, db_dir)
if not os.path.isdir(out_dir): if not os.path.isdir(out_dir):
os.makedirs(out_dir) os.makedirs(out_dir)
fnout_prefix = os.path.join(out_dir, '{0}.'.format(event_id)) fnout_prefix = os.path.join(out_dir, 'PyLoT_{0}.'.format(event_id))
evt.write(fnout_prefix + 'xml', format='QUAKEML') evt.write(fnout_prefix + 'xml', format='QUAKEML')
#evt.write(fnout_prefix + 'cnv', format='VELEST') #evt.write(fnout_prefix + 'cnv', format='VELEST')
@ -835,9 +838,10 @@ def merge_picks(event, picks):
err = pick.time_errors err = pick.time_errors
phase = pick.phase_hint phase = pick.phase_hint
station = pick.waveform_id.station_code station = pick.waveform_id.station_code
network = pick.waveform_id.network_code
method = pick.method_id method = pick.method_id
for p in event.picks: for p in event.picks:
if p.waveform_id.station_code == station and p.phase_hint == phase: if p.waveform_id.station_code == station and p.phase_hint == phase:
p.time, p.time_errors, p.method_id = time, err, method p.time, p.time_errors, p.waveform_id.network_code, p.method_id = time, err, network, method
del time, err, phase, station, method del time, err, phase, station, network, method
return event return event

View File

@ -212,6 +212,14 @@ class AICPicker(AutoPicker):
self.Data[0].data = self.Data[0].data * 1000000 self.Data[0].data = self.Data[0].data * 1000000
# get signal window # get signal window
isignal = getsignalwin(self.Tcf, self.Pick, self.TSNR[2]) isignal = getsignalwin(self.Tcf, self.Pick, self.TSNR[2])
ii = min([isignal[len(isignal)-1], len(self.Tcf)])
isignal = isignal[0:ii]
try:
aic[isignal]
except IndexError as e:
msg = "Time series out of bounds! {}".format(e)
print(msg)
return
# calculate SNR from CF # calculate SNR from CF
self.SNR = max(abs(aic[isignal] - np.mean(aic[isignal]))) / \ self.SNR = max(abs(aic[isignal] - np.mean(aic[isignal]))) / \
max(abs(aic[inoise] - np.mean(aic[inoise]))) max(abs(aic[inoise] - np.mean(aic[inoise])))

144
pylot/core/util/event.py Normal file
View File

@ -0,0 +1,144 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from obspy import UTCDateTime
from obspy.core.event import Event as ObsPyEvent
from obspy.core.event import Origin, Magnitude, ResourceIdentifier
from pylot.core.io.phases import picks_from_picksdict
class Event(ObsPyEvent):
'''
Pickable class derived from ~obspy.core.event.Event containing information on a single event.
'''
def __init__(self, path):
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 = path.split('/')[-3]
self.rootpath = '/' + os.path.join(*path.split('/')[:-3])
self.pylot_autopicks = {}
self.pylot_picks = {}
self.notes = ''
self._testEvent = False
self._refEvent = False
self.get_notes()
def get_notes_path(self):
notesfile = os.path.join(self.path, 'notes.txt')
return notesfile
def get_notes(self):
notesfile = self.get_notes_path()
if os.path.isfile(notesfile):
with open(notesfile) as infile:
path = str(infile.readlines()[0].split('\n')[0])
text = '[eventInfo: '+path+']'
self.addNotes(text)
try:
datetime = UTCDateTime(path.split('/')[-1])
origin = Origin(resource_id=self.resource_id, time=datetime, latitude=0, longitude=0, depth=0)
self.origins.append(origin)
except:
pass
def addNotes(self, notes):
self.notes = str(notes)
def clearNotes(self):
self.notes = None
def isRefEvent(self):
return self._refEvent
def isTestEvent(self):
return self._testEvent
def setRefEvent(self, bool):
self._refEvent = bool
if bool: self._testEvent = False
def setTestEvent(self, bool):
self._testEvent = bool
if bool: self._refEvent = False
def addPicks(self, picks):
'''
add pylot picks and overwrite existing
'''
for station in picks:
self.pylot_picks[station] = picks[station]
#add ObsPy picks
self.picks = picks_from_picksdict(self.pylot_picks)
def addAutopicks(self, autopicks):
for station in autopicks:
self.pylot_autopicks[station] = autopicks[station]
def setPick(self, station, pick):
if pick:
self.pylot_picks[station] = pick
self.picks = picks_from_picksdict(self.pylot_picks)
def setPicks(self, picks):
'''
set pylot picks and delete and overwrite all existing
'''
self.pylot_picks = picks
self.picks = picks_from_picksdict(self.pylot_picks)
def getPick(self, station):
if station in self.pylot_picks.keys():
return self.pylot_picks[station]
def getPicks(self):
return self.pylot_picks
def setAutopick(self, station, autopick):
if autopick:
self.pylot_autopicks[station] = autopick
def setAutopicks(self, autopicks):
self.pylot_autopicks = autopicks
def getAutopick(self, station):
if station in self.pylot_autopicks.keys():
return self.pylot_autopicks[station]
def getAutopicks(self):
return self.pylot_autopicks
def save(self, filename):
'''
Save PyLoT Event to a file.
Can be loaded by using event.load(filename).
'''
try:
import cPickle
except ImportError:
import _pickle as cPickle
try:
outfile = open(filename, 'wb')
cPickle.dump(self, outfile, -1)
except Exception as e:
print('Could not pickle PyLoT event. Reason: {}'.format(e))
@staticmethod
def load(filename):
'''
Load project from filename.
'''
try:
import cPickle
except ImportError:
import _pickle as cPickle
infile = open(filename, 'rb')
event = cPickle.load(infile)
print('Loaded %s' % filename)
return event

View File

@ -22,6 +22,7 @@ class map_projection(QtGui.QWidget):
self.parser = parent.metadata[1] self.parser = parent.metadata[1]
self.picks = None self.picks = None
self.picks_dict = None self.picks_dict = None
self.eventLoc = None
self.figure = figure self.figure = figure
self.init_graphics() self.init_graphics()
self.init_stations() self.init_stations()
@ -244,6 +245,10 @@ class map_projection(QtGui.QWidget):
self.sc = self.basemap.scatter(self.lon, self.lat, s=50, facecolor='none', latlon=True, self.sc = self.basemap.scatter(self.lon, self.lat, s=50, facecolor='none', latlon=True,
zorder=10, picker=True, edgecolor='m', label='Not Picked') zorder=10, picker=True, edgecolor='m', label='Not Picked')
self.cid = self.canvas.mpl_connect('pick_event', self.onpick) self.cid = self.canvas.mpl_connect('pick_event', self.onpick)
if self.eventLoc:
lat, lon = self.eventLoc
self.sc_event = self.basemap.scatter(lon, lat, s=100, facecolor='red',
latlon=True, zorder=11, label='Event (might be outside map region)')
def scatter_picked_stations(self): def scatter_picked_stations(self):
lon = self.lon_no_nan lon = self.lon_no_nan
@ -274,8 +279,7 @@ class map_projection(QtGui.QWidget):
def refresh_drawings(self, picks=None): def refresh_drawings(self, picks=None):
self.picks_dict = picks self.picks_dict = picks
self.remove_drawings() self._refresh_drawings()
self.draw_everything()
def _refresh_drawings(self): def _refresh_drawings(self):
self.remove_drawings() self.remove_drawings()
@ -303,6 +307,9 @@ class map_projection(QtGui.QWidget):
if hasattr(self, 'sc_picked'): if hasattr(self, 'sc_picked'):
self.sc_picked.remove() self.sc_picked.remove()
del(self.sc_picked) del(self.sc_picked)
if hasattr(self, 'sc_event'):
self.sc_event.remove()
del(self.sc_event)
if hasattr(self, 'cbar'): if hasattr(self, 'cbar'):
self.cbar.remove() self.cbar.remove()
del(self.cbar) del(self.cbar)

View File

@ -12,7 +12,7 @@ import subprocess
from obspy import UTCDateTime, read from obspy import UTCDateTime, read
from pylot.core.io.inputs import PylotParameter from pylot.core.io.inputs import PylotParameter
def _pickle_method(m): def _pickle_method(m):
if m.im_self is None: if m.im_self is None:
return getattr, (m.im_class, m.im_func.func_name) return getattr, (m.im_class, m.im_func.func_name)

View File

@ -1646,7 +1646,7 @@ class TuneAutopicker(QWidget):
model = self.stationBox.model() model = self.stationBox.model()
for network, station in stations: for network, station in stations:
item = QtGui.QStandardItem(network+'.'+station) item = QtGui.QStandardItem(network+'.'+station)
if station in self.get_current_event().picks: if station in self.get_current_event().pylot_picks:
item.setBackground(self.parent._colors['ref']) item.setBackground(self.parent._colors['ref'])
model.appendRow(item) model.appendRow(item)
@ -1687,8 +1687,8 @@ class TuneAutopicker(QWidget):
self.listWidget.scrollToBottom() self.listWidget.scrollToBottom()
def get_current_event(self): def get_current_event(self):
index = self.eventBox.currentIndex() path = self.eventBox.currentText()
return self.eventBox.itemData(index) return self.parent.project.getEventFromPath(path)
def get_current_event_name(self): def get_current_event_name(self):
return self.eventBox.currentText().split('/')[-1] return self.eventBox.currentText().split('/')[-1]
@ -1698,13 +1698,13 @@ class TuneAutopicker(QWidget):
def get_current_event_picks(self, station): def get_current_event_picks(self, station):
event = self.get_current_event() event = self.get_current_event()
if station in event.picks.keys(): if station in event.pylot_picks.keys():
return event.picks[station] return event.pylot_picks[station]
def get_current_event_autopicks(self, station): def get_current_event_autopicks(self, station):
event = self.get_current_event() event = self.get_current_event()
if event.autopicks: if event.pylot_autopicks:
return event.autopicks[station] return event.pylot_autopicks[station]
def get_current_station(self): def get_current_station(self):
return str(self.stationBox.currentText()).split('.')[-1] return str(self.stationBox.currentText()).split('.')[-1]
@ -1855,6 +1855,9 @@ class TuneAutopicker(QWidget):
self.init_tab_names() self.init_tab_names()
def fill_eventbox(self): def fill_eventbox(self):
project = self.parent.project
if not project:
return
# update own list # update own list
self.parent.fill_eventbox(eventBox=self.eventBox, select_events='ref') self.parent.fill_eventbox(eventBox=self.eventBox, select_events='ref')
index_start = self.parent.eventBox.currentIndex() index_start = self.parent.eventBox.currentIndex()
@ -1862,11 +1865,15 @@ class TuneAutopicker(QWidget):
if index == -1: if index == -1:
index += 1 index += 1
nevents = self.eventBox.model().rowCount() nevents = self.eventBox.model().rowCount()
if self.eventBox.itemData(index).isTestEvent(): path = self.eventBox.itemText(index)
if project.getEventFromPath(path).isTestEvent():
for index in range(nevents): for index in range(nevents):
if not self.eventBox.itemData(index).isTestEvent(): path = self.eventBox.itemText(index)
break if project.getEventFromPath(index):
elif index == nevents - 1: if not project.getEventFromPath(index).isTestEvent():
break
#in case all events are marked as test events and last event is reached
if index == nevents - 1:
index = -1 index = -1
self.eventBox.setCurrentIndex(index) self.eventBox.setCurrentIndex(index)
if not index == index_start: if not index == index_start:
@ -1911,8 +1918,8 @@ class TuneAutopicker(QWidget):
self._warn('Could not execute picker:\n{}'.format( self._warn('Could not execute picker:\n{}'.format(
self.ap_thread._executedError)) self.ap_thread._executedError))
return return
self.picks = self.ap_thread.data self.pylot_picks = self.ap_thread.data
if not self.picks: if not self.pylot_picks:
self._warn('No picks found. See terminal output.') self._warn('No picks found. See terminal output.')
return return
#renew tabs #renew tabs