ElectroMagneticPython 2.2.1__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.
Files changed (46) hide show
  1. EMpy/RCWA.py +32 -12
  2. EMpy/__init__.py +10 -2
  3. EMpy/_version.py +24 -0
  4. EMpy/constants.py +0 -2
  5. EMpy/devices.py +8 -32
  6. EMpy/materials.py +1 -8
  7. EMpy/modesolvers/FD.py +34 -76
  8. EMpy/modesolvers/FMM.py +24 -23
  9. EMpy/modesolvers/__init__.py +1 -0
  10. EMpy/modesolvers/geometries.py +8 -9
  11. EMpy/transfer_matrix.py +10 -6
  12. EMpy/utils.py +12 -26
  13. electromagneticpython-2.2.4.dist-info/METADATA +99 -0
  14. electromagneticpython-2.2.4.dist-info/RECORD +45 -0
  15. {ElectroMagneticPython-2.2.1.dist-info → electromagneticpython-2.2.4.dist-info}/WHEEL +1 -1
  16. electromagneticpython-2.2.4.dist-info/top_level.txt +4 -0
  17. examples/ex_APRR.py +18 -0
  18. examples/ex_NRR.py +40 -0
  19. examples/ex_RCWA.py +95 -0
  20. examples/ex_RCWA_2.py +52 -0
  21. examples/ex_RCWA_3.py +58 -0
  22. examples/ex_SRR.py +23 -0
  23. examples/ex_laser_etch_monitor.py +241 -0
  24. examples/ex_modesolver.py +68 -0
  25. examples/ex_modesolver_2.py +58 -0
  26. examples/ex_modesolver_3.py +48 -0
  27. examples/ex_modesolver_4.py +43 -0
  28. examples/ex_modesolver_dch.py +296 -0
  29. examples/ex_modesolver_dch_anis.py +318 -0
  30. examples/ex_transfer_matrix.py +82 -0
  31. examples/ex_transfer_matrix_2.py +44 -0
  32. examples/ex_transfer_matrix_2.py.png +0 -0
  33. examples/ex_transfer_matrix_3.py +60 -0
  34. examples/lc_data.dat +27 -0
  35. examples/nk.py +1468 -0
  36. scripts/FDTD.py +741 -0
  37. tests/devices_test.py +31 -0
  38. tests/materials_test.py +1 -1
  39. tests/modesolvers_test.py +36 -0
  40. tests/transfer_matrix_test.py +134 -0
  41. tests/utils_test.py +9 -5
  42. EMpy/version.py +0 -1
  43. ElectroMagneticPython-2.2.1.dist-info/METADATA +0 -109
  44. ElectroMagneticPython-2.2.1.dist-info/RECORD +0 -22
  45. ElectroMagneticPython-2.2.1.dist-info/top_level.txt +0 -2
  46. {ElectroMagneticPython-2.2.1.dist-info → electromagneticpython-2.2.4.dist-info/licenses}/LICENSE +0 -0
EMpy/modesolvers/FMM.py CHANGED
@@ -13,15 +13,16 @@ Examples
13
13
  See L{FMM1d} and L{FMM2d}.
14
14
 
