Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'metric' argument to Party.decluster() #100

Merged
merged 6 commits into from
Jun 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions eqcorrscan/core/match_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,18 +410,23 @@ def rethreshold(self, new_threshold, new_threshold_type='MAD'):
family.catalog = Catalog([d.event for d in family])
return self

def decluster(self, trig_int, timing='detect'):
def decluster(self, trig_int, timing='detect', metric='avg_cor'):
"""
De-cluster a Party of detections by enforcing a detection separation.

De-clustering occurs between events detected by different (or the same)
templates. If multiple detections occur within trig_int then the
detection with the highest average single-channel correlation
(calculated as the cross-correlation sum / number of channels used in
detection) will be maintained.
preferred detection will be determined by the metric argument. This
can be either the average single-station correlation coefficient which
is calculated as Detection.detect_val / Detection.no_chans, or the
raw cross channel correlation sum which is simply Detection.detect_val.

:type trig_int: float
:param trig_int: Minimum detection separation in seconds.
:type metric: str
:param metric: What metric to sort peaks by. Either 'avg_cor' which
takes the single station average correlation or 'cor_sum' which
takes the total correlation sum across all channels.
:type timing: str
:param timing:
Either 'detect' or 'origin' to decluster based on either the
Expand All @@ -444,11 +449,24 @@ def decluster(self, trig_int, timing='detect'):
for fam in self.families:
all_detections.extend(fam.detections)
if timing == 'detect':
detect_info = [(d.detect_time, d.detect_val)
for d in all_detections]
if metric == 'avg_cor':
detect_info = [(d.detect_time, d.detect_val / d.no_chans)
for d in all_detections]
elif metric == 'cor_sum':
detect_info = [(d.detect_time, d.detect_val)
for d in all_detections]
else:
raise MatchFilterError('metric is not cor_sum or avg_cor')
elif timing == 'origin':
detect_info = [(_get_origin(d.event).time, d.detect_val)
for d in all_detections]
if metric == 'avg_cor':
detect_info = [(_get_origin(d.event).time,
d.detect_val / d.no_chans)
for d in all_detections]
elif metric == 'cor_sum':
detect_info = [(_get_origin(d.event).time, d.detect_val)
for d in all_detections]
else:
raise MatchFilterError('metric is not cor_sum or avg_cor')
else:
raise MatchFilterError('timing is not detect or origin')
min_det = sorted([d[0] for d in detect_info])[0]
Expand Down
24 changes: 15 additions & 9 deletions eqcorrscan/tests/match_filter_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,15 +696,21 @@ def test_party_add(self):
def test_party_decluster(self):
"""Test the decluster method on party."""
for trig_int in [40, 15, 3600]:
declustered = self.party.copy().decluster(trig_int=trig_int)
declustered_dets = [d for family in declustered
for d in family.detections]
for det in declustered_dets:
time_difs = [abs(det.detect_time - d.detect_time)
for d in declustered_dets]
for dif in time_difs:
if dif != 0:
self.assertTrue(dif > trig_int)
for metric in ['avg_cor', 'cor_sum']:
declust = self.party.copy().decluster(trig_int=trig_int,
metric=metric)
declustered_dets = [d for family in declust
for d in family.detections]
for det in declustered_dets:
time_difs = [abs(det.detect_time - d.detect_time)
for d in declustered_dets]
for dif in time_difs:
if dif != 0:
self.assertTrue(dif > trig_int)
with self.assertRaises(MatchFilterError):
self.party.copy().decluster(trig_int=trig_int,
timing='origin',
metric=metric)

def test_party_lag_calc(self):
"""Test the lag-calc method on Party objects."""
Expand Down