ElectroMagneticPython 2.2.1__py3-none-any.whl → 2.2.3__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 +34 -0
- EMpy/devices.py +4 -27
- EMpy/materials.py +1 -6
- EMpy/modesolvers/FD.py +34 -72
- EMpy/modesolvers/FMM.py +24 -23
- EMpy/modesolvers/__init__.py +1 -0
- EMpy/modesolvers/geometries.py +8 -9
- EMpy/transfer_matrix.py +1 -1
- EMpy/utils.py +12 -24
- electromagneticpython-2.2.3.dist-info/METADATA +99 -0
- electromagneticpython-2.2.3.dist-info/RECORD +44 -0
- {ElectroMagneticPython-2.2.1.dist-info → electromagneticpython-2.2.3.dist-info}/WHEEL +1 -1
- electromagneticpython-2.2.3.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/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.3.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,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
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
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '2.2.3'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 2, 3)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
EMpy/devices.py
CHANGED
|
@@ -31,6 +31,7 @@ devices, new ones can be studied.
|
|
|
31
31
|
isnumber=8367>}
|
|
32
32
|
|
|
33
33
|
"""
|
|
34
|
+
|
|
34
35
|
__author__ = "Lorenzo Bolla"
|
|
35
36
|
|
|
36
37
|
import numpy
|
|
@@ -39,7 +40,6 @@ from functools import reduce
|
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
class DeviceMatrix:
|
|
42
|
-
|
|
43
43
|
"""Device Matrix.
|
|
44
44
|
|
|
45
45
|
Base class for TransferMatrix and ChainMatrix.
|
|
@@ -83,7 +83,6 @@ class DeviceMatrix:
|
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
class TransferMatrix(DeviceMatrix):
|
|
86
|
-
|
|
87
86
|
"""Transfer Matrix.
|
|
88
87
|
|
|
89
88
|
Notation::
|
|
@@ -158,7 +157,6 @@ class TransferMatrix(DeviceMatrix):
|
|
|
158
157
|
|
|
159
158
|
|
|
160
159
|
class ChainMatrix(DeviceMatrix):
|
|
161
|
-
|
|
162
160
|
"""Chain Matrix.
|
|
163
161
|
|
|
164
162
|
Notation::
|
|
@@ -289,7 +287,6 @@ def composeCMlist(CMlist):
|
|
|
289
287
|
|
|
290
288
|
|
|
291
289
|
class Device:
|
|
292
|
-
|
|
293
290
|
"""Generic device.
|
|
294
291
|
|
|
295
292
|
Notes
|
|
@@ -307,7 +304,6 @@ class Device:
|
|
|
307
304
|
|
|
308
305
|
|
|
309
306
|
class Coupler(Device):
|
|
310
|
-
|
|
311
307
|
"""Coupler.
|
|
312
308
|
|
|
313
309
|
Examples
|
|
@@ -436,7 +432,6 @@ class Coupler(Device):
|
|
|
436
432
|
|
|
437
433
|
|
|
438
434
|
class Line(Device):
|
|
439
|
-
|
|
440
435
|
"""Line.
|
|
441
436
|
|
|
442
437
|
Notes
|
|
@@ -570,7 +565,6 @@ class Line(Device):
|
|
|
570
565
|
|
|
571
566
|
|
|
572
567
|
class MZ(Device):
|
|
573
|
-
|
|
574
568
|
"""Mach-Zehnder Interferometer (MZI).
|
|
575
569
|
|
|
576
570
|
A MZI is made of two L{Coupler}s connected by a L{Line}.
|
|
@@ -679,7 +673,6 @@ class MZ(Device):
|
|
|
679
673
|
|
|
680
674
|
|
|
681
675
|
class APRR(Device):
|
|
682
|
-
|
|
683
676
|
"""All-Pass Ring Resonator.
|
|
684
677
|
|
|
685
678
|
An APRR is made of a L{Coupler} with a feedback line (the ring).
|
|
@@ -746,7 +739,6 @@ class APRR(Device):
|
|
|
746
739
|
|
|
747
740
|
|
|
748
741
|
class SRR(Device):
|
|
749
|
-
|
|
750
742
|
"""Single Ring Resonator.
|
|
751
743
|
|
|
752
744
|
A SRR is made of the parallel of a L{Coupler} a feedback line (the
|
|
@@ -872,7 +864,6 @@ class SRR(Device):
|
|
|
872
864
|
|
|
873
865
|
|
|
874
866
|
class NRR(Device):
|
|
875
|
-
|
|
876
867
|
"""N-Rings Resonator.
|
|
877
868
|
|
|
878
869
|
A NRR is made of the parallel of two lines connected by N ring resonators.
|
|
@@ -996,7 +987,6 @@ class NRR(Device):
|
|
|
996
987
|
|
|
997
988
|
|
|
998
989
|
class T_TCRR(Device):
|
|
999
|
-
|
|
1000
990
|
"""Tunable Triple-Coupled Ring Resonator.
|
|
1001
991
|
|
|
1002
992
|
A T_TCRR is made of a L{MZ}, with a feedback line.
|
|
@@ -1056,8 +1046,7 @@ class T_TCRR(Device):
|
|
|
1056
1046
|
t4 = numpy.exp(-1j * beta * l[3])
|
|
1057
1047
|
|
|
1058
1048
|
denom = (
|
|
1059
|
-
q**3 * Kbar[2] * t3 * t4 * (Kbar[0] * Kbar[1] * t1 - K[0] * K[1] * t2)
|
|
1060
|
-
- 1.0
|
|
1049
|
+
q**3 * Kbar[2] * t3 * t4 * (Kbar[0] * Kbar[1] * t1 - K[0] * K[1] * t2) - 1.0
|
|
1061
1050
|
)
|
|
1062
1051
|
self.DROP = (
|
|
1063
1052
|
q**3 * K[2] * t3 * (K[0] * Kbar[1] * t1 + Kbar[0] * K[1] * t2) / denom
|
|
@@ -1071,7 +1060,6 @@ class T_TCRR(Device):
|
|
|
1071
1060
|
|
|
1072
1061
|
|
|
1073
1062
|
class T_CRTCRR(Device):
|
|
1074
|
-
|
|
1075
1063
|
"""Tunable Coupled Ring Triple-Coupled Ring Resonator.
|
|
1076
1064
|
|
|
1077
1065
|
NOTE
|
|
@@ -1129,16 +1117,7 @@ class T_CRTCRR(Device):
|
|
|
1129
1117
|
- q**2 * Kbar[1] * t2**2 * (Kbar[2] - q**3 * t1**2 * N1)
|
|
1130
1118
|
)
|
|
1131
1119
|
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
|
|
1120
|
+
1j * q**4 * K[0] * K[1] * K[2] * Kbar[0] * t1**1.5 * t2 * (1 + t31) / denom
|
|
1142
1121
|
)
|
|
1143
1122
|
self.THRU = (
|
|
1144
1123
|
q**2
|
|
@@ -1156,7 +1135,6 @@ class T_CRTCRR(Device):
|
|
|
1156
1135
|
|
|
1157
1136
|
|
|
1158
1137
|
class T_CTCRR(Device):
|
|
1159
|
-
|
|
1160
1138
|
"""Tunable Coupled Triple Coupled Ring Resonator.
|
|
1161
1139
|
|
|
1162
1140
|
NOTE
|
|
@@ -1363,7 +1341,6 @@ class SWG(Device):
|
|
|
1363
1341
|
|
|
1364
1342
|
|
|
1365
1343
|
class Etalon(Device):
|
|
1366
|
-
|
|
1367
1344
|
"""Etalon.
|
|
1368
1345
|
|
|
1369
1346
|
@ivar R: Reflectivity.
|
|
@@ -1402,7 +1379,7 @@ class Etalon(Device):
|
|
|
1402
1379
|
self.wl0 = numpy.mean(wls)
|
|
1403
1380
|
self.FSRwl = self.wl0**2 / (2 * n * l * numpy.cos(self.theta) + self.wl0)
|
|
1404
1381
|
|
|
1405
|
-
|
|
1382
|
+
self.f0, self.FSR = EMpy.utils.wl2f(self.wl0, self.FSRwl)
|
|
1406
1383
|
|
|
1407
1384
|
self.FINESSE = numpy.pi / (2 * numpy.arcsin(1.0 / numpy.sqrt(self.F)))
|
|
1408
1385
|
# self.FINESSE = numpy.pi * numpy.sqrt(self.F) / 2.
|
EMpy/materials.py
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
A material is an object with a refractive index function.
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
from functools import partial
|
|
9
10
|
|
|
10
11
|
import numpy
|
|
@@ -15,7 +16,6 @@ __author__ = "Lorenzo Bolla"
|
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class Material:
|
|
18
|
-
|
|
19
19
|
"""Generic class to handle materials.
|
|
20
20
|
|
|
21
21
|
This class is intended to be subclassed to obtain isotropic and
|
|
@@ -28,7 +28,6 @@ class Material:
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class RefractiveIndex:
|
|
31
|
-
|
|
32
31
|
"""Refractive Index.
|
|
33
32
|
|
|
34
33
|
Unaware of temperature.
|
|
@@ -146,7 +145,6 @@ class RefractiveIndex:
|
|
|
146
145
|
|
|
147
146
|
|
|
148
147
|
class ThermalOpticCoefficient:
|
|
149
|
-
|
|
150
148
|
"""Thermal Optic Coefficient."""
|
|
151
149
|
|
|
152
150
|
def __init__(self, data=None, T0=300):
|
|
@@ -168,7 +166,6 @@ class ThermalOpticCoefficient:
|
|
|
168
166
|
|
|
169
167
|
|
|
170
168
|
class IsotropicMaterial(Material):
|
|
171
|
-
|
|
172
169
|
"""Subclasses Material to describe isotropic materials.
|
|
173
170
|
|
|
174
171
|
Frequency dispersion and thermic aware.
|
|
@@ -232,7 +229,6 @@ class EpsilonTensor:
|
|
|
232
229
|
|
|
233
230
|
|
|
234
231
|
class AnisotropicMaterial(Material):
|
|
235
|
-
|
|
236
232
|
"""Subclass Material to describe anisotropic materials.
|
|
237
233
|
|
|
238
234
|
No frequency dispersion nor thermic aware.
|
|
@@ -292,7 +288,6 @@ BK7 = IsotropicMaterial(
|
|
|
292
288
|
|
|
293
289
|
|
|
294
290
|
class LiquidCrystal(Material):
|
|
295
|
-
|
|
296
291
|
"""Liquid Crystal.
|
|
297
292
|
|
|
298
293
|
A liquid crystal is determined by it ordinary and extraordinary
|
EMpy/modesolvers/FD.py
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
@see: http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=12734&objectType=FILE
|
|
11
11
|
|
|
12
12
|
"""
|
|
13
|
+
|
|
14
|
+
from matplotlib import pyplot as plt
|
|
13
15
|
import numpy
|
|
14
16
|
import scipy
|
|
15
17
|
import scipy.optimize
|
|
@@ -19,7 +21,6 @@ from EMpy.modesolvers.interface import Mode, ModeSolver
|
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
class SVFDModeSolver(ModeSolver):
|
|
22
|
-
|
|
23
24
|
"""
|
|
24
25
|
This function calculates the modes of a dielectric waveguide
|
|
25
26
|
using the semivectorial finite difference method.
|
|
@@ -142,10 +143,8 @@ class SVFDModeSolver(ModeSolver):
|
|
|
142
143
|
* (p * (ep - ew) + 2 * w * ew)
|
|
143
144
|
* ee
|
|
144
145
|
/ (
|
|
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)
|
|
146
|
+
(p * (ep - ee) + 2 * e * ee) * (p**2 * (ep - ew) + 4 * w**2 * ew)
|
|
147
|
+
+ (p * (ep - ew) + 2 * w * ew) * (p**2 * (ep - ee) + 4 * e**2 * ee)
|
|
149
148
|
)
|
|
150
149
|
)
|
|
151
150
|
Aw = (
|
|
@@ -153,10 +152,8 @@ class SVFDModeSolver(ModeSolver):
|
|
|
153
152
|
* (p * (ep - ee) + 2 * e * ee)
|
|
154
153
|
* ew
|
|
155
154
|
/ (
|
|
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)
|
|
155
|
+
(p * (ep - ee) + 2 * e * ee) * (p**2 * (ep - ew) + 4 * w**2 * ew)
|
|
156
|
+
+ (p * (ep - ew) + 2 * w * ew) * (p**2 * (ep - ee) + 4 * e**2 * ee)
|
|
160
157
|
)
|
|
161
158
|
)
|
|
162
159
|
Ap = ep * k**2 - An - As - Ae * ep / ee - Aw * ep / ew
|
|
@@ -169,10 +166,8 @@ class SVFDModeSolver(ModeSolver):
|
|
|
169
166
|
* (q * (ep - es) + 2 * s * es)
|
|
170
167
|
* en
|
|
171
168
|
/ (
|
|
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)
|
|
169
|
+
(q * (ep - en) + 2 * n * en) * (q**2 * (ep - es) + 4 * s**2 * es)
|
|
170
|
+
+ (q * (ep - es) + 2 * s * es) * (q**2 * (ep - en) + 4 * n**2 * en)
|
|
176
171
|
)
|
|
177
172
|
)
|
|
178
173
|
As = (
|
|
@@ -180,10 +175,8 @@ class SVFDModeSolver(ModeSolver):
|
|
|
180
175
|
* (q * (ep - en) + 2 * n * en)
|
|
181
176
|
* es
|
|
182
177
|
/ (
|
|
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)
|
|
178
|
+
(q * (ep - en) + 2 * n * en) * (q**2 * (ep - es) + 4 * s**2 * es)
|
|
179
|
+
+ (q * (ep - es) + 2 * s * es) * (q**2 * (ep - en) + 4 * n**2 * en)
|
|
187
180
|
)
|
|
188
181
|
)
|
|
189
182
|
Ae = 2 / e / (e + w)
|
|
@@ -255,14 +248,14 @@ class SVFDModeSolver(ModeSolver):
|
|
|
255
248
|
return A
|
|
256
249
|
|
|
257
250
|
def solve(self, neigs, tol):
|
|
258
|
-
from scipy.sparse
|
|
251
|
+
from scipy.sparse import linalg
|
|
259
252
|
|
|
260
253
|
self.nmodes = neigs
|
|
261
254
|
self.tol = tol
|
|
262
255
|
|
|
263
256
|
A = self.build_matrix()
|
|
264
257
|
|
|
265
|
-
eigvals, eigvecs =
|
|
258
|
+
eigvals, eigvecs = linalg.eigs( # type: ignore
|
|
266
259
|
A, k=neigs, which="LR", tol=tol, ncv=10 * neigs, return_eigenvectors=True
|
|
267
260
|
)
|
|
268
261
|
|
|
@@ -296,7 +289,6 @@ class SVFDModeSolver(ModeSolver):
|
|
|
296
289
|
|
|
297
290
|
|
|
298
291
|
class VFDModeSolver(ModeSolver):
|
|
299
|
-
|
|
300
292
|
"""
|
|
301
293
|
The VFDModeSolver class computes the electric and magnetic fields
|
|
302
294
|
for modes of a dielectric waveguide using the "Vector Finite
|
|
@@ -1135,12 +1127,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
1135
1127
|
(n * ezz1 * ezz2 / eyy1 + s * ezz2 * ezz1 / eyy2)
|
|
1136
1128
|
* (
|
|
1137
1129
|
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)
|
|
1130
|
+
+ 0.5 * s * ezz3 * ezz4 / eyy3 * (2.0 / e**2 + eyx3 / ezz3 / s / e)
|
|
1144
1131
|
)
|
|
1145
1132
|
/ ezz4
|
|
1146
1133
|
/ ezz3
|
|
@@ -1190,12 +1177,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
1190
1177
|
(-n * ezz4 * ezz3 / eyy4 - s * ezz3 * ezz4 / eyy3)
|
|
1191
1178
|
* (
|
|
1192
1179
|
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)
|
|
1180
|
+
+ 0.5 * s * ezz2 * ezz1 / eyy2 * (2.0 / w**2 - eyx2 / ezz2 / s / w)
|
|
1199
1181
|
)
|
|
1200
1182
|
/ ezz4
|
|
1201
1183
|
/ ezz3
|
|
@@ -1517,12 +1499,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
1517
1499
|
+ (ezz3 / exx2 * ezz2 * w + ezz2 / exx3 * ezz3 * e)
|
|
1518
1500
|
* (
|
|
1519
1501
|
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
|
|
1502
|
+
+ 0.5 * ezz1 * (2.0 / n**2 - exy4 / ezz4 / n / e) / exx4 * ezz4 * e
|
|
1526
1503
|
)
|
|
1527
1504
|
/ ezz3
|
|
1528
1505
|
/ ezz2
|
|
@@ -1572,12 +1549,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
1572
1549
|
- (ezz4 / exx1 * ezz1 * w + ezz1 / exx4 * ezz4 * e)
|
|
1573
1550
|
* (
|
|
1574
1551
|
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
|
|
1552
|
+
+ 0.5 * ezz2 * (2.0 / s**2 + exy3 / ezz3 / s / e) / exx3 * ezz3 * e
|
|
1581
1553
|
)
|
|
1582
1554
|
/ ezz3
|
|
1583
1555
|
/ ezz2
|
|
@@ -2066,7 +2038,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
2066
2038
|
Ez = solver.modes[0].Ez
|
|
2067
2039
|
"""
|
|
2068
2040
|
|
|
2069
|
-
from scipy.sparse
|
|
2041
|
+
from scipy.sparse import linalg
|
|
2070
2042
|
|
|
2071
2043
|
self.nmodes = neigs
|
|
2072
2044
|
self.tol = tol
|
|
@@ -2081,7 +2053,7 @@ class VFDModeSolver(ModeSolver):
|
|
|
2081
2053
|
shift = None
|
|
2082
2054
|
|
|
2083
2055
|
# Here is where the actual mode-solving takes place!
|
|
2084
|
-
[eigvals, eigvecs] =
|
|
2056
|
+
[eigvals, eigvecs] = linalg.eigs(
|
|
2085
2057
|
A,
|
|
2086
2058
|
k=neigs,
|
|
2087
2059
|
which="LR",
|
|
@@ -2320,14 +2292,9 @@ class FDMode(Mode):
|
|
|
2320
2292
|
|
|
2321
2293
|
@staticmethod
|
|
2322
2294
|
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")
|
|
2295
|
+
plt.hot()
|
|
2296
|
+
plt.contour(x, y, numpy.abs(field.T), 16)
|
|
2297
|
+
plt.axis("image")
|
|
2331
2298
|
|
|
2332
2299
|
def plot_Ex(self, x=None, y=None):
|
|
2333
2300
|
if x is None:
|
|
@@ -2385,30 +2352,25 @@ class FDMode(Mode):
|
|
|
2385
2352
|
|
|
2386
2353
|
def plot(self):
|
|
2387
2354
|
"""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)
|
|
2355
|
+
plt.figure()
|
|
2356
|
+
plt.subplot(2, 3, 1)
|
|
2395
2357
|
self.plot_Ex()
|
|
2396
|
-
|
|
2397
|
-
|
|
2358
|
+
plt.title("Ex")
|
|
2359
|
+
plt.subplot(2, 3, 2)
|
|
2398
2360
|
self.plot_Ey()
|
|
2399
|
-
|
|
2400
|
-
|
|
2361
|
+
plt.title("Ey")
|
|
2362
|
+
plt.subplot(2, 3, 3)
|
|
2401
2363
|
self.plot_Ez()
|
|
2402
|
-
|
|
2403
|
-
|
|
2364
|
+
plt.title("Ez")
|
|
2365
|
+
plt.subplot(2, 3, 4)
|
|
2404
2366
|
self.plot_Hx()
|
|
2405
|
-
|
|
2406
|
-
|
|
2367
|
+
plt.title("Hx")
|
|
2368
|
+
plt.subplot(2, 3, 5)
|
|
2407
2369
|
self.plot_Hy()
|
|
2408
|
-
|
|
2409
|
-
|
|
2370
|
+
plt.title("Hy")
|
|
2371
|
+
plt.subplot(2, 3, 6)
|
|
2410
2372
|
self.plot_Hz()
|
|
2411
|
-
|
|
2373
|
+
plt.title("Hz")
|
|
2412
2374
|
|
|
2413
2375
|
|
|
2414
2376
|
def stretchmesh(x, y, nlayers, factor, method="PPPP"):
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
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
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
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
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
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))
|