15
15
  """
16
- import copy
17
- from functools import reduce
18
16
 
19
17
  __author__ = "Luca Gamberale & Lorenzo Bolla"
20
18
 
19
+ import copy
20
+ from functools import reduce
21
+
22
+ from matplotlib import pyplot as plt
21
23
  import numpy
22
24
  import scipy
23
25
  import scipy.optimize
24
- import pylab
25
26
 
26
27
  import EMpy.utils
27
28
  from EMpy.modesolvers.interface import Mode, ModeSolver
@@ -247,11 +248,11 @@ class FMMMode1dy(FMMMode1d):
247
248
 
248
249
  def plot(self, y):
249
250
  f = self.eval(y)
250
- pylab.plot(y, numpy.real(f), y, numpy.imag(y))
251
- pylab.legend(("real", "imag"))
252
- pylab.xlabel("y")
253
- pylab.ylabel("mode1d")
254
- pylab.show()
251
+ plt.plot(y, numpy.real(f), y, numpy.imag(y))
252
+ plt.legend(("real", "imag"))
253
+ plt.xlabel("y")
254
+ plt.ylabel("mode1d")
255
+ plt.show()
255
256
 
256
257
  def __str__(self):
257
258
  return (
@@ -845,26 +846,26 @@ class FMMMode2d(Mode):
845
846
  f = self.fields(x, y)
846
847
 
847
848
  # fields
848
- pylab.figure()
849
+ plt.figure()
849
850
  titles = ["Ex", "Ey", "Ez", "cBx", "cBy", "cBz"]
850
851
  for i in range(6):
851
852
  subplot_id = 231 + i
852
- pylab.subplot(subplot_id)
853
- pylab.contour(x, y, numpy.abs(f[i]))
854
- pylab.xlabel("x")
855
- pylab.ylabel("y")
856
- pylab.title(titles[i])
857
- pylab.axis("image")
858
- pylab.show()
853
+ plt.subplot(subplot_id)
854
+ plt.contour(x, y, numpy.abs(f[i]))
855
+ plt.xlabel("x")
856
+ plt.ylabel("y")
857
+ plt.title(titles[i])
858
+ plt.axis("image")
859
+ plt.show()
859
860
 
860
861
  # power
861
- pylab.figure()
862
- pylab.contour(x, y, numpy.abs(f[-1]))
863
- pylab.xlabel("x")
864
- pylab.ylabel("y")
865
- pylab.title("cSz")
866
- pylab.axis("image")
867
- pylab.show()
862
+ plt.figure()
863
+ plt.contour(x, y, numpy.abs(f[-1]))
864
+ plt.xlabel("x")
865
+ plt.ylabel("y")
866
+ plt.title("cSz")
867
+ plt.axis("image")
868
+ plt.show()
868
869
 
869
870
  def __str__(self):
870
871
  return "neff = %s" % (self.keff / (2 * numpy.pi / self.slicesx[0].wl))
@@ -7,6 +7,7 @@ Modesolvers:
7
7
 
8
8
 
9
9
  """
10
+
10
11
  __all__ = ["FD", "FMM", "geometries"]
11
12
  __author__ = "Lorenzo Bolla"
12
13
 
@@ -1,8 +1,7 @@
1
- """Geometries.
1
+ """Geometries."""
2
2
 
3
- """
3
+ from matplotlib import pyplot as plt
4
4
  import numpy
5
- import pylab
6
5
 
7
6
  from EMpy.modesolvers.interface import interface_matrix
8
7
 
@@ -89,8 +88,8 @@ class SWG:
89
88
  numpy.abs(coeffLHS) ** 2 * tmp[:, numpy.newaxis] * const_z
90
89
  + numpy.abs(coeffRHS) ** 2 * tmp[:, numpy.newaxis] * const_z
91
90
  )
92
- pylab.hot()
93
- pylab.contourf(x, z0 + z, numpy.abs(f).T, 16)
91
+ plt.hot()
92
+ plt.contourf(x, z0 + z, numpy.abs(f).T, 16)
94
93
 
95
94
 
96
95
  class SimpleJoint:
@@ -221,9 +220,9 @@ class GenericDevice:
221
220
  for d in self.devlist:
222
221
  d.plot(sumx, nxy, nz, z0=z)
223
222
  z += d.length
224
- pylab.ylabel("z")
223
+ plt.ylabel("z")
225
224
  if sumx is None:
226
- pylab.xlabel("y")
225
+ plt.xlabel("y")
227
226
  else:
228
- pylab.xlabel("x")
229
- pylab.axis("tight")
227
+ plt.xlabel("x")
228
+ plt.axis("tight")
EMpy/transfer_matrix.py CHANGED
@@ -7,6 +7,7 @@ any thickness.
7
7
  Two versions of the algorithm are present: an isotropic one and an
8
8
  anisotropic one.
