Merge branch 'develop' of ariadne.geophysik.rub.de:/data/git/pylot into develop

This commit is contained in:
Ludger Küperkoch 2015-08-31 09:02:16 +02:00
commit 69c17f9fdb
4 changed files with 301 additions and 84 deletions

View File

@ -42,7 +42,8 @@ from pylot.core.read.data import Data
from pylot.core.read.inputs import FilterOptions, AutoPickParameter
from pylot.core.pick.autopick import autopickevent
from pylot.core.util.defaults import FILTERDEFAULTS
from pylot.core.util.errors import FormatError, DatastructureError
from pylot.core.util.errors import FormatError, DatastructureError,\
OverwriteError
from pylot.core.util.connection import checkurl
from pylot.core.util.utils import fnConstructor, createEvent, getLogin,\
createCreationInfo, getGlobalTimes
@ -399,7 +400,21 @@ class MainWindow(QMainWindow):
def saveData(self):
settings = QSettings()
exform = settings.value('data/exportFormat', 'QUAKEML')
try:
self.getData().applyEVTData(self.getPicks())
except OverwriteError:
msgBox = QMessageBox()
msgBox.setText("Picks have been modified!")
msgBox.setInformativeText("Do you want to save the changes and overwrite the picks?")
msgBox.setDetailedText(self.getData().getPicksStr())
msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Cancel)
msgBox.setDefaultButton(QMessageBox.Save)
ret = msgBox.exec_()
if ret == QMessageBox.Save:
self.getData().resetPicks()
self.saveData()
elif ret == QMessageBox.Cancel:
return False
try:
self.getData().exportEvent(self.fname, exform)
except FormatError:
@ -407,12 +422,14 @@ class MainWindow(QMainWindow):
except AttributeError, e:
print 'warning: {0}'.format(e)
directory = os.path.join(self.getRoot(), self.getEventFileName())
file_filter = "Seismic observation files (*.cnv *.obs *.xml)"
file_filter = "QuakeML file (*.xml);;VELEST observation file format (*.cnv);;NonLinLoc observation file (*.obs)"
fname = QFileDialog.getSaveFileName(self, 'Save event data ...',
directory, file_filter)
fbasename, exform = os.path.splitext(fname[0])
if not fbasename:
return False
elif not exform:
exform = fname[1].split('*')[1][:-1]
self.getData().exportEvent(fbasename, exform)
return True

View File

@ -1 +1 @@
1abc-dirty
497c-dirty

View File

