acoular 25.7__py3-none-any.whl → 26.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- acoular/aiaa/aiaa.py +8 -10
- acoular/base.py +13 -16
- acoular/calib.py +25 -24
- acoular/configuration.py +2 -2
- acoular/demo/__init__.py +97 -9
- acoular/demo/__main__.py +37 -0
- acoular/environments.py +119 -130
- acoular/fbeamform.py +438 -440
- acoular/fprocess.py +18 -13
- acoular/grids.py +122 -301
- acoular/h5cache.py +5 -1
- acoular/h5files.py +96 -9
- acoular/microphones.py +30 -35
- acoular/process.py +14 -25
- acoular/sdinput.py +9 -14
- acoular/signals.py +36 -34
- acoular/sources.py +263 -380
- acoular/spectra.py +60 -80
- acoular/tbeamform.py +242 -224
- acoular/tools/helpers.py +25 -33
- acoular/tools/metrics.py +5 -10
- acoular/tools/utils.py +168 -0
- acoular/tprocess.py +248 -271
- acoular/trajectory.py +5 -6
- acoular/version.py +2 -2
- {acoular-25.7.dist-info → acoular-26.1.dist-info}/METADATA +54 -105
- acoular-26.1.dist-info/RECORD +56 -0
- {acoular-25.7.dist-info → acoular-26.1.dist-info}/WHEEL +1 -1
- acoular/demo/acoular_demo.py +0 -135
- acoular-25.7.dist-info/RECORD +0 -56
- {acoular-25.7.dist-info → acoular-26.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {acoular-25.7.dist-info → acoular-26.1.dist-info}/licenses/LICENSE +0 -0
acoular/environments.py
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
"""
|
|
5
5
|
Implements acoustic environments with and without flow.
|
|
6
6
|
|
|
7
|
+
.. inheritance-diagram::
|
|
8
|
+
acoular.environments.Environment
|
|
9
|
+
:include-subclasses:
|
|
10
|
+
:top-classes:
|
|
11
|
+
acoular.environments.Environment
|
|
12
|
+
:parts: 1
|
|
13
|
+
|
|
14
|
+
.. inheritance-diagram::
|
|
15
|
+
acoular.environments.FlowField
|
|
16
|
+
:include-subclasses:
|
|
17
|
+
:top-classes:
|
|
18
|
+
acoular.environments.FlowField
|
|
19
|
+
:parts: 1
|
|
20
|
+
|
|
7
21
|
.. autosummary::
|
|
8
22
|
:toctree: generated/
|
|
9
23
|
|
|
@@ -24,35 +38,10 @@ from abc import abstractmethod
|
|
|
24
38
|
from warnings import warn
|
|
25
39
|
|
|
26
40
|
import numba as nb
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
arccos,
|
|
30
|
-
arctan2,
|
|
31
|
-
array,
|
|
32
|
-
ascontiguousarray,
|
|
33
|
-
cos,
|
|
34
|
-
cross,
|
|
35
|
-
dot,
|
|
36
|
-
empty,
|
|
37
|
-
exp,
|
|
38
|
-
float32,
|
|
39
|
-
float64,
|
|
40
|
-
hstack,
|
|
41
|
-
identity,
|
|
42
|
-
isscalar,
|
|
43
|
-
matmul,
|
|
44
|
-
newaxis,
|
|
45
|
-
pi,
|
|
46
|
-
sign,
|
|
47
|
-
sin,
|
|
48
|
-
sqrt,
|
|
49
|
-
sum, # noqa: A004
|
|
50
|
-
vstack,
|
|
51
|
-
zeros_like,
|
|
52
|
-
)
|
|
41
|
+
import numpy as np
|
|
42
|
+
import scipy.linalg as spla
|
|
53
43
|
from scipy.integrate import ode
|
|
54
44
|
from scipy.interpolate import LinearNDInterpolator
|
|
55
|
-
from scipy.linalg import norm
|
|
56
45
|
from scipy.spatial import ConvexHull
|
|
57
46
|
from traits.api import (
|
|
58
47
|
ABCHasStrictTraits,
|
|
@@ -100,7 +89,7 @@ def dist_mat(gpos, mpos): # pragma: no cover
|
|
|
100
89
|
"""
|
|
101
90
|
_, M = mpos.shape
|
|
102
91
|
_, N = gpos.shape
|
|
103
|
-
rm = empty((N, M), dtype=gpos.dtype)
|
|
92
|
+
rm = np.empty((N, M), dtype=gpos.dtype)
|
|
104
93
|
TWO = rm.dtype.type(2.0) # make sure to have a float32 or float 64 literal
|
|
105
94
|
m0 = mpos[0]
|
|
106
95
|
m1 = mpos[1]
|
|
@@ -110,7 +99,7 @@ def dist_mat(gpos, mpos): # pragma: no cover
|
|
|
110
99
|
g1 = gpos[1, n]
|
|
111
100
|
g2 = gpos[2, n]
|
|
112
101
|
for m in range(M):
|
|
113
|
-
rm[n, m] = sqrt((g0 - m0[m]) ** TWO + (g1 - m1[m]) ** TWO + (g2 - m2[m]) ** TWO)
|
|
102
|
+
rm[n, m] = np.sqrt((g0 - m0[m]) ** TWO + (g1 - m1[m]) ** TWO + (g2 - m2[m]) ** TWO)
|
|
114
103
|
return rm
|
|
115
104
|
|
|
116
105
|
|
|
@@ -137,10 +126,10 @@ def cartToCyl(x, Q=None): # noqa: N802, N803
|
|
|
137
126
|
Cylindrical representation of given `N` points in cartesian coodrinates as
|
|
138
127
|
an array of shape `(3, N)` with new coordinates :math:`(\phi, r, z)`.
|
|
139
128
|
"""
|
|
140
|
-
Q = identity(3) if Q is None else Q
|
|
141
|
-
if not (Q == identity(3)).all(): # noqa: SIM300
|
|
142
|
-
x =
|
|
143
|
-
return array([arctan2(x[1], x[0]), sqrt(x[0] ** 2 + x[1] ** 2), x[2]])
|
|
129
|
+
Q = np.identity(3) if Q is None else Q
|
|
130
|
+
if not (Q == np.identity(3)).all(): # noqa: SIM300
|
|
131
|
+
x = Q @ x # modified position vector
|
|
132
|
+
return np.array([np.arctan2(x[1], x[0]), np.sqrt(x[0] ** 2 + x[1] ** 2), x[2]])
|
|
144
133
|
|
|
145
134
|
|
|
146
135
|
def cylToCart(x, Q=None): # noqa: N802, N803
|
|
@@ -166,10 +155,10 @@ def cylToCart(x, Q=None): # noqa: N802, N803
|
|
|
166
155
|
Cartesian representation of given `N` points in cylindrical coodrinates as
|
|
167
156
|
an array of shape `(3, N)` with coodinates :math:`(x, y, z)`.
|
|
168
157
|
"""
|
|
169
|
-
Q = identity(3) if Q is None else Q
|
|
170
|
-
if not (Q == identity(3)).all(): # noqa: SIM300
|
|
171
|
-
x =
|
|
172
|
-
return array([x[1] * sin(x[0]), x[1] * cos(x[0]), x[2]])
|
|
158
|
+
Q = np.identity(3) if Q is None else Q
|
|
159
|
+
if not (Q == np.identity(3)).all(): # noqa: SIM300
|
|
160
|
+
x = Q @ x # modified position vector
|
|
161
|
+
return np.array([x[1] * np.sin(x[0]), x[1] * np.cos(x[0]), x[2]])
|
|
173
162
|
|
|
174
163
|
|
|
175
164
|
class Environment(HasStrictTraits):
|
|
@@ -193,7 +182,7 @@ class Environment(HasStrictTraits):
|
|
|
193
182
|
|
|
194
183
|
#: The speed of sound in the environment. Default is ``343.0``, which corresponds to the
|
|
195
184
|
#: approximate speed of sound at 20°C in dry air at sea level, if the unit is m/s.
|
|
196
|
-
c = Float(343.0
|
|
185
|
+
c = Float(343.0)
|
|
197
186
|
|
|
198
187
|
#: The region of interest (ROI) for calculations. (Not needed for most types of environment.)
|
|
199
188
|
#: Default is :obj:`None`.
|
|
@@ -231,12 +220,12 @@ class Environment(HasStrictTraits):
|
|
|
231
220
|
#
|
|
232
221
|
# - shape `(N,)` if ``mpos`` is a single point, or
|
|
233
222
|
# - shape `(N, M)` if ``mpos`` consists of multiple points.
|
|
234
|
-
if isscalar(mpos):
|
|
235
|
-
mpos = array((0, 0, 0), dtype=float64)[:, newaxis]
|
|
236
|
-
rm = dist_mat(ascontiguousarray(gpos), ascontiguousarray(mpos))
|
|
237
|
-
# mpos = mpos[:, newaxis, :]
|
|
238
|
-
# rmv = gpos[:, :, newaxis]-mpos
|
|
239
|
-
# rm = sum(rmv*rmv, 0)**0.5
|
|
223
|
+
if np.isscalar(mpos):
|
|
224
|
+
mpos = np.array((0, 0, 0), dtype=np.float64)[:, np.newaxis]
|
|
225
|
+
rm = dist_mat(np.ascontiguousarray(gpos), np.ascontiguousarray(mpos))
|
|
226
|
+
# mpos = mpos[:, np.newaxis, :]
|
|
227
|
+
# rmv = gpos[:, :, np.newaxis]-mpos
|
|
228
|
+
# rm = np.sum(rmv*rmv, 0)**0.5
|
|
240
229
|
if rm.shape[1] == 1:
|
|
241
230
|
rm = rm[:, 0]
|
|
242
231
|
return rm
|
|
@@ -261,11 +250,11 @@ class UniformFlowEnvironment(Environment):
|
|
|
261
250
|
|
|
262
251
|
#: The Mach number of the flow, defined as the ratio of the flow velocity to the speed of sound.
|
|
263
252
|
#: Default is ``0.0``, which corresponds to no flow.
|
|
264
|
-
ma = Float(0.0
|
|
253
|
+
ma = Float(0.0)
|
|
265
254
|
|
|
266
255
|
#: A unit vector specifying the direction of the flow in 3D Cartesian coordinates.
|
|
267
256
|
#: Default is ``(1.0, 0, 0)``, which corresponds to flow in the x-direction.
|
|
268
|
-
fdv = CArray(dtype=float64, shape=(3,), value=array((1.0, 0, 0))
|
|
257
|
+
fdv = CArray(dtype=np.float64, shape=(3,), value=np.array((1.0, 0, 0)))
|
|
269
258
|
|
|
270
259
|
#: A unique identifier based on the environment properties. (read-only)
|
|
271
260
|
digest = Property(
|
|
@@ -301,14 +290,14 @@ class UniformFlowEnvironment(Environment):
|
|
|
301
290
|
#
|
|
302
291
|
# - shape `(N,)` if ``mpos`` is a single point, or
|
|
303
292
|
# - shape `(N, M)` if ``mpos`` consists of multiple points.
|
|
304
|
-
if isscalar(mpos):
|
|
305
|
-
mpos = array((0, 0, 0), dtype=float32)[:, newaxis]
|
|
306
|
-
fdv = self.fdv / sqrt((self.fdv * self.fdv).sum())
|
|
307
|
-
mpos = mpos[:, newaxis, :]
|
|
308
|
-
rmv = gpos[:, :, newaxis] - mpos
|
|
309
|
-
rm = sqrt(sum(rmv * rmv, 0))
|
|
310
|
-
macostheta = (self.ma * sum(rmv.reshape((3, -1)) * fdv[:, newaxis], 0) / rm.reshape(-1)).reshape(rm.shape)
|
|
311
|
-
rm *= 1 / (-macostheta + sqrt(macostheta * macostheta - self.ma * self.ma + 1))
|
|
293
|
+
if np.isscalar(mpos):
|
|
294
|
+
mpos = np.array((0, 0, 0), dtype=np.float32)[:, np.newaxis]
|
|
295
|
+
fdv = self.fdv / np.sqrt((self.fdv * self.fdv).sum())
|
|
296
|
+
mpos = mpos[:, np.newaxis, :]
|
|
297
|
+
rmv = gpos[:, :, np.newaxis] - mpos
|
|
298
|
+
rm = np.sqrt(np.sum(rmv * rmv, 0))
|
|
299
|
+
macostheta = (self.ma * np.sum(rmv.reshape((3, -1)) * fdv[:, np.newaxis], 0) / rm.reshape(-1)).reshape(rm.shape)
|
|
300
|
+
rm *= 1 / (-macostheta + np.sqrt(macostheta * macostheta - self.ma * self.ma + 1))
|
|
312
301
|
if rm.shape[1] == 1:
|
|
313
302
|
rm = rm[:, 0]
|
|
314
303
|
return rm
|
|
@@ -355,24 +344,24 @@ class SlotJet(FlowField):
|
|
|
355
344
|
"""
|
|
356
345
|
|
|
357
346
|
#: Exit velocity at the :attr:`slot jet origin<origin>` (nozzle). Default is ``0.0``.
|
|
358
|
-
v0 = Float(0.0
|
|
347
|
+
v0 = Float(0.0)
|
|
359
348
|
|
|
360
349
|
#: The location of the slot nozzle center. Default is ``(0.0, 0.0, 0.0)``.
|
|
361
|
-
origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0))
|
|
350
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)))
|
|
362
351
|
|
|
363
352
|
#: Unit vector representing the flow direction. Default is ``(1.0, 0.0, 0.0)``.
|
|
364
|
-
flow = CArray(dtype=float64, shape=(3,), value=array((1.0, 0.0, 0.0))
|
|
353
|
+
flow = CArray(dtype=np.float64, shape=(3,), value=np.array((1.0, 0.0, 0.0)))
|
|
365
354
|
|
|
366
355
|
#: Unit vector parallel to the slot center plane, used to define the slot orientation.
|
|
367
356
|
#: Default is ``(0.0, 1.0, 0.0)``.
|
|
368
|
-
plane = CArray(dtype=float64, shape=(3,), value=array((0.0, 1.0, 0.0))
|
|
357
|
+
plane = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 1.0, 0.0)))
|
|
369
358
|
|
|
370
359
|
#: Width of the slot (slot diameter). Default is ``0.2``.
|
|
371
|
-
B = Float(0.2
|
|
360
|
+
B = Float(0.2)
|
|
372
361
|
|
|
373
362
|
#: Non-dimensional length of the zone of flow establishment (jet core length).
|
|
374
363
|
#: Default is ``5.2``.
|
|
375
|
-
l = Float(5.2
|
|
364
|
+
l = Float(5.2) # noqa: E741
|
|
376
365
|
|
|
377
366
|
#: A unique identifier based on the field properties. (read-only)
|
|
378
367
|
digest = Property(
|
|
@@ -415,18 +404,18 @@ class SlotJet(FlowField):
|
|
|
415
404
|
with respect to the spatial coordinates.
|
|
416
405
|
"""
|
|
417
406
|
# normalize
|
|
418
|
-
flow = self.flow / norm(self.flow)
|
|
419
|
-
plane = self.plane / norm(self.plane)
|
|
407
|
+
flow = self.flow / spla.norm(self.flow)
|
|
408
|
+
plane = self.plane / spla.norm(self.plane)
|
|
420
409
|
# additional axes of global coordinate system
|
|
421
|
-
yy = -cross(flow, plane)
|
|
422
|
-
zz = cross(flow, yy)
|
|
410
|
+
yy = -np.cross(flow, plane)
|
|
411
|
+
zz = np.cross(flow, yy)
|
|
423
412
|
# distance from slot exit plane
|
|
424
413
|
xx1 = xx - self.origin
|
|
425
414
|
# local coordinate system
|
|
426
|
-
x = dot(flow, xx1)
|
|
427
|
-
y = dot(yy, xx1)
|
|
415
|
+
x = np.dot(flow, xx1)
|
|
416
|
+
y = np.dot(yy, xx1)
|
|
428
417
|
x1 = 0.5668 / self.l * x # C1 in Albertson1950
|
|
429
|
-
h1 = abs(y) + sqrt(pi) * 0.5 * x1 - 0.5 * self.B
|
|
418
|
+
h1 = abs(y) + np.sqrt(np.pi) * 0.5 * x1 - 0.5 * self.B
|
|
430
419
|
if h1 < 0.0:
|
|
431
420
|
# core jet
|
|
432
421
|
Ux = self.v0
|
|
@@ -434,14 +423,14 @@ class SlotJet(FlowField):
|
|
|
434
423
|
Udy = 0
|
|
435
424
|
else:
|
|
436
425
|
# shear layer
|
|
437
|
-
Ux = self.v0 * exp(-h1 * h1 / (2 * x1 * x1))
|
|
438
|
-
Udx = (h1 * h1 / (x * x1 * x1) - sqrt(pi) * 0.5 * h1 / (x * x1)) * Ux
|
|
439
|
-
Udy = -sign(y) * h1 * Ux / (x1 * x1)
|
|
426
|
+
Ux = self.v0 * np.exp(-h1 * h1 / (2 * x1 * x1))
|
|
427
|
+
Udx = (h1 * h1 / (x * x1 * x1) - np.sqrt(np.pi) * 0.5 * h1 / (x * x1)) * Ux
|
|
428
|
+
Udy = -np.sign(y) * h1 * Ux / (x1 * x1)
|
|
440
429
|
# Jacobi matrix
|
|
441
|
-
dU = array(((Udx, 0, 0), (Udy, 0, 0), (0, 0, 0))).T
|
|
430
|
+
dU = np.array(((Udx, 0, 0), (Udy, 0, 0), (0, 0, 0))).T
|
|
442
431
|
# rotation matrix
|
|
443
|
-
R = array((flow, yy, zz)).T
|
|
444
|
-
return dot(R, array((Ux, 0, 0))), dot(dot(R, dU), R.T)
|
|
432
|
+
R = np.array((flow, yy, zz)).T
|
|
433
|
+
return np.dot(R, np.array((Ux, 0, 0))), np.dot(np.dot(R, dU), R.T)
|
|
445
434
|
|
|
446
435
|
|
|
447
436
|
class OpenJet(FlowField):
|
|
@@ -476,17 +465,17 @@ class OpenJet(FlowField):
|
|
|
476
465
|
"""
|
|
477
466
|
|
|
478
467
|
#: Exit velocity at the jet origin (nozzle). Default is ``0.0``.
|
|
479
|
-
v0 = Float(0.0
|
|
468
|
+
v0 = Float(0.0)
|
|
480
469
|
|
|
481
470
|
#: The location of the nozzle center. Default is ``(0.0, 0.0, 0.0)``.
|
|
482
|
-
origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0))
|
|
471
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)))
|
|
483
472
|
|
|
484
473
|
#: Diameter of the nozzle. Default is ``0.2``.
|
|
485
|
-
D = Float(0.2
|
|
474
|
+
D = Float(0.2)
|
|
486
475
|
|
|
487
476
|
#: Non-dimensional length of the zone of flow establishment (jet core length).
|
|
488
477
|
#: Default is ``6.2``. :cite:`Albertson1950`
|
|
489
|
-
l = Float(6.2
|
|
478
|
+
l = Float(6.2) # noqa: E741
|
|
490
479
|
|
|
491
480
|
#: A unique identifier based on the field properties. (read-only)
|
|
492
481
|
digest = Property(
|
|
@@ -530,10 +519,10 @@ class OpenJet(FlowField):
|
|
|
530
519
|
to `y` and `z` are set to zero to avoid division by zero.
|
|
531
520
|
"""
|
|
532
521
|
x, y, z = xx - self.origin
|
|
533
|
-
r = sqrt(y * y + z * z)
|
|
522
|
+
r = np.sqrt(y * y + z * z)
|
|
534
523
|
x1 = 0.5022 / self.l * x # C2 in Albertson1950
|
|
535
524
|
h1 = r + x1 - 0.5 * self.D
|
|
536
|
-
U = self.v0 * exp(-h1 * h1 / (2 * x1 * x1))
|
|
525
|
+
U = self.v0 * np.exp(-h1 * h1 / (2 * x1 * x1))
|
|
537
526
|
if h1 < 0.0:
|
|
538
527
|
Udr = 0.0
|
|
539
528
|
U = self.v0
|
|
@@ -549,9 +538,9 @@ class OpenJet(FlowField):
|
|
|
549
538
|
Udx = 0
|
|
550
539
|
|
|
551
540
|
# flow field
|
|
552
|
-
v = array((U, 0.0, 0.0))
|
|
541
|
+
v = np.array((U, 0.0, 0.0))
|
|
553
542
|
# Jacobi matrix
|
|
554
|
-
dv = array(((Udx, 0.0, 0.0), (Udy, 0.0, 0.0), (Udz, 0.0, 0.0))).T
|
|
543
|
+
dv = np.array(((Udx, 0.0, 0.0), (Udy, 0.0, 0.0), (Udz, 0.0, 0.0))).T
|
|
555
544
|
return v, dv
|
|
556
545
|
|
|
557
546
|
|
|
@@ -568,7 +557,7 @@ class RotatingFlow(FlowField):
|
|
|
568
557
|
- The rotation is assumed to be about the z-axis. The velocity components in the x-y plane are
|
|
569
558
|
determined by the angular velocity :attr:`omega`, while the z-component is constant
|
|
570
559
|
and set by :attr:`v0`.
|
|
571
|
-
- The angular velocity :attr:`omega` is computed as: ``omega = 2 * pi * rps``,
|
|
560
|
+
- The angular velocity :attr:`omega` is computed as: ``omega = 2 * np.pi * rps``,
|
|
572
561
|
with the :attr:`rps` given in revolutions per second (i.e. Hz).
|
|
573
562
|
|
|
574
563
|
Examples
|
|
@@ -577,7 +566,7 @@ class RotatingFlow(FlowField):
|
|
|
577
566
|
>>> import numpy as np
|
|
578
567
|
>>>
|
|
579
568
|
>>> flow = RotatingFlow(rps=1, v0=1.0)
|
|
580
|
-
>>> velocity, jacobian = flow.v(array((1.0, 1.0, 0.0)))
|
|
569
|
+
>>> velocity, jacobian = flow.v(np.array((1.0, 1.0, 0.0)))
|
|
581
570
|
>>> velocity
|
|
582
571
|
array([-6.28318531, 6.28318531, 1. ])
|
|
583
572
|
>>> jacobian
|
|
@@ -586,11 +575,11 @@ class RotatingFlow(FlowField):
|
|
|
586
575
|
[ 0. , 0. , 0. ]])
|
|
587
576
|
"""
|
|
588
577
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
rpm = Property(transient=True
|
|
578
|
+
#: Revolutions per minute (RPM). Default is ``0.0``.
|
|
579
|
+
#: Positive values indicate clockwise rotation of the flow.
|
|
580
|
+
#: This is contrary to the usual definition of the direction of rotation.
|
|
581
|
+
#: Deprecated! Please use the differently defined :attr:`rps` attribute instead.
|
|
582
|
+
rpm = Property(transient=True)
|
|
594
583
|
|
|
595
584
|
def _get_rpm(self):
|
|
596
585
|
warn(
|
|
@@ -612,14 +601,14 @@ class RotatingFlow(FlowField):
|
|
|
612
601
|
|
|
613
602
|
#: Rotational speed in revolutions per second. Negative values indicate clockwise
|
|
614
603
|
#: rigid-body-like rotation of the flow. Default is ``0.0``.
|
|
615
|
-
rps = Float(0.0
|
|
604
|
+
rps = Float(0.0)
|
|
616
605
|
|
|
617
606
|
#: Constant flow velocity in the z-direction. Default is ``0.0``.
|
|
618
|
-
v0 = Float(0.0
|
|
607
|
+
v0 = Float(0.0)
|
|
619
608
|
|
|
620
609
|
#: The location of the center of rotation.
|
|
621
610
|
#: Default is ``(0.0, 0.0, 0.0)``.
|
|
622
|
-
origin = CArray(dtype=float64, shape=(3,), value=array((0.0, 0.0, 0.0))
|
|
611
|
+
origin = CArray(dtype=np.float64, shape=(3,), value=np.array((0.0, 0.0, 0.0)))
|
|
623
612
|
|
|
624
613
|
#: A unique identifier based on the field properties. (read-only)
|
|
625
614
|
digest = Property(
|
|
@@ -634,7 +623,7 @@ class RotatingFlow(FlowField):
|
|
|
634
623
|
|
|
635
624
|
@cached_property
|
|
636
625
|
def _get_omega(self):
|
|
637
|
-
return 2 * pi * self.rps
|
|
626
|
+
return 2 * np.pi * self.rps
|
|
638
627
|
|
|
639
628
|
@cached_property
|
|
640
629
|
def _get_digest(self):
|
|
@@ -682,13 +671,13 @@ class RotatingFlow(FlowField):
|
|
|
682
671
|
W = self.v0
|
|
683
672
|
|
|
684
673
|
# flow field
|
|
685
|
-
v = array((U, V, W))
|
|
674
|
+
v = np.array((U, V, W))
|
|
686
675
|
# Jacobi matrix
|
|
687
|
-
dv = array(((0.0, omega, 0.0), (-omega, 0.0, 0.0), (0.0, 0.0, 0.0))).T
|
|
676
|
+
dv = np.array(((0.0, omega, 0.0), (-omega, 0.0, 0.0), (0.0, 0.0, 0.0))).T
|
|
688
677
|
return v, dv
|
|
689
678
|
|
|
690
679
|
|
|
691
|
-
def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
|
|
680
|
+
def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*np.pi
|
|
692
681
|
"""
|
|
693
682
|
Generate unit vectors equally distributed over a sphere or a portion of it.
|
|
694
683
|
|
|
@@ -706,7 +695,7 @@ def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
|
|
|
706
695
|
The number of points to generate on the sphere.
|
|
707
696
|
|
|
708
697
|
Om : :class:`float`, optional
|
|
709
|
-
The solid angle in steradians to cover on the sphere. Default is ``2 * pi``,
|
|
698
|
+
The solid angle in steradians to cover on the sphere. Default is ``2 * np.pi``,
|
|
710
699
|
which corresponds to a hemisphere. Smaller values result in covering
|
|
711
700
|
a smaller portion of the hemisphere.
|
|
712
701
|
|
|
@@ -743,37 +732,37 @@ def spiral_sphere(N, Om=None, b=None): # noqa: N803 # change to 4*pi
|
|
|
743
732
|
Generate 50 points over half a hemisphere with the z-axis as the center direction:
|
|
744
733
|
|
|
745
734
|
>>> import numpy as np
|
|
746
|
-
>>> points = spiral_sphere(50, Om=np.pi, b=array((0, 0, 1)))
|
|
735
|
+
>>> points = spiral_sphere(50, Om=np.pi, b=np.array((0, 0, 1)))
|
|
747
736
|
>>> points.shape
|
|
748
737
|
(3, 50)
|
|
749
738
|
|
|
750
739
|
Generate 200 points with a different direction vector:
|
|
751
740
|
|
|
752
|
-
>>> points = spiral_sphere(200, b=array((1, 0, 0)))
|
|
741
|
+
>>> points = spiral_sphere(200, b=np.array((1, 0, 0)))
|
|
753
742
|
>>> points.shape
|
|
754
743
|
(3, 200)
|
|
755
744
|
"""
|
|
756
|
-
Om = 2 * pi if Om is None else Om
|
|
757
|
-
b = array((0, 0, 1)) if b is None else b
|
|
745
|
+
Om = 2 * np.pi if Om is None else Om
|
|
746
|
+
b = np.array((0, 0, 1)) if b is None else b
|
|
758
747
|
# first produce 'equally' distributed directions in spherical coords
|
|
759
|
-
o = 4 * pi / Om
|
|
760
|
-
h = -1 + 2 * arange(N) / (N * o - 1.0)
|
|
761
|
-
theta = arccos(h)
|
|
762
|
-
phi = zeros_like(theta)
|
|
748
|
+
o = 4 * np.pi / Om
|
|
749
|
+
h = -1 + 2 * np.arange(N) / (N * o - 1.0)
|
|
750
|
+
theta = np.arccos(h)
|
|
751
|
+
phi = np.zeros_like(theta)
|
|
763
752
|
for i, hk in enumerate(h[1:]):
|
|
764
|
-
phi[i + 1] = phi[i] + 3.6 / sqrt(N * o * (1 - hk * hk)) % (2 * pi)
|
|
753
|
+
phi[i + 1] = phi[i] + 3.6 / np.sqrt(N * o * (1 - hk * hk)) % (2 * np.pi)
|
|
765
754
|
# translate to cartesian coords
|
|
766
|
-
xyz = vstack((sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)))
|
|
755
|
+
xyz = np.vstack((np.sin(theta) * np.cos(phi), np.sin(theta) * np.sin(phi), np.cos(theta)))
|
|
767
756
|
# mirror everything on a plane so that b points into the center
|
|
768
757
|
a = xyz[:, 0]
|
|
769
|
-
b = b / norm(b)
|
|
770
|
-
ab = (a - b)[:, newaxis]
|
|
771
|
-
if norm(ab) < 1e-10:
|
|
758
|
+
b = b / spla.norm(b)
|
|
759
|
+
ab = (a - b)[:, np.newaxis]
|
|
760
|
+
if spla.norm(ab) < 1e-10:
|
|
772
761
|
return xyz
|
|
773
762
|
# this is the Householder matrix for mirroring
|
|
774
|
-
H = identity(3) - dot(ab, ab.T) / dot(ab.T, a)
|
|
763
|
+
H = np.identity(3) - np.dot(ab, ab.T) / np.dot(ab.T, a)
|
|
775
764
|
# actual mirroring
|
|
776
|
-
return dot(H, xyz)
|
|
765
|
+
return np.dot(H, xyz)
|
|
777
766
|
|
|
778
767
|
|
|
779
768
|
class GeneralFlowEnvironment(Environment):
|
|
@@ -809,14 +798,14 @@ class GeneralFlowEnvironment(Environment):
|
|
|
809
798
|
|
|
810
799
|
#: The flow field object describing the velocity field,
|
|
811
800
|
#: which must be an instance of :class:`~acoular.environments.FlowField`.
|
|
812
|
-
ff = Instance(FlowField
|
|
801
|
+
ff = Instance(FlowField)
|
|
813
802
|
|
|
814
803
|
#: The number of rays used per solid angle :math:`\Omega`. Defaults to ``200``.
|
|
815
|
-
N = Int(200
|
|
804
|
+
N = Int(200)
|
|
816
805
|
|
|
817
806
|
#: The maximum solid angle (in steradians) used in the ray-tracing algorithm.
|
|
818
807
|
#: Default is :obj:`numpy.pi`.
|
|
819
|
-
Om = Float(pi
|
|
808
|
+
Om = Float(np.pi)
|
|
820
809
|
|
|
821
810
|
#: A unique identifier based on the environment properties. (read-only)
|
|
822
811
|
digest = Property(
|
|
@@ -834,10 +823,10 @@ class GeneralFlowEnvironment(Environment):
|
|
|
834
823
|
def _r(self, gpos, mpos=0.0):
|
|
835
824
|
c = self.c
|
|
836
825
|
|
|
837
|
-
if isscalar(mpos):
|
|
838
|
-
mpos = array((0, 0, 0), dtype=float32)[:, newaxis]
|
|
826
|
+
if np.isscalar(mpos):
|
|
827
|
+
mpos = np.array((0, 0, 0), dtype=np.float32)[:, np.newaxis]
|
|
839
828
|
|
|
840
|
-
gt = empty((gpos.shape[-1], mpos.shape[-1]))
|
|
829
|
+
gt = np.empty((gpos.shape[-1], mpos.shape[-1]))
|
|
841
830
|
for micnum, x0 in enumerate(mpos.T):
|
|
842
831
|
key = x0.tobytes() # make array hashable
|
|
843
832
|
try:
|
|
@@ -888,16 +877,16 @@ class GeneralFlowEnvironment(Environment):
|
|
|
888
877
|
x = y[0:3]
|
|
889
878
|
s = y[3:6]
|
|
890
879
|
vv, dv = v(x)
|
|
891
|
-
sa = sqrt(s[0] * s[0] + s[1] * s[1] + s[2] * s[2])
|
|
892
|
-
x = empty(6)
|
|
880
|
+
sa = np.sqrt(s[0] * s[0] + s[1] * s[1] + s[2] * s[2])
|
|
881
|
+
x = np.empty(6)
|
|
893
882
|
x[0:3] = c * s / sa - vv # time reversal
|
|
894
|
-
x[3:6] = dot(s, -dv.T) # time reversal
|
|
883
|
+
x[3:6] = np.dot(s, -dv.T) # time reversal
|
|
895
884
|
return x
|
|
896
885
|
|
|
897
886
|
# integration along a single ray
|
|
898
887
|
def fr(x0, n0, rmax, dt, v, xyz, t):
|
|
899
|
-
s0 = n0 / (c + dot(v(x0)[0], n0))
|
|
900
|
-
y0 = hstack((x0, s0))
|
|
888
|
+
s0 = n0 / (c + np.dot(v(x0)[0], n0))
|
|
889
|
+
y0 = np.hstack((x0, s0))
|
|
901
890
|
oo = ode(f1)
|
|
902
891
|
oo.set_f_params(v)
|
|
903
892
|
oo.set_integrator(
|
|
@@ -909,18 +898,18 @@ class GeneralFlowEnvironment(Environment):
|
|
|
909
898
|
while oo.successful():
|
|
910
899
|
xyz.append(oo.y[0:3])
|
|
911
900
|
t.append(oo.t)
|
|
912
|
-
if norm(oo.y[0:3] - x0) > rmax:
|
|
901
|
+
if spla.norm(oo.y[0:3] - x0) > rmax:
|
|
913
902
|
break
|
|
914
903
|
oo.integrate(oo.t + dt)
|
|
915
904
|
|
|
916
905
|
gs2 = roi.shape[-1]
|
|
917
906
|
vv = self.ff.v
|
|
918
|
-
NN = int(sqrt(self.N))
|
|
907
|
+
NN = int(np.sqrt(self.N))
|
|
919
908
|
xe = roi.mean(1) # center of grid
|
|
920
|
-
r = x0[:, newaxis] - roi
|
|
921
|
-
rmax = sqrt((r * r).sum(0).max()) # maximum distance
|
|
909
|
+
r = x0[:, np.newaxis] - roi
|
|
910
|
+
rmax = np.sqrt((r * r).sum(0).max()) # maximum distance
|
|
922
911
|
nv = spiral_sphere(self.N, self.Om, b=xe - x0)
|
|
923
|
-
rstep = rmax / sqrt(self.N)
|
|
912
|
+
rstep = rmax / np.sqrt(self.N)
|
|
924
913
|
rmax += rstep
|
|
925
914
|
tstep = rstep / c
|
|
926
915
|
xyz = []
|
|
@@ -930,13 +919,13 @@ class GeneralFlowEnvironment(Environment):
|
|
|
930
919
|
fr(x0, n0, rmax, tstep, vv, xyz, t)
|
|
931
920
|
if i and i % NN == 0:
|
|
932
921
|
if not lastind:
|
|
933
|
-
dd = ConvexHull(vstack((roi.T, xyz)), incremental=True)
|
|
922
|
+
dd = ConvexHull(np.vstack((roi.T, xyz)), incremental=True)
|
|
934
923
|
else:
|
|
935
924
|
dd.add_points(xyz[lastind:], restart=True)
|
|
936
925
|
lastind = len(xyz)
|
|
937
926
|
# ConvexHull includes grid if no grid points on hull
|
|
938
927
|
if dd.simplices.min() >= gs2:
|
|
939
928
|
break
|
|
940
|
-
xyz = array(xyz)
|
|
941
|
-
t = array(t)
|
|
929
|
+
xyz = np.array(xyz)
|
|
930
|
+
t = np.array(t)
|
|
942
931
|
return LinearNDInterpolator(xyz, t)
|