LightWave2D 0.0.4__tar.gz → 0.0.6__tar.gz

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 (53) hide show
  1. lightwave2d-0.0.6/LightWave2D/VERSION +1 -0
  2. lightwave2d-0.0.6/LightWave2D/__pycache__/__init__.cpython-311.pyc +0 -0
  3. lightwave2d-0.0.6/LightWave2D/__pycache__/components.cpython-311.pyc +0 -0
  4. lightwave2d-0.0.6/LightWave2D/__pycache__/detector.cpython-311.pyc +0 -0
  5. lightwave2d-0.0.6/LightWave2D/__pycache__/experiment.cpython-311.pyc +0 -0
  6. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/__pycache__/grid.cpython-311.pyc +0 -0
  7. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/__pycache__/physics.cpython-311.pyc +0 -0
  8. lightwave2d-0.0.6/LightWave2D/__pycache__/pml.cpython-311.pyc +0 -0
  9. lightwave2d-0.0.6/LightWave2D/__pycache__/source.cpython-311.pyc +0 -0
  10. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/__pycache__/utils.cpython-311.pyc +0 -0
  11. lightwave2d-0.0.6/LightWave2D/components.py +365 -0
  12. lightwave2d-0.0.6/LightWave2D/detector.py +156 -0
  13. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/experiment.py +98 -24
  14. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/grid.py +8 -0
  15. lightwave2d-0.0.6/LightWave2D/pml.py +97 -0
  16. lightwave2d-0.0.6/LightWave2D/source.py +262 -0
  17. lightwave2d-0.0.6/LightWave2D.egg-info/PKG-INFO +288 -0
  18. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D.egg-info/SOURCES.txt +2 -8
  19. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D.egg-info/requires.txt +1 -0
  20. lightwave2d-0.0.6/PKG-INFO +288 -0
  21. lightwave2d-0.0.6/README.rst +243 -0
  22. lightwave2d-0.0.6/developments/testings_0.py +82 -0
  23. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/setup.cfg +1 -0
  24. lightwave2d-0.0.4/LightWave2D/VERSION +0 -1
  25. lightwave2d-0.0.4/LightWave2D/__pycache__/__init__.cpython-311.pyc +0 -0
  26. lightwave2d-0.0.4/LightWave2D/__pycache__/detector.cpython-311.pyc +0 -0
  27. lightwave2d-0.0.4/LightWave2D/__pycache__/experiment.cpython-311.pyc +0 -0
  28. lightwave2d-0.0.4/LightWave2D/__pycache__/pml.cpython-311.pyc +0 -0
  29. lightwave2d-0.0.4/LightWave2D/__pycache__/source.cpython-311.pyc +0 -0
  30. lightwave2d-0.0.4/LightWave2D/components/__init__.py +0 -5
  31. lightwave2d-0.0.4/LightWave2D/components/__pycache__/__init__.cpython-311.pyc +0 -0
  32. lightwave2d-0.0.4/LightWave2D/components/__pycache__/base_class.cpython-311.pyc +0 -0
  33. lightwave2d-0.0.4/LightWave2D/components/__pycache__/basic.cpython-311.pyc +0 -0
  34. lightwave2d-0.0.4/LightWave2D/components/__pycache__/complex.cpython-311.pyc +0 -0
  35. lightwave2d-0.0.4/LightWave2D/components/base_class.py +0 -139
  36. lightwave2d-0.0.4/LightWave2D/components/basic.py +0 -133
  37. lightwave2d-0.0.4/LightWave2D/components/complex.py +0 -105
  38. lightwave2d-0.0.4/LightWave2D/detector.py +0 -85
  39. lightwave2d-0.0.4/LightWave2D/pml.py +0 -74
  40. lightwave2d-0.0.4/LightWave2D/source.py +0 -130
  41. lightwave2d-0.0.4/LightWave2D.egg-info/PKG-INFO +0 -91
  42. lightwave2d-0.0.4/PKG-INFO +0 -91
  43. lightwave2d-0.0.4/README.rst +0 -47
  44. lightwave2d-0.0.4/developments/testings_0.py +0 -127
  45. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LICENSE +0 -0
  46. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/__init__.py +0 -0
  47. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/directories.py +0 -0
  48. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/physics.py +0 -0
  49. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D/utils.py +0 -0
  50. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D.egg-info/dependency_links.txt +0 -0
  51. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/LightWave2D.egg-info/top_level.txt +0 -0
  52. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/MANIFEST.in +0 -0
  53. {lightwave2d-0.0.4 → lightwave2d-0.0.6}/setup.py +0 -0
