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.
- EMpy/RCWA.py +32 -12
- EMpy/__init__.py +10 -2
- EMpy/_version.py +24 -0
- EMpy/constants.py +0 -2
- EMpy/devices.py +8 -32
- EMpy/materials.py +1 -8
- EMpy/modesolvers/FD.py +34 -76
- EMpy/modesolvers/FMM.py +24 -23
- EMpy/modesolvers/__init__.py +1 -0
- EMpy/modesolvers/geometries.py +8 -9
- EMpy/transfer_matrix.py +10 -6
- EMpy/utils.py +12 -26
- electromagneticpython-2.2.4.dist-info/METADATA +99 -0
- electromagneticpython-2.2.4.dist-info/RECORD +45 -0
- {ElectroMagneticPython-2.2.1.dist-info → electromagneticpython-2.2.4.dist-info}/WHEEL +1 -1
- electromagneticpython-2.2.4.dist-info/top_level.txt +4 -0
- examples/ex_APRR.py +18 -0
- examples/ex_NRR.py +40 -0
- examples/ex_RCWA.py +95 -0
- examples/ex_RCWA_2.py +52 -0
- examples/ex_RCWA_3.py +58 -0
- examples/ex_SRR.py +23 -0
- examples/ex_laser_etch_monitor.py +241 -0
- examples/ex_modesolver.py +68 -0
- examples/ex_modesolver_2.py +58 -0
- examples/ex_modesolver_3.py +48 -0
- examples/ex_modesolver_4.py +43 -0
- examples/ex_modesolver_dch.py +296 -0
- examples/ex_modesolver_dch_anis.py +318 -0
- examples/ex_transfer_matrix.py +82 -0
- examples/ex_transfer_matrix_2.py +44 -0
- examples/ex_transfer_matrix_2.py.png +0 -0
- examples/ex_transfer_matrix_3.py +60 -0
- examples/lc_data.dat +27 -0
- examples/nk.py +1468 -0
- scripts/FDTD.py +741 -0
- tests/devices_test.py +31 -0
- tests/materials_test.py +1 -1
- tests/modesolvers_test.py +36 -0
- tests/transfer_matrix_test.py +134 -0
- tests/utils_test.py +9 -5
- EMpy/version.py +0 -1
- ElectroMagneticPython-2.2.1.dist-info/METADATA +0 -109
- ElectroMagneticPython-2.2.1.dist-info/RECORD +0 -22
- ElectroMagneticPython-2.2.1.dist-info/top_level.txt +0 -2
- {ElectroMagneticPython-2.2.1.dist-info → electromagneticpython-2.2.4.dist-info/licenses}/LICENSE +0 -0
EMpy/RCWA.py
CHANGED
|
@@ -12,6 +12,7 @@ for every diffraction order and layer thickness, and an anisotropic
|
|
|
12
12
|
one, only stable for low diffraction orders and thin layers.
|
|
13
13
|
|
|
14
14
|
"""
|
|
15
|
+
|
|
15
16
|
__author__ = "Lorenzo Bolla"
|
|
16
17
|
|
|
17
18
|
import numpy as np
|
|
@@ -95,7 +96,6 @@ def dispersion_relation_extraordinary(kx, ky, k, nO, nE, c):
|
|
|
95
96
|
|
|
96
97
|
|
|
97
98
|
class RCWA:
|
|
98
|
-
|
|
99
99
|
"""Class to handle the RCWA solvers.
|
|
100
100
|
|
|
101
101
|
NOTE
|
|
@@ -168,7 +168,6 @@ class RCWA:
|
|
|
168
168
|
|
|
169
169
|
|
|
170
170
|
class IsotropicRCWA(RCWA):
|
|
171
|
-
|
|
172
171
|
"""Isotropic RCWA solver."""
|
|
173
172
|
|
|
174
173
|
def solve(self, wls):
|
|
@@ -215,7 +214,11 @@ class IsotropicRCWA(RCWA):
|
|
|
215
214
|
DE3 = np.zeros_like(DE1)
|
|
216
215
|
|
|
217
216
|
dirk1 = np.array(
|
|
218
|
-
[
|
|
217
|
+
[
|
|
218
|
+
np.sin(alpha) * np.cos(delta),
|
|
219
|
+
np.sin(alpha) * np.sin(delta),
|
|
220
|
+
np.cos(alpha),
|
|
221
|
+
]
|
|
219
222
|
)
|
|
220
223
|
|
|
221
224
|
# usefull matrices
|
|
@@ -323,7 +326,9 @@ class IsotropicRCWA(RCWA):
|
|
|
323
326
|
# H_S_reduced = np.dot(Ky, Ky) + np.dot(Kx, linsolve(E, np.dot(Kx, E11))) - E11
|
|
324
327
|
H_S_reduced = (
|
|
325
328
|
(ky / k) ** 2 * I
|
|
326
|
-
+ kx[:, np.newaxis]
|
|
329
|
+
+ kx[:, np.newaxis]
|
|
330
|
+
/ k
|
|
331
|
+
* linsolve(E, kx[:, np.newaxis] / k * E11)
|
|
327
332
|
- E11
|
|
328
333
|
)
|
|
329
334
|
|
|
@@ -448,7 +453,6 @@ class IsotropicRCWA(RCWA):
|
|
|
448
453
|
|
|
449
454
|
|
|
450
455
|
class AnisotropicRCWA(RCWA):
|
|
451
|
-
|
|
452
456
|
"""Anisotropic RCWA solver."""
|
|
453
457
|
|
|
454
458
|
def solve(self, wls):
|
|
@@ -487,14 +491,20 @@ class AnisotropicRCWA(RCWA):
|
|
|
487
491
|
# grating on the xy plane
|
|
488
492
|
K = 2 * pi / LAMBDA * np.array([np.sin(phi), 0.0, np.cos(phi)], dtype=complex)
|
|
489
493
|
dirk1 = np.array(
|
|
490
|
-
[
|
|
494
|
+
[
|
|
495
|
+
np.sin(alpha) * np.cos(delta),
|
|
496
|
+
np.sin(alpha) * np.sin(delta),
|
|
497
|
+
np.cos(alpha),
|
|
498
|
+
]
|
|
491
499
|
)
|
|
492
500
|
|
|
493
501
|
# D polarization vector
|
|
494
502
|
u = np.array(
|
|
495
503
|
[
|
|
496
|
-
np.cos(psi) * np.cos(alpha) * np.cos(delta)
|
|
497
|
-
|
|
504
|
+
np.cos(psi) * np.cos(alpha) * np.cos(delta)
|
|
505
|
+
- np.sin(psi) * np.sin(delta),
|
|
506
|
+
np.cos(psi) * np.cos(alpha) * np.sin(delta)
|
|
507
|
+
+ np.sin(psi) * np.cos(delta),
|
|
498
508
|
-np.cos(psi) * np.sin(alpha),
|
|
499
509
|
]
|
|
500
510
|
)
|
|
@@ -814,7 +824,11 @@ class AnisotropicRCWA(RCWA):
|
|
|
814
824
|
denom = (k1[2] - np.dot(u, k1) * u[2]).real
|
|
815
825
|
DEO1[:, iwl] = (
|
|
816
826
|
-(
|
|
817
|
-
(
|
|
827
|
+
(
|
|
828
|
+
np.absolute(ROx) ** 2
|
|
829
|
+
+ np.absolute(ROy) ** 2
|
|
830
|
+
+ np.absolute(ROz) ** 2
|
|
831
|
+
)
|
|
818
832
|
* np.conj(kO1i[2, :])
|
|
819
833
|
- (ROx * kO1i[0, :] + ROy * kO1i[1, :] + ROz * kO1i[2, :])
|
|
820
834
|
* np.conj(ROz)
|
|
@@ -823,7 +837,11 @@ class AnisotropicRCWA(RCWA):
|
|
|
823
837
|
)
|
|
824
838
|
DEE1[:, iwl] = (
|
|
825
839
|
-(
|
|
826
|
-
(
|
|
840
|
+
(
|
|
841
|
+
np.absolute(REx) ** 2
|
|
842
|
+
+ np.absolute(REy) ** 2
|
|
843
|
+
+ np.absolute(REz) ** 2
|
|
844
|
+
)
|
|
827
845
|
* np.conj(kE1i[2, :])
|
|
828
846
|
- (REx * kE1i[0, :] + REy * kE1i[1, :] + REz * kE1i[2, :])
|
|
829
847
|
* np.conj(REz)
|
|
@@ -833,12 +851,14 @@ class AnisotropicRCWA(RCWA):
|
|
|
833
851
|
DEO3[:, iwl] = (
|
|
834
852
|
(np.absolute(TOx) ** 2 + np.absolute(TOy) ** 2 + np.absolute(TOz) ** 2)
|
|
835
853
|
* np.conj(kO3i[2, :])
|
|
836
|
-
- (TOx * kO3i[0, :] + TOy * kO3i[1, :] + TOz * kO3i[2, :])
|
|
854
|
+
- (TOx * kO3i[0, :] + TOy * kO3i[1, :] + TOz * kO3i[2, :])
|
|
855
|
+
* np.conj(TOz)
|
|
837
856
|
).real / denom
|
|
838
857
|
DEE3[:, iwl] = (
|
|
839
858
|
(np.absolute(TEx) ** 2 + np.absolute(TEy) ** 2 + np.absolute(TEz) ** 2)
|
|
840
859
|
* np.conj(kE3i[2, :])
|
|
841
|
-
- (TEx * kE3i[0, :] + TEy * kE3i[1, :] + TEz * kE3i[2, :])
|
|
860
|
+
- (TEx * kE3i[0, :] + TEy * kE3i[1, :] + TEz * kE3i[2, :])
|
|
861
|
+
* np.conj(TEz)
|
|
842
862
|
).real / denom
|
|
843
863
|
|
|
844
864
|
# save the results
|
EMpy/__init__.py
CHANGED
|
@@ -10,6 +10,7 @@ The package contains some useful routines to study electromagnetic problems with
|
|
|
10
10
|
It is based on U{numpy<http://numpy.scipy.org>} and U{scipy<http://www.scipy.org>}.
|
|
11
11
|
|
|
12
12
|
"""
|
|
13
|
+
|
|
13
14
|
__all__ = [
|
|
14
15
|
"constants",
|
|
15
16
|
"devices",
|
|
@@ -30,6 +31,13 @@ from . import RCWA
|
|
|
30
31
|
from . import scattering
|
|
31
32
|
from . import transfer_matrix
|
|
32
33
|
from . import utils
|
|
33
|
-
from .version import version
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
try:
|
|
36
|
+
from ._version import version as __version__
|
|
37
|
+
except ImportError:
|
|
38
|
+
# Fallback for development environments or edge cases
|
|
39
|
+
try:
|
|
40
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
41
|
+
__version__ = version("electromagneticpython")
|
|
42
|
+
except PackageNotFoundError:
|
|
43
|
+
__version__ = "0.0.0.dev0"
|
EMpy/_version.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '2.2.4'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 2, 4)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = 'gd8c276251'
|
EMpy/constants.py
CHANGED
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
|
|
|
@@ -31,6 +29,7 @@ devices, new ones can be studied.
|
|
|
31
29
|
isnumber=8367>}
|
|
32
30
|
|
|
33
31
|
"""
|
|
32
|
+
|
|
34
33
|
__author__ = "Lorenzo Bolla"
|
|
35
34
|
|
|
36
35
|
import numpy
|
|
@@ -39,7 +38,6 @@ from functools import reduce
|
|
|
39
38
|
|
|
40
39
|
|
|
41
40
|
class DeviceMatrix:
|
|
42
|
-
|
|
43
41
|
"""Device Matrix.
|
|
44
42
|
|
|
45
43
|
Base class for TransferMatrix and ChainMatrix.
|
|
@@ -62,7 +60,7 @@ class DeviceMatrix:
|
|
|
62
60
|
return self.__data
|
|
63
61
|
|
|
64
62
|
def setdata(self, value):
|
|
65
|
-
self.__data = numpy.
|
|
63
|
+
self.__data = numpy.array(value)
|
|
66
64
|
|
|
67
65
|
__data = None
|
|
68
66
|
data = property(fget=getdata, fset=setdata, doc="data")
|
|
@@ -83,7 +81,6 @@ class DeviceMatrix:
|
|
|
83
81
|
|
|
84
82
|
|
|
85
83
|
class TransferMatrix(DeviceMatrix):
|
|
86
|
-
|
|
87
84
|
"""Transfer Matrix.
|
|
88
85
|
|
|
89
86
|
Notation::
|
|
@@ -138,6 +135,7 @@ class TransferMatrix(DeviceMatrix):
|
|
|
138
135
|
|
|
139
136
|
Notation::
|
|
140
137
|
|
|
138
|
+
|
|
141
139
|
b12 = H1 a12 and d12 = H2 c12, but b12 == c12,
|
|
142
140
|
|
|
143
141
|
therefore::
|
|
@@ -154,11 +152,10 @@ class TransferMatrix(DeviceMatrix):
|
|
|
154
152
|
|
|
155
153
|
"""
|
|
156
154
|
|
|
157
|
-
return TransferMatrix(M.to_transfer().data
|
|
155
|
+
return TransferMatrix(M.to_transfer().data @ self.data)
|
|
158
156
|
|
|
159
157
|
|
|
160
158
|
class ChainMatrix(DeviceMatrix):
|
|
161
|
-
|
|
162
159
|
"""Chain Matrix.
|
|
163
160
|
|
|
164
161
|
Notation::
|
|
@@ -229,7 +226,7 @@ class ChainMatrix(DeviceMatrix):
|
|
|
229
226
|
|
|
230
227
|
"""
|
|
231
228
|
|
|
232
|
-
return ChainMatrix(self.data
|
|
229
|
+
return ChainMatrix(self.data @ M.to_chain().data)
|
|
233
230
|
|
|
234
231
|
|
|
235
232
|
def composeTM(A, B):
|
|
@@ -289,7 +286,6 @@ def composeCMlist(CMlist):
|
|
|
289
286
|
|
|
290
287
|
|
|
291
288
|
class Device:
|
|
292
|
-
|
|
293
289
|
"""Generic device.
|
|
294
290
|
|
|
295
291
|
Notes
|
|
@@ -307,7 +303,6 @@ class Device:
|
|
|
307
303
|
|
|
308
304
|
|
|
309
305
|
class Coupler(Device):
|
|
310
|
-
|
|
311
306
|
"""Coupler.
|
|
312
307
|
|
|
313
308
|
Examples
|
|
@@ -436,7 +431,6 @@ class Coupler(Device):
|
|
|
436
431
|
|
|
437
432
|
|
|
438
433
|
class Line(Device):
|
|
439
|
-
|
|
440
434
|
"""Line.
|
|
441
435
|
|
|
442
436
|
Notes
|
|
@@ -570,7 +564,6 @@ class Line(Device):
|
|
|
570
564
|
|
|
571
565
|
|
|
572
566
|
class MZ(Device):
|
|
573
|
-
|
|
574
567
|
"""Mach-Zehnder Interferometer (MZI).
|
|
575
568
|
|
|
576
569
|
A MZI is made of two L{Coupler}s connected by a L{Line}.
|
|
@@ -679,7 +672,6 @@ class MZ(Device):
|
|
|
679
672
|
|
|
680
673
|
|
|
681
674
|
class APRR(Device):
|
|
682
|
-
|
|
683
675
|
"""All-Pass Ring Resonator.
|
|
684
676
|
|
|
685
677
|
An APRR is made of a L{Coupler} with a feedback line (the ring).
|
|
@@ -746,7 +738,6 @@ class APRR(Device):
|
|
|
746
738
|
|
|
747
739
|
|
|
748
740
|
class SRR(Device):
|
|
749
|
-
|
|
750
741
|
"""Single Ring Resonator.
|
|
751
742
|
|
|
752
743
|
A SRR is made of the parallel of a L{Coupler} a feedback line (the
|
|
@@ -872,7 +863,6 @@ class SRR(Device):
|
|
|
872
863
|
|
|
873
864
|
|
|
874
865
|
class NRR(Device):
|
|
875
|
-
|
|
876
866
|
"""N-Rings Resonator.
|
|
877
867
|
|
|
878
868
|
A NRR is made of the parallel of two lines connected by N ring resonators.
|
|
@@ -996,7 +986,6 @@ class NRR(Device):
|
|
|
996
986
|
|
|
997
987
|
|
|
998
988
|
class T_TCRR(Device):
|
|
999
|
-
|
|
1000
989
|
"""Tunable Triple-Coupled Ring Resonator.
|
|
1001
990
|
|
|
1002
991
|
A T_TCRR is made of a L{MZ}, with a feedback line.
|
|
@@ -1056,8 +1045,7 @@ class T_TCRR(Device):
|
|
|
1056
1045
|
t4 = numpy.exp(-1j * beta * l[3])
|
|
1057
1046
|
|
|
1058
1047
|
denom = (
|
|
1059
|
-
q**3 * Kbar[2] * t3 * t4 * (Kbar[0] * Kbar[1] * t1 - K[0] * K[1] * t2)
|
|
1060
|
-
- 1.0
|
|
1048
|
+
q**3 * Kbar[2] * t3 * t4 * (Kbar[0] * Kbar[1] * t1 - K[0] * K[1] * t2) - 1.0
|
|
1061
1049
|
)
|
|
1062
1050
|
self.DROP = (
|
|
1063
1051
|
q**3 * K[2] * t3 * (K[0] * Kbar[1] * t1 + Kbar[0] * K[1] * t2) / denom
|
|
@@ -1071,7 +1059,6 @@ class T_TCRR(Device):
|
|
|
1071
1059
|
|
|
1072
1060
|
|
|
1073
1061
|
class T_CRTCRR(Device):
|
|
1074
|
-
|
|
1075
1062
|
"""Tunable Coupled Ring Triple-Coupled Ring Resonator.
|
|
1076
1063
|
|
|
1077
1064
|
NOTE
|
|
@@ -1129,16 +1116,7 @@ class T_CRTCRR(Device):
|
|
|
1129
1116
|
- q**2 * Kbar[1] * t2**2 * (Kbar[2] - q**3 * t1**2 * N1)
|
|
1130
1117
|
)
|
|
1131
1118
|
self.DROP = (
|
|
1132
|
-
1j
|
|
1133
|
-
* q**4
|
|
1134
|
-
* K[0]
|
|
1135
|
-
* K[1]
|
|
1136
|
-
* K[2]
|
|
1137
|
-
* Kbar[0]
|
|
1138
|
-
* t1**1.5
|
|
1139
|
-
* t2
|
|
1140
|
-
* (1 + t31)
|
|
1141
|
-
/ denom
|
|
1119
|
+
1j * q**4 * K[0] * K[1] * K[2] * Kbar[0] * t1**1.5 * t2 * (1 + t31) / denom
|
|
1142
1120
|
)
|
|
1143
1121
|
self.THRU = (
|
|
1144
1122
|
q**2
|
|
@@ -1156,7 +1134,6 @@ class T_CRTCRR(Device):
|
|
|
1156
1134
|
|
|
1157
1135
|
|
|
1158
1136
|
class T_CTCRR(Device):
|
|
1159
|
-
|
|
1160
1137
|
"""Tunable Coupled Triple Coupled Ring Resonator.
|
|
1161
1138
|
|
|
1162
1139
|
NOTE
|
|
@@ -1363,7 +1340,6 @@ class SWG(Device):
|
|
|
1363
1340
|
|
|
1364
1341
|
|
|
1365
1342
|
class Etalon(Device):
|
|
1366
|
-
|
|
1367
1343
|
"""Etalon.
|
|
1368
1344
|
|
|
1369
1345
|
@ivar R: Reflectivity.
|
|
@@ -1402,7 +1378,7 @@ class Etalon(Device):
|
|
|
1402
1378
|
self.wl0 = numpy.mean(wls)
|
|
1403
1379
|
self.FSRwl = self.wl0**2 / (2 * n * l * numpy.cos(self.theta) + self.wl0)
|
|
1404
1380
|
|
|
1405
|
-
|
|
1381
|
+
self.f0, self.FSR = EMpy.utils.wl2f(self.wl0, self.FSRwl)
|
|
1406
1382
|
|
|
1407
1383
|
self.FINESSE = numpy.pi / (2 * numpy.arcsin(1.0 / numpy.sqrt(self.F)))
|
|
1408
1384
|
# self.FINESSE = numpy.pi * numpy.sqrt(self.F) / 2.
|
EMpy/materials.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
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.
|
|
6
4
|
|
|
7
5
|
"""
|
|
6
|
+
|
|
8
7
|
from functools import partial
|
|
9
8
|
|
|
10
9
|
import numpy
|
|
@@ -15,7 +14,6 @@ __author__ = "Lorenzo Bolla"
|
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class Material:
|
|
18
|
-
|
|
19
17
|
"""Generic class to handle materials.
|
|
20
18
|
|
|
21
19
|
This class is intended to be subclassed to obtain isotropic and
|
|
@@ -28,7 +26,6 @@ class Material:
|
|
|
28
26
|
|
|
29
27
|
|
|
30
28
|
class RefractiveIndex:
|
|
31
|
-
|
|
32
29
|
"""Refractive Index.
|
|
33
30
|
|
|
34
31
|
Unaware of temperature.
|
|
@@ -146,7 +143,6 @@ class RefractiveIndex:
|
|
|
146
143
|
|
|
147
144
|
|
|
148
145
|
class ThermalOpticCoefficient:
|
|
149
|
-
|
|
150
146
|
"""Thermal Optic Coefficient."""
|
|
151
147
|
|
|
152
148
|
def __init__(self, data=None, T0=300):
|
|
@@ -168,7 +164,6 @@ class ThermalOpticCoefficient:
|
|
|
168
164
|
|
|
169
165
|
|
|
170
166
|
class IsotropicMaterial(Material):
|
|
171
|
-
|
|
172
167
|
"""Subclasses Material to describe isotropic materials.
|
|
173
168
|
|
|
174
169
|
Frequency dispersion and thermic aware.
|
|
@@ -232,7 +227,6 @@ class EpsilonTensor:
|
|
|
232
227
|
|
|
233
228
|
|
|
234
229
|
class AnisotropicMaterial(Material):
|
|
235
|
-
|
|
236
230
|
"""Subclass Material to describe anisotropic materials.
|
|
237
231
|
|
|
238
232
|
No frequency dispersion nor thermic aware.
|
|
@@ -292,7 +286,6 @@ BK7 = IsotropicMaterial(
|
|
|
292
286
|
|
|
293
287
|
|
|
294
288
|
class LiquidCrystal(Material):
|
|
295
|
-
|
|
296
289
|
"""Liquid Crystal.
|
|
297
290
|
|
|
298
291
|
A liquid crystal is determined by it ordinary and extraordinary
|
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",
|
|
@@ -10,6 +6,8 @@
|
|
|
10
6
|
@see: http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=12734&objectType=FILE
|
|
11
7
|
|
|
12
8
|
"""
|
|
9
|
+
|
|
10
|
+
from matplotlib import pyplot as plt
|
|
13
11
|
import numpy
|
|
14
12
|
import scipy
|
|
15
13
|
import scipy.optimize
|
|
@@ -19,7 +17,6 @@ from EMpy.modesolvers.interface import Mode, ModeSolver
|
|
|
19
17
|
|
|
20
18
|
|
|
21
19
|
class SVFDModeSolver(ModeSolver):
|
|
22
|
-
|
|
23
20
|
"""
|
|
24
21
|
This function calculates the modes of a dielectric waveguide
|
|
25
22
|
using the semivectorial finite difference method.
|
|
@@ -142,10 +139,8 @@ class SVFDModeSolver(ModeSolver):
|
|
|
142
139
|
* (p * (ep - ew) + 2 * w * ew)
|
|
143
140
|
* ee
|
|
144
141
|
/ (
|
|
145
|
-
(p * (ep - ee) + 2 * e * ee)
|
|
146
|
-
* (p**2 * (ep -
|
|
147
|
-
+ (p * (ep - ew) + 2 * w * ew)
|
|
148
|
-
* (p**2 * (ep - ee) + 4 * e**2 * ee)
|
|
142
|
+
(p * (ep - ee) + 2 * e * ee) * (p**2 * (ep - ew) + 4 * w**2 * ew)
|
|
143
|
+
+ (p * (ep - ew) + 2 * w * ew) * (p**2 * (ep - ee) + 4 * e**2 * ee)
|
|
149
144
|
)
|
|
150
145
|
)
|
|
151
146
|
Aw = (
|
|
@@ -153,10 +148,8 @@ class SVFDModeSolver(ModeSolver):
|
|
|
153
148
|
* (p * (ep - ee) + 2 * e * ee)
|
|
154
149
|
* ew
|
|
155
150
|
/ (
|
|
156
|
-
(p * (ep - ee) + 2 * e * ee)
|
|
157
|
-
* (p**2 * (ep -
|
|
158
|
-
+ (p * (ep - ew) + 2 * w * ew)
|
|
159
|
-
* (p**2 * (ep - ee) + 4 * e**2 * ee)
|
|
151
|
+
(p * (ep - ee) + 2 * e * ee) * (p**2 * (ep - ew) + 4 * w**2 * ew)
|
|
152
|
+
+ (p * (ep - ew) + 2 * w * ew) * (p**2 * (ep - ee) + 4 * e**2 * ee)
|
|
160
153
|
)
|
|
161
154
|
)
|
|
162
155
|
Ap = ep * k**2 - An - As - Ae * ep / ee - Aw * ep / ew
|
|
@@ -169,10 +162,8 @@ class SVFDModeSolver(ModeSolver):
|
|
|
169
162
|
* (q * (ep - es) + 2 * s * es)
|
|
170
163
|
* en
|
|
171
164
|
/ (
|
|
172
|
-
(q * (ep - en) + 2 * n * en)
|
|
173
|
-
* (q**2 * (ep -
|
|
174
|
-
+ (q * (ep - es) + 2 * s * es)
|
|
175
|
-
* (q**2 * (ep - en) + 4 * n**2 * en)
|
|
165
|
+
(q * (ep - en) + 2 * n * en) * (q**2 * (ep - es) + 4 * s**2 * es)
|
|
166
|
+
+ (q * (ep - es) + 2 * s * es) * (q**2 * (ep - en) + 4 * n**2 * en)
|
|
176
167
|
)
|
|
177
168
|
)
|
|
178
169
|
As = (
|
|
@@ -180,10 +171,8 @@ class SVFDModeSolver(ModeSolver):
|
|
|
180
171
|
* (q * (ep - en) + 2 * n * en)
|
|
181
172
|
* es
|
|
182
173
|
/ (
|
|
183
|
-
(q * (ep - en) + 2 * n * en)
|
|
184
|
-
* (q**2 * (ep -
|
|
185
|
-
+ (q * (ep - es) + 2 * s * es)
|
|
186
|
-
* (q**2 * (ep - en) + 4 * n**2 * en)
|
|
174
|
+
(q * (ep - en) + 2 * n * en) * (q**2 * (ep - es) + 4 * s**2 * es)
|
|
175
|
+
+ (q * (ep - es) + 2 * s * es) * (q**2 * (ep - en) + 4 * n**2 * en)
|
|
187
176
|
)
|
|
188
177
|
)
|
|
189
178
|
Ae = 2 / e / (e + w)
|
|
@@ -255,14 +244,14 @@ class SVFDModeSolver(ModeSolver):
|
|
|
255
244
|
return A
|
|
256
245
|
|
|
257
246
|
def solve(self, neigs, tol):
|
|
258
|
-
from scipy.sparse
|
|
247
|
+
from scipy.sparse import linalg
|
|
259
248
|
|
|
260
249
|
self.nmodes = neigs
|
|
261
250
|
self.tol = tol
|
|
262
251
|
|
|
263
252
|
A = self.build_matrix()
|
|
264
253
|
|
|
265
|
-
eigvals, eigvecs =
|
|
254
|
+
eigvals, eigvecs = linalg.eigs( # type: ignore
|
|
266
255
|
A, k=neigs, which="LR", tol=tol, ncv=10 * neigs, return_eigenvectors=True
|
|
267
256
|
)
|
|
268
257
|
|
|
@@ -296,7 +285,6 @@ class SVFDModeSolver(ModeSolver):
|
|
|
296
285
|
|
|
297
286
|
|
|
298
287
|
class VFDModeSolver(ModeSolver):
|
|
299
|
-
|
|
300
288
|
"""
|
|
301
289
|
The VFDModeSolver class computes the electric and magnetic fields
|
|
302
290
|
for modes of a dielectric waveguide using the "Vector Finite
|
|
@@ -1135,12 +1123,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
1135
1123
|
(n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2)
|
|
1136
1124
|
* (
|
|
1137
1125
|
0.5 * n * ezz4 * ezz3 / eyy4 * (2.0 / e**2 - eyx4 / ezz4 / n / e)
|
|
1138
|
-
+ 0.5
|
|
1139
|
-
* s
|
|
1140
|
-
* ezz3
|
|
1141
|
-
* ezz4
|
|
1142
|
-
/ eyy3
|
|
1143
|
-
* (2.0 / e**2 + eyx3 / ezz3 / s / e)
|
|
1126
|
+
+ 0.5 * s * ezz3 * ezz4 / eyy3 * (2.0 / e**2 + eyx3 / ezz3 / s / e)
|
|
1144
1127
|
)
|
|
1145
1128
|
/ ezz4
|
|
1146
1129
|
/ ezz3
|
|
@@ -1190,12 +1173,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
1190
1173
|
(-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3)
|
|
1191
1174
|
* (
|
|
1192
1175
|
0.5 * n * ezz1 * ezz2 / eyy1 * (2.0 / w**2 + eyx1 / ezz1 / n / w)
|
|
1193
|
-
+ 0.5
|
|
1194
|
-
* s
|
|
1195
|
-
* ezz2
|
|
1196
|
-
* ezz1
|
|
1197
|
-
/ eyy2
|
|
1198
|
-
* (2.0 / w**2 - eyx2 / ezz2 / s / w)
|
|
1176
|
+
+ 0.5 * s * ezz2 * ezz1 / eyy2 * (2.0 / w**2 - eyx2 / ezz2 / s / w)
|
|
1199
1177
|
)
|
|
1200
1178
|
/ ezz4
|
|
1201
1179
|
/ ezz3
|
|
@@ -1517,12 +1495,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
1517
1495
|
+ (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e)
|
|
1518
1496
|
* (
|
|
1519
1497
|
0.5 * ezz4 * (2.0 / n**2 + exy1 / ezz1 / n / w) / exx1 * ezz1 * w
|
|
1520
|
-
+ 0.5
|
|
1521
|
-
* ezz1
|
|
1522
|
-
* (2.0 / n**2 - exy4 / ezz4 / n / e)
|
|
1523
|
-
/ exx4
|
|
1524
|
-
* ezz4
|
|
1525
|
-
* e
|
|
1498
|
+
+ 0.5 * ezz1 * (2.0 / n**2 - exy4 / ezz4 / n / e) / exx4 * ezz4 * e
|
|
1526
1499
|
)
|
|
1527
1500
|
/ ezz3
|
|
1528
1501
|
/ ezz2
|
|
@@ -1572,12 +1545,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
1572
1545
|
- (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e)
|
|
1573
1546
|
* (
|
|
1574
1547
|
0.5 * ezz3 * (2.0 / s**2 - exy2 / ezz2 / s / w) / exx2 * ezz2 * w
|
|
1575
|
-
+ 0.5
|
|
1576
|
-
* ezz2
|
|
1577
|
-
* (2.0 / s**2 + exy3 / ezz3 / s / e)
|
|
1578
|
-
/ exx3
|
|
1579
|
-
* ezz3
|
|
1580
|
-
* e
|
|
1548
|
+
+ 0.5 * ezz2 * (2.0 / s**2 + exy3 / ezz3 / s / e) / exx3 * ezz3 * e
|
|
1581
1549
|
)
|
|
1582
1550
|
/ ezz3
|
|
1583
1551
|
/ ezz2
|
|
@@ -2066,7 +2034,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
2066
2034
|
Ez = solver.modes[0].Ez
|
|
2067
2035
|
"""
|
|
2068
2036
|
|
|
2069
|
-
from scipy.sparse
|
|
2037
|
+
from scipy.sparse import linalg
|
|
2070
2038
|
|
|
2071
2039
|
self.nmodes = neigs
|
|
2072
2040
|
self.tol = tol
|
|
@@ -2081,7 +2049,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
2081
2049
|
shift = None
|
|
2082
2050
|
|
|
2083
2051
|
# Here is where the actual mode-solving takes place!
|
|
2084
|
-
[eigvals, eigvecs] =
|
|
2052
|
+
[eigvals, eigvecs] = linalg.eigs(
|
|
2085
2053
|
A,
|
|
2086
2054
|
k=neigs,
|
|
2087
2055
|
which="LR",
|
|
@@ -2320,14 +2288,9 @@ class FDMode(Mode):
|
|
|
2320
2288
|
|
|
2321
2289
|
@staticmethod
|
|
2322
2290
|
def plot_field(x, y, field):
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
print("no pylab installed")
|
|
2327
|
-
return
|
|
2328
|
-
pylab.hot()
|
|
2329
|
-
pylab.contour(x, y, numpy.abs(field.T), 16)
|
|
2330
|
-
pylab.axis("image")
|
|
2291
|
+
plt.hot()
|
|
2292
|
+
plt.contour(x, y, numpy.abs(field.T), 16)
|
|
2293
|
+
plt.axis("image")
|
|
2331
2294
|
|
|
2332
2295
|
def plot_Ex(self, x=None, y=None):
|
|
2333
2296
|
if x is None:
|
|
@@ -2385,30 +2348,25 @@ class FDMode(Mode):
|
|
|
2385
2348
|
|
|
2386
2349
|
def plot(self):
|
|
2387
2350
|
"""Plot the mode's fields."""
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
except ImportError:
|
|
2391
|
-
print("no pylab installed")
|
|
2392
|
-
return
|
|
2393
|
-
pylab.figure()
|
|
2394
|
-
pylab.subplot(2, 3, 1)
|
|
2351
|
+
plt.figure()
|
|
2352
|
+
plt.subplot(2, 3, 1)
|
|
2395
2353
|
self.plot_Ex()
|
|
2396
|
-
|
|
2397
|
-
|
|
2354
|
+
plt.title("Ex")
|
|
2355
|
+
plt.subplot(2, 3, 2)
|
|
2398
2356
|
self.plot_Ey()
|
|
2399
|
-
|
|
2400
|
-
|
|
2357
|
+
plt.title("Ey")
|
|
2358
|
+
plt.subplot(2, 3, 3)
|
|
2401
2359
|
self.plot_Ez()
|
|
2402
|
-
|
|
2403
|
-
|
|
2360
|
+
plt.title("Ez")
|
|
2361
|
+
plt.subplot(2, 3, 4)
|
|
2404
2362
|
self.plot_Hx()
|
|
2405
|
-
|
|
2406
|
-
|
|
2363
|
+
plt.title("Hx")
|
|
2364
|
+
plt.subplot(2, 3, 5)
|
|
2407
2365
|
self.plot_Hy()
|
|
2408
|
-
|
|
2409
|
-
|
|
2366
|
+
plt.title("Hy")
|
|
2367
|
+
plt.subplot(2, 3, 6)
|
|
2410
2368
|
self.plot_Hz()
|
|
2411
|
-
|
|
2369
|
+
plt.title("Hz")
|
|
2412
2370
|
|
|
2413
2371
|
|
|
2414
2372
|
def stretchmesh(x, y, nlayers, factor, method="PPPP"):
|