acoular 23.11__py3-none-any.whl → 24.5__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.
Files changed (137) hide show
  1. acoular/__init__.py +118 -50
  2. acoular/calib.py +29 -38
  3. acoular/configuration.py +116 -73
  4. acoular/demo/__init__.py +10 -4
  5. acoular/demo/acoular_demo.py +78 -53
  6. acoular/environments.py +265 -262
  7. acoular/fastFuncs.py +361 -191
  8. acoular/fbeamform.py +1478 -1407
  9. acoular/grids.py +501 -545
  10. acoular/h5cache.py +50 -59
  11. acoular/h5files.py +154 -137
  12. acoular/internal.py +10 -11
  13. acoular/microphones.py +57 -53
  14. acoular/sdinput.py +47 -52
  15. acoular/signals.py +167 -179
  16. acoular/sources.py +818 -693
  17. acoular/spectra.py +349 -359
  18. acoular/tbeamform.py +414 -413
  19. acoular/tfastfuncs.py +178 -101
  20. acoular/tools/__init__.py +25 -0
  21. acoular/tools/aiaa.py +186 -0
  22. acoular/tools/helpers.py +189 -0
  23. acoular/tools/metrics.py +165 -0
  24. acoular/tprocess.py +1201 -1143
  25. acoular/traitsviews.py +513 -501
  26. acoular/trajectory.py +50 -52
  27. acoular/version.py +5 -6
  28. acoular/xml/minidsp_uma-16.xml +20 -0
  29. acoular/xml/{minidsp_uma16.xml → minidsp_uma-16_mirrored.xml} +3 -0
  30. {acoular-23.11.dist-info → acoular-24.5.dist-info}/METADATA +47 -40
  31. acoular-24.5.dist-info/RECORD +50 -0
  32. {acoular-23.11.dist-info → acoular-24.5.dist-info}/WHEEL +1 -1
  33. acoular-24.5.dist-info/licenses/LICENSE +28 -0
  34. acoular/fileimport.py +0 -380
  35. acoular/nidaqimport.py +0 -273
  36. acoular/tests/reference_data/BeamformerBase.npy +0 -0
  37. acoular/tests/reference_data/BeamformerBaseFalse1.npy +0 -0
  38. acoular/tests/reference_data/BeamformerBaseFalse2.npy +0 -0
  39. acoular/tests/reference_data/BeamformerBaseFalse3.npy +0 -0
  40. acoular/tests/reference_data/BeamformerBaseFalse4.npy +0 -0
  41. acoular/tests/reference_data/BeamformerBaseTrue1.npy +0 -0
  42. acoular/tests/reference_data/BeamformerBaseTrue2.npy +0 -0
  43. acoular/tests/reference_data/BeamformerBaseTrue3.npy +0 -0
  44. acoular/tests/reference_data/BeamformerBaseTrue4.npy +0 -0
  45. acoular/tests/reference_data/BeamformerCMF.npy +0 -0
  46. acoular/tests/reference_data/BeamformerCapon.npy +0 -0
  47. acoular/tests/reference_data/BeamformerClean.npy +0 -0
  48. acoular/tests/reference_data/BeamformerCleansc.npy +0 -0
  49. acoular/tests/reference_data/BeamformerCleant.npy +0 -0
  50. acoular/tests/reference_data/BeamformerCleantSq.npy +0 -0
  51. acoular/tests/reference_data/BeamformerCleantSqTraj.npy +0 -0
  52. acoular/tests/reference_data/BeamformerCleantTraj.npy +0 -0
  53. acoular/tests/reference_data/BeamformerDamas.npy +0 -0
  54. acoular/tests/reference_data/BeamformerDamasPlus.npy +0 -0
  55. acoular/tests/reference_data/BeamformerEig.npy +0 -0
  56. acoular/tests/reference_data/BeamformerEigFalse1.npy +0 -0
  57. acoular/tests/reference_data/BeamformerEigFalse2.npy +0 -0
  58. acoular/tests/reference_data/BeamformerEigFalse3.npy +0 -0
  59. acoular/tests/reference_data/BeamformerEigFalse4.npy +0 -0
  60. acoular/tests/reference_data/BeamformerEigTrue1.npy +0 -0
  61. acoular/tests/reference_data/BeamformerEigTrue2.npy +0 -0
  62. acoular/tests/reference_data/BeamformerEigTrue3.npy +0 -0
  63. acoular/tests/reference_data/BeamformerEigTrue4.npy +0 -0
  64. acoular/tests/reference_data/BeamformerFunctional.npy +0 -0
  65. acoular/tests/reference_data/BeamformerGIB.npy +0 -0
  66. acoular/tests/reference_data/BeamformerGridlessOrth.npy +0 -0
  67. acoular/tests/reference_data/BeamformerMusic.npy +0 -0
  68. acoular/tests/reference_data/BeamformerOrth.npy +0 -0
  69. acoular/tests/reference_data/BeamformerTime.npy +0 -0
  70. acoular/tests/reference_data/BeamformerTimeSq.npy +0 -0
  71. acoular/tests/reference_data/BeamformerTimeSqTraj.npy +0 -0
  72. acoular/tests/reference_data/BeamformerTimeTraj.npy +0 -0
  73. acoular/tests/reference_data/Environment.npy +0 -0
  74. acoular/tests/reference_data/Example1_numerical_values_testsum.h5 +0 -0
  75. acoular/tests/reference_data/FiltFiltOctave__.npy +0 -0
  76. acoular/tests/reference_data/FiltFiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  77. acoular/tests/reference_data/FiltFreqWeight_weight_A_.npy +0 -0
  78. acoular/tests/reference_data/FiltFreqWeight_weight_C_.npy +0 -0
  79. acoular/tests/reference_data/FiltFreqWeight_weight_Z_.npy +0 -0
  80. acoular/tests/reference_data/FiltOctave__.npy +0 -0
  81. acoular/tests/reference_data/FiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  82. acoular/tests/reference_data/Filter__.npy +0 -0
  83. acoular/tests/reference_data/GeneralFlowEnvironment.npy +0 -0
  84. acoular/tests/reference_data/OctaveFilterBank__.npy +0 -0
  85. acoular/tests/reference_data/OpenJet.npy +0 -0
  86. acoular/tests/reference_data/PointSource.npy +0 -0
  87. acoular/tests/reference_data/PowerSpectra_csm.npy +0 -0
  88. acoular/tests/reference_data/PowerSpectra_ev.npy +0 -0
  89. acoular/tests/reference_data/RotatingFlow.npy +0 -0
  90. acoular/tests/reference_data/SlotJet.npy +0 -0
  91. acoular/tests/reference_data/TimeAverage__.npy +0 -0
  92. acoular/tests/reference_data/TimeCumAverage__.npy +0 -0
  93. acoular/tests/reference_data/TimeExpAverage_weight_F_.npy +0 -0
  94. acoular/tests/reference_data/TimeExpAverage_weight_I_.npy +0 -0
  95. acoular/tests/reference_data/TimeExpAverage_weight_S_.npy +0 -0
  96. acoular/tests/reference_data/TimeInOut__.npy +0 -0
  97. acoular/tests/reference_data/TimePower__.npy +0 -0
  98. acoular/tests/reference_data/TimeReverse__.npy +0 -0
  99. acoular/tests/reference_data/UniformFlowEnvironment.npy +0 -0
  100. acoular/tests/reference_data/beamformer_traj_time_data.h5 +0 -0
  101. acoular/tests/run_tests.sh +0 -18
  102. acoular/tests/run_tests_osx.sh +0 -16
  103. acoular/tests/test.npy +0 -0
  104. acoular/tests/test_beamformer_results.py +0 -204
  105. acoular/tests/test_classes.py +0 -60
  106. acoular/tests/test_digest.py +0 -125
  107. acoular/tests/test_environments.py +0 -73
  108. acoular/tests/test_example1.py +0 -124
  109. acoular/tests/test_grid.py +0 -92
  110. acoular/tests/test_integrate.py +0 -102
  111. acoular/tests/test_signals.py +0 -60
  112. acoular/tests/test_sources.py +0 -65
  113. acoular/tests/test_spectra.py +0 -38
  114. acoular/tests/test_timecache.py +0 -35
  115. acoular/tests/test_tprocess.py +0 -90
  116. acoular/tests/test_traj_beamformer_results.py +0 -164
  117. acoular/tests/unsupported/SpeedComparison/OvernightTestcasesBeamformer_nMics32_nGridPoints100_nFreqs4_nTrials10.png +0 -0
  118. acoular/tests/unsupported/SpeedComparison/cythonBeamformer.pyx +0 -237
  119. acoular/tests/unsupported/SpeedComparison/mainForCython.py +0 -103
  120. acoular/tests/unsupported/SpeedComparison/mainForParallelJit.py +0 -143
  121. acoular/tests/unsupported/SpeedComparison/setupCythonOpenMP.py +0 -63
  122. acoular/tests/unsupported/SpeedComparison/sharedFunctions.py +0 -153
  123. acoular/tests/unsupported/SpeedComparison/timeOverNMics_AllImportantMethods.png +0 -0
  124. acoular/tests/unsupported/SpeedComparison/timeOverNMics_faverage.png +0 -0
  125. acoular/tests/unsupported/SpeedComparison/vglOptimierungFAverage.py +0 -204
  126. acoular/tests/unsupported/SpeedComparison/vglOptimierungGaussSeidel.py +0 -182
  127. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAMFULL_INVERSE.py +0 -764
  128. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAM_OS.py +0 -231
  129. acoular/tests/unsupported/SpeedComparison/whatsFastestWayFor_absASquared.py +0 -48
  130. acoular/tests/unsupported/functionalBeamformer.py +0 -123
  131. acoular/tests/unsupported/precisionTest.py +0 -153
  132. acoular/tests/unsupported/validationOfBeamformerFuncsPOSTAcoularIntegration.py +0 -254
  133. acoular/tests/unsupported/validationOfBeamformerFuncsPREeAcoularIntegration.py +0 -531
  134. acoular/tools.py +0 -418
  135. acoular-23.11.dist-info/RECORD +0 -146
  136. acoular-23.11.dist-info/licenses/LICENSE +0 -29
  137. {acoular-23.11.dist-info → acoular-24.5.dist-info}/licenses/AUTHORS.rst +0 -0
