Merge branch 'develop' of ariadne.geophysik.ruhr-uni-bochum.de:/data/git/pylot into develop

This commit is contained in:
marcel 2017-06-28 09:27:21 +02:00
commit b140dd4f53
15 changed files with 1324 additions and 488 deletions

File diff suppressed because it is too large Load Diff

View File

@ -16,9 +16,9 @@ import pylot.core.loc.focmec as focmec
import pylot.core.loc.hash as hash
import pylot.core.loc.nll as nll
#from PySide.QtGui import QWidget, QInputDialog
from pylot.core.analysis.magnitude import MomentMagnitude, RichterMagnitude
from pylot.core.analysis.magnitude import MomentMagnitude, LocalMagnitude
from pylot.core.io.data import Data
from pylot.core.io.inputs import AutoPickParameter
from pylot.core.io.inputs import PylotParameter
from pylot.core.pick.autopick import autopickevent, iteratepicker
from pylot.core.util.dataprocessing import restitute_data, read_metadata, \
remove_underscores
@ -35,7 +35,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
:param inputfile: path to the input file containing all parameter
information for automatic picking (for formatting details, see.
`~pylot.core.io.inputs.AutoPickParameter`
`~pylot.core.io.inputs.PylotParameter`
:type inputfile: str
:return:
@ -71,13 +71,13 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
if not parameter:
if inputfile:
parameter = AutoPickParameter(inputfile)
parameter = PylotParameter(inputfile)
iplot = parameter['iplot']
else:
print('No parameters set and no input file given. Choose either of both.')
return
else:
if not type(parameter) == AutoPickParameter:
if not type(parameter) == PylotParameter:
print('Wrong input type for parameter: {}'.format(type(parameter)))
return
if inputfile:
@ -98,8 +98,8 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
exf = ['root', 'dpath', 'dbase']
if parameter.hasParam('eventID') and fnames == 'None':
dsfields['eventID'] = parameter.get('eventID')
if parameter['eventID'] is not '*' and fnames == 'None':
dsfields['eventID'] = parameter['eventID']
exf.append('eventID')
datastructure.modifyFields(**dsfields)
@ -130,20 +130,34 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
print("!!No source parameter estimation possible!!")
print(" !!! ")
datapath = datastructure.expandDataPath()
if fnames == 'None' and not parameter.hasParam('eventID'):
# multiple event processing
# read each event in database
events = [events for events in glob.glob(os.path.join(datapath, '*')) if os.path.isdir(events)]
elif fnames == 'None' and parameter.hasParam('eventID'):
# single event processing
events = glob.glob(os.path.join(datapath, parameter.get('eventID')))
if not input_dict:
# started in production mode
datapath = datastructure.expandDataPath()
if fnames == 'None' and parameter['eventID'] is '*':
# multiple event processing
# read each event in database
events = [events for events in glob.glob(os.path.join(datapath, '*')) if os.path.isdir(events)]
elif fnames == 'None' and parameter['eventID'] is not '*':
# single event processing
events = glob.glob(os.path.join(datapath, parameter['eventID']))
else:
# autoPyLoT was initialized from GUI
events = []
events.append(eventid)
evID = os.path.split(eventid)[-1]
locflag = 2
else:
# autoPyLoT was initialized from GUI
# started in tune mode
datapath = os.path.join(parameter['rootpath'],
parameter['datapath'])
events = []
events.append(eventid)
evID = os.path.split(eventid)[-1]
locflag = 2
events.append(os.path.join(datapath,
parameter['database'],
parameter['eventID']))
if not events:
print('autoPyLoT: No events given. Return!')
return
for event in events:
if fnames == 'None':
@ -229,7 +243,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
# get latest NLLoc-location file if several are available
nllocfile = max(glob.glob(locsearch), key=os.path.getctime)
evt = read_events(nllocfile)[0]
# calculating seismic moment Mo and moment magnitude Mw
# calculate seismic moment Mo and moment magnitude Mw
moment_mag = MomentMagnitude(corr_dat, evt, parameter.get('vp'),
parameter.get('Qp'),
parameter.get('rho'), True, \
@ -238,15 +252,29 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
for station, props in moment_mag.moment_props.items():
picks[station]['P'].update(props)
evt = moment_mag.updated_event()
local_mag = RichterMagnitude(corr_dat, evt,
parameter.get('sstop'), True,\
iplot)
net_mw = moment_mag.net_magnitude()
print("Network moment magnitude: %4.1f" % net_mw.mag)
# calculate local (Richter) magntiude
WAscaling = parameter.get('WAscaling')
magscaling = parameter.get('magscaling')
local_mag = LocalMagnitude(corr_dat, evt,
parameter.get('sstop'),
WAscaling, True, iplot)
for station, amplitude in local_mag.amplitudes.items():
picks[station]['S']['Ao'] = amplitude.generic_amplitude
evt = local_mag.updated_event()
print("Local station magnitudes scaled with:")
print("log(Ao) + %f * log(r) + %f * r + %f" % (WAscaling[0],
WAscaling[1],
WAscaling[2]))
evt = local_mag.updated_event(magscaling)
net_ml = local_mag.net_magnitude(magscaling)
print("Network local magnitude: %4.1f" % net_ml.mag)
print("Network local magnitude scaled with:")
print("%f * Ml + %f" % (magscaling[0], magscaling[1]))
else:
print("autoPyLoT: No NLLoc-location file available!")
print("No source parameter estimation possible!")
locflag = 9
else:
# get theoretical P-onset times from NLLoc-location file
locsearch = '%s/loc/%s.????????.??????.grid?.loc.hyp' % (nllocroot, nllocout)
@ -287,7 +315,7 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
nlloccounter = maxnumit
evt = read_events(nllocfile)[0]
if locflag < 2:
# calculating seismic moment Mo and moment magnitude Mw
# calculate seismic moment Mo and moment magnitude Mw
moment_mag = MomentMagnitude(corr_dat, evt, parameter.get('vp'),
parameter.get('Qp'),
parameter.get('rho'), True, \
@ -296,14 +324,25 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
for station, props in moment_mag.moment_props.items():
picks[station]['P'].update(props)
evt = moment_mag.updated_event()
local_mag = RichterMagnitude(corr_dat, evt,
parameter.get('sstop'), True, \
iplot)
for station, amplitude in local_mag.amplitudes.items():
picks[station]['S']['Ao'] = amplitude.generic_amplitude
evt = local_mag.updated_event()
net_mw = moment_mag.net_magnitude()
print("Network moment magnitude: %4.1f" % net_mw.mag)
# calculate local (Richter) magntiude
WAscaling = parameter.get('WAscaling')
magscaling = parameter.get('magscaling')
local_mag = LocalMagnitude(corr_dat, evt,
parameter.get('sstop'),
WAscaling, True, iplot)
for station, amplitude in local_mag.amplitudes.items():
picks[station]['S']['Ao'] = amplitude.generic_amplitude
print("Local station magnitudes scaled with:")
print("log(Ao) + %f * log(r) + %f * r + %f" % (WAscaling[0],
WAscaling[1],
WAscaling[2]))
evt = local_mag.updated_event(magscaling)
net_ml = local_mag.net_magnitude(magscaling)
print("Network local magnitude: %4.1f" % net_ml.mag)
print("Network local magnitude scaled with:")
print("%f * Ml + %f" % (magscaling[0], magscaling[1]))
else:
print("autoPyLoT: No NLLoc-location file available! Stop iteration!")
locflag = 9
@ -314,26 +353,26 @@ def autoPyLoT(input_dict=None, parameter=None, inputfile=None, fnames=None, even
data.applyEVTData(picks)
if evt is not None:
data.applyEVTData(evt, 'event')
fnqml = '%s/autoPyLoT' % event
data.exportEvent(fnqml)
# HYPO71
hypo71file = '%s/autoPyLoT_HYPO71_phases' % event
hypo71.export(picks, hypo71file, parameter)
# HYPOSAT
hyposatfile = '%s/autoPyLoT_HYPOSAT_phases' % event
hyposat.export(picks, hyposatfile, parameter)
fnqml = '%s/PyLoT_%s' % (event, evID)
data.exportEvent(fnqml, fnext='.xml', fcheck='manual')
if locflag == 1:
# HYPO71
hypo71file = '%s/PyLoT_%s_HYPO71_phases' % (event, evID)
hypo71.export(picks, hypo71file, parameter)
# HYPOSAT
hyposatfile = '%s/PyLoT_%s_HYPOSAT_phases' % (event, evID)
hyposat.export(picks, hyposatfile, parameter)
# VELEST
velestfile = '%s/autoPyLoT_VELEST_phases.cnv' % event
velestfile = '%s/PyLoT_%s_VELEST_phases.cnv' % (event, evID)
velest.export(picks, velestfile, parameter, evt)
# hypoDD
hypoddfile = '%s/autoPyLoT_hypoDD_phases.pha' % event
hypoddfile = '%s/PyLoT_%s_hypoDD_phases.pha' % (event, evID)
hypodd.export(picks, hypoddfile, parameter, evt)
# FOCMEC
focmecfile = '%s/autoPyLoT_FOCMEC.in' % event
focmecfile = '%s/PyLoT_%s_FOCMEC.in' % (event, evID)
focmec.export(picks, focmecfile, parameter, evt)
# HASH
hashfile = '%s/autoPyLoT_HASH' % event
hashfile = '%s/PyLoT_%s_HASH' % (event, evID)
hash.export(picks, hashfile, parameter, evt)
endsplash = '''------------------------------------------\n'
@ -385,9 +424,5 @@ if __name__ == "__main__":
cla = parser.parse_args()
try:
picks, mainFig = autoPyLoT(inputfile=str(cla.inputfile), fnames=str(cla.fnames),
eventid=str(cla.eventid), savepath=str(cla.spath))
except ValueError:
print("autoPyLoT was running in production mode.")
picks = autoPyLoT(inputfile=str(cla.inputfile), fnames=str(cla.fnames),
eventid=str(cla.eventid), savepath=str(cla.spath))

View File

@ -1 +0,0 @@
0af79-dirty

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
"""
Created autumn/winter 2015.
Revised/extended summer 2017.
:author: Ludger Küperkoch / MAGS2 EP3 working group
"""
@ -17,10 +18,17 @@ from pylot.core.pick.utils import getsignalwin, crossings_nonzero_all, \
from pylot.core.util.utils import common_range, fit_curve
def richter_magnitude_scaling(delta):
relation = np.loadtxt(os.path.join(os.path.expanduser('~'),
'.pylot', 'richter_scaling.data'))
distance = np.array([0, 10, 20, 25, 30, 35,40, 45, 50, 60, 70, 75, 85, 90, 100, 110,
120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 230, 240, 250,
260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380,
390, 400, 430, 470, 510, 560, 600, 700, 800, 900, 1000])
richter_scaling = np.array([1.4, 1.5, 1.7, 1.9, 2.1, 2.3, 2.4, 2.5, 2.6, 2.8, 2.8, 2.9,
2.9, 3.0, 3.1, 3.1, 3.2, 3.2, 3.3, 3.3, 3.4, 3.4, 3.5, 3.5,
3.6, 3.7, 3.7, 3.8, 3.8, 3.9, 3.9, 4.0, 4.0, 4.1, 4.2, 4.2,
4.2, 4.2, 4.3, 4.3, 4.3, 4.4, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9,
5.1, 5.2, 5.4, 5.5, 5.7])
# prepare spline interpolation to calculate return value
func, params = fit_curve(relation[:, 0], relation[:, 1])
func, params = fit_curve(distance, richter_scaling)
return func(delta, params)
@ -31,10 +39,10 @@ class Magnitude(object):
def __init__(self, stream, event, verbosity=False, iplot=0):
self._type = "M"
self._stream = stream
self._plot_flag = iplot
self._verbosity = verbosity
self._event = event
self._stream = stream
self._magnitudes = dict()
def __str__(self):
@ -108,28 +116,35 @@ class Magnitude(object):
def calc(self):
pass
def updated_event(self):
self.event.magnitudes.append(self.net_magnitude())
def updated_event(self, magscaling=None):
self.event.magnitudes.append(self.net_magnitude(magscaling))
return self.event
def net_magnitude(self):
def net_magnitude(self, magscaling=None):
if self:
# TODO if an average Magnitude instead of the median is calculated
# StationMagnitudeContributions should be added to the returned
# Magnitude object
# mag_error => weights (magnitude error estimate from peak_to_peak, calcsourcespec?)
# weights => StationMagnitdeContribution
mag = ope.Magnitude(
mag=np.median([M.mag for M in self.magnitudes.values()]),
magnitude_type=self.type,
origin_id=self.origin_id,
station_count=len(self.magnitudes),
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
if magscaling is not None and str(magscaling) is not '[0.0, 0.0]':
# scaling necessary
print("Scaling network magnitude ...")
mag = ope.Magnitude(
mag=np.median([M.mag for M in self.magnitudes.values()]) *\
magscaling[0] + magscaling[1],
magnitude_type=self.type,
origin_id=self.origin_id,
station_count=len(self.magnitudes),
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
else:
# no saling necessary
mag = ope.Magnitude(
mag=np.median([M.mag for M in self.magnitudes.values()]),
magnitude_type=self.type,
origin_id=self.origin_id,
station_count=len(self.magnitudes),
azimuthal_gap=self.origin_id.get_referred_object().quality.azimuthal_gap)
return mag
return None
class RichterMagnitude(Magnitude):
class LocalMagnitude(Magnitude):
"""
Method to derive peak-to-peak amplitude as seen on a Wood-Anderson-
seismograph. Has to be derived from instrument corrected traces!
@ -146,10 +161,11 @@ class RichterMagnitude(Magnitude):
_amplitudes = dict()
def __init__(self, stream, event, calc_win, verbosity=False, iplot=0):
super(RichterMagnitude, self).__init__(stream, event, verbosity, iplot)
def __init__(self, stream, event, calc_win, wascaling, verbosity=False, iplot=0):
super(LocalMagnitude, self).__init__(stream, event, verbosity, iplot)
self._calc_win = calc_win
self._wascaling = wascaling
self._type = 'ML'
self.calc()
@ -161,6 +177,10 @@ class RichterMagnitude(Magnitude):
def calc_win(self, value):
self._calc_win = value
@property
def wascaling(self):
return self._wascaling
@property
def amplitudes(self):
return self._amplitudes
@ -195,6 +215,8 @@ class RichterMagnitude(Magnitude):
th = np.arange(0, len(sqH) * dt, dt)
# get maximum peak within pick window
iwin = getsignalwin(th, t0 - stime, self.calc_win)
ii = min([iwin[len(iwin)-1], len(th)])
iwin = iwin[0:ii]
wapp = np.max(sqH[iwin])
if self.verbose:
print("Determined Wood-Anderson peak-to-peak amplitude for station {0}: {1} "
@ -244,10 +266,17 @@ class RichterMagnitude(Magnitude):
self.event.amplitudes.append(amplitude)
self.amplitudes = (station, amplitude)
# using standard Gutenberg-Richter relation
# TODO make the ML calculation more flexible by allowing
# use of custom relation functions
magnitude = ope.StationMagnitude(
mag=np.log10(a0) + richter_magnitude_scaling(delta))
# or scale WA amplitude with given scaling relation
if str(self.wascaling) == '[0.0, 0.0, 0.0]':
print("Calculating original Richter magnitude ...")
magnitude = ope.StationMagnitude(mag=np.log10(a0) \
+ richter_magnitude_scaling(delta))
else:
print("Calculating scaled local magnitude ...")
a0 = a0 * 1e03 # mm to nm (see Havskov & Ottemöller, 2010)
magnitude = ope.StationMagnitude(mag=np.log10(a0) \
+ self.wascaling[0] * np.log10(delta) + self.wascaling[1]
* delta + self.wascaling[2])
magnitude.origin_id = self.origin_id
magnitude.waveform_id = pick.waveform_id
magnitude.amplitude_id = amplitude.resource_id

View File

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

View File

@ -14,7 +14,7 @@ defaults = {'rootpath': {'type': str,
'value': ''},
'eventID': {'type': str,
'tooltip': 'event ID for single event processing',
'tooltip': 'event ID for single event processing (* for all events found in database)',
'value': ''},
'extent': {'type': str,
@ -275,7 +275,17 @@ defaults = {'rootpath': {'type': str,
'wdttolerance': {'type': float,
'tooltip': 'maximum allowed deviation from Wadati-diagram',
'value': 1.0}
'value': 1.0},
'WAscaling': {'type': (float, float, float),
'tooltip': 'Scaling relation (log(Ao)+Alog(r)+Br+C) of Wood-Anderson amplitude Ao [nm] \
If zeros are set, original Richter magnitude is calculated!',
'value': (0., 0., 0.)},
'magscaling': {'type': (float, float),
'tooltip': 'Scaling relation for derived local magnitude [a*Ml+b]. \
If zeros are set, no scaling of network magnitude is applied!',
'value': (0., 0.)}
}
settings_main={
@ -298,6 +308,9 @@ settings_main={
'vp',
'rho',
'Qp'],
'localmag':[
'WAscaling',
'magscaling'],
'pick':[
'extent',
'pstart',

View File

@ -4,9 +4,9 @@
from pylot.core.util.errors import ParameterError
import default_parameters
class AutoPickParameter(object):
class PylotParameter(object):
'''
AutoPickParameters is a parameter type object capable to read and/or write
PylotParameter is a parameter type object capable to read and/or write
parameter ASCII.
:param fn str: Filename of the input file
@ -78,7 +78,7 @@ class AutoPickParameter(object):
# String representation of the object
def __repr__(self):
return "AutoPickParameter('%s')" % self.__filename
return "PylotParameter('%s')" % self.__filename
# Boolean test
def __nonzero__(self):
@ -140,6 +140,7 @@ class AutoPickParameter(object):
all_names += self.get_main_para_names()['dirs']
all_names += self.get_main_para_names()['nlloc']
all_names += self.get_main_para_names()['smoment']
all_names += self.get_main_para_names()['localmag']
all_names += self.get_main_para_names()['pick']
all_names += self.get_special_para_names()['z']
all_names += self.get_special_para_names()['h']
@ -220,22 +221,23 @@ class AutoPickParameter(object):
# for key, value in self.iteritems():
# lines.append('{key}\t{value}\n'.format(key=key, value=value))
# fid_out.writelines(lines)
header = ('%This is a parameter input file for PyLoT/autoPyLoT.\n'+
'%All main and special settings regarding data handling\n'+
'%and picking are to be set here!\n'+
'%Parameters are optimized for local data sets!\n')
seperator = '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n'
'%Parameters are optimized for %{} data sets!\n'.format(self.get_main_para_names()['pick'][0]))
separator = '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n'
fid_out.write(header)
self.write_section(fid_out, self.get_main_para_names()['dirs'],
'main settings', seperator)
'main settings', separator)
self.write_section(fid_out, self.get_main_para_names()['nlloc'],
'NLLoc settings', seperator)
'NLLoc settings', separator)
self.write_section(fid_out, self.get_main_para_names()['smoment'],
'parameters for seismic moment estimation', seperator)
'parameters for seismic moment estimation', separator)
self.write_section(fid_out, self.get_main_para_names()['localmag'],
'settings local magnitude', separator)
self.write_section(fid_out, self.get_main_para_names()['pick'],
'common settings picker', seperator)
'common settings picker', separator)
fid_out.write(('#special settings for calculating CF#\n'+
'%!!Edit the following only if you know what you are doing!!%\n'))
self.write_section(fid_out, self.get_special_para_names()['z'],
@ -247,9 +249,9 @@ class AutoPickParameter(object):
self.write_section(fid_out, self.get_special_para_names()['quality'],
'quality assessment', None)
def write_section(self, fid, names, title, seperator):
if seperator:
fid.write(seperator)
def write_section(self, fid, names, title, separator):
if separator:
fid.write(separator)
fid.write('#{}#\n'.format(title))
l_val = 50
l_name = 15

View File

@ -7,8 +7,9 @@ import os
import scipy.io as sio
import warnings
from obspy.core import UTCDateTime
from obspy.core.util import AttribDict
from pylot.core.io.inputs import AutoPickParameter
from pylot.core.io.inputs import PylotParameter
from pylot.core.io.location import create_arrival, create_event, \
create_magnitude, create_origin, create_pick
from pylot.core.pick.utils import select_for_phase
@ -116,7 +117,7 @@ def picksdict_from_pilot(fn):
picks = dict()
phases_pilot = sio.loadmat(fn)
stations = stations_from_pilot(phases_pilot['stat'])
params = AutoPickParameter(TIMEERROR_DEFAULTS)
params = PylotParameter(TIMEERROR_DEFAULTS)
timeerrors = dict(P=params.get('timeerrorsP'),
S=params.get('timeerrorsS'))
for n, station in enumerate(stations):
@ -195,6 +196,7 @@ def picksdict_from_picks(evt):
phase = {}
station = pick.waveform_id.station_code
channel = pick.waveform_id.channel_code
network = pick.waveform_id.network_code
try:
onsets = picks[station]
except KeyError as e:
@ -215,6 +217,7 @@ def picksdict_from_picks(evt):
phase['lpp'] = lpp
phase['spe'] = spe
phase['channel'] = channel
phase['network'] = network
try:
picker = str(pick.method_id)
if picker.startswith('smi:local/'):
@ -231,7 +234,7 @@ def picks_from_picksdict(picks, creation_info=None):
picks_list = list()
for station, onsets in picks.items():
for label, phase in onsets.items():
if not isinstance(phase, dict):
if not isinstance(phase, dict) and not isinstance(phase, AttribDict):
continue
onset = phase['mpp']
try:
@ -295,14 +298,14 @@ def reassess_pilot_db(root_dir, db_dir, out_dir=None, fn_param=None, verbosity=0
def reassess_pilot_event(root_dir, db_dir, event_id, out_dir=None, fn_param=None, verbosity=0):
from obspy import read
from pylot.core.io.inputs import AutoPickParameter
from pylot.core.io.inputs import PylotParameter
from pylot.core.pick.utils import earllatepicker
if fn_param is None:
import pylot.core.util.defaults as defaults
fn_param = defaults.AUTOMATIC_DEFAULTS
default = AutoPickParameter(fn_param, verbosity)
default = PylotParameter(fn_param, verbosity)
search_base = os.path.join(root_dir, db_dir, event_id)
phases_file = glob.glob(os.path.join(search_base, 'PHASES.mat'))
@ -382,12 +385,12 @@ def reassess_pilot_event(root_dir, db_dir, event_id, out_dir=None, fn_param=None
evt.picks = picks_from_picksdict(picks_dict)
# write phase information to file
if not out_dir:
fnout_prefix = os.path.join(root_dir, db_dir, event_id, '{0}.'.format(event_id))
fnout_prefix = os.path.join(root_dir, db_dir, event_id, 'PyLoT_{0}.'.format(event_id))
else:
out_dir = os.path.join(out_dir, db_dir)
if not os.path.isdir(out_dir):
os.makedirs(out_dir)
fnout_prefix = os.path.join(out_dir, '{0}.'.format(event_id))
fnout_prefix = os.path.join(out_dir, 'PyLoT_{0}.'.format(event_id))
evt.write(fnout_prefix + 'xml', format='QUAKEML')
#evt.write(fnout_prefix + 'cnv', format='VELEST')
@ -835,9 +838,10 @@ def merge_picks(event, picks):
err = pick.time_errors
phase = pick.phase_hint
station = pick.waveform_id.station_code
network = pick.waveform_id.network_code
method = pick.method_id
for p in event.picks:
if p.waveform_id.station_code == station and p.phase_hint == phase:
p.time, p.time_errors, p.method_id = time, err, method
del time, err, phase, station, method
p.time, p.time_errors, p.waveform_id.network_code, p.method_id = time, err, network, method
del time, err, phase, station, network, method
return event

View File

@ -11,7 +11,7 @@ function conglomerate utils.
import matplotlib.pyplot as plt
import numpy as np
from pylot.core.io.inputs import AutoPickParameter
from pylot.core.io.inputs import PylotParameter
from pylot.core.pick.picker import AICPicker, PragPicker
from pylot.core.pick.charfuns import CharacteristicFunction
from pylot.core.pick.charfuns import HOScf, AICcf, ARZcf, ARHcf, AR3Ccf
@ -81,7 +81,7 @@ def autopickstation(wfstream, pickparam, verbose=False, iplot=0, fig_dict=None):
:param pickparam: container of picking parameters from input file,
usually autoPyLoT.in
:type pickparam: AutoPickParameter
:type pickparam: PylotParameter
:param verbose:
:type verbose: bool

View File

@ -212,6 +212,14 @@ class AICPicker(AutoPicker):
self.Data[0].data = self.Data[0].data * 1000000
# get signal window
isignal = getsignalwin(self.Tcf, self.Pick, self.TSNR[2])
ii = min([isignal[len(isignal)-1], len(self.Tcf)])
isignal = isignal[0:ii]
try:
aic[isignal]
except IndexError as e:
msg = "Time series out of bounds! {}".format(e)
print(msg)
return
# calculate SNR from CF
self.SNR = max(abs(aic[isignal] - np.mean(aic[isignal]))) / \
max(abs(aic[inoise] - np.mean(aic[inoise])))
@ -223,28 +231,29 @@ class AICPicker(AutoPicker):
# find maximum within slope determination window
# 'cause slope should be calculated up to first local minimum only!
imax = np.argmax(self.Data[0].data[islope])
if imax == 0:
print('AICPicker: Maximum for slope determination right at the beginning of the window!')
print('Choose longer slope determination window!')
if self.iplot > 1:
if not self.fig:
fig = plt.figure() #self.iplot) ### WHY? MP MP
else:
fig = self.fig
ax = fig.add_subplot(111)
x = self.Data[0].data
ax.plot(self.Tcf, x / max(x), 'k', legend='(HOS-/AR-) Data')
ax.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', legend='Smoothed AIC-CF')
ax.legend()
ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
ax.set_yticks([])
ax.set_title(self.Data[0].stats.station)
return
iislope = islope[0][0:imax]
if len(iislope) <= 3:
if len(iislope) <= 2:
# calculate slope from initial onset to maximum of AIC function
print("AICPicker: Not enough data samples left for slope calculation!")
print("Calculating slope from initial onset to maximum of AIC function ...")
imax = np.argmax(aicsmooth[islope])
if imax == 0:
print("AICPicker: Maximum for slope determination right at the beginning of the window!")
print("Choose longer slope determination window!")
if self.iplot > 1:
if not self.fig:
fig = plt.figure() #self.iplot) ### WHY? MP MP
else:
fig = self.fig
ax = fig.add_subplot(111)
x = self.Data[0].data
ax.plot(self.Tcf, x / max(x), 'k', label='(HOS-/AR-) Data')
ax.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', label='Smoothed AIC-CF')
ax.legend()
ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime)
ax.set_yticks([])
ax.set_title(self.Data[0].stats.station)
return
iislope = islope[0][0:imax]
dataslope = self.Data[0].data[iislope]
# calculate slope as polynomal fit of order 1

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

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

View File

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

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
import sys
import sys, os
from PySide.QtCore import QThread, Signal, Qt
from PySide.QtGui import QDialog, QProgressBar, QLabel, QHBoxLayout
@ -64,7 +64,9 @@ class Thread(QThread):
except Exception as e:
self._executed = False
self._executedError = e
print(e)
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print('Exception: {}, file: {}, line: {}'.format(exc_type, fname, exc_tb.tb_lineno))
sys.stdout = sys.__stdout__
def __del__(self):

View File

@ -10,7 +10,7 @@ import re
import warnings
import subprocess
from obspy import UTCDateTime, read
from pylot.core.io.inputs import AutoPickParameter
from pylot.core.io.inputs import PylotParameter
def _pickle_method(m):
@ -497,7 +497,7 @@ def which(program, infile=None):
bpath = os.path.join(os.path.expanduser('~'), '.pylot', infile)
if os.path.exists(bpath):
nllocpath = ":" + AutoPickParameter(bpath).get('nllocbin')
nllocpath = ":" + PylotParameter(bpath).get('nllocbin')
os.environ['PATH'] += nllocpath
except ImportError as e:
print(e.message)

View File

@ -12,6 +12,11 @@ import copy
import datetime
import numpy as np
try:
import pyqtgraph as pg
except:
pg = None
from matplotlib.figure import Figure
from pylot.core.util.utils import find_horizontals
@ -31,7 +36,7 @@ from PySide.QtCore import QSettings, Qt, QUrl, Signal, Slot
from PySide.QtWebKit import QWebView
from obspy import Stream, UTCDateTime
from pylot.core.io.data import Data
from pylot.core.io.inputs import FilterOptions, AutoPickParameter
from pylot.core.io.inputs import FilterOptions, PylotParameter
from pylot.core.pick.utils import getSNR, earllatepicker, getnoisewin, \
getResolutionWindow
from pylot.core.pick.compare import Comparison
@ -42,6 +47,12 @@ from autoPyLoT import autoPyLoT
from pylot.core.util.thread import Thread
import icons_rc
if pg:
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')
pg.setConfigOptions(antialias=True)
#pg.setConfigOption('leftButtonPan', False)
def getDataType(parent):
type = QInputDialog().getItem(parent, "Select phases type", "Type:",
["manual", "automatic"])
@ -393,6 +404,174 @@ class PlotWidget(FigureCanvas):
return self._parent
class WaveformWidgetPG(QtGui.QWidget):
def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'):
QtGui.QWidget.__init__(self, parent)#, 1)
self.setParent(parent)
self._parent = parent
# attribute plotdict is a dictionary connecting position and a name
self.plotdict = dict()
# create plot
self.main_layout = QtGui.QVBoxLayout()
self.label = QtGui.QLabel()
self.setLayout(self.main_layout)
self.plotWidget = pg.PlotWidget(title=title, autoDownsample=True)
self.main_layout.addWidget(self.plotWidget)
self.main_layout.addWidget(self.label)
self.plotWidget.showGrid(x=False, y=True, alpha=0.2)
self.plotWidget.hideAxis('bottom')
self.plotWidget.hideAxis('left')
self.reinitMoveProxy()
self._proxy = pg.SignalProxy(self.plotWidget.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
def reinitMoveProxy(self):
self.vLine = pg.InfiniteLine(angle=90, movable=False)
self.hLine = pg.InfiniteLine(angle=0, movable=False)
self.plotWidget.addItem(self.vLine, ignoreBounds=True)
self.plotWidget.addItem(self.hLine, ignoreBounds=True)
def mouseMoved(self, evt):
pos = evt[0] ## using signal proxy turns original arguments into a tuple
if self.plotWidget.sceneBoundingRect().contains(pos):
mousePoint = self.plotWidget.getPlotItem().vb.mapSceneToView(pos)
x, y, = (mousePoint.x(), mousePoint.y())
#if x > 0:# and index < len(data1):
wfID = self._parent.getWFID(y)
station = self._parent.getStationName(wfID)
if self._parent.get_current_event():
self.label.setText("station = {}, t = {} [s]".format(station, x))
self.vLine.setPos(mousePoint.x())
self.hLine.setPos(mousePoint.y())
def getPlotDict(self):
return self.plotdict
def setPlotDict(self, key, value):
self.plotdict[key] = value
def clearPlotDict(self):
self.plotdict = dict()
def getParent(self):
return self._parent
def setParent(self, parent):
self._parent = parent
def plotWFData(self, wfdata, title=None, zoomx=None, zoomy=None,
noiselevel=None, scaleddata=False, mapping=True,
component='*', nth_sample=1, iniPick=None):
self.title = title
self.clearPlotDict()
wfstart, wfend = full_range(wfdata)
nmax = 0
settings = QSettings()
compclass = settings.value('compclass')
if not compclass:
print('Warning: No settings for channel components found. Using default')
compclass = SetChannelComponents()
if not component == '*':
alter_comp = compclass.getCompPosition(component)
#alter_comp = str(alter_comp[0])
st_select = wfdata.select(component=component)
st_select += wfdata.select(component=alter_comp)
else:
st_select = wfdata
# list containing tuples of network, station, channel (for sorting)
nsc = []
for trace in st_select:
nsc.append((trace.stats.network, trace.stats.station, trace.stats.channel))
nsc.sort()
nsc.reverse()
plots = []
try:
self.plotWidget.getPlotItem().vb.setLimits(xMin=float(0),
xMax=float(wfend-wfstart),
yMin=-0.5,
yMax=len(nsc)+0.5)
except:
print('Warning: Could not set zoom limits')
for n, (network, station, channel) in enumerate(nsc):
st = st_select.select(network=network, station=station, channel=channel)
trace = st[0]
if mapping:
comp = channel[-1]
n = compclass.getPlotPosition(str(comp))
#n = n[0]
if n > nmax:
nmax = n
msg = 'plotting %s channel of station %s' % (channel, station)
print(msg)
stime = trace.stats.starttime - wfstart
time_ax = prepTimeAxis(stime, trace)
if time_ax is not None:
if not scaleddata:
trace.detrend('constant')
trace.normalize(np.max(np.abs(trace.data)) * 2)
times = [time for index, time in enumerate(time_ax) if not index%nth_sample]
data = [datum + n for index, datum in enumerate(trace.data) if not index%nth_sample]
plots.append((times, data))
self.setPlotDict(n, (station, channel, network))
self.xlabel = 'seconds since {0}'.format(wfstart)
self.ylabel = ''
self.setXLims([0, wfend - wfstart])
self.setYLims([-0.5, nmax + 0.5])
return plots
# def getAxes(self):
# return self.axes
# def getXLims(self):
# return self.getAxes().get_xlim()
# def getYLims(self):
# return self.getAxes().get_ylim()
def setXLims(self, lims):
vb = self.plotWidget.getPlotItem().getViewBox()
vb.setXRange(float(lims[0]), float(lims[1]), padding=0)
def setYLims(self, lims):
vb = self.plotWidget.getPlotItem().getViewBox()
vb.setYRange(float(lims[0]), float(lims[1]), padding=0)
def setYTickLabels(self, pos, labels):
ticks = zip(pos, labels)
minorTicks = [(0, 0) for item in labels]
# leftAx.tickLength = 5
# leftAx.orientation = 'right'
self.getAxItem('left').setTicks([ticks, minorTicks])
def updateXLabel(self, text):
self.getAxItem('bottom').setLabel(text)
self.draw()
def updateYLabel(self, text):
self.getAxItem('left').setLabel(text)
self.draw()
def getAxItem(self, position):
return self.plotWidget.getPlotItem().axes[position]['item']
def updateTitle(self, text):
self.plotWidget.getPlotItem().setTitle(text)
self.draw()
def updateWidget(self):#, xlabel, ylabel, title):
self.updateXLabel(self.xlabel)
self.updateYLabel(self.ylabel)
self.updateTitle(self.title)
def draw(self):
pass
class WaveformWidget(FigureCanvas):
def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'):
@ -446,18 +625,20 @@ class WaveformWidget(FigureCanvas):
alter_comp = compclass.getCompPosition(component)
#alter_comp = str(alter_comp[0])
wfdata = wfdata.select(component=component)
wfdata += wfdata.select(component=alter_comp)
st_select = wfdata.select(component=component)
st_select += wfdata.select(component=alter_comp)
else:
st_select = wfdata
# list containing tuples of network, station, channel (for sorting)
nsc = []
for trace in wfdata:
for trace in st_select:
nsc.append((trace.stats.network, trace.stats.station, trace.stats.channel))
nsc.sort()
nsc.reverse()
for n, (network, station, channel) in enumerate(nsc):
st = wfdata.select(network=network, station=station, channel=channel)
st = st_select.select(network=network, station=station, channel=channel)
trace = st[0]
if mapping:
comp = channel[-1]
@ -571,6 +752,7 @@ class PickDlg(QDialog):
self._init_autopicks = {}
self.filteroptions = FILTERDEFAULTS
self.pick_block = False
self.nextStation = QtGui.QCheckBox('Continue with next station.')
# initialize panning attributes
self.press = None
@ -664,9 +846,6 @@ class PickDlg(QDialog):
self.s_button = QPushButton('S', self)
self.p_button.setCheckable(True)
self.s_button.setCheckable(True)
# button shortcuts (1 for P-button, 2 for S-button)
self.p_button.setShortcut(QKeySequence('1'))
self.s_button.setShortcut(QKeySequence('2'))
# set button tooltips
self.p_button.setToolTip('Hotkey: "1"')
self.s_button.setToolTip('Hotkey: "2"')
@ -676,6 +855,13 @@ class PickDlg(QDialog):
self.reject_button = QPushButton('&Reject Picks')
self.disable_ar_buttons()
# add hotkeys
self._shortcut_space = QtGui.QShortcut(QtGui.QKeySequence(' '), self)
self._shortcut_space.activated.connect(self.accept_button.clicked)
# button shortcuts (1 for P-button, 2 for S-button)
self.p_button.setShortcut(QKeySequence('1'))
self.s_button.setShortcut(QKeySequence('2'))
# layout the outermost appearance of the Pick Dialog
_outerlayout = QVBoxLayout()
_dialtoolbar = QToolBar()
@ -692,6 +878,8 @@ class PickDlg(QDialog):
if self._embedded:
_dialtoolbar.addWidget(self.accept_button)
_dialtoolbar.addWidget(self.reject_button)
else:
_dialtoolbar.addWidget(self.nextStation)
# layout the innermost widget
_innerlayout = QVBoxLayout()
@ -1429,7 +1617,6 @@ class TuneAutopicker(QWidget):
self.eventBox = self.parent.createEventBox()
self.eventBox.setMaxVisibleItems(20)
self.fill_eventbox()
self.eventBox.setCurrentIndex(0)
self.trace_layout.addWidget(self.eventBox)
def init_stationlist(self):
@ -1459,7 +1646,7 @@ class TuneAutopicker(QWidget):
model = self.stationBox.model()
for network, station in stations:
item = QtGui.QStandardItem(network+'.'+station)
if station in self.get_current_event().picks:
if station in self.get_current_event().pylot_picks:
item.setBackground(self.parent._colors['ref'])
model.appendRow(item)
@ -1475,7 +1662,7 @@ class TuneAutopicker(QWidget):
self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick']
def add_parameters(self):
self.paraBox = AutoPickParaBox(self.parameter)
self.paraBox = PylotParaBox(self.parameter)
self.paraBox.set_tune_mode(True)
self.update_eventID()
self.parameter_layout.addWidget(self.paraBox)
@ -1500,8 +1687,8 @@ class TuneAutopicker(QWidget):
self.listWidget.scrollToBottom()
def get_current_event(self):
index = self.eventBox.currentIndex()
return self.eventBox.itemData(index)
path = self.eventBox.currentText()
return self.parent.project.getEventFromPath(path)
def get_current_event_name(self):
return self.eventBox.currentText().split('/')[-1]
@ -1511,13 +1698,13 @@ class TuneAutopicker(QWidget):
def get_current_event_picks(self, station):
event = self.get_current_event()
if station in event.picks.keys():
return event.picks[station]
if station in event.pylot_picks.keys():
return event.pylot_picks[station]
def get_current_event_autopicks(self, station):
event = self.get_current_event()
if event.autopicks:
return event.autopicks[station]
if event.pylot_autopicks:
return event.pylot_autopicks[station]
def get_current_station(self):
return str(self.stationBox.currentText()).split('.')[-1]
@ -1531,6 +1718,9 @@ class TuneAutopicker(QWidget):
return widget
def gen_pick_dlg(self):
if not self.get_current_event():
self.pickDlg = None
return
station = self.get_current_station()
data = self.data.getWFData()
pickDlg = PickDlg(self, data=data.select(station=station),
@ -1541,7 +1731,6 @@ class TuneAutopicker(QWidget):
pickDlg.update_picks.connect(self.picks_from_pickdlg)
pickDlg.update_picks.connect(self.fill_eventbox)
pickDlg.update_picks.connect(self.fill_stationbox)
pickDlg.update_picks.connect(self.parent.drawPicks)
pickDlg.update_picks.connect(lambda: self.parent.setDirty(True))
pickDlg.update_picks.connect(self.parent.enableSaveManualPicksAction)
self.pickDlg = QtGui.QWidget()
@ -1551,7 +1740,15 @@ class TuneAutopicker(QWidget):
def picks_from_pickdlg(self, picks=None):
station = self.get_current_station()
replot = self.parent.addPicks(station, picks)
self.get_current_event().setPick(station, picks)
if self.get_current_event() == self.parent.get_current_event():
if replot:
self.parent.plotWaveformDataThread()
self.parent.drawPicks()
else:
self.parent.drawPicks(station)
self.parent.draw()
def plot_manual_picks_to_figs(self):
picks = self.get_current_event_picks(self.get_current_station())
@ -1619,7 +1816,7 @@ class TuneAutopicker(QWidget):
id1 = self.figure_tabs.insertTab(1, self.overview, 'Overview')
id2 = self.figure_tabs.insertTab(2, self.p_tabs, 'P')
id3 = self.figure_tabs.insertTab(3, self.s_tabs, 'S')
if picked:
if picked and self.get_current_event():
self.fill_p_tabs(canvas_dict)
self.fill_s_tabs(canvas_dict)
self.toggle_autopickTabs(bool(self.fig_dict['mainFig'].axes))
@ -1658,7 +1855,30 @@ class TuneAutopicker(QWidget):
self.init_tab_names()
def fill_eventbox(self):
project = self.parent.project
if not project:
return
# update own list
self.parent.fill_eventbox(eventBox=self.eventBox, select_events='ref')
index_start = self.parent.eventBox.currentIndex()
index = index_start
if index == -1:
index += 1
nevents = self.eventBox.model().rowCount()
path = self.eventBox.itemText(index)
if project.getEventFromPath(path).isTestEvent():
for index in range(nevents):
path = self.eventBox.itemText(index)
if project.getEventFromPath(index):
if not project.getEventFromPath(index).isTestEvent():
break
#in case all events are marked as test events and last event is reached
if index == nevents - 1:
index = -1
self.eventBox.setCurrentIndex(index)
if not index == index_start:
self.eventBox.activated.emit(index)
# update parent
self.parent.fill_eventbox()
def update_eventID(self):
@ -1698,8 +1918,8 @@ class TuneAutopicker(QWidget):
self._warn('Could not execute picker:\n{}'.format(
self.ap_thread._executedError))
return
self.picks = self.ap_thread.data
if not self.picks:
self.pylot_picks = self.ap_thread.data
if not self.pylot_picks:
self._warn('No picks found. See terminal output.')
return
#renew tabs
@ -1729,7 +1949,8 @@ class TuneAutopicker(QWidget):
def clear_all(self):
if hasattr(self, 'pickDlg'):
self.pickDlg.setParent(None)
if self.pickDlg:
self.pickDlg.setParent(None)
del(self.pickDlg)
if hasattr(self, 'overview'):
self.overview.setParent(None)
@ -1754,13 +1975,13 @@ class TuneAutopicker(QWidget):
self.qmb.show()
class AutoPickParaBox(QtGui.QWidget):
class PylotParaBox(QtGui.QWidget):
def __init__(self, parameter, parent=None):
'''
Generate Widget containing parameters for automatic picking algorithm.
:param: parameter
:type: AutoPickParameter (object)
:type: PylotParameter (object)
'''
QtGui.QWidget.__init__(self, parent)
@ -1773,6 +1994,7 @@ class AutoPickParaBox(QtGui.QWidget):
self.labels = {}
self.boxes = {}
self.groupboxes = {}
self._exclusive_widgets = []
self._init_sublayouts()
self.setLayout(self.layout)
self.add_main_parameters_tab()
@ -1780,6 +2002,7 @@ class AutoPickParaBox(QtGui.QWidget):
self.params_to_gui()
self._toggle_advanced_settings()
self.resize(720, 1280)
self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
def _init_sublayouts(self):
self._main_layout = QtGui.QVBoxLayout()
@ -1819,7 +2042,7 @@ class AutoPickParaBox(QtGui.QWidget):
def _create_advanced_cb(self):
self._advanced_cb = QtGui.QCheckBox('Enable Advanced Settings')
self._advanced_layout.addWidget(self._advanced_cb)
self._advanced_layout.insertWidget(0, self._advanced_cb)
self._advanced_cb.toggled.connect(self._toggle_advanced_settings)
def _toggle_advanced_settings(self):
@ -1907,31 +2130,31 @@ class AutoPickParaBox(QtGui.QWidget):
scrollA = QtGui.QScrollArea()
scrollA.setWidgetResizable(True)
scrollA.setWidget(widget)
widget.setLayout(layout)
self.tabs.addTab(scrollA, name)
def add_main_parameters_tab(self):
self.add_to_layout(self._main_layout, 'Directories',
self.parameter.get_main_para_names()['dirs'])
self.parameter.get_main_para_names()['dirs'], 0)
self.add_to_layout(self._main_layout, 'NLLoc',
self.parameter.get_main_para_names()['nlloc'])
self.parameter.get_main_para_names()['nlloc'], 1)
self.add_to_layout(self._main_layout, 'Seismic Moment',
self.parameter.get_main_para_names()['smoment'])
self.parameter.get_main_para_names()['smoment'], 2)
self.add_to_layout(self._main_layout, 'Local Magnitude',
self.parameter.get_main_para_names()['localmag'], 3)
self.add_to_layout(self._main_layout, 'Common Settings Characteristic Function',
self.parameter.get_main_para_names()['pick'])
self.parameter.get_main_para_names()['pick'], 4)
self.add_tab(self._main_layout, 'Main Settings')
def add_special_pick_parameters_tab(self):
self.add_to_layout(self._advanced_layout, 'Z-component',
self.parameter.get_special_para_names()['z'])
self.parameter.get_special_para_names()['z'], 1)
self.add_to_layout(self._advanced_layout, 'H-components',
self.parameter.get_special_para_names()['h'])
self.parameter.get_special_para_names()['h'], 2)
self.add_to_layout(self._advanced_layout, 'First-motion picker',
self.parameter.get_special_para_names()['fm'])
self.parameter.get_special_para_names()['fm'], 3)
self.add_to_layout(self._advanced_layout, 'Quality assessment',
self.parameter.get_special_para_names()['quality'])
self.parameter.get_special_para_names()['quality'], 4)
self.add_tab(self._advanced_layout, 'Advanced Settings')
# def gen_h_seperator(self):
@ -1946,11 +2169,45 @@ class AutoPickParaBox(QtGui.QWidget):
# label.setFont(font)
# return label
def add_to_layout(self, layout, name, items):
def refresh(self):
for groupbox in self.groupboxes.values():
layout = groupbox._parentLayout
position = groupbox._position
layout.insertWidget(position, groupbox)
def get_groupbox_exclusive(self, name):
widget = QtGui.QWidget(self, 1)
layout = QtGui.QVBoxLayout()
widget.setLayout(layout)
layout.addWidget(self.groupboxes[name])
self._exclusive_widgets.append(widget)
return widget
def get_groupbox_dialog(self, name):
widget = self.get_groupbox_exclusive(name)
dialog = QtGui.QDialog(self.parent())
layout = QtGui.QVBoxLayout()
dialog.setLayout(layout)
buttonbox = QtGui.QDialogButtonBox(QDialogButtonBox.Ok |
QDialogButtonBox.Cancel)
buttonbox.accepted.connect(dialog.accept)
buttonbox.accepted.connect(self.refresh)
buttonbox.accepted.connect(self.params_from_gui)
buttonbox.rejected.connect(dialog.reject)
buttonbox.rejected.connect(self.refresh)
buttonbox.rejected.connect(self.params_to_gui)
layout.addWidget(widget)
layout.addWidget(buttonbox)
self._exclusive_dialog = dialog
return dialog
def add_to_layout(self, layout, name, items, position):
groupbox = QtGui.QGroupBox(name)
groupbox._position = position
groupbox._parentLayout = layout
self.groupboxes[name] = groupbox
groupbox.setLayout(self.init_boxes(items))
layout.addWidget(groupbox)
layout.insertWidget(position, groupbox)
def show_groupboxes(self):
for name in self.groupboxes.keys():
@ -1974,6 +2231,16 @@ class AutoPickParaBox(QtGui.QWidget):
else:
print('Groupbox {} not part of object.'.format(name))
def show_file_buttons(self):
self.saveButton.show()
self.loadButton.show()
self.defaultsButton.show()
def hide_file_buttons(self):
self.saveButton.hide()
self.loadButton.hide()
self.defaultsButton.hide()
def show_parameter(self, name=None):
if not name:
for name in self.boxes.keys():
@ -2028,6 +2295,8 @@ class AutoPickParaBox(QtGui.QWidget):
if type(box) == QtGui.QLineEdit:
box.setText(str(value))
elif type(box) == QtGui.QSpinBox or type(box) == QtGui.QDoubleSpinBox:
if not value:
value = 0.
box.setValue(value)
elif type(box) == QtGui.QCheckBox:
if value == 'True':
@ -2085,6 +2354,14 @@ class AutoPickParaBox(QtGui.QWidget):
self._warn('Could not restore defaults:\n{}'.format(e))
return
def show(self):
self.refresh()
self.show_parameter()
if hasattr(self, '_exclusive_dialog'):
self._exclusive_dialog.close()
self._exclusive_widgets = []
QtGui.QWidget.show(self)
def _warn(self, message):
self.qmb = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning,
'Warning', message)
@ -2197,6 +2474,7 @@ class PropTab(QWidget):
def resetValues(self, infile=None):
return None
class InputsTab(PropTab):
def __init__(self, parent, infile=None):
super(InputsTab, self).__init__(parent)
@ -2250,7 +2528,7 @@ class InputsTab(PropTab):
return values
def resetValues(self, infile):
para = AutoPickParameter(infile)
para = PylotParameter(infile)
datstruct = para.get('datastructure')
if datstruct == 'SeisComp':
index = 0
@ -2307,6 +2585,7 @@ class GraphicsTab(PropTab):
def __init__(self, parent=None):
super(GraphicsTab, self).__init__(parent)
self.init_layout()
self.add_pg_cb()
self.add_nth_sample()
self.setLayout(self.main_layout)
@ -2321,15 +2600,28 @@ class GraphicsTab(PropTab):
self.spinbox_nth_sample = QtGui.QSpinBox()
label = QLabel('nth sample')
label.setToolTip('Plot every nth sample (to speed up plotting)')
self.spinbox_nth_sample.setMinimum(1)
self.spinbox_nth_sample.setMaximum(10e3)
self.spinbox_nth_sample.setValue(int(nth_sample))
label.setToolTip('Plot every nth sample (to speed up plotting)')
self.main_layout.addWidget(label, 1, 0)
self.main_layout.addWidget(self.spinbox_nth_sample, 1, 1)
def add_pg_cb(self):
text = {True: 'Use pyqtgraphic library for plotting',
False: 'Cannot use library: pyqtgraphic not found on system'}
label = QLabel('PyQt graphic')
label.setToolTip(text[bool(pg)])
label.setEnabled(bool(pg))
self.checkbox_pg = QtGui.QCheckBox()
self.checkbox_pg.setEnabled(bool(pg))
self.checkbox_pg.setChecked(bool(pg))
self.main_layout.addWidget(label, 0, 0)
self.main_layout.addWidget(self.spinbox_nth_sample, 0, 1)
self.main_layout.addWidget(self.checkbox_pg, 0, 1)
def getValues(self):
values = {'nth_sample': self.spinbox_nth_sample.value()}
values = {'nth_sample': self.spinbox_nth_sample.value(),
'pyqtgraphic': self.checkbox_pg.isChecked()}
return values
@ -2492,7 +2784,7 @@ class LocalisationTab(PropTab):
return values
def resetValues(self, infile):
para = AutoPickParameter(infile)
para = PylotParameter(infile)
nllocroot = para.get('nllocroot')
nllocbin = para.get('nllocbin')
loctool = self.locToolComboBox.setCurrentIndex(3)