acoular 25.7__py3-none-any.whl → 26.1__py3-none-any.whl

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.
acoular/tools/helpers.py CHANGED
@@ -17,17 +17,7 @@
17
17
  from pathlib import Path
18
18
  from warnings import warn
19
19
 
20
- from numpy import (
21
- array,
22
- concatenate,
23
- isscalar,
24
- newaxis,
25
- searchsorted,
26
- sum, # noqa A004
27
- where,
28
- zeros_like,
29
- )
30
- from numpy.ma import masked_where
20
+ import numpy as np
31
21
 
32
22
  from acoular.tools.utils import mole_fraction_of_water_vapor
33
23
 
@@ -79,20 +69,20 @@ def synthetic(data, freqs, f, num=3):
79
69
  and used :attr:`FFT block size<acoular.spectra.PowerSpectra.block_size>`.
80
70
 
81
71
  """
82
- if isscalar(f):
72
+ if np.isscalar(f):
83
73
  f = (f,)
84
74
  if num == 0:
85
75
  # single frequency lines
86
76
  res = []
87
77
  for i in f:
88
- ind = searchsorted(freqs, i)
78
+ ind = np.searchsorted(freqs, i)
89
79
  if ind >= len(freqs):
90
80
  warn(
91
81
  f'Queried frequency ({i:g} Hz) not in resolved frequency range. Returning zeros.',
92
82
  Warning,
93
83
  stacklevel=2,
94
84
  )
95
- h = zeros_like(data[0])
85
+ h = np.zeros_like(data[0])
96
86
  else:
97
87
  if freqs[ind] != i:
98
88
  warn(
@@ -110,8 +100,8 @@ def synthetic(data, freqs, f, num=3):
110
100
  for i in f:
111
101
  f1 = i * 2.0 ** (-0.5 / num)
112
102
  f2 = i * 2.0 ** (+0.5 / num)
113
- ind1 = searchsorted(freqs, f1)
114
- ind2 = searchsorted(freqs, f2)
103
+ ind1 = np.searchsorted(freqs, f1)
104
+ ind2 = np.searchsorted(freqs, f2)
115
105
  if ind1 == ind2:
116
106
  warn(
117
107
  f'Queried frequency band ({f1:g} to {f2:g} Hz) does not '
@@ -120,11 +110,11 @@ def synthetic(data, freqs, f, num=3):
120
110
  Warning,
121
111
  stacklevel=2,
122
112
  )
123
- h = zeros_like(data[0])
113
+ h = np.zeros_like(data[0])
124
114
  else:
125
- h = sum(data[ind1:ind2], 0)
115
+ h = np.sum(data[ind1:ind2], 0)
126
116
  res += [h]
127
- return array(res)
117
+ return np.array(res)
128
118
 
129
119
 
130
120
  def return_result(source, nmax=-1, num=128):
@@ -154,8 +144,8 @@ def return_result(source, nmax=-1, num=128):
154
144
 
155
145
  if nmax > 0:
156
146
  nblocks = (nmax - 1) // num + 1
157
- return concatenate([res for _, res in zip(range(nblocks), resulter)])[:nmax]
158
- return concatenate(list(resulter))
147
+ return np.concatenate([res for _, res in zip(range(nblocks), resulter, strict=True)])[:nmax]
148
+ return np.concatenate(list(resulter))
159
149
 
160
150
 
161
151
  def barspectrum(data, fftfreqs, num=3, bar=True, xoffset=0.0):
@@ -203,9 +193,9 @@ def barspectrum(data, fftfreqs, num=3, bar=True, xoffset=0.0):
203
193
  return (0, 0, 0)
204
194
 
205
195
  # preferred center freqs after din en iso 266 for third-octave bands
206
- fcbase = array([31.5, 40, 50, 63, 80, 100, 125, 160, 200, 250])
196
+ fcbase = np.array([31.5, 40, 50, 63, 80, 100, 125, 160, 200, 250])
207
197
  # DIN band center frequencies from 31.5 Hz to 25 kHz
208
- fc = concatenate((fcbase, fcbase * 10.0, fcbase[:] * 100.0))[:: (3 // num)]
198
+ fc = np.concatenate((fcbase, fcbase * 10.0, fcbase[:] * 100.0))[:: (3 // num)]
209
199
 
210
200
  # exponent for band width calculation
211
201
  ep = 1.0 / (2.0 * num)
@@ -215,16 +205,16 @@ def barspectrum(data, fftfreqs, num=3, bar=True, xoffset=0.0):
215
205
  f_low = fftfreqs[1] * 2**ep
216
206
  f_high = fftfreqs[-1] * 2**-ep
217
207
  # get possible index range
218
- i_low = 0 if fc[0] >= f_low else where(fc < f_low)[0][-1]
208
+ i_low = 0 if fc[0] >= f_low else np.where(fc < f_low)[0][-1]
219
209
 
220
- i_high = fc.shape[0] if fc[-1] <= f_high else where(fc > f_high)[0][0]
210
+ i_high = fc.shape[0] if fc[-1] <= f_high else np.where(fc > f_high)[0][0]
221
211
 
222
212
  # synthesize sound pressure values
223
- p = array([synthetic(data, fftfreqs, list(fc[i_low:i_high]), num)])
213
+ p = np.array([synthetic(data, fftfreqs, list(fc[i_low:i_high]), num)])
224
214
 
225
215
  if bar:
226
216
  # upper and lower band borders
227
- flu = concatenate(
217
+ flu = np.concatenate(
228
218
  (
229
219
  fc[i_low : i_low + 1] * 2**-ep,
230
220
  (fc[i_low : i_high - 1] * 2**ep + fc[i_low + 1 : i_high] * 2**-ep) / 2.0,
@@ -232,9 +222,9 @@ def barspectrum(data, fftfreqs, num=3, bar=True, xoffset=0.0):
232
222
  ),
233
223
  )
234
224
  # band borders as coordinates for bar plotting
235
- flulist = 2 ** (2 * xoffset * ep) * (array([1, 1])[:, newaxis] * flu[newaxis, :]).T.reshape(-1)[1:-1]
225
+ flulist = 2 ** (2 * xoffset * ep) * (np.array([1, 1])[:, np.newaxis] * flu[np.newaxis, :]).T.reshape(-1)[1:-1]
236
226
  # sound pressures as list for bar plotting
237
- plist = (array([1, 1])[:, newaxis] * p[newaxis, :]).T.reshape(-1)
227
+ plist = (np.array([1, 1])[:, np.newaxis] * p[np.newaxis, :]).T.reshape(-1)
238
228
  else:
239
229
  flulist = fc[i_low:i_high]
240
230
  plist = p[0, :]
@@ -280,17 +270,19 @@ def bardata(data, fc, num=3, bar=True, xoffset=0.0, masked=-360):
280
270
 
281
271
  if bar:
282
272
  # upper and lower band borders
283
- flu = concatenate((fc[:1] * 2**-ep, (fc[:-1] * 2**ep + fc[1:] * 2**-ep) / 2.0, fc[-1:] * 2**ep))
273
+ flu = np.concatenate((fc[:1] * 2**-ep, (fc[:-1] * 2**ep + fc[1:] * 2**-ep) / 2.0, fc[-1:] * 2**ep))
284
274
  # band borders as coordinates for bar plotting
285
- flulist = 2 ** (xoffset * 1.0 / num) * (array([1, 1])[:, newaxis] * flu[newaxis, :]).T.reshape(-1)[1:-1]
275
+ flulist = (
276
+ 2 ** (xoffset * 1.0 / num) * (np.array([1, 1])[:, np.newaxis] * flu[np.newaxis, :]).T.reshape(-1)[1:-1]
277
+ )
286
278
  # sound pressures as list for bar plotting
287
- plist = (array([1, 1])[:, newaxis] * data[newaxis, :]).T.reshape(-1)
279
+ plist = (np.array([1, 1])[:, np.newaxis] * data[np.newaxis, :]).T.reshape(-1)
288
280
  else:
289
281
  flulist = fc
290
282
  plist = data
291
283
  # print(flulist.shape, plist.shape)
292
284
  if masked > -360:
293
- plist = masked_where(plist <= masked, plist)
285
+ plist = np.ma.masked_where(plist <= masked, plist)
294
286
  return (flulist, plist)
295
287
 
296
288
 
acoular/tools/metrics.py CHANGED
@@ -11,12 +11,7 @@
11
11
 
12
12
  from copy import copy
13
13
 
14
- from numpy import (
15
- empty,
16
- inf,
17
- minimum,
18
- ones,
19
- )
14
+ import numpy as np
20
15
  from scipy.spatial.distance import cdist
21
16
  from traits.api import Bool, CArray, HasStrictTraits, Instance, Property
22
17
 
@@ -82,13 +77,13 @@ class MetricEvaluator(HasStrictTraits):
82
77
 
83
78
  def _get_sector_radii(self):
84
79
  ns = self.target_data.shape[1]
85
- radii = ones(ns) * self.sector.r
80
+ radii = np.ones(ns) * self.sector.r
86
81
  if self.adaptive_sector_size:
87
82
  locs = self.target_grid.pos.T
88
83
  intersrcdist = cdist(locs, locs)
89
- intersrcdist[intersrcdist == 0] = inf
84
+ intersrcdist[intersrcdist == 0] = np.inf
90
85
  intersrcdist = intersrcdist.min(0) / 2
91
- radii = minimum(radii, intersrcdist)
86
+ radii = np.minimum(radii, intersrcdist)
92
87
  return radii
93
88
 
94
89
  def _get_sectors(self):
@@ -115,7 +110,7 @@ class MetricEvaluator(HasStrictTraits):
115
110
 
116
111
  """