acoular/environments.py CHANGED
@@ -1,8 +1,6 @@
1
- # -*- coding: utf-8 -*-
2
- #pylint: disable-msg=E0611, E1103, C0103, R0901, R0902, R0903, R0904, W0232
3
- #------------------------------------------------------------------------------
1
+ # ------------------------------------------------------------------------------
4
2
  # Copyright (c) Acoular Development Team.
5
- #------------------------------------------------------------------------------
3
+ # ------------------------------------------------------------------------------
6
4
  """Implements acoustic environments with and without flow.
7
5
 
8
6
  .. autosummary::
@@ -17,56 +15,81 @@
17
15
  SlotJet
18
16
 
19
17
  """
18
+
20
19
  import numba as nb
21
- from numpy import array, isscalar, float32, float64, newaxis, \
22
- sqrt, arange, pi, exp, sin, cos, arccos, zeros_like, empty, dot, hstack, \
23
- vstack, identity, cross, sign, arctan2, matmul, sum, ascontiguousarray
20
+ from numpy import (
21
+ arange,
22
+ arccos,
23
+ arctan2,
24
+ array,
25
+ ascontiguousarray,
26
+ cos,
27
+ cross,
28
+ dot,
29
+ empty,
30
+ exp,
31
+ float32,
32
+ float64,
33
+ hstack,
34
+ identity,
35
+ isscalar,
36
+ matmul,
37
+ newaxis,
38
+ pi,
39
+ sign,
40
+ sin,
41
+ sqrt,
42
+ sum,
43
+ vstack,
44
+ zeros_like,
45
+ )
24
46
  from numpy.linalg.linalg import norm
25
47
  from scipy.integrate import ode
26
48
  from scipy.interpolate import LinearNDInterpolator
27
49
  from scipy.spatial import ConvexHull
28
- from traits.api import HasPrivateTraits, Float, Property, Int, \
29
- CArray, cached_property, Trait, Dict
50
+ from traits.api import CArray, Dict, Float, HasPrivateTraits, Int, Property, Trait, cached_property
30
51
 
