acoular 24.3__py3-none-any.whl → 24.7__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 (139) hide show
  1. acoular/__init__.py +119 -54
  2. acoular/calib.py +29 -38
  3. acoular/configuration.py +132 -82
  4. acoular/demo/__init__.py +10 -4
  5. acoular/demo/acoular_demo.py +73 -55
  6. acoular/environments.py +270 -264
  7. acoular/fastFuncs.py +366 -196
  8. acoular/fbeamform.py +1797 -1934
  9. acoular/grids.py +504 -548
  10. acoular/h5cache.py +74 -83
  11. acoular/h5files.py +159 -142
  12. acoular/internal.py +13 -14
  13. acoular/microphones.py +57 -53
  14. acoular/sdinput.py +57 -53
  15. acoular/signals.py +180 -178
  16. acoular/sources.py +920 -724
  17. acoular/spectra.py +353 -363
  18. acoular/tbeamform.py +416 -416
  19. acoular/tfastfuncs.py +180 -104
  20. acoular/tools/__init__.py +25 -0
  21. acoular/tools/aiaa.py +185 -0
  22. acoular/tools/helpers.py +189 -0
  23. acoular/tools/metrics.py +165 -0
  24. acoular/tprocess.py +1240 -1182
  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-24.3.dist-info → acoular-24.7.dist-info}/METADATA +58 -39
  31. acoular-24.7.dist-info/RECORD +50 -0
  32. {acoular-24.3.dist-info → acoular-24.7.dist-info}/WHEEL +1 -1
  33. acoular-24.7.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/BeamformerCMFLassoLarsBIC.npy +0 -0
  46. acoular/tests/reference_data/BeamformerCMFNNLS.npy +0 -0
  47. acoular/tests/reference_data/BeamformerCapon.npy +0 -0
  48. acoular/tests/reference_data/BeamformerClean.npy +0 -0
  49. acoular/tests/reference_data/BeamformerCleansc.npy +0 -0
  50. acoular/tests/reference_data/BeamformerCleant.npy +0 -0
  51. acoular/tests/reference_data/BeamformerCleantSq.npy +0 -0
  52. acoular/tests/reference_data/BeamformerCleantSqTraj.npy +0 -0
  53. acoular/tests/reference_data/BeamformerCleantTraj.npy +0 -0
  54. acoular/tests/reference_data/BeamformerDamas.npy +0 -0
  55. acoular/tests/reference_data/BeamformerDamasPlus.npy +0 -0
  56. acoular/tests/reference_data/BeamformerEig.npy +0 -0
  57. acoular/tests/reference_data/BeamformerEigFalse1.npy +0 -0
  58. acoular/tests/reference_data/BeamformerEigFalse2.npy +0 -0
  59. acoular/tests/reference_data/BeamformerEigFalse3.npy +0 -0
  60. acoular/tests/reference_data/BeamformerEigFalse4.npy +0 -0
  61. acoular/tests/reference_data/BeamformerEigTrue1.npy +0 -0
  62. acoular/tests/reference_data/BeamformerEigTrue2.npy +0 -0
  63. acoular/tests/reference_data/BeamformerEigTrue3.npy +0 -0
  64. acoular/tests/reference_data/BeamformerEigTrue4.npy +0 -0
  65. acoular/tests/reference_data/BeamformerFunctional.npy +0 -0
  66. acoular/tests/reference_data/BeamformerGIB.npy +0 -0
  67. acoular/tests/reference_data/BeamformerGridlessOrth.npy +0 -0
  68. acoular/tests/reference_data/BeamformerMusic.npy +0 -0
  69. acoular/tests/reference_data/BeamformerOrth.npy +0 -0
  70. acoular/tests/reference_data/BeamformerSODIX.npy +0 -0
  71. acoular/tests/reference_data/BeamformerTime.npy +0 -0
  72. acoular/tests/reference_data/BeamformerTimeSq.npy +0 -0
  73. acoular/tests/reference_data/BeamformerTimeSqTraj.npy +0 -0
  74. acoular/tests/reference_data/BeamformerTimeTraj.npy +0 -0
  75. acoular/tests/reference_data/Environment.npy +0 -0
  76. acoular/tests/reference_data/Example1_numerical_values_testsum.h5 +0 -0
  77. acoular/tests/reference_data/FiltFiltOctave__.npy +0 -0
  78. acoular/tests/reference_data/FiltFiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  79. acoular/tests/reference_data/FiltFreqWeight_weight_A_.npy +0 -0
  80. acoular/tests/reference_data/FiltFreqWeight_weight_C_.npy +0 -0
  81. acoular/tests/reference_data/FiltFreqWeight_weight_Z_.npy +0 -0
  82. acoular/tests/reference_data/FiltOctave__.npy +0 -0
  83. acoular/tests/reference_data/FiltOctave_band_100_0_fraction_Thirdoctave_.npy +0 -0
  84. acoular/tests/reference_data/Filter__.npy +0 -0
  85. acoular/tests/reference_data/GeneralFlowEnvironment.npy +0 -0
  86. acoular/tests/reference_data/OctaveFilterBank__.npy +0 -0
  87. acoular/tests/reference_data/OpenJet.npy +0 -0
  88. acoular/tests/reference_data/PointSource.npy +0 -0
  89. acoular/tests/reference_data/PowerSpectra_csm.npy +0 -0
  90. acoular/tests/reference_data/PowerSpectra_ev.npy +0 -0
  91. acoular/tests/reference_data/RotatingFlow.npy +0 -0
  92. acoular/tests/reference_data/SlotJet.npy +0 -0
  93. acoular/tests/reference_data/TimeAverage__.npy +0 -0
  94. acoular/tests/reference_data/TimeCumAverage__.npy +0 -0
  95. acoular/tests/reference_data/TimeExpAverage_weight_F_.npy +0 -0
  96. acoular/tests/reference_data/TimeExpAverage_weight_I_.npy +0 -0
  97. acoular/tests/reference_data/TimeExpAverage_weight_S_.npy +0 -0
  98. acoular/tests/reference_data/TimeInOut__.npy +0 -0
  99. acoular/tests/reference_data/TimePower__.npy +0 -0
  100. acoular/tests/reference_data/TimeReverse__.npy +0 -0
  101. acoular/tests/reference_data/UniformFlowEnvironment.npy +0 -0
  102. acoular/tests/reference_data/beamformer_traj_time_data.h5 +0 -0
  103. acoular/tests/run_tests.sh +0 -18
  104. acoular/tests/run_tests_osx.sh +0 -16
  105. acoular/tests/test.npy +0 -0
  106. acoular/tests/test_beamformer_results.py +0 -213
  107. acoular/tests/test_classes.py +0 -60
  108. acoular/tests/test_digest.py +0 -125
  109. acoular/tests/test_environments.py +0 -73
  110. acoular/tests/test_example1.py +0 -124
  111. acoular/tests/test_grid.py +0 -92
  112. acoular/tests/test_integrate.py +0 -102
  113. acoular/tests/test_signals.py +0 -60
  114. acoular/tests/test_sources.py +0 -65
  115. acoular/tests/test_spectra.py +0 -38
  116. acoular/tests/test_timecache.py +0 -35
  117. acoular/tests/test_tprocess.py +0 -90
  118. acoular/tests/test_traj_beamformer_results.py +0 -164
  119. acoular/tests/unsupported/SpeedComparison/OvernightTestcasesBeamformer_nMics32_nGridPoints100_nFreqs4_nTrials10.png +0 -0
  120. acoular/tests/unsupported/SpeedComparison/cythonBeamformer.pyx +0 -237
  121. acoular/tests/unsupported/SpeedComparison/mainForCython.py +0 -103
  122. acoular/tests/unsupported/SpeedComparison/mainForParallelJit.py +0 -143
  123. acoular/tests/unsupported/SpeedComparison/setupCythonOpenMP.py +0 -63
  124. acoular/tests/unsupported/SpeedComparison/sharedFunctions.py +0 -153
  125. acoular/tests/unsupported/SpeedComparison/timeOverNMics_AllImportantMethods.png +0 -0
  126. acoular/tests/unsupported/SpeedComparison/timeOverNMics_faverage.png +0 -0
  127. acoular/tests/unsupported/SpeedComparison/vglOptimierungFAverage.py +0 -204
  128. acoular/tests/unsupported/SpeedComparison/vglOptimierungGaussSeidel.py +0 -182
  129. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAMFULL_INVERSE.py +0 -764
  130. acoular/tests/unsupported/SpeedComparison/vglOptimierungR_BEAM_OS.py +0 -231
  131. acoular/tests/unsupported/SpeedComparison/whatsFastestWayFor_absASquared.py +0 -48
  132. acoular/tests/unsupported/functionalBeamformer.py +0 -123
  133. acoular/tests/unsupported/precisionTest.py +0 -153
  134. acoular/tests/unsupported/validationOfBeamformerFuncsPOSTAcoularIntegration.py +0 -254
  135. acoular/tests/unsupported/validationOfBeamformerFuncsPREeAcoularIntegration.py +0 -531
  136. acoular/tools.py +0 -422
  137. acoular-24.3.dist-info/RECORD +0 -148
  138. acoular-24.3.dist-info/licenses/LICENSE +0 -29
  139. {acoular-24.3.dist-info → acoular-24.7.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): # noqa: N802, N803
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): # noqa: N802, N803
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,48 @@ 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')
305
+
306
+ #: Nondimensional length of zone of flow establishment (jet core length), defaults to 5.2
307
+ l = Float(5.2, desc='flow establishment length') # noqa: E741
290
308
 