9
9
  """
10
+
10
11
  __author__ = "Lorenzo Bolla"
11
12
 
12
13
  import numpy as np
@@ -18,7 +19,6 @@ from EMpy.constants import c, mu0
18
19
 
19
20
 
20
21
  class TransferMatrix:
21
-
22
22
  """Class to handle the transfer matrix solvers."""
23
23
 
24
24
  def __init__(self, multilayer):
@@ -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,21 +1,21 @@
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"
6
4
 
5
+ import time
6
+ import sys
7
+
8
+ from matplotlib import pyplot as plt
7
9
  import numpy
8
- import EMpy.constants
9
- import EMpy.materials
10
10
  import scipy.linalg
11
11
  import scipy.interpolate
12
12
  import scipy.optimize
13
- import time
14
- import sys
15
13
 
14
+ import EMpy.constants
15
+ import EMpy.materials
16
16
 
17
- class Layer:
18
17
 
18
+ class Layer:
19
19
  """A layer is defined by a material (iso or aniso) and a thickness."""
20
20
 
21
21
  def __init__(self, mat, thickness):
@@ -96,9 +96,7 @@ class BinaryGrating:
96
96
  f = self.dc
97
97
  h = numpy.arange(-hmax, hmax + 1)
98
98
  EPS = (rix1**2 - rix2**2) * f * numpy.sinc(h * f) + rix2**2 * (h == 0)
99
- EPS1 = (rix1**-2 - rix2**-2) * f * numpy.sinc(h * f) + rix2**-2 * (
100
- h == 0
101
- )
99
+ EPS1 = (rix1**-2 - rix2**-2) * f * numpy.sinc(h * f) + rix2**-2 * (h == 0)
102
100
  return EPS, EPS1
103
101
  else:
104
102
  # anisotropic
@@ -694,7 +692,6 @@ class LiquidCrystalCell:
694
692
 
695
693
 
696
694
  class Multilayer:
697
-
698
695
  """A Multilayer is a list of layers with some more methods."""
699
696
 
700
697
  def __init__(self, data=None):
@@ -816,22 +813,17 @@ class Slice(Multilayer):
816
813
  return self[0]
817
814
 
818
815
  def plot(self, x0, x1, nmin, nmax, wl=1.55e-6):
819
- try:
820
- import pylab
821
- except ImportError:
822
- warning("no pylab installed")
823
- return
824
816
  y0 = 0
825
817
  # ytot = sum([l.thickness for l in self])
826
818
  for l in self:
827
819
  y1 = y0 + l.thickness
828
820
  n = l.mat.n(wl)
829
821
  r = 1.0 - (1.0 * (n - nmin) / (nmax - nmin))
830
- pylab.fill(
822
+ plt.fill(
831
823
  [x0, x1, x1, x0], [y0, y0, y1, y1], ec="yellow", fc=(r, r, r), alpha=0.5
832
824
  )
833
825
  y0 = y1
834
- pylab.axis("image")
826
+ plt.axis("image")
835
827
 
836
828
  def __str__(self):
837
829
  return "width = %e\n%s" % (self.width, Multilayer.__str__(self))
@@ -916,11 +908,6 @@ class CrossSection(list):
916
908
  return eps
917
909
 
918
910
  def plot(self, wl=1.55e-6):
919
- try:
920
- import pylab
921
- except ImportError:
922
- warning("no pylab installed")
923
- return
924
911
  x0 = 0
925
912
  ns = [[l.mat.n(wl) for l in s] for s in self]
926
913
  nmax = max(max(ns))
@@ -929,7 +916,7 @@ class CrossSection(list):
929
916
  x1 = x0 + s.width
930
917
  s.plot(x0, x1, nmin, nmax, wl=wl)
931
918
  x0 = x1
932
- pylab.axis("image")
919
+ plt.axis("image")
933
920
 
934
921
 
935
922
  class Peak:
@@ -1218,7 +1205,7 @@ def interp2(x, y, xp, yp, fp):
1218
1205
 
1219
1206
  def trapz2(f, x=None, y=None, dx=1.0, dy=1.0):
1220
1207
  """Double integrate."""
1221
- return numpy.trapz(numpy.trapz(f, x=y, dx=dy), x=x, dx=dx)
1208
+ return numpy.trapezoid(numpy.trapezoid(f, x=y, dx=dy), x=x, dx=dx)
1222
1209
 
1223
1210
 
1224
1211
  def centered1d(x):
@@ -1251,7 +1238,6 @@ def warning(s):
1251
1238
 
1252
1239
 
1253
1240
  class ProgressBar:
1254
-
1255
1241
  """Creates a text-based progress bar. Call the object with the `print'
1256
1242
  command to see the progress bar, which looks something like this:
1257
1243
 
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.4
2
+ Name: ElectroMagneticPython
3
+ Version: 2.2.4
4
+ Summary: EMpy - ElectroMagnetic Python
5
+ Author-email: Lorenzo Bolla <code@lbolla.info>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, http://lbolla.github.io/EMpy/
8
+ Project-URL: Repository, https://github.com/lbolla/EMpy
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Natural Language :: English
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Topic :: Scientific/Engineering :: Physics
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: numpy>=1.18
20
+ Requires-Dist: scipy>=1.7
21
+ Requires-Dist: matplotlib>=3.1
22
+ Dynamic: license-file
23
+
24
+ # EMpy - ElectroMagnetic Python
25
+
26
+ [![CI](https://github.com/lbolla/EMpy/actions/workflows/python-app.yml/badge.svg)](https://github.com/lbolla/EMpy/actions/workflows/python-app.yml) [![PyPI](https://badge.fury.io/py/ElectroMagneticPython.svg)](https://badge.fury.io/py/ElectroMagneticPython)
27
+
28
+ `EMpy - ElectroMagnetic Python` is a suite of algorithms widely known and used in electromagnetic problems and optics: the transfer matrix algorithm, the rigorous coupled wave analysis algorithm and more.
29
+
30
+ Run the examples in `examples/*` to have an idea how EMpy works.
31
+
32
+ Visit https://lbolla.github.io/EMpy/ for more information.
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install ElectromagneticPython
38
+ ```
39
+
40
+ Optionally, install `bvp`:
41
+
42
+ ```bash
43
+ pip install scikits.bvp1lg
44
+ ```
45
+
46
+ ## Development
47
+
48
+ First, download the source code from https://github.com/lbolla/EMpy.
49
+
50
+ EMpy is managed with `uv` (https://docs.astral.sh/uv/):
51
+
52
+ Install dev environment with:
53
+
54
+ ```bash
55
+ make develop
56
+ ```
57
+
58
+ Run tests with:
59
+
60
+ ```bash
61
+ make test
62
+ ```
63
+
64
+ Run examples with, e.g.:
65
+ ```bash
66
+ uv run examples/ex_APRR.py
67
+ ```
68
+
69
+ Upgrade dependencies with `uv`:
70
+
71
+ ```bash
72
+ make upgrade
73
+ ```
74
+
75
+ ## Release process
76
+
77
+ Package version is handled by `setuptools_scm`/`uv`:
78
+
79
+ ```bash
80
+ make release PART=...
81
+ ```
82
+
83
+ GitHub actions will build and upload the package to PyPI.
84
+
85
+ ## Citation
86
+
87
+ If you find EMpy useful in your job, please consider adding a citation.
88
+
89
+ As reference:
90
+
91
+ ```
92
+ Bolla, L. (2017). EMpy [Computer software]. https://github.com/lbolla/EMpy/
93
+ ```
94
+
95
+ As text:
96
+
97
+ ```
98
+ We used EMpy (version x.y.z) to complete our work.
99
+ ```
@@ -0,0 +1,45 @@
1
+ EMpy/RCWA.py,sha256=ORsYHvt1p7TIR3vKYQfhigRH1RnHyAX98kkGMkmxIi0,32673
2
+ EMpy/__init__.py,sha256=aAaHG0VlGltUrWWZ4JMlVms2HDGj7RZ3CYNKqpZVYtM,1285
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
+ EMpy/scattering.py,sha256=1rY8_TI0kzTLYwpFSSXndaO9FzDzVPRVow55vzIDQiM,7339
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
+ EMpy/modesolvers/FMM.py,sha256=Z0HL_QGeJoQC9vyY2obBomcey0ZzVT5YZmD2-hABqZ8,78351
12
+ EMpy/modesolvers/__init__.py,sha256=rg8pzFcZd7cihqfXYj0sQamogjtMV3ObNXCNbFD3bu0,222
13
+ EMpy/modesolvers/geometries.py,sha256=X8Jd1iNoPRl5ibZiaKG13lHDIzejQ6PfrB6Zbe_c5lg,7906
14
+ EMpy/modesolvers/interface.py,sha256=spMy30TFedYXJHcoV3yUdGkycGt5cplJUCeZui6a5MY,2397
15
+ electromagneticpython-2.2.4.dist-info/licenses/LICENSE,sha256=NlQFsrkwMvQ2aD8531IDm6Rk01KzlI42HVzK5M1Hpw8,1065
16
+ examples/ex_APRR.py,sha256=f3-LOPoLNSxjqfwAJJNjVSnKYB88CIULhbjzkzdavXA,459
17
+ examples/ex_NRR.py,sha256=NVs4UASVdwiogZDSOfGAoSnbBByhB8EBLu4x3CDOnyE,900
18
+ examples/ex_RCWA.py,sha256=05Cvv3BqFgSDn_u2iZsV65HdmvVbNljgJfISaPsqd1o,2733
19
+ examples/ex_RCWA_2.py,sha256=Iwb75g2OYWayBpGn2P5BlPBh_50ZeM354eJ3kjj8pgg,1455
20
+ examples/ex_RCWA_3.py,sha256=unROedjRchAnLmyqPdhkl2-qekmddtWw6d8i6oo5VQU,1329
21
+ examples/ex_SRR.py,sha256=ciRDjn0IlpThYVLpSkn2dW6oOnJwt7_c7JJzMydl444,612
22
+ examples/ex_laser_etch_monitor.py,sha256=n6Ov8BvStKw-2veSNvX2nmR2VQJyWfsyOSh1ggvZ2qM,7589
23
+ examples/ex_modesolver.py,sha256=gD06Z2DXrxVCfakAIkqNR5k7ynSz5e1hfEYvt8ZyO0w,1529
24
+ examples/ex_modesolver_2.py,sha256=nWohSs9eftfY06wsg13M3UHBMcmM0QdPrOEWNta28mo,1264
25
+ examples/ex_modesolver_3.py,sha256=RA6LvitShITChg4DWFleI8FUUOnSUwIOCsxfW4VByGg,1209
26
+ examples/ex_modesolver_4.py,sha256=9JUjg6NK7IjwSgQvg3D_n6l_Cr0ev6hEoJGS0xffrFo,901
27
+ examples/ex_modesolver_dch.py,sha256=ha38QB7rLklEnTNfF_C0b8u7gTGKIk_T3FB0TMib5eM,7314
28
+ examples/ex_modesolver_dch_anis.py,sha256=Ye4nV5FXVxjT-FtJ3CyjzjXh9pmx9A0mbv-CkZxIN3Y,8184
29
+ examples/ex_transfer_matrix.py,sha256=JyC_MPrrfpNItYmMQjm5RbMWXe7CSd96RplJrntdOaI,1789
30
+ examples/ex_transfer_matrix_2.py,sha256=anMoXcGgpioJ5k0AvHHFEynT32etWFgmEpLy5SL2nNI,1060
31
+ examples/ex_transfer_matrix_2.py.png,sha256=-cgjAE1t_6UPJyOZbAagaaBs-odr59A1RYldSpMOo0M,34886
32
+ examples/ex_transfer_matrix_3.py,sha256=J8GePd3b45TmGJWL_Df7GFg-4FN8846WS9j7l9TmvRs,1501
33
+ examples/lc_data.dat,sha256=MrT57K7PZV0YT2GPU9LjO6WlC-xCd6n841P57tQW5_s,4151
34
+ examples/nk.py,sha256=hjUhwu4QzXCR0_PSKAnQ0RTD4mfe7xCYW6AbrSu4d3U,43161
35
+ scripts/FDTD.py,sha256=eK3Ra8GqkgWGP_oAPrM5pXlxERWgrwl2jwJIwoYGDfE,25308
36
+ tests/__init__.py,sha256=XNMyfmlHhqih2xHEklXlmQ8GVUAdiiWrkT3trIOMpRQ,29
37
+ tests/devices_test.py,sha256=UbmJgHp7kNVQyBYwxgaAierUVMvC7Pq5Jv7BKdFQPSw,890
38
+ tests/materials_test.py,sha256=-Z8ZmqwgSCg2AJwF_4j-RH8Ct7AOOWhV67lyMm5dcO8,1846
39
+ tests/modesolvers_test.py,sha256=v_nRDbKlda4w7A5mbZZl5fKYa2GlgLzHZaKDJZzGyrM,984
40
+ tests/transfer_matrix_test.py,sha256=hp9idGz0G9BcriJYVxtJJokROqliSyl8RR4Zuxjm8Tw,5330
41
+ tests/utils_test.py,sha256=QnG4O_FHrX6tXH1MuocFXxptOuOtoU-dR-crCtADzQw,721
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 (75.7.0)
2
+ Generator: setuptools (84.2.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,4 @@
1
+ EMpy
2
+ examples
3
+ scripts
4
+ tests
examples/ex_APRR.py ADDED
@@ -0,0 +1,18 @@
1
+ """All-pass ring resonator example."""
2
+
3
+ from matplotlib import pyplot as plt
4
+ import numpy
5
+
6
+ import EMpy
7
+
8
+ wls = numpy.linspace(1.5e-6, 1.6e-6, 1000)
9
+ K = EMpy.devices.Coupler(wls, numpy.sqrt(0.08), 1.0)
10
+ l = 2 * numpy.pi * 5e-6
11
+ SWG = EMpy.devices.SWG(400, 220, 125).solve(wls)
12
+ APRR = EMpy.devices.APRR(K, SWG.neff, l).solve()
13
+
14
+ plt.plot(wls, numpy.unwrap(numpy.angle(APRR.THRU)), "r.-")
15
+ plt.axis("tight")
16
+ plt.xlabel("wavelength /m")
17
+ plt.ylabel("phase")
18
+ plt.show()
examples/ex_NRR.py ADDED
@@ -0,0 +1,40 @@
1
+ """N-Ring resonators example."""
2
+
3
+
4
+ from matplotlib import pyplot as plt
5
+ import numpy
6
+
7
+ import EMpy
8
+
9
+ wls = numpy.linspace(1.53e-6, 1.57e-6, 1000)
10
+
11
+ Ks = [
12
+ EMpy.devices.Coupler(wls, numpy.sqrt(0.08), 1.0),
13
+ EMpy.devices.Coupler(wls, numpy.sqrt(0.008), 1.0),
14
+ EMpy.devices.Coupler(wls, numpy.sqrt(0.006), 1.0),
15
+ EMpy.devices.Coupler(wls, numpy.sqrt(0.09), 1.0),
16
+ ]
17
+
18
+ R = 5e-6
19
+ l1s = [numpy.pi * R, numpy.pi * R, numpy.pi * R]
20
+ l2s = [numpy.pi * R, numpy.pi * R, numpy.pi * R]
21
+
22
+ SWG = EMpy.devices.SWG(400, 220, 125).solve(wls)
23
+ neffs = [SWG.neff, SWG.neff, SWG.neff]
24
+
25
+ NRR = EMpy.devices.NRR(Ks, neffs, l1s, l2s).solve()
26
+
27
+ plt.plot(
28
+ wls,
29
+ 20 * numpy.log10(numpy.absolute(NRR.THRU)),
30
+ "r.-",
31
+ wls,
32
+ 20 * numpy.log10(numpy.absolute(NRR.DROP)),
33
+ "g.-",
34
+ )
35
+ plt.axis("tight")
36
+ plt.ylim([-30, 0])
37
+ plt.xlabel("wavelength /m")
38
+ plt.ylabel("power /dB")
39
+ plt.legend(("THRU", "DROP"))
40
+ plt.show()
examples/ex_RCWA.py ADDED
@@ -0,0 +1,95 @@
1
+ """Rigorous Coupled Wave Analysis example."""
2
+
3
+ from matplotlib import pyplot as plt
4
+ import numpy
5
+
6
+ import EMpy
7
+ from EMpy.materials import (
8
+ IsotropicMaterial,
9
+ AnisotropicMaterial,
10
+ RefractiveIndex,
11
+ EpsilonTensor,
12
+ )
13
+
14
+ alpha = 0.0
15
+ delta = 0.0
16
+ # psi = EMpy.utils.deg2rad(0.) # TM
17
+ # psi = EMpy.utils.deg2rad(90.) # TE
18
+ psi = EMpy.utils.deg2rad(70.0) # hybrid
19
+ phi = EMpy.utils.deg2rad(90.0)
20
+
21
+ LAMBDA = 1016e-9 # grating periodicity
22
+ n = 2 # orders of diffraction
23
+
24
+ UV6 = IsotropicMaterial("UV6", n0=RefractiveIndex(n0_const=1.560))
25
+ SiN = AnisotropicMaterial(
26
+ "SiN",
27
+ epsilon_tensor=EpsilonTensor(
28
+ epsilon_tensor_const=EMpy.constants.eps0
29
+ * EMpy.utils.euler_rotate(
30
+ numpy.diag(numpy.asarray([1.8550, 1.8750, 1.9130]) ** 2),
31
+ EMpy.utils.deg2rad(14),
32
+ EMpy.utils.deg2rad(25),
33
+ EMpy.utils.deg2rad(32),
34
+ )
35
+ ),
36
+ )
37
+ BPTEOS = IsotropicMaterial("BPTEOS", n0=RefractiveIndex(n0_const=1.448))
38
+ ARC1 = IsotropicMaterial("ARC1", n0=RefractiveIndex(n0_const=1.448))
39
+
40
+ EFF = IsotropicMaterial("EFF", n0=RefractiveIndex(n0_const=1.6))
41
+
42
+ multilayer1 = EMpy.utils.Multilayer(
43
+ [
44
+ EMpy.utils.Layer(EMpy.materials.Air, numpy.inf),
45
+ EMpy.utils.Layer(SiN, 226e-9),
46
+ EMpy.utils.Layer(BPTEOS, 226e-9),
47
+ EMpy.utils.BinaryGrating(SiN, BPTEOS, 0.659, LAMBDA, 123e-9),
48
+ EMpy.utils.Layer(SiN, 219e-9),
49
+ EMpy.utils.Layer(EMpy.materials.SiO2, 2188e-9),
50
+ EMpy.utils.Layer(EMpy.materials.Si, numpy.inf),
51
+ ]
52
+ )
53
+
54
+ multilayer2 = EMpy.utils.Multilayer(
55
+ [
56
+ EMpy.utils.Layer(EMpy.materials.Air, numpy.inf),
57
+ EMpy.utils.Layer(SiN, 226e-9),
58
+ EMpy.utils.Layer(BPTEOS, 226e-9),
59
+ EMpy.utils.Layer(IsotropicMaterial(n0=RefractiveIndex(n0_const=1.6)), 123e-9),
60
+ EMpy.utils.Layer(SiN, 219e-9),
61
+ EMpy.utils.Layer(EMpy.materials.SiO2, 2188e-9),
62
+ EMpy.utils.Layer(EMpy.materials.Si, numpy.inf),
63
+ ]
64
+ )
65
+
66
+ wls = numpy.linspace(1.45e-6, 1.75e-6, 301)
67
+
68
+ solution1 = EMpy.RCWA.AnisotropicRCWA(multilayer1, alpha, delta, psi, phi, n).solve(wls)
69
+ solution2 = EMpy.RCWA.AnisotropicRCWA(multilayer2, alpha, delta, psi, phi, n).solve(wls)
70
+
71
+ um = 1e-6
72
+ plt.plot(
73
+ # wls / um, solution1.DEO1[n, :], 'k.-',
74
+ # wls / um, solution1.DEO3[n, :], 'r.-',
75
+ wls / um,
76
+ solution1.DEE1[n, :],
77
+ "b.-",
78
+ wls / um,
79
+ solution1.DEE3[n, :],
80
+ "g.-",
81
+ # wls / um, solution2.DEO1[n, :], 'k--',
82
+ # wls / um, solution2.DEO3[n, :], 'r--',
83
+ wls / um,
84
+ solution2.DEE1[n, :],
85
+ "b--",
86
+ wls / um,
87
+ solution2.DEE3[n, :],
88
+ "g--",
89
+ )
90
+ plt.xlabel("wavelength [um]")
91
+ plt.ylabel("diffraction efficiency")
92
+ plt.legend(("DEO1", "DEO3", "DEE1", "DEE3"))
93
+ plt.axis("tight")
94
+ plt.ylim([0, 0.15])
95
+ plt.show()
examples/ex_RCWA_2.py ADDED
@@ -0,0 +1,52 @@
1
+ """Rigorous Coupled Wave Analysis example.
2
+
3
+ Inspired by Moharam, "Formulation for stable and efficient implementation of the rigorous coupled-wave analysis of
4
+ binary gratings", JOSA A, 12(5), 1995
5
+ """
6
+
7
+ from matplotlib import pyplot as plt
8
+ import numpy
9
+
10
+ import EMpy
11
+ from EMpy.materials import IsotropicMaterial, RefractiveIndex
12
+
13
+ alpha = EMpy.utils.deg2rad(10.0)
14
+ delta = EMpy.utils.deg2rad(0.0)
15
+ psi = EMpy.utils.deg2rad(0.0) # TE
16
+ phi = EMpy.utils.deg2rad(90.0)
17
+
18
+ wl = numpy.array([1.55e-6])
19
+ ds = numpy.linspace(0.0, 5.0, 100) * wl
20
+ LAMBDA = 10 * wl
21
+
22
+ n = 3 # orders of diffraction
23
+
24
+ Top = IsotropicMaterial("Top", n0=RefractiveIndex(n0_const=1.0))
25
+ Bottom = IsotropicMaterial("Bottom", n0=RefractiveIndex(n0_const=2.04))
26
+
27
+ solutions = []
28
+ for d in ds:
29
+ multilayer = EMpy.utils.Multilayer(
30
+ [
31
+ EMpy.utils.Layer(Top, numpy.inf),
32
+ EMpy.utils.BinaryGrating(Top, Bottom, 0.3, LAMBDA, d),
33
+ EMpy.utils.Layer(Bottom, numpy.inf),
34
+ ]
35
+ )
36
+
37
+ solution = EMpy.RCWA.IsotropicRCWA(multilayer, alpha, delta, psi, phi, n).solve(wl)
38
+ solutions.append(solution)
39
+
40
+ DE1 = numpy.zeros(len(solutions))
41
+ DE3 = numpy.zeros(len(solutions))
42
+ for ss, s in enumerate(solutions):
43
+ DE1[ss] = s.DE1[n, 0]
44
+ DE3[ss] = s.DE3[n, 0]
45
+
46
+ plt.plot(ds / wl, DE1[:], "k.-", ds / wl, DE3[:], "r.-")
47
+ plt.xlabel("normalized groove depth")
48
+ plt.ylabel("diffraction efficiency")
49
+ plt.legend(("DE1", "DE3"))
50
+ plt.axis("tight")
51
+ plt.ylim([0, 1])
52
+ plt.show()