ElectroMagneticPython 2.2.3__py3-none-any.whl → 2.2.4__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.
EMpy/_version.py CHANGED
@@ -1,5 +1,6 @@
1
- # file generated by setuptools-scm
1
+ # file generated by vcs-versioning
2
2
  # don't change, don't track in version control
3
+ from __future__ import annotations
3
4
 
4
5
  __all__ = [
5
6
  "__version__",
@@ -10,25 +11,14 @@ __all__ = [
10
11
  "commit_id",
11
12
  ]
12
13
 
13
- TYPE_CHECKING = False
14
- if TYPE_CHECKING:
15
- from typing import Tuple
16
- from typing import Union
17
-
18
- VERSION_TUPLE = Tuple[Union[int, str], ...]
19
- COMMIT_ID = Union[str, None]
20
- else:
21
- VERSION_TUPLE = object
22
- COMMIT_ID = object
23
-
24
14
  version: str
25
15
  __version__: str
26
- __version_tuple__: VERSION_TUPLE
27
- version_tuple: VERSION_TUPLE
28
- commit_id: COMMIT_ID
29
- __commit_id__: COMMIT_ID
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
30
20
 
31
- __version__ = version = '2.2.3'
32
- __version_tuple__ = version_tuple = (2, 2, 3)
21
+ __version__ = version = '2.2.4'
22
+ __version_tuple__ = version_tuple = (2, 2, 4)
33
23
 
34
- __commit_id__ = commit_id = None
24
+ __commit_id__ = commit_id = 'gd8c276251'
EMpy/constants.py CHANGED
@@ -1,5 +1,3 @@
1
- # pylint: disable=C0301
2
-
3
1
  """Useful constants.
4
2
 
5
3
  Constants used in mathematics and electromagnetism.
EMpy/devices.py CHANGED
@@ -1,5 +1,3 @@
1
- # pylint: disable=C0302,W0622,W1001,R0902,R0903,W0201,R0913,R0914,C0325,W0221
2
-
3
1
  """Set of objects and functions to describe the behaviour of some
4
2
  widely known devices and build new ones.
5
3
 
@@ -62,7 +60,7 @@ class DeviceMatrix:
62
60
  return self.__data
63
61
 
64
62
  def setdata(self, value):
65
- self.__data = numpy.asmatrix(value)
63
+ self.__data = numpy.array(value)
66
64
 
67
65
  __data = None
68
66
  data = property(fget=getdata, fset=setdata, doc="data")
@@ -137,6 +135,7 @@ class TransferMatrix(DeviceMatrix):
137
135
 
138
136
  Notation::
139
137
 
138
+
140
139
  b12 = H1 a12 and d12 = H2 c12, but b12 == c12,
141
140
 
142
141
  therefore::
@@ -153,7 +152,7 @@ class TransferMatrix(DeviceMatrix):
153
152
 
154
153
  """
155
154
 
156
- return TransferMatrix(M.to_transfer().data * self.data)
155
+ return TransferMatrix(M.to_transfer().data @ self.data)
157
156
 
158
157
 
159
158
  class ChainMatrix(DeviceMatrix):
@@ -227,7 +226,7 @@ class ChainMatrix(DeviceMatrix):
227
226
 
228
227
  """
229
228
 
230
- return ChainMatrix(self.data * M.to_chain().data)
229
+ return ChainMatrix(self.data @ M.to_chain().data)
231
230
 
232
231
 
233
232
  def composeTM(A, B):
EMpy/materials.py CHANGED
@@ -1,5 +1,3 @@
1
- # pylint: disable=W0622,R0903,R0902,R0913,W0633
2
-
3
1
  """Functions and objects to manipulate materials.
4
2
 
5
3
  A material is an object with a refractive index function.
EMpy/modesolvers/FD.py CHANGED
@@ -1,7 +1,3 @@
1
- # pylint: disable=line-too-long,too-many-locals,too-many-statements,too-many-branches
2
- # pylint: disable=redefined-builtin,wildcard-import,unused-wildcard-import
3
- # pylint: disable=attribute-defined-outside-init,too-many-instance-attributes
4
- # pylint: disable=arguments-differ,too-many-arguments
5
1
  """Finite Difference Modesolver.
6
2
 
7
3
  @see: Fallahkhair, "Vector Finite Difference Modesolver for Anisotropic Dielectric Waveguides",
EMpy/transfer_matrix.py CHANGED
@@ -39,8 +39,8 @@ class IsotropicTransferMatrix(TransferMatrix):
39
39
 
40
40
  INPUT
41
41
  multilayer = Multilayer obj describing the sequence of layers.
42
- theta_inc = angle of the incident wave (in radiant) wrt the
43
- normal.
42
+ theta_inc = angle of the incident wave (in radians) wrt the
43
+ normal, measured in the first layer (multilayer[0]).
44
44
  """
45
45
  if not multilayer.isIsotropic():
46
46
  raise ValueError(
@@ -118,12 +118,14 @@ class IsotropicTransferMatrix(TransferMatrix):
118
118
 
119
119
  Rs[iwl] = np.absolute(rs) ** 2
120
120
  Ts[iwl] = (
121
- np.absolute((n[-1] * np.cos(theta[-1])) / (n[0] * np.cos(theta[0])))
121
+ np.real(n[-1] * np.cos(theta[-1]))
122
+ / np.real(n[0] * np.cos(theta[0]))
122
123
  * np.absolute(ts) ** 2
123
124
  )
124
125
  Rp[iwl] = np.absolute(rp) ** 2
125
126
  Tp[iwl] = (
126
- np.absolute((n[-1] * np.cos(theta[-1])) / (n[0] * np.cos(theta[0])))
127
+ np.real(np.conj(n[-1]) * np.cos(theta[-1]))
128
+ / np.real(np.conj(n[0]) * np.cos(theta[0]))
127
129
  * np.absolute(tp) ** 2
128
130
  )
129
131
 
@@ -160,7 +162,9 @@ class AnisotropicTransferMatrix(TransferMatrix):
160
162
  INPUT
161
163
  multilayer = Multilayer obj describing the sequence of layers.
162
164
  theta_inc_x and theta_inc_y = angles of the incident wave (in
163
- radiant) wrt the normal.
165
+ radians) wrt the normal in vacuum, i.e. kx = k0 * sin(theta_inc_x)
166
+ and ky = k0 * sin(theta_inc_y) (unlike IsotropicTransferMatrix,
167
+ where theta_inc is measured in multilayer[0]).
164
168
  """
165
169
  TransferMatrix.__init__(self, multilayer)
166
170
  self.theta_inc_x = theta_inc_x
EMpy/utils.py CHANGED
@@ -1,5 +1,3 @@
1
- # pylint: disable=R0913,R0914,W0201,W0622,C0302,R0902,R0903,W1001,W0612,W0613
2
-
3
1
  """Useful functions and objects used more or less everywhere."""
4
2
 
5
3
  __author__ = "Lorenzo Bolla"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ElectroMagneticPython
3
- Version: 2.2.3
3
+ Version: 2.2.4
4
4
  Summary: EMpy - ElectroMagnetic Python
5
5
  Author-email: Lorenzo Bolla <code@lbolla.info>
6
6
  License-Expression: MIT
@@ -1,18 +1,18 @@
1
1
  EMpy/RCWA.py,sha256=ORsYHvt1p7TIR3vKYQfhigRH1RnHyAX98kkGMkmxIi0,32673
2
2
  EMpy/__init__.py,sha256=aAaHG0VlGltUrWWZ4JMlVms2HDGj7RZ3CYNKqpZVYtM,1285
3
- EMpy/_version.py,sha256=KPjL9Q7mJ1mOq60evnMRyAe7ifMMp2BfVmDRydV9x98,704
4
- EMpy/constants.py,sha256=x1N8eRXQW_gdr1557n7tvUXiM4RW_Fc_EydLd5AUC1o,723
5
- EMpy/devices.py,sha256=Tu7CVvrhqfHBSf1EiDNPnUG4Dn6MDb6qgg2VpafmdHs,37760
6
- EMpy/materials.py,sha256=pgEM4Izy6HTA87Rl_GtNiiq5AKzc3M54fVFPFRnA8_I,10682
3
+ EMpy/_version.py,sha256=L0uLqtm_cNa8ezMmrDendz17E_txW-SkqG84SLLwt1o,528
4
+ EMpy/constants.py,sha256=kYVVAdOENFthm_Aqt5oT4eMOmbMNdkvpM2t1r-_IShE,698
5
+ EMpy/devices.py,sha256=08LN_Nas0cpzQVj-J3x25AdObycwm_0b6k3s_dw2w6c,37679
6
+ EMpy/materials.py,sha256=2TSTVY5R6tw5auHyWJcvFHSgMA2KANbCCbziuRO0GyY,10633
7
7
  EMpy/scattering.py,sha256=1rY8_TI0kzTLYwpFSSXndaO9FzDzVPRVow55vzIDQiM,7339
8
- EMpy/transfer_matrix.py,sha256=wSFqcEQYNUV4oM5SlZkglwRVyU5_w5dvRENXHfRXQpQ,14582
9
- EMpy/utils.py,sha256=hIZ07CqM1lhRTIujbReGldlBkUjzI3iXAyAReEATBqA,41762
10
- EMpy/modesolvers/FD.py,sha256=vKQOTgXY3-KzODAX0IOAfLbcFHUbpRt0MgteRLU3vjk,79281
8
+ EMpy/transfer_matrix.py,sha256=0xqCbNvlxSQxqcWXm0Q_O0e9NWWvKPMlfZY36HIXAnk,14848
9
+ EMpy/utils.py,sha256=BWgKxpdS29OXWkLp13Ft00ef-vzR8COZO1hn8KsASPc,41683
10
+ EMpy/modesolvers/FD.py,sha256=oBlMSP1F1Ja1NIiIQcxUm-ZWHYYrKQHZaPxQ0ZuPMfY,78988
11
11
  EMpy/modesolvers/FMM.py,sha256=Z0HL_QGeJoQC9vyY2obBomcey0ZzVT5YZmD2-hABqZ8,78351
12
12
  EMpy/modesolvers/__init__.py,sha256=rg8pzFcZd7cihqfXYj0sQamogjtMV3ObNXCNbFD3bu0,222
13
13
  EMpy/modesolvers/geometries.py,sha256=X8Jd1iNoPRl5ibZiaKG13lHDIzejQ6PfrB6Zbe_c5lg,7906
14
14
  EMpy/modesolvers/interface.py,sha256=spMy30TFedYXJHcoV3yUdGkycGt5cplJUCeZui6a5MY,2397
15
- electromagneticpython-2.2.3.dist-info/licenses/LICENSE,sha256=NlQFsrkwMvQ2aD8531IDm6Rk01KzlI42HVzK5M1Hpw8,1065
15
+ electromagneticpython-2.2.4.dist-info/licenses/LICENSE,sha256=NlQFsrkwMvQ2aD8531IDm6Rk01KzlI42HVzK5M1Hpw8,1065
16
16
  examples/ex_APRR.py,sha256=f3-LOPoLNSxjqfwAJJNjVSnKYB88CIULhbjzkzdavXA,459
17
17
  examples/ex_NRR.py,sha256=NVs4UASVdwiogZDSOfGAoSnbBByhB8EBLu4x3CDOnyE,900
18
18
  examples/ex_RCWA.py,sha256=05Cvv3BqFgSDn_u2iZsV65HdmvVbNljgJfISaPsqd1o,2733
@@ -27,7 +27,7 @@ examples/ex_modesolver_4.py,sha256=9JUjg6NK7IjwSgQvg3D_n6l_Cr0ev6hEoJGS0xffrFo,9
27
27
  examples/ex_modesolver_dch.py,sha256=ha38QB7rLklEnTNfF_C0b8u7gTGKIk_T3FB0TMib5eM,7314
28
28
  examples/ex_modesolver_dch_anis.py,sha256=Ye4nV5FXVxjT-FtJ3CyjzjXh9pmx9A0mbv-CkZxIN3Y,8184
29
29
  examples/ex_transfer_matrix.py,sha256=JyC_MPrrfpNItYmMQjm5RbMWXe7CSd96RplJrntdOaI,1789
30
- examples/ex_transfer_matrix_2.py,sha256=i1YMmrOSWDK0YS9aGF2thFD4_suNZsRJvs7Ei62sHAI,1058
30
+ examples/ex_transfer_matrix_2.py,sha256=anMoXcGgpioJ5k0AvHHFEynT32etWFgmEpLy5SL2nNI,1060
31
31
  examples/ex_transfer_matrix_2.py.png,sha256=-cgjAE1t_6UPJyOZbAagaaBs-odr59A1RYldSpMOo0M,34886
32
32
  examples/ex_transfer_matrix_3.py,sha256=J8GePd3b45TmGJWL_Df7GFg-4FN8846WS9j7l9TmvRs,1501
33
33
  examples/lc_data.dat,sha256=MrT57K7PZV0YT2GPU9LjO6WlC-xCd6n841P57tQW5_s,4151
@@ -37,8 +37,9 @@ tests/__init__.py,sha256=XNMyfmlHhqih2xHEklXlmQ8GVUAdiiWrkT3trIOMpRQ,29
37
37
  tests/devices_test.py,sha256=UbmJgHp7kNVQyBYwxgaAierUVMvC7Pq5Jv7BKdFQPSw,890
38
38
  tests/materials_test.py,sha256=-Z8ZmqwgSCg2AJwF_4j-RH8Ct7AOOWhV67lyMm5dcO8,1846
39
39
  tests/modesolvers_test.py,sha256=v_nRDbKlda4w7A5mbZZl5fKYa2GlgLzHZaKDJZzGyrM,984
40
+ tests/transfer_matrix_test.py,sha256=hp9idGz0G9BcriJYVxtJJokROqliSyl8RR4Zuxjm8Tw,5330
40
41
  tests/utils_test.py,sha256=QnG4O_FHrX6tXH1MuocFXxptOuOtoU-dR-crCtADzQw,721
41
- electromagneticpython-2.2.3.dist-info/METADATA,sha256=XB6uQFtMcIOL-56FDLYMqR1_i_Cne79NZP4UApAC8os,2351
42
- electromagneticpython-2.2.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
43
- electromagneticpython-2.2.3.dist-info/top_level.txt,sha256=CosMJsXjoaa3iZmCrZf7E0eorTFxpEFfrtfUx1YWIHA,28
44
- electromagneticpython-2.2.3.dist-info/RECORD,,
42
+ electromagneticpython-2.2.4.dist-info/METADATA,sha256=bHDIDEcgf6o6NK-aSI3g1pBTf02A9VXpuicoHsF9zvU,2351
43
+ electromagneticpython-2.2.4.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
44
+ electromagneticpython-2.2.4.dist-info/top_level.txt,sha256=CosMJsXjoaa3iZmCrZf7E0eorTFxpEFfrtfUx1YWIHA,28
45
+ electromagneticpython-2.2.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.2)
2
+ Generator: setuptools (84.2.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -40,5 +40,5 @@ plt.xlabel("wavelength /m")
40
40
  plt.ylabel("Power /dB")
41
41
  plt.grid()
42
42
  plt.xlim(wls.min(), wls.max())
43
- plt.savefig(__file__ + ".png")
43
+ # plt.savefig(__file__ + ".png")
44
44
  plt.show()
@@ -0,0 +1,134 @@
1
+ from unittest import TestCase
2
+
3
+ import numpy as np
4
+ from numpy.testing import assert_allclose
5
+
6
+ import EMpy
7
+
8
+
9
+ def _make_iso_multilayer(n_list, d_list):
10
+ layers = EMpy.utils.Multilayer()
11
+ for n, d in zip(n_list, d_list):
12
+ mat = EMpy.materials.IsotropicMaterial(
13
+ "mat", n0=EMpy.materials.RefractiveIndex(n0_const=n)
14
+ )
15
+ layers.append(EMpy.utils.Layer(mat, d))
16
+ return layers
17
+
18
+
19
+ def _make_aniso_multilayer(n_list, d_list):
20
+ layers = EMpy.utils.Multilayer()
21
+ for n, d in zip(n_list, d_list):
22
+ eps = EMpy.materials.EpsilonTensor(
23
+ epsilon_tensor_const=(n**2) * EMpy.constants.eps0 * np.eye(3)
24
+ )
25
+ mat = EMpy.materials.AnisotropicMaterial("mat", epsilon_tensor=eps)
26
+ layers.append(EMpy.utils.Layer(mat, d))
27
+ return layers
28
+
29
+
30
+ class TransferMatrixTest(TestCase):
31
+
32
+ def test_fresnel_brewster(self):
33
+ n1, n2 = 1.0, 1.5
34
+ theta_b = np.arctan2(n2, n1)
35
+ layers = _make_iso_multilayer([n1, n2], [np.inf, np.inf])
36
+ sol = EMpy.transfer_matrix.IsotropicTransferMatrix(layers, theta_b).solve(
37
+ [1.55e-6]
38
+ )
39
+ assert_allclose(sol.Rp, [0.0], atol=1e-15)
40
+ assert_allclose(sol.Tp, [1.0], atol=1e-15)
41
+ assert_allclose(sol.Rs + sol.Ts, [1.0], atol=1e-15)
42
+
43
+ def test_total_internal_reflection(self):
44
+ layers = _make_iso_multilayer([1.5, 1.0], [np.inf, np.inf])
45
+ theta_inc = EMpy.utils.deg2rad(60.0)
46
+ sol = EMpy.transfer_matrix.IsotropicTransferMatrix(layers, theta_inc).solve(
47
+ [1.55e-6]
48
+ )
49
+ assert_allclose(sol.Rs, [1.0], atol=1e-15)
50
+ assert_allclose(sol.Ts, [0.0], atol=1e-15)
51
+ assert_allclose(sol.Rp, [1.0], atol=1e-15)
52
+ assert_allclose(sol.Tp, [0.0], atol=1e-15)
53
+
54
+ def test_frustrated_total_internal_reflection(self):
55
+ layers = _make_iso_multilayer([1.5, 1.0, 1.5], [np.inf, 0.2e-6, np.inf])
56
+ theta_inc = EMpy.utils.deg2rad(60.0)
57
+ sol = EMpy.transfer_matrix.IsotropicTransferMatrix(layers, theta_inc).solve(
58
+ [1.55e-6]
59
+ )
60
+ self.assertTrue((0.0 < sol.Ts[0] < 1.0) and (0.0 < sol.Tp[0] < 1.0))
61
+ assert_allclose(sol.Rs + sol.Ts, [1.0], atol=1e-15)
62
+ assert_allclose(sol.Rp + sol.Tp, [1.0], atol=1e-15)
63
+
64
+ def test_absorbing_exit_medium(self):
65
+ wls = [1.55e-6]
66
+ theta_inc = EMpy.utils.deg2rad(40.0)
67
+ n_list = [1.0, 1.5 - 0.5j]
68
+ d_list = [np.inf, np.inf]
69
+
70
+ iso_layers = _make_iso_multilayer(n_list, d_list)
71
+ aniso_layers = _make_aniso_multilayer(n_list, d_list)
72
+
73
+ sol_iso = EMpy.transfer_matrix.IsotropicTransferMatrix(
74
+ iso_layers, theta_inc
75
+ ).solve(wls)
76
+ sol_aniso = EMpy.transfer_matrix.AnisotropicTransferMatrix(
77
+ aniso_layers, theta_inc, 0.0
78
+ ).solve(wls)
79
+
80
+ # Single interface from lossless medium: net flux across z=0 is conserved
81
+ assert_allclose(sol_iso.Rs + sol_iso.Ts, [1.0], atol=1e-15)
82
+ assert_allclose(sol_iso.Rp + sol_iso.Tp, [1.0], atol=1e-15)
83
+
84
+ assert_allclose(sol_iso.Rs, sol_aniso.R[0, 0, :], rtol=1e-6)
85
+ assert_allclose(sol_iso.Ts, sol_aniso.T[0, 0, :], rtol=1e-6)
86
+ assert_allclose(sol_iso.Rp, sol_aniso.R[1, 1, :], rtol=1e-6)
87
+ assert_allclose(sol_iso.Tp, sol_aniso.T[1, 1, :], rtol=1e-6)
88
+
89
+ def test_absorbing_slab(self):
90
+ wls = [1.55e-6]
91
+ theta_inc = EMpy.utils.deg2rad(20.0)
92
+ n_list = [1.0, 2.0 - 0.1j, 1.0]
93
+ d_list = [np.inf, 0.5e-6, np.inf]
94
+
95
+ iso_layers = _make_iso_multilayer(n_list, d_list)
96
+ aniso_layers = _make_aniso_multilayer(n_list, d_list)
97
+
98
+ sol_iso = EMpy.transfer_matrix.IsotropicTransferMatrix(
99
+ iso_layers, theta_inc
100
+ ).solve(wls)
101
+ sol_aniso = EMpy.transfer_matrix.AnisotropicTransferMatrix(
102
+ aniso_layers, theta_inc, 0.0
103
+ ).solve(wls)
104
+
105
+ self.assertLess(sol_iso.Rs[0] + sol_iso.Ts[0], 1.0)
106
+ self.assertLess(sol_iso.Rp[0] + sol_iso.Tp[0], 1.0)
107
+ assert_allclose(sol_iso.Rs, sol_aniso.R[0, 0, :], rtol=1e-6)
108
+ assert_allclose(sol_iso.Ts, sol_aniso.T[0, 0, :], rtol=1e-6)
109
+ assert_allclose(sol_iso.Rp, sol_aniso.R[1, 1, :], rtol=1e-6)
110
+ assert_allclose(sol_iso.Tp, sol_aniso.T[1, 1, :], rtol=1e-6)
111
+
112
+ def test_iso_vs_aniso_non_unit_incident_index(self):
113
+ wls = np.linspace(1.4e-6, 1.7e-6, 5)
114
+ n_list = [1.5, 2.1, 1.0]
115
+ d_list = [np.inf, 0.3e-6, np.inf]
116
+ theta_inc = EMpy.utils.deg2rad(30.0)
117
+ theta_vac = np.arcsin(n_list[0] * np.sin(theta_inc))
118
+
119
+ iso_layers = _make_iso_multilayer(n_list, d_list)
120
+ aniso_layers = _make_aniso_multilayer(n_list, d_list)
121
+
122
+ sol_iso = EMpy.transfer_matrix.IsotropicTransferMatrix(
123
+ iso_layers, theta_inc
124
+ ).solve(wls)
125
+ sol_aniso = EMpy.transfer_matrix.AnisotropicTransferMatrix(
126
+ aniso_layers, theta_vac, 0.0
127
+ ).solve(wls)
128
+
129
+ assert_allclose(sol_iso.Rs + sol_iso.Ts, 1.0, atol=1e-14)
130
+ assert_allclose(sol_iso.Rp + sol_iso.Tp, 1.0, atol=1e-14)
131
+ assert_allclose(sol_iso.Rs, sol_aniso.R[0, 0, :], rtol=1e-6)
132
+ assert_allclose(sol_iso.Ts, sol_aniso.T[0, 0, :], rtol=1e-6)
133
+ assert_allclose(sol_iso.Rp, sol_aniso.R[1, 1, :], rtol=1e-6)
134
+ assert_allclose(sol_iso.Tp, sol_aniso.T[1, 1, :], rtol=1e-6)