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/grids.py CHANGED
@@ -4,6 +4,24 @@
4
4
  """
5
5
  Implement support for multidimensional grids and integration sectors.
6
6
 
7
+ .. inheritance-diagram::
8
+ acoular.grids.Grid
9
+ acoular.grids.RectGrid
10
+ acoular.grids.RectGrid3D
11
+ acoular.grids.ImportGrid
12
+ acoular.grids.LineGrid
13
+ acoular.grids.MergeGrid
14
+ :top-classes:
15
+ acoular.grids.Grid
16
+ :parts: 1
17
+
18
+ .. inheritance-diagram::
19
+ acoular.grids.Sector
20
+ :include-subclasses:
21
+ :top-classes:
22
+ acoular.grids.Sector
23
+ :parts: 1
24
+
7
25
  .. autosummary::
8
26
  :toctree: generated/
9
27
 
@@ -30,31 +48,8 @@ import xml.dom.minidom
30
48
  from abc import abstractmethod
31
49
  from pathlib import Path
32
50
 
33
- from numpy import (
34
- absolute,
35
- append,
36
- arange,
37
- argmin,
38
- array,
39
- asarray,
40
- concatenate,
41
- copysign,
42
- fabs,
43
- inf,
44
- isscalar,
45
- ma,
46
- mgrid,
47
- newaxis,
48
- ones,
49
- ones_like,
50
- s_,
51
- sum, # noqa: A004
52
- tile,
53
- unique,
54
- where,
55
- zeros,
56
- )
57
- from scipy.linalg import norm
51
+ import numpy as np
52
+ import scipy.linalg as spla
58
53
 
59
54
  # from matplotlib.path import Path
60
55
  from scipy.spatial import Delaunay
@@ -73,14 +68,13 @@ from traits.api import (
73
68
  Union,
74
69
  cached_property,
75
70
  observe,
76
- on_trait_change,
77
71
  property_depends_on,
78
72
  )
79
73
  from traits.trait_errors import TraitError
80
74
 
81
75
  # acoular imports
82
- from .deprecation import deprecated_alias
83
76
  from .internal import digest, ldigest
77
+ from .tools.utils import Polygon
84
78
 
85
79
 
86
80
  def in_hull(p, hull, border=True, tol=0):
@@ -135,174 +129,6 @@ def in_hull(p, hull, border=True, tol=0):
135
129
  return hull.find_simplex(p, tol=tol) > 0
136
130
 
137
131
 
138
- def _det(xvert, yvert):
139
- xvert = asarray(xvert, dtype=float)
140
- yvert = asarray(yvert, dtype=float)
141
- x_prev = concatenate(([xvert[-1]], xvert[:-1]))
142
- y_prev = concatenate(([yvert[-1]], yvert[:-1]))
143
- return sum(yvert * x_prev - xvert * y_prev, axis=0)
144
-
145
-
146
- class Polygon:
147
- """
148
- Create an object representing a general polygon in a 2D plane.
149
-
150
- This class allows defining a polygon by specifying the coordinates of its vertices and provides
151
- methods for checking whether a set of points lies inside the polygon, or if a point is closer to
152
- a side or vertex of the polygon.
153
-
154
- Parameters
155
- ----------
156
- x : array_like
157
- Array of x-coordinates of the vertices that define the polygon. These coordinates should
158
- form a closed shape (i.e., the last point should be the same as the first point).
159
-
160
- y : array_like
161
- Array of y-coordinates of the vertices that define the polygon. These coordinates should
162
- correspond to the x-coordinates, forming a closed shape.
163
-
164
- Attributes
165
- ----------
166
- x : :class:`numpy.ndarray`
167
- Array of x-coordinates of the polygon vertices.
168
-
169
- y : :class:`numpy.ndarray`
170
- Array of y-coordinates of the polygon vertices.
171
- """
172
-
173
- def __init__(self, x, y):
174
- if len(x) != len(y):
175
- msg = 'x and y must be equally sized.'
176
- raise IndexError(msg)
177
- self.x = asarray(x, dtype=float)
178
- self.y = asarray(y, dtype=float)
179
- # Closes the polygon if were open
180
- x1, y1 = x[0], y[0]
181
- xn, yn = x[-1], y[-1]
182
- if x1 != xn or y1 != yn:
183
- self.x = concatenate((self.x, [x1]))
184
- self.y = concatenate((self.y, [y1]))
185
- # Anti-clockwise coordinates
186
- if _det(self.x, self.y) < 0:
187
- self.x = self.x[::-1]
188
- self.y = self.y[::-1]
189
-
190
- def is_inside(self, xpoint, ypoint, smalld=1e-12):
191
- """
192
- Check if a point or set of points are inside the polygon.
193
-
194
- Parameters
195
- ----------
196
- xpoint : :class:`float` or array_like
197
- Array of x-coordinates of the points to be tested.
198
-
199
- ypoint : :class:`float` or array_like
200
- Array of y-coordinates of the points to be tested.
201
-
202
- smalld : :class:`float`, optional
203
- Tolerance used for floating point comparisons when checking if a point is exactly on a
204
- polygon's edge. The default value is ``1e-12``.
205
-
206
- Returns
207
- -------
208
- :class:`float` or array_like
209
- The distance from the point to the nearest point on the polygon. The values returned
210
- have the following meanings:
211
- - ``mindst < 0``: Point is outside the polygon.
212
- - ``mindst = 0``: Point is on an edge of the polygon.
213
- - ``mindst > 0``: Point is inside the polygon.
214
-
215
- Notes
216
- -----
217
- The method uses an improved algorithm based on Nordbeck and Rydstedt for determining
218
- whether a point is inside a polygon :cite:`SLOAN198545`.
219
- """
220
- xpoint = asarray(xpoint, dtype=float)
221
- ypoint = asarray(ypoint, dtype=float)
222
- # Scalar to array
223
- if xpoint.shape == ():
224
- xpoint = array([xpoint], dtype=float)
225
- ypoint = array([ypoint], dtype=float)
226
- scalar = True
227
- else:
228
- scalar = False
229
- # Check consistency
230
- if xpoint.shape != ypoint.shape:
231
- msg = 'x and y has different shapes'
232
- raise IndexError(msg)
233
- # If snear = True: Dist to nearest side < nearest vertex
234
- # If snear = False: Dist to nearest vertex < nearest side
235
- snear = ma.masked_all(xpoint.shape, dtype=bool)
236
- # Initialize arrays
237
- mindst = ones_like(xpoint, dtype=float) * inf
238
- j = ma.masked_all(xpoint.shape, dtype=int)
239
- x = self.x
240
- y = self.y
241
- n = len(x) - 1 # Number of sides/vertices defining the polygon
242
- # Loop over each side defining polygon
243
- for i in range(n):
244
- d = ones_like(xpoint, dtype=float) * inf
245
- # Start of side has coords (x1, y1)
246
- # End of side has coords (x2, y2)
247
- # Point has coords (xpoint, ypoint)
248
- x1 = x[i]
249
- y1 = y[i]
250
- x21 = x[i + 1] - x1
251
- y21 = y[i + 1] - y1
252
- x1p = x1 - xpoint
253
- y1p = y1 - ypoint
254
- # Points on infinite line defined by
255
- # x = x1 + t * (x1 - x2)
256
- # y = y1 + t * (y1 - y2)
257
- # where
258
- # t = 0 at (x1, y1)
259
- # t = 1 at (x2, y2)
260
- # Find where normal passing through (xpoint, ypoint) intersects
261
- # infinite line
262
- t = -(x1p * x21 + y1p * y21) / (x21**2 + y21**2)
263
- tlt0 = t < 0
264
- tle1 = (t >= 0) & (t <= 1)
265
- # Normal intersects side
266
- d[tle1] = (x1p[tle1] + t[tle1] * x21) ** 2 + (y1p[tle1] + t[tle1] * y21) ** 2
267
- # Normal does not intersects side
268
- # Point is closest to vertex (x1, y1)
269
- # Compute square of distance to this vertex
270
- d[tlt0] = x1p[tlt0] ** 2 + y1p[tlt0] ** 2
271
- # Store distances
272
- mask = d < mindst
273
- mindst[mask] = d[mask]
274
- j[mask] = i
275
- # Point is closer to (x1, y1) than any other vertex or side
276
- snear[mask & tlt0] = False
277
- # Point is closer to this side than to any other side or vertex
278
- snear[mask & tle1] = True
279
- if ma.count(snear) != snear.size:
280
- msg = 'Error computing distances'
281
- raise IndexError(msg)
282
- mindst **= 0.5
283
- # Point is closer to its nearest vertex than its nearest side, check if
284
- # nearest vertex is concave.
285
- # If the nearest vertex is concave then point is inside the polygon,
286
- # else the point is outside the polygon.
287
- jo = j.copy()
288
- jo[j == 0] -= 1
289
- area = _det([x[j + 1], x[j], x[jo - 1]], [y[j + 1], y[j], y[jo - 1]])
290
- mindst[~snear] = copysign(mindst, area)[~snear]
291
- # Point is closer to its nearest side than to its nearest vertex, check
292
- # if point is to left or right of this side.
293
- # If point is to left of side it is inside polygon, else point is
294
- # outside polygon.
295
- area = _det([x[j], x[j + 1], xpoint], [y[j], y[j + 1], ypoint])
296
- mindst[snear] = copysign(mindst, area)[snear]
297
- # Point is on side of polygon
298
- mindst[fabs(mindst) < smalld] = 0
299
- # If input values were scalar then the output should be too
300
- if scalar:
301
- mindst = float(mindst)
302
- return mindst
303
-
304
-
305
- @deprecated_alias({'gpos': 'pos'}, removal_version='25.10')
306
132
  class Grid(ABCHasStrictTraits):
307
133
  """