31
52
  from .internal import digest
32
53
 
33
- f64ro = nb.types.Array(nb.types.float64,2,'C',readonly=True)
34
- f32ro = nb.types.Array(nb.types.float32,2,'C',readonly=True)
54
+ f64ro = nb.types.Array(nb.types.float64, 2, 'C', readonly=True)
55
+ f32ro = nb.types.Array(nb.types.float32, 2, 'C', readonly=True)
56
+
35
57
 
36
- @nb.njit([(f64ro, f64ro), (f64ro, f32ro), (f32ro, f64ro),(f32ro, f32ro)],
37
- cache=True, fastmath=True)
38
- def dist_mat(gpos,mpos):
39
- """computes distance matrix, accelerated with numba
58
+ @nb.njit([(f64ro, f64ro), (f64ro, f32ro), (f32ro, f64ro), (f32ro, f32ro)], cache=True, fastmath=True)
59
+ def dist_mat(gpos, mpos):
60
+ """Computes distance matrix, accelerated with numba.
40
61
 
41
62
  Args:
63
+ ----
42
64
  gpos (3,N)
43
65
  mpos (3,M)
44
66
 
45
- Returns:
67
+ Returns
68
+ -------
46
69
  (N,M) distance matrix
47
- """
48
- _,M = mpos.shape
49
- _,N = gpos.shape
50
- rm = empty((N,M),dtype=gpos.dtype)
51
- TWO = rm.dtype.type(2.0) # make sure to have a float32 or float 64 literal
70
+
71
+ """
72
+ _, M = mpos.shape
73
+ _, N = gpos.shape
74
+ rm = empty((N, M), dtype=gpos.dtype)
75
+ TWO = rm.dtype.type(2.0) # make sure to have a float32 or float 64 literal
52
76
  m0 = mpos[0]
53
77
  m1 = mpos[1]
54
78
  m2 = mpos[2]
55
79
  for n in range(N):
56
- g0 = gpos[0,n]
57
- g1 = gpos[1,n]
58
- g2 = gpos[2,n]
80
+ g0 = gpos[0, n]
81
+ g1 = gpos[1, n]
82
+ g2 = gpos[2, n]
59
83
  for m in range(M):
60
- rm[n,m] = sqrt((g0 - m0[m])**TWO + (g1 - m1[m])**TWO + (g2 - m2[m])**TWO)
84
+ rm[n, m] = sqrt((g0 - m0[m]) ** TWO + (g1 - m1[m]) ** TWO + (g2 - m2[m]) ** TWO)
61
85
  return rm
62
86
 
63
87
 
64
- def cartToCyl(x, Q=identity(3)):
65
- """
66
- Returns the cylindrical coordinate representation of a input position
88
+ def cartToCyl(x, Q=None):
89
+ """Returns the cylindrical coordinate representation of a input position
67
90
  which was before transformed into a modified cartesian coordinate, which
68
91
  has flow into positive z direction.
69
-
92
+
70
93
  Parameters
71
94
  ----------
72
95
  x : float[3, nPoints]
@@ -75,80 +98,78 @@ def cartToCyl(x, Q=identity(3)):
75
98
  Orthogonal transformation matrix. If provided, the pos vectors are
76
99
  transformed via posiMod = Q * x, before transforming those modified
77
100
  coordinates into cylindrical ones. Default is identity matrix.
78
-
101
+
79
102
  Returns
80
103
  -------
81
104
  cylCoord : [3, nPoints]
82
105
  cylindrical representation of those n points with (phi, r, z)
106
+
83
107
  """
84
- if not (Q == identity(3)).all():
108
+ Q = identity(3) if Q is None else Q
109
+ if not (Q == identity(3)).all(): # noqa: SIM300
85
110
  x = matmul(Q, x) # modified position vector
86
- cylCoord = array([arctan2(x[1], x[0]), sqrt(x[0]**2 + x[1]**2), x[2]])
87
- return cylCoord
111
+ return array([arctan2(x[1], x[0]), sqrt(x[0] ** 2 + x[1] ** 2), x[2]])
88
112
 
89
113
 
90
- def cylToCart(x, Q=identity(3)):
91
- """
92
- Returns the cartesian coordinate representation of a input position
93
- which was before transformed into a cylindrical coordinate, which
94
- has flow into positive z direction.
95
-
96
- Parameters
97
- ----------
98
- x : float[3, nPoints]
99
- cylindrical representation of those n points with (phi, r, z)
100
- cartesian coordinates of n points
101
-
102
- Q : float[3,3]
103
- Orthogonal transformation matrix. If provided, the pos vectors are
104
- transformed via posiMod = Q * x, before transforming those modified
105
- coordinates into cylindrical ones. Default is identity matrix.
106
-
107
-
108
- Returns
109
- -------
110
- CartCoord : [3, nPoints]
114
+ def cylToCart(x, Q=None):
115
+ """Returns the cartesian coordinate representation of a input position
116
+ which was before transformed into a cylindrical coordinate, which
117
+ has flow into positive z direction.
118
+
119
+ Parameters
120
+ ----------
121
+ x : float[3, nPoints]
122
+ cylindrical representation of those n points with (phi, r, z)
111
123
  cartesian coordinates of n points
112
-
113
- """
114
- if not (Q == identity(3)).all():
115
- x = matmul(Q, x) # modified position vector
116
- CartCoord = array([x[1]*sin(x[0]),x[1]*cos(x[0]) , x[2]])
117
- return CartCoord
124
+
125
+ Q : float[3,3]
126
+ Orthogonal transformation matrix. If provided, the pos vectors are
127
+ transformed via posiMod = Q * x, before transforming those modified
128
+ coordinates into cylindrical ones. Default is identity matrix.
118
129
 
119
130
 
