DASPy-toolbox 1.1.2__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.
Files changed (30) hide show
  1. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/PKG-INFO +3 -2
  2. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/PKG-INFO +3 -2
  3. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/advanced_tools/channel.py +88 -105
  4. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/advanced_tools/strain2vel.py +1 -2
  5. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/basic_tools/preprocessing.py +11 -11
  6. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/core/collection.py +21 -11
  7. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/core/dasdatetime.py +4 -4
  8. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/core/section.py +10 -3
  9. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/setup.py +1 -1
  10. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/SOURCES.txt +0 -0
  11. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/dependency_links.txt +0 -0
  12. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/entry_points.txt +0 -0
  13. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/requires.txt +0 -0
  14. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/DASPy_toolbox.egg-info/top_level.txt +0 -0
  15. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/LICENSE +0 -0
  16. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/README.md +0 -0
  17. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/__init__.py +0 -0
  18. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/advanced_tools/__init__.py +0 -0
  19. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/advanced_tools/decomposition.py +0 -0
  20. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/advanced_tools/denoising.py +0 -0
  21. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/advanced_tools/fdct.py +0 -0
  22. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/basic_tools/__init__.py +0 -0
  23. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/basic_tools/filter.py +0 -0
  24. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/basic_tools/freqattributes.py +0 -0
  25. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/basic_tools/visualization.py +0 -0
  26. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/core/__init__.py +0 -0
  27. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/core/example.pkl +0 -0
  28. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/core/read.py +0 -0
  29. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/daspy/core/write.py +0 -0
  30. {daspy_toolbox-1.1.2 → daspy_toolbox-1.1.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: DASPy-toolbox
3
- Version: 1.1.2
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
@@ -28,6 +28,7 @@ Dynamic: classifier
28
28
  Dynamic: description
29
29
  Dynamic: home-page
30
30
  Dynamic: license
31
+ Dynamic: license-file
31
32
  Dynamic: maintainer
32
33
  Dynamic: maintainer-email
33
34
  Dynamic: requires-dist
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: DASPy-toolbox
3
- Version: 1.1.2
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
@@ -28,6 +28,7 @@ Dynamic: classifier
28
28
  Dynamic: description
29
29
  Dynamic: home-page
30
30
  Dynamic: license
31
+ Dynamic: license-file
31
32
  Dynamic: maintainer
32
33
  Dynamic: maintainer-email
33
34
  Dynamic: requires-dist
@@ -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: 2024.11.18
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
@@ -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(channels, dist, dx):
369
- if len(channels) > 20:
370
- return _equally_spacing_2(channels, dist, dx)
371
- else:
372
- return _equally_spacing_1(channels, dist, dx)
373
-
374
-
375
- def _equally_spacing_1(channels, dist, dx):
376
- nch = len(channels)
377
- residual = np.inf
378
- for i in range(2 ** (nch - 2)):
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
- channels_equal.append(channels[i + 1])
420
- dist_equal.append(d)
421
- i += 1
380
+ index.append(index[k])
381
+ # print(index, residual)
382
+
383
+ return index[-1]
422
384
 
423
- return channels_equal, dist_equal
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:]
416
+
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 = np.zeros(nch - 1)
450
- for i in range(nch - 1):
451
- lon0, lat0 = geometry[i, :2]
452
- lon1, lat1 = geometry[i+1, :2]
453
- d = Geodesic.WGS84.Inverse(lat0, lon0, lat1, lon1)['s12']
454
- if depth_info:
455
- dist[i] = np.sqrt(d**2 + (geometry[i+1, 2] - geometry[i, 2]) ** 2)
456
- else:
457
- dist[i] = d
458
-
459
- channels_equal = [channels[0]]
460
- dist_equal = []
461
- channels_seg = []
462
- dist_seg = []
463
- flag = False
464
- for i in range(1, nch-1):
465
- if dist[i-1] + dist[i] <= dx * 1.5:
466
- channels_seg.append(channels[i-1])
467
- dist_seg.append(dist[i-1])
468
- else:
469
- if len(channels_seg):
470
- channels_seg.extend(channels[i-1:i+1])
471
- dist_seg.append(dist[i-1])
472
- channels_seg, dist_seg = _equally_spacing(channels_seg,
473
- dist_seg, dx)
474
- dist_equal.extend(dist_seg)
475
- channels_equal.extend(channels_seg[1:])
476
- channels_seg = []
477
- dist_seg = []
478
- flag = False
479
- else:
480
- if flag:
481
- channels_equal.append(channels[i-1])
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.6.8
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: 2024.10.25
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', **kwargs):
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
- if method == 'one-bit':
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,6 +1,6 @@
1
1
  # Purpose: Module for handling Collection objects.
