acoular 25.10__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/tbeamform.py CHANGED
@@ -83,19 +83,19 @@ class BeamformerTime(TimeOut):
83
83
  #: Data source; :class:`~acoular.base.SamplesGenerator` or derived object.
84
84
  source = Instance(SamplesGenerator)
85
85
 
86
- # Instance of :class:`~acoular.fbeamform.SteeringVector` or its derived classes
87
- # that contains information about the steering vector. This is a private trait.
88
- # Do not set this directly, use `steer` trait instead.
86
+ #: Instance of :class:`~acoular.fbeamform.SteeringVector` or its derived classes
87
+ #: that contains information about the steering vector. This is a private trait.
88
+ #: Do not set this directly, use :attr:`steer` trait instead.
89
89
  steer = Instance(SteeringVector, args=())
90
90
 
91
91
  #: Number of channels in output (=number of grid points).
92
92
  num_channels = Property()
93
93
 
94
94
  #: Spatial weighting function.
95
- weights = Map(possible_weights, default_value='none', desc='spatial weighting function')
95
+ weights = Map(possible_weights, default_value='none')
96
96
  # (from timedomain.possible_weights)
97
97
 
98
- # internal identifier
98
+ #: A unique identifier for the beamformer, based on its properties. (read-only)
99
99
  digest = Property(
100
100
  depends_on=['steer.digest', 'source.digest', 'weights'],
101
101
  )
@@ -231,9 +231,9 @@ class BeamformerTimeSq(BeamformerTime):
231
231
  """
232
232
 
233
233
  #: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
234
- r_diag = Bool(True, desc='removal of diagonal')
234
+ r_diag = Bool(True)
235
235
 
236
- # internal identifier
236
+ #: A unique identifier for the beamformer, based on its properties. (read-only)
237
237
  digest = Property(
238
238
  depends_on=['steer.digest', 'source.digest', 'r_diag', 'weights'],
239
239
  )
@@ -275,18 +275,18 @@ class BeamformerTimeTraj(BeamformerTime):
275
275
 
276
276
  #: :class:`~acoular.trajectory.Trajectory` or derived object.
277
277
  #: Start time is assumed to be the same as for the samples.
278
- trajectory = Instance(Trajectory, desc='trajectory of the grid center')
278
+ trajectory = Instance(Trajectory)
279
279
 
280
280
  #: Reference vector, perpendicular to the y-axis of moving grid.
281
- rvec = CArray(dtype=float, shape=(3,), value=np.array((0, 0, 0)), desc='reference vector')
281
+ rvec = CArray(dtype=float, shape=(3,), value=np.array((0, 0, 0)))
282
282
 
283
283
  #: Considering of convective amplification in beamforming formula.
284
- conv_amp = Bool(False, desc='determines if convective amplification of source is considered')
284
+ conv_amp = Bool(False)
285
285
 
286
286
  #: Floating point and integer precision
287
- precision = Enum(64, 32, desc='numeric precision')
287
+ precision = Enum(64, 32)
288
288
 
289
- # internal identifier
289
+ #: A unique identifier for the beamformer, based on its properties. (read-only)
290
290
  digest = Property(
291
291
  depends_on=[
292
292
  'steer.digest',
@@ -325,7 +325,7 @@ class BeamformerTimeTraj(BeamformerTime):
325
325
  tpos = gpos + np.array(g)[:, np.newaxis]
326
326
  yield tpos
327
327
  else:
328
- for g, g1 in zip(trajg, trajg1):
328
+ for g, g1 in zip(trajg, trajg1, strict=True):
329
329
  # grid is both translated and rotated
330
330
  loc = np.array(g) # translation array([0., 0.4, 1.])
331
331
  dx = np.array(g1) # direction vector (new x-axis)
@@ -520,7 +520,7 @@ class BeamformerTimeSqTraj(BeamformerTimeSq, BeamformerTimeTraj):
520
520
  removal for a grid moving along a trajectory.
521
521
  """
522
522
 