291
309
  # internal identifier
292
310
  digest = Property(
293
- depends_on=['v0', 'origin', 'flow', 'plane', 'B'],
294
- )
311
+ depends_on=['v0', 'origin', 'flow', 'plane', 'B', 'l'],
312
+ )
295
313
 
296
314
  @cached_property
297
- def _get_digest( self ):
298
- return digest( self )
315
+ def _get_digest(self):
316
+ return digest(self)
299
317
 
300
- def v( self, xx):
301
- """
302
- Provides the flow field as a function of the location. This is
318
+ def v(self, xx):
319
+ """Provides the flow field as a function of the location. This is
303
320
  implemented here only for the component in the direction of :attr:`flow`;
304
321
  entrainment components are set to zero.
305
322
 
@@ -314,21 +331,21 @@ class SlotJet( FlowField ):
314
331
  The first element in the tuple is the velocity vector and the
315
332
  second is the Jacobian of the velocity vector field, both at the
316
333
  given location.
334
+
317
335
  """
318
- # TODO: better to make sure that self.flow and self.plane are indeed unit vectors before
319
336
  # normalize
320
- flow = self.flow/norm(self.flow)
321
- plane = self.plane/norm(self.plane)
337
+ flow = self.flow / norm(self.flow)
338
+ plane = self.plane / norm(self.plane)
322
339
  # additional axes of global co-ordinate system
323
- yy = -cross(flow,plane)
324
- zz = cross(flow,yy)
340
+ yy = -cross(flow, plane)
341
+ zz = cross(flow, yy)
325
342
  # 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
343
+ xx1 = xx - self.origin
344
+ # local co-ordinate system
345
+ x = dot(flow, xx1)
346
+ y = dot(yy, xx1)
347
+ x1 = 0.5668 / self.l * x # C1 in Albertson1950
348
+ h1 = abs(y) + sqrt(pi) * 0.5 * x1 - 0.5 * self.B
332
349
  if h1 < 0.0:
333
350
  # core jet
334
351
  Ux = self.v0
@@ -336,18 +353,18 @@ class SlotJet( FlowField ):
336
353
  Udy = 0
337
354
  else:
338
355
  # 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)
356
+ Ux = self.v0 * exp(-h1 * h1 / (2 * x1 * x1))
357
+ Udx = (h1 * h1 / (x * x1 * x1) - sqrt(pi) * 0.5 * h1 / (x * x1)) * Ux
358
+ Udy = -sign(y) * h1 * Ux / (x1 * x1)
342
359
  # Jacobi matrix
343
- dU = array(((Udx,0,0),(Udy,0,0),(0,0,0))).T
360
+ dU = array(((Udx, 0, 0), (Udy, 0, 0), (0, 0, 0))).T
344
361
  # rotation matrix
345
- R = array((flow,yy,zz)).T
346
- return dot(R,array((Ux,0,0))), dot(dot(R,dU),R.T)
362
+ R = array((flow, yy, zz)).T
363
+ return dot(R, array((Ux, 0, 0))), dot(dot(R, dU), R.T)
347
364
 
348
- class OpenJet( FlowField ):
349
- """
350
- Provides an analytical approximation of the flow field of an open jet,
365
+
366
+ class OpenJet(FlowField):
367
+ """Provides an analytical approximation of the flow field of an open jet,
351
368
  see :ref:`Albertson et al., 1950<Albertson1950>`.
352
369
 
353
370
  Notes
@@ -355,31 +372,32 @@ class OpenJet( FlowField ):
355
372
  This is not a fully generic implementation and is limited to flow in the
356
373
  x-direction only. No other directions are possible at the moment and flow
357
374
  components in the other direction are zero.
375
+
358
376
  """