2
2
  # Author: Minzhe Hu
3
- # Date: 2025.1.23
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
- timeinfo_format=None, timeinfo_from_basename=True, **kwargs):
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 timeinfo_format: str or (slice, str). Format for extracting start
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.
@@ -90,17 +95,22 @@ class Collection(object):
90
95
  setattr(self, key, metadata[i])
91
96
 
92
97
  if not hasattr(self, 'ftime'):
93
- if isinstance(timeinfo_format, tuple):
94
- timeinfo_slice, timeinfo_format = timeinfo_format
95
- else:
96
- timeinfo_slice = slice(None)
97
98
  if timeinfo_from_basename:
98
- self.ftime = [DASDateTime.strptime(
99
- os.path.basename(f)[timeinfo_slice], timeinfo_format)
100
- for f in self.flist]
99
+ flist_use = [os.path.basename(f) for f in self.flist]
101
100
  else:
101
+ flist_use = self.flist
102
+ if timeinfo_tz is None:
102
103
  self.ftime = [DASDateTime.strptime(f[timeinfo_slice],
103
- timeinfo_format) for f in self.flist]
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]
104
114
 
105
115
  self._sort()
106
116
  if flength is None:
@@ -1,6 +1,6 @@
1
1
  # Purpose: Module for handling DASDateTime objects.
2
2
  # Author: Minzhe Hu
3
- # Date: 2025.2.11
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
 
@@ -1,6 +1,6 @@
1
1
  # Purpose: Module for handling Section objects.
2
2
  # Author: Minzhe Hu
3
- # Date: 2025.2.25
3
+ # Date: 2025.3.10
4
4
  # Email: hmz2018@mail.ustc.edu.cn
5
5
  import warnings
6
6
  import os
@@ -169,6 +169,10 @@ class Section(object):
169
169
  @property
170
170
  def distance(self):
171
171
  return self.nch * self.dx
172
+
173
+ @property
174
+ def channel_distance(self):
175
+ return self.dx * np.arange(self.nch) + self.start_channel
172
176
 
173
177
  @property
174
178
  def end_distance(self):
@@ -497,7 +501,10 @@ class Section(object):
497
501
  :param xlog, ylog: bool. If True, set the x-axis' or y-axis' scale as
498
502
  log.
499
503
  :param xinv, yinv: bool. If True, invert x-axis or y-axis.
500
- :param xaxis, yaxis: bool. Show ticks and labels for x-axis or y-axis.
504
+ :param xlabel, ylabel: bool or str. Whether to plot a label or what
505
+ label to plot for x-axis or y-axis.
506
+ :param xticklabels, yticklabels: bool or sequence of str. Whether to
507
+ plot ticklabels or what ticklabels to plot for x-axis or y-axis.
501
508
  :param colorbar: bool, str or Matplotlib.axes.Axes. Bool means plot
502
509
  colorbar or not. Str means the location of colorbar. Axes means the
503
510
  Axes into which the colorbar will be drawn.
@@ -617,7 +624,7 @@ class Section(object):
617
624
  Normalize for each individual channel using Z-score method.
618
625
 
619
626
  :param method: str. Method for normalization, should be one of 'max',
620
- 'z-score', or 'one-bit'.
627
+ 'z-score', 'MAD' or 'one-bit'.
621
628
  """
622
629
  self.data = normalization(self.data, method=method)
623
630
  if hasattr(self, 'data_type'):
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
 
4
4
  setup(
5
- name='DASPy-toolbox', version='1.1.2',
5
+ name='DASPy-toolbox', version='1.1.3',
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