120
- class Environment( HasPrivateTraits ):
131
+ Returns
132
+ -------
133
+ CartCoord : [3, nPoints]
134
+ cartesian coordinates of n points
135
+
121
136
  """
122
- A simple acoustic environment without flow.
137
+ Q = identity(3) if Q is None else Q
138
+ if not (Q == identity(3)).all(): # noqa: SIM300
139
+ x = matmul(Q, x) # modified position vector
140
+ return array([x[1] * sin(x[0]), x[1] * cos(x[0]), x[2]])
141
+
142
+
143
+ class Environment(HasPrivateTraits):
144
+ """A simple acoustic environment without flow.
123
145
 
124
146
  This class provides the facilities to calculate the travel time (distances)
125
147
  between grid point locations and microphone locations.
126
148
  """
149
+
127
150
  # internal identifier
128
151
  digest = Property(
129
- depends_on=['c'],
130
- )
152
+ depends_on=['c'],
153
+ )
131
154
 
132
155
  #: The speed of sound, defaults to 343 m/s
133
- c = Float(343.,
134
- desc="speed of sound")
156
+ c = Float(343.0, desc='speed of sound')
135
157
 
136
158
  #: The region of interest (ROI), not needed for most types of environment
137
- roi = Trait(None,(None,CArray))
159
+ roi = Trait(None, (None, CArray))
138
160
 
139
- def _get_digest( self ):
140
- return digest( self )
161
+ def _get_digest(self):
162
+ return digest(self)
141
163
 
142
- def _r( self, gpos, mpos=0.0):
143
- """
144
- Calculates distances between grid point locations and microphone
164
+ def _r(self, gpos, mpos=0.0):
165
+ """Calculates distances between grid point locations and microphone
145
166
  locations or the origin. Functionality may change in the future.
146
167
 
147
168
  Parameters
148
169
  ----------
149
170
  gpos : array of floats of shape (3, N)
150
171
  The locations of points in the beamforming map grid in 3D cartesian
151
- co-ordinates.
172
+ co-ordinates.
152
173
  mpos : array of floats of shape (3, M), optional
153
174
  The locations of microphones in 3D cartesian co-ordinates. If not
154
175
  given, then only one microphone at the origin (0, 0, 0) is
@@ -157,48 +178,47 @@ class Environment( HasPrivateTraits ):
157
178
  Returns
158
179
  -------
159
180
  r : array of floats
160
- The distances in a twodimensional (N, M) array of floats. If M==1,
181
+ The distances in a twodimensional (N, M) array of floats. If M==1,
161
182
  then only a one-dimensional array is returned.
183
+
162
184
  """
163
185
  if isscalar(mpos):
164
- mpos = array((0, 0, 0), dtype = float64)[:, newaxis]
165
- rm = dist_mat(ascontiguousarray(gpos),ascontiguousarray(mpos))
166
- # mpos = mpos[:, newaxis, :]
167
- # rmv = gpos[:, :, newaxis]-mpos
168
- # rm = sum(rmv*rmv, 0)**0.5
186
+ mpos = array((0, 0, 0), dtype=float64)[:, newaxis]
187
+ rm = dist_mat(ascontiguousarray(gpos), ascontiguousarray(mpos))
188
+ # mpos = mpos[:, newaxis, :]
189
+ # rmv = gpos[:, :, newaxis]-mpos
190
+ # rm = sum(rmv*rmv, 0)**0.5
169
191
  if rm.shape[1] == 1:
170
192
  rm = rm[:, 0]
171
193
  return rm
172
194
 
173
- class UniformFlowEnvironment( Environment):
174
- """
175
- An acoustic environment with uniform flow.
195
+
196
+ class UniformFlowEnvironment(Environment):
197
+ """An acoustic environment with uniform flow.
176
198
 
177
199
  This class provides the facilities to calculate the travel time (distances)
178
200
  between grid point locations and microphone locations in a uniform flow
179
201
  field.
180
202
  """
203
+
181
204
  #: The Mach number, defaults to 0.
182
- ma = Float(0.0,
183
- desc="flow mach number")
205
+ ma = Float(0.0, desc='flow mach number')
184
206
 
185
207
  #: The unit vector that gives the direction of the flow, defaults to
186
208
  #: flow in x-direction.
187
- fdv = CArray( dtype=float64, shape=(3, ), value=array((1.0, 0, 0)),
188
- desc="flow direction")
209
+ fdv = CArray(dtype=float64, shape=(3,), value=array((1.0, 0, 0)), desc='flow direction')
189
210
 
190
211
  # internal identifier
191
212
  digest = Property(
192
- depends_on=['c', 'ma', 'fdv'],
193
- )
213
+ depends_on=['c', 'ma', 'fdv'],
214
+ )
194
215
 
195
216
  @cached_property
196
- def _get_digest( self ):
197
- return digest( self )
217
+ def _get_digest(self):
218
+ return digest(self)
198
219
 
199
- def _r( self, gpos, mpos=0.0):
200
- """
201
- Calculates the virtual distances between grid point locations and
220
+ def _r(self, gpos, mpos=0.0):
221
+ """Calculates the virtual distances between grid point locations and
202
222
  microphone locations or the origin. These virtual distances correspond
203
223
  to travel times of the sound. Functionality may change in the future.
204
224
 
@@ -215,35 +235,33 @@ class UniformFlowEnvironment( Environment):
215
235
  Returns
216
236
  -------
217
237
  array of floats
218
- The distances in a twodimensional (N, M) array of floats. If M==1,
238
+ The distances in a twodimensional (N, M) array of floats. If M==1,
219
239
  then only a one-dimensional array is returned.
240
+
220
241
  """
221
242
  if isscalar(mpos):
222
- mpos = array((0, 0, 0), dtype = float32)[:, newaxis]
223
- fdv = self.fdv/sqrt((self.fdv*self.fdv).sum())
243
+ mpos = array((0, 0, 0), dtype=float32)[:, newaxis]
244
+ fdv = self.fdv / sqrt((self.fdv * self.fdv).sum())
224
245
  mpos = mpos[:, newaxis, :]
