Resolved conflicts fmtomoUtils

This commit is contained in:
Marcel Paffrath 2016-05-02 11:28:56 +02:00
commit ddb1ad4a15
38 changed files with 2332 additions and 1398 deletions

View File

@ -43,8 +43,10 @@ from obspy import UTCDateTime
from pylot.core.read.data import Data from pylot.core.read.data import Data
from pylot.core.read.inputs import FilterOptions, AutoPickParameter from pylot.core.read.inputs import FilterOptions, AutoPickParameter
from pylot.core.pick.autopick import autopickevent from pylot.core.pick.autopick import autopickevent
from pylot.core.read.io import picks_from_evt
from pylot.core.loc.nll import locate as locateNll from pylot.core.loc.nll import locate as locateNll
from pylot.core.util.defaults import FILTERDEFAULTS from pylot.core.util.defaults import FILTERDEFAULTS, COMPNAME_MAP,\
AUTOMATIC_DEFAULTS
from pylot.core.util.errors import FormatError, DatastructureError, \ from pylot.core.util.errors import FormatError, DatastructureError, \
OverwriteError OverwriteError
from pylot.core.util.connection import checkurl from pylot.core.util.connection import checkurl
@ -110,8 +112,10 @@ class MainWindow(QMainWindow):
# load and display waveform data # load and display waveform data
self.dirty = False self.dirty = False
self.loadData() self.loadData()
self.loadWaveformData() if self.loadWaveformData():
self.updateFilterOptions() self.updateFilterOptions()
else:
sys.exit(0)
def setupUi(self): def setupUi(self):
@ -354,7 +358,10 @@ class MainWindow(QMainWindow):
settings = QSettings() settings = QSettings()
return settings.value("data/dataRoot") return settings.value("data/dataRoot")
def loadData(self, fname=None): def loadAutoPicks(self):
self.loadData(type='auto')
def loadData(self, fname=None, type='manual'):
if not self.okToContinue(): if not self.okToContinue():
return return
if fname is None: if fname is None:
@ -368,10 +375,10 @@ class MainWindow(QMainWindow):
filter=filt) filter=filt)
fname = fname[0] fname = fname[0]
else: else:
fname = unicode(action.data().toString()) fname = str(action.data().toString())
self.setFileName(fname) self.setFileName(fname)
self.data += Data(self, evtdata=self.getFileName()) self.data += Data(self, evtdata=self.getFileName())
self.updatePicks() self.updatePicks(type=type)
self.drawPicks() self.drawPicks()
def getLastEvent(self): def getLastEvent(self):
@ -403,6 +410,8 @@ class MainWindow(QMainWindow):
else: else:
raise DatastructureError('not specified') raise DatastructureError('not specified')
if not self.fnames:
return None
return self.fnames return self.fnames
except DatastructureError as e: except DatastructureError as e:
print(e) print(e)
@ -431,13 +440,14 @@ class MainWindow(QMainWindow):
print('warning: {0}'.format(e)) print('warning: {0}'.format(e))
directory = os.path.join(self.getRoot(), self.getEventFileName()) directory = os.path.join(self.getRoot(), self.getEventFileName())
file_filter = "QuakeML file (*.xml);;VELEST observation file format (*.cnv);;NonLinLoc observation file (*.obs)" file_filter = "QuakeML file (*.xml);;VELEST observation file format (*.cnv);;NonLinLoc observation file (*.obs)"
fname = QFileDialog.getSaveFileName(self, 'Save event data ...', fname, selected_filter = QFileDialog.getSaveFileName(self, 'Save event data ...',
directory, file_filter) directory, file_filter)
fbasename, exform = os.path.splitext(fname[0]) fbasename, exform = os.path.splitext(fname)
if not exform and selected_filter:
exform = selected_filter.split('*')[1][:-1]
if not exform:
exform = file_filter[0].split('*')[1][:-1]
return fbasename, exform return fbasename, exform
settings = QSettings() settings = QSettings()
@ -455,7 +465,7 @@ class MainWindow(QMainWindow):
ret = msgBox.exec_() ret = msgBox.exec_()
if ret == QMessageBox.Save: if ret == QMessageBox.Save:
self.getData().resetPicks() self.getData().resetPicks()
self.saveData() return self.saveData()
elif ret == QMessageBox.Cancel: elif ret == QMessageBox.Cancel:
return False return False
try: try:
@ -524,17 +534,23 @@ class MainWindow(QMainWindow):
def loadWaveformData(self): def loadWaveformData(self):
if self.fnames and self.okToContinue(): if self.fnames and self.okToContinue():
self.setDirty(True) self.setDirty(True)
self.data.setWFData(self.fnames) ans = self.data.setWFData(self.fnames)
elif self.fnames is None and self.okToContinue(): elif self.fnames is None and self.okToContinue():
self.data.setWFData(self.getWFFnames()) ans = self.data.setWFData(self.getWFFnames())
if ans:
self.plotWaveformData() self.plotWaveformData()
return ans
else:
return ans
def plotWaveformData(self): def plotWaveformData(self):
zne_text = {'Z': 'vertical', 'N': 'north-south', 'E': 'east-west'} zne_text = {'Z': 'vertical', 'N': 'north-south', 'E': 'east-west'}
comp = self.getComponent() comp = self.getComponent()
title = 'section: {0} components'.format(zne_text[comp]) title = 'section: {0} components'.format(zne_text[comp])
alter_comp = COMPNAME_MAP[comp]
wfst = self.getData().getWFData().select(component=comp) wfst = self.getData().getWFData().select(component=comp)
self.getPlotWidget().plotWFData(wfdata=wfst, title=title) wfst += self.getData().getWFData().select(component=alter_comp)
self.getPlotWidget().plotWFData(wfdata=wfst, title=title, mapping=False)
self.draw() self.draw()
plotDict = self.getPlotWidget().getPlotDict() plotDict = self.getPlotWidget().getPlotDict()
pos = plotDict.keys() pos = plotDict.keys()
@ -569,6 +585,7 @@ class MainWindow(QMainWindow):
else: else:
self.getData().resetWFData() self.getData().resetWFData()
self.plotWaveformData() self.plotWaveformData()
self.drawPicks()
def adjustFilterOptions(self): def adjustFilterOptions(self):
fstring = "Filter Options ({0})".format(self.getSeismicPhase()) fstring = "Filter Options ({0})".format(self.getSeismicPhase())
@ -673,8 +690,7 @@ class MainWindow(QMainWindow):
self.logDockWidget.setWidget(self.listWidget) self.logDockWidget.setWidget(self.listWidget)
self.addDockWidget(Qt.LeftDockWidgetArea, self.logDockWidget) self.addDockWidget(Qt.LeftDockWidgetArea, self.logDockWidget)
self.addListItem('loading default values for local data ...') self.addListItem('loading default values for local data ...')
home = os.path.expanduser("~") autopick_parameter = AutoPickParameter(AUTOMATIC_DEFAULTS)
autopick_parameter = AutoPickParameter('%s/.pylot/autoPyLoT_local.in' % home)
self.addListItem(str(autopick_parameter)) self.addListItem(str(autopick_parameter))
# Create the worker thread and run it # Create the worker thread and run it
@ -718,29 +734,12 @@ class MainWindow(QMainWindow):
self.getPicks(type=type)[station] = stat_picks self.getPicks(type=type)[station] = stat_picks
return rval return rval
def updatePicks(self): def updatePicks(self, type='manual'):
evt = self.getData().getEvtData() picks = picks_from_evt(evt=self.getData().getEvtData())
picks = {} if type == 'manual':
for pick in evt.picks:
phase = {}
station = pick.waveform_id.station_code
try:
onsets = picks[station]
except KeyError as e:
print(e)
onsets = {}
mpp = pick.time
lpp = mpp + pick.time_errors.upper_uncertainty
epp = mpp - pick.time_errors.lower_uncertainty
spe = pick.time_errors.uncertainty
phase['mpp'] = mpp
phase['epp'] = epp
phase['lpp'] = lpp
phase['spe'] = spe
onsets[pick.phase_hint] = phase.copy()
picks[station] = onsets.copy()
self.picks.update(picks) self.picks.update(picks)
elif type == 'auto':
self.autopicks.update(picks)
def drawPicks(self, station=None, picktype='manual'): def drawPicks(self, station=None, picktype='manual'):
# if picks to draw not specified, draw all picks available # if picks to draw not specified, draw all picks available

View File

@ -1,6 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import print_function
import os import os
import argparse import argparse
import glob import glob
@ -94,7 +95,6 @@ def autoPyLoT(inputfile):
print("!!No source parameter estimation possible!!") print("!!No source parameter estimation possible!!")
print(" !!! ") print(" !!! ")
# multiple event processing # multiple event processing
# read each event in database # read each event in database
datapath = datastructure.expandDataPath() datapath = datastructure.expandDataPath()
@ -202,10 +202,15 @@ def autoPyLoT(inputfile):
if hasattr(finalpicks, 'getpicdic'): if hasattr(finalpicks, 'getpicdic'):
if finalpicks.getpicdic() is not None: if finalpicks.getpicdic() is not None:
writephases(finalpicks.getpicdic(), 'HYPO71', hypo71file) writephases(finalpicks.getpicdic(), 'HYPO71', hypo71file)
data.applyEVTData(finalpicks.getpicdic())
else: else:
writephases(picks, 'HYPO71', hypo71file) writephases(picks, 'HYPO71', hypo71file)
data.applyEVTData(picks)
else: else:
writephases(picks, 'HYPO71', hypo71file) writephases(picks, 'HYPO71', hypo71file)
data.applyEVTData(picks)
fnqml = '%s/autoPyLoT' % event
data.exportEvent(fnqml)
endsplash = '''------------------------------------------\n' endsplash = '''------------------------------------------\n'
-----Finished event %s!-----\n' -----Finished event %s!-----\n'
@ -218,8 +223,8 @@ def autoPyLoT(inputfile):
# single event processing # single event processing
else: else:
data.setWFData(glob.glob(os.path.join(datapath, parameter.getParam('eventID'), '*'))) data.setWFData(glob.glob(os.path.join(datapath, parameter.getParam('eventID'), '*')))
print("Working on event "), parameter.getParam('eventID') print("Working on event {0}".format(parameter.getParam('eventID')))
print data print(data)
wfdat = data.getWFData() # all available streams wfdat = data.getWFData() # all available streams
########################################################## ##########################################################
@ -318,10 +323,15 @@ def autoPyLoT(inputfile):
if hasattr(finalpicks, 'getpicdic'): if hasattr(finalpicks, 'getpicdic'):
if finalpicks.getpicdic() is not None: if finalpicks.getpicdic() is not None:
writephases(finalpicks.getpicdic(), 'HYPO71', hypo71file) writephases(finalpicks.getpicdic(), 'HYPO71', hypo71file)
data.applyEVTData(finalpicks.getpicdic())
else: else:
writephases(picks, 'HYPO71', hypo71file) writephases(picks, 'HYPO71', hypo71file)
data.applyEVTData(picks)
else: else:
writephases(picks, 'HYPO71', hypo71file) writephases(picks, 'HYPO71', hypo71file)
data.applyEVTData(picks)
fnqml = '%s/%s/autoPyLoT' % (datapath, parameter.getParam('eventID'))
data.exportEvent(fnqml)
endsplash = '''------------------------------------------\n' endsplash = '''------------------------------------------\n'
-----Finished event %s!-----\n' -----Finished event %s!-----\n'
@ -338,7 +348,9 @@ def autoPyLoT(inputfile):
************************************'''.format(version=_getVersionString()) ************************************'''.format(version=_getVersionString())
print(endsp) print(endsp)
if __name__ == "__main__": if __name__ == "__main__":
from pylot.core.util.defaults import AUTOMATIC_DEFAULTS
# parse arguments # parse arguments
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='''autoPyLoT automatically picks phase onset times using higher order statistics, description='''autoPyLoT automatically picks phase onset times using higher order statistics,
@ -348,8 +360,7 @@ if __name__ == "__main__":
action='store', action='store',
help='''full path to the file containing the input help='''full path to the file containing the input
parameters for autoPyLoT''', parameters for autoPyLoT''',
default=os.path.join(os.path.expanduser('~'), '.pylot', default=AUTOMATIC_DEFAULTS
'autoPyLoT.in')
) )
parser.add_argument('-v', '-V', '--version', action='version', parser.add_argument('-v', '-V', '--version', action='version',
version='autoPyLoT ' + __version__, version='autoPyLoT ' + __version__,

View File

@ -1,2 +1,2 @@
P P bandpass 4 2.0 20.0
S bandpass 4 0.5 5.0 S bandpass 4 2.0 15.0

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# encoding: utf-8 # encoding: utf-8
from __future__ import print_function
""" """
makePyLoT -- build and install PyLoT makePyLoT -- build and install PyLoT
@ -123,7 +125,7 @@ USAGE
except KeyboardInterrupt: except KeyboardInterrupt:
cleanUp(verbose) cleanUp(verbose)
return 0 return 0
except Exception, e: except Exception as e:
if DEBUG or TESTRUN: if DEBUG or TESTRUN:
raise e raise e
indent = len(program_name) * " " indent = len(program_name) * " "
@ -139,7 +141,7 @@ def buildPyLoT(verbosity=None):
"\n" "\n"
" Current working directory: {1}\n" " Current working directory: {1}\n"
).format(system, os.getcwd()) ).format(system, os.getcwd())
print msg print(msg)
if system.startswith(('win', 'microsoft')): if system.startswith(('win', 'microsoft')):
raise CLIError( raise CLIError(
"building on Windows system not tested yet; implementation pending") "building on Windows system not tested yet; implementation pending")

View File

@ -1 +1 @@
a31e-dirty 1508-dirty

View File

@ -4,6 +4,7 @@ import numpy as np
from pylot.core.active import seismicshot from pylot.core.active import seismicshot
from pylot.core.active.surveyUtils import cleanUp from pylot.core.active.surveyUtils import cleanUp
class Survey(object): class Survey(object):
def __init__(self, path, sourcefile, receiverfile, useDefaultParas=False): def __init__(self, path, sourcefile, receiverfile, useDefaultParas=False):
''' '''
@ -70,7 +71,8 @@ class Survey(object):
Removes traces that do not exist in the dataset for any reason. Removes traces that do not exist in the dataset for any reason.
''' '''
filename = 'updateShots.out' filename = 'updateShots.out'
count = 0; countTraces = 0 count = 0;
countTraces = 0
for shot in self.data.values(): for shot in self.data.values():
del_traceIDs = shot.updateTraceList() del_traceIDs = shot.updateTraceList()
if len(del_traceIDs) > 0: if len(del_traceIDs) > 0:
@ -135,7 +137,10 @@ class Survey(object):
def plotDiffs(self): def plotDiffs(self):
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
diffs = []; dists = []; mpicks = []; picks = [] diffs = [];
dists = [];
mpicks = [];
picks = []
diffsDic = self.getDiffsFromManual() diffsDic = self.getDiffsFromManual()
for shot in self.data.values(): for shot in self.data.values():
for traceID in shot.getTraceIDlist(): for traceID in shot.getTraceIDlist():
@ -181,10 +186,12 @@ class Survey(object):
''' '''
from datetime import datetime from datetime import datetime
starttime = datetime.now() starttime = datetime.now()
count = 0; tpicksum = starttime - starttime count = 0;
tpicksum = starttime - starttime
for shot in self.data.values(): for shot in self.data.values():
tstartpick = datetime.now(); count += 1 tstartpick = datetime.now();
count += 1
for traceID in shot.getTraceIDlist(): for traceID in shot.getTraceIDlist():
distance = shot.getDistance(traceID) # receive distance distance = shot.getDistance(traceID) # receive distance
@ -211,7 +218,8 @@ class Survey(object):
if shot.getSNR(traceID)[0] > 1: if shot.getSNR(traceID)[0] > 1:
shot.setEarllatepick(traceID) shot.setEarllatepick(traceID)
tpicksum += (datetime.now() - tstartpick); tpick = tpicksum/count tpicksum += (datetime.now() - tstartpick);
tpick = tpicksum / count
tremain = (tpick * (len(self.getShotDict()) - count)) tremain = (tpick * (len(self.getShotDict()) - count))
tend = datetime.now() + tremain tend = datetime.now() + tremain
progress = float(count) / float(len(self.getShotDict())) * 100 progress = float(count) / float(len(self.getShotDict())) * 100
@ -339,7 +347,9 @@ class Survey(object):
count = 0 count = 0
fmtomo_factor = 1000 # transforming [m/s] -> [km/s] fmtomo_factor = 1000 # transforming [m/s] -> [km/s]
LatAll = []; LonAll = []; DepthAll = [] LatAll = [];
LonAll = [];
DepthAll = []
srcfile = open(directory + '/' + sourcefile, 'w') srcfile = open(directory + '/' + sourcefile, 'w')
srcfile.writelines('%10s\n' % len(self.data)) # number of sources srcfile.writelines('%10s\n' % len(self.data)) # number of sources
for shotnumber in self.getShotlist(): for shotnumber in self.getShotlist():
@ -347,7 +357,9 @@ class Survey(object):
ttfilename = str(shotnumber) + ttFileExtension ttfilename = str(shotnumber) + ttFileExtension
(x, y, z) = shot.getSrcLoc() # getSrcLoc returns (x, y, z) (x, y, z) = shot.getSrcLoc() # getSrcLoc returns (x, y, z)
srcfile.writelines('%10s %10s %10s\n' % (getAngle(y), getAngle(x), (-1) * z)) # lat, lon, depth srcfile.writelines('%10s %10s %10s\n' % (getAngle(y), getAngle(x), (-1) * z)) # lat, lon, depth
LatAll.append(getAngle(y)); LonAll.append(getAngle(x)); DepthAll.append((-1)*z) LatAll.append(getAngle(y));
LonAll.append(getAngle(x));
DepthAll.append((-1) * z)
srcfile.writelines('%10s\n' % 1) # srcfile.writelines('%10s\n' % 1) #
srcfile.writelines('%10s %10s %10s\n' % (1, 1, ttfilename)) srcfile.writelines('%10s %10s %10s\n' % (1, 1, ttfilename))
ttfile = open(directory + '/' + ttfilename, 'w') ttfile = open(directory + '/' + ttfilename, 'w')
@ -360,7 +372,9 @@ class Survey(object):
delta = shot.getSymmetricPickError(traceID) * fmtomo_factor delta = shot.getSymmetricPickError(traceID) * fmtomo_factor
(x, y, z) = shot.getRecLoc(traceID) (x, y, z) = shot.getRecLoc(traceID)
ttfile.writelines('%20s %20s %20s %10s %10s\n' % (getAngle(y), getAngle(x), (-1) * z, pick, delta)) ttfile.writelines('%20s %20s %20s %10s %10s\n' % (getAngle(y), getAngle(x), (-1) * z, pick, delta))
LatAll.append(getAngle(y)); LonAll.append(getAngle(x)); DepthAll.append((-1)*z) LatAll.append(getAngle(y));
LonAll.append(getAngle(x));
DepthAll.append((-1) * z)
count += 1 count += 1
ttfile.close() ttfile.close()
srcfile.close() srcfile.close()

View File

