DASPy-toolbox 1.1.1__tar.gz → 1.1.3__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.
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/PKG-INFO +17 -6
- daspy_toolbox-1.1.3/DASPy_toolbox.egg-info/SOURCES.txt +28 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/PKG-INFO +17 -6
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/README.md +2 -3
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/advanced_tools/channel.py +89 -106
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/advanced_tools/strain2vel.py +1 -2
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/basic_tools/preprocessing.py +11 -11
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/basic_tools/visualization.py +17 -11
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/core/collection.py +42 -18
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/core/dasdatetime.py +27 -5
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/core/section.py +22 -8
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/setup.py +1 -1
- DASPy-toolbox-1.1.1/DASPy_toolbox.egg-info/SOURCES.txt +0 -53
- DASPy-toolbox-1.1.1/daspy/core/make_example.py +0 -32
- DASPy-toolbox-1.1.1/daspy/seismic_detection/__init__.py +0 -1
- DASPy-toolbox-1.1.1/daspy/seismic_detection/calc_travel_time.py +0 -23
- DASPy-toolbox-1.1.1/daspy/seismic_detection/core.py +0 -186
- DASPy-toolbox-1.1.1/daspy/seismic_detection/detection.py +0 -12
- DASPy-toolbox-1.1.1/daspy/seismic_detection/gamma/__init__.py +0 -13
- DASPy-toolbox-1.1.1/daspy/seismic_detection/gamma/_base.py +0 -549
- DASPy-toolbox-1.1.1/daspy/seismic_detection/gamma/_bayesian_mixture.py +0 -875
- DASPy-toolbox-1.1.1/daspy/seismic_detection/gamma/_gaussian_mixture.py +0 -866
- DASPy-toolbox-1.1.1/daspy/seismic_detection/gamma/app.py +0 -192
- DASPy-toolbox-1.1.1/daspy/seismic_detection/gamma/seismic_ops.py +0 -478
- DASPy-toolbox-1.1.1/daspy/seismic_detection/gamma/utils.py +0 -512
- DASPy-toolbox-1.1.1/daspy/seismic_detection/location.py +0 -266
- DASPy-toolbox-1.1.1/daspy/seismic_detection/magnitude.py +0 -43
- DASPy-toolbox-1.1.1/daspy/seismic_detection/phase_picking.py +0 -87
- DASPy-toolbox-1.1.1/daspy/structure_imaging/__init__.py +0 -0
- DASPy-toolbox-1.1.1/daspy/structure_imaging/ambient_noise.py +0 -4
- DASPy-toolbox-1.1.1/daspy/structure_imaging/core.py +0 -39
- DASPy-toolbox-1.1.1/daspy/structure_imaging/dispersion.py +0 -27
- DASPy-toolbox-1.1.1/daspy/structure_imaging/fault_zone.py +0 -90
- DASPy-toolbox-1.1.1/daspy/structure_imaging/inversion.py +0 -6
- DASPy-toolbox-1.1.1/daspy/traffic_monitoring/JamDetection.py +0 -6
- DASPy-toolbox-1.1.1/daspy/traffic_monitoring/SpeedMeasurement.py +0 -6
- DASPy-toolbox-1.1.1/daspy/traffic_monitoring/VehicleDetection.py +0 -6
- DASPy-toolbox-1.1.1/daspy/traffic_monitoring/__init__.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/dependency_links.txt +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/entry_points.txt +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/requires.txt +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/top_level.txt +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/LICENSE +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/__init__.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/advanced_tools/__init__.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/advanced_tools/decomposition.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/advanced_tools/denoising.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/advanced_tools/fdct.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/basic_tools/__init__.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/basic_tools/filter.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/basic_tools/freqattributes.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/core/__init__.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/core/example.pkl +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/core/read.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/daspy/core/write.py +0 -0
- {DASPy-toolbox-1.1.1 → daspy_toolbox-1.1.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: DASPy-toolbox
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.3
|
|
4
4
|
Summary: DASPy is an open-source project dedicated to provide a python package for DAS (Distributed Acoustic Sensing) data processing, which comprises classic seismic data processing techniques and Specialized algorithms for DAS applications.
|
|
5
5
|
Home-page: https://github.com/HMZ-03/DASPy
|
|
6
6
|
Author: Minzhe Hu, Zefeng Li
|
|
@@ -22,14 +22,25 @@ Requires-Dist: h5py
|
|
|
22
22
|
Requires-Dist: segyio
|
|
23
23
|
Requires-Dist: nptdms
|
|
24
24
|
Requires-Dist: tqdm
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: license
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
Dynamic: maintainer
|
|
33
|
+
Dynamic: maintainer-email
|
|
34
|
+
Dynamic: requires-dist
|
|
35
|
+
Dynamic: requires-python
|
|
36
|
+
Dynamic: summary
|
|
37
|
+
|
|
38
|
+
<img src="https://raw.github.com/hmz-03/daspy/main/website/logo.png" height="200" />
|
|
29
39
|
|
|
30
40
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
31
41
|
[](https://opensource.org/license/mit)
|
|
32
42
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
43
|
+
|
|
33
44
|
[](https://doi.org/10.1785/0220240124)
|
|
34
45
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
35
46
|
[](https://anaconda.org/conda-forge/daspy-toolbox)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
DASPy_toolbox.egg-info/PKG-INFO
|
|
5
|
+
DASPy_toolbox.egg-info/SOURCES.txt
|
|
6
|
+
DASPy_toolbox.egg-info/dependency_links.txt
|
|
7
|
+
DASPy_toolbox.egg-info/entry_points.txt
|
|
8
|
+
DASPy_toolbox.egg-info/requires.txt
|
|
9
|
+
DASPy_toolbox.egg-info/top_level.txt
|
|
10
|
+
daspy/__init__.py
|
|
11
|
+
daspy/advanced_tools/__init__.py
|
|
12
|
+
daspy/advanced_tools/channel.py
|
|
13
|
+
daspy/advanced_tools/decomposition.py
|
|
14
|
+
daspy/advanced_tools/denoising.py
|
|
15
|
+
daspy/advanced_tools/fdct.py
|
|
16
|
+
daspy/advanced_tools/strain2vel.py
|
|
17
|
+
daspy/basic_tools/__init__.py
|
|
18
|
+
daspy/basic_tools/filter.py
|
|
19
|
+
daspy/basic_tools/freqattributes.py
|
|
20
|
+
daspy/basic_tools/preprocessing.py
|
|
21
|
+
daspy/basic_tools/visualization.py
|
|
22
|
+
daspy/core/__init__.py
|
|
23
|
+
daspy/core/collection.py
|
|
24
|
+
daspy/core/dasdatetime.py
|
|
25
|
+
daspy/core/example.pkl
|
|
26
|
+
daspy/core/read.py
|
|
27
|
+
daspy/core/section.py
|
|
28
|
+
daspy/core/write.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: DASPy-toolbox
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.3
|
|
4
4
|
Summary: DASPy is an open-source project dedicated to provide a python package for DAS (Distributed Acoustic Sensing) data processing, which comprises classic seismic data processing techniques and Specialized algorithms for DAS applications.
|
|
5
5
|
Home-page: https://github.com/HMZ-03/DASPy
|
|
6
6
|
Author: Minzhe Hu, Zefeng Li
|
|
@@ -22,14 +22,25 @@ Requires-Dist: h5py
|
|
|
22
22
|
Requires-Dist: segyio
|
|
23
23
|
Requires-Dist: nptdms
|
|
24
24
|
Requires-Dist: tqdm
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: license
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
Dynamic: maintainer
|
|
33
|
+
Dynamic: maintainer-email
|
|
34
|
+
Dynamic: requires-dist
|
|
35
|
+
Dynamic: requires-python
|
|
36
|
+
Dynamic: summary
|
|
37
|
+
|
|
38
|
+
<img src="https://raw.github.com/hmz-03/daspy/main/website/logo.png" height="200" />
|
|
29
39
|
|
|
30
40
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
31
41
|
[](https://opensource.org/license/mit)
|
|
32
42
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
43
|
+
|
|
33
44
|
[](https://doi.org/10.1785/0220240124)
|
|
34
45
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
35
46
|
[](https://anaconda.org/conda-forge/daspy-toolbox)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
<img src="
|
|
2
|
-
|
|
3
|
-
# DASPy
|
|
1
|
+
<img src="https://raw.github.com/hmz-03/daspy/main/website/logo.png" height="200" />
|
|
4
2
|
|
|
5
3
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
6
4
|
[](https://opensource.org/license/mit)
|
|
7
5
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
6
|
+
|
|
8
7
|
[](https://doi.org/10.1785/0220240124)
|
|
9
8
|
[](https://pypi.org/project/DASPy-toolbox/)
|
|
10
9
|
[](https://anaconda.org/conda-forge/daspy-toolbox)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Several functions for analysis data quality and geometry of channels
|
|
2
2
|
# Author: Minzhe Hu, Zefeng Li
|
|
3
|
-
# Date:
|
|
3
|
+
# Date: 2025.3.31
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import numpy as np
|
|
6
6
|
from copy import deepcopy
|
|
@@ -84,7 +84,7 @@ def channel_checking(data, deg=10, thresh=5, continuity=True, adjacent=2,
|
|
|
84
84
|
bad_chn = np.argwhere(deviation < -thresh * mad).ravel().tolist()
|
|
85
85
|
elif mode == 'high':
|
|
86
86
|
bad_chn = np.argwhere(deviation > thresh * mad).ravel().tolist()
|
|
87
|
-
elif mode == '
|
|
87
|
+
elif mode == 'both':
|
|
88
88
|
bad_chn = np.argwhere(deviation < -thresh * mad).ravel().tolist() + \
|
|
89
89
|
np.argwhere(deviation > thresh * mad).ravel().tolist()
|
|
90
90
|
good_chn = list(set(range(nch)) - set(bad_chn))
|
|
@@ -365,62 +365,62 @@ def turning_points(data, data_type='coordinate', thresh=5, depth_info=False,
|
|
|
365
365
|
raise ValueError('Data_type should be \'coordinate\' or \'waveform\'.')
|
|
366
366
|
|
|
367
367
|
|
|
368
|
-
def _equally_spacing(
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
state = bin(i)[2:].rjust(nch - 2, '0')
|
|
380
|
-
dist_new = [dist[0]]
|
|
381
|
-
channels_new = [channels[0]]
|
|
382
|
-
idx = 0
|
|
383
|
-
for j, s in enumerate(state):
|
|
384
|
-
if s == '0':
|
|
385
|
-
dist_new[idx] += dist[j+1]
|
|
386
|
-
else:
|
|
387
|
-
dist_new.append(dist[j+1])
|
|
388
|
-
channels_new.append(channels[j+1])
|
|
389
|
-
idx += 1
|
|
390
|
-
res = sum([abs(d - dx) for d in dist_new])
|
|
391
|
-
if res < residual:
|
|
392
|
-
residual = res
|
|
393
|
-
dist_equal = dist_new
|
|
394
|
-
channels_equal = channels_new
|
|
395
|
-
channels_equal.append(channels[-1])
|
|
396
|
-
return channels_equal, dist_equal
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
def _equally_spacing_2(channels, dist, dx):
|
|
400
|
-
channels_equal = [channels[0]]
|
|
401
|
-
dist_equal = []
|
|
402
|
-
i = 0
|
|
403
|
-
while i < len(dist):
|
|
404
|
-
d = dist[i]
|
|
405
|
-
if d < dx and i < len(dist) - 1:
|
|
406
|
-
d1 = d + dist[i + 1]
|
|
407
|
-
while d1 < dx and i < len(dist) - 2:
|
|
408
|
-
d = d1
|
|
409
|
-
i += 1
|
|
410
|
-
d1 += dist[i + 1]
|
|
411
|
-
if abs(d - dx) <= abs(d1 - dx):
|
|
412
|
-
channels_equal.append(channels[i + 1])
|
|
413
|
-
dist_equal.append(d)
|
|
414
|
-
else:
|
|
415
|
-
i += 1
|
|
416
|
-
channels_equal.append(channels[i + 1])
|
|
417
|
-
dist_equal.append(d1)
|
|
368
|
+
def _equally_spacing(dist, dx):
|
|
369
|
+
index = [[], []]
|
|
370
|
+
residual = [0, abs(dist[0]-dx)]
|
|
371
|
+
for i in range(2, len(dist)+1):
|
|
372
|
+
res = []
|
|
373
|
+
for j in range(i):
|
|
374
|
+
res.append(residual[j] + abs(dx - sum(dist[j:i])))
|
|
375
|
+
residual.append(min(res))
|
|
376
|
+
k = np.argmin(res)
|
|
377
|
+
if k > 0:
|
|
378
|
+
index.append(index[k] + [k])
|
|
418
379
|
else:
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
380
|
+
index.append(index[k])
|
|
381
|
+
# print(index, residual)
|
|
382
|
+
|
|
383
|
+
return index[-1]
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def channel_spacing(geometry, depth_info=False):
|
|
387
|
+
nch = len(geometry)
|
|
388
|
+
dist = np.zeros(nch - 1)
|
|
389
|
+
for i in range(nch - 1):
|
|
390
|
+
lon0, lat0 = geometry[i, :2]
|
|
391
|
+
lon1, lat1 = geometry[i+1, :2]
|
|
392
|
+
d = Geodesic.WGS84.Inverse(lat0, lon0, lat1, lon1)['s12']
|
|
393
|
+
if depth_info:
|
|
394
|
+
dist[i] = np.sqrt(d**2 + (geometry[i+1, 2] - geometry[i, 2]) ** 2)
|
|
395
|
+
else:
|
|
396
|
+
dist[i] = d
|
|
397
|
+
|
|
398
|
+
return dist
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def closest_channel_to_point(geometry, point):
|
|
402
|
+
"""
|
|
403
|
+
Find the channel number closest to a given point.
|
|
404
|
+
|
|
405
|
+
:param geometry: numpy.ndarray. It needs to consist of longitude, latitude
|
|
406
|
+
or channel number, longitude, latitude.
|
|
407
|
+
:param point: tuple or numpy.ndarray. A tuple consisting of latitude and longitude.
|
|
408
|
+
:return: int. The channel number closest to the given point.
|
|
409
|
+
"""
|
|
410
|
+
if geometry.shape[1] == 2:
|
|
411
|
+
channels = np.arange(len(geometry)).astype(int)
|
|
412
|
+
else:
|
|
413
|
+
geometry = geometry[geometry[:, 0].argsort()]
|
|
414
|
+
channels = geometry[:, 0].astype(int)
|
|
415
|
+
geometry = geometry[:, 1:]
|
|
422
416
|
|
|
423
|
-
|
|
417
|
+
lat, lon = point
|
|
418
|
+
distances = np.array([
|
|
419
|
+
Geodesic.WGS84.Inverse(lat, lon, geometry[i, 0], geometry[i, 1])['s12']
|
|
420
|
+
for i in range(len(geometry))
|
|
421
|
+
])
|
|
422
|
+
closest_index = np.argmin(distances)
|
|
423
|
+
return int(channels[closest_index])
|
|
424
424
|
|
|
425
425
|
|
|
426
426
|
def equally_spaced_channels(geometry, dx, depth_info=False, verbose=False):
|
|
@@ -446,53 +446,36 @@ def equally_spaced_channels(geometry, dx, depth_info=False, verbose=False):
|
|
|
446
446
|
channels = geometry[:, 0].astype(int)
|
|
447
447
|
geometry = geometry[:, 1:]
|
|
448
448
|
|
|
449
|
-
dist =
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
if
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
dist_equal.append(dist[i-1])
|
|
483
|
-
else:
|
|
484
|
-
flag = True
|
|
485
|
-
|
|
486
|
-
if len(channels_seg):
|
|
487
|
-
channels_seg.extend(channels[i:i+2])
|
|
488
|
-
dist_seg.append(dist[i])
|
|
489
|
-
channels_seg, dist_seg = _equally_spacing(channels_seg, dist_seg, dx)
|
|
490
|
-
dist_equal.extend(dist_seg)
|
|
491
|
-
channels_equal.extend(channels_seg[1:])
|
|
492
|
-
else:
|
|
493
|
-
channels_equal.extend(channels[-2:])
|
|
494
|
-
dist_equal.extend(dist[-2:])
|
|
495
|
-
|
|
496
|
-
if verbose:
|
|
497
|
-
return channels_equal, dist_equal
|
|
498
|
-
return channels_equal
|
|
449
|
+
dist = channel_spacing(geometry, depth_info=False)
|
|
450
|
+
|
|
451
|
+
s = 0
|
|
452
|
+
idx_equal = [0]
|
|
453
|
+
for i in range(nch-2):
|
|
454
|
+
if dist[i] > dx * 2:
|
|
455
|
+
e = i
|
|
456
|
+
if e == s + 1:
|
|
457
|
+
idx_equal.append(e)
|
|
458
|
+
elif e >= s + 2:
|
|
459
|
+
idx_equal.extend([idx + s for idx in
|
|
460
|
+
_equally_spacing(dist[s:e], dx)])
|
|
461
|
+
idx_equal.append(e)
|
|
462
|
+
s = e + 1
|
|
463
|
+
idx_equal.append(s)
|
|
464
|
+
elif dist[i] + dist[i+1] > dx * 1.5:
|
|
465
|
+
e = i + 1
|
|
466
|
+
if e == s + 1:
|
|
467
|
+
idx_equal.append(e)
|
|
468
|
+
elif e >= s + 2:
|
|
469
|
+
idx_equal.extend([idx + s for idx in
|
|
470
|
+
_equally_spacing(dist[s:e], dx)])
|
|
471
|
+
idx_equal.append(e)
|
|
472
|
+
s = e
|
|
473
|
+
e = nch - 1
|
|
474
|
+
if e == s + 1:
|
|
475
|
+
idx_equal.append(e)
|
|
476
|
+
elif e >= s + 2:
|
|
477
|
+
idx_equal.extend([idx + s for idx in
|
|
478
|
+
_equally_spacing(dist[s:e], dx)])
|
|
479
|
+
idx_equal.append(e)
|
|
480
|
+
|
|
481
|
+
return channels[idx_equal]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Convert strain rate data to velocity
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2024.
|
|
3
|
+
# Date: 2024.3.10
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import numpy as np
|
|
6
6
|
from numpy.fft import irfft2, ifftshift
|
|
@@ -103,7 +103,6 @@ def curvelet_conversion(data, dx, fs, pad=0.3, scale_begin=2, nbscales=None,
|
|
|
103
103
|
:return: numpy.ndarray. Converted data.
|
|
104
104
|
"""
|
|
105
105
|
if turning is not None:
|
|
106
|
-
print(1)
|
|
107
106
|
data_vel = np.zeros_like(data)
|
|
108
107
|
start_ch = [0, *turning]
|
|
109
108
|
end_ch = [*turning, len(data)]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Some preprocess methods
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date:
|
|
3
|
+
# Date: 2025.3.10
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import numpy as np
|
|
6
6
|
from scipy.signal import detrend
|
|
@@ -23,13 +23,13 @@ def phase2strain(data, lam, e, n, gl):
|
|
|
23
23
|
return data * (lam * 1e-9) / (e * 4 * np.pi * n * gl)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def normalization(data, method='z-score'
|
|
26
|
+
def normalization(data, method='z-score'):
|
|
27
27
|
"""
|
|
28
28
|
Normalize for each individual channel using Z-score method.
|
|
29
29
|
|
|
30
30
|
:param data: numpy.ndarray. Data to normalize.
|
|
31
31
|
:param method: str. Method for normalization, should be one of 'max',
|
|
32
|
-
'z-score', or 'one-bit'.
|
|
32
|
+
'z-score', 'MAD' or 'one-bit'.
|
|
33
33
|
:return: Normalized data.
|
|
34
34
|
"""
|
|
35
35
|
if data.ndim == 1:
|
|
@@ -37,21 +37,21 @@ def normalization(data, method='z-score', **kwargs):
|
|
|
37
37
|
elif data.ndim != 2:
|
|
38
38
|
raise ValueError("Data should be 1-D or 2-D array")
|
|
39
39
|
|
|
40
|
-
if method == 'max':
|
|
40
|
+
if method.lower() == 'max':
|
|
41
41
|
amp = np.max(abs(data), 1, keepdims=True)
|
|
42
42
|
amp[amp == 0] = amp[amp > 0].min()
|
|
43
43
|
return data / amp
|
|
44
|
-
|
|
45
|
-
if method == 'z-score':
|
|
44
|
+
elif method.lower() == 'z-score':
|
|
46
45
|
mean = np.mean(data, axis=1, keepdims=True)
|
|
47
46
|
std = np.std(data, axis=1, keepdims=True)
|
|
48
47
|
std[std == 0] = std[std > 0].min()
|
|
49
|
-
if 'p' in kwargs.keys():
|
|
50
|
-
thresh = np.percentile(std, kwargs['p'])
|
|
51
|
-
std[std > thresh] = thresh
|
|
52
48
|
return (data - mean) / std
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
elif method.lower() == 'mad':
|
|
50
|
+
median = np.median(data, axis=1, keepdims=True)
|
|
51
|
+
mad = np.median(abs(data - median), axis=1, keepdims=True)
|
|
52
|
+
mad[mad == 0] = mad[mad > 0].min()
|
|
53
|
+
return (data - median) / mad
|
|
54
|
+
elif method.lower() == 'one-bit':
|
|
55
55
|
return np.sign(data)
|
|
56
56
|
|
|
57
57
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Purpose: Plot data
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date:
|
|
3
|
+
# Date: 2025.1.6
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import numpy as np
|
|
6
6
|
import matplotlib.pyplot as plt
|
|
7
7
|
from collections.abc import Sequence
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=
|
|
10
|
+
def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=300,
|
|
11
11
|
title=None, transpose=False, t0=0, x0=0, pick=None, f=None, k=None,
|
|
12
12
|
t=None, c=None, cmap=None, vmin=None, vmax=None, dB=False,
|
|
13
13
|
xmode='distance', tmode='time', xlim=None, ylim=None, xlog=False,
|
|
@@ -29,7 +29,9 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=150,
|
|
|
29
29
|
:param title: str. The title of this axes.
|
|
30
30
|
:param transpose: bool. Transpose the figure or not.
|
|
31
31
|
:param t0, x0: The beginning of time and space.
|
|
32
|
-
:param pick:
|
|
32
|
+
:param pick: dictionary of sequence of picked phases. Key should be 'P' for
|
|
33
|
+
P phase, 'S' for S phase and 'N' for unknown phase type. Required if
|
|
34
|
+
obj=='phasepick'.
|
|
33
35
|
:param f: Sequence of frequency. Required if obj is one of 'spectrum',
|
|
34
36
|
'spectrogram', 'fk' or 'dispersion'.
|
|
35
37
|
:param k: Wavenumber sequence. Required if obj=='fk'.
|
|
@@ -82,14 +84,18 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=150,
|
|
|
82
84
|
extent = [x0 * 1e-3, (x0 + nch * dx) * 1e-3, t0 + nt / fs, t0]
|
|
83
85
|
|
|
84
86
|
if obj == 'phasepick' and len(pick):
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
pick_color = {'P': 'r', 'S': 'b', 'N': 'k'}
|
|
88
|
+
for phase, pck in pick.items():
|
|
89
|
+
if len(pck):
|
|
90
|
+
pck = np.array(pck).astype(float)
|
|
91
|
+
if xmode.lower() == 'distance':
|
|
92
|
+
pck[:, 0] = (x0 + pck[:, 0] * dx) * 1e-3
|
|
93
|
+
elif xmode.lower() == 'channel':
|
|
94
|
+
pck[:, 0] = x0 + pck[:, 0]
|
|
95
|
+
if tmode.lower() == 'sampling':
|
|
96
|
+
pck[:, 1] = pck[:, 1] / fs
|
|
97
|
+
ax.scatter(pck[:,0], t0 + pck[:,1], marker=',', s=0.1,
|
|
98
|
+
c=pick_color[phase])
|
|
93
99
|
|
|
94
100
|
elif obj in ['spectrum', 'spectrogram', 'fk', 'dispersion']:
|
|
95
101
|
if isinstance(data[0,0], (complex, np.complex64)):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for handling Collection objects.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.3.30
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import os
|
|
6
6
|
import warnings
|
|
@@ -18,7 +18,8 @@ cascade_method = ['time_integration', 'time_differential', 'downsampling',
|
|
|
18
18
|
|
|
19
19
|
class Collection(object):
|
|
20
20
|
def __init__(self, fpath, ftype=None, flength=None, meta_from_file=True,
|
|
21
|
-
|
|
21
|
+
timeinfo_slice=slice(None), timeinfo_format=None,
|
|
22
|
+
timeinfo_tz=None, timeinfo_from_basename=True, **kwargs):
|
|
22
23
|
"""
|
|
23
24
|
:param fpath: str or Sequence of str. File path(s) containing data.
|
|
24
25
|
:param ftype: None or str. None for automatic detection, or 'pkl',
|
|
@@ -28,7 +29,11 @@ class Collection(object):
|
|
|
28
29
|
and gauge_length. True for extracting dt, dx, fs and gauge_length
|
|
29
30
|
from first 2 file. 'all' for exracting and checking these metadata
|
|
30
31
|
from all file.
|
|
31
|
-
:param
|
|
32
|
+
:param timeinfo_slice: slice. Slice for extracting start time from file
|
|
33
|
+
name.
|
|
34
|
+
:param timeinfo_format: str. Format for extracting start time from file
|
|
35
|
+
name.
|
|
36
|
+
:param timeinfo_tz: datetime.timezone. Time zone for extracting start
|
|
32
37
|
time from file name.
|
|
33
38
|
:param timeinfo_from_basename: bool. If True, timeinfo_format will use
|
|
34
39
|
DASDateTime.strptime to basename of fpath.
|
|
@@ -63,7 +68,7 @@ class Collection(object):
|
|
|
63
68
|
sec.gauge_length = None
|
|
64
69
|
ftime.append(sec.start_time)
|
|
65
70
|
metadata_list.append((sec.nch, sec.nt, sec.dx, sec.fs,
|
|
66
|
-
sec.gauge_length))
|
|
71
|
+
sec.gauge_length, sec.duration))
|
|
67
72
|
|
|
68
73
|
if len(set(metadata_list)) > 1:
|
|
69
74
|
warnings.warn('More than one kind of setting detected.')
|
|
@@ -71,6 +76,8 @@ class Collection(object):
|
|
|
71
76
|
for i, key in enumerate(['nch', 'nt', 'dx', 'fs', 'gauge_length']):
|
|
72
77
|
if not hasattr(self, key):
|
|
73
78
|
setattr(self, key, metadata[i])
|
|
79
|
+
if flength is None:
|
|
80
|
+
flength = metadata[-1]
|
|
74
81
|
self.ftime = ftime
|
|
75
82
|
elif meta_from_file:
|
|
76
83
|
i = int(len(self.flist) > 1)
|
|
@@ -88,17 +95,22 @@ class Collection(object):
|
|
|
88
95
|
setattr(self, key, metadata[i])
|
|
89
96
|
|
|
90
97
|
if not hasattr(self, 'ftime'):
|
|
91
|
-
if isinstance(timeinfo_format, tuple):
|
|
92
|
-
timeinfo_slice, timeinfo_format = timeinfo_format
|
|
93
|
-
else:
|
|
94
|
-
timeinfo_slice = slice(None)
|
|
95
98
|
if timeinfo_from_basename:
|
|
96
|
-
|
|
97
|
-
os.path.basename(f)[timeinfo_slice], timeinfo_format)
|
|
98
|
-
for f in self.flist]
|
|
99
|
+
flist_use = [os.path.basename(f) for f in self.flist]
|
|
99
100
|
else:
|
|
101
|
+
flist_use = self.flist
|
|
102
|
+
if timeinfo_tz is None:
|
|
100
103
|
self.ftime = [DASDateTime.strptime(f[timeinfo_slice],
|
|
101
|
-
timeinfo_format) for f in
|
|
104
|
+
timeinfo_format) for f in flist_use]
|
|
105
|
+
else:
|
|
106
|
+
if '%z' in timeinfo_format.lower():
|
|
107
|
+
self.ftime = [DASDateTime.strptime(f[timeinfo_slice],
|
|
108
|
+
timeinfo_format).astimezone(timeinfo_tz) for f in
|
|
109
|
+
flist_use]
|
|
110
|
+
else:
|
|
111
|
+
self.ftime = [DASDateTime.strptime(f[timeinfo_slice],
|
|
112
|
+
timeinfo_format).replace(tzinfo=timeinfo_tz) for f in
|
|
113
|
+
flist_use]
|
|
102
114
|
|
|
103
115
|
self._sort()
|
|
104
116
|
if flength is None:
|
|
@@ -211,6 +223,9 @@ class Collection(object):
|
|
|
211
223
|
flist.append(self.flist[i])
|
|
212
224
|
ftime.append(self.ftime[i])
|
|
213
225
|
|
|
226
|
+
if len(flist) == 0:
|
|
227
|
+
warnings.warn('Out of collection time range.')
|
|
228
|
+
return None
|
|
214
229
|
if readsec:
|
|
215
230
|
sec = read(flist[0], **kwargs)
|
|
216
231
|
for f in flist[1:]:
|
|
@@ -218,10 +233,9 @@ class Collection(object):
|
|
|
218
233
|
sec.trimming(tmin=stime, tmax=etime)
|
|
219
234
|
return sec
|
|
220
235
|
else:
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return coll
|
|
236
|
+
self.flist = flist
|
|
237
|
+
self.ftime = ftime
|
|
238
|
+
return self
|
|
225
239
|
|
|
226
240
|
def _optimize_for_continuity(self, operations):
|
|
227
241
|
method_list = []
|
|
@@ -231,8 +245,8 @@ class Collection(object):
|
|
|
231
245
|
for opera in operations:
|
|
232
246
|
method, kwargs = opera
|
|
233
247
|
if method == 'downsampling':
|
|
234
|
-
if hasattr(kwargs, 'lowpass_filter') and not\
|
|
235
|
-
|
|
248
|
+
if (hasattr(kwargs, 'lowpass_filter') and not\
|
|
249
|
+
kwargs['lowpass_filter']) or not hasattr(kwargs, 'tint'):
|
|
236
250
|
method_list.append('downsampling')
|
|
237
251
|
kwargs_list.append(kwargs)
|
|
238
252
|
else:
|
|
@@ -271,6 +285,16 @@ class Collection(object):
|
|
|
271
285
|
merge = len(self)
|
|
272
286
|
for i in tqdm(range(0, len(self))):
|
|
273
287
|
f = self[i]
|
|
288
|
+
if os.path.getsize(f) == 0:
|
|
289
|
+
for j, method in enumerate(method_list):
|
|
290
|
+
if method == 'time_integration':
|
|
291
|
+
kwargs_list[j]['c'] = 0
|
|
292
|
+
elif method == 'time_differential':
|
|
293
|
+
kwargs_list[j]['prepend'] = 0
|
|
294
|
+
elif method in ['bandpass', 'bandstop', 'lowpass',
|
|
295
|
+
'highpass', 'lowpass_cheby_2']:
|
|
296
|
+
kwargs_list[j]['zi'] = 0
|
|
297
|
+
continue
|
|
274
298
|
sec = read(f, ftype=self.ftype, **read_kwargs)
|
|
275
299
|
for j, method in enumerate(method_list):
|
|
276
300
|
if method in ['taper', 'cosine_taper']:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for handling DASDateTime objects.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date:
|
|
3
|
+
# Date: 2025.3.29
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import time
|
|
6
6
|
from typing import Iterable
|
|
@@ -48,10 +48,10 @@ class DASDateTime(datetime):
|
|
|
48
48
|
def __gt__(self, other):
|
|
49
49
|
return datetime.__gt__(*self._unify_tz(other))
|
|
50
50
|
|
|
51
|
-
def _unify_tz(self, other):
|
|
52
|
-
if self.tzinfo and not other.tzinfo:
|
|
51
|
+
def _unify_tz(self, other: datetime):
|
|
52
|
+
if self.tzinfo and (not other.tzinfo):
|
|
53
53
|
return self, other.replace(tzinfo=self.tzinfo)
|
|
54
|
-
elif not self.tzinfo and other.tzinfo:
|
|
54
|
+
elif (not self.tzinfo) and other.tzinfo:
|
|
55
55
|
return self.replace(tzinfo=other.tzinfo), other
|
|
56
56
|
return self, other
|
|
57
57
|
|
|
@@ -77,4 +77,26 @@ class DASDateTime(datetime):
|
|
|
77
77
|
|
|
78
78
|
def to_obspy_UTCDateTime(self):
|
|
79
79
|
from obspy import UTCDateTime
|
|
80
|
-
return UTCDateTime(UTCDateTime(self.to_datetime()))
|
|
80
|
+
return UTCDateTime(UTCDateTime(self.to_datetime()))
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def strptime(cls, date_string, format):
|
|
84
|
+
"""
|
|
85
|
+
string, format -> new datetime parsed from a string
|
|
86
|
+
(like time.strptime()).
|
|
87
|
+
"""
|
|
88
|
+
from _strptime import _strptime
|
|
89
|
+
tt, fraction, gmtoff_fraction = _strptime(date_string, format)
|
|
90
|
+
tzname, gmtoff = tt[-2:]
|
|
91
|
+
args = tt[:6] + (fraction,)
|
|
92
|
+
if gmtoff is not None:
|
|
93
|
+
tzdelta = timedelta(seconds=gmtoff, microseconds=gmtoff_fraction)
|
|
94
|
+
if tzname:
|
|
95
|
+
tz = timezone(tzdelta, tzname)
|
|
96
|
+
else:
|
|
97
|
+
tz = timezone(tzdelta)
|
|
98
|
+
args += (tz,)
|
|
99
|
+
elif tt[-3] == 0:
|
|
100
|
+
args += (utc,)
|
|
101
|
+
|
|
102
|
+
return cls(*args)
|