225
- rmv = gpos[:, :, newaxis]-mpos
226
- rm = sqrt(sum(rmv*rmv, 0))
227
- macostheta = (self.ma*sum(rmv.reshape((3, -1))*fdv[:, newaxis], 0)\
228
- /rm.reshape(-1)).reshape(rm.shape)
229
- rm *= 1/(-macostheta + sqrt(macostheta*macostheta-self.ma*self.ma+1))
246
+ rmv = gpos[:, :, newaxis] - mpos
247
+ rm = sqrt(sum(rmv * rmv, 0))
248
+ macostheta = (self.ma * sum(rmv.reshape((3, -1)) * fdv[:, newaxis], 0) / rm.reshape(-1)).reshape(rm.shape)
249
+ rm *= 1 / (-macostheta + sqrt(macostheta * macostheta - self.ma * self.ma + 1))
230
250
  if rm.shape[1] == 1:
231
251
  rm = rm[:, 0]
232
252
  return rm
233
-
234
253
 
235
- class FlowField( HasPrivateTraits ):
236
- """
237
- An abstract base class for a spatial flow field.
238
- """
254
+
255
+ class FlowField(HasPrivateTraits):
256
+ """An abstract base class for a spatial flow field."""
257
+
239
258
  digest = Property
240
259
 
241
- def _get_digest( self ):
260
+ def _get_digest(self):
242
261
  return ''
243
262
 
244
- def v( self, xx):
245
- """
246
- Provides the flow field as a function of the location. This is
263
+ def v(self, xx): # noqa: ARG002
264
+ """Provides the flow field as a function of the location. This is
247
265
  implemented here for the possibly most simple case: a quiescent fluid.
248
266
 
249
267
  Parameters
@@ -257,49 +275,45 @@ class FlowField( HasPrivateTraits ):
257
275
  The first element in the tuple is the velocity vector and the
258
276
  second is the Jacobian of the velocity vector field, both at the
259
277
  given location.
278
+
260
279
  """
261
- v = array((0., 0., 0.))
262
- dv = array(((0., 0., 0.), (0., 0., 0.), (0., 0., 0.)))
280
+ v = array((0.0, 0.0, 0.0))
281
+ dv = array(((0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0)))
263
282
  return -v, -dv
264
283
 
265
- class SlotJet( FlowField ):
266
- """
267
- Provides an analytical approximation of the flow field of a slot jet,
284
+
285
+ class SlotJet(FlowField):
286
+ """Provides an analytical approximation of the flow field of a slot jet,
268
287
  see :ref:`Albertson et al., 1950<Albertson1950>`.
269
288
  """
289
+
270
290
  #: Exit velocity at jet origin, i.e. the nozzle. Defaults to 0.
271
- v0 = Float(0.0,
272
- desc="exit velocity")
291
+ v0 = Float(0.0, desc='exit velocity')
273
292
 
274
- #: Location of a point at the slot center line,
293
+ #: Location of a point at the slot center line,
275
294
  #: defaults to the co-ordinate origin.
276
- origin = CArray( dtype=float64, shape=(3, ), value=array((0., 0., 0.)),
277
- desc="center of nozzle")
295
+ origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
278
296
 
279
297
  #: Unit flow direction of the slot jet, defaults to (1,0,0).
280
- flow = CArray( dtype=float64, shape=(3, ), value=array((1., 0., 0.)),
281
- desc="flow direction")
298
+ flow = CArray(dtype=float64, shape=(3,), value=array((1.0, 0.0, 0.0)), desc='flow direction')
282
299
 
283
300
  #: Unit vector parallel to slot center plane, defaults to (0,1,0).
284
- plane = CArray( dtype=float64, shape=(3, ), value=array((0., 1., 0.)),
285
- desc="slot center line direction")
286
-
301
+ plane = CArray(dtype=float64, shape=(3,), value=array((0.0, 1.0, 0.0)), desc='slot center line direction')
302
+
287
303
  #: Width of the slot, defaults to 0.2 .
288
- B = Float(0.2,
289
- desc="nozzle diameter")
304
+ B = Float(0.2, desc='nozzle diameter')
290
305
 
291
306
  # internal identifier
292
307
  digest = Property(
293
- depends_on=['v0', 'origin', 'flow', 'plane', 'B'],
294
- )
308
+ depends_on=['v0', 'origin', 'flow', 'plane', 'B'],
309
+ )
295
310
 
296
311
  @cached_property
297
- def _get_digest( self ):
298
- return digest( self )
312
+ def _get_digest(self):
313
+ return digest(self)
299
314
 
300
- def v( self, xx):
301
- """
302
- Provides the flow field as a function of the location. This is
315
+ def v(self, xx):
316
+ """Provides the flow field as a function of the location. This is
303
317
  implemented here only for the component in the direction of :attr:`flow`;
304
318
  entrainment components are set to zero.
305
319
 
@@ -314,21 +328,22 @@ class SlotJet( FlowField ):
314
328
  The first element in the tuple is the velocity vector and the
315
329
  second is the Jacobian of the velocity vector field, both at the
316
330
  given location.