377
+
359
378
  #: Exit velocity at jet origin, i.e. the nozzle. Defaults to 0.
360
- v0 = Float(0.0,
361
- desc="exit velocity")
379
+ v0 = Float(0.0, desc='exit velocity')
362
380
 
363
381
  #: 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")
382
+ origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
366
383
 
367
384
  #: Diameter of the nozzle, defaults to 0.2 .
368
- D = Float(0.2,
369
- desc="nozzle diameter")
385
+ D = Float(0.2, desc='nozzle diameter')
386
+
387
+ #: Nondimensional length of zone of flow establishment (jet core length), defaults to 6.2
388
+ l = Float(6.2, desc='flow establishment length') # noqa: E741
370
389
 
371
390
  # internal identifier
372
391
  digest = Property(
373
- depends_on=['v0', 'origin', 'D'],
374
- )
392
+ depends_on=['v0', 'origin', 'D', 'l'],
393
+ )
375
394
 
376
395
  @cached_property
377
- def _get_digest( self ):
378
- return digest( self )
396
+ def _get_digest(self):
397
+ return digest(self)
379
398
 
380
- def v( self, xx):
381
- """
382
- Provides the flow field as a function of the location. This is
399
+ def v(self, xx):
400
+ """Provides the flow field as a function of the location. This is
383
401
  implemented here only for a jet in `x`-direction and the `y`- and
