LightWave2D 0.0.3__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 (36) hide show
  1. lightwave2d-0.0.3/LICENSE +21 -0
  2. lightwave2d-0.0.3/LightWave2D/VERSION +1 -0
  3. lightwave2d-0.0.3/LightWave2D/__init__.py +0 -0
  4. lightwave2d-0.0.3/LightWave2D/__pycache__/__init__.cpython-311.pyc +0 -0
  5. lightwave2d-0.0.3/LightWave2D/__pycache__/detector.cpython-311.pyc +0 -0
  6. lightwave2d-0.0.3/LightWave2D/__pycache__/experiment.cpython-311.pyc +0 -0
  7. lightwave2d-0.0.3/LightWave2D/__pycache__/grid.cpython-311.pyc +0 -0
  8. lightwave2d-0.0.3/LightWave2D/__pycache__/physics.cpython-311.pyc +0 -0
  9. lightwave2d-0.0.3/LightWave2D/__pycache__/pml.cpython-311.pyc +0 -0
  10. lightwave2d-0.0.3/LightWave2D/__pycache__/source.cpython-311.pyc +0 -0
  11. lightwave2d-0.0.3/LightWave2D/__pycache__/utils.cpython-311.pyc +0 -0
  12. lightwave2d-0.0.3/LightWave2D/components/__init__.py +4 -0
  13. lightwave2d-0.0.3/LightWave2D/components/__pycache__/__init__.cpython-311.pyc +0 -0
  14. lightwave2d-0.0.3/LightWave2D/components/__pycache__/base_class.cpython-311.pyc +0 -0
  15. lightwave2d-0.0.3/LightWave2D/components/__pycache__/scatterers.cpython-311.pyc +0 -0
  16. lightwave2d-0.0.3/LightWave2D/components/base_class.py +100 -0
  17. lightwave2d-0.0.3/LightWave2D/components/scatterers.py +185 -0
  18. lightwave2d-0.0.3/LightWave2D/detector.py +88 -0
  19. lightwave2d-0.0.3/LightWave2D/directories.py +33 -0
  20. lightwave2d-0.0.3/LightWave2D/experiment.py +383 -0
  21. lightwave2d-0.0.3/LightWave2D/grid.py +156 -0
  22. lightwave2d-0.0.3/LightWave2D/physics.py +17 -0
  23. lightwave2d-0.0.3/LightWave2D/pml.py +74 -0
  24. lightwave2d-0.0.3/LightWave2D/source.py +119 -0
  25. lightwave2d-0.0.3/LightWave2D/utils.py +95 -0
  26. lightwave2d-0.0.3/LightWave2D.egg-info/PKG-INFO +54 -0
  27. lightwave2d-0.0.3/LightWave2D.egg-info/SOURCES.txt +35 -0
  28. lightwave2d-0.0.3/LightWave2D.egg-info/dependency_links.txt +1 -0
  29. lightwave2d-0.0.3/LightWave2D.egg-info/requires.txt +22 -0
  30. lightwave2d-0.0.3/LightWave2D.egg-info/top_level.txt +5 -0
  31. lightwave2d-0.0.3/MANIFEST.in +7 -0
  32. lightwave2d-0.0.3/PKG-INFO +54 -0
  33. lightwave2d-0.0.3/README.rst +10 -0
  34. lightwave2d-0.0.3/developments/testings_0.py +87 -0
  35. lightwave2d-0.0.3/setup.cfg +92 -0
  36. lightwave2d-0.0.3/setup.py +6 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Martin de Sivry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ 0.0.3