331
+
317
332
  """
318
333
  # TODO: better to make sure that self.flow and self.plane are indeed unit vectors before
319
334
  # normalize
320
- flow = self.flow/norm(self.flow)
321
- plane = self.plane/norm(self.plane)
335
+ flow = self.flow / norm(self.flow)
336
+ plane = self.plane / norm(self.plane)
322
337
  # additional axes of global co-ordinate system
323
- yy = -cross(flow,plane)
324
- zz = cross(flow,yy)
338
+ yy = -cross(flow, plane)
339
+ zz = cross(flow, yy)
325
340
  # distance from slot exit plane
326
- xx1 = xx-self.origin
327
- # local co-ordinate system
328
- x = dot(flow,xx1)
329
- y = dot(yy,xx1)
330
- x1 = 0.109*x
331
- h1 = abs(y)+sqrt(pi)*0.5*x1-0.5*self.B
341
+ xx1 = xx - self.origin
342
+ # local co-ordinate system
343
+ x = dot(flow, xx1)
344
+ y = dot(yy, xx1)
345
+ x1 = 0.109 * x
346
+ h1 = abs(y) + sqrt(pi) * 0.5 * x1 - 0.5 * self.B
332
347
  if h1 < 0.0:
333
348
  # core jet
334
349
  Ux = self.v0
@@ -336,18 +351,18 @@ class SlotJet( FlowField ):
336
351
  Udy = 0
337
352
  else:
338
353
  # shear layer
339
- Ux = self.v0*exp(-h1*h1/(2*x1*x1))
340
- Udx = (h1*h1/(x*x1*x1)-sqrt(pi)*0.5*h1/(x*x1))*Ux
341
- Udy = -sign(y)*h1*Ux/(x1*x1)
354
+ Ux = self.v0 * exp(-h1 * h1 / (2 * x1 * x1))
355
+ Udx = (h1 * h1 / (x * x1 * x1) - sqrt(pi) * 0.5 * h1 / (x * x1)) * Ux
356
+ Udy = -sign(y) * h1 * Ux / (x1 * x1)
342
357
  # Jacobi matrix
343
- dU = array(((Udx,0,0),(Udy,0,0),(0,0,0))).T
358
+ dU = array(((Udx, 0, 0), (Udy, 0, 0), (0, 0, 0))).T
344
359
  # rotation matrix
345
- R = array((flow,yy,zz)).T
346
- return dot(R,array((Ux,0,0))), dot(dot(R,dU),R.T)
360
+ R = array((flow, yy, zz)).T
361
+ return dot(R, array((Ux, 0, 0))), dot(dot(R, dU), R.T)
347
362
 
348
- class OpenJet( FlowField ):
349
- """
350
- Provides an analytical approximation of the flow field of an open jet,
363
+
364
+ class OpenJet(FlowField):
365
+ """Provides an analytical approximation of the flow field of an open jet,
351
366
  see :ref:`Albertson et al., 1950<Albertson1950>`.
352
367
 
353
368
  Notes
@@ -355,31 +370,29 @@ class OpenJet( FlowField ):
355
370
  This is not a fully generic implementation and is limited to flow in the
356
371
  x-direction only. No other directions are possible at the moment and flow
357
372
  components in the other direction are zero.
373
+
358
374
  """
375
+
359
376
  #: Exit velocity at jet origin, i.e. the nozzle. Defaults to 0.
360
- v0 = Float(0.0,
361
- desc="exit velocity")
377
+ v0 = Float(0.0, desc='exit velocity')
362
378
 
363
379
  #: Location of the nozzle center, defaults to the co-ordinate origin.
364
- origin = CArray( dtype=float64, shape=(3, ), value=array((0., 0., 0.)),
365
- desc="center of nozzle")
380
+ origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
366
381
 
367
382
  #: Diameter of the nozzle, defaults to 0.2 .
368
- D = Float(0.2,
369
- desc="nozzle diameter")
383
+ D = Float(0.2, desc='nozzle diameter')
370
384
 
371
385
  # internal identifier
372
386
  digest = Property(
373
- depends_on=['v0', 'origin', 'D'],
374
- )
387
+ depends_on=['v0', 'origin', 'D'],
388
+ )
375
389
 
376
390
  @cached_property
377
- def _get_digest( self ):
378
- return digest( self )
391
+ def _get_digest(self):
392
+ return digest(self)
379
393
 
380
- def v( self, xx):
381
- """
382
- Provides the flow field as a function of the location. This is
394
+ def v(self, xx):
395
+ """Provides the flow field as a function of the location. This is
383
396
  implemented here only for a jet in `x`-direction and the `y`- and
384
397
  `z`-components are set to zero.
385
398
 
@@ -394,73 +407,65 @@ class OpenJet( FlowField ):
394
407
  The first element in the tuple is the velocity vector and the
395
408
  second is the Jacobian of the velocity vector field, both at the
396
409
  given location.
410
+
397
411
  """
398
- x, y, z = xx-self.origin
399
- r = sqrt(y*y+z*z)
400
- x1 = 0.081*x
401
- h1 = r+x1-0.5*self.D
402
- U = self.v0*exp(-h1*h1/(2*x1*x1))
412
+ x, y, z = xx - self.origin
413
+ r = sqrt(y * y + z * z)
414
+ x1 = 0.081 * x
415
+ h1 = r + x1 - 0.5 * self.D
416
+ U = self.v0 * exp(-h1 * h1 / (2 * x1 * x1))
403
417
  if h1 < 0.0:
404
418
  Udr = 0.0
405
419
  U = self.v0
406
420
  else:
407
- Udr = -h1*U/(x1*x1)
421
+ Udr = -h1 * U / (x1 * x1)
408
422
  if r > 0.0:
409
- Udy = y*Udr/r
410
- Udz = z*Udr/r
423
+ Udy = y * Udr / r
424
+ Udz = z * Udr / r
411
425
  else:
412
426
  Udy = Udz = 0.0
413
- Udx = (h1*h1/(x*x1*x1)-h1/(x*x1))*U
427
+ Udx = (h1 * h1 / (x * x1 * x1) - h1 / (x * x1)) * U
414
428
  if h1 < 0.0:
415
429
  Udx = 0
416
430
 
417
431
  # flow field
418
- v = array( (U, 0., 0.) )
432
+ v = array((U, 0.0, 0.0))
419
433
  # Jacobi matrix
420
- dv = array( ((Udx, 0., 0.), (Udy, 0., 0.), (Udz, 0., 0.)) ).T
434
+ dv = array(((Udx, 0.0, 0.0), (Udy, 0.0, 0.0), (Udz, 0.0, 0.0))).T
421
435
  return v, dv
422
436
 
423
437
 
438
+ class RotatingFlow(FlowField):
439
+ """Provides an analytical approximation of the flow field of a rotating fluid with constant flow."""
424
440
 
425
-
426
- class RotatingFlow( FlowField ):
427
- """
428
- Provides an analytical approximation of the flow field of a rotating fluid with constant flow.
429
-
430
-
431
- """
432
441
  #: Exit velocity at jet origin, i.e. the nozzle. Defaults to 0.
433
- rpm = Float(0.0,
434
- desc="revolutions per minute of the virtual array; negative values for clockwise rotation")
442
+ rpm = Float(0.0, desc='revolutions per minute of the virtual array; negative values for clockwise rotation')
435
443
 
436
- v0 = Float(0.0,
437
- desc="flow velocity")
444
+ v0 = Float(0.0, desc='flow velocity')
438
445
 
439
446
  #: Location of the nozzle center, defaults to the co-ordinate origin.
440
- origin = CArray( dtype=float64, shape=(3, ), value=array((0., 0., 0.)),
441
- desc="center of nozzle")
447
+ origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
442
448
 
443
449
  # internal identifier
444
450
  digest = Property(
445
- depends_on=['v0', 'origin', 'rpm'],
446
- )
451
+ depends_on=['v0', 'origin', 'rpm'],
452
+ )
447
453
 
448
454
  # internal identifier
449
455
  omega = Property(
450
- depends_on=['rpm'],
451
- )
456
+ depends_on=['rpm'],
457
+ )
452
458
 
453
459
  @cached_property
454
460
  def _get_omega(self):
455
461
  return 2 * pi * self.rpm / 60
456
462
 
457
463
  @cached_property
458
- def _get_digest( self ):
459
- return digest( self )
464
+ def _get_digest(self):
465
+ return digest(self)
460
466
 
461
- def v( self, xx):
462
- """
463
- Provides the rotating flow field around the z-Axis as a function of the location.
467
+ def v(self, xx):
468
+ """Provides the rotating flow field around the z-Axis as a function of the location.
464
469
 
465
470
  Parameters
466
471
  ----------
@@ -473,55 +478,55 @@ class RotatingFlow( FlowField ):
473
478
  The first element in the tuple is the velocity vector and the
474
479
  second is the Jacobian of the velocity vector field, both at the
475
480
  given location.
481
+
476
482
  """
