requake 0.4__tar.gz → 0.5__tar.gz
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.
- {requake-0.4 → requake-0.5}/CHANGELOG.md +18 -2
- {requake-0.4 → requake-0.5}/PKG-INFO +36 -4
- {requake-0.4 → requake-0.5}/README.md +32 -3
- {requake-0.4 → requake-0.5}/requake/_version.py +3 -3
- {requake-0.4 → requake-0.5}/requake/catalog/catalog.py +66 -0
- {requake-0.4 → requake-0.5}/requake/catalog/read_catalog.py +64 -10
- {requake-0.4 → requake-0.5}/requake/catalog/read_catalog_from_csv.py +11 -1
- {requake-0.4 → requake-0.5}/requake/config/configspec.conf +10 -0
- {requake-0.4 → requake-0.5}/requake/config/parse_arguments.py +14 -19
- {requake-0.4 → requake-0.5}/requake/config/rq_setup.py +50 -10
- {requake-0.4 → requake-0.5}/requake/config/utils.py +40 -0
- {requake-0.4 → requake-0.5}/requake/families/families.py +7 -0
- {requake-0.4 → requake-0.5}/requake/families/print_families.py +15 -2
- requake-0.5/requake/main.py +69 -0
- {requake-0.4 → requake-0.5}/requake/plot/map_families.py +13 -28
- requake-0.5/requake/plot/plot_slip.py +119 -0
- requake-0.5/requake/plot/plot_timespans.py +132 -0
- requake-0.5/requake/plot/plot_utils.py +148 -0
- {requake-0.4 → requake-0.5}/requake/scan/scan_catalog.py +7 -3
- {requake-0.4 → requake-0.5}/requake/waveforms/station_metadata.py +3 -3
- {requake-0.4 → requake-0.5}/requake/waveforms/waveforms.py +7 -2
- {requake-0.4 → requake-0.5}/requake.egg-info/PKG-INFO +36 -4
- {requake-0.4 → requake-0.5}/requake.egg-info/SOURCES.txt +2 -0
- requake-0.5/requake.egg-info/entry_points.txt +2 -0
- {requake-0.4 → requake-0.5}/setup.py +9 -2
- requake-0.4/requake/plot/plot_slip.py +0 -121
- requake-0.4/requake/plot/plot_timespans.py +0 -145
- requake-0.4/requake.egg-info/entry_points.txt +0 -2
- {requake-0.4 → requake-0.5}/CONTRIBUTORS.txt +0 -0
- {requake-0.4 → requake-0.5}/LICENSE.txt +0 -0
- {requake-0.4 → requake-0.5}/MANIFEST.in +0 -0
- {requake-0.4 → requake-0.5}/requake/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/catalog/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/catalog/read_catalog_from_fdsnws.py +0 -0
- {requake-0.4 → requake-0.5}/requake/catalog/read_catalog_from_quakeml.py +0 -0
- {requake-0.4 → requake-0.5}/requake/config/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/config/config.py +0 -0
- {requake-0.4 → requake-0.5}/requake/config/configobj/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/config/configobj/_version.py +0 -0
- {requake-0.4 → requake-0.5}/requake/config/configobj/validate.py +0 -0
- {requake-0.4 → requake-0.5}/requake/families/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/families/build_families.py +0 -0
- {requake-0.4 → requake-0.5}/requake/families/build_templates.py +0 -0
- {requake-0.4 → requake-0.5}/requake/families/flag_family.py +0 -0
- {requake-0.4 → requake-0.5}/requake/formulas/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/formulas/conversion.py +0 -0
- {requake-0.4 → requake-0.5}/requake/formulas/slip.py +0 -0
- {requake-0.4 → requake-0.5}/requake/plot/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/plot/cached_tiler.py +0 -0
- {requake-0.4 → requake-0.5}/requake/plot/map_tiles.py +0 -0
- {requake-0.4 → requake-0.5}/requake/plot/plot_families.py +0 -0
- {requake-0.4 → requake-0.5}/requake/plot/plot_pair.py +0 -0
- {requake-0.4 → requake-0.5}/requake/scan/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/scan/scan_templates.py +0 -0
- {requake-0.4 → requake-0.5}/requake/waveforms/__init__.py +0 -0
- {requake-0.4 → requake-0.5}/requake/waveforms/arrivals.py +0 -0
- {requake-0.4 → requake-0.5}/requake.egg-info/dependency_links.txt +0 -0
- {requake-0.4 → requake-0.5}/requake.egg-info/requires.txt +0 -0
- {requake-0.4 → requake-0.5}/requake.egg-info/top_level.txt +0 -0
- {requake-0.4 → requake-0.5}/setup.cfg +0 -0
- {requake-0.4 → requake-0.5}/versioneer.py +0 -0
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
# Requake
|
|
1
|
+
# Requake Changelog
|
|
2
2
|
|
|
3
|
-
(c) 2021-2024 Claudio Satriano <satriano@ipgp.fr>
|
|
3
|
+
Copyright (c) 2021-2024 Claudio Satriano <satriano@ipgp.fr>
|
|
4
|
+
|
|
5
|
+
## v0.5 - 2024-04-23
|
|
6
|
+
|
|
7
|
+
- New config options: `station_metadata_path` and `waveform_data_path` to
|
|
8
|
+
read station metadata and waveform data from files. Supports any metadata
|
|
9
|
+
format supported by ObsPy and SDS (SeisComp Data Structure) waveform
|
|
10
|
+
archives.
|
|
11
|
+
- Filter catalog files on reading using the criteria in the config file
|
|
12
|
+
- Improved time axes in `plot_timespans` and `plot_slip` for short time
|
|
13
|
+
intervals
|
|
14
|
+
- `print_families`: autoset duration units based on the average duration
|
|
15
|
+
- `plot_timespans`: default sorting changed to `family_number`
|
|
16
|
+
|
|
17
|
+
## v0.4.1 - 2024-03-11
|
|
18
|
+
|
|
19
|
+
- Bugfix: `requake` executable was not installed
|
|
4
20
|
|
|
5
21
|
## v0.4 - 2024-03-11
|
|
6
22
|
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: requake
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5
|
|
4
4
|
Summary: Repeating earthquakes search and analysis
|
|
5
|
-
Home-page:
|
|
5
|
+
Home-page: https://requake.seismicsource.org
|
|
6
6
|
Author: Claudio Satriano
|
|
7
7
|
Author-email: satriano@ipgp.fr
|
|
8
8
|
License: GNU General Public License v3 or later (GPLv3+)
|
|
9
|
+
Project-URL: Homepage, https://requake.seismicsource.org
|
|
10
|
+
Project-URL: Source, https://github.com/SeismicSource/requake
|
|
11
|
+
Project-URL: Documentation, https://requake.readthedocs.io
|
|
9
12
|
Platform: OS Independent
|
|
10
13
|
Classifier: Development Status :: 4 - Beta
|
|
11
14
|
Classifier: Environment :: Console
|
|
@@ -30,6 +33,8 @@ Requires-Dist: argcomplete
|
|
|
30
33
|
Requires-Dist: tqdm
|
|
31
34
|
Requires-Dist: tabulate
|
|
32
35
|
|
|
36
|
+
<img src="imgs/Requake_logo.svg" width="400">
|
|
37
|
+
|
|
33
38
|
# Requake
|
|
34
39
|
|
|
35
40
|
Repeating earthquakes search and analysis.
|
|
@@ -37,6 +42,8 @@ Repeating earthquakes search and analysis.
|
|
|
37
42
|
[![changelog-badge]][changelog-link]
|
|
38
43
|
[![PyPI-badge]][PyPI-link]
|
|
39
44
|
[![license-badge]][license-link]
|
|
45
|
+
[![docs-badge]][docs-link]
|
|
46
|
+
[![DOI-badge]][DOI-link]
|
|
40
47
|
|
|
41
48
|
Copyright (c) 2021-2024 Claudio Satriano <satriano@ipgp.fr>
|
|
42
49
|
|
|
@@ -47,8 +54,8 @@ Requake is a command line tool to search and analyse repeating earthquakes.
|
|
|
47
54
|
It can either scan an existing earthquake catalog to search for similar events,
|
|
48
55
|
or perform template matching on a continuous waveform stream.
|
|
49
56
|
|
|
50
|
-
Catalogs and waveforms
|
|
51
|
-
[FDSN web services](https://www.fdsn.org/webservices/).
|
|
57
|
+
Catalogs and waveforms can be read from local files or downloaded using
|
|
58
|
+
standard [FDSN web services](https://www.fdsn.org/webservices/).
|
|
52
59
|
|
|
53
60
|
Requake is written in Python and uses [ObsPy](https://obspy.org) as backend.
|
|
54
61
|
|
|
@@ -181,10 +188,35 @@ parallelization will be implemented.
|
|
|
181
188
|
|
|
182
189
|
- `requake build_families` is fast™.
|
|
183
190
|
|
|
191
|
+
## How to Cite
|
|
192
|
+
|
|
193
|
+
If you used Requake for a scientific paper, please cite it as:
|
|
194
|
+
|
|
195
|
+
> Satriano, C. (2024). Requake: Repeating earthquakes search and analysis (X.Y).
|
|
196
|
+
> [doi: 10.5281/ZENODO.10832204]
|
|
197
|
+
|
|
198
|
+
Please replace `X.Y` with the Requake version number you used.
|
|
199
|
+
|
|
200
|
+
You can also cite the following abstract presented at the
|
|
201
|
+
2016 AGU Fall Meeting:
|
|
202
|
+
|
|
203
|
+
> Satriano, C., Doucet, A. & Bouin, M.-P. (2021).
|
|
204
|
+
> Probing the creep rate along the Lesser Antilles Subduction Zone through repeating earthquakes.
|
|
205
|
+
> In AGU Fall Meeting Abstracts
|
|
206
|
+
> (Vol. 2021, pp. T25A-0167), [bibcode: 2021AGUFM.T25A0167S]
|
|
207
|
+
|
|
184
208
|
<!-- Badges and project links -->
|
|
185
209
|
[PyPI-badge]: http://img.shields.io/pypi/v/requake.svg
|
|
186
210
|
[PyPI-link]: https://pypi.python.org/pypi/requake
|
|
187
211
|
[license-badge]: https://img.shields.io/badge/license-GPLv3-green
|
|
188
212
|
[license-link]: https://www.gnu.org/licenses/gpl-3.0.html
|
|
213
|
+
[docs-badge]: https://readthedocs.org/projects/requake/badge/?version=latest
|
|
214
|
+
[docs-link]: https://requake.readthedocs.io/en/latest/?badge=latest
|
|
189
215
|
[changelog-badge]: https://img.shields.io/badge/Changelog-136CB6.svg
|
|
190
216
|
[changelog-link]: https://github.com/SeismicSource/requake/blob/main/CHANGELOG.md
|
|
217
|
+
[DOI-badge]: https://zenodo.org/badge/DOI/10.5281/zenodo.10832204.svg
|
|
218
|
+
[DOI-link]: https://doi.org/10.5281/zenodo.10832204
|
|
219
|
+
|
|
220
|
+
<!-- References -->
|
|
221
|
+
[doi: 10.5281/ZENODO.10832204]: https://doi.org/10.5281/ZENODO.10832204
|
|
222
|
+
[bibcode: 2021AGUFM.T25A0167S]: https://ui.adsabs.harvard.edu/abs/2021AGUFM.T25A0167S
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<img src="imgs/Requake_logo.svg" width="400">
|
|
2
|
+
|
|
1
3
|
# Requake
|
|
2
4
|
|
|
3
5
|
Repeating earthquakes search and analysis.
|
|
@@ -5,6 +7,8 @@ Repeating earthquakes search and analysis.
|
|
|
5
7
|
[![changelog-badge]][changelog-link]
|
|
6
8
|
[![PyPI-badge]][PyPI-link]
|
|
7
9
|
[![license-badge]][license-link]
|
|
10
|
+
[![docs-badge]][docs-link]
|
|
11
|
+
[![DOI-badge]][DOI-link]
|
|
8
12
|
|
|
9
13
|
Copyright (c) 2021-2024 Claudio Satriano <satriano@ipgp.fr>
|
|
10
14
|
|
|
@@ -15,8 +19,8 @@ Requake is a command line tool to search and analyse repeating earthquakes.
|
|
|
15
19
|
It can either scan an existing earthquake catalog to search for similar events,
|
|
16
20
|
or perform template matching on a continuous waveform stream.
|
|
17
21
|
|
|
18
|
-
Catalogs and waveforms
|
|
19
|
-
[FDSN web services](https://www.fdsn.org/webservices/).
|
|
22
|
+
Catalogs and waveforms can be read from local files or downloaded using
|
|
23
|
+
standard [FDSN web services](https://www.fdsn.org/webservices/).
|
|
20
24
|
|
|
21
25
|
Requake is written in Python and uses [ObsPy](https://obspy.org) as backend.
|
|
22
26
|
|
|
@@ -149,10 +153,35 @@ parallelization will be implemented.
|
|
|
149
153
|
|
|
150
154
|
- `requake build_families` is fast™.
|
|
151
155
|
|
|
156
|
+
## How to Cite
|
|
157
|
+
|
|
158
|
+
If you used Requake for a scientific paper, please cite it as:
|
|
159
|
+
|
|
160
|
+
> Satriano, C. (2024). Requake: Repeating earthquakes search and analysis (X.Y).
|
|
161
|
+
> [doi: 10.5281/ZENODO.10832204]
|
|
162
|
+
|
|
163
|
+
Please replace `X.Y` with the Requake version number you used.
|
|
164
|
+
|
|
165
|
+
You can also cite the following abstract presented at the
|
|
166
|
+
2016 AGU Fall Meeting:
|
|
167
|
+
|
|
168
|
+
> Satriano, C., Doucet, A. & Bouin, M.-P. (2021).
|
|
169
|
+
> Probing the creep rate along the Lesser Antilles Subduction Zone through repeating earthquakes.
|
|
170
|
+
> In AGU Fall Meeting Abstracts
|
|
171
|
+
> (Vol. 2021, pp. T25A-0167), [bibcode: 2021AGUFM.T25A0167S]
|
|
172
|
+
|
|
152
173
|
<!-- Badges and project links -->
|
|
153
174
|
[PyPI-badge]: http://img.shields.io/pypi/v/requake.svg
|
|
154
175
|
[PyPI-link]: https://pypi.python.org/pypi/requake
|
|
155
176
|
[license-badge]: https://img.shields.io/badge/license-GPLv3-green
|
|
156
177
|
[license-link]: https://www.gnu.org/licenses/gpl-3.0.html
|
|
178
|
+
[docs-badge]: https://readthedocs.org/projects/requake/badge/?version=latest
|
|
179
|
+
[docs-link]: https://requake.readthedocs.io/en/latest/?badge=latest
|
|
157
180
|
[changelog-badge]: https://img.shields.io/badge/Changelog-136CB6.svg
|
|
158
|
-
[changelog-link]: https://github.com/SeismicSource/requake/blob/main/CHANGELOG.md
|
|
181
|
+
[changelog-link]: https://github.com/SeismicSource/requake/blob/main/CHANGELOG.md
|
|
182
|
+
[DOI-badge]: https://zenodo.org/badge/DOI/10.5281/zenodo.10832204.svg
|
|
183
|
+
[DOI-link]: https://doi.org/10.5281/zenodo.10832204
|
|
184
|
+
|
|
185
|
+
<!-- References -->
|
|
186
|
+
[doi: 10.5281/ZENODO.10832204]: https://doi.org/10.5281/ZENODO.10832204
|
|
187
|
+
[bibcode: 2021AGUFM.T25A0167S]: https://ui.adsabs.harvard.edu/abs/2021AGUFM.T25A0167S
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2024-
|
|
11
|
+
"date": "2024-04-23T09:52:34+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.
|
|
14
|
+
"full-revisionid": "5223a069ca428a69bba654b59dc8bc7b8860cbdd",
|
|
15
|
+
"version": "0.5"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -182,6 +182,72 @@ class RequakeCatalog(list):
|
|
|
182
182
|
fp.write(ev.fdsn_text() + '\n')
|
|
183
183
|
|
|
184
184
|
|
|
185
|
+
def filter(
|
|
186
|
+
self, starttime=None, endtime=None,
|
|
187
|
+
minlatitude=None, maxlatitude=None,
|
|
188
|
+
minlongitude=None, maxlongitude=None,
|
|
189
|
+
mindepth=None, maxdepth=None,
|
|
190
|
+
minmagnitude=None, maxmagnitude=None):
|
|
191
|
+
"""
|
|
192
|
+
Filter the catalog, based on the specified criteria.
|
|
193
|
+
|
|
194
|
+
Returns a new catalog.
|
|
195
|
+
|
|
196
|
+
:param starttime: start time
|
|
197
|
+
:type starttime: obspy.UTCDateTime
|
|
198
|
+
:param endtime: end time
|
|
199
|
+
:type endtime: obspy.UTCDateTime
|
|
200
|
+
:param minlatitude: minimum latitude
|
|
201
|
+
:type minlatitude: float
|
|
202
|
+
:param maxlatitude: maximum latitude
|
|
203
|
+
:type maxlatitude: float
|
|
204
|
+
:param minlongitude: minimum longitude
|
|
205
|
+
:type minlongitude: float
|
|
206
|
+
:param maxlongitude: maximum longitude
|
|
207
|
+
:type maxlongitude: float
|
|
208
|
+
:param mindepth: minimum depth (in km)
|
|
209
|
+
:type mindepth: float
|
|
210
|
+
:param maxdepth: maximum depth (in km)
|
|
211
|
+
:type maxdepth: float
|
|
212
|
+
:param minmagnitude: minimum magnitude
|
|
213
|
+
:type minmagnitude: float
|
|
214
|
+
:param maxmagnitude: maximum magnitude
|
|
215
|
+
:type maxmagnitude: float
|
|
216
|
+
|
|
217
|
+
:return: a new catalog
|
|
218
|
+
:rtype: RequakeCatalog
|
|
219
|
+
"""
|
|
220
|
+
outcat = RequakeCatalog()
|
|
221
|
+
for ev in self:
|
|
222
|
+
if ev.orig_time is not None:
|
|
223
|
+
if starttime is not None and ev.orig_time < starttime:
|
|
224
|
+
continue
|
|
225
|
+
if endtime is not None and ev.orig_time > endtime:
|
|
226
|
+
continue
|
|
227
|
+
if ev.lat is not None:
|
|
228
|
+
if minlatitude is not None and ev.lat < minlatitude:
|
|
229
|
+
continue
|
|
230
|
+
if maxlatitude is not None and ev.lat > maxlatitude:
|
|
231
|
+
continue
|
|
232
|
+
if ev.lon is not None:
|
|
233
|
+
if minlongitude is not None and ev.lon < minlongitude:
|
|
234
|
+
continue
|
|
235
|
+
if maxlongitude is not None and ev.lon > maxlongitude:
|
|
236
|
+
continue
|
|
237
|
+
if ev.depth is not None:
|
|
238
|
+
if mindepth is not None and ev.depth < mindepth:
|
|
239
|
+
continue
|
|
240
|
+
if maxdepth is not None and ev.depth > maxdepth:
|
|
241
|
+
continue
|
|
242
|
+
if ev.mag is not None:
|
|
243
|
+
if minmagnitude is not None and ev.mag < minmagnitude:
|
|
244
|
+
continue
|
|
245
|
+
if maxmagnitude is not None and ev.mag > maxmagnitude:
|
|
246
|
+
continue
|
|
247
|
+
outcat.append(ev)
|
|
248
|
+
return outcat
|
|
249
|
+
|
|
250
|
+
|
|
185
251
|
def read_stored_catalog(config):
|
|
186
252
|
"""
|
|
187
253
|
Read the catalog stored in the output directory.
|
|
@@ -9,6 +9,7 @@ Read an event catalog from web services or from a file.
|
|
|
9
9
|
GNU General Public License v3.0 or later
|
|
10
10
|
(https://www.gnu.org/licenses/gpl-3.0-standalone.html)
|
|
11
11
|
"""
|
|
12
|
+
import os
|
|
12
13
|
import logging
|
|
13
14
|
import contextlib
|
|
14
15
|
from ..catalog.catalog import RequakeCatalog
|
|
@@ -34,8 +35,14 @@ def _read_catalog_from_file(config):
|
|
|
34
35
|
:raises ValueError: if the file format is not supported
|
|
35
36
|
"""
|
|
36
37
|
catalog_file = config.args.catalog_file
|
|
38
|
+
# return ValueError if the file is empty
|
|
39
|
+
if os.stat(catalog_file).st_size == 0:
|
|
40
|
+
raise ValueError('Empty file')
|
|
41
|
+
# return ValueError if the file is a directory
|
|
42
|
+
if os.path.isdir(catalog_file):
|
|
43
|
+
raise ValueError('Is a directory')
|
|
37
44
|
# try to read the catalog as a QuakeML file
|
|
38
|
-
with contextlib.suppress(TypeError):
|
|
45
|
+
with contextlib.suppress(TypeError, IndexError, ValueError):
|
|
39
46
|
return read_catalog_from_quakeml(catalog_file)
|
|
40
47
|
# try to read the catalog as a FDSN text file
|
|
41
48
|
with contextlib.suppress(ValueError):
|
|
@@ -47,6 +54,45 @@ def _read_catalog_from_file(config):
|
|
|
47
54
|
return read_catalog_from_csv(catalog_file)
|
|
48
55
|
|
|
49
56
|
|
|
57
|
+
def _filter_catalog(catalog, config):
|
|
58
|
+
"""
|
|
59
|
+
Filter an event catalog, based on the criteria specified
|
|
60
|
+
in the configuration.
|
|
61
|
+
|
|
62
|
+
:param catalog: Event catalog.
|
|
63
|
+
:type catalog: requake.catalog.RequakeCatalog
|
|
64
|
+
:param config: Configuration object.
|
|
65
|
+
:type config: requake.rq_setup.RequakeConfig
|
|
66
|
+
:return: Filtered event catalog.
|
|
67
|
+
:rtype: requake.catalog.RequakeCatalog
|
|
68
|
+
"""
|
|
69
|
+
lon_min = config.catalog_lon_min
|
|
70
|
+
lon_max = config.catalog_lon_max
|
|
71
|
+
lat_min = config.catalog_lat_min
|
|
72
|
+
lat_max = config.catalog_lat_max
|
|
73
|
+
depth_min = config.catalog_depth_min
|
|
74
|
+
depth_max = config.catalog_depth_max
|
|
75
|
+
mag_min = config.catalog_mag_min
|
|
76
|
+
mag_max = config.catalog_mag_max
|
|
77
|
+
outcat = catalog
|
|
78
|
+
for start_time, end_time in zip(config.catalog_start_times,
|
|
79
|
+
config.catalog_end_times):
|
|
80
|
+
outcat = outcat.filter(
|
|
81
|
+
starttime=start_time, endtime=end_time,
|
|
82
|
+
minlatitude=lat_min, maxlatitude=lat_max,
|
|
83
|
+
minlongitude=lon_min, maxlongitude=lon_max,
|
|
84
|
+
mindepth=depth_min, maxdepth=depth_max,
|
|
85
|
+
minmagnitude=mag_min, maxmagnitude=mag_max
|
|
86
|
+
)
|
|
87
|
+
nevents_in = len(catalog)
|
|
88
|
+
nevents_out = len(outcat)
|
|
89
|
+
logger.info(
|
|
90
|
+
'Catalog filtered based on configuration file: '
|
|
91
|
+
f'{nevents_out} events out of {nevents_in}'
|
|
92
|
+
)
|
|
93
|
+
return outcat
|
|
94
|
+
|
|
95
|
+
|
|
50
96
|
def read_catalog(config):
|
|
51
97
|
"""
|
|
52
98
|
Read an event catalog from web services or from a file.
|
|
@@ -59,34 +105,42 @@ def read_catalog(config):
|
|
|
59
105
|
:rtype: requake.catalog.RequakeCatalog
|
|
60
106
|
"""
|
|
61
107
|
catalog = RequakeCatalog()
|
|
62
|
-
|
|
108
|
+
output_cat_file = config.scan_catalog_file
|
|
63
109
|
nevs_read = 0
|
|
64
110
|
if config.args.append:
|
|
65
111
|
with contextlib.suppress(FileNotFoundError):
|
|
66
112
|
catalog = RequakeCatalog()
|
|
67
|
-
catalog.read(
|
|
113
|
+
catalog.read(output_cat_file)
|
|
68
114
|
nevs_read = len(catalog)
|
|
69
|
-
logger.info(f'{nevs_read} events read from "{
|
|
115
|
+
logger.info(f'{nevs_read} events read from "{output_cat_file}"')
|
|
70
116
|
logger.info('Reading catalog...')
|
|
71
|
-
|
|
72
|
-
if
|
|
117
|
+
input_cat_file = config.args.catalog_file
|
|
118
|
+
if input_cat_file is not None:
|
|
73
119
|
try:
|
|
74
120
|
catalog += _read_catalog_from_file(config)
|
|
121
|
+
# Filter catalog based on configuration
|
|
122
|
+
catalog = _filter_catalog(catalog, config)
|
|
75
123
|
except FileNotFoundError:
|
|
76
|
-
logger.error(f'File "{
|
|
124
|
+
logger.error(f'File "{input_cat_file}" not found')
|
|
77
125
|
rq_exit(1)
|
|
78
126
|
except ValueError as m:
|
|
79
|
-
logger.error(f'Error reading catalog file "{
|
|
127
|
+
logger.error(f'Error reading catalog file "{input_cat_file}": {m}')
|
|
80
128
|
rq_exit(1)
|
|
81
129
|
else:
|
|
82
130
|
catalog += read_catalog_from_fdsnws(config)
|
|
83
131
|
if not catalog:
|
|
84
132
|
logger.error('No event read')
|
|
85
133
|
rq_exit(1)
|
|
134
|
+
# Deduplicate catalog
|
|
135
|
+
len_before = len(catalog)
|
|
86
136
|
catalog.deduplicate()
|
|
137
|
+
len_after = len(catalog)
|
|
138
|
+
nevs_dedup = len_before - len_after
|
|
139
|
+
if nevs_dedup > 0:
|
|
140
|
+
logger.info(f'{nevs_dedup} duplicate events removed')
|
|
87
141
|
# Sort catalog in increasing time order
|
|
88
142
|
catalog.sort()
|
|
89
143
|
# Write catalog to output file
|
|
90
|
-
catalog.write(
|
|
144
|
+
catalog.write(output_cat_file)
|
|
91
145
|
nevs_written = len(catalog) - nevs_read
|
|
92
|
-
logger.info(f'{nevs_written} events written to "{
|
|
146
|
+
logger.info(f'{nevs_written} events written to "{output_cat_file}"')
|
|
@@ -183,7 +183,17 @@ def read_catalog_from_csv(filename):
|
|
|
183
183
|
year=year, month=month, day=day,
|
|
184
184
|
hour=hour, minute=minute, second=0) + seconds
|
|
185
185
|
else:
|
|
186
|
-
|
|
186
|
+
try:
|
|
187
|
+
orig_time = UTCDateTime(row[fields['orig_time']])
|
|
188
|
+
except ValueError:
|
|
189
|
+
# one last try: check if the time is in the format
|
|
190
|
+
# YYYYMMDD.hhmmss.
|
|
191
|
+
# Replace the dot with a space, pad with zeros
|
|
192
|
+
# and try again
|
|
193
|
+
orig_time = UTCDateTime(
|
|
194
|
+
row[fields['orig_time']]
|
|
195
|
+
.replace('.', ' ').ljust(15, '0')
|
|
196
|
+
)
|
|
187
197
|
row[None] = None
|
|
188
198
|
ev = RequakeEvent()
|
|
189
199
|
ev.orig_time = orig_time
|
|
@@ -4,9 +4,19 @@
|
|
|
4
4
|
## FDSN station webservice URL to retrieve station metadata.
|
|
5
5
|
## Use a full URL or a ObsPy shortcut (e.g., IRIS, RESIF, GEOFON, ...)
|
|
6
6
|
fdsn_station_url = string(default=http://example.com)
|
|
7
|
+
## Alternatively, you can provide the path to a local file with station
|
|
8
|
+
## metadata in any format supported by ObsPy (note that some formats may not
|
|
9
|
+
## contain station coordinates, which are required for the scan,
|
|
10
|
+
## see https://docs.obspy.org/packages/obspy.core.inventory.html).
|
|
11
|
+
## If both fdsn_station_url and stationxml_file are provided, the
|
|
12
|
+
## local file will be used.
|
|
13
|
+
station_metadata_path = string(default=None)
|
|
7
14
|
## FDSN dataselect webservice URL to retrieve waveforms.
|
|
8
15
|
## Use a full URL or a ObsPy shortcut (e.g., IRIS, RESIF, GEOFON, ...)
|
|
9
16
|
fdsn_dataselect_url = string(default=http://example.com)
|
|
17
|
+
## Alternatively, you can provide the path to a local SDS waveform archive
|
|
18
|
+
## (see https://docs.obspy.org/packages/autogen/obspy.clients.filesystem.sds.html)
|
|
19
|
+
waveform_data_path = string(default=None)
|
|
10
20
|
|
|
11
21
|
#### Catalog-based scan
|
|
12
22
|
### The following parameters are for a catalog-based scan:
|
|
@@ -132,7 +132,7 @@ def parse_arguments(progname='requake'):
|
|
|
132
132
|
'-l', '--longerthan', type=str, default=0, metavar='DURATION',
|
|
133
133
|
help='only use families lasting longer than this value. '
|
|
134
134
|
'You can specify DURATION in days (e.g., 100d) '
|
|
135
|
-
'or in years (e.g., 2.5y)
|
|
135
|
+
'or in years (e.g., 2.5y)'
|
|
136
136
|
)
|
|
137
137
|
# ---
|
|
138
138
|
# --- minevents
|
|
@@ -141,7 +141,7 @@ def parse_arguments(progname='requake'):
|
|
|
141
141
|
minevents = argparse.ArgumentParser(add_help=False)
|
|
142
142
|
minevents.add_argument(
|
|
143
143
|
'-m', '--minevents', type=int, default=0, metavar='NEVENTS',
|
|
144
|
-
help='only use families with at least NEVENTS events
|
|
144
|
+
help='only use families with at least NEVENTS events'
|
|
145
145
|
)
|
|
146
146
|
# ---
|
|
147
147
|
# --- familynumbers
|
|
@@ -153,7 +153,7 @@ def parse_arguments(progname='requake'):
|
|
|
153
153
|
help='family numbers to use. It can be a single number, '
|
|
154
154
|
'a comma-separated list (ex.: 1,4,8), '
|
|
155
155
|
'a hyphen-separated number range (ex.: 2-12), or "all" '
|
|
156
|
-
'(default:
|
|
156
|
+
'(default: %(default)s)'
|
|
157
157
|
)
|
|
158
158
|
# ---
|
|
159
159
|
# --- traceid
|
|
@@ -162,7 +162,7 @@ def parse_arguments(progname='requake'):
|
|
|
162
162
|
traceid = argparse.ArgumentParser(add_help=False)
|
|
163
163
|
traceid.add_argument(
|
|
164
164
|
'-t', '--traceid', type=str, default=None,
|
|
165
|
-
help='use this traceid instead of the default one for the family
|
|
165
|
+
help='use this traceid instead of the default one for the family'
|
|
166
166
|
)
|
|
167
167
|
# ---
|
|
168
168
|
# --- print_families
|
|
@@ -173,8 +173,8 @@ def parse_arguments(progname='requake'):
|
|
|
173
173
|
)
|
|
174
174
|
printfamilies.add_argument(
|
|
175
175
|
'-f', '--format', type=str, default='simple',
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
choices=['simple', 'markdown', 'csv'],
|
|
177
|
+
help='format for the output table (default: %(default)s)'
|
|
178
178
|
)
|
|
179
179
|
# ---
|
|
180
180
|
# --- plot_families
|
|
@@ -185,11 +185,11 @@ def parse_arguments(progname='requake'):
|
|
|
185
185
|
)
|
|
186
186
|
plotfamilies.add_argument(
|
|
187
187
|
'-s', '--starttime', type=float, default=None,
|
|
188
|
-
help='start time, in seconds relative to trace start, for the plot
|
|
188
|
+
help='start time, in seconds relative to trace start, for the plot'
|
|
189
189
|
)
|
|
190
190
|
plotfamilies.add_argument(
|
|
191
191
|
'-e', '--endtime', type=float, default=None,
|
|
192
|
-
help='end time, in seconds relative to trace start, for the plot
|
|
192
|
+
help='end time, in seconds relative to trace start, for the plot'
|
|
193
193
|
)
|
|
194
194
|
# ---
|
|
195
195
|
# --- plot_timespans
|
|
@@ -199,15 +199,12 @@ def parse_arguments(progname='requake'):
|
|
|
199
199
|
help='plot family timespans'
|
|
200
200
|
)
|
|
201
201
|
timespans.add_argument(
|
|
202
|
-
'-s', '--sortby', type=str, default=
|
|
202
|
+
'-s', '--sortby', type=str, default='family_number',
|
|
203
203
|
choices=[
|
|
204
204
|
'time', 'latitude', 'longitude', 'depth', 'distance_from',
|
|
205
205
|
'family_number'
|
|
206
206
|
],
|
|
207
|
-
help='quantity to sort families by on y-axis
|
|
208
|
-
'Possible values are: time, latitude, longitude, depth, '
|
|
209
|
-
'distance_from, family_number. If not specified, the config '
|
|
210
|
-
'value "sort_families_by" will be used.'
|
|
207
|
+
help='quantity to sort families by on y-axis (default: %(default)s)'
|
|
211
208
|
)
|
|
212
209
|
# ---
|
|
213
210
|
# --- plot_slip
|
|
@@ -229,19 +226,17 @@ def parse_arguments(progname='requake'):
|
|
|
229
226
|
'stamen_terrain', 'satellite', 'street', 'hillshade',
|
|
230
227
|
'hillshade_dark', 'ocean'
|
|
231
228
|
],
|
|
232
|
-
help='style of map to plot
|
|
233
|
-
'stamen_terrain, satellite, street, hillshade, hillshade_dark, '
|
|
234
|
-
'ocean'
|
|
229
|
+
help='style of map to plot (default: %(default)s)'
|
|
235
230
|
)
|
|
236
231
|
mapfamilies.add_argument(
|
|
237
232
|
'-k', '--apikey', type=str, default=None,
|
|
238
|
-
help='API key for Stamen Terrain map tiles (default:
|
|
233
|
+
help='API key for Stamen Terrain map tiles (default: %(default)s). '
|
|
239
234
|
'You can get a free API key at https://stadiamaps.com/'
|
|
240
235
|
)
|
|
241
236
|
mapfamilies.add_argument(
|
|
242
237
|
'-z', '--zoom', type=int, default=None,
|
|
243
238
|
help='zoom level for the map tiles (default: None). Note that '
|
|
244
|
-
'certain map tiles might not be available at all zoom levels
|
|
239
|
+
'certain map tiles might not be available at all zoom levels'
|
|
245
240
|
)
|
|
246
241
|
# ---
|
|
247
242
|
# --- flag_family
|
|
@@ -254,7 +249,7 @@ def parse_arguments(progname='requake'):
|
|
|
254
249
|
flagfamily.add_argument(
|
|
255
250
|
'is_valid',
|
|
256
251
|
help='"true" (or "t") to flag family as valid, '
|
|
257
|
-
'"false" (or "f") to flag family as not valid
|
|
252
|
+
'"false" (or "f") to flag family as not valid'
|
|
258
253
|
)
|
|
259
254
|
# ---
|
|
260
255
|
# --- build_templates
|
|
@@ -17,7 +17,10 @@ import logging
|
|
|
17
17
|
import signal
|
|
18
18
|
import tqdm
|
|
19
19
|
from obspy import UTCDateTime
|
|
20
|
-
from obspy
|
|
20
|
+
from obspy import read_inventory
|
|
21
|
+
from obspy.clients.filesystem.sds import Client as SDSClient
|
|
22
|
+
from obspy.clients.fdsn import Client as FDSNClient
|
|
23
|
+
from obspy.clients.fdsn.header import FDSNNoServiceException
|
|
21
24
|
from .._version import get_versions
|
|
22
25
|
from .config import Config
|
|
23
26
|
from .utils import (
|
|
@@ -104,14 +107,51 @@ def _setup_logging(config, progname, action_name):
|
|
|
104
107
|
logger.debug(' '.join(sys.argv))
|
|
105
108
|
|
|
106
109
|
|
|
107
|
-
def
|
|
108
|
-
"""
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
def _connect_station_dataselect(config):
|
|
111
|
+
"""
|
|
112
|
+
Connect to station and dataselect services.
|
|
113
|
+
|
|
114
|
+
Those can be either FDSN web services or local files.
|
|
115
|
+
"""
|
|
116
|
+
if config.station_metadata_path is not None:
|
|
117
|
+
config.inventory = read_inventory(config.station_metadata_path)
|
|
118
|
+
config.station_client = None
|
|
119
|
+
logger.info(
|
|
120
|
+
'Reading station metadata from local file: '
|
|
121
|
+
f'{config.station_metadata_path}'
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
config.station_client = FDSNClient(config.fdsn_station_url)
|
|
125
|
+
logger.info(
|
|
126
|
+
f'Connected to FDSN station server: {config.fdsn_station_url}'
|
|
127
|
+
)
|
|
128
|
+
if config.waveform_data_path is not None:
|
|
129
|
+
_connect_sds(config)
|
|
130
|
+
else:
|
|
131
|
+
config.dataselect_client = FDSNClient(config.fdsn_dataselect_url)
|
|
132
|
+
logger.info(
|
|
133
|
+
'Connected to FDSN dataselect server: '
|
|
134
|
+
f'{config.fdsn_dataselect_url}'
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _connect_sds(config):
|
|
139
|
+
"""
|
|
140
|
+
Connect to a local SeisComP Data Structure (SDS) archive.
|
|
141
|
+
"""
|
|
142
|
+
_client = SDSClient(config.waveform_data_path)
|
|
143
|
+
all_nslc = _client.get_all_nslc()
|
|
144
|
+
if not all_nslc:
|
|
145
|
+
raise FileNotFoundError(
|
|
146
|
+
f'No SDS archive found in {config.waveform_data_path}'
|
|
147
|
+
)
|
|
148
|
+
config.dataselect_client = _client
|
|
112
149
|
logger.info(
|
|
113
|
-
|
|
150
|
+
'Reading waveform data from local SDS archive: '
|
|
151
|
+
f'{config.waveform_data_path}'
|
|
114
152
|
)
|
|
153
|
+
all_nslc_str = '\n'.join('.'.join(nslc) for nslc in all_nslc)
|
|
154
|
+
logger.info(f'Found the following NSLC codes:\n{all_nslc_str}')
|
|
115
155
|
|
|
116
156
|
|
|
117
157
|
def _parse_catalog_options(config):
|
|
@@ -140,7 +180,7 @@ def _connect_fdsn_catalog(config):
|
|
|
140
180
|
"""Connect to FDSN catalog services."""
|
|
141
181
|
config.catalog_fdsn_event_clients = []
|
|
142
182
|
for url in config.catalog_fdsn_event_urls:
|
|
143
|
-
config.catalog_fdsn_event_clients.append(
|
|
183
|
+
config.catalog_fdsn_event_clients.append(FDSNClient(url))
|
|
144
184
|
logger.info(f'Connected to FDSN event server: {url}')
|
|
145
185
|
|
|
146
186
|
|
|
@@ -205,10 +245,10 @@ def configure(args):
|
|
|
205
245
|
)
|
|
206
246
|
try:
|
|
207
247
|
if args.action in actions_needing_fdsn_station_dataselect:
|
|
208
|
-
|
|
248
|
+
_connect_station_dataselect(config)
|
|
209
249
|
if args.action == 'read_catalog' and not args.catalog_file:
|
|
210
250
|
_connect_fdsn_catalog(config)
|
|
211
|
-
except
|
|
251
|
+
except (FileNotFoundError, ValueError, FDSNNoServiceException) as m:
|
|
212
252
|
logger.error(m)
|
|
213
253
|
rq_exit(1)
|
|
214
254
|
# Template times must be UTCDateTime objects
|
|
@@ -12,6 +12,8 @@ Utility functions for Requake.
|
|
|
12
12
|
import os
|
|
13
13
|
import sys
|
|
14
14
|
import locale
|
|
15
|
+
import traceback
|
|
16
|
+
from .. import __version__
|
|
15
17
|
from .configobj import ConfigObj
|
|
16
18
|
from .configobj.validate import Validator
|
|
17
19
|
locale.setlocale(locale.LC_ALL, '')
|
|
@@ -129,3 +131,41 @@ def validate_config(config_obj):
|
|
|
129
131
|
sys.exit(1)
|
|
130
132
|
if not test:
|
|
131
133
|
err_exit('No configuration value present!')
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def manage_uncaught_exception(exception):
|
|
137
|
+
"""
|
|
138
|
+
Manage an uncaught exception.
|
|
139
|
+
|
|
140
|
+
:param exception: Exception object.
|
|
141
|
+
:type exception: Exception
|
|
142
|
+
"""
|
|
143
|
+
sys.stderr.write("""
|
|
144
|
+
# BEGIN TRACEBACK #############################################################
|
|
145
|
+
""")
|
|
146
|
+
sys.stderr.write('\n')
|
|
147
|
+
traceback.print_exc()
|
|
148
|
+
sys.stderr.write("""
|
|
149
|
+
# END TRACEBACK ###############################################################
|
|
150
|
+
""")
|
|
151
|
+
sys.stderr.write("""
|
|
152
|
+
|
|
153
|
+
Congratulations, you've found a bug in Requake! 🐞
|
|
154
|
+
|
|
155
|
+
Please report it on https://github.com/SeismicSource/requake/issues
|
|
156
|
+
or by email to satriano@ipgp.fr.
|
|
157
|
+
|
|
158
|
+
Include the following information in your report:
|
|
159
|
+
|
|
160
|
+
""")
|
|
161
|
+
sys.stderr.write(f' Requake version: {__version__}\n')
|
|
162
|
+
sys.stderr.write(f' Python version: {sys.version}\n')
|
|
163
|
+
sys.stderr.write(f' Platform: {sys.platform}\n')
|
|
164
|
+
sys.stderr.write(f' Command line: {" ".join(sys.argv)}\n')
|
|
165
|
+
sys.stderr.write(f' Error message: {str(exception)}\n')
|
|
166
|
+
sys.stderr.write('\n')
|
|
167
|
+
sys.stderr.write(
|
|
168
|
+
'Also, please copy and paste the traceback above in your '
|
|
169
|
+
'report.\n\n')
|
|
170
|
+
sys.stderr.write('Thank you for your help!\n\n')
|
|
171
|
+
sys.exit(1)
|