utdquake 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- utdquake/__init__.py +0 -0
- utdquake/clients/__init__.py +0 -0
- utdquake/clients/local/__init__.py +0 -0
- utdquake/clients/local/client.py +123 -0
- utdquake/clients/utd/__init__.py +0 -0
- utdquake/clients/utd/client.py +154 -0
- utdquake/clients/utd/utils.py +422 -0
- utdquake/core/__init__.py +0 -0
- utdquake/core/database.py +128 -0
- utdquake/scan/__init__.py +0 -0
- utdquake/scan/scanner.py +886 -0
- utdquake-0.0.1.dist-info/LICENSE +674 -0
- utdquake-0.0.1.dist-info/METADATA +45 -0
- utdquake-0.0.1.dist-info/RECORD +16 -0
- utdquake-0.0.1.dist-info/WHEEL +5 -0
- utdquake-0.0.1.dist-info/top_level.txt +1 -0
utdquake/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# /**
|
|
2
|
+
# * @author Emmanuel Castillo
|
|
3
|
+
# * @email [castillo.280997@gmail.com]
|
|
4
|
+
# * @create date 2024-09-22 22:07:55
|
|
5
|
+
# * @modify date 2024-09-22 22:07:55
|
|
6
|
+
# * @desc [description]
|
|
7
|
+
# */
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# import objects
|
|
13
|
+
import os
|
|
14
|
+
import glob
|
|
15
|
+
import sqlite3
|
|
16
|
+
import pandas as pd
|
|
17
|
+
from obspy import UTCDateTime
|
|
18
|
+
from datetime import timedelta
|
|
19
|
+
from obspy.core.util.misc import BAND_CODE
|
|
20
|
+
from scan.stats import get_rolling_stats
|
|
21
|
+
from obspy.clients.fdsn import Client as FDSNClient
|
|
22
|
+
from obspy.clients.filesystem.sds import Client
|
|
23
|
+
|
|
24
|
+
class LocalClient(Client):
|
|
25
|
+
|
|
26
|
+
def __init__(self,root,fmt,**kwargs):
|
|
27
|
+
"""
|
|
28
|
+
This script is an example to make a client class
|
|
29
|
+
for specific data structure archive on local filesystem.
|
|
30
|
+
|
|
31
|
+
The mandatory parameters for LocalClient class is: root_path and field_name
|
|
32
|
+
Example:
|
|
33
|
+
---------
|
|
34
|
+
root = "/home/emmanuel/myarchive"
|
|
35
|
+
fmt = "{year}-{month:02d}/{year}-{month:02d}-{day:02d}/{network}.{station}.{location}.{channel}.{year}.{julday:03d}"
|
|
36
|
+
client = LocalClient(root,fmt)
|
|
37
|
+
st = client.get_waveforms("YY","XXXX","00",
|
|
38
|
+
channel="HHZ",starttime = UTCDateTime("20220102T000100"),
|
|
39
|
+
endtime = UTCDateTime("20220102T000200"))
|
|
40
|
+
|
|
41
|
+
Parameters:
|
|
42
|
+
-----------
|
|
43
|
+
root: str
|
|
44
|
+
Path where is located the Local structure
|
|
45
|
+
fmt: str
|
|
46
|
+
The parameter should name the corresponding keys of the stats object, e.g.
|
|
47
|
+
"{year}-{month:02d}/{year}-{month:02d}-{day:02d}/{network}.{station}.{location}.{channel}.{year}.{julday:03d}"
|
|
48
|
+
|
|
49
|
+
**kwargs SDS client additional args
|
|
50
|
+
"""
|
|
51
|
+
self.root = root
|
|
52
|
+
self.fmt = fmt
|
|
53
|
+
super().__init__(root,**kwargs)
|
|
54
|
+
|
|
55
|
+
def _get_filenames(self, network, station, location, channel, starttime,
|
|
56
|
+
endtime, sds_type=None):
|
|
57
|
+
"""
|
|
58
|
+
Get list of filenames for certain waveform and time span.
|
|
59
|
+
:type network: str
|
|
60
|
+
:param network: Network code of requested data (e.g. "IU").
|
|
61
|
+
:type station: str
|
|
62
|
+
:param station: Station code of requested data (e.g. "ANMO").
|
|
63
|
+
:type location: str
|
|
64
|
+
:param location: Location code of requested data (e.g. "").
|
|
65
|
+
:type channel: str
|
|
66
|
+
:param channel: Channel code of requested data (e.g. "HHZ").
|
|
67
|
+
:type time: :class:`~obspy.core.utcdatetime.UTCDateTime`
|
|
68
|
+
:param time: Time of interest.
|
|
69
|
+
:type sds_type: str
|
|
70
|
+
:param sds_type: None
|
|
71
|
+
:rtype: str
|
|
72
|
+
"""
|
|
73
|
+
sds_type = sds_type or self.sds_type
|
|
74
|
+
# SDS has data sometimes in adjacent days, so also try to read the
|
|
75
|
+
# requested data from those files. Usually this is only a few seconds
|
|
76
|
+
# of data after midnight, but for now we play safe here to catch all
|
|
77
|
+
# requested data (and with MiniSEED - the usual SDS file format - we
|
|
78
|
+
# can use starttime/endtime kwargs anyway to read only desired parts).
|
|
79
|
+
year_doy = set()
|
|
80
|
+
# determine how far before starttime/after endtime we should check
|
|
81
|
+
# other dayfiles for the data
|
|
82
|
+
t_buffer = self.fileborder_samples / BAND_CODE.get(channel[:1], 20.0)
|
|
83
|
+
t_buffer = max(t_buffer, self.fileborder_seconds)
|
|
84
|
+
t = starttime - t_buffer
|
|
85
|
+
t_max = endtime + t_buffer
|
|
86
|
+
# make a list of year/doy combinations that covers the whole requested
|
|
87
|
+
# time window (plus day before and day after)
|
|
88
|
+
while t < t_max:
|
|
89
|
+
year_doy.add((t.year,t.month,t.day, t.julday))
|
|
90
|
+
t += timedelta(days=1)
|
|
91
|
+
year_doy.add((t_max.year,t_max.month,t_max.day, t_max.julday))
|
|
92
|
+
|
|
93
|
+
full_paths = set()
|
|
94
|
+
for year,month,day,doy in year_doy:
|
|
95
|
+
filename = self.fmt.format(
|
|
96
|
+
network=network, station=station, location=location,
|
|
97
|
+
channel=channel, year=year, month=month,
|
|
98
|
+
day=day, julday=doy,sds_type=sds_type)
|
|
99
|
+
full_path = os.path.join(self.sds_root, filename)
|
|
100
|
+
full_paths = full_paths.union(glob.glob(full_path))
|
|
101
|
+
|
|
102
|
+
return full_paths
|
|
103
|
+
|
|
104
|
+
def _get_filename(self, network, station, location, channel, time, sds_type=None):
|
|
105
|
+
"""
|
|
106
|
+
Get filename for certain waveform.
|
|
107
|
+
:type network: str
|
|
108
|
+
:param network: Network code of requested data (e.g. "IU").
|
|
109
|
+
:type station: str
|
|
110
|
+
:param station: Station code of requested data (e.g. "ANMO").
|
|
111
|
+
:type location: str
|
|
112
|
+
:param location: Location code of requested data (e.g. "").
|
|
113
|
+
:type channel: str
|
|
114
|
+
:param channel: Channel code of requested data (e.g. "HHZ").
|
|
115
|
+
:type time: :class:`~obspy.core.utcdatetime.UTCDateTime`
|
|
116
|
+
:param time: Time of interest.
|
|
117
|
+
"""
|
|
118
|
+
sds_type = sds_type or self.sds_type
|
|
119
|
+
filename = self.fmt.format(
|
|
120
|
+
network=network, station=station, location=location,
|
|
121
|
+
channel=channel, year=time.year, month=time.month,
|
|
122
|
+
day=time.day, doy=time.julday,sds_type=sds_type)
|
|
123
|
+
return os.path.join(self.sds_root, filename)
|
|
File without changes
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
|
|
2
|
+
import os
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from .utils import get_event_ids, get_custom_info, save_info
|
|
5
|
+
from utdquake.tools.stats import get_rolling_stats
|
|
6
|
+
from obspy.clients.fdsn import Client as FDSNClient
|
|
7
|
+
|
|
8
|
+
class Client(FDSNClient):
|
|
9
|
+
"""
|
|
10
|
+
A client class for retrieving and calculating rolling statistics on seismic data.
|
|
11
|
+
|
|
12
|
+
Inherits from:
|
|
13
|
+
FDSNClient: Base class for FDSN web service clients.
|
|
14
|
+
|
|
15
|
+
Attributes:
|
|
16
|
+
output (str): Path to the SQLite database file for saving results.
|
|
17
|
+
step (int): Step size for the rolling window in seconds.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self,*args, **kwargs):
|
|
21
|
+
"""
|
|
22
|
+
Initializes the Client class by calling the constructor
|
|
23
|
+
of the base FDSN Client class.
|
|
24
|
+
|
|
25
|
+
Parameters:
|
|
26
|
+
*args : variable length argument list
|
|
27
|
+
Positional arguments passed to the base class constructor.
|
|
28
|
+
**kwargs : variable length keyword arguments
|
|
29
|
+
Keyword arguments passed to the base class constructor.
|
|
30
|
+
"""
|
|
31
|
+
super().__init__(*args, **kwargs)
|
|
32
|
+
|
|
33
|
+
def get_custom_events(self, *args, max_events_in_ram=1e6,
|
|
34
|
+
output_folder=None, drop_level=True,
|
|
35
|
+
**kwargs):
|
|
36
|
+
"""
|
|
37
|
+
Retrieves custom seismic event data including origins, picks,
|
|
38
|
+
and magnitudes.
|
|
39
|
+
|
|
40
|
+
Parameters:
|
|
41
|
+
*args : variable length argument list
|
|
42
|
+
Positional arguments passed to the get_events method.
|
|
43
|
+
max_events_in_ram : int, optional, default=1e6
|
|
44
|
+
Maximum number of events to hold in memory (RAM) before stopping or
|
|
45
|
+
prompting to save the data to disk.
|
|
46
|
+
output_folder : str, optional, default=None
|
|
47
|
+
Folder path where the event data will be saved if provided. If not
|
|
48
|
+
specified, data will only be stored in memory.
|
|
49
|
+
drop_level : bool, optional, default=True
|
|
50
|
+
True if you want to have only one level in your origin dataframe.
|
|
51
|
+
**kwargs : variable length keyword arguments
|
|
52
|
+
Keyword arguments passed to the get_events method.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
tuple
|
|
56
|
+
A tuple containing:
|
|
57
|
+
- DataFrame of origins for all events.
|
|
58
|
+
- DataFrame of picks for all events.
|
|
59
|
+
- DataFrame of magnitudes for all events.
|
|
60
|
+
"""
|
|
61
|
+
# Retrieve the catalog of events using the get_events method
|
|
62
|
+
catalog = self.get_events(*args, **kwargs)
|
|
63
|
+
|
|
64
|
+
# Extract event IDs from the catalog
|
|
65
|
+
ev_ids = get_event_ids(catalog)
|
|
66
|
+
|
|
67
|
+
# Initialize lists to store origins, picks, and magnitudes
|
|
68
|
+
all_origins, all_picks, all_mags = [], [], []
|
|
69
|
+
|
|
70
|
+
# Loop through each event ID to gather detailed event information
|
|
71
|
+
for ev_id in ev_ids[::-1]:
|
|
72
|
+
# Catalog with arrivals. This is a workaround to retrieve
|
|
73
|
+
# arrivals by specifying the event ID.
|
|
74
|
+
cat = self.get_events(eventid=ev_id)
|
|
75
|
+
|
|
76
|
+
# Get the first event from the catalog
|
|
77
|
+
event = cat[0]
|
|
78
|
+
|
|
79
|
+
# Extract custom information for the event
|
|
80
|
+
origin, picks, mags = get_custom_info(event, drop_level)
|
|
81
|
+
|
|
82
|
+
info = {
|
|
83
|
+
"origin": origin,
|
|
84
|
+
"picks": picks,
|
|
85
|
+
"mags": mags
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Save information to the output folder, if specified
|
|
89
|
+
if output_folder is not None:
|
|
90
|
+
if not os.path.isdir(output_folder):
|
|
91
|
+
os.makedirs(output_folder)
|
|
92
|
+
save_info(output_folder, info=info)
|
|
93
|
+
|
|
94
|
+
# Append information to the lists or break if memory limit is reached
|
|
95
|
+
if len(all_origins) < max_events_in_ram:
|
|
96
|
+
all_origins.append(origin)
|
|
97
|
+
all_picks.append(picks)
|
|
98
|
+
all_mags.append(mags)
|
|
99
|
+
else:
|
|
100
|
+
if output_folder is not None:
|
|
101
|
+
print(f"max_events_in_ram: {max_events_in_ram} is reached. "
|
|
102
|
+
"But it is still saving on disk.")
|
|
103
|
+
else:
|
|
104
|
+
print(f"max_events_in_ram: {max_events_in_ram} is reached. "
|
|
105
|
+
"It is recommended to save the data on disk using the 'output_folder' parameter.")
|
|
106
|
+
break
|
|
107
|
+
|
|
108
|
+
# Concatenate data from all events, if multiple events are found
|
|
109
|
+
if len(ev_ids) > 1:
|
|
110
|
+
all_origins = pd.concat(all_origins, axis=0)
|
|
111
|
+
all_picks = pd.concat(all_picks, axis=0)
|
|
112
|
+
all_mags = pd.concat(all_mags, axis=0)
|
|
113
|
+
else:
|
|
114
|
+
# If only one event is found, retain the single DataFrame
|
|
115
|
+
all_origins = all_origins[0]
|
|
116
|
+
all_picks = all_picks[0]
|
|
117
|
+
all_mags = all_mags[0]
|
|
118
|
+
|
|
119
|
+
return all_origins, all_picks, all_mags
|
|
120
|
+
|
|
121
|
+
def get_stats(self, output, step, starttime, endtime, **kwargs):
|
|
122
|
+
"""
|
|
123
|
+
Retrieve waveforms and compute rolling statistics for the specified time interval.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
output (str): Path to the SQLite database file for saving results.
|
|
127
|
+
step (int): Step size for the rolling window in seconds.
|
|
128
|
+
starttime (UTCDateTime): Start time of the data.
|
|
129
|
+
endtime (UTCDateTime): End time of the data.
|
|
130
|
+
**kwargs: Keyword arguments for retrieving waveforms, including:
|
|
131
|
+
- Additional arguments required by `self.get_waveforms`.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
pd.DataFrame: A DataFrame containing rolling statistics for each interval, with columns including:
|
|
135
|
+
- Availability percentage
|
|
136
|
+
- Gaps duration
|
|
137
|
+
- Overlaps duration
|
|
138
|
+
- Gaps count
|
|
139
|
+
- Overlaps count
|
|
140
|
+
"""
|
|
141
|
+
# Extract start and end times from keyword arguments
|
|
142
|
+
# Retrieve waveforms using base class method
|
|
143
|
+
st = self.get_waveforms(**kwargs)
|
|
144
|
+
|
|
145
|
+
# Compute rolling statistics for the retrieved waveforms
|
|
146
|
+
stats = get_rolling_stats(
|
|
147
|
+
st=st,
|
|
148
|
+
step=step,
|
|
149
|
+
starttime=starttime.datetime,
|
|
150
|
+
endtime=endtime.datetime,
|
|
151
|
+
sqlite_output=output
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return stats
|