477
- x, y, z = xx-self.origin
483
+ x, y, z = xx - self.origin
478
484
 
479
485
  # rotational speed
480
486
  omega = self.omega
481
487
 
482
- #velocity vector
488
+ # velocity vector
483
489
  U = omega * y
484
490
  V = -omega * x
485
- W = self.v0
486
-
491
+ W = self.v0
492
+
487
493
  # flow field
488
- v = array( (U, V, W) )
494
+ v = array((U, V, W))
489
495
  # Jacobi matrix
490
- dv = array( ((0, -omega, 0.), (omega, 0, 0.), (0., 0., 0.)) ).T
496
+ dv = array(((0, -omega, 0.0), (omega, 0, 0.0), (0.0, 0.0, 0.0))).T
491
497
  return v, dv
492
498
 
493
499
 
494
-
495
-
496
- def spiral_sphere(N, Om=2*pi, b=array((0, 0, 1))): #change to 4*pi
497
- """
498
- Internal helper function for the raycasting that returns an array of
500
+ def spiral_sphere(N, Om=None, b=None): # change to 4*pi
501
+ """Internal helper function for the raycasting that returns an array of
499
502
  unit vectors (N, 3) giving equally distributed directions on a part of
500
503
  sphere given by the center direction b and the solid angle Om.
501
504
  """
505
+ Om = 2 * pi if Om is None else Om
506
+ b = array((0, 0, 1)) if b is None else b
502
507
  # first produce 'equally' distributed directions in spherical coords
503
- o = 4*pi/Om
504
- h = -1+ 2*arange(N)/(N*o-1.)
508
+ o = 4 * pi / Om
509
+ h = -1 + 2 * arange(N) / (N * o - 1.0)
505
510
  theta = arccos(h)
506
511
  phi = zeros_like(theta)
507
512
  for i, hk in enumerate(h[1:]):
508
- phi[i+1] = phi[i]+3.6/sqrt(N*o*(1-hk*hk)) % (2*pi)
513
+ phi[i + 1] = phi[i] + 3.6 / sqrt(N * o * (1 - hk * hk)) % (2 * pi)
509
514
  # translate to cartesian coords
510
515
  xyz = vstack((sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)))
511
516
  # mirror everything on a plane so that b points into the center
512
517
  a = xyz[:, 0]
513
- b = b/norm(b)
514
- ab = (a-b)[:, newaxis]
515
- if norm(ab)<1e-10:
518
+ b = b / norm(b)
519
+ ab = (a - b)[:, newaxis]
520
+ if norm(ab) < 1e-10:
516
521
  return xyz
517
522
  # this is the Householder matrix for mirroring
518
- H = identity(3)-dot(ab, ab.T)/dot(ab.T, a)
523
+ H = identity(3) - dot(ab, ab.T) / dot(ab.T, a)
519
524
  # actual mirroring
520
525
  return dot(H, xyz)
521
526
 
527
+
522
528
  class GeneralFlowEnvironment(Environment):
523
- """
524
- An acoustic environment with a generic flow field.
529
+ """An acoustic environment with a generic flow field.
525
530
 
526
531
  This class provides the facilities to calculate the travel time (distances)
527
532
  between grid point locations and microphone locations in a generic flow
@@ -531,33 +536,30 @@ class GeneralFlowEnvironment(Environment):
531
536
  backwards in time. The result is interpolated within a tetrahedal grid
532
537
  spanned between these rays.
533
538
  """
539
+
534
540
  #: The flow field, must be of type :class:`~acoular.environments.FlowField`.
535
- ff = Trait(FlowField,
536
- desc="flow field")
541
+ ff = Trait(FlowField, desc='flow field')
537
542
 
538
543
  #: Number of rays used per solid angle :math:`\Omega`, defaults to 200.
539
- N = Int(200,
540
- desc="number of rays per Om")
544
+ N = Int(200, desc='number of rays per Om')
541
545
 
542
546
  #: The maximum solid angle used in the algorithm, defaults to :math:`\pi`.
543
- Om = Float(pi,
544
- desc="maximum solid angle")
547
+ Om = Float(pi, desc='maximum solid angle')
545
548
 
546
549
  # internal identifier
547
550
  digest = Property(
548
- depends_on=['c', 'ff.digest', 'N', 'Om'],
549
- )
551
+ depends_on=['c', 'ff.digest', 'N', 'Om'],
552
+ )
550
553
 
551
554
  # internal dictionary of interpolators
552
555
  idict = Dict
553
556
 
554
557
  @cached_property
555
- def _get_digest( self ):
556
- return digest( self )
558
+ def _get_digest(self):
559
+ return digest(self)
557
560
 
558
- def _r( self, gpos, mpos=0.0):
559
- """
560
- Calculates the virtual distances between grid point locations and
561
+ def _r(self, gpos, mpos=0.0):
562
+ """Calculates the virtual distances between grid point locations and
561
563
  microphone locations or the origin. These virtual distances correspond