@ -2,6 +2,7 @@
import sys import sys
import numpy as np import numpy as np
def vgrids2VTK(inputfile='vgrids.in', outputfile='vgrids.vtk', absOrRel='abs', inputfileref='vgridsref.in'): def vgrids2VTK(inputfile='vgrids.in', outputfile='vgrids.vtk', absOrRel='abs', inputfileref='vgridsref.in'):
''' '''
Generate a vtk-file readable by e.g. paraview from FMTOMO output vgrids.in Generate a vtk-file readable by e.g. paraview from FMTOMO output vgrids.in
@ -19,7 +20,9 @@ def vgrids2VTK(inputfile = 'vgrids.in', outputfile = 'vgrids.vtk', absOrRel = 'a
nPoints = nR * nTheta * nPhi nPoints = nR * nTheta * nPhi
nX = nPhi; nY = nTheta; nZ = nR nX = nPhi;
nY = nTheta;
nZ = nR
sZ = sR - R sZ = sR - R
sX = _getDistance(sPhi) sX = _getDistance(sPhi)
@ -42,9 +45,13 @@ def vgrids2VTK(inputfile = 'vgrids.in', outputfile = 'vgrids.vtk', absOrRel = 'a
outfile.writelines('POINT_DATA %15d\n' % (nPoints)) outfile.writelines('POINT_DATA %15d\n' % (nPoints))
if absOrRel == 'abs': if absOrRel == 'abs':
<<<<<<< HEAD
outfile.writelines('SCALARS velocity float %d\n' %(1)) outfile.writelines('SCALARS velocity float %d\n' %(1))
if absOrRel == 'relDepth': if absOrRel == 'relDepth':
outfile.writelines('SCALARS velocity2depthMean float %d\n' %(1)) outfile.writelines('SCALARS velocity2depthMean float %d\n' %(1))
=======
outfile.writelines('SCALARS velocity float %d\n' % (1))
>>>>>>> 37f9292c39246b327d3630995ca2521725c6cdd7
elif absOrRel == 'rel': elif absOrRel == 'rel':
outfile.writelines('SCALARS velChangePercent float %d\n' % (1)) outfile.writelines('SCALARS velChangePercent float %d\n' % (1))
outfile.writelines('LOOKUP_TABLE default\n') outfile.writelines('LOOKUP_TABLE default\n')
@ -55,6 +62,7 @@ def vgrids2VTK(inputfile = 'vgrids.in', outputfile = 'vgrids.vtk', absOrRel = 'a
if absOrRel == 'abs': if absOrRel == 'abs':
print("Writing velocity values to VTK file...") print("Writing velocity values to VTK file...")
for velocity in vel: for velocity in vel:
<<<<<<< HEAD
outfile.writelines('%10f\n' %velocity) outfile.writelines('%10f\n' %velocity)
elif absOrRel == 'relDepth': elif absOrRel == 'relDepth':
print("Writing velocity values to VTK file relative to mean of each depth...") print("Writing velocity values to VTK file relative to mean of each depth...")
@ -69,6 +77,9 @@ def vgrids2VTK(inputfile = 'vgrids.in', outputfile = 'vgrids.vtk', absOrRel = 'a
for vel in veldepth: for vel in veldepth:
outfile.writelines('%10f\n' %(vel - velmean)) outfile.writelines('%10f\n' %(vel - velmean))
veldepth = [] veldepth = []
=======
outfile.writelines('%10f\n' % velocity)
>>>>>>> 37f9292c39246b327d3630995ca2521725c6cdd7
elif absOrRel == 'rel': elif absOrRel == 'rel':
nref, dref, sref, velref = _readVgrid(inputfileref) nref, dref, sref, velref = _readVgrid(inputfileref)
nR_ref, nTheta_ref, nPhi_ref = nref nR_ref, nTheta_ref, nPhi_ref = nref
@ -96,6 +107,7 @@ def vgrids2VTK(inputfile = 'vgrids.in', outputfile = 'vgrids.vtk', absOrRel = 'a
print("Wrote velocity grid for %d points to file: %s" % (nPoints, outputfile)) print("Wrote velocity grid for %d points to file: %s" % (nPoints, outputfile))
return return
def rays2VTK(fnin, fdirout='./vtk_files/', nthPoint=50): def rays2VTK(fnin, fdirout='./vtk_files/', nthPoint=50):
''' '''
Writes VTK file(s) for FMTOMO rays from rays.dat Writes VTK file(s) for FMTOMO rays from rays.dat
@ -127,7 +139,8 @@ def rays2VTK(fnin, fdirout = './vtk_files/', nthPoint = 50):
for index in range(nRayPoints): for index in range(nRayPoints):
if index % nthPoint is 0 or index == (nRayPoints - 1): if index % nthPoint is 0 or index == (nRayPoints - 1):
rad, lat, lon = infile.readline().split() rad, lat, lon = infile.readline().split()
rays[shotnumber][raynumber].append([_getDistance(np.rad2deg(float(lon))), _getDistance(np.rad2deg(float(lat))), float(rad) - R]) rays[shotnumber][raynumber].append(
[_getDistance(np.rad2deg(float(lon))), _getDistance(np.rad2deg(float(lat))), float(rad) - R])
else: else:
dummy = infile.readline() dummy = infile.readline()
@ -169,6 +182,7 @@ def rays2VTK(fnin, fdirout = './vtk_files/', nthPoint = 50):
count += 1 count += 1
outfile.writelines('\n') outfile.writelines('\n')
def _readVgrid(filename): def _readVgrid(filename):
def readNumberOfPoints(filename): def readNumberOfPoints(filename):
fin = open(filename, 'r') fin = open(filename, 'r')
@ -209,7 +223,8 @@ def _readVgrid(filename):
''' '''
Reads in velocity from vgrids file and returns a list containing all values in the same order Reads in velocity from vgrids file and returns a list containing all values in the same order
''' '''
vel = []; count = 0 vel = [];
count = 0
fin = open(filename, 'r') fin = open(filename, 'r')
vglines = fin.readlines() vglines = fin.readlines()
@ -235,6 +250,7 @@ def _readVgrid(filename):
start = (sR, sTheta, sPhi) start = (sR, sTheta, sPhi)
return number, delta, start, vel return number, delta, start, vel
def _generateGrids(number, delta, start): def _generateGrids(number, delta, start):
nR, nTheta, nPhi = number nR, nTheta, nPhi = number
dR, dTheta, dPhi = delta dR, dTheta, dPhi = delta
@ -250,6 +266,7 @@ def _generateGrids(number, delta, start):
return (thetaGrid, phiGrid, rGrid) return (thetaGrid, phiGrid, rGrid)
def addCheckerboard(spacing=10., pertubation=0.1, inputfile='vgrids.in', def addCheckerboard(spacing=10., pertubation=0.1, inputfile='vgrids.in',
outputfile='vgrids_cb.in', ampmethod='linear', rect=(None, None)): outputfile='vgrids_cb.in', ampmethod='linear', rect=(None, None)):
''' '''
@ -261,6 +278,7 @@ def addCheckerboard(spacing = 10., pertubation = 0.1, inputfile = 'vgrids.in',
:param: pertubation, pertubation (default: 0.1 = 10%) :param: pertubation, pertubation (default: 0.1 = 10%)
type: float type: float
''' '''
def correctSpacing(spacing, delta, disttype=None): def correctSpacing(spacing, delta, disttype=None):
if spacing > delta: if spacing > delta:
spacing_corr = round(spacing / delta) * delta spacing_corr = round(spacing / delta) * delta
@ -315,7 +333,8 @@ def addCheckerboard(spacing = 10., pertubation = 0.1, inputfile = 'vgrids.in',
count = 0 count = 0
evenOdd = 1 evenOdd = 1
even = 0; odd = 0 even = 0;
odd = 0
# In the following loop it is checked whether the positive distance from the border of the model # In the following loop it is checked whether the positive distance from the border of the model
# for a point on the grid divided by the spacing is even or odd and then pertubated. # for a point on the grid divided by the spacing is even or odd and then pertubated.
@ -361,6 +380,7 @@ def addCheckerboard(spacing = 10., pertubation = 0.1, inputfile = 'vgrids.in',
'Outputfile: %s.' % (inputfile, spacing, pertubation * 100, outputfile)) 'Outputfile: %s.' % (inputfile, spacing, pertubation * 100, outputfile))
outfile.close() outfile.close()
def addBox(x=(None, None), y=(None, None), z=(None, None), def addBox(x=(None, None), y=(None, None), z=(None, None),
boxvelocity=1.0, inputfile='vgrids.in', boxvelocity=1.0, inputfile='vgrids.in',
outputfile='vgrids_box.in'): outputfile='vgrids_box.in'):
@ -440,10 +460,12 @@ def addBox(x = (None, None), y = (None, None), z = (None, None),
'Outputfile: %s.' % (inputfile, outputfile)) 'Outputfile: %s.' % (inputfile, outputfile))
outfile.close() outfile.close()
def _update_progress(progress): def _update_progress(progress):
sys.stdout.write("%d%% done \r" % (progress)) sys.stdout.write("%d%% done \r" % (progress))
sys.stdout.flush() sys.stdout.flush()
def _getAngle(distance): def _getAngle(distance):
''' '''
Function returns the angle on a Sphere of the radius R = 6371 [km] for a distance [km]. Function returns the angle on a Sphere of the radius R = 6371 [km] for a distance [km].
@ -453,9 +475,9 @@ def _getAngle(distance):
angle = distance * 180. / (PI * R) angle = distance * 180. / (PI * R)
return angle return angle
def _getDistance(angle): def _getDistance(angle):
PI = np.pi PI = np.pi
R = 6371. R = 6371.
distance = angle / 180 * (PI * R) distance = angle / 180 * (PI * R)
return distance return distance

View File

@ -3,6 +3,7 @@ import sys
import numpy as np import numpy as np
from scipy.interpolate import griddata from scipy.interpolate import griddata
class SeisArray(object): class SeisArray(object):
''' '''
Can be used to interpolate missing values of a receiver grid, if only support points were measured. Can be used to interpolate missing values of a receiver grid, if only support points were measured.
@ -15,6 +16,7 @@ class SeisArray(object):
Supports vtk output for sources and receivers. Supports vtk output for sources and receivers.
Note: Source and Receiver files for FMTOMO will be generated by the Survey object (because traveltimes will be added directly). Note: Source and Receiver files for FMTOMO will be generated by the Survey object (because traveltimes will be added directly).
''' '''
def __init__(self, recfile): def __init__(self, recfile):
self.recfile = recfile self.recfile = recfile
self._receiverlines = {} self._receiverlines = {}
@ -151,7 +153,8 @@ class SeisArray(object):
Returns the mean distance between two traceID's depending on the number of geophones in between Returns the mean distance between two traceID's depending on the number of geophones in between
''' '''
num_spaces = abs(self._getGeophoneNumber(traceID1) - self._getGeophoneNumber(traceID2)) num_spaces = abs(self._getGeophoneNumber(traceID1) - self._getGeophoneNumber(traceID2))
mean_distance = abs(self._getReceiverValue(traceID1, coordinate) - self._getReceiverValue(traceID2, coordinate))/num_spaces mean_distance = abs(
self._getReceiverValue(traceID1, coordinate) - self._getReceiverValue(traceID2, coordinate)) / num_spaces
return mean_distance return mean_distance
def interpolateValues(self, coordinate): def interpolateValues(self, coordinate):
@ -214,7 +217,8 @@ class SeisArray(object):
for traceID in self.getReceiverCoordinates().keys(): for traceID in self.getReceiverCoordinates().keys():
if type(self.getReceiverCoordinates()[traceID]) is not tuple: if type(self.getReceiverCoordinates()[traceID]) is not tuple:
z = griddata((measured_x, measured_y), measured_z, (self._getXreceiver(traceID), self._getYreceiver(traceID)), method = method) z = griddata((measured_x, measured_y), measured_z,
(self._getXreceiver(traceID), self._getYreceiver(traceID)), method=method)
self._setZvalue(traceID, float(z)) self._setZvalue(traceID, float(z))
def _getAngle(self, distance): def _getAngle(self, distance):
@ -239,7 +243,9 @@ class SeisArray(object):
''' '''
Returns a list of all measured receivers known to SeisArray. Returns a list of all measured receivers known to SeisArray.
''' '''
x = []; y = []; z = [] x = [];
y = [];
z = []
for traceID in self.getMeasuredReceivers().keys(): for traceID in self.getMeasuredReceivers().keys():
x.append(self.getMeasuredReceivers()[traceID][0]) x.append(self.getMeasuredReceivers()[traceID][0])
y.append(self.getMeasuredReceivers()[traceID][1]) y.append(self.getMeasuredReceivers()[traceID][1])
@ -250,7 +256,9 @@ class SeisArray(object):
''' '''
Returns a list of all measured topography points known to the SeisArray. Returns a list of all measured topography points known to the SeisArray.
''' '''
x = []; y = []; z = [] x = [];
y = [];
z = []
for pointID in self.getMeasuredTopo().keys(): for pointID in self.getMeasuredTopo().keys():
x.append(self.getMeasuredTopo()[pointID][0]) x.append(self.getMeasuredTopo()[pointID][0])
y.append(self.getMeasuredTopo()[pointID][1]) y.append(self.getMeasuredTopo()[pointID][1])
@ -261,7 +269,9 @@ class SeisArray(object):
''' '''
Returns a list of all measured source locations known to SeisArray. Returns a list of all measured source locations known to SeisArray.
''' '''
x = []; y = []; z = [] x = [];
y = [];
z = []
for pointID in self.getSourceLocations().keys(): for pointID in self.getSourceLocations().keys():
x.append(self.getSourceLocations()[pointID][0]) x.append(self.getSourceLocations()[pointID][0])
y.append(self.getSourceLocations()[pointID][1]) y.append(self.getSourceLocations()[pointID][1])
@ -285,7 +295,9 @@ class SeisArray(object):
''' '''
Returns a list of all receivers (measured and interpolated). Returns a list of all receivers (measured and interpolated).
''' '''
x = []; y =[]; z = [] x = [];
y = [];
z = []
for traceID in self.getReceiverCoordinates().keys(): for traceID in self.getReceiverCoordinates().keys():
x.append(self.getReceiverCoordinates()[traceID][0]) x.append(self.getReceiverCoordinates()[traceID][0])
y.append(self.getReceiverCoordinates()[traceID][1]) y.append(self.getReceiverCoordinates()[traceID][1])
@ -364,7 +376,8 @@ class SeisArray(object):
thetaGrid = np.linspace(thetaS - deltaTheta, thetaN + deltaTheta, num=nTheta + 2) # +2 cushion nodes thetaGrid = np.linspace(thetaS - deltaTheta, thetaN + deltaTheta, num=nTheta + 2) # +2 cushion nodes
phiGrid = np.linspace(phiW - deltaPhi, phiE + deltaPhi, num=nPhi + 2) # +2 cushion nodes phiGrid = np.linspace(phiW - deltaPhi, phiE + deltaPhi, num=nPhi + 2) # +2 cushion nodes
nTotal = len(thetaGrid) * len(phiGrid); count = 0 nTotal = len(thetaGrid) * len(phiGrid);
count = 0
for theta in thetaGrid: for theta in thetaGrid:
for phi in phiGrid: for phi in phiGrid:
xval = self._getDistance(phi) xval = self._getDistance(phi)
@ -457,7 +470,6 @@ class SeisArray(object):
outfile.close() outfile.close()
def generateInterfaces(self, nTheta, nPhi, depthmax, cushionfactor=0.1, def generateInterfaces(self, nTheta, nPhi, depthmax, cushionfactor=0.1,
outfilename='interfaces.in', method='linear', outfilename='interfaces.in', method='linear',
returnInterfaces=False): returnInterfaces=False):
@ -641,7 +653,10 @@ class SeisArray(object):
return nlayers return nlayers
def readMygrid(filename): def readMygrid(filename):
ztop = []; zbot = []; vtop = []; vbot = [] ztop = [];
zbot = [];
vtop = [];
vbot = []
infile = open(filename, 'r') infile = open(filename, 'r')
nlayers = readMygridNlayers(filename) nlayers = readMygridNlayers(filename)
@ -696,7 +711,8 @@ class SeisArray(object):
outfile.writelines('%10s %10s \n' % (1, 1)) outfile.writelines('%10s %10s \n' % (1, 1))
outfile.writelines('%10s %10s %10s\n' % (nR + 2, nTheta + 2, nPhi + 2)) outfile.writelines('%10s %10s %10s\n' % (nR + 2, nTheta + 2, nPhi + 2))
outfile.writelines('%10s %10s %10s\n' % (deltaR, np.deg2rad(deltaTheta), np.deg2rad(deltaPhi))) outfile.writelines('%10s %10s %10s\n' % (deltaR, np.deg2rad(deltaTheta), np.deg2rad(deltaPhi)))
outfile.writelines('%10s %10s %10s\n' %(rbot - deltaR, np.deg2rad(thetaS - deltaTheta), np.deg2rad(phiW - deltaPhi))) outfile.writelines(
'%10s %10s %10s\n' % (rbot - deltaR, np.deg2rad(thetaS - deltaTheta), np.deg2rad(phiW - deltaPhi)))
surface = self.interpolateTopography(nTheta, nPhi, thetaSN, phiWE, method=method) surface = self.interpolateTopography(nTheta, nPhi, thetaSN, phiWE, method=method)
@ -726,14 +742,18 @@ class SeisArray(object):
else: else:
for index in range(nlayers): for index in range(nlayers):
if (ztop[index]) >= depth > (zbot[index]): if (ztop[index]) >= depth > (zbot[index]):
vel = (depth - ztop[index]) / (zbot[index] - ztop[index]) * (vbot[index] - vtop[index]) + vtop[index] vel = (depth - ztop[index]) / (zbot[index] - ztop[index]) * (
vbot[index] - vtop[index]) + vtop[index]
break break
if not (ztop[index]) >= depth > (zbot[index]): if not (ztop[index]) >= depth > (zbot[index]):
print('ERROR in grid inputfile, could not find velocity for a z-value of %s in the inputfile'%(depth-topo)) print(
'ERROR in grid inputfile, could not find velocity for a z-value of %s in the inputfile' % (
depth - topo))
return return
count += 1 count += 1
if vel < 0: if vel < 0:
print('ERROR, vel <0; z, topo, zbot, vbot, vtop:', depth, topo, zbot[index], vbot[index], vtop[index]) print(
'ERROR, vel <0; z, topo, zbot, vbot, vtop:', depth, topo, zbot[index], vbot[index], vtop[index])
outfile.writelines('%10s %10s\n' % (vel, decm)) outfile.writelines('%10s %10s\n' % (vel, decm))
progress = float(count) / float(nTotal) * 100 progress = float(count) / float(nTotal) * 100
@ -786,11 +806,11 @@ class SeisArray(object):
plt.legend() plt.legend()
if annotations == True: if annotations == True:
for traceID in self.getReceiverCoordinates().keys(): for traceID in self.getReceiverCoordinates().keys():
ax.annotate((' ' + str(traceID)), xy = (self._getXreceiver(traceID), self._getYreceiver(traceID)), fontsize = 'x-small', color = 'k') ax.annotate((' ' + str(traceID)), xy=(self._getXreceiver(traceID), self._getYreceiver(traceID)),
fontsize='x-small', color='k')
for shotnumber in self.getSourceLocations().keys(): for shotnumber in self.getSourceLocations().keys():
ax.annotate((' ' + str(shotnumber)), xy = (self._getXshot(shotnumber), self._getYshot(shotnumber)), fontsize = 'x-small', color = 'b') ax.annotate((' ' + str(shotnumber)), xy=(self._getXshot(shotnumber), self._getYshot(shotnumber)),
fontsize='x-small', color='b')
def plotArray3D(self, ax=None): def plotArray3D(self, ax=None):
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
@ -815,12 +835,13 @@ class SeisArray(object):
ax.plot(xmr, ymr, zmr, 'ro', label='measured receivers') ax.plot(xmr, ymr, zmr, 'ro', label='measured receivers')
if len(xsc) > 0: if len(xsc) > 0:
ax.plot(xsc, ysc, zsc, 'b*', label='shot locations') ax.plot(xsc, ysc, zsc, 'b*', label='shot locations')
ax.set_xlabel('X [m]'); ax.set_ylabel('Y [m]'); ax.set_zlabel('Z [m]') ax.set_xlabel('X [m]');
ax.set_ylabel('Y [m]');
ax.set_zlabel('Z [m]')
ax.legend() ax.legend()
return ax return ax
def plotSurface3D(self, ax=None, step=0.5, method='linear', exag=False): def plotSurface3D(self, ax=None, step=0.5, method='linear', exag=False):
from matplotlib import cm from matplotlib import cm
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
@ -853,7 +874,9 @@ class SeisArray(object):
ax.set_zlim(-(max(x) - min(x) / 2), (max(x) - min(x) / 2)) ax.set_zlim(-(max(x) - min(x) / 2), (max(x) - min(x) / 2))
ax.set_aspect('equal') ax.set_aspect('equal')
ax.set_xlabel('X [m]'); ax.set_ylabel('Y [m]'); ax.set_zlabel('Z [m]') ax.set_xlabel('X [m]');
ax.set_ylabel('Y [m]');
ax.set_zlabel('Z [m]')
ax.legend() ax.legend()
return ax return ax
@ -1005,7 +1028,6 @@ class SeisArray(object):
print("Wrote %d sources to file: %s" % (nPoints, filename)) print("Wrote %d sources to file: %s" % (nPoints, filename))
return return
def saveSeisArray(self, filename='seisArray.pickle'): def saveSeisArray(self, filename='seisArray.pickle'):
import cPickle import cPickle
outfile = open(filename, 'wb') outfile = open(filename, 'wb')

View File

@ -6,17 +6,20 @@ import numpy as np
from obspy.core import read from obspy.core import read
from obspy import Stream from obspy import Stream
from obspy import Trace from obspy import Trace
from pylot.core.pick.CharFuns import HOScf from pylot.core.pick.charfuns import HOScf
from pylot.core.pick.CharFuns import AICcf from pylot.core.pick.charfuns import AICcf
from pylot.core.pick.utils import getSNR from pylot.core.pick.utils import getSNR
from pylot.core.pick.utils import earllatepicker from pylot.core.pick.utils import earllatepicker
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
plt.interactive('True') plt.interactive('True')
class SeismicShot(object): class SeismicShot(object):
''' '''
SuperClass for a seismic shot object. SuperClass for a seismic shot object.
''' '''
def __init__(self, obsfile): def __init__(self, obsfile):
''' '''
Initialize seismic shot object giving an inputfile. Initialize seismic shot object giving an inputfile.
@ -368,7 +371,8 @@ class SeismicShot(object):
# threshold = folm * max(hoscflist[leftb : rightb]) # combination of local maximum and threshold # threshold = folm * max(hoscflist[leftb : rightb]) # combination of local maximum and threshold
### TEST TEST ### TEST TEST
threshold = folm * (max(hoscflist[leftb : rightb]) - min(hoscflist[leftb : rightb])) + min(hoscflist[leftb : rightb]) # combination of local maximum and threshold threshold = folm * (max(hoscflist[leftb: rightb]) - min(hoscflist[leftb: rightb])) + min(
hoscflist[leftb: rightb]) # combination of local maximum and threshold
### TEST TEST ### TEST TEST
m = leftb m = leftb
@ -446,7 +450,8 @@ class SeismicShot(object):
return float(x), float(y), float(z) return float(x), float(y), float(z)
# return float(self.getSingleStream(traceID)[0].stats.seg2['SOURCE_LOCATION']) # return float(self.getSingleStream(traceID)[0].stats.seg2['SOURCE_LOCATION'])
def getTraceIDs4Dist(self, distance = 0, distancebin = (0, 0)): ########## nur fuer 2D benutzt, 'distance bins' ########## def getTraceIDs4Dist(self, distance=0,
distancebin=(0, 0)): ########## nur fuer 2D benutzt, 'distance bins' ##########
''' '''
Returns the traceID(s) for a certain distance between source and receiver. Returns the traceID(s) for a certain distance between source and receiver.
Used for 2D Tomography. TO BE IMPROVED. Used for 2D Tomography. TO BE IMPROVED.
@ -517,7 +522,6 @@ class SeismicShot(object):
else: else:
self.setManualPickFlag(traceID, 1) self.setManualPickFlag(traceID, 1)
def setPick(self, traceID, pick): ########## siehe Kommentar ########## def setPick(self, traceID, pick): ########## siehe Kommentar ##########
if not traceID in self.picks.keys(): if not traceID in self.picks.keys():
self.picks[traceID] = {} self.picks[traceID] = {}
@ -587,7 +591,6 @@ class SeismicShot(object):
return distancearray return distancearray
def plot2dttc(self, ax=None): ########## 2D ########## def plot2dttc(self, ax=None): ########## 2D ##########
''' '''
Function to plot the traveltime curve for automated picks of a shot. 2d only! ATM: X DIRECTION!! Function to plot the traveltime curve for automated picks of a shot. 2d only! ATM: X DIRECTION!!
@ -605,7 +608,8 @@ class SeismicShot(object):
# shotnumbers = [shotnumbers for (shotnumbers, shotnames) in sorted(zip(shotnumbers, shotnames))] # shotnumbers = [shotnumbers for (shotnumbers, shotnames) in sorted(zip(shotnumbers, shotnames))]
plotarray = sorted(zip(self.getDistArray4ttcPlot(), picks)) plotarray = sorted(zip(self.getDistArray4ttcPlot(), picks))
x = []; y = [] x = [];
y = []
for point in plotarray: for point in plotarray:
x.append(point[0]) x.append(point[0])
y.append(point[1]) y.append(point[1])
@ -632,7 +636,8 @@ class SeismicShot(object):
ax = fig.add_subplot(111) ax = fig.add_subplot(111)
plotarray = sorted(zip(self.getDistArray4ttcPlot(), manualpicktimesarray)) plotarray = sorted(zip(self.getDistArray4ttcPlot(), manualpicktimesarray))
x = []; y = [] x = [];
y = []
for point in plotarray: for point in plotarray:
x.append(point[0]) x.append(point[0])
y.append(point[1]) y.append(point[1])
@ -669,7 +674,8 @@ class SeismicShot(object):
ax.plot([0, tnoise], [noiselevel, noiselevel], 'm', linewidth=lw, label='noise level') ax.plot([0, tnoise], [noiselevel, noiselevel], 'm', linewidth=lw, label='noise level')
ax.plot([tnoise, pick], [noiselevel, noiselevel], 'g:', linewidth=lw, label='gap') ax.plot([tnoise, pick], [noiselevel, noiselevel], 'g:', linewidth=lw, label='gap')
ax.plot([tnoise + tgap, pick + tsignal], [noiselevel * snr, noiselevel * snr], 'b', linewidth = lw, label = 'signal level') ax.plot([tnoise + tgap, pick + tsignal], [noiselevel * snr, noiselevel * snr], 'b', linewidth=lw,
label='signal level')
ax.legend() ax.legend()
ax.text(0.05, 0.9, 'SNR: %s' % snr, transform=ax.transAxes) ax.text(0.05, 0.9, 'SNR: %s' % snr, transform=ax.transAxes)
@ -868,9 +874,12 @@ class SeismicShot(object):
from matplotlib import cm from matplotlib import cm
cmap = cm.jet cmap = cm.jet
x = []; xcut = [] x = [];
y = []; ycut = [] xcut = []
z = []; zcut = [] y = [];
ycut = []
z = [];
zcut = []
for traceID in self.picks.keys(): for traceID in self.picks.keys():
if self.getPickFlag(traceID) != 0: if self.getPickFlag(traceID) != 0:
@ -895,7 +904,8 @@ class SeismicShot(object):
ax = plt.axes() ax = plt.axes()
count = 0 count = 0
ax.imshow(zgrid, extent = [min(x), max(x), min(y), max(y)], vmin = tmin, vmax = tmax, cmap = cmap, origin = 'lower', alpha = 0.85) ax.imshow(zgrid, extent=[min(x), max(x), min(y), max(y)], vmin=tmin, vmax=tmax, cmap=cmap, origin='lower',
alpha=0.85)
ax.text(0.5, 0.95, 'shot: %s' % self.getShotnumber(), transform=ax.transAxes ax.text(0.5, 0.95, 'shot: %s' % self.getShotnumber(), transform=ax.transAxes
, horizontalalignment='center') , horizontalalignment='center')
sc = ax.scatter(x, y, c=z, s=30, label='picked shots', vmin=tmin, vmax=tmax, cmap=cmap, linewidths=1.5) sc = ax.scatter(x, y, c=z, s=30, label='picked shots', vmin=tmin, vmax=tmax, cmap=cmap, linewidths=1.5)
@ -928,5 +938,3 @@ class SeismicShot(object):
fontsize='x-small', color='r') fontsize='x-small', color='r')
plt.show() plt.show()

View File

@ -2,8 +2,10 @@
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import math import math
import numpy as np import numpy as np
plt.interactive(True) plt.interactive(True)
class regions(object): class regions(object):
''' '''
A class used for manual inspection and processing of all picks for the user. A class used for manual inspection and processing of all picks for the user.
@ -179,7 +181,8 @@ class regions(object):
self.drawLastPolyLine() self.drawLastPolyLine()
x = self._polyx x = self._polyx
y = self._polyy y = self._polyy
self._polyx = []; self._polyy = [] self._polyx = [];
self._polyy = []
key = self.getKey() key = self.getKey()
self.markPolygon(x, y, key=key) self.markPolygon(x, y, key=key)
@ -279,8 +282,10 @@ class regions(object):
angle = 0 angle = 0
epsilon = 1e-07 epsilon = 1e-07
for index in range(len(x)): for index in range(len(x)):
xval1 = x[index - 1]; yval1 = y[index - 1] xval1 = x[index - 1];
xval2 = x[index]; yval2 = y[index] yval1 = y[index - 1]
xval2 = x[index];
yval2 = y[index]
angle += getangle([xval1 - pickX, yval1 - pickY], [xval2 - pickX, yval2 - pickY]) angle += getangle([xval1 - pickX, yval1 - pickY], [xval2 - pickX, yval2 - pickY])
if 360 - epsilon <= angle <= 360 + epsilon: ### IMPROVE THAT?? if 360 - epsilon <= angle <= 360 + epsilon: ### IMPROVE THAT??
return True return True
@ -289,9 +294,12 @@ class regions(object):
self.printOutput('No polygon defined.') self.printOutput('No polygon defined.')
return return
shots_found = {}; numtraces = 0 shots_found = {};
x0 = min(x); x1 = max(x) numtraces = 0
y0 = min(y); y1 = max(y) x0 = min(x);
x1 = max(x)
y0 = min(y);
y1 = max(y)
shots, numtracesrect = self.findTracesInShotDict((x0, x1), (y0, y1), highlight=False) shots, numtracesrect = self.findTracesInShotDict((x0, x1), (y0, y1), highlight=False)
for shotnumber in shots.keys(): for shotnumber in shots.keys():
@ -315,9 +323,12 @@ class regions(object):
''' '''
Returns traces corresponding to a certain area in the plot with all picks over the distances. Returns traces corresponding to a certain area in the plot with all picks over the distances.
''' '''
shots_found = {}; numtraces = 0 shots_found = {};
if picks == 'normal': pickflag = 0 numtraces = 0
elif picks == 'includeCutOut': pickflag = None if picks == 'normal':
pickflag = 0
elif picks == 'includeCutOut':
pickflag = None
for line in self._allpicks: for line in self._allpicks:
dist, pick, shotnumber, traceID, flag = line dist, pick, shotnumber, traceID, flag = line
@ -344,9 +355,11 @@ class regions(object):
if shot.getPickFlag(traceID) is 0: if shot.getPickFlag(traceID) is 0:
return return
self.ax.scatter(shot.getDistance(traceID), shot.getPick(traceID), s = 50, marker = 'o', facecolors = 'none', edgecolors = 'm', alpha = 1) self.ax.scatter(shot.getDistance(traceID), shot.getPick(traceID), s=50, marker='o', facecolors='none',
edgecolors='m', alpha=1)
if annotations == True: if annotations == True:
self.ax.annotate(s='s%s|t%s' % (shot.getShotnumber(), traceID), xy=(shot.getDistance(traceID), shot.getPick(traceID)), fontsize='xx-small') self.ax.annotate(s='s%s|t%s' % (shot.getShotnumber(), traceID),
xy=(shot.getDistance(traceID), shot.getPick(traceID)), fontsize='xx-small')
def highlightAllActiveRegions(self): def highlightAllActiveRegions(self):
''' '''
@ -382,7 +395,8 @@ class regions(object):
for traceID in self.shots_found[key]['shots'][shotnumber]: for traceID in self.shots_found[key]['shots'][shotnumber]:
count += 1 count += 1
if count > maxfigures: if count > maxfigures:
print 'Maximum number of figures (%s) reached. %sth figure was not opened.' %(maxfigures, count) print 'Maximum number of figures (%s) reached. %sth figure was not opened.' % (
maxfigures, count)
break break
shot.plot_traces(traceID) shot.plot_traces(traceID)
else: else:
@ -420,7 +434,6 @@ class regions(object):
self.markPolygon(self.shots_found[key]['xvalues'], self.markPolygon(self.shots_found[key]['xvalues'],
self.shots_found[key]['yvalues'], key=key) self.shots_found[key]['yvalues'], key=key)
def markRectangle(self, (x0, x1), (y0, y1), key=None, color='grey', alpha=0.1, linewidth=1): def markRectangle(self, (x0, x1), (y0, y1), key=None, color='grey', alpha=0.1, linewidth=1):
''' '''
Mark a rectangular region on the axes. Mark a rectangular region on the axes.

View File

@ -1,6 +1,13 @@
import numpy as np from __future__ import print_function
def readParameters(parfile, parameter): def readParameters(parfile, parameter):
"""
:param parfile:
:param parameter:
:return:
"""
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
parameterConfig = ConfigParser() parameterConfig = ConfigParser()
parameterConfig.read('parfile') parameterConfig.read('parfile')
@ -9,14 +16,29 @@ def readParameters(parfile, parameter):
return value return value
def setArtificialPick(shot_dict, traceID, pick): def setArtificialPick(shot_dict, traceID, pick):
"""
:param shot_dict:
:param traceID:
:param pick:
:return:
"""
for shot in shot_dict.values(): for shot in shot_dict.values():
shot.setPick(traceID, pick) shot.setPick(traceID, pick)
shot.setPickwindow(traceID, shot.getCut()) shot.setPickwindow(traceID, shot.getCut())
def fitSNR4dist(shot_dict, shiftdist=30, shiftSNR=100): def fitSNR4dist(shot_dict, shiftdist=30, shiftSNR=100):
"""
:param shot_dict:
:param shiftdist:
:param shiftSNR:
:return:
"""
import numpy as np import numpy as np
import matplotlib.pyplot as plt
dists = [] dists = []
picks = [] picks = []
snrs = [] snrs = []
@ -41,6 +63,14 @@ def fitSNR4dist(shot_dict, shiftdist = 30, shiftSNR = 100):
def plotFittedSNR(dists, snrthresholds, snrs, snrBestFit): def plotFittedSNR(dists, snrthresholds, snrs, snrBestFit):
"""
:param dists:
:param snrthresholds:
:param snrs:
:param snrBestFit:
:return:
"""
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
plt.interactive(True) plt.interactive(True)
fig = plt.figure() fig = plt.figure()
@ -54,7 +84,22 @@ def plotFittedSNR(dists, snrthresholds, snrs, snrBestFit):
plt.ylabel('SNR') plt.ylabel('SNR')
plt.legend() plt.legend()
def setDynamicFittedSNR(shot_dict, shiftdist=30, shiftSNR=100, p1=0.004, p2=-0.0007): def setDynamicFittedSNR(shot_dict, shiftdist=30, shiftSNR=100, p1=0.004, p2=-0.0007):
"""
:param shot_dict:
:type shot_dict: dict
:param shiftdist:
:type shiftdist: int
:param shiftSNR:
:type shiftSNR: int
:param p1:
:type p1: float
:param p2:
:type p2: float
:return:
"""
import numpy as np import numpy as np
minSNR = 2.5 minSNR = 2.5
# fit_fn = fitSNR4dist(shot_dict) # fit_fn = fitSNR4dist(shot_dict)
@ -69,14 +114,21 @@ def setDynamicFittedSNR(shot_dict, shiftdist = 30, shiftSNR = 100, p1 = 0.004, p
shot.setSNRthreshold(traceID, minSNR) shot.setSNRthreshold(traceID, minSNR)
else: else:
shot.setSNRthreshold(traceID, snrthreshold) shot.setSNRthreshold(traceID, snrthreshold)
print "setDynamicFittedSNR: Finished setting of fitted SNR-threshold" print("setDynamicFittedSNR: Finished setting of fitted SNR-threshold")
def setConstantSNR(shot_dict, snrthreshold=2.5): def setConstantSNR(shot_dict, snrthreshold=2.5):
import numpy as np """
:param shot_dict:
:param snrthreshold:
:return:
"""
for shot in shot_dict.values(): for shot in shot_dict.values():
for traceID in shot.getTraceIDlist(): for traceID in shot.getTraceIDlist():
shot.setSNRthreshold(traceID, snrthreshold) shot.setSNRthreshold(traceID, snrthreshold)
print "setConstantSNR: Finished setting of SNR threshold to a constant value of %s"%snrthreshold print("setConstantSNR: Finished setting of SNR threshold to a constant value of %s" % snrthreshold)
def findTracesInRanges(shot_dict, distancebin, pickbin): def findTracesInRanges(shot_dict, distancebin, pickbin):
''' '''
@ -103,11 +155,17 @@ def findTracesInRanges(shot_dict, distancebin, pickbin):
return shots_found return shots_found
def cleanUp(survey):
def cleanUp(survey):
"""
:param survey:
:return:
"""
for shot in survey.data.values(): for shot in survey.data.values():
shot.traces4plot = {} shot.traces4plot = {}
# def plotScatterStats(survey, key, ax = None): # def plotScatterStats(survey, key, ax = None):
# import matplotlib.pyplot as plt # import matplotlib.pyplot as plt
# x = []; y = []; value = [] # x = []; y = []; value = []
@ -131,14 +189,19 @@ def cleanUp(survey):
# cbar.set_label(key) # cbar.set_label(key)
def plotScatterStats4Shots(survey, key): def plotScatterStats4Shots(survey, key):
''' """
Statistics, scatter plot. Statistics, scatter plot.
key can be 'mean SNR', 'median SNR', 'mean SPE', 'median SPE', or 'picked traces' key can be 'mean SNR', 'median SNR', 'mean SPE', 'median SPE', or 'picked traces'
''' :param survey:
:param key:
:return:
"""
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
statsShot = {} statsShot = {}
x = []; y = []; value = [] x = []
y = []
value = []
for shot in survey.data.values(): for shot in survey.data.values():
for traceID in shot.getTraceIDlist(): for traceID in shot.getTraceIDlist():
if not shot in statsShot.keys(): if not shot in statsShot.keys():
@ -182,15 +245,21 @@ def plotScatterStats4Shots(survey, key):
ax.annotate(' %s' % shot.getShotnumber(), xy=(shot.getSrcLoc()[0], shot.getSrcLoc()[1]), ax.annotate(' %s' % shot.getShotnumber(), xy=(shot.getSrcLoc()[0], shot.getSrcLoc()[1]),
fontsize='x-small', color='k') fontsize='x-small', color='k')
def plotScatterStats4Receivers(survey, key): def plotScatterStats4Receivers(survey, key):
''' """
Statistics, scatter plot. Statistics, scatter plot.
key can be 'mean SNR', 'median SNR', 'mean SPE', 'median SPE', or 'picked traces' key can be 'mean SNR', 'median SNR', 'mean SPE', 'median SPE', or 'picked traces'
''' :param survey:
:param key:
:return:
"""
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
statsRec = {} statsRec = {}
x = []; y = []; value = [] x = []
y = []
value = []
for shot in survey.data.values(): for shot in survey.data.values():
for traceID in shot.getTraceIDlist(): for traceID in shot.getTraceIDlist():
if not traceID in statsRec.keys(): if not traceID in statsRec.keys():
@ -205,7 +274,6 @@ def plotScatterStats4Receivers(survey, key):
statsRec[traceID]['picked traces'] += 1 statsRec[traceID]['picked traces'] += 1
statsRec[traceID]['SPE'].append(shot.getSymmetricPickError(traceID)) statsRec[traceID]['SPE'].append(shot.getSymmetricPickError(traceID))
for traceID in statsRec.keys(): for traceID in statsRec.keys():
statsRec[traceID]['mean SNR'] = np.mean(statsRec[traceID]['SNR']) statsRec[traceID]['mean SNR'] = np.mean(statsRec[traceID]['SNR'])
statsRec[traceID]['median SNR'] = np.median(statsRec[traceID]['SNR']) statsRec[traceID]['median SNR'] = np.median(statsRec[traceID]['SNR'])

View File

@ -5,9 +5,7 @@ from obspy.core import read
from obspy.signal.trigger import coincidenceTrigger from obspy.signal.trigger import coincidenceTrigger
class CoincidenceTimes(object): class CoincidenceTimes(object):
def __init__(self, st, comp='Z', coinum=4, sta=1., lta=10., on=5., off=1.): def __init__(self, st, comp='Z', coinum=4, sta=1., lta=10., on=5., off=1.):
_type = 'recstalta' _type = 'recstalta'
self.coinclist = self.createCoincTriggerlist(data=st, trigcomp=comp, self.coinclist = self.createCoincTriggerlist(data=st, trigcomp=comp,

View File

@ -6,11 +6,15 @@ import numpy as np
def crosscorrsingle(wf1, wf2, taumax): def crosscorrsingle(wf1, wf2, taumax):
''' '''
Calculates the crosscorrelation between two waveforms with a defined maximum timedifference.
:param Wx: :param wf1: first waveformdata
:param Wy: :type wf1: list
:param taumax: :param wf2: second waveformdata
:return: :type wf2: list
:param taumax: maximum time difference between waveforms
:type taumax: positive integer
:return: returns the crosscorrelation funktion 'c' and the lagvector 'l'
:rtype: c and l are lists
''' '''
N = len(wf1) N = len(wf1)
c = np.zeros(2 * taumax - 1) c = np.zeros(2 * taumax - 1)
@ -83,10 +87,13 @@ def wfscrosscorr(weights, wfs, taumax):
SWB 26.01.2010 as arranged with Thomas Meier and Monika Bischoff SWB 26.01.2010 as arranged with Thomas Meier and Monika Bischoff
:param weights: :param weights: weighting factors for the single components
:param wfs: :type weights: tuple
:param taumax: :param wfs: tuple of `~numpy.array` object containing waveform data
:return: :type wfs: tuple
:param taumax: maximum time difference
:type taumax: positive integer
:return: returns cross correlation function normalized by the waveform energy
''' '''
ccnorm = 0. ccnorm = 0.

View File

@ -15,6 +15,7 @@ from scipy.optimize import curve_fit
from scipy import integrate, signal from scipy import integrate, signal
from pylot.core.read.data import Data from pylot.core.read.data import Data
class Magnitude(object): class Magnitude(object):
''' '''
Superclass for calculating Wood-Anderson peak-to-peak Superclass for calculating Wood-Anderson peak-to-peak
@ -72,7 +73,6 @@ class Magnitude(object):
self.calcsourcespec() self.calcsourcespec()
self.run_calcMoMw() self.run_calcMoMw()
def getwfstream(self): def getwfstream(self):
return self.wfstream return self.wfstream
@ -154,6 +154,7 @@ class Magnitude(object):
def run_calcMoMw(self): def run_calcMoMw(self):
self.pickdic = None self.pickdic = None
class WApp(Magnitude): class WApp(Magnitude):
''' '''
Method to derive peak-to-peak amplitude as seen on a Wood-Anderson- Method to derive peak-to-peak amplitude as seen on a Wood-Anderson-
@ -261,6 +262,7 @@ class M0Mw(Magnitude):
picks[key]['P']['Mw'] = Mw picks[key]['P']['Mw'] = Mw
self.picdic = picks self.picdic = picks
def calcMoMw(wfstream, w0, rho, vp, delta, inv): def calcMoMw(wfstream, w0, rho, vp, delta, inv):
''' '''
Subfunction of run_calcMoMw to calculate individual Subfunction of run_calcMoMw to calculate individual
@ -302,7 +304,6 @@ def calcMoMw(wfstream, w0, rho, vp, delta, inv):
return Mo, Mw return Mo, Mw
def calcsourcespec(wfstream, onset, inventory, vp, delta, azimuth, incidence, Qp, iplot): def calcsourcespec(wfstream, onset, inventory, vp, delta, azimuth, incidence, Qp, iplot):
''' '''
Subfunction to calculate the source spectrum and to derive from that the plateau Subfunction to calculate the source spectrum and to derive from that the plateau
@ -639,10 +640,3 @@ def fitSourceModel(f, S, fc0, iplot):
plt.close() plt.close()
return w0, fc return w0, fc

View File

@ -1,25 +1,31 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from obspy.signal.trigger import recSTALTA, triggerOnset from obspy.signal.trigger import recursive_sta_lta, trigger_onset
def createSingleTriggerlist(st, station='ZV01', trigcomp='Z', stalta=(1, 10), def createSingleTriggerlist(st, station='ZV01', trigcomp='Z', stalta=(1, 10),
trigonoff=(6, 1)): trigonoff=(6, 1)):
''' '''
uses a single-station trigger to create a triggerlist for this station uses a single-station trigger to create a triggerlist for this station
:param st: :param st: obspy stream
:param station: :type st:
:param trigcomp: :param station: station name to get triggers for (optional, default = ZV01)
:param stalta: :type station: str
:param trigonoff: :param trigcomp: (optional, default = Z)
:return: :type trigcomp: str
:param stalta: (optional, default = (1,10))
:type stalta: tuple
:param trigonoff: (optional, default = (6,1))
:type trigonoff: tuple
:return: list of triggtimes
:rtype: list
''' '''
tr = st.copy().select(component=trigcomp, station=station)[0] tr = st.copy().select(component=trigcomp, station=station)[0]
df = tr.stats.sampling_rate df = tr.stats.sampling_rate
cft = recSTALTA(tr.data, int(stalta[0] * df), int(stalta[1] * df)) cft = recursive_sta_lta(tr.data, int(stalta[0] * df), int(stalta[1] * df))
triggers = triggerOnset(cft, trigonoff[0], trigonoff[1]) triggers = trigger_onset(cft, trigonoff[0], trigonoff[1])
trigg = [] trigg = []
for time in triggers: for time in triggers:
trigg.append(tr.stats.starttime + time[0] / df) trigg.append(tr.stats.starttime + time[0] / df)
@ -32,7 +38,7 @@ def createSubCoincTriggerlist(trig, station='ZV01'):
coincidence trigger and are seen at the demanded station coincidence trigger and are seen at the demanded station
:param trig: list containing triggers from coincidence trigger :param trig: list containing triggers from coincidence trigger
:type trig: list :type trig: list
:param station: station name to get triggers for :param station: station name to get triggers for (optional, default = ZV01)
:type station: str :type station: str
:return: list of triggertimes :return: list of triggertimes
:rtype: list :rtype: list

View File

@ -3,13 +3,13 @@
import subprocess import subprocess
import os import os
from obspy.core.event import readEvents
from pylot.core.pick.utils import writephases from pylot.core.pick.utils import writephases
from pylot.core.util.utils import getPatternLine from pylot.core.util.utils import getPatternLine
from pylot.core.util.version import get_git_version as _getVersionString from pylot.core.util.version import get_git_version as _getVersionString
__version__ = _getVersionString() __version__ = _getVersionString()
def picksExport(picks, locrt, phasefile): def picksExport(picks, locrt, phasefile):
''' '''
Take <picks> dictionary and exports picking data to a NLLOC-obs Take <picks> dictionary and exports picking data to a NLLOC-obs
@ -27,6 +27,7 @@ def picksExport(picks, locrt, phasefile):
# write phases to NLLoc-phase file # write phases to NLLoc-phase file
writephases(picks, locrt, phasefile) writephases(picks, locrt, phasefile)
def modifyInputFile(ctrfn, root, nllocoutn, phasefn, tttn): def modifyInputFile(ctrfn, root, nllocoutn, phasefn, tttn):
''' '''
:param ctrfn: name of NLLoc-control file :param ctrfn: name of NLLoc-control file
@ -64,6 +65,7 @@ def modifyInputFile(ctrfn, root, nllocoutn, phasefn, tttn):
nllfile.write(filedata) nllfile.write(filedata)
nllfile.close() nllfile.close()
def locate(call, fnin): def locate(call, fnin):
''' '''
Takes paths to NLLoc executable <call> and input parameter file <fnin> Takes paths to NLLoc executable <call> and input parameter file <fnin>
@ -79,8 +81,10 @@ def locate(call, fnin):
# locate the event # locate the event
subprocess.call([call, fnin]) subprocess.call([call, fnin])
def readLocation(fn): def readLocation(fn):
pass pass
if __name__ == '__main__': if __name__ == '__main__':
pass pass

View File

@ -11,15 +11,17 @@ function conglomerate utils.
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
from scipy import integrate from pylot.core.read.inputs import AutoPickParameter
from pylot.core.pick.Picker import AICPicker, PragPicker from pylot.core.pick.picker import AICPicker, PragPicker
from pylot.core.pick.CharFuns import HOScf, AICcf, ARZcf, ARHcf, AR3Ccf from pylot.core.pick.charfuns import CharacteristicFunction
from pylot.core.pick.charfuns import HOScf, AICcf, ARZcf, ARHcf, AR3Ccf
from pylot.core.pick.utils import checksignallength, checkZ4S, earllatepicker, \ from pylot.core.pick.utils import checksignallength, checkZ4S, earllatepicker, \
getSNR, fmpicker, checkPonsets, wadaticheck getSNR, fmpicker, checkPonsets, wadaticheck
from pylot.core.util.utils import getPatternLine from pylot.core.util.utils import getPatternLine
from pylot.core.read.data import Data from pylot.core.read.data import Data
from pylot.core.analysis.magnitude import WApp from pylot.core.analysis.magnitude import WApp
def autopickevent(data, param): def autopickevent(data, param):
stations = [] stations = []
all_onsets = {} all_onsets = {}
@ -46,14 +48,18 @@ def autopickevent(data, param):
# check S-P times (Wadati) # check S-P times (Wadati)
return wadaticheck(jk_checked_onsets, wdttolerance, iplot) return wadaticheck(jk_checked_onsets, wdttolerance, iplot)
def autopickstation(wfstream, pickparam, verbose=False): def autopickstation(wfstream, pickparam, verbose=False):
""" """
:param: wfstream :param wfstream: `~obspy.core.stream.Stream` containing waveform
:type: `~obspy.core.stream.Stream` :type wfstream: obspy.core.stream.Stream
:param: pickparam :param pickparam: container of picking parameters from input file,
:type: container of picking parameters from input file,
usually autoPyLoT.in usually autoPyLoT.in
:type pickparam: AutoPickParameter
:param verbose:
:type verbose: bool
""" """
# declaring pickparam variables (only for convenience) # declaring pickparam variables (only for convenience)
@ -138,6 +144,7 @@ def autopickstation(wfstream, pickparam, verbose=False):
Sflag = 0 Sflag = 0
Pmarker = [] Pmarker = []
Ao = None # Wood-Anderson peak-to-peak amplitude Ao = None # Wood-Anderson peak-to-peak amplitude
picker = 'autoPyLoT' # name of the picking programm
# split components # split components
zdat = wfstream.select(component="Z") zdat = wfstream.select(component="Z")
@ -175,6 +182,7 @@ def autopickstation(wfstream, pickparam, verbose=False):
pstart = 0 pstart = 0
pstop = len(zdat[0].data) * zdat[0].stats.delta pstop = len(zdat[0].data) * zdat[0].stats.delta
cuttimes = [pstart, pstop] cuttimes = [pstart, pstop]
cf1 = None
if algoP == 'HOS': if algoP == 'HOS':
# calculate HOS-CF using subclass HOScf of class # calculate HOS-CF using subclass HOScf of class
# CharacteristicFunction # CharacteristicFunction
@ -188,6 +196,10 @@ def autopickstation(wfstream, pickparam, verbose=False):
# calculate AIC-HOS-CF using subclass AICcf of class # calculate AIC-HOS-CF using subclass AICcf of class
# CharacteristicFunction # CharacteristicFunction
# class needs stream object => build it # class needs stream object => build it
assert isinstance(cf1, CharacteristicFunction), 'cf2 is not set ' \
'correctly: maybe the algorithm name ({algoP}) is ' \
'corrupted'.format(
algoP=algoP)
tr_aic = tr_filt.copy() tr_aic = tr_filt.copy()
tr_aic.data = cf1.getCF() tr_aic.data = cf1.getCF()
z_copy[0].data = tr_aic.data z_copy[0].data = tr_aic.data
@ -249,8 +261,7 @@ def autopickstation(wfstream, pickparam, verbose=False):
############################################################## ##############################################################
# go on with processing if AIC onset passes quality control # go on with processing if AIC onset passes quality control
if (aicpick.getSlope() >= minAICPslope and if (aicpick.getSlope() >= minAICPslope and
aicpick.getSNR() >= minAICPSNR and aicpick.getSNR() >= minAICPSNR and Pflag == 1):
Pflag == 1):
aicPflag = 1 aicPflag = 1
msg = 'AIC P-pick passes quality control: Slope: {0} counts/s, ' \ msg = 'AIC P-pick passes quality control: Slope: {0} counts/s, ' \
'SNR: {1}\nGo on with refined picking ...\n' \ 'SNR: {1}\nGo on with refined picking ...\n' \
@ -270,6 +281,7 @@ def autopickstation(wfstream, pickparam, verbose=False):
cuttimes2 = [round(max([aicpick.getpick() - Precalcwin, 0])), cuttimes2 = [round(max([aicpick.getpick() - Precalcwin, 0])),
round(min([len(zdat[0].data) * zdat[0].stats.delta, round(min([len(zdat[0].data) * zdat[0].stats.delta,
aicpick.getpick() + Precalcwin]))] aicpick.getpick() + Precalcwin]))]
cf2 = None
if algoP == 'HOS': if algoP == 'HOS':
# calculate HOS-CF using subclass HOScf of class # calculate HOS-CF using subclass HOScf of class
# CharacteristicFunction # CharacteristicFunction
@ -282,14 +294,18 @@ def autopickstation(wfstream, pickparam, verbose=False):
addnoise) # instance of ARZcf addnoise) # instance of ARZcf
############################################################## ##############################################################
# get refined onset time from CF2 using class Picker # get refined onset time from CF2 using class Picker
assert isinstance(cf2, CharacteristicFunction), 'cf2 is not set ' \
'correctly: maybe the algorithm name ({algoP}) is ' \
'corrupted'.format(
algoP=algoP)
refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot, ausP, tsmoothP, refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot, ausP, tsmoothP,
aicpick.getpick()) aicpick.getpick())
mpickP = refPpick.getpick() mpickP = refPpick.getpick()
############################################################# #############################################################
if mpickP is not None: if mpickP is not None:
# quality assessment # quality assessment
# get earliest and latest possible pick and symmetrized uncertainty # get earliest/latest possible pick and symmetrized uncertainty
[lpickP, epickP, Perror] = earllatepicker(z_copy, nfacP, tsnrz, [epickP, lpickP, Perror] = earllatepicker(z_copy, nfacP, tsnrz,
mpickP, iplot) mpickP, iplot)
# get SNR # get SNR
@ -473,13 +489,14 @@ def autopickstation(wfstream, pickparam, verbose=False):
############################################################# #############################################################
if mpickS is not None: if mpickS is not None:
# quality assessment # quality assessment
# get earliest and latest possible pick and symmetrized uncertainty # get earliest/latest possible pick and symmetrized uncertainty
h_copy[0].data = trH1_filt.data h_copy[0].data = trH1_filt.data
[lpickS1, epickS1, Serror1] = earllatepicker(h_copy, nfacS, [epickS1, lpickS1, Serror1] = earllatepicker(h_copy, nfacS,
tsnrh, tsnrh,
mpickS, iplot) mpickS, iplot)
h_copy[0].data = trH2_filt.data h_copy[0].data = trH2_filt.data
[lpickS2, epickS2, Serror2] = earllatepicker(h_copy, nfacS, [epickS2, lpickS2, Serror2] = earllatepicker(h_copy, nfacS,
tsnrh, tsnrh,
mpickS, iplot) mpickS, iplot)
if epickS1 is not None and epickS2 is not None: if epickS1 is not None and epickS2 is not None:
@ -488,28 +505,30 @@ def autopickstation(wfstream, pickparam, verbose=False):
epick = [epickS1, epickS2] epick = [epickS1, epickS2]
lpick = [lpickS1, lpickS2] lpick = [lpickS1, lpickS2]
pickerr = [Serror1, Serror2] pickerr = [Serror1, Serror2]
if epickS1 == None and epickS2 is not None: if epickS1 is None and epickS2 is not None:
ipick = 1 ipick = 1
elif epickS1 is not None and epickS2 == None: elif epickS1 is not None and epickS2 is None:
ipick = 0 ipick = 0
elif epickS1 is not None and epickS2 is not None: elif epickS1 is not None and epickS2 is not None:
ipick = np.argmin([epickS1, epickS2]) ipick = np.argmin([epickS1, epickS2])
elif algoS == 'AR3': elif algoS == 'AR3':
[lpickS3, epickS3, Serror3] = earllatepicker(h_copy, nfacS, [epickS3, lpickS3, Serror3] = earllatepicker(h_copy,
nfacS,
tsnrh, tsnrh,
mpickS, iplot) mpickS,
iplot)
# get earliest pick of all three picks # get earliest pick of all three picks
epick = [epickS1, epickS2, epickS3] epick = [epickS1, epickS2, epickS3]
lpick = [lpickS1, lpickS2, lpickS3] lpick = [lpickS1, lpickS2, lpickS3]
pickerr = [Serror1, Serror2, Serror3] pickerr = [Serror1, Serror2, Serror3]
if epickS1 == None and epickS2 is not None \ if epickS1 is None and epickS2 is not None \
and epickS3 is not None: and epickS3 is not None:
ipick = np.argmin([epickS2, epickS3]) ipick = np.argmin([epickS2, epickS3])
elif epickS1 is not None and epickS2 == None \ elif epickS1 is not None and epickS2 is None \
and epickS3 is not None: and epickS3 is not None:
ipick = np.argmin([epickS2, epickS3]) ipick = np.argmin([epickS2, epickS3])
elif epickS1 is not None and epickS2 is not None \ elif epickS1 is not None and epickS2 is not None \
and epickS3 == None: and epickS3 is None:
ipick = np.argmin([epickS1, epickS2]) ipick = np.argmin([epickS1, epickS2])
elif epickS1 is not None and epickS2 is not None \ elif epickS1 is not None and epickS2 is not None \
and epickS3 is not None: and epickS3 is not None:
@ -538,7 +557,7 @@ def autopickstation(wfstream, pickparam, verbose=False):
'SNR[dB]: {2}\n' 'SNR[dB]: {2}\n'
'################################################' '################################################'
''.format(Sweight, SNRS, SNRSdB)) ''.format(Sweight, SNRS, SNRSdB))
################################################################## ################################################################
# get Wood-Anderson peak-to-peak amplitude # get Wood-Anderson peak-to-peak amplitude
# initialize Data object # initialize Data object
data = Data() data = Data()
@ -555,7 +574,7 @@ def autopickstation(wfstream, pickparam, verbose=False):
else: else:
# use larger window for getting peak-to-peak amplitude # use larger window for getting peak-to-peak amplitude
# as the S pick is quite unsure # as the S pick is quite unsure
wapp = WApp(cordat, mpickP, mpickP + sstop + \ wapp = WApp(cordat, mpickP, mpickP + sstop +
(0.5 * (mpickP + sstop)), iplot) (0.5 * (mpickP + sstop)), iplot)
Ao = wapp.getwapp() Ao = wapp.getwapp()
@ -585,7 +604,8 @@ def autopickstation(wfstream, pickparam, verbose=False):
# calculate WA-peak-to-peak amplitude # calculate WA-peak-to-peak amplitude
# using subclass WApp of superclass Magnitude # using subclass WApp of superclass Magnitude
wapp = WApp(cordat, mpickP, mpickP + sstop + (0.5 * (mpickP wapp = WApp(cordat, mpickP, mpickP + sstop + (0.5 * (mpickP
+ sstop)), iplot) + sstop)),
iplot)
Ao = wapp.getwapp() Ao = wapp.getwapp()
else: else:
@ -754,46 +774,46 @@ def autopickstation(wfstream, pickparam, verbose=False):
plt.close() plt.close()
########################################################################## ##########################################################################
# calculate "real" onset times # calculate "real" onset times
if mpickP is not None and epickP is not None and mpickP is not None: if lpickP is not None and lpickP == mpickP:
lpickP += timeerrorsP[0]
if epickP is not None and epickP == mpickP:
epickP -= timeerrorsP[0]
if mpickP is not None and epickP is not None and lpickP is not None:
lpickP = zdat[0].stats.starttime + lpickP lpickP = zdat[0].stats.starttime + lpickP
epickP = zdat[0].stats.starttime + epickP epickP = zdat[0].stats.starttime + epickP
mpickP = zdat[0].stats.starttime + mpickP mpickP = zdat[0].stats.starttime + mpickP
else: else:
# dummy values (start of seismic trace) in order to derive # dummy values (start of seismic trace) in order to derive
# theoretical onset times for iteratve picking # theoretical onset times for iteratve picking
lpickP = zdat[0].stats.starttime lpickP = zdat[0].stats.starttime + timeerrorsP[3]
epickP = zdat[0].stats.starttime epickP = zdat[0].stats.starttime - timeerrorsP[3]
mpickP = zdat[0].stats.starttime mpickP = zdat[0].stats.starttime
if mpickS is not None and epickS is not None and mpickS is not None: if lpickS is not None and lpickS == mpickS:
lpickS += timeerrorsS[0]
if epickS is not None and epickS == mpickS:
epickS -= timeerrorsS[0]
if mpickS is not None and epickS is not None and lpickS is not None:
lpickS = edat[0].stats.starttime + lpickS lpickS = edat[0].stats.starttime + lpickS
epickS = edat[0].stats.starttime + epickS epickS = edat[0].stats.starttime + epickS
mpickS = edat[0].stats.starttime + mpickS mpickS = edat[0].stats.starttime + mpickS
else: else:
# dummy values (start of seismic trace) in order to derive # dummy values (start of seismic trace) in order to derive
# theoretical onset times for iteratve picking # theoretical onset times for iteratve picking
lpickS = edat[0].stats.starttime lpickS = edat[0].stats.starttime + timeerrorsS[3]
epickS = edat[0].stats.starttime epickS = edat[0].stats.starttime - timeerrorsS[3]
mpickS = edat[0].stats.starttime mpickS = edat[0].stats.starttime
# create dictionary # create dictionary
# for P phase # for P phase
phase = 'P' ppick = dict(lpp=lpickP, epp=epickP, mpp=mpickP, spe=Perror, snr=SNRP,
phasepick = {'lpp': lpickP, 'epp': epickP, 'mpp': mpickP, 'spe': Perror, snrdb=SNRPdB, weight=Pweight, fm=FM, w0=None, fc=None, Mo=None,
'snr': SNRP, 'snrdb': SNRPdB, 'weight': Pweight, 'fm': FM, Mw=None, picker=picker, marked=Pmarker)
'w0': None, 'fc': None, 'Mo': None, 'Mw': None}
picks = {phase: phasepick}
# add P marker
picks[phase]['marked'] = Pmarker
# add S phase # add S phase
phase = 'S' spick = dict(lpp=lpickS, epp=epickS, mpp=mpickS, spe=Serror, snr=SNRS,
phasepick = {'lpp': lpickS, 'epp': epickS, 'mpp': mpickS, 'spe': Serror, snrdb=SNRSdB, weight=Sweight, fm=None, picker=picker, Ao=Ao)
'snr': SNRS, 'snrdb': SNRSdB, 'weight': Sweight, 'fm': None} # merge picks into returning dictionary
picks[phase] = phasepick picks = dict(P=ppick, S=spick)
# add Wood-Anderson amplitude
picks[phase]['Ao'] = Ao
return picks return picks
@ -844,22 +864,31 @@ def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter):
Precalcwin_old = pickparameter.getParam('Precalcwin') Precalcwin_old = pickparameter.getParam('Precalcwin')
noisefactor_old = pickparameter.getParam('noisefactor') noisefactor_old = pickparameter.getParam('noisefactor')
zfac_old = pickparameter.getParam('zfac') zfac_old = pickparameter.getParam('zfac')
pickparameter.setParam(pstart=max([0, badpicks[i][1] - wf2pick[0].stats.starttime \ pickparameter.setParam(
pstart=max([0, badpicks[i][1] - wf2pick[0].stats.starttime \
- pickparameter.getParam('tlta')])) - pickparameter.getParam('tlta')]))
pickparameter.setParam(pstop=pickparameter.getParam('pstart') + \ pickparameter.setParam(pstop=pickparameter.getParam('pstart') + \
(3 * pickparameter.getParam('tlta'))) (3 * pickparameter.getParam('tlta')))
pickparameter.setParam(sstop=pickparameter.getParam('sstop') / 2) pickparameter.setParam(sstop=pickparameter.getParam('sstop') / 2)
pickparameter.setParam(pickwinP=pickparameter.getParam('pickwinP') / 2) pickparameter.setParam(pickwinP=pickparameter.getParam('pickwinP') / 2)
pickparameter.setParam(Precalcwin=pickparameter.getParam('Precalcwin') / 2) pickparameter.setParam(
Precalcwin=pickparameter.getParam('Precalcwin') / 2)
pickparameter.setParam(noisefactor=1.0) pickparameter.setParam(noisefactor=1.0)
pickparameter.setParam(zfac=1.0) pickparameter.setParam(zfac=1.0)
print("iteratepicker: The following picking parameters have been modified for iterative picking:") print(
print("pstart: %fs => %fs" % (pstart_old, pickparameter.getParam('pstart'))) "iteratepicker: The following picking parameters have been modified for iterative picking:")
print("pstop: %fs => %fs" % (pstop_old, pickparameter.getParam('pstop'))) print(
print("sstop: %fs => %fs" % (sstop_old, pickparameter.getParam('sstop'))) "pstart: %fs => %fs" % (pstart_old, pickparameter.getParam('pstart')))
print("pickwinP: %fs => %fs" % (pickwinP_old, pickparameter.getParam('pickwinP'))) print(
print("Precalcwin: %fs => %fs" % (Precalcwin_old, pickparameter.getParam('Precalcwin'))) "pstop: %fs => %fs" % (pstop_old, pickparameter.getParam('pstop')))
print("noisefactor: %f => %f" % (noisefactor_old, pickparameter.getParam('noisefactor'))) print(
"sstop: %fs => %fs" % (sstop_old, pickparameter.getParam('sstop')))
print("pickwinP: %fs => %fs" % (
pickwinP_old, pickparameter.getParam('pickwinP')))
print("Precalcwin: %fs => %fs" % (
Precalcwin_old, pickparameter.getParam('Precalcwin')))
print("noisefactor: %f => %f" % (
noisefactor_old, pickparameter.getParam('noisefactor')))
print("zfac: %f => %f" % (zfac_old, pickparameter.getParam('zfac'))) print("zfac: %f => %f" % (zfac_old, pickparameter.getParam('zfac')))
# repick station # repick station
@ -879,10 +908,3 @@ def iteratepicker(wf, NLLocfile, picks, badpicks, pickparameter):
pickparameter.setParam(zfac=zfac_old) pickparameter.setParam(zfac=zfac_old)
return picks return picks

View File

@ -21,10 +21,12 @@ import matplotlib.pyplot as plt
import numpy as np import numpy as np
from obspy.core import Stream from obspy.core import Stream
class CharacteristicFunction(object): class CharacteristicFunction(object):
''' '''
SuperClass for different types of characteristic functions. SuperClass for different types of characteristic functions.
''' '''
def __init__(self, data, cut, t2=None, order=None, t1=None, fnoise=None, stealthMode=False): def __init__(self, data, cut, t2=None, order=None, t1=None, fnoise=None, stealthMode=False):
''' '''
Initialize data type object with information from the original Initialize data type object with information from the original
@ -247,6 +249,7 @@ class AICcf(CharacteristicFunction):
self.cf = cf - np.mean(cf) self.cf = cf - np.mean(cf)
self.xcf = x self.xcf = x
class HOScf(CharacteristicFunction): class HOScf(CharacteristicFunction):
''' '''
Function to calculate skewness (statistics of order 3) or kurtosis Function to calculate skewness (statistics of order 3) or kurtosis
@ -302,7 +305,6 @@ class HOScf(CharacteristicFunction):
class ARZcf(CharacteristicFunction): class ARZcf(CharacteristicFunction):
def calcCF(self, data): def calcCF(self, data):
print 'Calculating AR-prediction error from single trace ...' print 'Calculating AR-prediction error from single trace ...'
@ -426,7 +428,6 @@ class ARZcf(CharacteristicFunction):
class ARHcf(CharacteristicFunction): class ARHcf(CharacteristicFunction):
def calcCF(self, data): def calcCF(self, data):
print 'Calculating AR-prediction error from both horizontal traces ...' print 'Calculating AR-prediction error from both horizontal traces ...'
@ -464,7 +465,8 @@ class ARHcf(CharacteristicFunction):
self.arPredH(xnp, self.arpara, i + 1, lpred) self.arPredH(xnp, self.arpara, i + 1, lpred)
# prediction error = CF # prediction error = CF
cf[i + lpred] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \ cf[i + lpred] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2)) / (2 * lpred)) + np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2)) / (
2 * lpred))
nn = np.isnan(cf) nn = np.isnan(cf)
if len(nn) > 1: if len(nn) > 1:
cf[nn] = 0 cf[nn] = 0
@ -561,8 +563,8 @@ class ARHcf(CharacteristicFunction):
z = np.array([z1.tolist(), z2.tolist()]) z = np.array([z1.tolist(), z2.tolist()])
self.xpred = z self.xpred = z
class AR3Ccf(CharacteristicFunction):
class AR3Ccf(CharacteristicFunction):
def calcCF(self, data): def calcCF(self, data):
print 'Calculating AR-prediction error from all 3 components ...' print 'Calculating AR-prediction error from all 3 components ...'
@ -605,7 +607,8 @@ class AR3Ccf(CharacteristicFunction):
# prediction error = CF # prediction error = CF
cf[i + lpred] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \ cf[i + lpred] = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2) \ + np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2) \
+ np.power(self.xpred[2][i:i + lpred] - xnp[2][i:i + lpred], 2)) / (3 * lpred)) + np.power(self.xpred[2][i:i + lpred] - xnp[2][i:i + lpred], 2)) / (
3 * lpred))
nn = np.isnan(cf) nn = np.isnan(cf)
if len(nn) > 1: if len(nn) > 1:
cf[nn] = 0 cf[nn] = 0

259
pylot/core/pick/compare.py Normal file
View File

@ -0,0 +1,259 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import copy
import numpy as np
import matplotlib.pyplot as plt
from obspy import read_events
from pylot.core.read.io import picks_from_evt
from pylot.core.util.pdf import ProbabilityDensityFunction
from pylot.core.util.version import get_git_version as _getVersionString
__version__ = _getVersionString()
__author__ = 'sebastianw'
class Comparison(object):
"""
A Comparison object contains information on the evaluated picks' probability
density function and compares these in terms of building the difference of
compared pick sets. The results can be displayed as histograms showing its
properties.
"""
def __init__(self, **kwargs):
names = list()
self._pdfs = dict()
for name, fn in kwargs.items():
self._pdfs[name] = PDFDictionary.from_quakeml(fn)
names.append(name)
if len(names) > 2:
raise ValueError('Comparison is only defined for two '
'arguments!')
self._names = names
self._compare = self.compare_picksets()
def __nonzero__(self):
if not len(self.names) == 2 or not self._pdfs:
return False
return True
def get(self, name):
return self._pdfs[name]
@property
def names(self):
return self._names
@names.setter
def names(self, names):
assert isinstance(names, list) and len(names) == 2, 'variable "names"' \
' is either not a' \
' list or its ' \
'length is not 2:' \
'names : {names}'.format(
names=names)
self._names = names
@property
def comparison(self):
return self._compare
@property
def stations(self):
return self.comparison.keys()
@property
def nstations(self):
return len(self.stations)
def compare_picksets(self, type='exp'):
"""
Compare two picksets A and B and return a dictionary compiling the results.
Comparison is carried out with the help of pdf representation of the picks
and a probabilistic approach to the time difference of two onset
measurements.
:param a: filename for pickset A
:type a: str
:param b: filename for pickset B
:type b: str
:return: dictionary containing the resulting comparison pdfs for all picks
:rtype: dict
"""
compare_pdfs = dict()
pdf_a = self.get(self.names[0]).pdf_data(type)
pdf_b = self.get(self.names[1]).pdf_data(type)
for station, phases in pdf_a.items():
if station in pdf_b.keys():
compare_pdf = dict()
for phase in phases:
if phase in pdf_b[station].keys():
compare_pdf[phase] = phases[phase] - pdf_b[station][
phase]
if compare_pdf is not None:
compare_pdfs[station] = compare_pdf
return compare_pdfs
def plot(self):
nstations = self.nstations
stations = self.stations
istations = range(nstations)
fig, axarr = plt.subplots(nstations, 2, sharex='col', sharey='row')
for n in istations:
station = stations[n]
compare_pdf = self.comparison[station]
for l, phase in enumerate(compare_pdf.keys()):
axarr[n, l].plot(compare_pdf[phase].axis,
compare_pdf[phase].data)
if n is 0:
axarr[n, l].set_title(phase)
if l is 0:
axann = axarr[n, l].annotate(station, xy=(.05, .5),
xycoords='axes fraction')
bbox_props = dict(boxstyle='round', facecolor='lightgrey',
alpha=.7)
axann.set_bbox(bbox_props)
if n == int(np.median(istations)) and l is 0:
label = 'probability density (qualitative)'
axarr[n, l].set_ylabel(label)
plt.setp([a.get_xticklabels() for a in axarr[0, :]], visible=False)
plt.setp([a.get_yticklabels() for a in axarr[:, 1]], visible=False)
plt.setp([a.get_yticklabels() for a in axarr[:, 0]], visible=False)
plt.show()
def get_expectation_array(self, phase):
pdf_dict = self.comparison
exp_array = list()
for station, phases in pdf_dict.items():
try:
exp_array.append(phases[phase].expectation())
except KeyError as e:
print('{err_msg}; station = {station}, phase = {phase}'.format(
err_msg=str(e), station=station, phase=phase))
continue
return exp_array
def get_std_array(self, phase):
pdf_dict = self.comparison
std_array = list()
for station, phases in pdf_dict.items():
try:
std_array.append(phases[phase].standard_deviation())
except KeyError as e:
print('{err_msg}; station = {station}, phase = {phase}'.format(
err_msg=str(e), station=station, phase=phase))
continue
return std_array
def hist_expectation(self, phases='all', bins=20, normed=False):
phases.strip()
if phases.find('all') is 0:
phases = 'ps'
phases = phases.upper()
nsp = len(phases)
fig, axarray = plt.subplots(1, nsp, sharey=True)
for n, phase in enumerate(phases):
ax = axarray[n]
data = self.get_expectation_array(phase)
xlims = [min(data), max(data)]
ax.hist(data, range=xlims, bins=bins, normed=normed)
title_str = 'phase: {0}, samples: {1}'.format(phase, len(data))
ax.set_title(title_str)
ax.set_xlabel('expectation [s]')
if n is 0:
ax.set_ylabel('abundance [-]')
plt.setp([a.get_yticklabels() for a in axarray[1:]], visible=False)
plt.show()
def hist_standard_deviation(self, phases='all', bins=20, normed=False):
phases.strip()
if phases.find('all') == 0:
phases = 'ps'
phases = phases.upper()
nsp = len(phases)
fig, axarray = plt.subplots(1, nsp, sharey=True)
for n, phase in enumerate(phases):
ax = axarray[n]
data = self.get_std_array(phase)
xlims = [min(data), max(data)]
ax.hist(data, range=xlims, bins=bins, normed=normed)
title_str = 'phase: {0}, samples: {1}'.format(phase, len(data))
ax.set_title(title_str)
ax.set_xlabel('standard deviation [s]')
if n is 0:
ax.set_ylabel('abundance [-]')
plt.setp([a.get_yticklabels() for a in axarray[1:]], visible=False)
plt.show()
def hist(self, type='std'):
pass
class PDFDictionary(object):
"""
A PDFDictionary is a dictionary like object containing structured data on
the probability density function of seismic phase onsets.
"""
def __init__(self, data):
self._pickdata = data
def __nonzero__(self):
if len(self.pick_data) < 1:
return False
else:
return True
@property
def pick_data(self):
return self._pickdata
@pick_data.setter
def pick_data(self, data):
self._pickdata = data
@classmethod
def from_quakeml(self, fn):
cat = read_events(fn)
if len(cat) > 1:
raise NotImplementedError('reading more than one event at the same '
'time is not implemented yet! Sorry!')
return PDFDictionary(picks_from_evt(cat[0]))
def pdf_data(self, type='exp'):
"""
Returns probabiliy density function dictionary containing the
representation of the actual pick_data.
:param type: type of the returned
`~pylot.core.util.pdf.ProbabilityDensityFunction` object
:type type: str
:return: a dictionary containing the picks represented as pdfs
"""
pdf_picks = copy.deepcopy(self.pick_data)
for station, phases in pdf_picks.items():
for phase, values in phases.items():
phases[phase] = ProbabilityDensityFunction.from_pick(
values['epp'],
values['mpp'],
values['lpp'],
type=type)
return pdf_picks
#comp_obj = Comparison(manual='/home/sebastianp/Data/Insheim/e0019.048.13.xml',
# auto='/data/Geothermie/Insheim/EVENT_DATA/LOCAL/RefDB/e0019.048.13/autoPyLoT.xml')
#comp_obj.plot()
#comp_obj.hist_expectation()
#comp_obj.hist_standard_deviation()

View File

@ -22,10 +22,11 @@ calculated after Diehl & Kissling (2009).
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from pylot.core.pick.utils import getnoisewin, getsignalwin from pylot.core.pick.utils import getnoisewin, getsignalwin
from pylot.core.pick.CharFuns import CharacteristicFunction from pylot.core.pick.charfuns import CharacteristicFunction
import warnings import warnings
class AutoPicking(object):
class AutoPicker(object):
''' '''
Superclass of different, automated picking algorithms applied on a CF determined Superclass of different, automated picking algorithms applied on a CF determined
using AIC, HOS, or AR prediction. using AIC, HOS, or AR prediction.
@ -87,7 +88,6 @@ class AutoPicking(object):
Tsmooth=self.getTsmooth(), Tsmooth=self.getTsmooth(),
Pick1=self.getpick1()) Pick1=self.getpick1())
def getTSNR(self): def getTSNR(self):
return self.TSNR return self.TSNR
@ -137,7 +137,7 @@ class AutoPicking(object):
self.Pick = None self.Pick = None
class AICPicker(AutoPicking): class AICPicker(AutoPicker):
''' '''
Method to derive the onset time of an arriving phase based on CF Method to derive the onset time of an arriving phase based on CF
derived from AIC. In order to get an impression of the quality of this inital pick, derived from AIC. In order to get an impression of the quality of this inital pick,
@ -273,7 +273,8 @@ class AICPicker(AutoPicking):
p13, = plt.plot(self.Tcf[isignal], self.Data[0].data[isignal], 'r') p13, = plt.plot(self.Tcf[isignal], self.Data[0].data[isignal], 'r')
p14, = plt.plot(self.Tcf[islope], dataslope, 'g--') p14, = plt.plot(self.Tcf[islope], dataslope, 'g--')
p15, = plt.plot(self.Tcf[islope], datafit, 'g', linewidth=2) p15, = plt.plot(self.Tcf[islope], datafit, 'g', linewidth=2)
plt.legend([p11, p12, p13, p14, p15], ['Data', 'Noise Window', 'Signal Window', 'Slope Window', 'Slope'], plt.legend([p11, p12, p13, p14, p15],
['Data', 'Noise Window', 'Signal Window', 'Slope Window', 'Slope'],
loc='best') loc='best')
plt.title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station, plt.title('Station %s, SNR=%7.2f, Slope= %12.2f counts/s' % (self.Data[0].stats.station,
self.SNR, self.slope)) self.SNR, self.slope))
@ -289,7 +290,7 @@ class AICPicker(AutoPicking):
print('AICPicker: Could not find minimum, picking window too short?') print('AICPicker: Could not find minimum, picking window too short?')
class PragPicker(AutoPicking): class PragPicker(AutoPicker):
''' '''
Method of pragmatic picking exploiting information given by CF. Method of pragmatic picking exploiting information given by CF.
''' '''

View File

@ -70,7 +70,8 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealthMode = False):
# get earliest possible pick # get earliest possible pick
EPick = np.nan; count = 0 EPick = np.nan;
count = 0
pis = isignal pis = isignal
# if EPick stays NaN the signal window size will be doubled # if EPick stays NaN the signal window size will be doubled
@ -94,7 +95,6 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealthMode = False):
T0 = np.mean(np.diff(zc)) * X[0].stats.delta # this is half wave length! T0 = np.mean(np.diff(zc)) * X[0].stats.delta # this is half wave length!
EPick = Pick1 - T0 # half wavelength as suggested by Diehl et al. EPick = Pick1 - T0 # half wavelength as suggested by Diehl et al.
# get symmetric pick error as mean from earliest and latest possible pick # get symmetric pick error as mean from earliest and latest possible pick
# by weighting latest possible pick two times earliest possible pick # by weighting latest possible pick two times earliest possible pick
diffti_tl = LPick - Pick1 diffti_tl = LPick - Pick1
@ -133,117 +133,6 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=None, stealthMode = False):
return EPick, LPick, PickError return EPick, LPick, PickError
def gauss_parameter(te, tm, tl, eta):
'''
takes three onset times and returns the parameters sig1, sig2, a1 and a2
to represent the pick as a probability density funtion (PDF) with two
Gauss branches
:param te:
:param tm:
:param tl:
:param eta:
:return:
'''
sig1 = (tm - te) / np.sqrt(2 * np.log(1 / eta))
sig2 = (tl - tm) / np.sqrt(2 * np.log(1 / eta))
a1 = 2 / (1 + sig2 / sig1)
a2 = 2 / (1 + sig1 / sig2)
return sig1, sig2, a1, a2
def exp_parameter(te, tm, tl, eta):
'''
takes three onset times te, tm and tl and returns the parameters sig1,
sig2 and a to represent the pick as a probability density function (PDF)
with two exponential decay branches
:param te:
:param tm:
:param tl:
:param eta:
:return:
'''
sig1 = np.log(eta) / (te - tm)
sig2 = np.log(eta) / (tm - tl)
a = 1 / (1 / sig1 + 1 / sig2)
return sig1, sig2, a
def gauss_branches(x, mu, sig1, sig2, a1, a2):
'''
function gauss_branches takes an axes x, a center value mu, two sigma
values sig1 and sig2 and two scaling factors a1 and a2 and return a
list containing the values of a probability density function (PDF)
consisting of gauss branches
:param x:
:type x:
:param mu:
:type mu:
:param sig1:
:type sig1:
:param sig2:
:type sig2:
:param a1:
:type a1:
:param a2:
:returns fun_vals: list with function values along axes x
'''
fun_vals = []
for k in x:
if k < mu:
fun_vals.append(a1 * 1 / (np.sqrt(2 * np.pi) * sig1) * np.exp(-((k - mu) / sig1)**2 / 2 ))
else:
fun_vals.append(a2 * 1 / (np.sqrt(2 * np.pi) * sig2) * np.exp(-((k - mu) / sig2)**2 / 2))
return fun_vals
def exp_branches(x, mu, sig1, sig2, a):
'''
function exp_branches takes an axes x, a center value mu, two sigma
values sig1 and sig2 and a scaling factor a and return a
list containing the values of a probability density function (PDF)
consisting of exponential decay branches
:param x:
:param mu:
:param sig1:
:param sig2:
:param a:
:returns fun_vals: list with function values along axes x:
'''
fun_vals = []
for k in x:
if k < mu:
fun_vals.append(a * np.exp(sig1 * (k - mu)))
else:
fun_vals.append(a * np.exp(-sig2 * (k - mu)))
return fun_vals
def pick_pdf(t, te, tm, tl, type='gauss', eta=0.01):
'''
:param t:
:param te:
:param tm:
:param tl:
:param type:
:param eta:
:param args:
:return:
'''
parameter = dict(gauss=gauss_parameter, exp=exp_parameter)
branches = dict(gauss=gauss_branches, exp=exp_branches)
params = parameter[type](te, tm, tl, eta)
return branches[type](t, tm, *params)
def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None): def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=None):
''' '''
Function to derive first motion (polarity) of given phase onset Pick. Function to derive first motion (polarity) of given phase onset Pick.
@ -432,7 +321,7 @@ def crossings_nonzero_all(data):
return ((pos[:-1] & npos[1:]) | (npos[:-1] & pos[1:])).nonzero()[0] return ((pos[:-1] & npos[1:]) | (npos[:-1] & pos[1:])).nonzero()[0]
def getSNR(X, TSNR, t1): def getSNR(X, TSNR, t1, tracenum=0):
''' '''
Function to calculate SNR of certain part of seismogram relative to Function to calculate SNR of certain part of seismogram relative to
given time (onset) out of given noise and signal windows. A safety gap given time (onset) out of given noise and signal windows. A safety gap
@ -451,9 +340,11 @@ def getSNR(X, TSNR, t1):
assert isinstance(X, Stream), "%s is not a stream object" % str(X) assert isinstance(X, Stream), "%s is not a stream object" % str(X)
x = X[0].data x = X[tracenum].data
t = np.arange(0, X[0].stats.npts / X[0].stats.sampling_rate, npts = X[tracenum].stats.npts
X[0].stats.delta) sr = X[tracenum].stats.sampling_rate
dt = X[tracenum].stats.delta
t = np.arange(0, npts / sr, dt)
# get noise window # get noise window
inoise = getnoisewin(t, t1, TSNR[0], TSNR[1]) inoise = getnoisewin(t, t1, TSNR[0], TSNR[1])
@ -471,8 +362,12 @@ def getSNR(X, TSNR, t1):
x = x - np.mean(x[inoise]) x = x - np.mean(x[inoise])
# calculate ratios # calculate ratios
noiselevel = np.sqrt(np.mean(np.square(x[inoise]))) # noiselevel = np.sqrt(np.mean(np.square(x[inoise])))
signallevel = np.sqrt(np.mean(np.square(x[isignal]))) # signallevel = np.sqrt(np.mean(np.square(x[isignal])))
noiselevel = np.abs(x[inoise]).max()
signallevel = np.abs(x[isignal]).max()
SNR = signallevel / noiselevel SNR = signallevel / noiselevel
SNRdB = 10 * np.log10(SNR) SNRdB = 10 * np.log10(SNR)
@ -604,7 +499,6 @@ def wadaticheck(pickdic, dttolerance, iplot):
Spicks.append(UTCSpick.timestamp) Spicks.append(UTCSpick.timestamp)
SPtimes.append(spt) SPtimes.append(spt)
if len(SPtimes) >= 3: if len(SPtimes) >= 3:
# calculate slope # calculate slope
p1 = np.polyfit(Ppicks, SPtimes, 1) p1 = np.polyfit(Ppicks, SPtimes, 1)
@ -986,7 +880,6 @@ def checkZ4S(X, pick, zfac, checkwin, iplot):
if len(ndat) == 0: # check for other components if len(ndat) == 0: # check for other components
ndat = X.select(component="1") ndat = X.select(component="1")
z = zdat[0].data z = zdat[0].data
tz = np.arange(0, zdat[0].stats.npts / zdat[0].stats.sampling_rate, tz = np.arange(0, zdat[0].stats.npts / zdat[0].stats.sampling_rate,
zdat[0].stats.delta) zdat[0].stats.delta)
@ -1065,7 +958,6 @@ def writephases(arrivals, fformat, filename):
:type: string :type: string
''' '''
if fformat == 'NLLoc': if fformat == 'NLLoc':
print ("Writing phases to %s for NLLoc" % filename) print ("Writing phases to %s for NLLoc" % filename)
fid = open("%s" % filename, 'w') fid = open("%s" % filename, 'w')
@ -1203,4 +1095,5 @@ def writephases(arrivals, fformat, filename):
if __name__ == '__main__': if __name__ == '__main__':
import doctest import doctest
doctest.testmod() doctest.testmod()

View File

@ -3,9 +3,10 @@
import os import os
import glob import glob
from obspy.xseed import Parser import warnings
from obspy.io.xseed import Parser
from obspy.core import read, Stream, UTCDateTime from obspy.core import read, Stream, UTCDateTime
from obspy import readEvents, read_inventory from obspy import read_events, read_inventory
from obspy.core.event import Event, ResourceIdentifier, Pick, WaveformStreamID from obspy.core.event import Event, ResourceIdentifier, Pick, WaveformStreamID
from pylot.core.read.io import readPILOTEvent from pylot.core.read.io import readPILOTEvent
@ -37,9 +38,10 @@ class Data(object):
if isinstance(evtdata, Event): if isinstance(evtdata, Event):
self.evtdata = evtdata self.evtdata = evtdata
elif isinstance(evtdata, dict): elif isinstance(evtdata, dict):
cat = readPILOTEvent(**evtdata) evt = readPILOTEvent(**evtdata)
self.evtdata = evt
elif evtdata: elif evtdata:
cat = readEvents(evtdata) cat = read_events(evtdata)
self.evtdata = cat[0] self.evtdata = cat[0]
else: # create an empty Event object else: # create an empty Event object
self.setNew() self.setNew()
@ -79,7 +81,6 @@ class Data(object):
picks_str += str(pick) + '\n' picks_str += str(pick) + '\n'
return picks_str return picks_str
def getParent(self): def getParent(self):
""" """
@ -186,8 +187,11 @@ class Data(object):
self.wforiginal = None self.wforiginal = None
if fnames is not None: if fnames is not None:
self.appendWFData(fnames) self.appendWFData(fnames)
else:
return False
self.wforiginal = self.getWFData().copy() self.wforiginal = self.getWFData().copy()
self.dirty = False self.dirty = False
return True
def appendWFData(self, fnames): def appendWFData(self, fnames):
""" """
@ -413,16 +417,24 @@ class Data(object):
for station, onsets in picks.items(): 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(): for label, phase in onsets.items():
if not isinstance(phase, dict):
continue
onset = phase['mpp'] onset = phase['mpp']
epp = phase['epp'] epp = phase['epp']
lpp = phase['lpp'] lpp = phase['lpp']
error = phase['spe'] error = phase['spe']
try:
picker = phase['picker']
except KeyError as e:
warnings.warn(str(e), Warning)
picker = 'Unknown'
pick = Pick() pick = Pick()
pick.time = onset pick.time = onset
pick.time_errors.lower_uncertainty = onset - epp pick.time_errors.lower_uncertainty = onset - epp
pick.time_errors.upper_uncertainty = lpp - onset pick.time_errors.upper_uncertainty = lpp - onset
pick.time_errors.uncertainty = error pick.time_errors.uncertainty = error
pick.phase_hint = label pick.phase_hint = label
pick.method_id = ResourceIdentifier(id=picker)
pick.waveform_id = WaveformStreamID(station_code=station) pick.waveform_id = WaveformStreamID(station_code=station)
self.getEvtData().picks.append(pick) self.getEvtData().picks.append(pick)
try: try:
@ -432,11 +444,13 @@ class Data(object):
if firstonset is None or firstonset > onset: if firstonset is None or firstonset > onset:
firstonset = onset firstonset = onset
if 'smi:local' in self.getID(): if 'smi:local' in self.getID() and firstonset:
fonset_str = firstonset.strftime('%Y_%m_%d_%H_%M_%S') fonset_str = firstonset.strftime('%Y_%m_%d_%H_%M_%S')
ID = ResourceIdentifier('event/' + fonset_str) ID = ResourceIdentifier('event/' + fonset_str)
ID.convertIDToQuakeMLURI(authority_id=authority_id) ID.convertIDToQuakeMLURI(authority_id=authority_id)
self.getEvtData().resource_id = ID self.getEvtData().resource_id = ID
else:
print('No picks to apply!')
def applyArrivals(arrivals): def applyArrivals(arrivals):
""" """

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from pylot.core.util.errors import ParameterError
class AutoPickParameter(object): class AutoPickParameter(object):
''' '''
@ -57,7 +59,7 @@ class AutoPickParameter(object):
for line in lines: for line in lines:
parspl = line.split('\t')[:2] parspl = line.split('\t')[:2]
parFileCont[parspl[0].strip()] = parspl[1] parFileCont[parspl[0].strip()] = parspl[1]
except Exception as e: except IndexError as e:
self._printParameterError(e) self._printParameterError(e)
inputFile.seek(0) inputFile.seek(0)
lines = inputFile.readlines() lines = inputFile.readlines()
@ -136,11 +138,13 @@ class AutoPickParameter(object):
return self.__getitem__(param) return self.__getitem__(param)
except KeyError as e: except KeyError as e:
self._printParameterError(e) self._printParameterError(e)
raise ParameterError(e)
except TypeError: except TypeError:
try: try:
return self.__getitem__(args) return self.__getitem__(args)
except KeyError as e: except KeyError as e:
self._printParameterError(e) self._printParameterError(e)
raise ParameterError(e)
def setParam(self, **kwargs): def setParam(self, **kwargs):
for param, value in kwargs.items(): for param, value in kwargs.items():
@ -190,6 +194,7 @@ class FilterOptions(object):
``'highpass'`` ``'highpass'``
Butterworth-Highpass Butterworth-Highpass
''' '''
def __init__(self, filtertype='bandpass', freq=[2., 5.], order=3, def __init__(self, filtertype='bandpass', freq=[2., 5.], order=3,
**kwargs): **kwargs):
self._order = order self._order = order

View File

@ -10,6 +10,7 @@ from obspy.core import UTCDateTime
from pylot.core.util.utils import getOwner, createPick, createArrival, \ from pylot.core.util.utils import getOwner, createPick, createArrival, \
createEvent, createOrigin, createMagnitude createEvent, createOrigin, createMagnitude
def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs): def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
""" """
readPILOTEvent - function readPILOTEvent - function
@ -134,4 +135,57 @@ def readPILOTEvent(phasfn=None, locfn=None, authority_id=None, **kwargs):
raise AttributeError('{0} - Matlab LOC files {1} and {2} contains \ raise AttributeError('{0} - Matlab LOC files {1} and {2} contains \
insufficient data!'.format(e, phasfn, locfn)) insufficient data!'.format(e, phasfn, locfn))
def picks_from_obs(fn):
picks = dict()
station_name = str()
for line in open(fn, 'r'):
if line.startswith('#'):
continue
else:
phase_line = line.split()
if not station_name == phase_line[0]:
phase = dict()
station_name = phase_line[0]
phase_name = phase_line[4].upper()
pick = UTCDateTime(phase_line[6] + phase_line[7] + phase_line[8])
phase[phase_name] = dict(mpp=pick, fm=phase_line[5])
picks[station_name] = phase
return picks
def picks_from_evt(evt):
'''
Takes an Event object and return the pick dictionary commonly used within
PyLoT
:param evt: Event object contain all available information
:type evt: `~obspy.core.event.Event`
:return: pick dictionary
'''
picks = {}
for pick in evt.picks:
phase = {}
station = pick.waveform_id.station_code
try:
onsets = picks[station]
except KeyError as e:
print(e)
onsets = {}
mpp = pick.time
lpp = mpp + pick.time_errors.upper_uncertainty
epp = mpp - pick.time_errors.lower_uncertainty
spe = pick.time_errors.uncertainty
phase['mpp'] = mpp
phase['epp'] = epp
phase['lpp'] = lpp
phase['spe'] = spe
try:
picker = str(pick.method_id)
if picker.startswith('smi:local/'):
picker = picker.split('smi:local/')[1]
phase['picker'] = picker
except IndexError:
pass
onsets[pick.phase_hint] = phase.copy()
picks[station] = onsets.copy()
return picks

View File

@ -7,7 +7,7 @@ from pylot.core.pick.utils import getnoisewin
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--t', type=~numpy.array, help='numpy array of time stamps') parser.add_argument('--t', type=numpy.array, help='numpy array of time stamps')
parser.add_argument('--t1', type=float, help='time from which relativ to it noise window is extracted') parser.add_argument('--t1', type=float, help='time from which relativ to it noise window is extracted')
parser.add_argument('--tnoise', type=float, help='length of time window [s] for noise part extraction') parser.add_argument('--tnoise', type=float, help='length of time window [s] for noise part extraction')
parser.add_argument('--tgap', type=float, help='safety gap between signal (t1=onset) and noise') parser.add_argument('--tgap', type=float, help='safety gap between signal (t1=onset) and noise')

View File

@ -14,11 +14,12 @@ import argparse
import obspy import obspy
from pylot.core.pick.utils import earllatepicker from pylot.core.pick.utils import earllatepicker
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--X', type=~obspy.core.stream.Stream, help='time series (seismogram) read with obspy module read') parser.add_argument('--X', type=~obspy.core.stream.Stream,
parser.add_argument('--nfac', type=int, help='(noise factor), nfac times noise level to calculate latest possible pick') help='time series (seismogram) read with obspy module read')
parser.add_argument('--nfac', type=int,
help='(noise factor), nfac times noise level to calculate latest possible pick')
parser.add_argument('--TSNR', type=tuple, help='length of time windows around pick used to determine SNR \ parser.add_argument('--TSNR', type=tuple, help='length of time windows around pick used to determine SNR \
[s] (Tnoise, Tgap, Tsignal)') [s] (Tnoise, Tgap, Tsignal)')
parser.add_argument('--Pick1', type=float, help='Onset time of most likely pick') parser.add_argument('--Pick1', type=float, help='Onset time of most likely pick')

View File

@ -13,11 +13,12 @@ from pylot.core.pick.utils import fmpicker
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--Xraw', type=~obspy.core.stream.Stream, help='unfiltered time series (seismogram) read with obspy module read') parser.add_argument('--Xraw', type=obspy.core.stream.Stream,
parser.add_argument('--Xfilt', type=~obspy.core.stream.Stream, help='filtered time series (seismogram) read with obspy module read') help='unfiltered time series (seismogram) read with obspy module read')
parser.add_argument('--Xfilt', type=obspy.core.stream.Stream,
help='filtered time series (seismogram) read with obspy module read')
parser.add_argument('--pickwin', type=float, help='length of pick window [s] for first motion determination') parser.add_argument('--pickwin', type=float, help='length of pick window [s] for first motion determination')
parser.add_argument('--Pick', type=float, help='Onset time of most likely pick') parser.add_argument('--Pick', type=float, help='Onset time of most likely pick')
parser.add_argument('--iplot', type=int, help='if set, figure no. iplot occurs') parser.add_argument('--iplot', type=int, help='if set, figure no. iplot occurs')
args = parser.parse_args() args = parser.parse_args()
fmpicker(args.Xraw, args.Xfilt, args.pickwin, args.Pick, args.iplot) fmpicker(args.Xraw, args.Xfilt, args.pickwin, args.Pick, args.iplot)

View File

@ -7,7 +7,7 @@ from pylot.core.pick.utils import getsignalwin
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--t', type=~numpy.array, help='numpy array of time stamps') parser.add_argument('--t', type=numpy.array, help='numpy array of time stamps')
parser.add_argument('--t1', type=float, help='time from which relativ to it signal window is extracted') parser.add_argument('--t1', type=float, help='time from which relativ to it signal window is extracted')
parser.add_argument('--tsignal', type=float, help='length of time window [s] for signal part extraction') parser.add_argument('--tsignal', type=float, help='length of time window [s] for signal part extraction')
args = parser.parse_args() args = parser.parse_args()

View File

@ -14,7 +14,7 @@ from pylot.core.pick.utils import getSNR
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--data', '-d', type=~obspy.core.stream.Stream, parser.add_argument('--data', '-d', type=obspy.core.stream.Stream,
help='time series (seismogram) read with obspy module ' help='time series (seismogram) read with obspy module '
'read', 'read',
dest='data') dest='data')

View File

@ -9,8 +9,8 @@
from obspy.core import read from obspy.core import read
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
from pylot.core.pick.CharFuns import CharacteristicFunction from pylot.core.pick.charfuns import CharacteristicFunction
from pylot.core.pick.Picker import AutoPicking from pylot.core.pick.picker import AutoPicker
from pylot.core.pick.utils import * from pylot.core.pick.utils import *
import glob import glob
import argparse import argparse

View File

@ -11,6 +11,7 @@ from pylot.core.loc import nll
from pylot.core.loc import hsat from pylot.core.loc import hsat
from pylot.core.loc import velest from pylot.core.loc import velest
def readFilterInformation(fname): def readFilterInformation(fname):
def convert2FreqRange(*args): def convert2FreqRange(*args):
if len(args) > 1: if len(args) > 1:
@ -18,6 +19,7 @@ def readFilterInformation(fname):
elif len(args) == 1: elif len(args) == 1:
return float(args[0]) return float(args[0])
return None return None
filter_file = open(fname, 'r') filter_file = open(fname, 'r')
filter_information = dict() filter_information = dict()
for filter_line in filter_file.readlines(): for filter_line in filter_file.readlines():
@ -41,8 +43,19 @@ FILTERDEFAULTS = readFilterInformation(os.path.join(os.path.expanduser('~'),
'.pylot', '.pylot',
'filter.in')) 'filter.in'))
AUTOMATIC_DEFAULTS = os.path.join(os.path.expanduser('~'),
'.pylot',
'autoPyLoT.in')
OUTPUTFORMATS = {'.xml': 'QUAKEML', OUTPUTFORMATS = {'.xml': 'QUAKEML',
'.cnv': 'CNV', '.cnv': 'CNV',
'.obs': 'NLLOC_OBS'} '.obs': 'NLLOC_OBS'}
LOCTOOLS = dict(nll=nll, hsat=hsat, velest=velest) LOCTOOLS = dict(nll=nll, hsat=hsat, velest=velest)
COMPPOSITION_MAP = dict(Z=2, N=1, E=0)
COMPPOSITION_MAP['1'] = 1
COMPPOSITION_MAP['2'] = 0
COMPPOSITION_MAP['3'] = 2
COMPNAME_MAP = dict(Z='3', N='1', E='2')

View File

@ -20,3 +20,7 @@ class DatastructureError(Exception):
class OverwriteError(IOError): class OverwriteError(IOError):
pass pass
class ParameterError(Exception):
pass

395
pylot/core/util/pdf.py Normal file
View File

@ -0,0 +1,395 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import warnings
import numpy as np
from obspy import UTCDateTime
from pylot.core.util.utils import find_nearest
from pylot.core.util.version import get_git_version as _getVersionString
__version__ = _getVersionString()
__author__ = 'sebastianw'
def create_axis(x0, incr, npts):
ax = np.zeros(npts)
for i in range(npts):
ax[i] = x0 + incr * i
return ax
def gauss_parameter(te, tm, tl, eta):
'''
takes three onset times and returns the parameters sig1, sig2, a1 and a2
to represent the pick as a probability density funtion (PDF) with two
Gauss branches
:param te:
:param tm:
:param tl:
:param eta:
:return:
'''
sig1 = (tm - te) / np.sqrt(2 * np.log(1 / eta))
sig2 = (tl - tm) / np.sqrt(2 * np.log(1 / eta))
a1 = 2 / (1 + sig2 / sig1)
a2 = 2 / (1 + sig1 / sig2)
return sig1, sig2, a1, a2
def exp_parameter(te, tm, tl, eta):
'''
takes three onset times te, tm and tl and returns the parameters sig1,
sig2 and a to represent the pick as a probability density function (PDF)
with two exponential decay branches
:param te:
:param tm:
:param tl:
:param eta:
:return:
'''
sig1 = np.log(eta) / (te - tm)
sig2 = np.log(eta) / (tm - tl)
a = 1 / (1 / sig1 + 1 / sig2)
return sig1, sig2, a
def gauss_branches(x, mu, sig1, sig2, a1, a2):
'''
function gauss_branches takes an axes x, a center value mu, two sigma
values sig1 and sig2 and two scaling factors a1 and a2 and return a
list containing the values of a probability density function (PDF)
consisting of gauss branches
:param x:
:type x:
:param mu:
:type mu:
:param sig1:
:type sig1:
:param sig2:
:type sig2:
:param a1:
:type a1:
:param a2:
:returns fun_vals: list with function values along axes x
'''
fun_vals = []
for k in x:
if k < mu:
fun_vals.append(a1 * 1 / (np.sqrt(2 * np.pi) * sig1) * np.exp(-((k - mu) / sig1) ** 2 / 2))
else:
fun_vals.append(a2 * 1 / (np.sqrt(2 * np.pi) * sig2) * np.exp(-((k - mu) / sig2) ** 2 / 2))
return np.array(fun_vals)
def exp_branches(x, mu, sig1, sig2, a):
'''
function exp_branches takes an axes x, a center value mu, two sigma
values sig1 and sig2 and a scaling factor a and return a
list containing the values of a probability density function (PDF)
consisting of exponential decay branches
:param x:
:param mu:
:param sig1:
:param sig2:
:param a:
:returns fun_vals: list with function values along axes x:
'''
fun_vals = []
for k in x:
if k < mu:
fun_vals.append(a * np.exp(sig1 * (k - mu)))
else:
fun_vals.append(a * np.exp(-sig2 * (k - mu)))
return np.array(fun_vals)
# define container dictionaries for different types of pdfs
parameter = dict(gauss=gauss_parameter, exp=exp_parameter)
branches = dict(gauss=gauss_branches, exp=exp_branches)
class ProbabilityDensityFunction(object):
'''
A probability density function toolkit.
'''
version = __version__
def __init__(self, x0, incr, npts, pdf):
self.x0 = x0
self.incr = incr
self.npts = npts
self.axis = create_axis(x0, incr, npts)
self.data = pdf
def __add__(self, other):
assert isinstance(other, ProbabilityDensityFunction), \
'both operands must be of type ProbabilityDensityFunction'
x0, incr, npts, pdf_self, pdf_other = self.rearrange(other)
pdf = np.convolve(pdf_self, pdf_other, 'full') * incr
# shift axis values for correct plotting
npts = pdf.size
x0 *= 2
return ProbabilityDensityFunction(x0, incr, npts, pdf)
def __sub__(self, other):
assert isinstance(other, ProbabilityDensityFunction), \
'both operands must be of type ProbabilityDensityFunction'
x0, incr, npts, pdf_self, pdf_other = self.rearrange(other)
pdf = np.correlate(pdf_self, pdf_other, 'same') * incr
# shift axis values for correct plotting
midpoint = npts / 2
x0 = -incr * midpoint
return ProbabilityDensityFunction(x0, incr, npts, pdf)
def __nonzero__(self):
prec = self.precision(self.incr)
gtzero = np.all(self.data >= 0)
probone = bool(np.round(self.prob_gt_val(self.axis[0]), prec) == 1.)
return bool(gtzero and probone)
def __str__(self):
return str(self.data)
@staticmethod
def precision(incr):
prec = int(np.ceil(np.abs(np.log10(incr)))) - 2
return prec if prec >= 0 else 0
@property
def data(self):
return self._pdf
@data.setter
def data(self, pdf):
self._pdf = np.array(pdf)
@property
def axis(self):
return self._x
@axis.setter
def axis(self, x):
self._x = np.array(x)
@classmethod
def from_pick(self, lbound, barycentre, rbound, incr=0.001, decfact=0.01,
type='gauss'):
'''
Initialize a new ProbabilityDensityFunction object.
Takes incr, lbound, barycentre and rbound to derive x0 and the number
of points npts for the axis vector.
Maximum density
is given at the barycentre and on the boundaries the function has
declined to decfact times the maximum value. Integration of the
function over a particular interval gives the probability for the
variable value to be in that interval.
'''
# derive adequate window of definition
margin = 2. * np.max([barycentre - lbound, rbound - barycentre])
# find midpoint accounting also for `~obspy.UTCDateTime` object usage
try:
midpoint = (rbound + lbound) / 2
except TypeError:
try:
midpoint = (rbound + float(lbound)) / 2
except TypeError:
midpoint = float(rbound + float(lbound)) / 2
# find x0 on a grid point and sufficient npts
was_datetime = None
if isinstance(barycentre, UTCDateTime):
barycentre = float(barycentre)
was_datetime = True
n = int(np.ceil((barycentre - midpoint) / incr))
m = int(np.ceil((margin / incr)))
midpoint = barycentre - n * incr
margin = m * incr
x0 = midpoint - margin
npts = 2 * m
if was_datetime:
barycentre = UTCDateTime(barycentre)
# calculate parameter for pdf representing function
params = parameter[type](lbound, barycentre, rbound, decfact)
# calculate pdf values
try:
pdf = branches[type](create_axis(x0, incr, npts), barycentre, *params)
except TypeError as e:
print('Warning:\n' + e.message + '\n' + 'trying timestamp instead')
assert isinstance(barycentre, UTCDateTime), 'object not capable of' \
' timestamp representation'
pdf = branches[type](create_axis(x0, incr, npts),
barycentre.timestamp, *params)
# return the object
return ProbabilityDensityFunction(x0, incr, npts, pdf)
def broadcast(self, pdf, si, ei, data):
try:
pdf[si:ei] = data
except ValueError as e:
warnings.warn(str(e), Warning)
return self.broadcast(pdf, si, ei, data[:-1])
return pdf
def expectation(self):
'''
returns the expectation value of the actual pdf object
..formula::
mu_{\Delta t} = \int\limits_{-\infty}^\infty x \cdot f(x)dx
:return float: rval
'''
rval = 0
for n, x in enumerate(self.axis):
rval += x * self.data[n]
return rval * self.incr
def standard_deviation(self):
mu = self.expectation()
rval = 0
for n, x in enumerate(self.axis):
rval += (x - mu) ** 2 * self.data[n]
return rval * self.incr
def prob_lt_val(self, value):
if value <= self.axis[0] or value > self.axis[-1]:
raise ValueError('value out of bounds: {0}'.format(value))
return self.prob_limits((self.axis[0], value))
def prob_gt_val(self, value):
if value < self.axis[0] or value >= self.axis[-1]:
raise ValueError('value out of bounds: {0}'.format(value))
return self.prob_limits((value, self.axis[-1]))
def prob_limits(self, limits):
lim_ind = np.logical_and(limits[0] <= self.axis, self.axis <= limits[1])
data = self.data[lim_ind]
min_est, max_est = 0., 0.
for n in range(len(data) - 1):
min_est += min(data[n], data[n + 1])
max_est += max(data[n], data[n + 1])
return (min_est + max_est) / 2. * self.incr
def prob_val(self, value):
if not (self.axis[0] <= value <= self.axis[-1]):
Warning('{0} not on axis'.format(value))
return None
return self.data[find_nearest(self.axis, value)] * self.incr
def plot(self, label=None):
import matplotlib.pyplot as plt
plt.plot(self.axis, self.data)
plt.xlabel('x')
plt.ylabel('f(x)')
plt.autoscale(axis='x', tight=True)
if self:
title_str = 'Probability density function '
if label:
title_str += label
title_str.strip()
else:
title_str = 'Function not suitable as probability density function'
plt.title(title_str)
plt.show()
def commonlimits(self, incr, other, max_npts=1e5):
'''
Takes an increment incr and two left and two right limits and returns
the left most limit and the minimum number of points needed to cover
the whole given interval.
:param incr:
:param l1:
:param l2:
:param r1:
:param r2:
:param max_npts:
:return:
'''
# >>> manu = ProbabilityDensityFunction.from_pick(0.01, 0.3, 0.5, 0.54)
# >>> auto = ProbabilityDensityFunction.from_pick(0.01, 0.3, 0.34, 0.54)
# >>> manu.commonlimits(0.01, auto)
# (
l1 = self.x0
r1 = l1 + self.incr * self.npts
l2 = other.x0
r2 = l2 + other.incr * other.npts
if l1 < l2:
x0 = l1
else:
x0 = l2
# calculate index for rounding
ri = self.precision(incr)
if r1 < r2:
npts = int(round(r2 - x0, ri) // incr)
else:
npts = int(round(r1 - x0, ri) // incr)
if npts > max_npts:
raise ValueError('Maximum number of points exceeded:\n'
'max_npts - %d\n'
'npts - %d\n' % (max_npts, npts))
npts = np.max([npts, self.npts, other.npts])
if npts < self.npts or npts < other.npts:
raise ValueError('new npts is to small')
return x0, npts
def rearrange(self, other):
'''
Method rearrange takes another Probability Density Function and returns
a new axis with mid-point 0 and covering positive and negative range
of axis values, either containing the maximum value of both axis or
the sum of the maxima
:param other:
:return:
'''
assert isinstance(other, ProbabilityDensityFunction), \
'both operands must be of type ProbabilityDensityFunction'
if not self.incr == other.incr:
raise NotImplementedError('Upsampling of the lower sampled PDF not implemented yet!')
else:
incr = self.incr
x0, npts = self.commonlimits(incr, other)
pdf_self = np.zeros(npts)
pdf_other = np.zeros(npts)
x = create_axis(x0, incr, npts)
sstart = find_nearest(x, self.x0)
s_end = sstart + self.data.size
ostart = find_nearest(x, other.x0)
o_end = ostart + other.data.size
pdf_self = self.broadcast(pdf_self, sstart, s_end, self.data)
pdf_other = self.broadcast(pdf_other, ostart, o_end, other.data)
return x0, incr, npts, pdf_self, pdf_other

View File

@ -2,6 +2,7 @@
import sys import sys
from PySide.QtCore import QThread, Signal from PySide.QtCore import QThread, Signal
class AutoPickThread(QThread): class AutoPickThread(QThread):
message = Signal(str) message = Signal(str)
finished = Signal() finished = Signal()
@ -28,6 +29,5 @@ class AutoPickThread(QThread):
sys.stdout = sys.__stdout__ sys.stdout = sys.__stdout__
self.finished.emit() self.finished.emit()
def write(self, text): def write(self, text):
self.message.emit(text) self.message.emit(text)

View File

@ -10,6 +10,7 @@ import numpy as np
from obspy.core import UTCDateTime from obspy.core import UTCDateTime
import obspy.core.event as ope import obspy.core.event as ope
def createAmplitude(pickID, amp, unit, category, cinfo): def createAmplitude(pickID, amp, unit, category, cinfo):
''' '''
@ -28,6 +29,7 @@ def createAmplitude(pickID, amp, unit, category, cinfo):
amplitude.pick_id = pickID amplitude.pick_id = pickID
return amplitude return amplitude
def createArrival(pickresID, cinfo, phase, azimuth=None, dist=None): def createArrival(pickresID, cinfo, phase, azimuth=None, dist=None):
''' '''
createArrival - function to create an Obspy Arrival createArrival - function to create an Obspy Arrival
@ -56,6 +58,7 @@ def createArrival(pickresID, cinfo, phase, azimuth=None, dist=None):
arrival.distance = dist arrival.distance = dist
return arrival return arrival
def createCreationInfo(agency_id=None, creation_time=None, author=None): def createCreationInfo(agency_id=None, creation_time=None, author=None):
''' '''
@ -71,6 +74,7 @@ def createCreationInfo(agency_id=None, creation_time=None, author=None):
return ope.CreationInfo(agency_id=agency_id, author=author, return ope.CreationInfo(agency_id=agency_id, author=author,
creation_time=creation_time) creation_time=creation_time)
def createEvent(origintime, cinfo, originloc=None, etype=None, resID=None, def createEvent(origintime, cinfo, originloc=None, etype=None, resID=None,
authority_id=None): authority_id=None):
''' '''
@ -115,6 +119,7 @@ def createEvent(origintime, cinfo, originloc=None, etype=None, resID=None,
event.origins = [o] event.origins = [o]
return event return event
def createMagnitude(originID, cinfo): def createMagnitude(originID, cinfo):
''' '''
createMagnitude - function to create an ObsPy Magnitude object createMagnitude - function to create an ObsPy Magnitude object
@ -129,6 +134,7 @@ def createMagnitude(originID, cinfo):
magnitude.origin_id = originID magnitude.origin_id = originID
return magnitude return magnitude
def createOrigin(origintime, cinfo, latitude, longitude, depth): def createOrigin(origintime, cinfo, latitude, longitude, depth):
''' '''
createOrigin - function to create an ObsPy Origin createOrigin - function to create an ObsPy Origin
@ -158,6 +164,7 @@ def createOrigin(origintime, cinfo, latitude, longitude, depth):
origin.depth = depth origin.depth = depth
return origin return origin
def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station, def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
wfseedstr, authority_id): wfseedstr, authority_id):
''' '''
@ -196,6 +203,7 @@ def createPick(origintime, picknum, picktime, eventnum, cinfo, phase, station,
pick.waveform_id = ope.ResourceIdentifier(id=wfseedstr, prefix='file:/') pick.waveform_id = ope.ResourceIdentifier(id=wfseedstr, prefix='file:/')
return pick return pick
def createResourceID(timetohash, restype, authority_id=None, hrstr=None): def createResourceID(timetohash, restype, authority_id=None, hrstr=None):
''' '''
@ -220,6 +228,7 @@ def createResourceID(timetohash, restype, authority_id=None, hrstr=None):
resID.convertIDToQuakeMLURI(authority_id=authority_id) resID.convertIDToQuakeMLURI(authority_id=authority_id)
return resID return resID
def demeanTrace(trace, window): def demeanTrace(trace, window):
""" """
returns the DATA where each trace is demean by the average value within returns the DATA where each trace is demean by the average value within
@ -234,6 +243,7 @@ def demeanTrace(trace, window):
trace.data -= trace.data[window].mean() trace.data -= trace.data[window].mean()
return trace return trace
def findComboBoxIndex(combo_box, val): def findComboBoxIndex(combo_box, val):
""" """
Function findComboBoxIndex takes a QComboBox object and a string and Function findComboBoxIndex takes a QComboBox object and a string and
@ -246,6 +256,18 @@ def findComboBoxIndex(combo_box, val):
""" """
return combo_box.findText(val) if combo_box.findText(val) is not -1 else 0 return combo_box.findText(val) if combo_box.findText(val) is not -1 else 0
def find_nearest(array, value):
'''
Function find_nearest takes an array and a value and returns the
index of the nearest value found in the array.
:param array:
:param value:
:return:
'''
return (np.abs(array - value)).argmin()
def fnConstructor(s): def fnConstructor(s):
''' '''
@ -267,6 +289,7 @@ def fnConstructor(s):
fn = '_' + fn fn = '_' + fn
return fn return fn
def getGlobalTimes(stream): def getGlobalTimes(stream):
''' '''
@ -283,6 +306,7 @@ def getGlobalTimes(stream):
max_end = trace.stats.endtime max_end = trace.stats.endtime
return min_start, max_end return min_start, max_end
def getHash(time): def getHash(time):
''' '''
:param time: time object for which a hash should be calculated :param time: time object for which a hash should be calculated
@ -293,6 +317,7 @@ def getHash(time):
hg.update(time.strftime('%Y-%m-%d %H:%M:%S.%f')) hg.update(time.strftime('%Y-%m-%d %H:%M:%S.%f'))
return hg.hexdigest() return hg.hexdigest()
def getLogin(): def getLogin():
''' '''
@ -300,6 +325,7 @@ def getLogin():
''' '''
return pwd.getpwuid(os.getuid())[0] return pwd.getpwuid(os.getuid())[0]
def getOwner(fn): def getOwner(fn):
''' '''
@ -309,6 +335,7 @@ def getOwner(fn):
''' '''
return pwd.getpwuid(os.stat(fn).st_uid).pw_name return pwd.getpwuid(os.stat(fn).st_uid).pw_name
def getPatternLine(fn, pattern): def getPatternLine(fn, pattern):
""" """
Takes a file name and a pattern string to search for in the file and Takes a file name and a pattern string to search for in the file and
@ -333,6 +360,7 @@ def getPatternLine(fn, pattern):
return None return None
def isSorted(iterable): def isSorted(iterable):
''' '''
@ -342,6 +370,7 @@ def isSorted(iterable):
''' '''
return sorted(iterable) == iterable return sorted(iterable) == iterable
def prepTimeAxis(stime, trace): def prepTimeAxis(stime, trace):
''' '''
@ -368,6 +397,7 @@ def prepTimeAxis(stime, trace):
'delta: {2}'.format(nsamp, len(time_ax), tincr)) 'delta: {2}'.format(nsamp, len(time_ax), tincr))
return time_ax return time_ax
def scaleWFData(data, factor=None, components='all'): def scaleWFData(data, factor=None, components='all'):
""" """
produce scaled waveforms from given waveform data and a scaling factor, produce scaled waveforms from given waveform data and a scaling factor,
@ -399,6 +429,7 @@ def scaleWFData(data, factor=None, components='all'):
return data return data
def runProgram(cmd, parameter=None): def runProgram(cmd, parameter=None):
""" """
run an external program specified by cmd with parameters input returning the run an external program specified by cmd with parameters input returning the
@ -419,6 +450,8 @@ def runProgram(cmd, parameter=None):
output = subprocess.check_output('{} | tee /dev/stderr'.format(cmd), output = subprocess.check_output('{} | tee /dev/stderr'.format(cmd),
shell=True) shell=True)
if __name__ == "__main__": if __name__ == "__main__":
import doctest import doctest
doctest.testmod() doctest.testmod()

View File

@ -31,12 +31,15 @@
# #
# include RELEASE-VERSION # include RELEASE-VERSION
from __future__ import print_function
__all__ = "get_git_version" __all__ = "get_git_version"
# NO IMPORTS FROM PYLOT IN THIS FILE! (file gets used at installation time) # NO IMPORTS FROM PYLOT IN THIS FILE! (file gets used at installation time)
import os import os
import inspect import inspect
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
# NO IMPORTS FROM PYLOT IN THIS FILE! (file gets used at installation time) # NO IMPORTS FROM PYLOT IN THIS FILE! (file gets used at installation time)
script_dir = os.path.abspath(os.path.dirname(inspect.getfile( script_dir = os.path.abspath(os.path.dirname(inspect.getfile(
@ -108,4 +111,4 @@ def get_git_version(abbrev=4):
if __name__ == "__main__": if __name__ == "__main__":
print get_git_version() print(get_git_version())

View File

@ -5,10 +5,12 @@ Created on Wed Mar 19 11:27:35 2014
@author: sebastianw @author: sebastianw
""" """
import warnings
import datetime import datetime
import numpy as np import numpy as np
from matplotlib.figure import Figure from matplotlib.figure import Figure
try: try:
from matplotlib.backends.backend_qt4agg import FigureCanvas from matplotlib.backends.backend_qt4agg import FigureCanvas
except ImportError: except ImportError:
@ -25,7 +27,8 @@ from obspy import Stream, UTCDateTime
from pylot.core.read.inputs import FilterOptions from pylot.core.read.inputs import FilterOptions
from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \ from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \
getResolutionWindow getResolutionWindow
from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS, LOCTOOLS from pylot.core.util.defaults import OUTPUTFORMATS, FILTERDEFAULTS, LOCTOOLS, \
COMPPOSITION_MAP
from pylot.core.util.utils import prepTimeAxis, getGlobalTimes, scaleWFData, \ from pylot.core.util.utils import prepTimeAxis, getGlobalTimes, scaleWFData, \
demeanTrace, isSorted, findComboBoxIndex demeanTrace, isSorted, findComboBoxIndex
@ -63,7 +66,7 @@ class MPLWidget(FigureCanvas):
# clear axes each time plot is called # clear axes each time plot is called
self.axes.hold(True) self.axes.hold(True)
# initialize super class # initialize super class
FigureCanvas.__init__(self, self.figure) super(MPLWidget, self).__init__(self.figure)
# add an cursor for station selection # add an cursor for station selection
self.multiCursor = MultiCursor(self.figure.canvas, (self.axes,), self.multiCursor = MultiCursor(self.figure.canvas, (self.axes,),
horizOn=True, horizOn=True,
@ -87,13 +90,19 @@ class MPLWidget(FigureCanvas):
self._parent = parent self._parent = parent
def plotWFData(self, wfdata, title=None, zoomx=None, zoomy=None, def plotWFData(self, wfdata, title=None, zoomx=None, zoomy=None,
noiselevel=None, scaleddata=False): noiselevel=None, scaleddata=False, mapping=True):
self.getAxes().cla() self.getAxes().cla()
self.clearPlotDict() self.clearPlotDict()
wfstart, wfend = getGlobalTimes(wfdata) wfstart, wfend = getGlobalTimes(wfdata)
nmax = 0
for n, trace in enumerate(wfdata): for n, trace in enumerate(wfdata):
channel = trace.stats.channel channel = trace.stats.channel
station = trace.stats.station station = trace.stats.station
if mapping:
comp = channel[-1]
n = COMPPOSITION_MAP[comp]
if n > nmax:
nmax = n
msg = 'plotting %s channel of station %s' % (channel, station) msg = 'plotting %s channel of station %s' % (channel, station)
print(msg) print(msg)
stime = trace.stats.starttime - wfstart stime = trace.stats.starttime - wfstart
@ -110,7 +119,7 @@ class MPLWidget(FigureCanvas):
ylabel = '' ylabel = ''
self.updateWidget(xlabel, ylabel, title) self.updateWidget(xlabel, ylabel, title)
self.setXLims([0, wfend - wfstart]) self.setXLims([0, wfend - wfstart])
self.setYLims([-0.5, n + 0.5]) self.setYLims([-0.5, nmax + 0.5])
if zoomx is not None: if zoomx is not None:
self.setXLims(zoomx) self.setXLims(zoomx)
if zoomy is not None: if zoomy is not None:
@ -160,6 +169,7 @@ class MPLWidget(FigureCanvas):
xycoords='axes fraction') xycoords='axes fraction')
axann.set_bbox(dict(facecolor='lightgrey', alpha=.6)) axann.set_bbox(dict(facecolor='lightgrey', alpha=.6))
class PickDlg(QDialog): class PickDlg(QDialog):
def __init__(self, parent=None, data=None, station=None, picks=None, def __init__(self, parent=None, data=None, station=None, picks=None,
rotate=False): rotate=False):
@ -169,11 +179,14 @@ class PickDlg(QDialog):
self.station = station self.station = station
self.rotate = rotate self.rotate = rotate
self.components = 'ZNE' self.components = 'ZNE'
settings = QSettings()
self._user = settings.value('user/Login', 'anonymous')
if picks: if picks:
self.picks = picks self.picks = picks
else: else:
self.picks = {} self.picks = {}
self.filteroptions = FILTERDEFAULTS self.filteroptions = FILTERDEFAULTS
self.pick_block = False
# initialize panning attributes # initialize panning attributes
self.press = None self.press = None
@ -247,8 +260,7 @@ class PickDlg(QDialog):
slot=self.filterWFData, slot=self.filterWFData,
icon=filter_icon, icon=filter_icon,
tip='Toggle filtered/original' tip='Toggle filtered/original'
' waveforms', ' waveforms')
checkable=True)
self.zoomAction = createAction(parent=self, text='Zoom', self.zoomAction = createAction(parent=self, text='Zoom',
slot=self.zoom, icon=zoom_icon, slot=self.zoom, icon=zoom_icon,
tip='Zoom into waveform', tip='Zoom into waveform',
@ -337,6 +349,10 @@ class PickDlg(QDialog):
return widget.mpl_connect('button_release_event', slot) return widget.mpl_connect('button_release_event', slot)
def verifyPhaseSelection(self): def verifyPhaseSelection(self):
if self.pick_block:
self.pick_block = self.togglePickBlocker()
warnings.warn('Changed selection before phase was set!',
UserWarning)
phase = self.selectPhase.currentText() phase = self.selectPhase.currentText()
self.updateCurrentLimits() self.updateCurrentLimits()
if phase: if phase:
@ -348,6 +364,7 @@ class PickDlg(QDialog):
self.disconnectPressEvent() self.disconnectPressEvent()
self.cidpress = self.connectPressEvent(self.setIniPick) self.cidpress = self.connectPressEvent(self.setIniPick)
self.filterWFData() self.filterWFData()
self.pick_block = self.togglePickBlocker()
else: else:
self.disconnectPressEvent() self.disconnectPressEvent()
self.cidpress = self.connectPressEvent(self.panPress) self.cidpress = self.connectPressEvent(self.panPress)
@ -383,6 +400,9 @@ class PickDlg(QDialog):
traceIDs.append(traceID) traceIDs.append(traceID)
return traceIDs return traceIDs
def getUser(self):
return self._user
def getFilterOptions(self, phase): def getFilterOptions(self, phase):
options = self.filteroptions[phase] options = self.filteroptions[phase]
return FilterOptions(**options) return FilterOptions(**options)
@ -422,6 +442,11 @@ class PickDlg(QDialog):
trace = selectTrace(trace, 'NE') trace = selectTrace(trace, 'NE')
if trace: if trace:
wfdata.append(trace) wfdata.append(trace)
elif component == '1' or component == '2':
for trace in self.getWFData():
trace = selectTrace(trace, '12')
if trace:
wfdata.append(trace)
elif component == 'Z': elif component == 'Z':
wfdata = self.getWFData().select(component=component) wfdata = self.getWFData().select(component=component)
return wfdata return wfdata
@ -470,8 +495,22 @@ class PickDlg(QDialog):
noise_win = settings.value('picking/noise_win_P', 5.) noise_win = settings.value('picking/noise_win_P', 5.)
gap_win = settings.value('picking/gap_win_P', .2) gap_win = settings.value('picking/gap_win_P', .2)
signal_win = settings.value('picking/signal_win_P', 3.) signal_win = settings.value('picking/signal_win_P', 3.)
itrace = int(trace_number)
result = getSNR(wfdata, (noise_win, gap_win, signal_win), ini_pick) while itrace > len(wfdata) - 1:
itrace -= 1
# copy data for plotting
data = self.getWFData().copy()
# filter data and trace on which is picked prior to determination of SNR
phase = self.selectPhase.currentText()
filteroptions = self.getFilterOptions(phase).parseFilterOptions()
if filteroptions:
data.filter(**filteroptions)
wfdata.filter(**filteroptions)
result = getSNR(wfdata, (noise_win, gap_win, signal_win), ini_pick, itrace)
snr = result[0] snr = result[0]
noiselevel = result[2] * nfac noiselevel = result[2] * nfac
@ -479,8 +518,7 @@ class PickDlg(QDialog):
x_res = getResolutionWindow(snr) x_res = getResolutionWindow(snr)
# remove mean noise level from waveforms # remove mean noise level from waveforms
wfdata = self.getWFData().copy() for trace in data:
for trace in wfdata:
t = prepTimeAxis(trace.stats.starttime - self.getStartTime(), trace) t = prepTimeAxis(trace.stats.starttime - self.getStartTime(), trace)
inoise = getnoisewin(t, ini_pick, noise_win, gap_win) inoise = getnoisewin(t, ini_pick, noise_win, gap_win)
trace = demeanTrace(trace=trace, window=inoise) trace = demeanTrace(trace=trace, window=inoise)
@ -488,7 +526,7 @@ class PickDlg(QDialog):
self.setXLims([ini_pick - x_res, ini_pick + x_res]) self.setXLims([ini_pick - x_res, ini_pick + x_res])
self.setYLims(np.array([-noiselevel * 2.5, noiselevel * 2.5]) + self.setYLims(np.array([-noiselevel * 2.5, noiselevel * 2.5]) +
trace_number) trace_number)
self.getPlotWidget().plotWFData(wfdata=wfdata, self.getPlotWidget().plotWFData(wfdata=data,
title=self.getStation() + title=self.getStation() +
' picking mode', ' picking mode',
zoomx=self.getXLims(), zoomx=self.getXLims(),
@ -502,29 +540,39 @@ class PickDlg(QDialog):
settings = QSettings() settings = QSettings()
nfac = settings.value('picking/nfac_P', 1.5) nfac = settings.value('picking/nfac_S', 1.5)
noise_win = settings.value('picking/noise_win_P', 5.) noise_win = settings.value('picking/noise_win_S', 5.)
gap_win = settings.value('picking/gap_win_P', .2) gap_win = settings.value('picking/gap_win_S', .2)
signal_win = settings.value('picking/signal_win_P', 3.) signal_win = settings.value('picking/signal_win_S', 3.)
# copy data for plotting
data = self.getWFData().copy()
# filter data and trace on which is picked prior to determination of SNR
phase = self.selectPhase.currentText()
filteroptions = self.getFilterOptions(phase).parseFilterOptions()
if filteroptions:
data.filter(**filteroptions)
wfdata.filter(**filteroptions)
# determine SNR and noiselevel
result = getSNR(wfdata, (noise_win, gap_win, signal_win), ini_pick) result = getSNR(wfdata, (noise_win, gap_win, signal_win), ini_pick)
snr = result[0] snr = result[0]
noiselevel = result[2] * nfac noiselevel = result[2] * nfac
data = self.getWFData().copy() # prepare plotting of data
phase = self.selectPhase.currentText()
filteroptions = self.getFilterOptions(phase).parseFilterOptions()
data.filter(**filteroptions)
for trace in data: for trace in data:
t = prepTimeAxis(trace.stats.starttime - self.getStartTime(), trace) t = prepTimeAxis(trace.stats.starttime - self.getStartTime(), trace)
inoise = getnoisewin(t, ini_pick, noise_win, gap_win) inoise = getnoisewin(t, ini_pick, noise_win, gap_win)
trace = demeanTrace(trace, inoise) trace = demeanTrace(trace, inoise)
# account for non-oriented horizontal waveforms
try:
horiz_comp = ('n', 'e') horiz_comp = ('n', 'e')
data = scaleWFData(data, noiselevel * 2.5, horiz_comp)
except IndexError as e:
print('warning: {0}'.format(e))
horiz_comp = ('1', '2')
data = scaleWFData(data, noiselevel * 2.5, horiz_comp) data = scaleWFData(data, noiselevel * 2.5, horiz_comp)
x_res = getResolutionWindow(snr) x_res = getResolutionWindow(snr)
@ -554,21 +602,28 @@ class PickDlg(QDialog):
pick = gui_event.xdata # get pick time relative to the traces timeaxis not to the global pick = gui_event.xdata # get pick time relative to the traces timeaxis not to the global
channel = self.getChannelID(round(gui_event.ydata)) channel = self.getChannelID(round(gui_event.ydata))
wfdata = self.getWFData().copy().select(channel=channel)
stime = self.getStartTime()
# get earliest and latest possible pick and symmetric pick error
[epp, lpp, spe] = earllatepicker(wfdata, 1.5, (5., .5, 2.), pick)
# get name of phase actually picked # get name of phase actually picked
phase = self.selectPhase.currentText() phase = self.selectPhase.currentText()
# get filter parameter for the phase to be picked
filteroptions = self.getFilterOptions(phase).parseFilterOptions()
# copy and filter data for earliest and latest possible picks
wfdata = self.getWFData().copy().select(channel=channel)
wfdata.filter(**filteroptions)
# get earliest and latest possible pick and symmetric pick error
[epp, lpp, spe] = earllatepicker(wfdata, 1.5, (5., .5, 2.), pick)
# return absolute time values for phases # return absolute time values for phases
stime = self.getStartTime()
epp = stime + epp epp = stime + epp
mpp = stime + pick mpp = stime + pick
lpp = stime + lpp lpp = stime + lpp
# save pick times for actual phase # save pick times for actual phase
phasepicks = {'epp': epp, 'lpp': lpp, 'mpp': mpp, 'spe': spe} phasepicks = dict(epp=epp, lpp=lpp, mpp=mpp, spe=spe,
picker=self.getUser())
try: try:
oldphasepick = self.picks[phase] oldphasepick = self.picks[phase]
@ -601,6 +656,7 @@ class PickDlg(QDialog):
self.drawPicks() self.drawPicks()
self.disconnectPressEvent() self.disconnectPressEvent()
self.zoomAction.setEnabled(True) self.zoomAction.setEnabled(True)
self.pick_block = self.togglePickBlocker()
self.selectPhase.setCurrentIndex(-1) self.selectPhase.setCurrentIndex(-1)
self.setPlotLabels() self.setPlotLabels()
@ -660,7 +716,12 @@ class PickDlg(QDialog):
ax.figure.canvas.draw() ax.figure.canvas.draw()
def togglePickBlocker(self):
return not self.pick_block
def filterWFData(self): def filterWFData(self):
if self.pick_block:
return
self.updateCurrentLimits() self.updateCurrentLimits()
data = self.getWFData().copy() data = self.getWFData().copy()
old_title = self.getPlotWidget().getAxes().get_title() old_title = self.getPlotWidget().getAxes().get_title()
@ -675,13 +736,15 @@ class PickDlg(QDialog):
filtoptions = filtoptions.parseFilterOptions() filtoptions = filtoptions.parseFilterOptions()
if filtoptions is not None: if filtoptions is not None:
data.filter(**filtoptions) data.filter(**filtoptions)
if old_title.endswith(')'): if not old_title.endswith(')'):
title = old_title[:-1] + ', filtered)'
else:
title = old_title + ' (filtered)' title = old_title + ' (filtered)'
elif not old_title.endswith(' (filtered)') and not old_title.endswith(', filtered)'):
title = old_title[:-1] + ', filtered)'
else: else:
if old_title.endswith(' (filtered)'): if old_title.endswith(' (filtered)'):
title = old_title.replace(' (filtered)', '') title = old_title.replace(' (filtered)', '')
elif old_title.endswith(', filtered)'):
title = old_title.replace(', filtered)', ')')
if title is None: if title is None:
title = old_title title = old_title
self.getPlotWidget().plotWFData(wfdata=data, title=title, self.getPlotWidget().plotWFData(wfdata=data, title=title,
@ -702,7 +765,6 @@ class PickDlg(QDialog):
self.drawPicks() self.drawPicks()
self.draw() self.draw()
def setPlotLabels(self): def setPlotLabels(self):
# get channel labels # get channel labels
@ -715,7 +777,9 @@ class PickDlg(QDialog):
self.getPlotWidget().setYLims(self.getYLims()) self.getPlotWidget().setYLims(self.getYLims())
def zoom(self): def zoom(self):
if self.zoomAction.isChecked(): if self.zoomAction.isChecked() and self.pick_block:
self.zoomAction.setChecked(False)
elif self.zoomAction.isChecked():
self.disconnectPressEvent() self.disconnectPressEvent()
self.disconnectMotionEvent() self.disconnectMotionEvent()
self.disconnectReleaseEvent() self.disconnectReleaseEvent()
@ -995,7 +1059,6 @@ class LocalisationTab(PropTab):
return values return values
class NewEventDlg(QDialog): class NewEventDlg(QDialog):
def __init__(self, parent=None, titleString="Create a new event"): def __init__(self, parent=None, titleString="Create a new event"):
""" """
@ -1236,6 +1299,8 @@ class HelpForm(QDialog):
def updatePageTitle(self): def updatePageTitle(self):
self.pageLabel.setText(self.webBrowser.documentTitle()) self.pageLabel.setText(self.webBrowser.documentTitle())
if __name__ == '__main__': if __name__ == '__main__':
import doctest import doctest
doctest.testmod() doctest.testmod()

View File

@ -9,8 +9,8 @@
from obspy.core import read from obspy.core import read
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
from pylot.core.pick.CharFuns import * from pylot.core.pick.charfuns import *
from pylot.core.pick.Picker import * from pylot.core.pick.picker import *
import glob import glob
import argparse import argparse