File without changes
@@ -0,0 +1,4 @@
1
+ from .scatterers import Waveguide, Circle, Square, Ellipse # noqa: F401
2
+
3
+
4
+ # -
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from typing import NoReturn
5
+
6
+ import numpy
7
+ from LightWave2D.physics import Physics
8
+ import matplotlib.pyplot as plt
9
+ from matplotlib.patches import PathPatch
10
+
11
+
12
+ class BaseComponent():
13
+ def __post_init__(self):
14
+ self.build_object()
15
+
16
+ def build_object(self) -> NoReturn:
17
+ """
18
+ Build the permittivity mesh for the square scatterer.
19
+ """
20
+ self.epsilon_r_mesh = numpy.ones(self.grid.shape) # Background permittivity
21
+
22
+ self.compute_path()
23
+
24
+ x_mesh, y_mesh = numpy.meshgrid(self.grid.x_stamp, self.grid.y_stamp)
25
+
26
+ coordinates = numpy.c_[x_mesh.T.flatten(), y_mesh.T.flatten()]
27
+
28
+ self.idx = self.path.contains_points(coordinates).astype(bool).reshape(self.epsilon_r_mesh.shape)
29
+
30
+ self.epsilon_r_mesh[self.idx] = self.epsilon_r
31
+
32
+ def add_to_ax(self, ax: plt.axis) -> NoReturn:
33
+ """
34
+ Add the scatterer to the provided axis as a circle.
35
+
36
+ Args:
37
+ ax (Axis): The axis to which the scatterer will be added.
38
+ """
39
+ patch = PathPatch(
40
+ self.path,
41
+ alpha=0.7,
42
+ color=self.facecolor,
43
+ label=str(self.__class__.__name__),
44
+ )
45
+
46
+ return ax.add_patch(patch)
47
+
48
+ def plot(self) -> NoReturn:
49
+ figure, ax = plt.subplots(1, 1, figsize=(6, 6))
50
+ ax.set_title('FDTD Simulation')
51
+ ax.set_xlabel(r'x position [$\mu$m]')
52
+ ax.set_xlabel(r'y position [$\mu$m]')
53
+ ax.set_aspect('equal')
54
+
55
+ self.add_to_ax(ax)
56
+ ax.autoscale_view()
57
+
58
+ plt.show()
59
+
60
+ def interpret_position_to_index(self) -> tuple:
61
+ """
62
+ Interprets and returns the value of positions x and y of the waveguide
63
+
64
+ :returns: The index of width and height
65
+ :rtype: int
66
+ """
67
+ x, y = self.position
68
+
69
+ if isinstance(x, str):
70
+ x_index = self.grid.string_to_index(x, axis='x')
71
+ else:
72
+ x_index = self.grid.position_to_index(x, axis='x')
73
+
74
+ if isinstance(y, str):
75
+ y_index = self.grid.string_to_index(y, axis='y')
76
+ else:
77
+ y_index = self.grid.position_to_index(y, axis='y')
78
+
79
+ return x_index, y_index
80
+
81
+ def interpret_position_to_position(self) -> tuple:
82
+ """
83
+ Interprets and returns the value of positions x and y of the waveguide
84
+
85
+ :returns: The index of width and height
86
+ :rtype: int
87
+ """
88
+ x, y = self.position
89
+
90
+ coordinate = self.grid.get_coordinate(x=x, y=y)
91
+
92
+ return coordinate.x, coordinate.y
93
+
94
+ def add_to_mesh(self, epsilon_r_mesh: numpy.ndarray) -> None:
95
+ epsilon_r_mesh += self.epsilon_r_mesh
96
+
97
+ def add_non_linear_effect_to_field(self, field: numpy.ndarray) -> None:
98
+ chi_2 = 1e10
99
+
100
+ field += self.idx * self.grid.dt**2 / (self.epsilon_r_mesh * Physics.epsilon_0 * Physics.mu_0) * chi_2 * field ** 2
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from typing import Tuple, Union, NoReturn
5
+ from pydantic.dataclasses import dataclass
6
+ import numpy
7
+ from LightWave2D.grid import Grid
8
+ from LightWave2D.components.base_class import BaseComponent
9
+ from matplotlib.path import Path
10
+ import shapely.geometry as geo
11
+ from matplotlib import patches
12
+
13
+
14
+ config_dict = dict(
15
+ kw_only=True,
16
+ extra='forbid',
17
+ slots=True,
18
+ arbitrary_types_allowed=True
19
+ )
20
+
21
+
22
+ @dataclass(config=config_dict)
23
+ class Waveguide(BaseComponent):
24
+ """
25
+ Represents a waveguide in a simulation grid.
26
+
27
+ Attributes:
28
+ grid (Grid): The grid of the simulation mesh.
29
+ width (int | str): Width of the waveguide in grid cells or 'full' for full width.
30
+ height (int | str): Height of the waveguide in grid cells or 'full' for full height.
31
+ position (tuple): Starting position of the waveguide.
32
+ epsilon_r (float): Relative permittivity inside the waveguide.
33
+ """
34
+ grid: Grid
35
+ width: Union[int | str]
36
+ height: Union[int | str]
37
+ position: Tuple[float | str, float | str]
38
+ epsilon_r: float
39
+ facecolor: str = 'lightblue'
40
+ edgecolor: str = 'blue'
41
+
42
+ def build_mesh(self) -> NoReturn:
43
+ """
44
+ Build the permittivity mesh for the waveguide.
45
+ """
46
+ width_index, height_index = self._interpret_width_height()
47
+ x_index, y_index = self._interpret_position_to_index()
48
+
49
+ x_start, x_end = x_index, x_index + width_index
50
+ y_start, y_end = y_index, y_index + height_index
51
+
52
+ self.epsilon_r_mesh[x_start:x_end, y_start:y_end] = self.epsilon_r
53
+
54
+ def _interpret_width_height(self) -> Tuple[float, float]:
55
+ """
56
+ Interpret and return the width and height of the waveguide in grid indices.
57
+
58
+ Returns:
59
+ tuple: The indices of the width and height.
60
+ """
61
+ if isinstance(self.width, str) and self.width.lower() == 'full':
62
+ width_index = self.grid.n_x
63
+ else:
64
+ width_index = self.grid.position_to_index(self.width, axis='x')
65
+
66
+ if isinstance(self.height, str) and self.height.lower() == 'full':
67
+ height_index = self.grid.n_y
68
+ else:
69
+ height_index = self.grid.position_to_index(self.height, axis='y')
70
+
71
+ return int(width_index), int(height_index)
72
+
73
+ def _interpret_position_to_index(self) -> Tuple[int, int]:
74
+ """
75
+ Interpret and return the indices for the positions x and y of the waveguide.
76
+
77
+ Returns:
78
+ tuple: The indices of the x and y positions.
79
+ """
80
+ x, y = self.position
81
+ x_index = self.grid.string_to_position_x(x) if isinstance(x, str) else self.grid.position_to_index(x, axis='x')
82
+ y_index = self.grid.string_to_position_y(y) if isinstance(y, str) else self.grid.position_to_index(y, axis='y')
83
+ return x_index, y_index
84
+
85
+
86
+ @dataclass(config=config_dict)
87
+ class Square(BaseComponent):
88
+ """
89
+ Represents a square scatterer in a simulation grid.
90
+
91
+ Attributes:
92
+ grid (Grid): The grid of the simulation mesh.
93
+ position (Tuple[float | str, float | str]): Starting position of the scatterer (center of the square).
94
+ epsilon_r (float): Relative permittivity inside the scatterer.
95
+ side_length (float): Side length of the square scatterer.
96
+ """
97
+ grid: Grid
98
+ position: Tuple[float | str, float | str]
99
+ epsilon_r: float
100
+ side_length: float
101
+ facecolor: str = 'lightblue'
102
+ edgecolor: str = 'blue'
103
+
104
+ def compute_path(self) -> NoReturn:
105
+ x0, y0 = self.position
106
+ self.coordinate = self.grid.get_coordinate(x=x0, y=y0)
107
+
108
+ half_side = self.side_length / 2
109
+ self.x_start = (self.coordinate.x - half_side)
110
+ self.x_end = (self.coordinate.x + half_side)
111
+ self.y_start = (self.coordinate.y - half_side)
112
+ self.y_end = (self.coordinate.y + half_side)
113
+
114
+ p0 = geo.Point(self.x_start, self.y_start)
115
+ p1 = geo.Point(self.x_start, self.y_end)
116
+ p2 = geo.Point(self.x_end, self.y_start)
117
+ p3 = geo.Point(self.x_end, self.y_end)
118
+
119
+ self.polygon = geo.Polygon([p0, p1, p3, p2])
120
+
121
+ self.path = Path(numpy.array(self.polygon.exterior.coords))
122
+
123
+
124
+ @dataclass(config=config_dict)
125
+ class Circle(BaseComponent):
126
+ """
127
+ Represents a scatterer in a simulation grid.
128
+
129
+ Attributes:
130
+ grid (Grid): The grid of the simulation mesh.
131
+ position (Tuple[float | str, float | str]): Starting position of the scatterer.
132
+ epsilon_r (float): Relative permittivity inside the scatterer.
133
+ radius (float): Radius of the scatterer.
134
+ """
135
+ grid: Grid
136
+ position: Tuple[float | str, float | str]
137
+ epsilon_r: float
138
+ radius: float
139
+ facecolor: str = 'lightblue'
140
+
141
+ def compute_path(self) -> NoReturn:
142
+ x0, y0 = self.position
143
+ self.coordinate = self.grid.get_coordinate(x=x0, y=y0)
144
+ self.polygon = geo.Point(self.coordinate.x, self.coordinate.y).buffer(self.radius)
145
+ self.path = Path(numpy.array(self.polygon.exterior.coords))
146
+
147
+
148
+ @dataclass(config=config_dict)
149
+ class Ellipse(BaseComponent):
150
+ """
151
+ Represents a scatterer in a simulation grid.
152
+
153
+ Attributes:
154
+ grid (Grid): The grid of the simulation mesh.
155
+ position (Tuple[float | str, float | str]): Starting position of the scatterer.
156
+ epsilon_r (float): Relative permittivity inside the scatterer.
157
+ width (float):
158
+ height (float):
159
+ angle (float):
160
+ """
161
+ grid: Grid
162
+ position: Tuple[float | str, float | str]
163
+ width: float
164
+ height: float
165
+ epsilon_r: float
166
+ angle: float = 0
167
+ facecolor: str = 'lightblue'
168
+ edgecolor: str = 'blue'
169
+
170
+ def compute_path(self) -> NoReturn:
171
+ x0, y0 = self.position
172
+ self.coordinate = self.grid.get_coordinate(x=x0, y=y0)
173
+
174
+ polygon = patches.Ellipse(
175
+ (self.coordinate.x, self.coordinate.y),
176
+ width=self.width,
177
+ height=self.height,
178
+ angle=self.angle
179
+ )
180
+
181
+ vertices = polygon.get_verts()
182
+ self.polygon = geo.Polygon(vertices)
183
+ self.path = Path(numpy.array(self.polygon.exterior.coords))
184
+
185
+ # -
@@ -0,0 +1,88 @@
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
+ from MPSPlots.render2D import SceneList
9
+ import shapely.geometry as geo
10
+ from matplotlib.path import Path
11
+ import cv2
12
+ from pydantic.dataclasses import dataclass
13
+ from LightWave2D.components.base_class import BaseComponent
14
+ import matplotlib.pyplot as plt
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(config=config_dict)
25
+ class PointDetector(BaseComponent):
26
+ """
27
+ Represents a point detector within a simulation grid.
28
+
29
+ Attributes:
30
+ grid (Grid): The simulation mesh grid.
31
+ position (Tuple[float | str, float | str]): The (x, y) coordinates of the point detector on the grid.
32
+ data (numpy.ndarray): The data collected by the detector over time.
33
+ """
34
+ grid: Grid
35
+ position: Union[Tuple[float | str, float | str]]
36
+ data: numpy.ndarray = field(init=False)
37
+ facecolor: str = 'blue'
38
+
39
+ def __post_init__(self):
40
+ """
41
+ Initialize the PointDetector by converting the given position into
42
+ grid coordinates and initializing the data array.
43
+ """
44
+ x, y = self.position
45
+
46
+ self.p0 = self.grid.get_coordinate(x=x, y=y)
47
+
48
+ self.polygon = geo.Point(self.p0.x, self.p0.y)
49
+
50
+ self.path = Path(self.polygon.coords)
51
+
52
+ self.data = numpy.zeros(self.grid.n_steps)
53
+
54
+ def update_data(self, field: numpy.ndarray) -> NoReturn:
55
+ """
56
+ Update the detector data based on the provided field values.
57
+
58
+ Parameters:
59
+ field (numpy.ndarray): The field values to update the detector data.
60
+ """
61
+ self.data = field[:, self.p0.x_index, self.p0.y_index]
62
+
63
+ def plot_data(self) -> SceneList:
64
+ """
65
+ Plot the detector data over time.
66
+
67
+ Returns:
68
+ SceneList: A scene list containing the plot.
69
+ """
70
+ scene = SceneList()
71
+ ax = scene.append_ax()
72
+ ax.add_line(x=self.grid.time_stamp, y=self.data)
73
+ return scene
74
+
75
+ def add_to_ax(self, ax: plt.axis) -> NoReturn:
76
+ """
77
+ Add the scatterer to the provided axis as a circle.
78
+
79
+ Args:
80
+ ax (Axis): The axis to which the scatterer will be added.
81
+ """
82
+ ax.scatter(
83
+ self.p0.x,
84
+ self.p0.y,
85
+ color=self.facecolor
86
+ )
87
+
88
+
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from pathlib import Path
5
+ import LightWave2D
6
+
7
+
8
+ __all__ = [
9
+ 'root_path',
10
+ 'project_path',
11
+ 'doc_path',
12
+ 'doc_css_path',
13
+ 'version_path',
14
+ ]
15
+
16
+ root_path = Path(LightWave2D.__path__[0])
17
+
18
+ project_path = root_path.parents[0]
19
+
20
+ doc_path = project_path.joinpath('docs')
21
+
22
+ doc_css_path = doc_path.joinpath('source/_static/default.css')
23
+
24
+ version_path = root_path.joinpath('VERSION')
25
+
26
+
27
+ if __name__ == '__main__':
28
+ for path_name in __all__:
29
+ path = locals()[path_name]
30
+ print(path)
31
+ assert path.exists(), f"Path {path_name} do not exists"
32
+
33
+ # -