562
564
  to travel times of the sound along a ray that is traced through the
563
565
  medium. Functionality may change in the future.
@@ -575,21 +577,22 @@ class GeneralFlowEnvironment(Environment):
575
577
  Returns
576
578
  -------
577
579
  array of floats
578
- The distances in a twodimensional (N, M) array of floats. If M==1,
580
+ The distances in a twodimensional (N, M) array of floats. If M==1,
579
581
  then only a one-dimensional array is returned.
582
+
580
583
  """
581
584
  c = self.c
582
-
585
+
583
586
  if isscalar(mpos):
584
- mpos = array((0, 0, 0), dtype = float32)[:, newaxis]
587
+ mpos = array((0, 0, 0), dtype=float32)[:, newaxis]
585
588
 
586
589
  gt = empty((gpos.shape[-1], mpos.shape[-1]))
587
590
  for micnum, x0 in enumerate(mpos.T):
588
- key = x0.tobytes() # make array hashable
589
- #todo: the interpolator also depends the roi, so idict keys should also depend on roi
591
+ key = x0.tobytes() # make array hashable
592
+ # TODO: the interpolator also depends the roi, so idict keys should also depend on roi
590
593
  # OR the idict should be cleaned if roi changes
591
594
  try:
592
- li = self.idict[key] # fetch stored interpolator
595
+ li = self.idict[key] # fetch stored interpolator
593
596
  except KeyError:
594
597
  # if interpolator doesn't exist, construct it
595
598
  roi = gpos
@@ -601,11 +604,10 @@ class GeneralFlowEnvironment(Environment):
601
604
  gt[:, micnum] = li(gpos.T)
602
605
  if gt.shape[1] == 1:
603
606
  gt = gt[:, 0]
604
- return c*gt #return distance along ray
607
+ return c * gt # return distance along ray
605
608
 
606
- def get_interpolator( self, roi, x0 ):
607
- """
608
- gets an LinearNDInterpolator object
609
+ def get_interpolator(self, roi, x0):
610
+ """Gets an LinearNDInterpolator object.
609
611
 
610
612
  Parameters
611
613
  ----------
@@ -614,52 +616,55 @@ class GeneralFlowEnvironment(Environment):
614
616
  co-ordinates. Used to estimate the maximum distance and ROI
615
617
  extension and center.
616
618
  x0 : array of floats of shape (3)
617
- The location of the microphone in 3D cartesian co-ordinates.
619
+ The location of the microphone in 3D cartesian co-ordinates.
618
620
 
619
621
  Returns
620
622
  -------
621
623
  LinearNDInterpolator object
624
+
622
625
  """
623
626
  c = self.c
624
627
 
625
628
  # the DE system
626
- def f1(t, y, v):
629
+ def f1(t, y, v): # noqa: ARG001
627
630
  x = y[0:3]
628
631
  s = y[3:6]
629
632
  vv, dv = v(x)
630
- sa = sqrt(s[0]*s[0]+s[1]*s[1]+s[2]*s[2])
633
+ sa = sqrt(s[0] * s[0] + s[1] * s[1] + s[2] * s[2])
631
634
  x = empty(6)
632
- x[0:3] = c*s/sa - vv # time reversal
633
- x[3:6] = dot(s, -dv.T) # time reversal
635
+ x[0:3] = c * s / sa - vv # time reversal
636
+ x[3:6] = dot(s, -dv.T) # time reversal
634
637
  return x
635
638
 
636
639
  # integration along a single ray
637
640
  def fr(x0, n0, rmax, dt, v, xyz, t):
638
- s0 = n0 / (c+dot(v(x0)[0], n0))
641
+ s0 = n0 / (c + dot(v(x0)[0], n0))
639
642
  y0 = hstack((x0, s0))
640
643
  oo = ode(f1)
641
644
  oo.set_f_params(v)
642
- oo.set_integrator('vode',
643
- rtol=1e-4, # accuracy !
644
- max_step=1e-4*rmax) # for thin shear layer
645
+ oo.set_integrator(
646
+ 'vode',
647
+ rtol=1e-4, # accuracy !
648
+ max_step=1e-4 * rmax,
649
+ ) # for thin shear layer
645
650
  oo.set_initial_value(y0, 0)
646
651
  while oo.successful():
647
652
  xyz.append(oo.y[0:3])
648
653
  t.append(oo.t)
649
- if norm(oo.y[0:3]-x0)>rmax:
654
+ if norm(oo.y[0:3] - x0) > rmax:
650
655
  break
651
- oo.integrate(oo.t+dt)
656
+ oo.integrate(oo.t + dt)
652
657
 
653
658
  gs2 = roi.shape[-1]
654
659
  vv = self.ff.v
655
660
  NN = int(sqrt(self.N))
656
- xe = roi.mean(1) # center of grid
657
- r = x0[:, newaxis]-roi
658
- rmax = sqrt((r*r).sum(0).max()) # maximum distance
659
- nv = spiral_sphere(self.N, self.Om, b=xe-x0)
660
- rstep = rmax/sqrt(self.N)
661
+ xe = roi.mean(1) # center of grid
662
+ r = x0[:, newaxis] - roi
663
+ rmax = sqrt((r * r).sum(0).max()) # maximum distance
664
+ nv = spiral_sphere(self.N, self.Om, b=xe - x0)
665
+ rstep = rmax / sqrt(self.N)
661
666
  rmax += rstep
662
- tstep = rstep/c
667
+ tstep = rstep / c
663
668
  xyz = []
664
669
  t = []
665
670
  lastind = 0
@@ -672,10 +677,8 @@ class GeneralFlowEnvironment(Environment):
672
677
  dd.add_points(xyz[lastind:], restart=True)
673
678
  lastind = len(xyz)
674
679
  # ConvexHull includes grid if no grid points on hull
675
- if dd.simplices.min()>=gs2:
680
+ if dd.simplices.min() >= gs2:
676
681
  break
677
682
  xyz = array(xyz)
678
683
  t = array(t)
679
684
  return LinearNDInterpolator(xyz, t)
680
-
681
-