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

Client lag-calc implementation #589

Merged
merged 1 commit into from
Oct 22, 2024
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
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
- core.match_filter.tribe
- Add option to set minimum number of stations required to use a template in detect
(`min_stations` kwarg)
- core.match_filter.party
- Add client_lag_calc method to run lag-calc using data from a client.

## 0.5.0
* core.match_filter.tribe
Expand Down
84 changes: 84 additions & 0 deletions eqcorrscan/core/match_filter/party.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import logging
from os.path import join
import warnings
from tempfile import template

Check failure on line 24 in eqcorrscan/core/match_filter/party.py

View workflow job for this annotation

GitHub Actions / flake8-linter

F401 'tempfile.template' imported but unused
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from tempfile import template


import numpy as np
from obspy import Catalog, read_events, Stream
Expand Down Expand Up @@ -858,7 +859,90 @@
self.families = families
return self

def client_lag_calc(
self,
client,
shift_len=0.2,
min_gap=None,
retries=3,
*args, **kwargs):

Check failure on line 868 in eqcorrscan/core/match_filter/party.py

View workflow job for this annotation

GitHub Actions / flake8-linter

E125 continuation line with same indent as next logical line
"""
Compute picks based on cross-correlation using data from a Client.

Works in-place on events in Party.

:param client:
obspy FDSN-like client with at least a .get_waveforms method

All other arguments are passed to party.lag_calc. For documentation
see that method.
"""
from eqcorrscan.core.match_filter.helpers.tribe import _download_st

Check warning on line 880 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L880

Added line #L880 was not covered by tests

# 1. Group detections into chunks of process-len
det_times = [d.detect_time for f in self for d in f]
# Work out when our data need to start and end incorporating data pads
det_start, det_end = min(det_times), max(det_times)
pad = shift_len * 2

Check warning on line 886 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L885-L886

Added lines #L885 - L886 were not covered by tests
max_template_length = max(tr.stats.endtime - tr.stats.starttime
for f in self for tr in f.template.st)
det_start -= pad
chunk_overlap = pad + max_template_length

Check warning on line 890 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L889-L890

Added lines #L889 - L890 were not covered by tests
chunk_length = max(f.template.process_length for f in self)
det_end += chunk_overlap

Check warning on line 892 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L892

Added line #L892 was not covered by tests

# Loop over groups
chunk_start, chunk_end = det_start, det_start + chunk_length
detections_run = set() # Keep track of what we have done
catalog = Catalog()
Logger.info(f"Running in chunks of {chunk_length} s between "

Check warning on line 898 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L895-L898

Added lines #L895 - L898 were not covered by tests
f"{det_start} and {det_end}")
while chunk_start <= det_end:
# Make a party of just those detections in this chunk of data
chunk = Party()

Check warning on line 902 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L902

Added line #L902 was not covered by tests
for family in self:
chunk_detections = [
d for d in family
if d.detect_time <= (chunk_end - chunk_overlap)
and d.detect_time >= (chunk_start + pad)
and d.id not in detections_run]
if len(chunk_detections):
chunk_family = Family(

Check warning on line 910 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L910

Added line #L910 was not covered by tests
template=family.template, detections=chunk_detections)
chunk += chunk_family

Check warning on line 912 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L912

Added line #L912 was not covered by tests
if len(chunk) == 0:
Logger.info(f"No detections between {chunk_start} and "

Check warning on line 914 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L914

Added line #L914 was not covered by tests
f"{chunk_end}, skipping")
chunk_start += (chunk_length - chunk_overlap)
chunk_end = chunk_start + chunk_length
continue
Logger.info(f"Working on {len(chunk)} detections")

Check warning on line 919 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L916-L919

Added lines #L916 - L919 were not covered by tests

# 2. Download stream for those detections
Logger.info(

Check warning on line 922 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L922

Added line #L922 was not covered by tests
f"Downloading data between {chunk_start} and {chunk_end}")
template_channel_ids = {
tuple(tr.id.split('.')) for f in chunk for tr in f.template.st}
st = _download_st(

Check warning on line 926 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L926

Added line #L926 was not covered by tests
starttime=chunk_start, endtime=chunk_end, buff=300.0,
min_gap=min_gap, template_channel_ids=template_channel_ids,
client=client, retries=retries)
Logger.info(f"Downloaded data for {len(st)} channels, expected "

Check warning on line 930 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L930

Added line #L930 was not covered by tests
f"{len(template_channel_ids)} channels")

# 3. Run lag-calc
catalog += chunk.lag_calc(

Check warning on line 934 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L934

Added line #L934 was not covered by tests
stream=st, pre_processed=False, shift_len=shift_len,
*args, **kwargs)

# 4. Run next group
detections_run.update({d.id for f in chunk for d in f})
chunk_start += (chunk_length - chunk_overlap)
chunk_end = chunk_start + chunk_length
return catalog

Check warning on line 942 in eqcorrscan/core/match_filter/party.py

View check run for this annotation

Codecov / codecov/patch

eqcorrscan/core/match_filter/party.py#L940-L942

Added lines #L940 - L942 were not covered by tests


def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4,

Check failure on line 945 in eqcorrscan/core/match_filter/party.py

View workflow job for this annotation

GitHub Actions / flake8-linter

E303 too many blank lines (2)
min_cc_from_mean_cc_factor=None, vertical_chans=['Z'],
horizontal_chans=['E', 'N', '1', '2'],
cores=1, interpolate=False, plot=False, plotdir=None,
Expand Down
7 changes: 7 additions & 0 deletions eqcorrscan/tests/matched_filter/match_filter_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,13 @@ def test_party_lag_calc_preprocessed(self):
stream=self.st, pre_processed=True)
self.assertEqual(len(catalog), 4)

@pytest.mark.network
def test_party_lag_calc_from_client(self):
""" Test that getting data from a client works as expected. """
catalog = self.party.copy().client_lag_calc(
client=Client("NCEDC"))
self.assertEqual(len(catalog), 4)

def test_party_lag_calc_empty_families(self):
""" Test that passing some empty families works properly, see #341. """
party = self.party.copy()
Expand Down
Loading