384
402
  `z`-components are set to zero.
385
403
 
@@ -394,73 +412,65 @@ class OpenJet( FlowField ):
394
412
  The first element in the tuple is the velocity vector and the
395
413
  second is the Jacobian of the velocity vector field, both at the
396
414
  given location.
415
+
397
416
  """
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))
417
+ x, y, z = xx - self.origin
418
+ r = sqrt(y * y + z * z)
419
+ x1 = 0.5022 / self.l * x # C2 in Albertson1950
420
+ h1 = r + x1 - 0.5 * self.D
421
+ U = self.v0 * exp(-h1 * h1 / (2 * x1 * x1))
403
422
  if h1 < 0.0:
404
423
  Udr = 0.0
405
424
  U = self.v0
406
425
  else:
407
- Udr = -h1*U/(x1*x1)
426
+ Udr = -h1 * U / (x1 * x1)
408
427
  if r > 0.0:
409
- Udy = y*Udr/r
410
- Udz = z*Udr/r
428
+ Udy = y * Udr / r
429
+ Udz = z * Udr / r
411
430
  else:
412
431
  Udy = Udz = 0.0
413
- Udx = (h1*h1/(x*x1*x1)-h1/(x*x1))*U
432
+ Udx = (h1 * h1 / (x * x1 * x1) - h1 / (x * x1)) * U
414
433
  if h1 < 0.0:
415
434
  Udx = 0
416
435
 
417
436
  # flow field
418
- v = array( (U, 0., 0.) )
437
+ v = array((U, 0.0, 0.0))
419
438
  # Jacobi matrix
420
- dv = array( ((Udx, 0., 0.), (Udy, 0., 0.), (Udz, 0., 0.)) ).T
439
+ dv = array(((Udx, 0.0, 0.0), (Udy, 0.0, 0.0), (Udz, 0.0, 0.0))).T
421
440
  return v, dv
422
441
 
423
442
 
443
+ class RotatingFlow(FlowField):
444
+ """Provides an analytical approximation of the flow field of a rotating fluid with constant flow."""
424
445
 
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
446
  #: 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")
447
+ rpm = Float(0.0, desc='revolutions per minute of the virtual array; negative values for clockwise rotation')
435
448
 
436
- v0 = Float(0.0,
437
- desc="flow velocity")
449
+ v0 = Float(0.0, desc='flow velocity')
438
450
 
439
451
  #: 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")
452
+ origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0)), desc='center of nozzle')
442
453
 
443
454
  # internal identifier
444
455
  digest = Property(
445
- depends_on=['v0', 'origin', 'rpm'],
446
- )
456
+ depends_on=['v0', 'origin', 'rpm'],
457
+ )
447
458
 
448
459
  # internal identifier
449
460
  omega = Property(
450
- depends_on=['rpm'],
451
- )
461
+ depends_on=['rpm'],
462
+ )
452
463
 
453
464
  @cached_property
454
465
  def _get_omega(self):
455
466
  return 2 * pi * self.rpm / 60
456
467
 
457
468
  @cached_property
458
- def _get_digest( self ):
459
- return digest( self )
469
+ def _get_digest(self):
470
+ return digest(self)
460
471
 
461
- def v( self, xx):
462
- """
463
- Provides the rotating flow field around the z-Axis as a function of the location.
472
+ def v(self, xx):
473
+ """Provides the rotating flow field around the z-Axis as a function of the location.
464
474
 
465
475
  Parameters
466
476
  ----------
@@ -473,55 +483,55 @@ class RotatingFlow( FlowField ):
473
483
  The first element in the tuple is the velocity vector and the
474
484
  second is the Jacobian of the velocity vector field, both at the
475
485
  given location.
486
+
476
487
  """