308
134
  Abstract base class for grid geometries.
@@ -312,28 +138,27 @@ class Grid(ABCHasStrictTraits):
312
138
  implementations and should not be instantiated directly as it lacks concrete functionality.
313
139
 
314
140
  .. _units_note_grids:
141
+ .. admonition:: Unit of length
315
142
 
316
- Unit System
317
- -----------
318
- The source code is agnostic to the unit of length. The positions' coordinates are assumed to be
319
- in meters. This is consistent with the standard :class:`~acoular.environments.Environment` class
320
- which uses the speed of sound at 20°C at sea level under standard atmosphere pressure in m/s.
321
- If the positions' coordinates are provided in a unit other than meter, it is advisable to change
322
- the :attr:`~acoular.environments.Environment.c` attribute to match the given unit.
143
+ The source code is agnostic to the unit of length. The positions' coordinates are assumed to
144
+ be in meters. This is consistent with the standard :class:`~acoular.environments.Environment`
145
+ class which uses the speed of sound at 20°C at sea level under standard atmosphere pressure in
146
+ m/s. If the positions' coordinates are provided in a unit other than meter, it is advisable to
147
+ change the :attr:`~acoular.environments.Environment.c` attribute to match the given unit.
323
148
  """
324
149
 
325
150
  #: The total number of grid points. This property is automatically calculated based on other
326
151
  #: defining attributes of the grid. (read-only)
327
- size = Property(desc='overall number of grid points')
152
+ size = Property()
328
153
 
329
154
  #: The shape of the grid, represented as a tuple. Primarily useful for Cartesian grids.
330
155
  #: (read-only)
331
- shape = Property(desc='grid shape as tuple')
156
+ shape = Property()
332
157
 
333
158
  #: The grid positions represented as a (3, :attr:`size`) array of :class:`floats<float>`.
334
159
  #: (read-only)
335
- #: All positions' coordinates are in meters by default (see :ref:`notes <units_note_grids>`).
336
- pos = Property(desc='x, y, z positions of grid points')
160
+ #: All positions' coordinates are in meters by default (:ref:`see here <units_note_grids>`).
161
+ pos = Property()
337
162
 
338
163
  #: A unique identifier for the grid, based on its properties. (read-only)
339
164
  digest = Property
@@ -385,7 +210,7 @@ class Grid(ABCHasStrictTraits):
385
210
  # construct grid-shaped array with "True" entries where sector is
386
211
  xyi = sector.contains(xpos).reshape(self.shape)
387
212
  # return indices of "True" entries
388
- return where(xyi)
213
+ return np.where(xyi)
389
214
 
390
215
  def export_gpos(self, filename):
391
216
  """
