Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/parstack.py: 100%
65 statements
« prev ^ index » next coverage.py v6.5.0, created at 2024-03-07 11:54 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2024-03-07 11:54 +0000
1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6'''
7Fast weight-delay-and-sum implementation for seismic array processing and
8migration.
9'''
11import numpy as num
13from . import parstack_ext
15try:
16 range = xrange
17except NameError:
18 pass
20import multiprocessing
22nparallel = multiprocessing.cpu_count()
25def parstack(arrays, offsets, shifts, weights, method,
26 lengthout=-1,
27 offsetout=0,
28 result=None,
29 nparallel=nparallel,
30 dtype=num.float64,
31 impl='openmp'):
32 narrays = offsets.size
33 assert len(arrays) == narrays
34 nshifts = shifts.size // narrays
35 assert shifts.shape == (nshifts, narrays)
36 shifts = num.reshape(shifts, (nshifts*narrays))
37 assert weights.shape == (nshifts, narrays)
38 weights = num.reshape(weights, (nshifts*narrays))
40 weights = weights.astype(dtype, copy=False)
41 arrays = [arr.astype(dtype, copy=False) for arr in arrays]
43 if impl == 'openmp':
44 parstack_impl = parstack_ext.parstack
45 elif impl == 'numpy':
46 parstack_impl = parstack_numpy
48 result, offset = parstack_impl(
49 arrays, offsets, shifts, weights, method,
50 lengthout, offsetout, result, nparallel)
52 if method == 0:
53 nsamps = result.size // nshifts
54 result = result.reshape((nshifts, nsamps))
56 return result, offset
59def get_offset_and_length(arrays, offsets, shifts):
60 narrays = offsets.size
61 nshifts = shifts.size // narrays
62 if shifts.ndim == 2:
63 shifts = num.reshape(shifts, (nshifts*narrays))
65 lengths = num.array([a.size for a in arrays], dtype=int)
66 imin = offsets[0] + shifts[0]
67 imax = imin + lengths[0]
68 for iarray in range(len(arrays)):
69 istarts = offsets[iarray] + shifts[iarray::narrays]
70 iends = istarts + lengths[iarray]
71 imin = min(imin, num.amin(istarts))
72 imax = max(imax, num.amax(iends))
74 return imin, imax - imin
77def parstack_numpy(
78 arrays,
79 offsets,
80 shifts,
81 weights,
82 method,
83 lengthout,
84 offsetout,
85 result,
86 nparallel):
88 # nparallel is ignored here
90 narrays = offsets.size
92 lengths = num.array([a.size for a in arrays], dtype=int)
93 if lengthout < 0:
94 imin, nsamp = get_offset_and_length(arrays, offsets, shifts)
95 else:
96 nsamp = lengthout
97 imin = offsetout
99 nshifts = shifts.size // narrays
100 result = num.zeros(nsamp*nshifts, dtype=float)
102 for ishift in range(nshifts):
103 for iarray in range(narrays):
104 istart = offsets[iarray] + shifts[ishift*narrays + iarray]
105 weight = weights[ishift*narrays + iarray]
106 istart_r = ishift*nsamp + istart - imin
107 jstart = max(0, imin - istart)
108 jstop = max(jstart, min(nsamp - istart + imin, lengths[iarray]))
109 result[istart_r+jstart:istart_r+jstop] += \
110 arrays[iarray][jstart:jstop] * weight
112 if method == 0:
113 return result, imin
114 elif method == 1:
115 return num.amax(result.reshape((nshifts, nsamp)), axis=1), imin
118def argmax(a, nparallel=1):
119 '''
120 Same as numpys' argmax for 2 dimensional arrays along axis 0
121 but more memory efficient and twice as fast.
122 '''
124 return parstack_ext.argmax(a, nparallel)