477
- x, y, z = xx-self.origin
488
+ x, y, z = xx - self.origin
478
489
 
479
490
  # rotational speed
480
491
  omega = self.omega
481
492
 
482
- #velocity vector
493
+ # velocity vector
483
494
  U = omega * y
484
495
  V = -omega * x
485
- W = self.v0
486
-
496
+ W = self.v0
497
+
487
498
  # flow field
488
- v = array( (U, V, W) )
499
+ v = array((U, V, W))
489
500
  # Jacobi matrix
490
- dv = array( ((0, -omega, 0.), (omega, 0, 0.), (0., 0., 0.)) ).T
501
+ dv = array(((0, -omega, 0.0), (omega, 0, 0.0), (0.0, 0.0, 0.0))).T
491
502
  return v, dv
492
503
 
493
504
 
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
505
+ def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
506
+ """Internal helper function for the raycasting that returns an array of
499
507
  unit vectors (N, 3) giving equally distributed directions on a part of
500
508
  sphere given by the center direction b and the solid angle Om.
501
509
  """
510
+ Om = 2 * pi if Om is None else Om
511
+ b = array((0, 0, 1)) if b is None else b
502
512
  # first produce 'equally' distributed directions in spherical coords
503
- o = 4*pi/Om
504
- h = -1+ 2*arange(N)/(N*o-1.)
513
+ o = 4 * pi / Om
514
+ h = -1 + 2 * arange(N) / (N * o - 1.0)
505
515
  theta = arccos(h)
506
516
  phi = zeros_like(theta)
507
517
  for i, hk in enumerate(h[1:]):
508
- phi[i+1] = phi[i]+3.6/sqrt(N*o*(1-hk*hk)) % (2*pi)
518
+ phi[i + 1] = phi[i] + 3.6 / sqrt(N * o * (1 - hk * hk)) % (2 * pi)
509
519
  # translate to cartesian coords