@@ -446,7 +271,7 @@ class Grid(ABCHasStrictTraits):
446
271
  pos_str = ' '.join(
447
272
  [
448
273
  ' <pos',
449
- f'Name="Point {i+1}"',
274
+ f'Name="Point {i + 1}"',
450
275
  f'x="{self.pos[0, i]}"',
451
276
  f'y="{self.pos[1, i]}"',
452
277
  f'z="{self.pos[2, i]}"',
@@ -457,7 +282,6 @@ class Grid(ABCHasStrictTraits):
457
282
  f.write('</Grid>')
458
283
 
459
284
 
460
- @deprecated_alias({'gpos': 'pos'}, read_only=True, removal_version='25.10')
461
285
  class RectGrid(Grid):
462
286
  """
463
287
  Provides a 2D Cartesian grid for beamforming results.
@@ -467,31 +291,31 @@ class RectGrid(Grid):
467
291
  """
468
292
 
469
293
  #: The lower x-limit that defines the grid. Default is ``-1``.
470
- x_min = Float(-1.0, desc='minimum x-value')
294
+ x_min = Float(-1.0)
471
295
 
472
296
  #: The upper x-limit that defines the grid. Default is ``1``.
473
- x_max = Float(1.0, desc='maximum x-value')
297
+ x_max = Float(1.0)
474
298
 
475
299
  #: The lower y-limit that defines the grid. Default is ``-1``.
476
- y_min = Float(-1.0, desc='minimum y-value')
300
+ y_min = Float(-1.0)
477
301
 
478
302
  #: The upper y-limit that defines the grid. Default is ``1``.
479
- y_max = Float(1.0, desc='maximum y-value')
303
+ y_max = Float(1.0)
480
304
 
481
305
  #: The constant z-coordinate of the grid plane. Default is ``1.0``.
482
- z = Float(1.0, desc='position on z-axis')
306
+ z = Float(1.0)
483
307
 
484
308
  #: The side length of each cell. Default is ``0.1``.
485
- increment = Float(0.1, desc='step size')
309
+ increment = Float(0.1)
486
310
 
487
311
  #: Number of grid points along x-axis. (read-only)
488
- nxsteps = Property(desc='number of grid points along x-axis')
312
+ nxsteps = Property()
489
313
 
490
314
  #: Number of grid points along y-axis. (read-only)
491
- nysteps = Property(desc='number of grid points along y-axis')
315
+ nysteps = Property()
492
316
 
493
317
  #: The grid's extension in :obj:`matplotlib.pyplot.imshow` compatible form. (read-only)
494
- extent = Property(desc='grid extent as (x_min, x_max, y_min, y_max)')
318
+ extent = Property()
495
319
 
496
320
  #: A unique identifier for the grid, based on its properties. (read-only)
497
321
  digest = Property(
@@ -526,7 +350,7 @@ class RectGrid(Grid):
526
350
 
527
351
  @property_depends_on(['x_min', 'x_max', 'y_min', 'y_max', 'increment'])
528
352
  def _get_pos(self):
529
- bpos = mgrid[
353
+ bpos = np.mgrid[
530
354
  self.x_min : self.x_max : self.nxsteps * 1j,
531
355
  self.y_min : self.y_max : self.nysteps * 1j,
532
356
  self.z : self.z + 0.1,
@@ -642,36 +466,36 @@ class RectGrid(Grid):
642
466
  dr2 = (xpos[0, :] - r[0]) ** 2 + (xpos[1, :] - r[1]) ** 2
643
467
  # array with true/false entries
644
468
  inds = dr2 <= r[2] ** 2
645
- for np in arange(self.size)[inds]: # np -- points in x2-circle
646
- xi, yi = self.index(xpos[0, np], xpos[1, np])
469
+ for n_p in np.arange(self.size)[inds]: # n_p -- points in x2-circle
470
+ xi, yi = self.index(xpos[0, n_p], xpos[1, n_p])
647
471
  xis += [xi]
648
472
  yis += [yi]
649
473
  if not (xis and yis): # if no points in circle, take nearest one
650
474
  return self.index(r[0], r[1])
651
- return array(xis), array(yis)
475
+ return np.array(xis), np.array(yis)
652
476
  if len(r) == 4: # rectangular subdomain - old functionality
653
477
  xi1, yi1 = self.index(min(r[0], r[2]), min(r[1], r[3]))
654
478
  xi2, yi2 = self.index(max(r[0], r[2]), max(r[1], r[3]))
655
- return s_[xi1 : xi2 + 1], s_[yi1 : yi2 + 1]
479
+ return np.s_[xi1 : xi2 + 1], np.s_[yi1 : yi2 + 1]
656
480
  xpos = self.pos
657
481
  xis = []
658
482
  yis = []
659
483
  # replaced matplotlib Path by numpy
660
- # p = Path(array(r).reshape(-1,2))
484
+ # p = Path(np.array(r).reshape(-1,2))
661
485
  # inds = p.contains_points()
662
- # inds = in_poly(xpos[:2,:].T,array(r).reshape(-1,2))
663
- poly = Polygon(array(r).reshape(-1, 2)[:, 0], array(r).reshape(-1, 2)[:, 1])
486
+ # inds = in_poly(xpos[:2,:].T,np.array(r).reshape(-1,2))
487
+ poly = Polygon(np.array(r).reshape(-1, 2)[:, 0], np.array(r).reshape(-1, 2)[:, 1])
664
488
  dists = poly.is_inside(xpos[0, :], xpos[1, :])
665
489
  inds = dists >= 0
666
- for np in arange(self.size)[inds]: # np -- points in x2-circle
667
- xi, yi = self.index(xpos[0, np], xpos[1, np])
490
+ for n_p in np.arange(self.size)[inds]: # n_p -- points in x2-circle
491
+ xi, yi = self.index(xpos[0, n_p], xpos[1, n_p])
668
492
  xis += [xi]
669
493
  yis += [yi]
670
494
  if not (xis and yis): # if no points inside, take nearest to center
671
- center = array(r).reshape(-1, 2).mean(0)
495
+ center = np.array(r).reshape(-1, 2).mean(0)
672
496
  return self.index(center[0], center[1])
673
- return array(xis), array(yis)
674
- # return arange(self.size)[inds]
497
+ return np.array(xis), np.array(yis)
498
+ # return np.arange(self.size)[inds]
675
499
 
676
500
 
677
501
  class RectGrid3D(RectGrid):
@@ -682,39 +506,38 @@ class RectGrid3D(RectGrid):
682
506
  """
683
507
 
684
508
  #: The lower z-limit that defines the grid. Default is ``-1.0``.
685
- z_min = Float(-1.0, desc='minimum z-value')
509
+ z_min = Float(-1.0)
686
510
 
687
511
  #: The upper z-limit that defines the grid. Default is ``1.0``.
688
- z_max = Float(1.0, desc='maximum z-value')
512
+ z_max = Float(1.0)
689
513
 
690
514
  #: Number of grid points along x-axis. (read-only)
691
- nxsteps = Property(desc='number of grid points along x-axis')
515
+ nxsteps = Property()
692
516
 
693
517
  #: Number of grid points along y-axis. (read-only)
694
- nysteps = Property(desc='number of grid points along y-axis')
518
+ nysteps = Property()
695
519
 
696
520
  #: Number of grid points along z-axis. (read-only)
697
- nzsteps = Property(desc='number of grid points along z-axis')
521
+ nzsteps = Property()
698
522
 
699
- # Private trait for increment handling
700
- _increment = Union(Float(), CArray(shape=(3,), dtype=float), default_value=0.1, desc='step size')
523
+ _increment = Union(Float(), CArray(shape=(3,), dtype=float), default_value=0.1)
701
524
 
702
525
  #: The cell side length for the grid. This can either be a scalar (same increments in all 3
703
526
  #: dimensions) or a (3,) array of :class:`tuple` of :class:`floats<float>` with respective
704
527
  #: increments in x-, y-, and z-direction. Default is ``0.1``.
705
- increment = Property(desc='step size')
528
+ increment = Property()
706
529
 
707
530
  def _get_increment(self):
708
531
  return self._increment
709
532
 
710
533
  def _set_increment(self, increment):
711
- if isscalar(increment):
534
+ if np.isscalar(increment):
712
535
  try:
713
- self._increment = absolute(float(increment))
536
+ self._increment = np.abs(float(increment))
714
537
  except ValueError as ve:
715
538
  raise TraitError(args=self, name='increment', info='Float or CArray(3,)', value=increment) from ve
716
539
  elif len(increment) == 3:
717
- self._increment = array(increment, dtype=float)
540
+ self._increment = np.array(increment, dtype=float)
718
541
  else:
719
542
  raise (TraitError(args=self, name='increment', info='Float or CArray(3,)', value=increment))
720
543
 
@@ -733,28 +556,28 @@ class RectGrid3D(RectGrid):
733
556
 
734
557
  @property_depends_on(['x_min', 'x_max', '_increment'])
735
558
  def _get_nxsteps(self):
736
- i = abs(self.increment) if isscalar(self.increment) else abs(self.increment[0])
559
+ i = abs(self.increment) if np.isscalar(self.increment) else abs(self.increment[0])
737
560
  if i != 0:
738
561
  return int(round((abs(self.x_max - self.x_min) + i) / i))
739
562
  return 1
740
563
 
741
564
  @property_depends_on(['y_min', 'y_max', '_increment'])
742
565
  def _get_nysteps(self):
743
- i = abs(self.increment) if isscalar(self.increment) else abs(self.increment[1])
566
+ i = abs(self.increment) if np.isscalar(self.increment) else abs(self.increment[1])
744
567
  if i != 0:
745
568
  return int(round((abs(self.y_max - self.y_min) + i) / i))
746
569
  return 1
747
570
 
748
571
  @property_depends_on(['z_min', 'z_max', '_increment'])
749
572
  def _get_nzsteps(self):
750
- i = abs(self.increment) if isscalar(self.increment) else abs(self.increment[2])
573
+ i = abs(self.increment) if np.isscalar(self.increment) else abs(self.increment[2])
751
574
  if i != 0:
752
575
  return int(round((abs(self.z_max - self.z_min) + i) / i))
753
576
  return 1
754
577
 
755
578
  @property_depends_on('digest')
756
579
  def _get_pos(self):
757
- bpos = mgrid[
580
+ bpos = np.mgrid[
758
581
  self.x_min : self.x_max : self.nxsteps * 1j,
759
582
  self.y_min : self.y_max : self.nysteps * 1j,
760
583
  self.z_min : self.z_max : self.nzsteps * 1j,
@@ -810,7 +633,7 @@ class RectGrid3D(RectGrid):
810
633
  if z < self.z_min or z > self.z_max:
811
634
  msg = f'z-value out of range {z:f} ({self.z_min:f}, {self.z_max:f})'
812
635
  raise ValueError(msg)
813
- if isscalar(self.increment):
636
+ if np.isscalar(self.increment):
814
637
  incx = incy = incz = self.increment
815
638
  else:
816
639
  incx, incy, incz = self.increment
@@ -863,10 +686,9 @@ class RectGrid3D(RectGrid):
863
686
  """
864
687
  xi1, yi1, zi1 = self.index(min(x1, x2), min(y1, y2), min(z1, z2))
865
688
  xi2, yi2, zi2 = self.index(max(x1, x2), max(y1, y2), max(z1, z2))
866
- return s_[xi1 : xi2 + 1], s_[yi1 : yi2 + 1], s_[zi1 : zi2 + 1]
689
+ return np.s_[xi1 : xi2 + 1], np.s_[yi1 : yi2 + 1], np.s_[zi1 : zi2 + 1]
867
690
 
868
691
 
869
- @deprecated_alias({'from_file': 'file', 'gpos_file': 'pos'}, removal_version='25.10')
870
692
  class ImportGrid(Grid):
871
693
  """
872
694
  Load a 3D grid from an XML file.
@@ -876,13 +698,14 @@ class ImportGrid(Grid):
876
698
  """
877
699
 
878
700
  #: Name of the .xml-file from which to read the data.
879
- file = Union(None, File(filter=['*.xml'], exists=True), desc='name of the xml file to import')
701
+ file = Union(None, File(filter=['*.xml'], exists=True))
880
702
 
881
- _gpos = CArray(dtype=float, desc='x, y, z position of all Grid Points')
703
+ #: x, y, z position of all Grid Points
704
+ _gpos = CArray(dtype=float)
882
705
 
883
706
  #: Names of subgrids for each point.
884
707
  #: This is an optional property, typically used when grids are divided into named subregions.
885
- subgrids = CArray(desc='names of subgrids for each point')
708
+ subgrids = CArray()
886
709
 
887
710
  #: A unique identifier for the grid, based on its properties. (read-only)
888
711
  digest = Property(depends_on=['_gpos'])
@@ -906,8 +729,8 @@ class ImportGrid(Grid):
906
729
  def _set_pos(self, pos):
907
730
  self._gpos = pos
908
731
 
909
- @on_trait_change('file')
910
- def import_gpos(self):
732
+ @observe('file')
733
+ def _import_pos(self, event): # noqa ARG002
911
734
  """
912
735
  Import the grid point locations and subgrid names from an XML file.
913
736
 
@@ -924,14 +747,14 @@ class ImportGrid(Grid):
924
747
 
925
748
  >>> import numpy as np
926
749
  >>>
927
- >>> # Grid 1: ten points aranged in a circle in the x-y plane at z=0
750
+ >>> # Grid 1: ten points arranged in a circle in the x-y plane at z=0
928
751
  >>> args = 2 * np.pi * np.arange(10) / 10
929
752
  >>> x1 = np.cos(args)
930
753
  >>> y1 = np.sin(args)
931
754
  >>> z1 = np.zeros_like(x1)
932
755
  >>> grid1 = np.vstack([x1, y1, z1]).T
933
756
  >>>
934
- >>> # Grid 2: nine points aranged in a mesh grid the the x-y plane at z=1
757
+ >>> # Grid 2: nine points arranged in a mesh grid in the x-y plane at z=1
935
758
  >>> a = np.linspace(-1, 1, 3)
936
759
  >>> x2, y2 = np.meshgrid(a, a)
937
760
  >>> z2 = np.ones_like(x2)
@@ -1030,11 +853,10 @@ class ImportGrid(Grid):
1030
853
  for el in doc.getElementsByTagName('pos'):
1031
854
  names.append(el.getAttribute('subgrid'))
1032
855
  xyz.append([float(el.getAttribute(a)) for a in 'xyz'])
1033
- self._gpos = array(xyz, 'd').swapaxes(0, 1)
1034
- self.subgrids = array(names)
856
+ self._gpos = np.array(xyz, 'd').swapaxes(0, 1)
857
+ self.subgrids = np.array(names)
1035
858
 
1036
859
 
1037
- @deprecated_alias({'gpos': 'pos', 'numpoints': 'num_points'}, read_only=['gpos'], removal_version='25.10')
1038
860
  class LineGrid(Grid):
1039
861
  """
1040
862
  Define a 3D grid for a line geometry.
@@ -1070,22 +892,22 @@ class LineGrid(Grid):
1070
892
  loc = Tuple((0.0, 0.0, 0.0))
1071
893
 
1072
894
  #: A vector defining the orientation of the line in 3D space. Default is ``(1.0, 0.0, 0.0)``.
1073
- direction = Tuple((1.0, 0.0, 0.0), desc='Line orientation ')
895
+ direction = Tuple((1.0, 0.0, 0.0))
1074
896
 
1075
897
  #: Total length of the line. Default is ``1.0``.
1076
- length = Float(1, desc='length of the line source')
898
+ length = Float(1)
1077
899
 
1078
900
  #: Number of grid points along the line. Default is ``1``.
1079
- num_points = Int(1, desc='length of the line source')
901
+ num_points = Int(1)
1080
902
 
1081
903
  #: The total number of grid points. Automatically updated when other grid-defining attributes
1082
904
  #: are set. (read-only)
1083
- size = Property(desc='overall number of grid points')
905
+ size = Property()
1084
906
 
1085
907
  #: A (3, :attr:`size`) array containing the x, y, and z positions of the grid points.
1086
908
  #: (read-only)
1087
- #: All positions' coordinates are in meters by default (see :ref:`notes <units_note_grids>`).
1088
- pos = Property(desc='x, y, z positions of grid points')
909
+ #: All positions' coordinates are in meters by default (:ref:`see here <units_note_grids>`).
910
+ pos = Property()
1089
911
 
1090
912
  #: A unique identifier for the grid, based on its properties. (read-only)
1091
913
  digest = Property(
@@ -1107,15 +929,14 @@ class LineGrid(Grid):
1107
929
  @property_depends_on(['num_points', 'length', 'direction', 'loc'])
1108
930
  def _get_pos(self):
1109
931
  dist = self.length / (self.num_points - 1)
1110
- loc = array(self.loc, dtype=float).reshape((3, 1))
1111
- direc_n = array(self.direction) / norm(self.direction)
1112
- pos = zeros((self.num_points, 3))
932
+ loc = np.array(self.loc, dtype=float).reshape((3, 1))
933
+ direc_n = np.array(self.direction) / spla.norm(self.direction)
934
+ pos = np.zeros((self.num_points, 3))
1113
935
  for s in range(self.num_points):
1114
936
  pos[s] = loc.T + direc_n * dist * s
1115
937
  return pos.T
1116
938
 
1117
939
 
1118
- @deprecated_alias({'gpos': 'pos'}, read_only=True, removal_version='25.10')
1119
940
  class MergeGrid(Grid):
1120
941
  """
1121
942
  Base class for merging multiple grid geometries.
@@ -1148,13 +969,13 @@ class MergeGrid(Grid):
1148
969
 
1149
970
  #: A list of :class:`Grid` objects to be merged. Each grid is treated as a subdomain in the
1150
971
  #: resulting merged grid.
1151
- grids = List(desc='list of grids')
972
+ grids = List()
1152
973
 
1153
974
  #: A list of unique digests for each grid being merged. (read-only)
1154
- grid_digest = Str(desc='digest of the merged grids')
975
+ grid_digest = Str()
1155
976
 
1156
977
  #: Names of subgrids corresponding to each point in the merged grid. (read-only)
1157
- subgrids = Property(desc='names of subgrids for each point')
978
+ subgrids = Property()
1158
979
 
1159
980
  #: A unique identifier for the grid, based on its properties. (read-only)
1160
981
  digest = Property(depends_on=['grids', 'grid_digest'])
@@ -1177,17 +998,17 @@ class MergeGrid(Grid):
1177
998
 
1178
999
  @property_depends_on(['digest'])
1179
1000
  def _get_subgrids(self):
1180
- subgrids = zeros((1, 0), dtype=str)
1001
+ subgrids = np.zeros((1, 0), dtype=str)
1181
1002
  for grid in self.grids:
1182
- subgrids = append(subgrids, tile(grid.__class__.__name__ + grid.digest, grid.size))
1183
- return subgrids[:, newaxis].T
1003
+ subgrids = np.append(subgrids, np.tile(grid.__class__.__name__ + grid.digest, grid.size))
1004
+ return subgrids[:, np.newaxis].T
1184
1005
 
1185
1006
  @property_depends_on(['digest'])
1186
1007
  def _get_pos(self):
1187
- bpos = zeros((3, 0))
1008
+ bpos = np.zeros((3, 0))
1188
1009
  for grid in self.grids:
1189
- bpos = append(bpos, grid.pos, axis=1)
1190
- return unique(bpos, axis=1)
1010
+ bpos = np.append(bpos, grid.pos, axis=1)
1011
+ return np.unique(bpos, axis=1)
1191
1012
 
1192
1013
 
1193
1014
  class Sector(ABCHasStrictTraits):
@@ -1241,7 +1062,7 @@ class Sector(ABCHasStrictTraits):
1241
1062
  >>> sector.contains(positions)
1242
1063
  array([ True, True])
1243
1064
  """
1244
- return ones(pos.shape[1], dtype=bool)
1065
+ return np.ones(pos.shape[1], dtype=bool)
1245
1066
 
1246
1067
 
1247
1068
  class SingleSector(Sector):
@@ -1261,16 +1082,16 @@ class SingleSector(Sector):
1261
1082
 
1262
1083
  #: If ``True``, grid points lying on the sector border are included in the sector. Default is
1263
1084
  #: ``True``.
1264
- include_border = Bool(True, desc='include points on the border')
1085
+ include_border = Bool(True)
1265
1086
 
1266
1087
  #: The absolute tolerance to apply when determining if a grid point lies on the sector border.
1267
1088
  #: Default is ``1e-12``.
1268
- abs_tol = Float(1e-12, desc='absolute tolerance for sector border')
1089
+ abs_tol = Float(1e-12)
1269
1090
 
1270
1091
  #: If ``True``, the ``contains`` method (as in :meth:`RectSector.contains`,
1271
1092
  #: :meth:`RectSector3D.contains`, :meth:`CircSector.contains`, and :meth:`PolySector.contains`)
1272
1093
  #: returns the nearest grid point if no grid points are inside the sector. Default is ``True``.
1273
- default_nearest = Bool(True, desc='``contains`` method return nearest grid point to center if none inside sector')
1094
+ default_nearest = Bool(True)
1274
1095
 
1275
1096
 
1276
1097
  class RectSector(SingleSector):
@@ -1289,16 +1110,16 @@ class RectSector(SingleSector):
1289
1110
  """
1290
1111
 
1291
1112
  #: The minimum x position of the rectangle. Default is ``-1.0``.
1292
- x_min = Float(-1.0, desc='minimum x position of the rectangle')
1113
+ x_min = Float(-1.0)
1293
1114
 
1294
1115
  #: The maximum x position of the rectangle. Default is ``1.0``.
1295
- x_max = Float(1.0, desc='maximum x position of the rectangle')
1116
+ x_max = Float(1.0)
1296
1117
 
1297
1118
  #: The minimum y position of the rectangle. Default is ``-1.0``.
1298
- y_min = Float(-1.0, desc='minimum y position of the rectangle')
1119
+ y_min = Float(-1.0)
1299
1120
 
1300
1121
  #: The maximum y position of the rectangle. Default is ``1.0``.
1301
- y_max = Float(1.0, desc='maximum y position of the rectangle')
1122
+ y_max = Float(1.0)
1302
1123
 
1303
1124
  def contains(self, pos):
1304
1125
  """
@@ -1354,7 +1175,7 @@ class RectSector(SingleSector):
1354
1175
  x = (xmin + xmax) / 2.0
1355
1176
  y = (ymin + ymax) / 2.0
1356
1177
  dr2 = (pos[0, :] - x) ** 2 + (pos[1, :] - y) ** 2
1357
- inds[argmin(dr2)] = True
1178
+ inds[np.argmin(dr2)] = True
1358
1179
 
1359
1180
  return inds.astype(bool)
1360
1181
 
@@ -1373,10 +1194,10 @@ class RectSector3D(RectSector):
1373
1194
  """
1374
1195
 
1375
1196
  #: The lower z position of the cuboid. Default is ``-1.0``.
1376
- z_min = Float(-1.0, desc='minimum z position of the cuboid')
1197
+ z_min = Float(-1.0)
1377
1198
 
1378
1199
  #: The upper z position of the cuboid. Default is ``1.0``.
1379
- z_max = Float(1.0, desc='maximum z position of the cuboid')
1200
+ z_max = Float(1.0)
1380
1201
 
1381
1202
  def contains(self, pos):
1382
1203
  """
@@ -1442,7 +1263,7 @@ class RectSector3D(RectSector):
1442
1263
  x = (xmin + xmax) / 2.0
1443
1264
  y = (ymin + ymax) / 2.0
1444
1265
  dr2 = (pos[0, :] - x) ** 2 + (pos[1, :] - y) ** 2
1445
- inds[argmin(dr2)] = True
1266
+ inds[np.argmin(dr2)] = True
1446
1267
 
1447
1268
  return inds.astype(bool)
1448
1269
 
@@ -1462,13 +1283,13 @@ class CircSector(SingleSector):
1462
1283
  """
1463
1284
 
1464
1285
  #: The x position of the circle center. Default is ``0.0``.
1465
- x = Float(0.0, desc='x position of the circle center')
1286
+ x = Float(0.0)
1466
1287
 
1467
1288
  #: The y position of the circle center. Default is ``0.0``.
1468
- y = Float(0.0, desc='y position of the circle center')
1289
+ y = Float(0.0)
1469
1290
 
1470
1291
  #: Radius of the circle. Default is ``1.0``.
1471
- r = Float(1.0, desc='radius of the circle')
1292
+ r = Float(1.0)
1472
1293
 
1473
1294
  def contains(self, pos):
1474
1295
  """
@@ -1510,7 +1331,7 @@ class CircSector(SingleSector):
1510
1331
 
1511
1332
  # if there's no point inside
1512
1333
  if ~inds.any() and self.default_nearest:
1513
- inds[argmin(dr2)] = True
1334
+ inds[np.argmin(dr2)] = True
1514
1335
 
1515
1336
  return inds
1516
1337
 
@@ -1567,14 +1388,14 @@ class PolySector(SingleSector):
1567
1388
  >>> sec.contains(grid.pos)
1568
1389
  array([False, False, False, False, True, True, False, True, True])
1569
1390
  """
1570
- poly = Polygon(array(self.edges).reshape(-1, 2)[:, 0], array(self.edges).reshape(-1, 2)[:, 1])
1391
+ poly = Polygon(np.array(self.edges).reshape(-1, 2)[:, 0], np.array(self.edges).reshape(-1, 2)[:, 1])
1571
1392
  dists = poly.is_inside(pos[0, :], pos[1, :])
1572
1393
  inds = dists >= -self.abs_tol if self.include_border else dists > 0
1573
1394
 
1574
1395
  # if none inside, take nearest
1575
1396
  if ~inds.any() and self.default_nearest:
1576
- dr2 = array(self.edges).reshape(-1, 2).mean(0)
1577
- inds[argmin(dr2)] = True
1397
+ dr2 = np.array(self.edges).reshape(-1, 2).mean(0)
1398
+ inds[np.argmin(dr2)] = True
1578
1399
 
1579
1400
  return inds
1580
1401
 
@@ -1627,12 +1448,12 @@ class ConvexSector(SingleSector):
1627
1448
  >>> sec.contains(grid.pos)
1628
1449
  array([False, False, False, False, True, True, False, True, True])
1629
1450
  """
1630
- inds = in_hull(pos[:2, :].T, array(self.edges).reshape(-1, 2), border=self.include_border, tol=self.abs_tol)
1451
+ inds = in_hull(pos[:2, :].T, np.array(self.edges).reshape(-1, 2), border=self.include_border, tol=self.abs_tol)
1631
1452
 
1632
1453
  # if none inside, take nearest
1633
1454
  if ~inds.any() and self.default_nearest:
1634
- dr2 = array(self.edges).reshape(-1, 2).mean(0) # Use the centroid of the polygon as the "center"
1635
- inds[argmin(dr2)] = True
1455
+ dr2 = np.array(self.edges).reshape(-1, 2).mean(0) # Use the centroid of the polygon as the "center"
1456
+ inds[np.argmin(dr2)] = True
1636
1457
 
1637
1458
  return inds
1638
1459
 
@@ -1687,7 +1508,7 @@ class MultiSector(Sector):
1687
1508
  array([False, False, False, False, True, True, False, True, True])
1688
1509
  """
1689
1510
  # initialize with only "False" entries
1690
- inds = zeros(pos.shape[1], dtype=bool)
1511
+ inds = np.zeros(pos.shape[1], dtype=bool)
1691
1512
 
1692
1513
  # add points contained in each sector
1693
1514
  for sec in self.sectors: