[change] PickingResults now only stores actual results, PickingContainer stores intermediary values

PickingResults now stores only the actual results of picking, which are returned from the autopickstation function. 
To store intermediary results during picking, the new class PickingContainer is used.
This commit is contained in:
Darius Arnold 2018-08-03 10:59:10 +02:00
parent 076115f7f5
commit 8dcea2a8c3
2 changed files with 125 additions and 209 deletions

View File

@ -180,47 +180,11 @@ class PickingParameters(object):
class PickingResults(dict): class PickingResults(dict):
"""
Store picking results
"""
def init_for_picking(self): def __init__(self):
"""
Initialize intermediary values of PickingResults used during pick calculation.
:return:
:rtype:
"""
# initialize output
self.Pweight = 4 # weight for P onset
self.Sweight = 4 # weight for S onset
self.FM = 'N' # first motion (polarity)
self.SNRP = None # signal-to-noise ratio of P onset
self.SNRPdB = None # signal-to-noise ratio of P onset [dB]
self.SNRS = None # signal-to-noise ratio of S onset
self.SNRSdB = None # signal-to-noise ratio of S onset [dB]
self.mpickP = None # most likely P onset
self.lpickP = None # latest possible P onset
self.epickP = None # earliest possible P onset
self.mpickS = None # most likely S onset
self.lpickS = None # latest possible S onset
self.epickS = None # earliest possible S onset
self.Perror = None # symmetrized picking error P onset
self.Serror = None # symmetrized picking error S onset
self.Pmarker = []
self.Ao = None # Wood-Anderson peak-to-peak amplitude
self.picker = 'auto' # type of picks
# these get added during the construction of the p pick results dictionary
self.w0 = None
self.fc = None
self.Mw = None
self.Mo = None
# flags for plotting
self.p_aic_plot_flag = 0
self.aicSflag = 0
self.Pflag = 0
self.Sflag = 0
def init_default_values(self):
""" """
Inits default values of picking results. Called to generate a clean Inits default values of picking results. Called to generate a clean
PickingResults instance with sensible defaults. PickingResults instance with sensible defaults.
@ -234,87 +198,25 @@ class PickingResults(dict):
# TODO What are those? # TODO What are those?
self.w0 = None self.w0 = None
self.fc = None self.fc = None
self.Ao = None # Wood-Anderson peak-to-peak amplitude
# Station information # Station information
self.network = None self.network = None
self.channel = None self.channel = None
# pick information # pick information
self.picker = 'auto' self.picker = 'auto' # type of pick
self.marked = [] self.marked = []
# pick results # pick results
self.epp = None self.epp = None # earliest possible pick
self.mpp = None self.mpp = None # most likely onset
self.lpp = None self.lpp = None # latest possible pick
self.fm = 'N' self.fm = 'N' # first motion polarity, can be set to 'U' (Up) or 'D' (Down)
self.snr = None self.snr = None # signal-to-noise ratio of onset
self.snrdb = None self.snrdb = None # signal-to-noise ratio of onset [dB]
self.spe = None self.spe = None # symmetrized picking error
self.weight = 4 self.weight = 4 # weight of onset
def make_clean_results(self, pick, channel, network):
"""
Create a new PickingResults instance that only contains relevant results.
No intermediate pick information is saved in the new PickingResults.
:param pick: decides P or S pick results are collected
:type pick: str
:param channel: channel on which the pick was calculated
:type channel: str
:param network: Network id of station
:type network: str
:return:
:rtype: PickingResults
"""
if pick.upper() == 'P':
p = PickingResults()
p.init_default_values()
# Magnitude parameters
p.Mo = self.Mo
p.Mw = self.Mw
# TODO What are those?
p.w0 = self.w0
p.fc = self.fc
# Station information
p.network = network
p.channel = channel
# pick information
p.picker = self.picker
p.marked = self.Pmarker
# pick results
p.epp = self.epickP
p.mpp = self.mpickP
p.lpp = self.lpickP
p.fm = self.FM
p.snr = self.SNRP
p.snrdb = self.SNRPdB
p.spe = self.Perror
p.weight = self.Pweight
return p
if pick.upper() == 'S':
s = PickingResults()
s.init_default_values()
# Station information
s.network = network
s.channel = channel
# Pick results
s.lpp = self.lpickS
s.mpp = self.mpickS
s.epp = self.epickS
s.spe = self.Serror
s.snr = self.SNRS
s.snrdb = self.SNRSdB
s.weight = self.Sweight
s.fm = None
s.picker = self.picker
s.Ao = self.Ao
return s
def __setattr__(self, key, value): def __setattr__(self, key, value):
self[key] = value self[key] = value
@ -323,6 +225,19 @@ class PickingResults(dict):
return self[key] return self[key]
class PickingContainer:
"""
Keeps intermediary results and values during picking
"""
def __init__(self):
# flags for plotting
self.p_aic_plot_flag = 0
self.aicSflag = 0
self.Pflag = 0
self.Sflag = 0
class MissingTraceException(ValueError): class MissingTraceException(ValueError):
""" """
Used to indicate missing traces in a obspy.core.stream.Stream object Used to indicate missing traces in a obspy.core.stream.Stream object
@ -369,14 +284,15 @@ class AutopickStation(object):
# initialize picking results # initialize picking results
self.p_results = PickingResults() self.p_results = PickingResults()
self.p_results.init_for_picking()
self.s_results = PickingResults() self.s_results = PickingResults()
self.s_results.init_for_picking()
# intialize containers that keep intermediary values between picking P- and S phase and plotting
self.p_data = PickingContainer()
self.s_data = PickingContainer()
# extract additional information # extract additional information
pickparams = self.extract_pickparams(pickparam) pickparams = self.extract_pickparams(pickparam)
self.p_params, self.s_params, self.first_motion_params, self.signal_length_params = pickparams self.p_params, self.s_params, self.first_motion_params, self.signal_length_params = pickparams
self.results = PickingResults()
# TODO get channelorder from the pylot preferences # TODO get channelorder from the pylot preferences
self.channelorder = {'Z': 3, 'N': 1, 'E': 2} self.channelorder = {'Z': 3, 'N': 1, 'E': 2}
self.station_name = wfstream[0].stats.station self.station_name = wfstream[0].stats.station
@ -597,7 +513,7 @@ class AutopickStation(object):
except PickingFailedException as pfe: except PickingFailedException as pfe:
print(pfe) print(pfe)
if self.horizontal_traces_exist() and self.p_results.Pweight is not None and self.p_results.Pweight < 4: if self.horizontal_traces_exist() and self.p_results.weight is not None and self.p_results.weight < 4:
try: try:
self.pick_s_phase() self.pick_s_phase()
except MissingTraceException as mte: except MissingTraceException as mte:
@ -612,24 +528,23 @@ class AutopickStation(object):
def finish_picking(self): def finish_picking(self):
# calculate "real" onset times, save them in PickingResults # calculate "real" onset times, save them in PickingResults
if self.p_results.lpickP is not None and self.p_results.lpickP == self.p_results.mpickP: if self.p_results.lpp is not None and self.p_results.lpp == self.p_results.mpp:
self.p_results.lpickP += self.ztrace.stats.delta self.p_results.lpp += self.ztrace.stats.delta
if self.p_results.epickP is not None and self.p_results.epickP == self.p_results.mpickP: if self.p_results.epp is not None and self.p_results.epp == self.p_results.mpp:
self.p_results.epickP -= self.ztrace.stats.delta self.p_results.epp -= self.ztrace.stats.delta
if self.p_results.mpickP is not None and self.p_results.epickP is not None and self.p_results.lpickP is not None: if self.p_results.mpp is not None and self.p_results.epp is not None and self.p_results.lpp is not None:
self.p_results.lpickP = self.ztrace.stats.starttime + self.p_results.lpickP self.p_results.lpp = self.ztrace.stats.starttime + self.p_results.lpp
self.p_results.epickP = self.ztrace.stats.starttime + self.p_results.epickP self.p_results.epp = self.ztrace.stats.starttime + self.p_results.epp
self.p_results.mpickP = self.ztrace.stats.starttime + self.p_results.mpickP self.p_results.mpp = self.ztrace.stats.starttime + self.p_results.mpp
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 iterative picking # theoretical onset times for iterative picking
self.p_results.lpickP = self.ztrace.stats.starttime + self.p_params.timeerrorsP[3] self.p_results.lpp = self.ztrace.stats.starttime + self.p_params.timeerrorsP[3]
self.p_results.epickP = self.ztrace.stats.starttime - self.p_params.timeerrorsP[3] self.p_results.epp = self.ztrace.stats.starttime - self.p_params.timeerrorsP[3]
self.p_results.mpickP = self.ztrace.stats.starttime self.p_results.mpp = self.ztrace.stats.starttime
self.p_results = self.p_results.make_clean_results('P', self.ztrace.stats.channel, self.ztrace.stats.network)
# add picking results to PickingResults instance
self.p_results.channel = self.ztrace.stats.channel
self.p_results.network = self.ztrace.stats.network
# #
# S results # S results
# #
@ -641,22 +556,24 @@ class AutopickStation(object):
elif self.ntrace: elif self.ntrace:
hdat = self.ntrace hdat = self.ntrace
if self.s_results.lpickS is not None and self.s_results.lpickS == self.s_results.mpickS: if self.s_results.lpp is not None and self.s_results.lpp == self.s_results.mpp:
self.s_results.lpickS += hdat.stats.delta self.s_results.lpp += hdat.stats.delta
if self.s_results.epickS is not None and self.s_results.epickS == self.s_results.mpickS: if self.s_results.epp is not None and self.s_results.epp == self.s_results.mpp:
self.s_results.epickS -= hdat.stats.delta self.s_results.epp -= hdat.stats.delta
if self.s_results.mpickS is not None and self.s_results.epickS is not None and self.s_results.lpickS is not None: if self.s_results.mpp is not None and self.s_results.epp is not None and self.s_results.lpp is not None:
self.s_results.lpickS = hdat.stats.starttime + self.s_results.lpickS self.s_results.lpp = hdat.stats.starttime + self.s_results.lpp
self.s_results.epickS = hdat.stats.starttime + self.s_results.epickS self.s_results.epp = hdat.stats.starttime + self.s_results.epp
self.s_results.mpickS = hdat.stats.starttime + self.s_results.mpickS self.s_results.mpp = hdat.stats.starttime + self.s_results.mpp
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
self.s_results.lpickS = hdat.stats.starttime + self.s_params.timeerrorsS[3] self.s_results.lpp = hdat.stats.starttime + self.s_params.timeerrorsS[3]
self.s_results.epickS = hdat.stats.starttime - self.s_params.timeerrorsS[3] self.s_results.epp = hdat.stats.starttime - self.s_params.timeerrorsS[3]
self.s_results.mpickS = hdat.stats.starttime self.s_results.mpp = hdat.stats.starttime
self.s_results = self.s_results.make_clean_results('S', self.etrace.stats.channel, self.etrace.stats.network) self.s_results.channel = self.etrace.stats.channel
self.s_results.network = self.etrace.stats.network
self.s_results.fm = None # override default value 'N'
def plot_pick_results(self): def plot_pick_results(self):
if self.iplot > 0: if self.iplot > 0:
@ -674,12 +591,12 @@ class AutopickStation(object):
tdata = np.linspace(start=0, stop=self.ztrace.stats.npts*self.ztrace.stats.delta, num=self.ztrace.stats.npts) tdata = np.linspace(start=0, stop=self.ztrace.stats.npts*self.ztrace.stats.delta, num=self.ztrace.stats.npts)
# plot tapered trace filtered with bpz2 filter settings # plot tapered trace filtered with bpz2 filter settings
ax1.plot(tdata, self.tr_filt_z_bpz2.data/max(self.tr_filt_z_bpz2.data), color=linecolor, linewidth=0.7, label='Data') ax1.plot(tdata, self.tr_filt_z_bpz2.data/max(self.tr_filt_z_bpz2.data), color=linecolor, linewidth=0.7, label='Data')
if self.p_results.Pweight < 4: if self.p_results.weight < 4:
# plot CF of initial onset (HOScf or ARZcf) # plot CF of initial onset (HOScf or ARZcf)
ax1.plot(self.cf1.getTimeArray(), self.cf1.getCF()/max(self.cf1.getCF()), 'b', label='CF1') ax1.plot(self.cf1.getTimeArray(), self.cf1.getCF()/max(self.cf1.getCF()), 'b', label='CF1')
if self.p_results.p_aic_plot_flag == 1: if self.p_data.p_aic_plot_flag == 1:
aicpick = self.p_results.aicpick aicpick = self.p_data.aicpick
refPpick = self.p_results.refPpick refPpick = self.p_data.refPpick
# plot CF of precise pick (HOScf or ARZcf) # plot CF of precise pick (HOScf or ARZcf)
ax1.plot(self.cf2.getTimeArray(), self.cf2.getCF() / max(self.cf2.getCF()), 'm', label='CF2') ax1.plot(self.cf2.getTimeArray(), self.cf2.getCF() / max(self.cf2.getCF()), 'm', label='CF2')
# plot inital P pick # plot inital P pick
@ -691,36 +608,36 @@ class AutopickStation(object):
ax1.plot([refPpick.getpick() - 0.5, refPpick.getpick() + 0.5], [1.3, 1.3], 'r', linewidth=2) ax1.plot([refPpick.getpick() - 0.5, refPpick.getpick() + 0.5], [1.3, 1.3], 'r', linewidth=2)
ax1.plot([refPpick.getpick() - 0.5, refPpick.getpick() + 0.5], [-1.3, -1.3], 'r', linewidth=2) ax1.plot([refPpick.getpick() - 0.5, refPpick.getpick() + 0.5], [-1.3, -1.3], 'r', linewidth=2)
# plot latest possible P pick # plot latest possible P pick
ax1.plot([self.p_results.lpickP, self.p_results.lpickP], [-1.1, 1.1], 'r--', label='lpp') ax1.plot([self.p_results.lpp, self.p_results.lpp], [-1.1, 1.1], 'r--', label='lpp')
# plot earliest possible P pick # plot earliest possible P pick
ax1.plot([self.p_results.epickP, self.p_results.epickP], [-1.1, 1.1], 'r--', label='epp') ax1.plot([self.p_results.epp, self.p_results.epp], [-1.1, 1.1], 'r--', label='epp')
# add title to plot # add title to plot
title = '{station}, {channel}, P weight={pweight:d}, SNR={snr:7.2}, SNR[dB]={snrdb:7.2}, Polarity: {polarity}' title = '{station}, {channel}, P weight={pweight:d}, SNR={snr:7.2}, SNR[dB]={snrdb:7.2}, Polarity: {polarity}'
ax1.set_title(title.format(station=self.ztrace.stats.station, ax1.set_title(title.format(station=self.ztrace.stats.station,
channel=self.ztrace.stats.channel, channel=self.ztrace.stats.channel,
pweight=self.p_results.Pweight, pweight=self.p_results.weight,
snr=self.p_results.SNRP, snr=self.p_results.snr,
snrdb=self.p_results.SNRPdB, snrdb=self.p_results.snrdb,
polarity=self.p_results.FM)) polarity=self.p_results.fm))
else: else:
title = '{channel}, P weight={pweight}, SNR=None, SNR[dB]=None' title = '{channel}, P weight={pweight}, SNR=None, SNR[dB]=None'
ax1.set_title(title.format(channel=self.ztrace.stats.channel, pweight=self.p_results.Pweight)) ax1.set_title(title.format(channel=self.ztrace.stats.channel, pweight=self.p_results.weight))
ax1.legend(loc=1) ax1.legend(loc=1)
ax1.set_yticks([]) ax1.set_yticks([])
ax1.set_ylim([-1.5, 1.5]) ax1.set_ylim([-1.5, 1.5])
ax1.set_ylabel('Normalized Counts') ax1.set_ylabel('Normalized Counts')
if self.horizontal_traces_exist() and self.s_results.Sflag == 1: if self.horizontal_traces_exist() and self.s_data.Sflag == 1:
# plot E trace # plot E trace
ax2 = fig.add_subplot(3, 1, 2, sharex=ax1) ax2 = fig.add_subplot(3, 1, 2, sharex=ax1)
th1data = np.linspace(0, self.etrace.stats.npts*self.etrace.stats.delta, self.etrace.stats.npts) th1data = np.linspace(0, self.etrace.stats.npts*self.etrace.stats.delta, self.etrace.stats.npts)
# plot filtered and tapered waveform # plot filtered and tapered waveform
ax2.plot(th1data, self.etrace.data / max(self.etrace.data), color=linecolor, linewidth=0.7, label='Data') ax2.plot(th1data, self.etrace.data / max(self.etrace.data), color=linecolor, linewidth=0.7, label='Data')
if self.p_results.Pweight < 4: if self.p_results.weight < 4:
# plot initial CF (ARHcf or AR3Ccf) # plot initial CF (ARHcf or AR3Ccf)
ax2.plot(self.arhcf1.getTimeArray(), self.arhcf1.getCF() / max(self.arhcf1.getCF()), 'b', label='CF1') ax2.plot(self.arhcf1.getTimeArray(), self.arhcf1.getCF() / max(self.arhcf1.getCF()), 'b', label='CF1')
if self.s_results.aicSflag == 1 and self.s_results.Sweight <= 4: if self.s_data.aicSflag == 1 and self.s_results.weight <= 4:
aicarhpick = self.aicarhpick aicarhpick = self.aicarhpick
refSpick = self.refSpick refSpick = self.refSpick
# plot second cf, used for determing precise onset (ARHcf or AR3Ccf) # plot second cf, used for determing precise onset (ARHcf or AR3Ccf)
@ -733,16 +650,16 @@ class AutopickStation(object):
ax2.plot([refSpick.getpick(), refSpick.getpick()], [-1.3, 1.3], 'g', linewidth=2, label='Final S Pick') ax2.plot([refSpick.getpick(), refSpick.getpick()], [-1.3, 1.3], 'g', linewidth=2, label='Final S Pick')
ax2.plot([refSpick.getpick() - 0.5, refSpick.getpick() + 0.5], [1.3, 1.3], 'g', linewidth=2) ax2.plot([refSpick.getpick() - 0.5, refSpick.getpick() + 0.5], [1.3, 1.3], 'g', linewidth=2)
ax2.plot([refSpick.getpick() - 0.5, refSpick.getpick() + 0.5], [-1.3, -1.3], 'g', linewidth=2) ax2.plot([refSpick.getpick() - 0.5, refSpick.getpick() + 0.5], [-1.3, -1.3], 'g', linewidth=2)
ax2.plot([self.s_results.lpickS, self.s_results.lpickS], [-1.1, 1.1], 'g--', label='lpp') ax2.plot([self.s_results.lpp, self.s_results.lpp], [-1.1, 1.1], 'g--', label='lpp')
ax2.plot([self.s_results.epickS, self.s_results.epickS], [-1.1, 1.1], 'g--', label='epp') ax2.plot([self.s_results.epp, self.s_results.epp], [-1.1, 1.1], 'g--', label='epp')
title = '{channel}, S weight={sweight}, SNR={snr:7.2}, SNR[dB]={snrdb:7.2}' title = '{channel}, S weight={sweight}, SNR={snr:7.2}, SNR[dB]={snrdb:7.2}'
ax2.set_title(title.format(channel=self.etrace.stats.channel, ax2.set_title(title.format(channel=self.etrace.stats.channel,
sweight=self.s_results.Sweight, sweight=self.s_results.weight,
snr=self.s_results.SNRS, snr=self.s_results.snr,
snrdb=self.s_results.SNRSdB)) snrdb=self.s_results.snrdb))
else: else:
title = '{channel}, S weight={sweight}, SNR=None, SNR[dB]=None' title = '{channel}, S weight={sweight}, SNR=None, SNR[dB]=None'
ax2.set_title(title.format(channel=self.etrace.stats.channel, sweight=self.s_results.Sweight)) ax2.set_title(title.format(channel=self.etrace.stats.channel, sweight=self.s_results.weight))
ax2.legend(loc=1) ax2.legend(loc=1)
ax2.set_yticks([]) ax2.set_yticks([])
ax2.set_ylim([-1.5, 1.5]) ax2.set_ylim([-1.5, 1.5])
@ -753,9 +670,9 @@ class AutopickStation(object):
th2data= np.linspace(0, self.ntrace.stats.npts*self.ntrace.stats.delta, self.ntrace.stats.npts) th2data= np.linspace(0, self.ntrace.stats.npts*self.ntrace.stats.delta, self.ntrace.stats.npts)
# plot trace # plot trace
ax3.plot(th2data, self.ntrace.data / max(self.ntrace.data), color=linecolor, linewidth=0.7, label='Data') ax3.plot(th2data, self.ntrace.data / max(self.ntrace.data), color=linecolor, linewidth=0.7, label='Data')
if self.p_results.Pweight < 4: if self.p_results.weight < 4:
p22, = ax3.plot(self.arhcf1.getTimeArray(), self.arhcf1.getCF() / max(self.arhcf1.getCF()), 'b', label='CF1') p22, = ax3.plot(self.arhcf1.getTimeArray(), self.arhcf1.getCF() / max(self.arhcf1.getCF()), 'b', label='CF1')
if self.s_results.aicSflag == 1: if self.s_data.aicSflag == 1:
aicarhpick = self.aicarhpick aicarhpick = self.aicarhpick
refSpick = self.refSpick refSpick = self.refSpick
ax3.plot(self.arhcf2.getTimeArray(), self.arhcf2.getCF() / max(self.arhcf2.getCF()), 'm', label='CF2') ax3.plot(self.arhcf2.getTimeArray(), self.arhcf2.getCF() / max(self.arhcf2.getCF()), 'm', label='CF2')
@ -766,8 +683,8 @@ class AutopickStation(object):
label='Final S Pick') label='Final S Pick')
ax3.plot([refSpick.getpick() - 0.5, refSpick.getpick() + 0.5], [1.3, 1.3], 'g', linewidth=2) ax3.plot([refSpick.getpick() - 0.5, refSpick.getpick() + 0.5], [1.3, 1.3], 'g', linewidth=2)
ax3.plot([refSpick.getpick() - 0.5, refSpick.getpick() + 0.5], [-1.3, -1.3], 'g', linewidth=2) ax3.plot([refSpick.getpick() - 0.5, refSpick.getpick() + 0.5], [-1.3, -1.3], 'g', linewidth=2)
ax3.plot([self.s_results.lpickS, self.s_results.lpickS], [-1.1, 1.1], 'g--', label='lpp') ax3.plot([self.s_results.lpp, self.s_results.lpp], [-1.1, 1.1], 'g--', label='lpp')
ax3.plot([self.s_results.epickS, self.s_results.epickS], [-1.1, 1.1], 'g--', label='epp') ax3.plot([self.s_results.epp, self.s_results.epp], [-1.1, 1.1], 'g--', label='epp')
ax3.legend(loc=1) ax3.legend(loc=1)
ax3.set_yticks([]) ax3.set_yticks([])
ax3.set_ylim([-1.5, 1.5]) ax3.set_ylim([-1.5, 1.5])
@ -823,8 +740,8 @@ class AutopickStation(object):
self.signal_length_params.noisefactor, self.signal_length_params.minpercent, self.signal_length_params.noisefactor, self.signal_length_params.minpercent,
self.iplot, self.current_figure, self.current_linecolor) self.iplot, self.current_figure, self.current_linecolor)
if Pflag == 0: if Pflag == 0:
self.p_results.Pmarker = 'shortsignallength' self.p_results.marked = 'shortsignallength'
self.p_results.Pweight = 9 self.p_results.weight = 9
return 0 return 0
if self.nstream == self.estream: if self.nstream == self.estream:
@ -837,8 +754,8 @@ class AutopickStation(object):
Pflag = checkZ4S(zne, aicpick.getpick(), self.s_params.zfac, self.p_params.tsnrz[2], self.iplot, Pflag = checkZ4S(zne, aicpick.getpick(), self.s_params.zfac, self.p_params.tsnrz[2], self.iplot,
self.current_figure, self.current_linecolor) self.current_figure, self.current_linecolor)
if Pflag == 0: if Pflag == 0:
self.p_results.Pmarker = 'SinsteadP' self.p_results.marked = 'SinsteadP'
self.p_results.Pweight = 9 self.p_results.weight = 9
return 0 return 0
return 1 return 1
@ -885,7 +802,7 @@ class AutopickStation(object):
aicpick = AICPicker(aiccf, self.p_params.tsnrz, self.p_params.pickwinP, self.iplot, aicpick = AICPicker(aiccf, self.p_params.tsnrz, self.p_params.pickwinP, self.iplot,
Tsmooth=self.p_params.aictsmooth, fig=self.current_figure, linecolor=self.current_linecolor) Tsmooth=self.p_params.aictsmooth, fig=self.current_figure, linecolor=self.current_linecolor)
# save aicpick for plotting later # save aicpick for plotting later
self.p_results.aicpick = aicpick self.p_data.aicpick = aicpick
# add pstart and pstop to aic plot # add pstart and pstop to aic plot
if self.current_figure: if self.current_figure:
# TODO remove plotting from picking, make own plot function # TODO remove plotting from picking, make own plot function
@ -908,7 +825,7 @@ class AutopickStation(object):
error_msg = 'AIC P onset SNR to small: got {}, min {}'.format(aicpick.getSNR(), self.p_params.minAICPSNR) error_msg = 'AIC P onset SNR to small: got {}, min {}'.format(aicpick.getSNR(), self.p_params.minAICPSNR)
raise PickingFailedException(error_msg) raise PickingFailedException(error_msg)
self.p_results.p_aic_plot_flag = 1 self.p_data.p_aic_plot_flag = 1
msg = 'AIC P-pick passes quality control: Slope: {0} counts/s, SNR: {1}\nGo on with refined picking ...\n' \ msg = 'AIC P-pick passes quality control: Slope: {0} counts/s, SNR: {1}\nGo on with refined picking ...\n' \
'autopickstation: re-filtering vertical trace...'.format(aicpick.getSlope(), aicpick.getSNR()) 'autopickstation: re-filtering vertical trace...'.format(aicpick.getSlope(), aicpick.getSNR())
self.vprint(msg) self.vprint(msg)
@ -931,37 +848,38 @@ class AutopickStation(object):
refPpick = PragPicker(self.cf2, self.p_params.tsnrz, self.p_params.pickwinP, self.iplot, self.p_params.ausP, refPpick = PragPicker(self.cf2, self.p_params.tsnrz, self.p_params.pickwinP, self.iplot, self.p_params.ausP,
self.p_params.tsmoothP, aicpick.getpick(), self.current_figure, self.current_linecolor) self.p_params.tsmoothP, aicpick.getpick(), self.current_figure, self.current_linecolor)
# save PragPicker result for plotting # save PragPicker result for plotting
self.p_results.refPpick = refPpick self.p_data.refPpick = refPpick
self.p_results.mpickP = refPpick.getpick() self.p_results.mpp = refPpick.getpick()
if self.p_results.mpickP is None: if self.p_results.mpp is None:
msg = 'Bad initial (AIC) P-pick, skipping this onset!\n AIC-SNR={}, AIC-Slope={}counts/s\n' \ msg = 'Bad initial (AIC) P-pick, skipping this onset!\n AIC-SNR={}, AIC-Slope={}counts/s\n' \
'(min. AIC-SNR={}, min. AIC-Slope={}counts/s)' '(min. AIC-SNR={}, min. AIC-Slope={}counts/s)'
msg.format(aicpick.getSNR(), aicpick.getSlope(), self.p_params.minAICPSNR, self.p_params.minAICPslope) msg.format(aicpick.getSNR(), aicpick.getSlope(), self.p_params.minAICPSNR, self.p_params.minAICPslope)
self.vprint(msg) self.vprint(msg)
self.s_results.Sflag = 0 self.s_data.Sflag = 0
raise PickingFailedException(msg) raise PickingFailedException(msg)
# quality assessment, get earliest/latest pick and symmetrized uncertainty # quality assessment, get earliest/latest pick and symmetrized uncertainty
#todo quality assessment in own function #todo quality assessment in own function
self.set_current_figure('el_Ppick') self.set_current_figure('el_Ppick')
elpicker_results = earllatepicker(z_copy, self.p_params.nfacP, self.p_params.tsnrz, self.p_results.mpickP, elpicker_results = earllatepicker(z_copy, self.p_params.nfacP, self.p_params.tsnrz, self.p_results.mpp,
self.iplot, fig=self.current_figure, linecolor=self.current_linecolor) self.iplot, fig=self.current_figure, linecolor=self.current_linecolor)
self.p_results.epickP, self.p_results.lpickP, self.p_results.Perror = elpicker_results self.p_results.epp, self.p_results.lpp, self.p_results.spe = elpicker_results
snr_results = getSNR(z_copy, self.p_params.tsnrz, self.p_results.mpickP) snr_results = getSNR(z_copy, self.p_params.tsnrz, self.p_results.mpp)
self.p_results.SNRP, self.p_results.SNRPdB, self.p_results.Pnoiselevel = snr_results self.p_results.snr, self.p_results.snrdb, _ = snr_results
# weight P-onset using symmetric error # weight P-onset using symmetric error
self.p_results.Pweight = get_quality_class(self.p_results.Perror, self.p_params.timeerrorsP) self.p_results.weight = get_quality_class(self.p_results.spe, self.p_params.timeerrorsP)
if self.p_results.Pweight <= self.first_motion_params.minfmweight and self.p_results.SNRP >= self.first_motion_params.minFMSNR: if self.p_results.weight <= self.first_motion_params.minfmweight and self.p_results.snr >= self.first_motion_params.minFMSNR:
# if SNR is low enough, try to determine first motion of onset
self.set_current_figure('fm_picker') self.set_current_figure('fm_picker')
self.p_results.FM = fmpicker(self.zstream, z_copy, self.first_motion_params.fmpickwin, self.p_results.fm = fmpicker(self.zstream, z_copy, self.first_motion_params.fmpickwin,
self.p_results.mpickP, self.iplot, self.current_figure, self.current_linecolor) self.p_results.mpp, self.iplot, self.current_figure, self.current_linecolor)
msg = "autopickstation: P-weight: {}, SNR: {}, SNR[dB]: {}, Polarity: {}" msg = "autopickstation: P-weight: {}, SNR: {}, SNR[dB]: {}, Polarity: {}"
msg = msg.format(self.p_results.Pweight, self.p_results.SNRP, self.p_results.SNRPdB, self.p_results.FM) msg = msg.format(self.p_results.weight, self.p_results.snr, self.p_results.snrdb, self.p_results.fm)
print(msg) print(msg)
msg = 'autopickstation: Refined P-Pick: {} s | P-Error: {} s' msg = 'autopickstation: Refined P-Pick: {} s | P-Error: {} s'
msg = msg.format(self.p_results.mpickP, self.p_results.Perror) msg = msg.format(self.p_results.mpp, self.p_results.spe)
print(msg) print(msg)
self.s_results.Sflag = 1 self.s_data.Sflag = 1
def _calculate_cuttimes(self, type, iteration): def _calculate_cuttimes(self, type, iteration):
""" """
@ -978,16 +896,16 @@ class AutopickStation(object):
if iteration == 1: if iteration == 1:
return [self.p_params.pstart, self.p_params.pstop] return [self.p_params.pstart, self.p_params.pstop]
if iteration == 2: if iteration == 2:
starttime2 = round(max(self.p_results.aicpick.getpick() - self.p_params.Precalcwin, 0)) starttime2 = round(max(self.p_data.aicpick.getpick() - self.p_params.Precalcwin, 0))
endtime2 = round( endtime2 = round(
min(len(self.ztrace.data) * self.ztrace.stats.delta, self.p_results.aicpick.getpick() + self.p_params.Precalcwin)) min(len(self.ztrace.data) * self.ztrace.stats.delta, self.p_data.aicpick.getpick() + self.p_params.Precalcwin))
return [starttime2, endtime2] return [starttime2, endtime2]
elif type.upper() == 'S': elif type.upper() == 'S':
if iteration == 1: if iteration == 1:
# Calculate start times for preliminary S onset # Calculate start times for preliminary S onset
start = round(max(self.p_results.mpickP + self.s_params.sstart, 0)) # limit start time to >0 seconds start = round(max(self.p_results.mpp + self.s_params.sstart, 0)) # limit start time to >0 seconds
stop = round(min([ stop = round(min([
self.p_results.mpickP + self.s_params.sstop, self.p_results.mpp + self.s_params.sstop,
self.etrace.stats.endtime - self.etrace.stats.starttime, self.etrace.stats.endtime - self.etrace.stats.starttime,
self.ntrace.stats.endtime - self.ntrace.stats.starttime self.ntrace.stats.endtime - self.ntrace.stats.starttime
])) ]))
@ -1059,7 +977,7 @@ class AutopickStation(object):
if self.aicarhpick.getpick() is None: if self.aicarhpick.getpick() is None:
error_msg = 'Invalid AIC S pick!' error_msg = 'Invalid AIC S pick!'
raise PickingFailedException(error_msg) raise PickingFailedException(error_msg)
self.s_results.aicSflag = 1 self.s_data.aicSflag = 1
msg = 'AIC S-pick passes quality control: Slope: {0} counts/s, ' \ msg = 'AIC S-pick passes quality control: Slope: {0} counts/s, ' \
'SNR: {1}\nGo on with refined picking ...\n' \ 'SNR: {1}\nGo on with refined picking ...\n' \
'autopickstation: re-filtering horizontal traces ' \ 'autopickstation: re-filtering horizontal traces ' \
@ -1105,7 +1023,7 @@ class AutopickStation(object):
if self.iplot: if self.iplot:
self.set_current_figure('el_S1pick') self.set_current_figure('el_S1pick')
epickS1, lpickS1, Serror1 = earllatepicker(h_copy, self.s_params.nfacS, self.s_params.tsnrh, epickS1, lpickS1, Serror1 = earllatepicker(h_copy, self.s_params.nfacS, self.s_params.tsnrh,
self.s_results.mpickS, self.iplot, fig=self.current_figure, self.s_results.mpp, self.iplot, fig=self.current_figure,
linecolor=self.current_linecolor) linecolor=self.current_linecolor)
h_copy[0].data = self.nstream_bph2.data h_copy[0].data = self.nstream_bph2.data
@ -1115,7 +1033,7 @@ class AutopickStation(object):
# why is it set to empty here? DA # why is it set to empty here? DA
linecolor = '' linecolor = ''
epickS2, lpickS2, Serror2 = earllatepicker(h_copy, self.s_params.nfacS, self.s_params.tsnrh, epickS2, lpickS2, Serror2 = earllatepicker(h_copy, self.s_params.nfacS, self.s_params.tsnrh,
self.s_results.mpickS, self.iplot, fig=self.current_figure, self.s_results.mpp, self.iplot, fig=self.current_figure,
linecolor=self.current_linecolor) linecolor=self.current_linecolor)
if epickS1 is not None and epickS2 is not None: if epickS1 is not None and epickS2 is not None:
@ -1127,7 +1045,7 @@ class AutopickStation(object):
ipick = np.argmin(epick) ipick = np.argmin(epick)
if self.s_params.algoS == 'AR3': if self.s_params.algoS == 'AR3':
epickS3, lpickS3, Serror3 = earllatepicker(h_copy, self.s_params.nfacS, self.s_params.tsnrh, epickS3, lpickS3, Serror3 = earllatepicker(h_copy, self.s_params.nfacS, self.s_params.tsnrh,
self.s_results.mpickS, self.iplot) self.s_results.mpp, self.iplot)
# get earliest of all three picks # get earliest of all three picks
epick = [epickS1, epickS2, epickS3] epick = [epickS1, epickS2, epickS3]
lpick = [lpickS1, lpickS2, lpickS3] lpick = [lpickS1, lpickS2, lpickS3]
@ -1137,24 +1055,23 @@ class AutopickStation(object):
ipick = np.argmin(epick) ipick = np.argmin(epick)
else: else:
ipick = np.argmin([epickS1, epickS2]) ipick = np.argmin([epickS1, epickS2])
self.s_results.epickS = epick[ipick] self.s_results.epp = epick[ipick]
self.s_results.lpickS = lpick[ipick] self.s_results.lpp = lpick[ipick]
self.s_results.Serror = pickerr[ipick] self.s_results.spe = pickerr[ipick]
msg = 'autopickstation: Refined S-Pick: {} s | S-Error: {} s'.format(self.s_results.mpickS, msg = 'autopickstation: Refined S-Pick: {} s | S-Error: {} s'.format(self.s_results.mpp,
self.s_results.Serror) self.s_results.spe)
print(msg) print(msg)
# get SNR # get SNR
self.s_results.SNRS, self.s_results.SNRSdB, self.s_results.Snoiselevel = getSNR(h_copy, self.s_params.tsnrh, self.s_results.snr, self.s_results.snrdb, _ = getSNR(h_copy, self.s_params.tsnrh, self.s_results.mpp)
self.s_results.mpickS)
self.s_results.Sweight = get_quality_class(self.s_results.Serror, self.s_params.timeerrorsS) self.s_results.weight = get_quality_class(self.s_results.spe, self.s_params.timeerrorsS)
print('autopickstation: S-weight: {0}, SNR: {1}, ' print('autopickstation: S-weight: {0}, SNR: {1}, '
'SNR[dB]: {2}\n' 'SNR[dB]: {2}\n'
'##################################################' '##################################################'
''.format(self.s_results.Sweight, self.s_results.SNRS, self.s_results.SNRSdB)) ''.format(self.s_results.weight, self.s_results.snr, self.s_results.snrdb))
def pick_s_phase(self): def pick_s_phase(self):
@ -1185,9 +1102,9 @@ class AutopickStation(object):
self.s_params.tsmoothS, aicarhpick.getpick(), self.current_figure, self.current_linecolor) self.s_params.tsmoothS, aicarhpick.getpick(), self.current_figure, self.current_linecolor)
# save refSpick for later plotitng # save refSpick for later plotitng
self.refSpick = refSpick self.refSpick = refSpick
self.s_results.mpickS = refSpick.getpick() self.s_results.mpp = refSpick.getpick()
if self.s_results.mpickS is not None: if self.s_results.mpp is not None:
self._pick_s_quality_assessment(self.h_copy) self._pick_s_quality_assessment(self.h_copy)
def set_current_figure(self, figkey): def set_current_figure(self, figkey):

