DASPy-toolbox 1.1.5__tar.gz → 1.1.6__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.5 → daspy_toolbox-1.1.6}/DASPy_toolbox.egg-info/PKG-INFO +1 -1
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/PKG-INFO +1 -1
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/advanced_tools/channel.py +17 -18
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/basic_tools/preprocessing.py +3 -3
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/basic_tools/visualization.py +20 -10
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/core/collection.py +65 -26
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/core/read.py +26 -5
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/core/section.py +41 -7
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/core/write.py +12 -3
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/setup.py +1 -1
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/DASPy_toolbox.egg-info/SOURCES.txt +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/DASPy_toolbox.egg-info/dependency_links.txt +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/DASPy_toolbox.egg-info/entry_points.txt +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/DASPy_toolbox.egg-info/requires.txt +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/DASPy_toolbox.egg-info/top_level.txt +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/LICENSE +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/README.md +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/__init__.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/advanced_tools/__init__.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/advanced_tools/decomposition.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/advanced_tools/denoising.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/advanced_tools/fdct.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/advanced_tools/strain2vel.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/basic_tools/__init__.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/basic_tools/filter.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/basic_tools/freqattributes.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/core/__init__.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/core/dasdatetime.py +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/daspy/core/example.pkl +0 -0
- {daspy_toolbox-1.1.5 → daspy_toolbox-1.1.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DASPy-toolbox
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.6
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DASPy-toolbox
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.6
|
|
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
|
|
@@ -365,24 +365,6 @@ 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(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])
|
|
379
|
-
else:
|
|
380
|
-
index.append(index[k])
|
|
381
|
-
# print(index, residual)
|
|
382
|
-
|
|
383
|
-
return index[-1]
|
|
384
|
-
|
|
385
|
-
|
|
386
368
|
def channel_spacing(geometry, depth_info=False):
|
|
387
369
|
nch = len(geometry)
|
|
388
370
|
dist = np.zeros(nch - 1)
|
|
@@ -456,6 +438,23 @@ def closest_channel_to_point(geometry, points, verbose=False):
|
|
|
456
438
|
return channels[closest_index]
|
|
457
439
|
|
|
458
440
|
|
|
441
|
+
def _equally_spacing(dist, dx):
|
|
442
|
+
index = [[], []]
|
|
443
|
+
residual = [0, abs(dist[0]-dx)]
|
|
444
|
+
for i in range(2, len(dist)+1):
|
|
445
|
+
res = []
|
|
446
|
+
for j in range(i):
|
|
447
|
+
res.append(residual[j] + abs(dx - sum(dist[j:i])))
|
|
448
|
+
residual.append(min(res))
|
|
449
|
+
k = np.argmin(res)
|
|
450
|
+
if k > 0:
|
|
451
|
+
index.append(index[k] + [k])
|
|
452
|
+
else:
|
|
453
|
+
index.append(index[k])
|
|
454
|
+
|
|
455
|
+
return index[-1]
|
|
456
|
+
|
|
457
|
+
|
|
459
458
|
def equally_spaced_channels(geometry, dx, depth_info=False, verbose=False):
|
|
460
459
|
"""
|
|
461
460
|
Find equally spaced channel numbers based on known DAS latitude and
|
|
@@ -145,14 +145,14 @@ def downsampling(data, xint=None, tint=None, stack=True, lowpass_filter=True):
|
|
|
145
145
|
if stack:
|
|
146
146
|
data_ds = stacking(data, xint)
|
|
147
147
|
else:
|
|
148
|
-
data_ds = data_ds[::xint]
|
|
148
|
+
data_ds = data_ds[::xint].copy()
|
|
149
149
|
if tint and tint > 1:
|
|
150
150
|
if lowpass_filter:
|
|
151
151
|
data_ds = lowpass_cheby_2(data_ds, 1, 1 / 2 / tint)
|
|
152
152
|
if len(data_ds.shape) == 1:
|
|
153
|
-
data_ds = data_ds[::tint]
|
|
153
|
+
data_ds = data_ds[::tint].copy()
|
|
154
154
|
else:
|
|
155
|
-
data_ds = data_ds[:, ::tint]
|
|
155
|
+
data_ds = data_ds[:, ::tint].copy()
|
|
156
156
|
return data_ds
|
|
157
157
|
|
|
158
158
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Plot data
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.5.20
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import numpy as np
|
|
6
6
|
import matplotlib.pyplot as plt
|
|
@@ -9,11 +9,11 @@ from collections.abc import Sequence
|
|
|
9
9
|
|
|
10
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
|
-
t=None, c=None, cmap=None, vmin=None,
|
|
13
|
-
xmode='distance', tmode='time', xlim=None,
|
|
14
|
-
ylog=False, xinv=False, yinv=False, xlabel=True,
|
|
15
|
-
xticklabels=True, yticklabels=True, colorbar=True,
|
|
16
|
-
savefig=None):
|
|
12
|
+
t=None, c=None, cmap=None, vmin=None, vmin_per=None, vmax=None,
|
|
13
|
+
vmax_per=None, dB=False, xmode='distance', tmode='time', xlim=None,
|
|
14
|
+
ylim=None, xlog=False, ylog=False, xinv=False, yinv=False, xlabel=True,
|
|
15
|
+
ylabel=True, xticklabels=True, yticklabels=True, colorbar=True,
|
|
16
|
+
colorbar_label=None, savefig=None):
|
|
17
17
|
"""
|
|
18
18
|
Plot several types of 2-D seismological data.
|
|
19
19
|
|
|
@@ -40,6 +40,8 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=300,
|
|
|
40
40
|
:param cmap: str or Colormap. The Colormap instance or registered colormap
|
|
41
41
|
name used to map scalar data to colors.
|
|
42
42
|
:param vmin, vmax: Define the data range that the colormap covers.
|
|
43
|
+
:param vmin_per, vmax_per: float. Define the data range that the colormap
|
|
44
|
+
covers by percentile.
|
|
43
45
|
:param dB: bool. Transfer data unit to dB and take 1 as the reference value.
|
|
44
46
|
:param xmode: str. 'distance' or 'channel'.
|
|
45
47
|
:param tmode: str. 'time' or 'sampling'.
|
|
@@ -67,7 +69,9 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=300,
|
|
|
67
69
|
|
|
68
70
|
if obj in ['waveform', 'phasepick']:
|
|
69
71
|
cmap = 'RdBu' if cmap is None else cmap
|
|
70
|
-
|
|
72
|
+
if vmax is None:
|
|
73
|
+
vmax_per = 80 if vmax_per is None else vmax_per
|
|
74
|
+
vmax = np.percentile(data, vmax_per)
|
|
71
75
|
vmin = -vmax if vmin is None else vmin
|
|
72
76
|
origin = 'upper'
|
|
73
77
|
if fs is None or tmode == 'sampling':
|
|
@@ -98,13 +102,19 @@ def plot(data: np.ndarray, dx=None, fs=None, ax=None, obj='waveform', dpi=300,
|
|
|
98
102
|
c=pick_color[phase])
|
|
99
103
|
|
|
100
104
|
elif obj in ['spectrum', 'spectrogram', 'fk', 'dispersion']:
|
|
101
|
-
if
|
|
105
|
+
if np.iscomplex(data).any():
|
|
102
106
|
data = abs(data)
|
|
103
107
|
if dB:
|
|
104
108
|
data = 20 * np.log10(data)
|
|
105
109
|
cmap = 'jet' if cmap is None else cmap
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
|
|
111
|
+
if vmax is None:
|
|
112
|
+
vmax_per = 80 if vmax_per is None else vmax_per
|
|
113
|
+
vmax = np.percentile(data, vmax_per)
|
|
114
|
+
if vmin is None:
|
|
115
|
+
vmin_per = 20 if vmin_per is None else vmin_per
|
|
116
|
+
vmin = np.percentile(data, vmin_per)
|
|
117
|
+
|
|
108
118
|
if obj == 'spectrum':
|
|
109
119
|
origin = 'lower'
|
|
110
120
|
if dx is None or xmode.lower() == 'channel':
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Purpose: Module for handling Collection objects.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.5.21
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import os
|
|
6
|
+
import gc
|
|
6
7
|
import warnings
|
|
7
8
|
import numpy as np
|
|
8
9
|
from copy import deepcopy
|
|
@@ -12,10 +13,6 @@ from daspy.core.read import read
|
|
|
12
13
|
from daspy.core.dasdatetime import DASDateTime
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
cascade_method = ['time_integration', 'time_differential', 'downsampling',
|
|
16
|
-
'bandpass', 'bandstop', 'lowpass', 'highpass',
|
|
17
|
-
'lowpass_cheby_2']
|
|
18
|
-
|
|
19
16
|
class Collection(object):
|
|
20
17
|
def __init__(self, fpath, ftype=None, flength=None, meta_from_file=True,
|
|
21
18
|
timeinfo_slice=slice(None), timeinfo_format=None,
|
|
@@ -265,8 +262,18 @@ class Collection(object):
|
|
|
265
262
|
kwargs_list.append(kwargs)
|
|
266
263
|
return method_list, kwargs_list
|
|
267
264
|
|
|
265
|
+
def _kwargs_initialization(method_list, kwargs_list):
|
|
266
|
+
for j, method in enumerate(method_list):
|
|
267
|
+
if method == 'time_integration':
|
|
268
|
+
kwargs_list[j]['c'] = 0
|
|
269
|
+
elif method == 'time_differential':
|
|
270
|
+
kwargs_list[j]['prepend'] = 0
|
|
271
|
+
elif method in ['bandpass', 'bandstop', 'lowpass',
|
|
272
|
+
'highpass', 'lowpass_cheby_2']:
|
|
273
|
+
kwargs_list[j]['zi'] = 0
|
|
274
|
+
|
|
268
275
|
def process(self, operations, savepath='./processed', merge=1,
|
|
269
|
-
suffix='_pro', ftype=None, **read_kwargs):
|
|
276
|
+
suffix='_pro', ftype=None, dtype=None, **read_kwargs):
|
|
270
277
|
"""
|
|
271
278
|
:param operations: list. Each element of operations list should be [str
|
|
272
279
|
of method name, dict of kwargs].
|
|
@@ -274,8 +281,10 @@ class Collection(object):
|
|
|
274
281
|
:param merge: int or str. int for merge several processed files into 1.
|
|
275
282
|
'all' for merge all files.
|
|
276
283
|
:param suffix: str. Suffix for processed files.
|
|
277
|
-
:param ftype: None or str.
|
|
278
|
-
'pickle', 'tdms', 'h5', 'hdf5', 'segy', 'sgy',
|
|
284
|
+
:param ftype: None or str. File format for saving. None for automatic
|
|
285
|
+
detection, or 'pkl', 'pickle', 'tdms', 'h5', 'hdf5', 'segy', 'sgy',
|
|
286
|
+
'npy'.
|
|
287
|
+
:param dtype: str. The data type of the saved data.
|
|
279
288
|
:param read_kwargs: dict. Paramters for read function.
|
|
280
289
|
"""
|
|
281
290
|
if not os.path.exists(savepath):
|
|
@@ -283,36 +292,35 @@ class Collection(object):
|
|
|
283
292
|
method_list, kwargs_list = self._optimize_for_continuity(operations)
|
|
284
293
|
if merge == 'all' or merge > len(self):
|
|
285
294
|
merge = len(self)
|
|
286
|
-
for i in tqdm(range(
|
|
295
|
+
for i in tqdm(range(len(self))):
|
|
287
296
|
f = self[i]
|
|
288
297
|
if os.path.getsize(f) == 0:
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
kwargs_list[j]['zi'] = 0
|
|
298
|
+
self._kwargs_initialization(method_list, kwargs_list)
|
|
299
|
+
continue
|
|
300
|
+
try:
|
|
301
|
+
sec = read(f, ftype=self.ftype, **read_kwargs)
|
|
302
|
+
except Exception as e:
|
|
303
|
+
warnings.warn(f'Error reading {f}: {e}')
|
|
304
|
+
self._kwargs_initialization(method_list, kwargs_list)
|
|
297
305
|
continue
|
|
298
|
-
sec = read(f, ftype=self.ftype, **read_kwargs)
|
|
299
306
|
for j, method in enumerate(method_list):
|
|
300
307
|
if method in ['taper', 'cosine_taper']:
|
|
301
|
-
if not ((i==0 and kwargs_list[j] != 'right') or
|
|
302
|
-
(i == len(self) - 1 and kwargs_list[j] !=
|
|
308
|
+
if not ((i==0 and kwargs_list[j]['side'] != 'right') or
|
|
309
|
+
(i == len(self) - 1 and kwargs_list[j]['side'] !=
|
|
310
|
+
'left')):
|
|
303
311
|
continue
|
|
304
|
-
out =
|
|
312
|
+
out = getattr(sec, method)(**kwargs_list[j])
|
|
305
313
|
if method == 'time_integration':
|
|
306
|
-
kwargs_list[j]['c'] = sec.data[:, -1]
|
|
314
|
+
kwargs_list[j]['c'] = sec.data[:, -1].copy()
|
|
307
315
|
elif method == 'time_differential':
|
|
308
|
-
kwargs_list[j]['prepend'] = sec.data[:, -1]
|
|
316
|
+
kwargs_list[j]['prepend'] = sec.data[:, -1].copy()
|
|
309
317
|
elif method in ['bandpass', 'bandstop', 'lowpass', 'highpass',
|
|
310
318
|
'lowpass_cheby_2']:
|
|
311
319
|
kwargs_list[j]['zi'] = out
|
|
312
320
|
|
|
313
|
-
if i % merge == 0:
|
|
321
|
+
if i % merge == 0:
|
|
314
322
|
if i != 0:
|
|
315
|
-
sec_merge.save(filepath)
|
|
323
|
+
sec_merge.save(filepath, dtype=dtype)
|
|
316
324
|
sec_merge = sec
|
|
317
325
|
f0, f1 = os.path.splitext(os.path.basename(f))
|
|
318
326
|
if ftype is not None:
|
|
@@ -320,4 +328,35 @@ class Collection(object):
|
|
|
320
328
|
filepath = os.path.join(savepath, f0+suffix+f1)
|
|
321
329
|
else:
|
|
322
330
|
sec_merge += sec
|
|
323
|
-
|
|
331
|
+
del sec
|
|
332
|
+
gc.collect()
|
|
333
|
+
sec_merge.save(filepath, dtype=dtype)
|
|
334
|
+
|
|
335
|
+
# Dynamically add methods for cascade_methods
|
|
336
|
+
def _create_cascade_method(method_name):
|
|
337
|
+
def cascade_method(self, savepath='./processed', merge=1,
|
|
338
|
+
suffix=f'_{method_name}', ftype=None, dtype=None,
|
|
339
|
+
**kwargs):
|
|
340
|
+
"""
|
|
341
|
+
Automatically generated method for {method_name}.
|
|
342
|
+
Applies the {method_name} operation to the data and saves the result.
|
|
343
|
+
|
|
344
|
+
:param savepath: str. Path to save processed files.
|
|
345
|
+
:param merge: int or str. int for merge several processed files into 1.
|
|
346
|
+
'all' for merge all files.
|
|
347
|
+
:param suffix: str. Suffix for processed files.
|
|
348
|
+
:param ftype: None or str. None for automatic detection, or 'pkl',
|
|
349
|
+
'pickle', 'tdms', 'h5', 'hdf5', 'segy', 'sgy', 'npy'.
|
|
350
|
+
:param kwargs: dict. Parameters for the {method_name} operation.
|
|
351
|
+
:param dtype: str. The data type of the saved data.
|
|
352
|
+
"""
|
|
353
|
+
operations = [[method_name, kwargs]]
|
|
354
|
+
self.process(operations, savepath=savepath, merge=merge, suffix=suffix,
|
|
355
|
+
ftype=ftype, dtype=dtype)
|
|
356
|
+
return cascade_method
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
for method in ['time_integration', 'time_differential', 'downsampling',
|
|
360
|
+
'bandpass', 'bandstop', 'lowpass', 'highpass',
|
|
361
|
+
'lowpass_cheby_2']:
|
|
362
|
+
setattr(Collection, method, _create_cascade_method(method))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for reading DAS data.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date:
|
|
3
|
+
# Date: 2025.5.21
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
# Partially modified from
|
|
6
6
|
# https://github.com/RobbinLuo/das-toolkit/blob/main/DasTools/DasPrep.py
|
|
@@ -10,6 +10,7 @@ import pickle
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
import h5py
|
|
12
12
|
import segyio
|
|
13
|
+
from typing import Union
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
from nptdms import TdmsFile
|
|
15
16
|
from daspy.core.section import Section
|
|
@@ -17,7 +18,7 @@ from daspy.core.dasdatetime import DASDateTime, utc
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
def read(fname=None, output_type='section', ftype=None, headonly=False,
|
|
20
|
-
**kwargs):
|
|
21
|
+
dtype=None, **kwargs) -> Union[Section, tuple]:
|
|
21
22
|
"""
|
|
22
23
|
Read a .pkl/.pickle, .tdms, .h5/.hdf5, .segy/.sgy file.
|
|
23
24
|
|
|
@@ -34,6 +35,7 @@ def read(fname=None, output_type='section', ftype=None, headonly=False,
|
|
|
34
35
|
:param ch1: int. The first channel required.
|
|
35
36
|
:param ch2: int. The last channel required (not included).
|
|
36
37
|
:param dch: int. Channel step.
|
|
38
|
+
:param dtype: str. The data type of the returned data.
|
|
37
39
|
:return: An instance of daspy.Section, or numpy.array for data and a
|
|
38
40
|
dictionary for metadata.
|
|
39
41
|
"""
|
|
@@ -55,10 +57,13 @@ def read(fname=None, output_type='section', ftype=None, headonly=False,
|
|
|
55
57
|
ftype = ftype.replace(*rtp)
|
|
56
58
|
data, metadata = fun_map[ftype](fname, headonly=headonly, **kwargs)
|
|
57
59
|
|
|
60
|
+
if dtype is not None:
|
|
61
|
+
data = data.astype(dtype)
|
|
58
62
|
if output_type.lower() == 'section':
|
|
59
63
|
metadata['source'] = Path(fname)
|
|
60
64
|
metadata['source_type'] = ftype
|
|
61
|
-
|
|
65
|
+
data[np.isnan(data)] = 0
|
|
66
|
+
return Section(data, **metadata)
|
|
62
67
|
elif output_type.lower() == 'array':
|
|
63
68
|
return data, metadata
|
|
64
69
|
|
|
@@ -184,6 +189,22 @@ def _read_h5(fname, headonly=False, **kwargs):
|
|
|
184
189
|
'dx': dx * dch, 'start_channel': ch1,
|
|
185
190
|
'start_distance': ch1 * dx,
|
|
186
191
|
'gauge_length': h5_file.get('GaugeLength')[()]}
|
|
192
|
+
elif len(h5_file.keys()) == 3: # OpataSense
|
|
193
|
+
nch = h5_file['data'].shape[1]
|
|
194
|
+
ch1 = kwargs.pop('ch1', 0)
|
|
195
|
+
ch2 = kwargs.pop('ch2', nch)
|
|
196
|
+
dch = kwargs.pop('dch', 1)
|
|
197
|
+
if headonly:
|
|
198
|
+
data = np.zeros_like(h5_file['data'])
|
|
199
|
+
else:
|
|
200
|
+
data = h5_file['data'][ch1:ch2:dch, :]
|
|
201
|
+
dx = (h5_file['x_axis'][-1] - h5_file['x_axis'][0]) / \
|
|
202
|
+
(len(h5_file['x_axis']) - 1)
|
|
203
|
+
fs = (len(h5_file['t_axis']) - 1) / (h5_file['t_axis'][-1] -
|
|
204
|
+
h5_file['t_axis'][0])
|
|
205
|
+
metadata = {'dx': dx, 'fs': fs, 'start_channel': ch1,
|
|
206
|
+
'start_distance': h5_file['x_axis'][0] + dx * ch1,
|
|
207
|
+
'start_time': h5_file['t_axis'][0]}
|
|
187
208
|
elif set(h5_file.keys()) == {'Mapping', 'Acquisition'}: # Silixa/iDAS
|
|
188
209
|
nch = h5_file['Acquisition/Raw[0]'].attrs['NumberOfLoci']
|
|
189
210
|
ch1 = kwargs.pop('ch1', 0)
|
|
@@ -274,7 +295,7 @@ def _read_h5(fname, headonly=False, **kwargs):
|
|
|
274
295
|
ch2 = kwargs.pop('ch2', nch)
|
|
275
296
|
dch = kwargs.pop('dch', 1)
|
|
276
297
|
if headonly:
|
|
277
|
-
data = np.zeros_like(h5_file['
|
|
298
|
+
data = np.zeros_like(h5_file['data'])
|
|
278
299
|
else:
|
|
279
300
|
data = h5_file['data'][ch1:ch2:dch, :]
|
|
280
301
|
attr = h5_file['data'].attrs
|
|
@@ -340,7 +361,7 @@ def _read_h5(fname, headonly=False, **kwargs):
|
|
|
340
361
|
else:
|
|
341
362
|
if len(dataset.shape) == 3: # Febus A1-R
|
|
342
363
|
data = dataset[:, :, ch1 - start_channel:ch2 - start_channel
|
|
343
|
-
:dch].
|
|
364
|
+
:dch].reshape((-1, (ch2 - ch1) // dch)).T
|
|
344
365
|
elif len(dataset.shape) == 2: # Febus A1
|
|
345
366
|
data = dataset[:, ch1 - start_channel:ch2 - start_channel:
|
|
346
367
|
dch].T
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for handling Section objects.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date: 2025.
|
|
3
|
+
# Date: 2025.5.15
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import warnings
|
|
6
6
|
import os
|
|
@@ -162,6 +162,10 @@ class Section(object):
|
|
|
162
162
|
def nt(self):
|
|
163
163
|
return self.data.shape[1]
|
|
164
164
|
|
|
165
|
+
@property
|
|
166
|
+
def channel_number(self):
|
|
167
|
+
return np.arange(self.nch).astype(int) + self.start_channel
|
|
168
|
+
|
|
165
169
|
@property
|
|
166
170
|
def end_channel(self):
|
|
167
171
|
return self.start_channel + self.nch - 1
|
|
@@ -172,7 +176,7 @@ class Section(object):
|
|
|
172
176
|
|
|
173
177
|
@property
|
|
174
178
|
def channel_distance(self):
|
|
175
|
-
return self.dx * np.arange(self.nch) + self.
|
|
179
|
+
return self.dx * np.arange(self.nch) + self.start_distance
|
|
176
180
|
|
|
177
181
|
@property
|
|
178
182
|
def end_distance(self):
|
|
@@ -232,10 +236,10 @@ class Section(object):
|
|
|
232
236
|
data = np.zeros((max(channel_no) + 1, nt))
|
|
233
237
|
for i, tr in enumerate(st):
|
|
234
238
|
data[channel_no[i]] = tr.data
|
|
235
|
-
|
|
239
|
+
# data = data.astype(float)
|
|
236
240
|
warnings.warn('obspy.core.stream.Stream doesn\'t include channel '
|
|
237
241
|
'interval. Please set dx manually.')
|
|
238
|
-
return cls(data
|
|
242
|
+
return cls(data, None, fs, start_channel=start_channel,
|
|
239
243
|
start_time=start_time, scale=scale, source=source)
|
|
240
244
|
|
|
241
245
|
@classmethod
|
|
@@ -418,7 +422,7 @@ class Section(object):
|
|
|
418
422
|
start_channel=self.start_channel, channel_spacing=self.dx,
|
|
419
423
|
unit=unit)
|
|
420
424
|
|
|
421
|
-
def save(self, fname=None, ftype=None, keep_format=False):
|
|
425
|
+
def save(self, fname=None, ftype=None, keep_format=False, dtype=None):
|
|
422
426
|
"""
|
|
423
427
|
Save the instance as a pickle file or update the raw file and resave as
|
|
424
428
|
new file.
|
|
@@ -430,6 +434,7 @@ class Section(object):
|
|
|
430
434
|
:param keep_format: bool. If True, we will make a copy of the
|
|
431
435
|
self.source file and make changes to it. This will strictly preserve
|
|
432
436
|
the original format, but will cost more IO resources.
|
|
437
|
+
:param dtype: str. The data type of the saved data.
|
|
433
438
|
"""
|
|
434
439
|
if fname is None:
|
|
435
440
|
if hasattr(self, 'source'):
|
|
@@ -452,9 +457,36 @@ class Section(object):
|
|
|
452
457
|
raise ValueError('self.source is not a file.')
|
|
453
458
|
if ftype != self.source_type:
|
|
454
459
|
raise ValueError('self.source_type is different from ftype.')
|
|
455
|
-
write(self, fname, ftype=ftype, raw_fname=self.source)
|
|
460
|
+
write(self, fname, ftype=ftype, raw_fname=self.source, dtype=dtype)
|
|
461
|
+
else:
|
|
462
|
+
write(self, fname, ftype=ftype, dtype=dtype)
|
|
463
|
+
|
|
464
|
+
return self
|
|
465
|
+
|
|
466
|
+
def concat(self, other, reverse=True):
|
|
467
|
+
"""
|
|
468
|
+
Concatenate two sections in space.
|
|
469
|
+
|
|
470
|
+
:param other: Section. Another section to concatenate.
|
|
471
|
+
:param reverse: bool. If True, the start channels of the two are
|
|
472
|
+
connected, and the channel numbers of the original Section instances
|
|
473
|
+
becomes a negative number.
|
|
474
|
+
"""
|
|
475
|
+
if isinstance(other, Section):
|
|
476
|
+
assert self.fs == other.fs, 'The sampling rate of the two ' \
|
|
477
|
+
'sections should be the same.'
|
|
478
|
+
assert self.dx == other.dx, 'The channel interval of the two ' \
|
|
479
|
+
'sections should be the same.'
|
|
480
|
+
assert self.duration == other.duration, 'The duration of the two ' \
|
|
481
|
+
'sections should be the same.'
|
|
482
|
+
if reverse:
|
|
483
|
+
self.start_channel = -self.end_channel
|
|
484
|
+
self.start_distance = -self.end_distance
|
|
485
|
+
self.data = np.vstack((self.data[::-1], other.data))
|
|
486
|
+
else:
|
|
487
|
+
self.data = np.vstack((self.data, other.data))
|
|
456
488
|
else:
|
|
457
|
-
|
|
489
|
+
raise TypeError('The input should be Section.')
|
|
458
490
|
|
|
459
491
|
return self
|
|
460
492
|
|
|
@@ -495,6 +527,8 @@ class Section(object):
|
|
|
495
527
|
:param cmap: str or Colormap. The Colormap instance or registered
|
|
496
528
|
colormap name used to map scalar data to colors.
|
|
497
529
|
:param vmin, vmax: Define the data range that the colormap covers.
|
|
530
|
+
:param vmin_per, vmax_per: float. Define the data range that the
|
|
531
|
+
colormap covers by percentile.
|
|
498
532
|
:param xlim, ylim: Set the x-axis and y-axis view limits.
|
|
499
533
|
:param dB: bool. Transfer data unit to dB and take 1 as the reference
|
|
500
534
|
value.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Purpose: Module for writing DAS data.
|
|
2
2
|
# Author: Minzhe Hu
|
|
3
|
-
# Date:
|
|
3
|
+
# Date: 2025.5.21
|
|
4
4
|
# Email: hmz2018@mail.ustc.edu.cn
|
|
5
5
|
import os
|
|
6
6
|
import warnings
|
|
@@ -13,12 +13,15 @@ from nptdms import TdmsFile, TdmsWriter, RootObject, GroupObject, ChannelObject
|
|
|
13
13
|
from datetime import datetime
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def write(sec, fname, ftype=None, raw_fname=None):
|
|
16
|
+
def write(sec, fname, ftype=None, raw_fname=None, dtype=None):
|
|
17
17
|
fun_map = {'tdms': _write_tdms, 'h5': _write_h5, 'sgy': _write_segy}
|
|
18
18
|
if ftype is None:
|
|
19
19
|
ftype = str(fname).lower().split('.')[-1]
|
|
20
20
|
ftype.replace('hdf5', 'h5')
|
|
21
21
|
ftype.replace('segy', 'sgy')
|
|
22
|
+
if dtype is not None:
|
|
23
|
+
sec = sec.copy()
|
|
24
|
+
sec.data = sec.data.astype(dtype)
|
|
22
25
|
if ftype == 'pkl':
|
|
23
26
|
write_pkl(sec, fname)
|
|
24
27
|
elif ftype == 'npy':
|
|
@@ -175,6 +178,12 @@ def _write_h5(sec, fname, raw_fname=None):
|
|
|
175
178
|
if hasattr(sec, 'gauge_length'):
|
|
176
179
|
_update_h5_dataset(h5_file, '/', 'GaugeLength',
|
|
177
180
|
sec.gauge_length)
|
|
181
|
+
elif len(h5_file.keys()) == 3:
|
|
182
|
+
_update_h5_dataset(h5_file, '/', 'data', sec.data)
|
|
183
|
+
_update_h5_dataset(h5_file, '/', 'x_axis',
|
|
184
|
+
sec.start_distance + np.arange(sec.nch) * sec.dx)
|
|
185
|
+
_update_h5_dataset(h5_file, '/', 't_axis',
|
|
186
|
+
sec.start_time + np.arange(sec.nt) * sec.dt)
|
|
178
187
|
elif group == 'Acquisition':
|
|
179
188
|
h5_file['Acquisition'].attrs['NumberOfLoci'] = sec.nch
|
|
180
189
|
_update_h5_dataset(h5_file, 'Acquisition/Raw[0]/', 'RawData',
|
|
@@ -279,7 +288,7 @@ def _write_segy(sec, fname, raw_fname=None):
|
|
|
279
288
|
with segyio.create(fname, spec) as new_file:
|
|
280
289
|
new_file.header.length = sec.nch
|
|
281
290
|
new_file.header.segy._filename = fname
|
|
282
|
-
new_file.trace = sec.data.astype(np.float32)
|
|
291
|
+
new_file.trace = sec.data # .astype(np.float32)
|
|
283
292
|
else:
|
|
284
293
|
with segyio.open(raw_fname, ignore_geometry=True) as raw_file:
|
|
285
294
|
spec.sorting = raw_file.sorting
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
setup(
|
|
5
|
-
name='DASPy-toolbox', version='1.1.
|
|
5
|
+
name='DASPy-toolbox', version='1.1.6',
|
|
6
6
|
description=(
|
|
7
7
|
'DASPy is an open-source project dedicated to provide a python package '
|
|
8
8
|
'for DAS (Distributed Acoustic Sensing) data processing, which '
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|