117
112
  sectors = self.sectors
118
- results = empty(shape=self.target_data.shape)
113
+ results = np.empty(shape=self.target_data.shape)
119
114
  for f in range(self.target_data.shape[0]):
120
115
  data = self.data[f]
121
116
  for i in range(self.target_data.shape[1]):
acoular/tools/utils.py CHANGED
@@ -6,6 +6,7 @@
6
6
  get_file_basename
7
7
  find_basename
8
8
  mole_fraction_of_water_vapor
9
+ Polygon
9
10
  """
10
11
 
11
12
  from pathlib import Path
@@ -13,6 +14,173 @@ from pathlib import Path
13
14
  import numpy as np
14
15
 
15
16
 
17
+ def _det(xvert, yvert):
18
+ xvert = np.asarray(xvert, dtype=float)
19
+ yvert = np.asarray(yvert, dtype=float)
20
+ x_prev = np.concatenate(([xvert[-1]], xvert[:-1]))
21
+ y_prev = np.concatenate(([yvert[-1]], yvert[:-1]))
22
+ return np.sum(yvert * x_prev - xvert * y_prev, axis=0)
23
+
24
+
25
+ class Polygon:
26
+ """
27
+ Create an object representing a general polygon in a 2D plane.
28
+
29
+ This class allows defining a polygon by specifying the coordinates of its vertices and provides
30
+ methods for checking whether a set of points lies inside the polygon, or if a point is closer to
31
+ a side or vertex of the polygon.
32
+
33
+ Parameters
34
+ ----------
35
+ x : array_like
36
+ Array of x-coordinates of the vertices that define the polygon. These coordinates should
37
+ form a closed shape (i.e., the last point should be the same as the first point).
38
+
39
+ y : array_like
40
+ Array of y-coordinates of the vertices that define the polygon. These coordinates should
41
+ correspond to the x-coordinates, forming a closed shape.
42
+
43
+ Attributes
44
+ ----------
45
+ x : :class:`numpy.ndarray`
46
+ Array of x-coordinates of the polygon vertices.
47
+
48
+ y : :class:`numpy.ndarray`
49
+ Array of y-coordinates of the polygon vertices.
50
+ """
51
+
52
+ def __init__(self, x, y):
53
+ if len(x) != len(y):
54
+ msg = 'x and y must be equally sized.'
55
+ raise IndexError(msg)
56
+ self.x = np.asarray(x, dtype=float)
57
+ self.y = np.asarray(y, dtype=float)
58
+ # Closes the polygon if it were open
59
+ x1, y1 = x[0], y[0]
60
+ xn, yn = x[-1], y[-1]
61
+ if x1 != xn or y1 != yn:
62
+ self.x = np.concatenate((self.x, [x1]))
63
+ self.y = np.concatenate((self.y, [y1]))
64
+ # Anti-clockwise coordinates
65
+ if _det(self.x, self.y) < 0:
66
+ self.x = self.x[::-1]
67
+ self.y = self.y[::-1]
68
+
69
+ def is_inside(self, xpoint, ypoint, smalld=1e-12):
70
+ """
71
+ Check if a point or set of points are inside the polygon.
72
+
73
+ Parameters
74
+ ----------
75
+ xpoint : :class:`float` or array_like
76
+ Array of x-coordinates of the points to be tested.
77
+
78
+ ypoint : :class:`float` or array_like
79
+ Array of y-coordinates of the points to be tested.
80
+
81
+ smalld : :class:`float`, optional
82
+ Tolerance used for floating point comparisons when checking if a point is exactly on a
83
+ polygon's edge. The default value is ``1e-12``.
84
+
85
+ Returns
86
+ -------
87
+ :class:`float` or array_like
88
+ The distance from the point to the nearest point on the polygon. The values returned
89
+ have the following meanings:
90
+ - ``mindst < 0``: Point is outside the polygon.
91
+ - ``mindst = 0``: Point is on an edge of the polygon.
92
+ - ``mindst > 0``: Point is inside the polygon.
93
+
94
+ Notes
95
+ -----
96
+ The method uses an improved algorithm based on Nordbeck and Rydstedt for determining
97
+ whether a point is inside a polygon :cite:`SLOAN198545`.
98
+ """
99
+ xpoint = np.asarray(xpoint, dtype=float)
100
+ ypoint = np.asarray(ypoint, dtype=float)
101
+ # Scalar to array
102
+ if xpoint.shape == ():
103
+ xpoint = np.array([xpoint], dtype=float)
104
+ ypoint = np.array([ypoint], dtype=float)
105
+ scalar = True
106
+ else:
107
+ scalar = False
108
+ # Check consistency
109
+ if xpoint.shape != ypoint.shape:
110
+ msg = 'x and y have different shapes'
111
+ raise IndexError(msg)
112
+ # If snear = True: Dist to nearest side < nearest vertex
113
+ # If snear = False: Dist to nearest vertex < nearest side
114
+ snear = np.ma.masked_all(xpoint.shape, dtype=bool)
115
+ # Initialize arrays
116
+ mindst = np.ones_like(xpoint, dtype=float) * np.inf
117
+ j = np.ma.masked_all(xpoint.shape, dtype=int)
118
+ x = self.x
119
+ y = self.y
120
+ n = len(x) - 1 # Number of sides/vertices defining the polygon
121
+ # Loop over each side defining polygon
122
+ for i in range(n):
123
+ d = np.ones_like(xpoint, dtype=float) * np.inf
124
+ # Start of side has coords (x1, y1)
125
+ # End of side has coords (x2, y2)
126
+ # Point has coords (xpoint, ypoint)
127
+ x1 = x[i]
128
+ y1 = y[i]
129
+ x21 = x[i + 1] - x1
130
+ y21 = y[i + 1] - y1
131
+ x1p = x1 - xpoint
132
+ y1p = y1 - ypoint
133
+ # Points on infinite line defined by
134
+ # x = x1 + t * (x1 - x2)
135
+ # y = y1 + t * (y1 - y2)
136
+ # where
137
+ # t = 0 at (x1, y1)
138
+ # t = 1 at (x2, y2)
139
+ # Find where normal passing through (xpoint, ypoint) intersects
140
+ # infinite line
141
+ t = -(x1p * x21 + y1p * y21) / (x21**2 + y21**2)
142
+ tlt0 = t < 0
143
+ tle1 = (t >= 0) & (t <= 1)
144
+ # Normal intersects side
145
+ d[tle1] = (x1p[tle1] + t[tle1] * x21) ** 2 + (y1p[tle1] + t[tle1] * y21) ** 2
146
+ # Normal does not intersects side
147
+ # Point is closest to vertex (x1, y1)
148
+ # Compute square of distance to this vertex
149
+ d[tlt0] = x1p[tlt0] ** 2 + y1p[tlt0] ** 2
150
+ # Store distances
151
+ mask = d < mindst
152
+ mindst[mask] = d[mask]
153
+ j[mask] = i
154
+ # Point is closer to (x1, y1) than any other vertex or side
155
+ snear[mask & tlt0] = False
156
+ # Point is closer to this side than to any other side or vertex
157
+ snear[mask & tle1] = True
158
+ if np.ma.count(snear) != snear.size:
159
+ msg = 'Error computing distances'
160
+ raise IndexError(msg)
161
+ mindst **= 0.5
162
+ # Point is closer to its nearest vertex than its nearest side, check if
163
+ # nearest vertex is concave.
164
+ # If the nearest vertex is concave then point is inside the polygon,
165
+ # else the point is outside the polygon.
166
+ jo = j.copy()
167
+ jo[j == 0] -= 1
168
+ area = _det([x[j + 1], x[j], x[jo - 1]], [y[j + 1], y[j], y[jo - 1]])
169
+ mindst[~snear] = np.copysign(mindst, area)[~snear]
170
+ # Point is closer to its nearest side than to its nearest vertex, check
171
+ # if point is to left or right of this side.
172
+ # If point is to left of side it is inside polygon, else point is
173
+ # outside polygon.
174
+ area = _det([x[j], x[j + 1], xpoint], [y[j], y[j + 1], ypoint])
175
+ mindst[snear] = np.copysign(mindst, area)[snear]
176
+ # Point is on side of polygon
177
+ mindst[np.fabs(mindst) < smalld] = 0
178
+ # If input values were scalar then the output should be too
179
+ if scalar:
180
+ mindst = float(mindst[0])
181
+ return mindst
182
+
183
+
16
184
  def get_file_basename(file, alternative_basename='void'):
17
185
  """Return the basename of the file.
18
186