View File

@ -178,15 +178,14 @@ class TestAutopickStation(unittest.TestCase):
"""Picking on a stream without horizontal traces should still pick the P phase on the vertical component""" """Picking on a stream without horizontal traces should still pick the P phase on the vertical component"""
wfstream = self.gra1.copy() wfstream = self.gra1.copy()
wfstream = wfstream.select(channel='*Z') wfstream = wfstream.select(channel='*Z')
expected = {'P': {'picker': 'auto', 'snrdb': 15.405649120980094, 'network': u'GR', 'weight': 0, 'Mo': None, 'marked': [], 'lpp': UTCDateTime(2016, 1, 24, 10, 41, 32, 690000), 'Mw': None, 'fc': None, 'snr': 34.718816470730317, 'epp': UTCDateTime(2016, 1, 24, 10, 41, 28, 890000), 'mpp': UTCDateTime(2016, 1, 24, 10, 41, 31, 690000), 'w0': None, 'spe': 0.9333333333333323, 'fm': 'D', 'channel': u'LHZ'}, 'S': {'picker': 'auto', 'Sweight': 4, 'w0': None, 'epickP': None, 'epickS': None, 'FM': 'N', 'p_aic_plot_flag': 0, 'Serror': None, 'aicSflag': 0, 'Perror': None, 'lpickS': None, 'Mo': None, 'lpickP': None, 'Mw': None, 'fc': None, 'SNRSdB': None, 'Pweight': 4, 'Pflag': 0, 'Pmarker': [], 'mpickP': None, 'Ao': None, 'mpickS': None, 'SNRP': None, 'SNRS': None, 'Sflag': 1, 'SNRPdB': None}, 'station': u'GRA1'} expected = {'P': {'picker': 'auto', 'snrdb': 15.405649120980094, 'network': u'GR', 'weight': 0, 'Ao': None, 'Mo': None, 'marked': [], 'lpp': UTCDateTime(2016, 1, 24, 10, 41, 32, 690000), 'Mw': None, 'fc': None, 'snr': 34.718816470730317, 'epp': UTCDateTime(2016, 1, 24, 10, 41, 28, 890000), 'mpp': UTCDateTime(2016, 1, 24, 10, 41, 31, 690000), 'w0': None, 'spe': 0.9333333333333323, 'fm': 'D', 'channel': u'LHZ'}, 'S': {'picker': 'auto', 'snrdb': None, 'network': None, 'weight': 4, 'Mo': None, 'Ao': None, 'lpp': None, 'Mw': None, 'fc': None, 'snr': None, 'marked': [], 'mpp': None, 'w0': None, 'spe': None, 'epp': None, 'fm': 'N', 'channel': None}, 'station': u'GRA1'}
with HidePrints(): with HidePrints():
result = autopickstation(wfstream=wfstream, pickparam=self.pickparam_taupy_disabled, metadata=(None, None)) result = autopickstation(wfstream=wfstream, pickparam=self.pickparam_taupy_disabled, metadata=(None, None))
print(result['S'])
self.assertEqual(expected, result) self.assertEqual(expected, result)
def test_autopickstation_a106_taupy_enabled(self): def test_autopickstation_a106_taupy_enabled(self):
"""This station has invalid values recorded on both N and E component, but a pick can still be found on Z""" """This station has invalid values recorded on both N and E component, but a pick can still be found on Z"""
expected = {'P': {'picker': 'auto', 'snrdb': 12.862128789922826, 'network': u'Z3', 'weight': 0, 'Mo': None, 'marked': [], 'lpp': UTCDateTime(2016, 1, 24, 10, 41, 34), 'Mw': None, 'fc': None, 'snr': 19.329155459132608, 'epp': UTCDateTime(2016, 1, 24, 10, 41, 30), 'mpp': UTCDateTime(2016, 1, 24, 10, 41, 33), 'w0': None, 'spe': 1.6666666666666667, 'fm': None, 'channel': u'LHZ'}, 'S': {'picker': 'auto', 'snrdb': None, 'network': u'Z3', 'weight': 4, 'Ao': None, 'Mo': None, 'marked': [], 'lpp': UTCDateTime(2016, 1, 24, 10, 28, 56), 'Mw': None, 'fc': None, 'snr': None, 'epp': UTCDateTime(2016, 1, 24, 10, 28, 24), 'mpp': UTCDateTime(2016, 1, 24, 10, 28, 40), 'w0': None, 'spe': None, 'fm': None, 'channel': u'LHE'}, 'station': u'A106A'} expected = {'P': {'picker': 'auto', 'snrdb': 12.862128789922826, 'network': u'Z3', 'weight': 0, 'Ao': None, 'Mo': None, 'marked': [], 'lpp': UTCDateTime(2016, 1, 24, 10, 41, 34), 'Mw': None, 'fc': None, 'snr': 19.329155459132608, 'epp': UTCDateTime(2016, 1, 24, 10, 41, 30), 'mpp': UTCDateTime(2016, 1, 24, 10, 41, 33), 'w0': None, 'spe': 1.6666666666666667, 'fm': None, 'channel': u'LHZ'}, 'S': {'picker': 'auto', 'snrdb': None, 'network': u'Z3', 'weight': 4, 'Ao': None, 'Mo': None, 'marked': [], 'lpp': UTCDateTime(2016, 1, 24, 10, 28, 56), 'Mw': None, 'fc': None, 'snr': None, 'epp': UTCDateTime(2016, 1, 24, 10, 28, 24), 'mpp': UTCDateTime(2016, 1, 24, 10, 28, 40), 'w0': None, 'spe': None, 'fm': None, 'channel': u'LHE'}, 'station': u'A106A'}
with HidePrints(): with HidePrints():
result = autopickstation(wfstream=self.a106, pickparam=self.pickparam_taupy_enabled, metadata=self.metadata, origin=self.origin) result = autopickstation(wfstream=self.a106, pickparam=self.pickparam_taupy_enabled, metadata=self.metadata, origin=self.origin)
self.assertEqual(expected, result) self.assertEqual(expected, result)