@@ -0,0 +1 @@
1
+ 0.0.6
@@ -0,0 +1,365 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from typing import NoReturn, Union, Tuple
5
+ from pydantic.dataclasses import dataclass
6
+ import numpy
7
+ from LightWave2D.physics import Physics
8
+ import matplotlib.pyplot as plt
9
+ import shapely.geometry as geo
10
+ from matplotlib.patches import PathPatch
11
+ from matplotlib import patches
12
+ import numpy as np
13
+ from matplotlib.path import Path
14
+ from matplotlib.collections import PatchCollection
15
+ from LightWave2D.grid import Grid
16
+ from shapely.affinity import scale, rotate
17
+
18
+
19
+ # Configuration dictionary for dataclasses
20
+ config_dict = {
21
+ 'kw_only': True,
22
+ 'extra': 'forbid',
23
+ 'slots': True,
24
+ 'arbitrary_types_allowed': True
25
+ }
26
+
27
+
28
+ @dataclass(kw_only=True, config=config_dict)
29
+ class BaseComponent():
30
+ """
31
+ Represents a generic component in a simulation grid.
32
+
33
+ Attributes:
34
+ grid (Grid): The simulation grid.
35
+ facecolor (str): The color of the component's face.
36
+ edgecolor (str): The color of the component's edge.
37
+ alpha (float): Transparency level of the component.
38
+ rotation (float): Rotation angle of the component.
39
+ """
40
+ grid: Grid
41
+ facecolor: str = 'lightblue'
42
+ edgecolor: str = 'blue'
43
+ alpha: float = 0.3
44
+ rotation: float = 0
45
+
46
+ def __post_init__(self):
47
+ x0, y0 = self.position
48
+ self.coordinate = self.grid.get_coordinate(x=x0, y=y0)
49
+
50
+ self.build_object()
51
+
52
+ def build_object(self) -> NoReturn:
53
+ """
54
+ Build the permittivity mesh for the component.
55
+ """
56
+ self.epsilon_r_mesh = numpy.ones(self.grid.shape) # Background permittivity
57
+
58
+ self.compute_polygon()
59
+
60
+ self.polygon = rotate(self.polygon, angle=self.rotation)
61
+
62
+ self.polygon = self.polygon.intersection(self.grid.polygon)
63
+
64
+ self.path = Path(self.polygon.exterior.coords)
65
+
66
+ x_mesh, y_mesh = numpy.meshgrid(self.grid.x_stamp, self.grid.y_stamp)
67
+
68
+ coordinates = numpy.c_[x_mesh.T.flatten(), y_mesh.T.flatten()]
69
+
70
+ self.idx = self.path.contains_points(coordinates).astype(bool).reshape(self.epsilon_r_mesh.shape)
71
+
72
+ self.epsilon_r_mesh[self.idx] = self.epsilon_r
73
+
74
+ def add_to_ax(self, ax: plt.axis) -> PatchCollection:
75
+ """
76
+ Add the component to the provided axis.
77
+
78
+ Args:
79
+ ax (plt.Axes): The axis to which the component will be added.
80
+
81
+ Returns:
82
+ PatchCollection: The collection of patches added to the axis.
83
+ """
84
+ path = Path.make_compound_path(
85
+ Path(np.asarray(self.polygon.exterior.coords)[:, :2]),
86
+ *[Path(np.asarray(ring.coords)[:, :2]) for ring in self.polygon.interiors])
87
+
88
+ patch = PathPatch(path, facecolor=self.facecolor, edgecolor=self.edgecolor, alpha=0.4)
89
+ collection = PatchCollection([patch], facecolor=self.facecolor, edgecolor=self.edgecolor, alpha=self.alpha)
90
+
91
+ ax.add_collection(collection, autolim=True)
92
+ ax.autoscale_view()
93
+ return collection
94
+
95
+ def plot(self) -> NoReturn:
96
+ """
97
+ Plot the component.
98
+ """
99
+ figure, ax = plt.subplots(1, 1, figsize=(6, 6))
100
+ ax.set_title('FDTD Simulation')
101
+ ax.set_xlabel(r'x position [$\mu$m]')
102
+ ax.set_xlabel(r'y position [$\mu$m]')
103
+ ax.set_aspect('equal')
104
+
105
+ self.add_to_ax(ax)
106
+ ax.autoscale_view()
107
+
108
+ plt.show()
109
+
110
+ def add_to_mesh(self, epsilon_r_mesh: numpy.ndarray) -> NoReturn:
111
+ """
112
+ Add the component's permittivity to the provided mesh.
113
+
114
+ Args:
115
+ epsilon_r_mesh (np.ndarray): The permittivity mesh to be updated.
116
+ """
117
+ epsilon_r_mesh += self.epsilon_r_mesh
118
+
119
+ def add_non_linear_effect_to_field(self, field: numpy.ndarray) -> NoReturn:
120
+ """
121
+ Add non-linear effects to the field.
122
+
123
+ Args:
124
+ field (np.ndarray): The field to which non-linear effects will be added.
125
+ """
126
+ chi_2 = 1e10
127
+
128
+ field += self.idx * self.grid.dt**2 / (self.epsilon_r_mesh * Physics.epsilon_0 * Physics.mu_0) * chi_2 * field ** 2
129
+
130
+
131
+ @dataclass(config=config_dict)
132
+ class Waveguide(BaseComponent):
133
+ """
134
+ Represents a Waveguide scatterer in a simulation grid.
135
+
136
+ Attributes:
137
+ position (Tuple[Union[float, str], Union[float, str]]): The center position of the scatterer.
138
+ epsilon_r (float): The relative permittivity inside the scatterer.
139
+ side_length (float): The side length of the square scatterer.
140
+ """
141
+ position_0: Tuple[Union[float, str], Union[float, str]]
142
+ position_1: Tuple[Union[float, str], Union[float, str]]
143
+ width: float
144
+ epsilon_r: float
145
+
146
+ def __post_init__(self):
147
+ x0, y0 = self.position_0
148
+ x1, y1 = self.position_1
149
+ self.coordinate_0 = self.grid.get_coordinate(x=x0, y=y0)
150
+ self.coordinate_1 = self.grid.get_coordinate(x=x1, y=y1)
151
+
152
+ self.build_object()
153
+
154
+ def compute_polygon(self) -> Path:
155
+ """
156
+ Compute the polygon of the square scatterer.
157
+ """
158
+ line = geo.LineString(
159
+ [(self.coordinate_0.x, self.coordinate_0.y), (self.coordinate_1.x, self.coordinate_1.y)]
160
+ )
161
+
162
+ self.polygon = line.buffer(self.width)
163
+
164
+
165
+ @dataclass(config=config_dict)
166
+ class Square(BaseComponent):
167
+ """
168
+ Represents a square scatterer in a simulation grid.
169
+
170
+ Attributes:
171
+ position (Tuple[Union[float, str], Union[float, str]]): The center position of the scatterer.
172
+ epsilon_r (float): The relative permittivity inside the scatterer.
173
+ side_length (float): The side length of the square scatterer.
174
+ """
175
+ position: Tuple[Union[float, str], Union[float, str]]
176
+ epsilon_r: float
177
+ side_length: float
178
+
179
+ def compute_polygon(self) -> Path:
180
+ """
181
+ Compute the polygon of the square scatterer.
182
+ """
183
+ half_side = self.side_length / 2
184
+ x_start, x_end = self.coordinate.x - half_side, self.coordinate.x + half_side
185
+ y_start, y_end = self.coordinate.y - half_side, self.coordinate.y + half_side
186
+
187
+ self.polygon = geo.Polygon([
188
+ (x_start, y_start),
189
+ (x_start, y_end),
190
+ (x_end, y_end),
191
+ (x_end, y_start)
192
+ ]).convex_hull
193
+
194
+
195
+ @dataclass(config=config_dict)
196
+ class Circle(BaseComponent):
197
+ """
198
+ Represents a circular scatterer in a simulation grid.
199
+
200
+ Attributes:
201
+ position (Tuple[Union[float, str], Union[float, str]]): The center position of the scatterer.
202
+ epsilon_r (float): The relative permittivity inside the scatterer.
203
+ radius (float): The radius of the scatterer.
204
+ """
205
+ position: Tuple[Union[float, str], Union[float, str]]
206
+ epsilon_r: float
207
+ radius: float
208
+
209
+ def compute_polygon(self) -> NoReturn:
210
+ """
211
+ Compute the polygon of the circular scatterer.
212
+ """
213
+ self.polygon = geo.Point(self.coordinate.x, self.coordinate.y).buffer(self.radius)
214
+
215
+
216
+ @dataclass(config=config_dict)
217
+ class Triangle(BaseComponent):
218
+ """
219
+ Represents a triangular scatterer in a simulation grid.
220
+
221
+ Attributes:
222
+ position (Tuple[Union[float, str], Union[float, str]]): The center position of the scatterer.
223
+ epsilon_r (float): The relative permittivity inside the scatterer.
224
+ side_length (float): The side length of the triangular scatterer.
225
+ """
226
+ position: Tuple[Union[float, str], Union[float, str]]
227
+ epsilon_r: float
228
+ side_length: float
229
+
230
+ def compute_polygon(self) -> NoReturn:
231
+ """
232
+ Compute the polygon of the triangular scatterer.
233
+ """
234
+ height = (np.sqrt(3) / 2) * self.side_length
235
+
236
+ # Vertices of an equilateral triangle centered at (coordinate.x, coordinate.y)
237
+ p0 = (self.coordinate.x - self.side_length / 2, self.coordinate.y - height / 3)
238
+ p1 = (self.coordinate.x + self.side_length / 2, self.coordinate.y - height / 3)
239
+ p2 = (self.coordinate.x, self.coordinate.y + 2 * height / 3)
240
+
241
+ self.polygon = geo.Polygon([p0, p1, p2])
242
+
243
+
244
+ @dataclass(config=config_dict)
245
+ class Ellipse(BaseComponent):
246
+ """
247
+ Represents an elliptical scatterer in a simulation grid.
248
+
249
+ Attributes:
250
+ position (Tuple[Union[float, str], Union[float, str]]): The center position of the scatterer.
251
+ width (float): The width of the ellipse.
252
+ height (float): The height of the ellipse.
253
+ epsilon_r (float): The relative permittivity inside the scatterer.
254
+ resolution (float): The resolution of the ellipse.
255
+ """
256
+ position: Tuple[Union[float, str], Union[float, str]]
257
+ width: float
258
+ height: float
259
+ epsilon_r: float
260
+ resolution: float = 100
261
+
262
+ def compute_polygon(self) -> NoReturn:
263
+ """
264
+ Compute the polygon of the elliptical scatterer.
265
+ """
266
+ ellipse_patch = patches.Ellipse(
267
+ (self.coordinate.x, self.coordinate.y),
268
+ width=self.resolution,
269
+ height=self.resolution * self.height / self.width,
270
+ )
271
+
272
+ vertices = ellipse_patch.get_verts()
273
+ polygon = geo.Polygon(vertices)
274
+
275
+ self.polygon = scale(polygon, xfact=self.width / self.resolution, yfact=self.width / self.resolution)
276
+
277
+
278
+ @dataclass(config=config_dict)
279
+ class Grating(BaseComponent):
280
+ """
281
+ Represents a grating in a simulation grid.
282
+
283
+ Attributes:
284
+ position (Tuple[Union[float, str], Union[float, str]]): The starting position of the grating.
285
+ epsilon_r (float): The relative permittivity inside the grating.
286
+ period (float): The period of the grating.
287
+ duty_cycle (float): The duty cycle of the grating.
288
+ num_periods (int): The number of periods in the grating.
289
+ """
290
+ position: Tuple[Union[float, str], Union[float, str]]
291
+ epsilon_r: float
292
+ period: float
293
+ duty_cycle: float
294
+ num_periods: int
295
+
296
+ def compute_polygon(self) -> NoReturn:
297
+ """
298
+ Compute the polygon of the grating.
299
+ """
300
+ bars = []
301
+ for i in range(self.num_periods):
302
+ x_start = self.coordinate.x + i * self.period
303
+ x_end = x_start + self.duty_cycle * self.period
304
+ bar = geo.box(x_start, self.coordinate.y - 0.5, x_end, self.coordinate.y + 0.5)
305
+ bars.append(bar)
306
+
307
+ self.polygon = geo.MultiPolygon(bars)
308
+
309
+
310
+ @dataclass(config=config_dict)
311
+ class RingResonator(BaseComponent):
312
+ """
313
+ Represents a ring resonator in a simulation grid.
314
+
315
+ Attributes:
316
+ position (Tuple[Union[float, str], Union[float, str]]): The center position of the ring resonator.
317
+ epsilon_r (float): The relative permittivity inside the resonator.
318
+ inner_radius (float): The inner radius of the ring.
319
+ width (float): The width of the ring.
320
+ """
321
+ grid: Grid
322
+ position: Tuple[Union[float, str], Union[float, str]]
323
+ epsilon_r: float
324
+ inner_radius: float
325
+ width: float
326
+
327
+ def compute_polygon(self) -> NoReturn:
328
+ """
329
+ Compute the polygon of the ring resonator.
330
+ """
331
+ inner_circle = geo.Point(self.coordinate.x, self.coordinate.y).buffer(self.inner_radius)
332
+ outer_circle = geo.Point(self.coordinate.x, self.coordinate.y).buffer(self.inner_radius + self.width)
333
+ self.polygon = outer_circle.difference(inner_circle)
334
+
335
+
336
+ @dataclass(config=config_dict)
337
+ class Lense(BaseComponent):
338
+ """
339
+ Represents a lens in a simulation grid.
340
+
341
+ Attributes:
342
+ position (Tuple[Union[float, str], Union[float, str]]): The center position of the lens.
343
+ epsilon_r (float): The relative permittivity inside the lens.
344
+ width (float): The width of the lens.
345
+ curvature (float): The curvature of the lens (positive for convex, negative for concave).
346
+ """
347
+ position: Tuple[Union[float, str], Union[float, str]]
348
+ epsilon_r: float
349
+ width: float
350
+ curvature: float
351
+
352
+ def compute_polygon(self) -> NoReturn:
353
+ """
354
+ Compute the polygon of the lens.
355
+ """
356
+ # Create two arcs for the lens shape
357
+ x0 = self.coordinate.x + self.curvature - self.width / 2
358
+ x1 = self.coordinate.x - self.curvature + self.width / 2
359
+
360
+ arc3 = geo.Point(x0, self.coordinate.y).buffer(self.curvature, resolution=100)
361
+ arc4 = geo.Point(x1, self.coordinate.y).buffer(self.curvature, resolution=100)
362
+
363
+ self.polygon = arc3.intersection(arc4)
364
+
365
+ # -
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from typing import Tuple, Union, NoReturn
5
+ from dataclasses import field
6
+ import numpy
7
+ from LightWave2D.grid import Grid
8
+ import shapely.geometry as geo
9
+ from matplotlib.path import Path
10
+ from pydantic.dataclasses import dataclass
11
+ from matplotlib.collections import PatchCollection
12
+ from matplotlib.patches import PathPatch
13
+ import matplotlib.pyplot as plt
14
+ import matplotlib
15
+
16
+ config_dict = dict(
17
+ kw_only=True,
18
+ slots=True,
19
+ extra='forbid',
20
+ arbitrary_types_allowed=True
21
+ )
22
+
23
+
24
+ @dataclass(kw_only=True, config=config_dict)
25
+ class BaseDetector():
26
+ """
27
+ Represents an elliptical scatterer in a simulation grid.
28
+
29
+ Attributes:
30
+ grid (Grid): The grid of the simulation mesh.
31
+ angle (float): Rotation angle of the ellipse.
32
+ facecolor (str): Color of the scatterer face.
33
+ edgecolor (str): Color of the scatterer edge.
34
+ """
35
+ grid: Grid
36
+ facecolor: str = 'green'
37
+ edgecolor: str = 'green'
38
+ alpha: float = 0.8
39
+ rotation: float = 0
40
+
41
+ def __post_init__(self):
42
+ x0, y0 = self.position
43
+ self.coordinate = self.grid.get_coordinate(x=x0, y=y0)
44
+
45
+ self.build_object()
46
+
47
+ def build_object(self) -> NoReturn:
48
+ """
49
+ Build the permittivity mesh for the square scatterer.
50
+ """
51
+ self.compute_polygon()
52
+
53
+ self.path = Path(self.polygon.exterior.coords)
54
+
55
+ self.path = self.path.transformed(matplotlib.transforms.Affine2D().rotate_around(self.coordinate.x, self.coordinate.y, self.rotation))
56
+
57
+ def add_to_ax(self, ax: plt.axis) -> PatchCollection:
58
+ """
59
+ Add the scatterer to the provided axis as a circle.
60
+
61
+ Args:
62
+ ax (Axis): The axis to which the scatterer will be added.
63
+ """
64
+ path = Path.make_compound_path(
65
+ Path(numpy.asarray(self.polygon.exterior.coords)[:, :2]),
66
+ *[Path(numpy.asarray(ring.coords)[:, :2]) for ring in self.polygon.interiors])
67
+
68
+ patch = PathPatch(path, color=self.facecolor, edgecolor=self.edgecolor, alpha=0.4)
69
+ collection = PatchCollection([patch], color=self.facecolor, edgecolor=self.edgecolor, alpha=self.alpha)
70
+
71
+ ax.add_collection(collection, autolim=True)
72
+ ax.autoscale_view()
73
+ return collection
74
+
75
+ def plot(self) -> NoReturn:
76
+ figure, ax = plt.subplots(1, 1, figsize=(6, 6))
77
+ ax.set_title('FDTD Simulation')
78
+ ax.set_xlabel(r'x position [$\mu$m]')
79
+ ax.set_xlabel(r'y position [$\mu$m]')
80
+ ax.set_aspect('equal')
81
+
82
+ self.add_to_ax(ax)
83
+ ax.autoscale_view()
84
+
85
+ plt.show()
86
+
87
+
88
+ @dataclass(kw_only=True, config=config_dict)
89
+ class PointDetector(BaseDetector):
90
+ """
91
+ Represents a point detector within a simulation grid.
92
+
93
+ Attributes:
94
+ grid (Grid): The simulation mesh grid.
95
+ position (Tuple[float | str, float | str]): The (x, y) coordinates of the point detector on the grid.
96
+ data (numpy.ndarray): The data collected by the detector over time.
97
+ """
98
+ position: Union[Tuple[float | str, float | str]]
99
+ coherent: bool = True
100
+ data: numpy.ndarray = field(init=False)
101
+
102
+ def __post_init__(self):
103
+ """
104
+ Initialize the PointDetector by converting the given position into
105
+ grid coordinates and initializing the data array.
106
+ """
107
+ x, y = self.position
108
+
109
+ self.p0 = self.grid.get_coordinate(x=x, y=y)
110
+
111
+ self.polygon = geo.Point(self.p0.x, self.p0.y)
112
+
113
+ self.path = Path(self.polygon.coords)
114
+
115
+ self.data = numpy.zeros(self.grid.n_steps)
116
+
117
+ def update_data(self, field: numpy.ndarray) -> NoReturn:
118
+ """
119
+ Update the detector data based on the provided field values.
120
+
121
+ Parameters:
122
+ field (numpy.ndarray): The field values to update the detector data.
123
+ """
124
+ if self.coherent:
125
+ self.data = field[:, self.p0.x_index, self.p0.y_index]
126
+ else:
127
+ self.data = abs(field[:, self.p0.x_index, self.p0.y_index])
128
+
129
+ def plot_data(self) -> NoReturn:
130
+ """
131
+ Plot the detector data over time.
132
+
133
+ Returns:
134
+ SceneList: A scene list containing the plot.
135
+ """
136
+ figure, ax = plt.subplots(1, 1, figsize=(8, 4))
137
+ ax.plot(self.grid.time_stamp, self.data)
138
+ ax.set_ylabel('Amplitude')
139
+ ax.set_xlabel('Time [seconds]')
140
+ figure.show()
141
+
142
+ def add_to_ax(self, ax: plt.axis) -> NoReturn:
143
+ """
144
+ Add the scatterer to the provided axis as a circle.
145
+
146
+ Args:
147
+ ax (Axis): The axis to which the scatterer will be added.
148
+ """
149
+ ax.scatter(
150
+ self.p0.x,
151
+ self.p0.y,
152
+ color=self.facecolor,
153
+ label='detector'
154
+ )
155
+
156
+ # -