@ -3,7 +3,6 @@
import os
import glob
import matplotlib.pyplot as plt
from obspy.xseed import Parser
from obspy.core import read, Stream, UTCDateTime
from obspy import readEvents, read_inventory
@ -11,24 +10,21 @@ from obspy.core.event import Event, ResourceIdentifier, Pick, WaveformStreamID
from pylot.core.read.io import readPILOTEvent
from pylot.core.util.utils import fnConstructor, getGlobalTimes
from pylot.core.util.errors import FormatError
from pylot.core.util.errors import FormatError, OverwriteError
class Data(object):
'''
"""
Data container with attributes wfdata holding ~obspy.core.stream.
:type parent: PySide.QtGui.QWidget object, optional
:param parent: A PySide.QtGui.QWidget object utilized when
called by a GUI to display a PySide.QtGui.QMessageBox instead of printing
to standard out.
:type wfdata: ~obspy.core.stream.Stream object, optional
:param wfdata: ~obspy.core.stream.Stream object containing all available
waveform data for the actual event
:type evtdata: ~obspy.core.event.Event object, optional
:param evtdata ~obspy.core.event.Event object containing all derived or
loaded event. Container object holding, e.g. phase arrivals, etc.
'''
"""
def __init__(self, parent=None, evtdata=None):
self._parent = parent
@ -56,32 +52,69 @@ class Data(object):
def __str__(self):
return str(self.wfdata)
def getPicksStr(self):
picks_str = ''
for pick in self.getEvtData().picks:
picks_str += str(pick) + '\n'
return picks_str
def getParent(self):
"""
:return:
"""
return self._parent
def isNew(self):
"""
:return:
"""
return self.newevent
def getCutTimes(self):
"""
:return:
"""
if self.cuttimes is None:
self.updateCutTimes()
return self.cuttimes
def updateCutTimes(self):
"""
"""
self.cuttimes = getGlobalTimes(self.getWFData())
def getEventFileName(self):
"""
:return:
"""
ID = self.getID()
# handle forbidden filenames especially on windows systems
return fnConstructor(str(ID))
def exportEvent(self, fnout, fnext='.xml'):
"""
:param fnout:
:param fnext:
:raise KeyError:
"""
from pylot.core.util.defaults import OUTPUTFORMATS
try:
evtformat = OUTPUTFORMATS[fnext]
except KeyError, e:
except KeyError as e:
errmsg = '{0}; selected file extension {1} not ' \
'supported'.format(e, fnext)
raise FormatError(errmsg)
@ -89,24 +122,42 @@ class Data(object):
# try exporting event via ObsPy
try:
self.getEvtData().write(fnout + fnext, format=evtformat)
except KeyError, e:
except KeyError as e:
raise KeyError('''{0} export format
not implemented: {1}'''.format(evtformat, e))
def getComp(self):
"""
:return:
"""
return self.comp
def getID(self):
"""
:return:
"""
try:
return self.evtdata.get('resource_id').id
except:
return None
def filterWFData(self, kwargs):
"""
:param kwargs:
"""
self.getWFData().filter(**kwargs)
self.dirty = True
def setWFData(self, fnames):
"""
:param fnames:
"""
self.wfdata = Stream()
self.wforiginal = None
if fnames is not None:
@ -115,10 +166,14 @@ class Data(object):
self.dirty = False
def appendWFData(self, fnames):
"""
:param fnames:
"""
assert isinstance(fnames, list), "input parameter 'fnames' is " \
"supposed to be of type 'list' " \
"but is actually {0}".format(type(
fnames))
"but is actually" \
" {0}".format(type(fnames))
if self.dirty:
self.resetWFData()
@ -129,24 +184,51 @@ class Data(object):
except TypeError:
try:
self.wfdata += read(fname, format='GSE2')
except Exception, e:
except Exception as e:
warnmsg += '{0}\n{1}\n'.format(fname, e)
if warnmsg:
warnmsg = 'WARNING: unable to read\n' + warnmsg
print warnmsg
print(warnmsg)
def getWFData(self):
"""
:return:
"""
return self.wfdata
def getOriginalWFData(self):
"""
:return:
"""
return self.wforiginal
def resetWFData(self):
"""
"""
self.wfdata = self.getOriginalWFData().copy()
self.dirty = False
def resetPicks(self):
"""
"""
self.getEvtData().picks = []
def restituteWFData(self, invdlpath, streams=None):
if streams == None:
"""
:param invdlpath:
:param streams:
:return:
"""
if streams is None:
st = self.getWFData()
else:
st = streams
@ -164,10 +246,10 @@ class Data(object):
# check for dataless-SEED file
if len(dlfile) >= 1:
print "Found dataless-SEED file(s)!"
print "Reading meta data information ..."
print("Found dataless-SEED file(s)!")
print("Reading meta data information ...")
for j in range(len(dlfile)):
print "Found dataless-SEED file %s" % dlfile[j]
print("Found dataless-SEED file %s" % dlfile[j])
parser = Parser('%s' % dlfile[j])
for i in range(len(st)):
# check, whether this trace has already been corrected
@ -175,27 +257,32 @@ class Data(object):
st[i].stats.processing
except:
try:
print "Correcting %s, %s for instrument response ..." \
% (st[i].stats.station, st[i].stats.channel)
print(
"Correcting %s, %s for instrument response "
"..." % (st[i].stats.station,
st[i].stats.channel))
# get corner frequencies for pre-filtering
fny = st[i].stats.sampling_rate / 2
fc21 = fny - (fny * 0.05)
fc22 = fny - (fny * 0.02)
prefilt = [0.5, 0.9, fc21, fc22]
# instrument correction
st[i].simulate(pre_filt=prefilt, seedresp={'filename': parser, \
'date': st[i].stats.starttime, 'units': "VEL"})
except ValueError, e:
st[i].simulate(pre_filt=prefilt,
seedresp={'filename': parser,
'date': st[
i].stats.starttime,
'units': "VEL"})
except ValueError as e:
vmsg = '{0}'.format(e)
print vmsg
print(vmsg)
else:
print "Trace has already been corrected!"
print("Trace has already been corrected!")
# check for inventory-xml file
if len(invfile) >= 1:
print "Found inventory-xml file(s)!"
print "Reading meta data information ..."
print("Found inventory-xml file(s)!")
print("Reading meta data information ...")
for j in range(len(invfile)):
print "Found inventory-xml file %s" % invfile[j]
print("Found inventory-xml file %s" % invfile[j])
inv = read_inventory(invfile[j], format="STATIONXML")
for i in range(len(st)):
# check, whether this trace has already been corrected
@ -203,8 +290,9 @@ class Data(object):
st[i].stats.processing
except:
try:
print "Correcting %s, %s for instrument response ..." \
% (st[i].stats.station, st[i].stats.channel)
print("Correcting %s, %s for instrument response "
"..." % (st[i].stats.station,
st[i].stats.channel))
# get corner frequencies for pre-filtering
fny = st[i].stats.sampling_rate / 2
fc21 = fny - (fny * 0.05)
@ -212,56 +300,84 @@ class Data(object):
prefilt = [0.5, 0.9, fc21, fc22]
# instrument correction
st[i].attach_response(inv)
st[i].remove_response(output='VEL', pre_filt=prefilt)
except ValueError, e:
st[i].remove_response(output='VEL',
pre_filt=prefilt)
except ValueError as e:
vmsg = '{0}'.format(e)
print vmsg
print(vmsg)
else:
print "Trace has already been corrected!"
print("Trace has already been corrected!")
# check for RESP-file
if len(respfile) >= 1:
print "Found response file(s)!"
print "Reading meta data information ..."
print("Found response file(s)!")
print("Reading meta data information ...")
for j in range(len(respfile)):
print "Found RESP-file %s" % respfile[j]
print("Found RESP-file %s" % respfile[j])
for i in range(len(st)):
# check, whether this trace has already been corrected
try:
st[i].stats.processing
except:
try:
print "Correcting %s, %s for instrument response ..." \
% (st[i].stats.station, st[i].stats.channel)
print("Correcting %s, %s for instrument response "
"..." % (st[i].stats.station,
st[i].stats.channel))
# get corner frequencies for pre-filtering
fny = st[i].stats.sampling_rate / 2
fc21 = fny - (fny * 0.05)
fc22 = fny - (fny * 0.02)
prefilt = [0.5, 0.9, fc21, fc22]
# instrument correction
seedresp={'filename': respfile[0], 'date': st[0].stats.starttime, \
seedresp = {'filename': respfile[0],
'date': st[0].stats.starttime,
'units': "VEL"}
st[i].simulate(paz_remove=None, pre_filt=prefilt, seedresp=seedresp)
except ValueError, e:
st[i].simulate(paz_remove=None, pre_filt=prefilt,
seedresp=seedresp)
except ValueError as e:
vmsg = '{0}'.format(e)
print vmsg
print(vmsg)
else:
print "Trace has already been corrected!"
print("Trace has already been corrected!")
if len(respfile) < 1 and len(invfile) < 1 and len(dlfile) < 1:
print "No dataless-SEED file,inventory-xml file nor RESP-file found!"
print "Go on processing data without source parameter determination!"
print("No dataless-SEED file,inventory-xml file nor RESP-file "
"found!")
print("Go on processing data without source parameter "
"determination!")
return st
def getEvtData(self):
"""
:return:
"""
return self.evtdata
def applyEVTData(self, data, type='pick', authority_id='rub'):
"""
:param data:
:param type:
:param authority_id:
:raise OverwriteError:
"""
def applyPicks(picks):
"""
Creates ObsPy pick objects and append it to the picks list from the
PyLoT dictionary contain all picks.
:param picks:
:raise OverwriteError: raises an OverwriteError if the picks list is
not empty. The GUI will then ask for a decision.
"""
firstonset = None
if self.getEvtData().picks:
raise OverwriteError('Actual picks would be overwritten!')
for station, onsets in picks.items():
print 'Reading picks on station %s' % station
print('Reading picks on station %s' % station)
for label, phase in onsets.items():
onset = phase['mpp']
epp = phase['epp']
@ -277,8 +393,8 @@ class Data(object):
self.getEvtData().picks.append(pick)
try:
polarity = phase['fm']
except KeyError, e:
print 'No polarity information found for %s' % phase
except KeyError as e:
print('No polarity information found for %s' % phase)
if firstonset is None or firstonset > onset:
firstonset = onset
@ -289,9 +405,17 @@ class Data(object):
self.getEvtData().resource_id = ID
def applyArrivals(arrivals):
"""
:param arrivals:
"""
pass
def applyEvent(event):
"""
:param event:
"""
pass
applydata = {'pick': applyPicks,
@ -302,10 +426,10 @@ class Data(object):
class GenericDataStructure(object):
'''
"""
GenericDataBase type holds all information about the current data-
base working on.
'''
"""
def __init__(self, **kwargs):
@ -317,6 +441,10 @@ class GenericDataStructure(object):
def modifyFields(self, **kwargs):
"""
:param kwargs:
"""
assert isinstance(kwargs, dict), 'dictionary type object expected'
if not self.extraAllowed():
@ -332,37 +460,67 @@ class GenericDataStructure(object):
value = str(value)
try:
self.setFieldValue(key, value)
except KeyError, e:
except KeyError as e:
errmsg = ''
errmsg += 'WARNING:\n'
errmsg += 'unable to set values for datastructure fields\n'
errmsg += '%s; desired value was: %s\n' % (e, value)
print errmsg
print(errmsg)
def isField(self, key):
"""
:param key:
:return:
"""
return key in self.getFields().keys()
def getFieldValue(self, key):
"""
:param key:
:return:
"""
if self.isField(key):
return self.getFields()[key]
else:
return
def setFieldValue(self, key, value):
"""
:param key:
:param value:
:raise KeyError:
"""
if not self.extraAllowed() and key not in self.getAllowed():
raise KeyError
else:
if not self.isField(key):
print 'creating new field "%s"' % key
print('creating new field "%s"' % key)
self.getFields()[key] = value
def getFields(self):
"""
:return:
"""
return self.dsFields
def getExpandFields(self):
"""
:return:
"""
return self.expandFields
def setExpandFields(self, keys):
"""
:param keys:
"""
expandFields = []
for key in keys:
if self.isField(key):
@ -370,18 +528,38 @@ class GenericDataStructure(object):
self.expandFields = expandFields
def getAllowed(self):
"""
:return:
"""
return self.allowedFields
def extraAllowed(self):
"""
:return:
"""
return not self.allowedFields
def updateNotAllowed(self, kwargs):
"""
:param kwargs:
:return:
"""
for key in kwargs:
if key not in self.getAllowed():
kwargs.__delitem__(key)
return kwargs
def hasSuffix(self):
"""
:return:
"""
try:
self.getFieldValue('suffix')
except KeyError:
@ -392,6 +570,11 @@ class GenericDataStructure(object):
return False
def expandDataPath(self):
"""
:return:
"""
expandList = []
for item in self.getExpandFields():
expandList.append(self.getFieldValue(item))
@ -400,14 +583,19 @@ class GenericDataStructure(object):
return os.path.join(*expandList)
def getCatalogName(self):
"""
:return:
"""
return os.path.join(self.getFieldValue('root'), 'catalog.qml')
class PilotDataStructure(GenericDataStructure):
'''
"""
Object containing the data access information for the old PILOT data
structure.
'''
"""
def __init__(self, **fields):
if not fields:
@ -420,14 +608,14 @@ class PilotDataStructure(GenericDataStructure):
class SeiscompDataStructure(GenericDataStructure):
'''
"""
Dictionary containing the data access information for an SDS data archive:
:param str dataType: Desired data type. Default: ``'waveform'``
:param sdate, edate: Either date string or an instance of
:class:`obspy.core.utcdatetime.UTCDateTime. Default: ``None``
:type sdate, edate: str or UTCDateTime or None
'''
"""
def __init__(self, rootpath='/data/SDS', dataformat='MSEED',
filesuffix=None, **kwargs):
@ -458,6 +646,10 @@ class SeiscompDataStructure(GenericDataStructure):
self.modifiyFields(**kwargs)
def modifiyFields(self, **kwargs):
"""
:param kwargs:
"""
if kwargs and isinstance(kwargs, dict):
for key, value in kwargs.iteritems():
key = str(key)
@ -467,28 +659,32 @@ class SeiscompDataStructure(GenericDataStructure):
else:
value = str(value)
try:
self.setField(key, value)
except KeyError, e:
self.setFieldValue(key, value)
except KeyError as e:
errmsg = ''
errmsg += 'WARNING:\n'
errmsg += 'unable to set values for SDS fields\n'
errmsg += '%s; desired value was: %s\n' % (e, value)
print errmsg
print(errmsg)
def setFieldValue(self, key, value):
"""
:param key:
:param value:
"""
if self.isField(key):
self.getFields()[key] = value
else:
print('Warning: trying to set value of non-existent field '
'{field}'.format(field=key))
def getFields(self):
return self.__sdsFields
def getName(self):
return self.__name
def expandDataPath(self):
"""
:return:
"""
fullChan = '{0}.{1}'.format(self.getFields()['CHAN'], self.getType())
dataPath = os.path.join(self.getFields()['SDSdir'],
self.getFields()['YEAR'],

View File

@ -16,3 +16,7 @@ class FormatError(Exception):
class DatastructureError(Exception):
pass
class OverwriteError(IOError):
pass