510
520
  xyz = vstack((sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)))
511
521
  # mirror everything on a plane so that b points into the center
512
522
  a = xyz[:, 0]
513
- b = b/norm(b)
514
- ab = (a-b)[:, newaxis]
515
- if norm(ab)<1e-10:
523
+ b = b / norm(b)
524
+ ab = (a - b)[:, newaxis]
525
+ if norm(ab) < 1e-10:
516
526
  return xyz
517
527
  # this is the Householder matrix for mirroring
518
- H = identity(3)-dot(ab, ab.T)/dot(ab.T, a)
528
+ H = identity(3) - dot(ab, ab.T) / dot(ab.T, a)
519
529
  # actual mirroring
520
530
  return dot(H, xyz)
521
531
 
532
+
522
533
  class GeneralFlowEnvironment(Environment):
523
- """
524
- An acoustic environment with a generic flow field.
534
+ """An acoustic environment with a generic flow field.
525
535
 
526
536
  This class provides the facilities to calculate the travel time (distances)
527
537
  between grid point locations and microphone locations in a generic flow
@@ -531,33 +541,30 @@ class GeneralFlowEnvironment(Environment):
531
541
  backwards in time. The result is interpolated within a tetrahedal grid
532
542
  spanned between these rays.
533
543
  """
544
+
534
545
  #: The flow field, must be of type :class:`~acoular.environments.FlowField`.
535
- ff = Trait(FlowField,
536
- desc="flow field")
546
+ ff = Trait(FlowField, desc='flow field')
537
547
 
538
548
  #: Number of rays used per solid angle :math:`\Omega`, defaults to 200.
539
- N = Int(200,
540
- desc="number of rays per Om")
549
+ N = Int(200, desc='number of rays per Om')
541
550
 
542
551
  #: The maximum solid angle used in the algorithm, defaults to :math:`\pi`.
543
- Om = Float(pi,
544
- desc="maximum solid angle")
552
+ Om = Float(pi, desc='maximum solid angle')
545
553
 
546
554
  # internal identifier
547
555
  digest = Property(
548
- depends_on=['c', 'ff.digest', 'N', 'Om'],
549
- )
556
+ depends_on=['c', 'ff.digest', 'N', 'Om'],
557
+ )
550
558
 
551
559
  # internal dictionary of interpolators
552
560
  idict = Dict
553
561
 
554
562
  @cached_property
555
- def _get_digest( self ):
556
- return digest( self )
563
+ def _get_digest(self):
564
+ return digest(self)
557
565
 
558
- def _r( self, gpos, mpos=0.0):
559
- """
560
- Calculates the virtual distances between grid point locations and
566
+ def _r(self, gpos, mpos=0.0):
567
+ """Calculates the virtual distances between grid point locations and
561
568
  microphone locations or the origin. These virtual distances correspond
562
569
  to travel times of the sound along a ray that is traced through the
563
570
  medium. Functionality may change in the future.
@@ -575,21 +582,20 @@ class GeneralFlowEnvironment(Environment):
575
582
  Returns
576
583
  -------
577
584
  array of floats
578
- The distances in a twodimensional (N, M) array of floats. If M==1,
585
+ The distances in a twodimensional (N, M) array of floats. If M==1,
579
586
  then only a one-dimensional array is returned.
587
+
580
588
  """
581
589
  c = self.c
582
-
590
+
583
591
  if isscalar(mpos):
584
- mpos = array((0, 0, 0), dtype = float32)[:, newaxis]
592
+ mpos = array((0, 0, 0), dtype=float32)[:, newaxis]
585
593
 
586
594
  gt = empty((gpos.shape[-1], mpos.shape[-1]))
587
595
  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
590
- # OR the idict should be cleaned if roi changes
596
+ key = x0.tobytes() # make array hashable
591
597
  try:
592
- li = self.idict[key] # fetch stored interpolator
598
+ li = self.idict[key] # fetch stored interpolator
593
599
  except KeyError:
594
600
  # if interpolator doesn't exist, construct it
595
601
  roi = gpos