523
- # internal identifier
523
+ #: A unique identifier for the beamformer, based on its properties. (read-only)
524
524
  digest = Property(
525
525
  depends_on=[
526
526
  'steer.digest',
@@ -571,16 +571,16 @@ class BeamformerCleant(BeamformerTime):
571
571
  """
572
572
 
573
573
  #: Boolean flag, always False
574
- r_diag = Enum(False, desc='False, as we do not remove autopower in this beamformer')
574
+ r_diag = Enum(False)
575
575
 
576
576
  #: iteration damping factor also referred as loop gain in Cousson et al.
577
577
  #: defaults to 0.6
578
- damp = Range(0.01, 1.0, 0.6, desc='damping factor (loop gain)')
578
+ damp = Range(0.01, 1.0, 0.6)
579
579
 
580
580
  #: max number of iterations
581
- n_iter = Int(100, desc='maximum number of iterations')
581
+ n_iter = Int(100)
582
582
 
583
- # internal identifier
583
+ #: A unique identifier for the beamformer, based on its properties. (read-only)
584
584
  digest = Property(
585
585
  depends_on=['steer.digest', 'source.digest', 'weights', 'damp', 'n_iter'],
586
586
  )
@@ -623,9 +623,9 @@ class BeamformerCleantSq(BeamformerCleant):
623
623
  """
624
624
 
625
625
  #: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
626
- r_diag = Bool(True, desc='removal of diagonal')
626
+ r_diag = Bool(True)
627
627
 
628
- # internal identifier
628
+ #: A unique identifier for the beamformer, based on its properties. (read-only)
629
629
  digest = Property(
630
630
  depends_on=['steer.digest', 'source.digest', 'weights', 'damp', 'n_iter', 'r_diag'],
631
631
  )
@@ -668,9 +668,9 @@ class BeamformerCleantTraj(BeamformerCleant, BeamformerTimeTraj):
668
668
  """
669
669
 
670
670
  #: Floating point and integer precision
671
- precision = Enum(32, 64, desc='numeric precision')
671
+ precision = Enum(32, 64)
672
672
 
673
- # internal identifier
673
+ #: A unique identifier for the beamformer, based on its properties. (read-only)
674
674
  digest = Property(
675
675
  depends_on=[
676
676
  'steer.digest',
@@ -723,9 +723,9 @@ class BeamformerCleantSqTraj(BeamformerCleantTraj, BeamformerTimeSq):
723
723
  """
724
724
 
725
725
  #: Boolean flag, if 'True' (default), the main diagonal is removed before beamforming.
726
- r_diag = Bool(True, desc='removal of diagonal')
726
+ r_diag = Bool(True)
727
727
 
728
- # internal identifier
728
+ #: A unique identifier for the beamformer, based on its properties. (read-only)
729
729
  digest = Property(
730
730
  depends_on=[
731
731
  'steer.digest',
@@ -777,7 +777,7 @@ class IntegratorSectorTime(TimeOut):
777
777
  source = Instance(SamplesGenerator)
778
778
 
779
779
  #: :class:`~acoular.grids.RectGrid` object that provides the grid locations.
780
- grid = Instance(RectGrid, desc='beamforming grid')
780
+ grid = Instance(RectGrid)
781
781
 
782
782
  #: List of sectors in grid
783
783
  sectors = List()
@@ -788,7 +788,7 @@ class IntegratorSectorTime(TimeOut):
788
788
  #: Number of channels in output (= number of sectors).
789
789
  num_channels = Property(depends_on=['sectors'])
790
790
 
791
- # internal identifier
791
+ #: A unique identifier for the integrator, based on its properties. (read-only)
792
792
  digest = Property(
793
793
  depends_on=['sectors', 'clip', 'grid.digest', 'source.digest'],
794
794
  )
acoular/tools/helpers.py CHANGED
@@ -144,7 +144,7 @@ def return_result(source, nmax=-1, num=128):
144
144
 
145
145
  if nmax > 0:
146
146
  nblocks = (nmax - 1) // num + 1
147
- return np.concatenate([res for _, res in zip(range(nblocks), resulter)])[:nmax]
147
+ return np.concatenate([res for _, res in zip(range(nblocks), resulter, strict=True)])[:nmax]
148
148
  return np.concatenate(list(resulter))
149
149
 
150
150
 
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