diff --git a/CHANGELOG.md b/CHANGELOG.md index 5899154..426ec94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ Copyright (c) 2022-2024 Claudio Satriano ## unreleased - `seiscat download` renamed to `seiscat fetchdata` +- New option for `seiscat fetchdata`: `--sds` to retrieve waveform data from + a local SDS archive - New option for `seiscat initdb` and `seiscat updatedb`: `--fromfile` to initialize or update the database from a CSV file diff --git a/seiscat/fetchdata/event_waveforms.py b/seiscat/fetchdata/event_waveforms.py index 77510e4..5e51e4f 100644 --- a/seiscat/fetchdata/event_waveforms.py +++ b/seiscat/fetchdata/event_waveforms.py @@ -10,6 +10,7 @@ (https://www.gnu.org/licenses/gpl-3.0-standalone.html) """ import pathlib +from .sds import get_sds_client, fetch_sds_waveforms from .mass_downloader import mass_download_waveforms from ..database.dbfunctions import read_events_from_db from ..utils import ExceptionExit @@ -24,7 +25,13 @@ def fetch_event_waveforms(config): """ with ExceptionExit(): events = read_events_from_db(config) - event_dir = pathlib.Path(config['event_dir']) - event_dir.mkdir(parents=True, exist_ok=True) - for event in events: - mass_download_waveforms(config, event) + event_dir = pathlib.Path(config['event_dir']) + event_dir.mkdir(parents=True, exist_ok=True) + args = config['args'] + if args.sds: + sds_client = get_sds_client(args.sds) + for event in events: + fetch_sds_waveforms(config, event, sds_client) + else: + for event in events: + mass_download_waveforms(config, event) diff --git a/seiscat/fetchdata/sds.py b/seiscat/fetchdata/sds.py new file mode 100644 index 0000000..f714178 --- /dev/null +++ b/seiscat/fetchdata/sds.py @@ -0,0 +1,86 @@ +# -*- coding: utf8 -*- +# SPDX-License-Identifier: GPL-3.0-or-later +""" +Fetch event waveforms from a local SDS archive. + +:copyright: + 2022-2024 Claudio Satriano +:license: + GNU General Public License v3.0 or later + (https://www.gnu.org/licenses/gpl-3.0-standalone.html) +""" +import pathlib +import re +from obspy.clients.filesystem.sds import Client + + +def get_sds_client(sds_root): + """ + Get an SDS client. + + :param sds_root: path to SDS archive + :type sds_root: str + + :return: SDS client + :rtype: obspy.clients.filesystem.sds.Client + """ + client = Client(sds_root) + all_nslc = client.get_all_nslc() + if not all_nslc: + raise FileNotFoundError( + f'No SDS archive found in {sds_root}') + return client + + +def _check_channel(channel, channel_priorities): + """ + Check if a channel is in the list of channel priorities. + + :param channel: channel code + :type channel: str + :param channel_priorities: list of channel codes + :type channel_priorities: list + + :return: True if the channel is in the list of channel priorities + :rtype: bool + """ + for priority in channel_priorities: + # Convert wildcard pattern to regex pattern + regex_pattern = re.escape(priority)\ + .replace(r'\*', '.*').replace(r'\?', '.') + # Handle character sets like [ZNE] + regex_pattern = re.sub(r'\\\[([^\\\]]+)\\\]', r'[\1]', regex_pattern) + if re.fullmatch(regex_pattern, channel): + return True + return False + + +def fetch_sds_waveforms(config, event, client): + """ + Fetch event waveforms from a local SDS archive. + + :param config: config object + :type config: dict + :param event: an event dictionary + :type event: dict + :param client: SDS client + :type client: obspy.clients.filesystem.sds.Client + """ + event_dir = pathlib.Path(config['event_dir'], event['evid'], 'waveforms') + event_dir.mkdir(parents=True, exist_ok=True) + seconds_before = config['seconds_before_origin'] + seconds_after = config['seconds_after_origin'] + t0 = event['time'] - seconds_before + t1 = event['time'] + seconds_after + channel_priorities = config['channel_priorities'] + print(f'Fetching waveforms for event: {event["evid"]}') + all_nslc = client.get_all_nslc() + for nslc in all_nslc: + if not _check_channel(nslc[-1], channel_priorities): + continue + net, sta, loc, chan = nslc + st = client.get_waveforms(net, sta, loc, chan, t0, t1) + outfile = event_dir / f'{net}.{sta}.{loc}.{chan}.mseed' + st.write(outfile, format='MSEED') + print(f' {outfile} written') + print() diff --git a/seiscat/parse_arguments.py b/seiscat/parse_arguments.py index 9959318..b72703b 100644 --- a/seiscat/parse_arguments.py +++ b/seiscat/parse_arguments.py @@ -192,6 +192,12 @@ def parse_arguments(): help='fetch full event details and/or waveform data and metadata', formatter_class=NewlineHelpFormatter ) + fetchdata_parser.add_argument( + '-s', '--sds', + metavar='SDS_DIR', + type=str, + help='fetch waveform data from a local SDS archive' + ) fetchdata_parser.add_argument( 'eventid', nargs='?', help='event ID to download (default: all events)'