@@ -601,11 +607,10 @@ class GeneralFlowEnvironment(Environment):
601
607
  gt[:, micnum] = li(gpos.T)
602
608
  if gt.shape[1] == 1:
603
609
  gt = gt[:, 0]
604
- return c*gt #return distance along ray
610
+ return c * gt # return distance along ray
605
611
 
606
- def get_interpolator( self, roi, x0 ):
607
- """
608
- gets an LinearNDInterpolator object
612
+ def get_interpolator(self, roi, x0):
613
+ """Gets an LinearNDInterpolator object.
609
614
 
610
615
  Parameters
611
616
  ----------
@@ -614,52 +619,55 @@ class GeneralFlowEnvironment(Environment):
614
619
  co-ordinates. Used to estimate the maximum distance and ROI
615
620
  extension and center.
616
621
  x0 : array of floats of shape (3)
617
- The location of the microphone in 3D cartesian co-ordinates.
622
+ The location of the microphone in 3D cartesian co-ordinates.
618
623
 
619
624
  Returns
620
625
  -------
621
626
  LinearNDInterpolator object
627
+
622
628
  """
623
629
  c = self.c
624
630
 
625
631
  # the DE system
626
- def f1(t, y, v):
632
+ def f1(t, y, v): # noqa: ARG001
627
633
  x = y[0:3]
628
634
  s = y[3:6]
629
635
  vv, dv = v(x)
630
- sa = sqrt(s[0]*s[0]+s[1]*s[1]+s[2]*s[2])
636
+ sa = sqrt(s[0] * s[0] + s[1] * s[1] + s[2] * s[2])
631
637
  x = empty(6)
632
- x[0:3] = c*s/sa - vv # time reversal
633
- x[3:6] = dot(s, -dv.T) # time reversal
638
+ x[0:3] = c * s / sa - vv # time reversal
639
+ x[3:6] = dot(s, -dv.T) # time reversal
634
640
  return x
635
641
 
636
642
  # integration along a single ray
637
643
  def fr(x0, n0, rmax, dt, v, xyz, t):
638
- s0 = n0 / (c+dot(v(x0)[0], n0))
644
+ s0 = n0 / (c + dot(v(x0)[0], n0))
639
645
  y0 = hstack((x0, s0))
640
646
  oo = ode(f1)
641
647
  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
648
+ oo.set_integrator(
649
+ 'vode',
650
+ rtol=1e-4, # accuracy !
651
+ max_step=1e-4 * rmax,
652
+ ) # for thin shear layer
645
653
  oo.set_initial_value(y0, 0)
646
654
  while oo.successful():
647
655
  xyz.append(oo.y[0:3])
648
656
  t.append(oo.t)
649
- if norm(oo.y[0:3]-x0)>rmax:
657
+ if norm(oo.y[0:3] - x0) > rmax:
650
658
  break
651
- oo.integrate(oo.t+dt)
659
+ oo.integrate(oo.t + dt)
652
660
 
653
661
  gs2 = roi.shape[-1]
654
662
  vv = self.ff.v
655
663
  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)
664
+ xe = roi.mean(1) # center of grid
665
+ r = x0[:, newaxis] - roi
666
+ rmax = sqrt((r * r).sum(0).max()) # maximum distance
667
+ nv = spiral_sphere(self.N, self.Om, b=xe - x0)
668
+ rstep = rmax / sqrt(self.N)
661
669
  rmax += rstep
662
- tstep = rstep/c
670
+ tstep = rstep / c
663
671
  xyz = []
664
672
  t = []
665
673
  lastind = 0
@@ -672,10 +680,8 @@ class GeneralFlowEnvironment(Environment):
672
680
  dd.add_points(xyz[lastind:], restart=True)
673
681
  lastind = len(xyz)
674
682
  # ConvexHull includes grid if no grid points on hull
675
- if dd.simplices.min()>=gs2:
683
+ if dd.simplices.min() >= gs2:
676
684
  break
677
685
  xyz = array(xyz)
678
686
  t = array(t)
679
687
  return LinearNDInterpolator(xyz, t)
680
-
681
-