ElectroMagneticPython 2.0.0__tar.gz → 2.1.5__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.
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/RCWA.py +242 -154
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/__init__.py +13 -9
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/constants.py +3 -3
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/devices.py +228 -162
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/materials.py +77 -53
- ElectroMagneticPython-2.1.5/EMpy/modesolvers/FD.py +2522 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/modesolvers/FMM.py +1082 -826
- ElectroMagneticPython-2.1.5/EMpy/modesolvers/__init__.py +13 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/modesolvers/geometries.py +72 -72
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/modesolvers/interface.py +27 -28
- ElectroMagneticPython-2.1.5/EMpy/scattering.py +236 -0
- ElectroMagneticPython-2.1.5/EMpy/transfer_matrix.py +418 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/EMpy/utils.py +387 -271
- ElectroMagneticPython-2.1.5/EMpy/version.py +1 -0
- ElectroMagneticPython-2.1.5/ElectroMagneticPython.egg-info/PKG-INFO +95 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/ElectroMagneticPython.egg-info/SOURCES.txt +3 -0
- ElectroMagneticPython-2.1.5/ElectroMagneticPython.egg-info/requires.txt +3 -0
- ElectroMagneticPython-2.1.5/LICENSE +21 -0
- ElectroMagneticPython-2.1.5/PKG-INFO +95 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/README.rst +6 -10
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/ex_APRR.py +5 -5
- ElectroMagneticPython-2.1.5/examples/ex_NRR.py +38 -0
- ElectroMagneticPython-2.1.5/examples/ex_RCWA.py +96 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/ex_RCWA_2.py +19 -19
- ElectroMagneticPython-2.1.5/examples/ex_RCWA_3.py +58 -0
- ElectroMagneticPython-2.1.5/examples/ex_SRR.py +21 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/ex_laser_etch_monitor.py +63 -43
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/ex_modesolver.py +20 -18
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/ex_modesolver_2.py +25 -17
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/ex_modesolver_3.py +8 -7
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/ex_modesolver_4.py +11 -8
- ElectroMagneticPython-2.1.5/examples/ex_modesolver_dch.py +296 -0
- ElectroMagneticPython-2.1.5/examples/ex_modesolver_dch_anis.py +318 -0
- ElectroMagneticPython-2.1.5/examples/ex_transfer_matrix.py +81 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/ex_transfer_matrix_2.py +18 -11
- ElectroMagneticPython-2.1.5/examples/ex_transfer_matrix_3.py +59 -0
- ElectroMagneticPython-2.1.5/examples/nk.py +1474 -0
- ElectroMagneticPython-2.1.5/requirements.txt +34 -0
- ElectroMagneticPython-2.1.5/setup.cfg +11 -0
- ElectroMagneticPython-2.1.5/setup.py +42 -0
- ElectroMagneticPython-2.1.5/tests/__init__.py +1 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/tests/materials_test.py +3 -6
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/tests/utils_test.py +0 -1
- ElectroMagneticPython-2.0.0/EMpy/modesolvers/FD.py +0 -1428
- ElectroMagneticPython-2.0.0/EMpy/modesolvers/__init__.py +0 -15
- ElectroMagneticPython-2.0.0/EMpy/scattering.py +0 -191
- ElectroMagneticPython-2.0.0/EMpy/transfer_matrix.py +0 -380
- ElectroMagneticPython-2.0.0/EMpy/version.py +0 -1
- ElectroMagneticPython-2.0.0/ElectroMagneticPython.egg-info/PKG-INFO +0 -95
- ElectroMagneticPython-2.0.0/ElectroMagneticPython.egg-info/requires.txt +0 -4
- ElectroMagneticPython-2.0.0/PKG-INFO +0 -95
- ElectroMagneticPython-2.0.0/examples/ex_NRR.py +0 -31
- ElectroMagneticPython-2.0.0/examples/ex_RCWA.py +0 -85
- ElectroMagneticPython-2.0.0/examples/ex_RCWA_3.py +0 -44
- ElectroMagneticPython-2.0.0/examples/ex_SRR.py +0 -23
- ElectroMagneticPython-2.0.0/examples/ex_transfer_matrix.py +0 -46
- ElectroMagneticPython-2.0.0/examples/ex_transfer_matrix_3.py +0 -48
- ElectroMagneticPython-2.0.0/examples/nk.py +0 -1036
- ElectroMagneticPython-2.0.0/requirements.txt +0 -18
- ElectroMagneticPython-2.0.0/setup.cfg +0 -10
- ElectroMagneticPython-2.0.0/setup.py +0 -45
- ElectroMagneticPython-2.0.0/tests/__init__.py +0 -1
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/ElectroMagneticPython.egg-info/dependency_links.txt +0 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/ElectroMagneticPython.egg-info/top_level.txt +0 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/MANIFEST.in +0 -0
- {ElectroMagneticPython-2.0.0 → ElectroMagneticPython-2.1.5}/examples/lc_data.dat +0 -0
|
@@ -12,16 +12,19 @@ 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
|
-
from builtins import range
|
|
16
|
-
from builtins import object
|
|
17
|
-
|
|
18
15
|
__author__ = "Lorenzo Bolla"
|
|
19
16
|
|
|
20
17
|
import scipy as S
|
|
21
18
|
from scipy.linalg import toeplitz, inv, eig, solve as linsolve
|
|
22
19
|
from numpy import pi
|
|
23
20
|
|
|
24
|
-
from EMpy.utils import
|
|
21
|
+
from EMpy.utils import (
|
|
22
|
+
cond,
|
|
23
|
+
warning,
|
|
24
|
+
BinaryGrating,
|
|
25
|
+
SymmetricDoubleGrating,
|
|
26
|
+
AsymmetricDoubleGrating,
|
|
27
|
+
)
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
def dispersion_relation_ordinary(kx, ky, k, nO):
|
|
@@ -35,9 +38,9 @@ def dispersion_relation_ordinary(kx, ky, k, nO):
|
|
|
35
38
|
"""
|
|
36
39
|
|
|
37
40
|
if kx.shape != ky.shape:
|
|
38
|
-
raise ValueError(
|
|
41
|
+
raise ValueError("kx and ky must have the same length")
|
|
39
42
|
|
|
40
|
-
delta = (k * nO) ** 2 - (kx
|
|
43
|
+
delta = (k * nO) ** 2 - (kx**2 + ky**2)
|
|
41
44
|
kz = S.sqrt(delta)
|
|
42
45
|
|
|
43
46
|
# Adjust sign of real/imag part
|
|
@@ -59,19 +62,25 @@ def dispersion_relation_extraordinary(kx, ky, k, nO, nE, c):
|
|
|
59
62
|
|
|
60
63
|
if kx.shape != ky.shape or c.size != 3:
|
|
61
64
|
raise ValueError(
|
|
62
|
-
|
|
65
|
+
"kx and ky must have the same length and c must have 3 components"
|
|
66
|
+
)
|
|
63
67
|
|
|
64
68
|
kz = S.empty_like(kx)
|
|
65
69
|
|
|
66
70
|
for ii in range(0, kx.size):
|
|
67
|
-
|
|
68
|
-
alpha = nE ** 2 - nO ** 2
|
|
71
|
+
alpha = nE**2 - nO**2
|
|
69
72
|
beta = kx[ii] / k * c[0] + ky[ii] / k * c[1]
|
|
70
73
|
|
|
71
74
|
# coeffs
|
|
72
|
-
C = S.array(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
C = S.array(
|
|
76
|
+
[
|
|
77
|
+
nO**2 + c[2] ** 2 * alpha,
|
|
78
|
+
2.0 * c[2] * beta * alpha,
|
|
79
|
+
nO**2 * (kx[ii] ** 2 + ky[ii] ** 2) / k**2
|
|
80
|
+
+ alpha * beta**2
|
|
81
|
+
- nO**2 * nE**2,
|
|
82
|
+
]
|
|
83
|
+
)
|
|
75
84
|
|
|
76
85
|
# two solutions of type +x or -x, purely real or purely imag
|
|
77
86
|
tmp_kz = k * S.roots(C)
|
|
@@ -85,7 +94,7 @@ def dispersion_relation_extraordinary(kx, ky, k, nO, nE, c):
|
|
|
85
94
|
return kz
|
|
86
95
|
|
|
87
96
|
|
|
88
|
-
class RCWA
|
|
97
|
+
class RCWA:
|
|
89
98
|
|
|
90
99
|
"""Class to handle the RCWA solvers.
|
|
91
100
|
|
|
@@ -136,9 +145,16 @@ class RCWA(object):
|
|
|
136
145
|
def get_pitch(self):
|
|
137
146
|
"""Inspect the multilayer to check that all the binary
|
|
138
147
|
gratings present have the same pitch, and return it."""
|
|
139
|
-
idx = S.where(
|
|
140
|
-
|
|
141
|
-
|
|
148
|
+
idx = S.where(
|
|
149
|
+
[
|
|
150
|
+
(
|
|
151
|
+
isinstance(m, BinaryGrating)
|
|
152
|
+
| isinstance(m, SymmetricDoubleGrating)
|
|
153
|
+
| isinstance(m, AsymmetricDoubleGrating)
|
|
154
|
+
)
|
|
155
|
+
for m in self.multilayer
|
|
156
|
+
]
|
|
157
|
+
)[0]
|
|
142
158
|
if idx.size == 0:
|
|
143
159
|
# warning('no BinaryGratings: better use a simple transfer matrix.')
|
|
144
160
|
return 1.0 # return LAMBDA: any value will do
|
|
@@ -146,8 +162,7 @@ class RCWA(object):
|
|
|
146
162
|
# check that all the pitches are the same!
|
|
147
163
|
l = S.asarray([self.multilayer[i].pitch for i in idx])
|
|
148
164
|
if not S.all(l == l[0]):
|
|
149
|
-
raise ValueError(
|
|
150
|
-
'All the BinaryGratings must have the same pitch.')
|
|
165
|
+
raise ValueError("All the BinaryGratings must have the same pitch.")
|
|
151
166
|
else:
|
|
152
167
|
return l[0]
|
|
153
168
|
|
|
@@ -194,15 +209,14 @@ class IsotropicRCWA(RCWA):
|
|
|
194
209
|
|
|
195
210
|
# grating vector (on the xz plane)
|
|
196
211
|
# grating on the xy plane
|
|
197
|
-
K = 2 * pi / LAMBDA *
|
|
198
|
-
S.array([S.sin(phi), 0., S.cos(phi)], dtype=complex)
|
|
212
|
+
K = 2 * pi / LAMBDA * S.array([S.sin(phi), 0.0, S.cos(phi)], dtype=complex)
|
|
199
213
|
|
|
200
214
|
DE1 = S.zeros((nood, self.wls.size))
|
|
201
215
|
DE3 = S.zeros_like(DE1)
|
|
202
216
|
|
|
203
|
-
dirk1 = S.array(
|
|
204
|
-
|
|
205
|
-
|
|
217
|
+
dirk1 = S.array(
|
|
218
|
+
[S.sin(alpha) * S.cos(delta), S.sin(alpha) * S.sin(delta), S.cos(alpha)]
|
|
219
|
+
)
|
|
206
220
|
|
|
207
221
|
# usefull matrices
|
|
208
222
|
I = S.eye(i.size)
|
|
@@ -219,7 +233,6 @@ class IsotropicRCWA(RCWA):
|
|
|
219
233
|
dlt = (i == 0).astype(int)
|
|
220
234
|
|
|
221
235
|
for iwl, wl in enumerate(self.wls):
|
|
222
|
-
|
|
223
236
|
# free space wavevector
|
|
224
237
|
k = 2 * pi / wl
|
|
225
238
|
|
|
@@ -250,36 +263,32 @@ class IsotropicRCWA(RCWA):
|
|
|
250
263
|
|
|
251
264
|
Kx = S.diag(kx / k)
|
|
252
265
|
Ky = ky / k * I
|
|
253
|
-
Z1 = S.diag(k1i[2, :] / (k * n1
|
|
266
|
+
Z1 = S.diag(k1i[2, :] / (k * n1**2))
|
|
254
267
|
Y1 = S.diag(k1i[2, :] / k)
|
|
255
|
-
Z3 = S.diag(k3i[2, :] / (k * n3
|
|
268
|
+
Z3 = S.diag(k3i[2, :] / (k * n3**2))
|
|
256
269
|
Y3 = S.diag(k3i[2, :] / k)
|
|
257
270
|
# Fc = S.diag(S.cos(phi_i))
|
|
258
271
|
fc = S.cos(phi_i)
|
|
259
272
|
# Fs = S.diag(S.sin(phi_i))
|
|
260
273
|
fs = S.sin(phi_i)
|
|
261
274
|
|
|
262
|
-
MR = S.asarray(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
[ZERO, -1j * Z1]]))
|
|
275
|
+
MR = S.asarray(
|
|
276
|
+
S.bmat([[I, ZERO], [-1j * Y1, ZERO], [ZERO, I], [ZERO, -1j * Z1]])
|
|
277
|
+
)
|
|
266
278
|
|
|
267
|
-
MT = S.asarray(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
[ZERO, 1j * Z3]]))
|
|
279
|
+
MT = S.asarray(
|
|
280
|
+
S.bmat([[I, ZERO], [1j * Y3, ZERO], [ZERO, I], [ZERO, 1j * Z3]])
|
|
281
|
+
)
|
|
271
282
|
|
|
272
283
|
# internal layers (grating or layer)
|
|
273
284
|
X.fill(0.0)
|
|
274
285
|
MTp1.fill(0.0)
|
|
275
286
|
MTp2.fill(0.0)
|
|
276
287
|
for nlayer in range(nlayers - 2, 0, -1): # internal layers
|
|
277
|
-
|
|
278
288
|
layer = multilayer[nlayer]
|
|
279
289
|
d = layer.thickness
|
|
280
290
|
|
|
281
|
-
EPS2, EPS21 = layer.getEPSFourierCoeffs(
|
|
282
|
-
wl, n, anisotropic=False)
|
|
291
|
+
EPS2, EPS21 = layer.getEPSFourierCoeffs(wl, n, anisotropic=False)
|
|
283
292
|
|
|
284
293
|
E = toeplitz(EPS2[hmax::-1], EPS2[hmax:])
|
|
285
294
|
E1 = toeplitz(EPS21[hmax::-1], EPS21[hmax:])
|
|
@@ -296,25 +305,27 @@ class IsotropicRCWA(RCWA):
|
|
|
296
305
|
# non sono invertibili --> cambio leggermente i kx... ma dovrei invece
|
|
297
306
|
# trattare separatamente (analiticamente) questi casi
|
|
298
307
|
if cond(A) > 1e10:
|
|
299
|
-
warning(
|
|
308
|
+
warning("BAD CONDITIONING: randomization of kx")
|
|
300
309
|
while cond(A) > 1e10:
|
|
301
310
|
Kx = Kx * (1 + 1e-9 * S.rand())
|
|
302
311
|
B = kx[:, S.newaxis] / k * linsolve(E, Kx) - I
|
|
303
312
|
A = S.diag((kx / k) ** 2) - E
|
|
304
313
|
|
|
305
314
|
if S.absolute(K[2] / k) > 1e-10:
|
|
306
|
-
|
|
307
315
|
raise ValueError(
|
|
308
|
-
|
|
316
|
+
"First Order Helmholtz Operator not implemented, yet!"
|
|
317
|
+
)
|
|
309
318
|
|
|
310
319
|
elif ky == 0 or S.allclose(S.diag(Ky / ky * k), 1):
|
|
311
|
-
|
|
312
320
|
# lalanne
|
|
313
321
|
# H_U_reduced = S.dot(Ky, Ky) + A
|
|
314
322
|
H_U_reduced = (ky / k) ** 2 * I + A
|
|
315
323
|
# H_S_reduced = S.dot(Ky, Ky) + S.dot(Kx, linsolve(E, S.dot(Kx, E11))) - E11
|
|
316
|
-
H_S_reduced = (
|
|
317
|
-
|
|
324
|
+
H_S_reduced = (
|
|
325
|
+
(ky / k) ** 2 * I
|
|
326
|
+
+ kx[:, S.newaxis] / k * linsolve(E, kx[:, S.newaxis] / k * E11)
|
|
327
|
+
- E11
|
|
328
|
+
)
|
|
318
329
|
|
|
319
330
|
q1, W1 = eig(H_U_reduced)
|
|
320
331
|
q1 = S.sqrt(q1)
|
|
@@ -347,10 +358,16 @@ class IsotropicRCWA(RCWA):
|
|
|
347
358
|
# Vps = S.dot(Fs, V11)
|
|
348
359
|
Vps = fs[:, S.newaxis] * V11
|
|
349
360
|
|
|
350
|
-
Mc2bar = S.asarray(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
361
|
+
Mc2bar = S.asarray(
|
|
362
|
+
S.bmat(
|
|
363
|
+
[
|
|
364
|
+
[Vss, Vsp, Vss, Vsp],
|
|
365
|
+
[Wss, Wsp, -Wss, -Wsp],
|
|
366
|
+
[Wps, Wpp, -Wps, -Wpp],
|
|
367
|
+
[Vps, Vpp, Vps, Vpp],
|
|
368
|
+
]
|
|
369
|
+
)
|
|
370
|
+
)
|
|
354
371
|
|
|
355
372
|
x = S.r_[S.exp(-k * q1 * d), S.exp(-k * q2 * d)]
|
|
356
373
|
|
|
@@ -361,28 +378,28 @@ class IsotropicRCWA(RCWA):
|
|
|
361
378
|
X[:, :, nlayer] = S.diag(x)
|
|
362
379
|
|
|
363
380
|
MTp = linsolve(Mc2bar, MT)
|
|
364
|
-
MTp1[:, :, nlayer] = MTp[0:2 * nood, :]
|
|
365
|
-
MTp2 = MTp[2 * nood:, :]
|
|
381
|
+
MTp1[:, :, nlayer] = MTp[0 : 2 * nood, :]
|
|
382
|
+
MTp2 = MTp[2 * nood :, :]
|
|
366
383
|
|
|
367
384
|
MT = S.dot(
|
|
368
|
-
Mc1,
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
385
|
+
Mc1,
|
|
386
|
+
S.r_[
|
|
387
|
+
I2,
|
|
388
|
+
S.dot(MTp2, linsolve(MTp1[:, :, nlayer], X[:, :, nlayer])),
|
|
389
|
+
],
|
|
390
|
+
)
|
|
374
391
|
|
|
375
392
|
else:
|
|
376
|
-
|
|
377
|
-
ValueError(
|
|
378
|
-
'Second Order Helmholtz Operator not implemented, yet!')
|
|
393
|
+
ValueError("Second Order Helmholtz Operator not implemented, yet!")
|
|
379
394
|
|
|
380
395
|
# M = S.asarray(S.bmat([-MR, MT]))
|
|
381
396
|
M = S.c_[-MR, MT]
|
|
382
|
-
b = S.r_[
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
397
|
+
b = S.r_[
|
|
398
|
+
S.sin(psi) * dlt,
|
|
399
|
+
1j * S.sin(psi) * n1 * S.cos(alpha) * dlt,
|
|
400
|
+
-1j * S.cos(psi) * n1 * dlt,
|
|
401
|
+
S.cos(psi) * S.cos(alpha) * dlt,
|
|
402
|
+
]
|
|
386
403
|
|
|
387
404
|
x = linsolve(M, b)
|
|
388
405
|
R, T = S.split(x, 2)
|
|
@@ -391,12 +408,12 @@ class IsotropicRCWA(RCWA):
|
|
|
391
408
|
T = S.dot(linsolve(MTp1[:, :, ii], X[:, :, ii]), T)
|
|
392
409
|
Ts, Tp = S.split(T, 2)
|
|
393
410
|
|
|
394
|
-
DE1[:, iwl] = (k1i[2, :] / (k1[2])).real * S.absolute(Rs) ** 2 +
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
DE3[:, iwl] = (k3i[2, :] / (k1[2])).real * S.absolute(Ts) ** 2 +
|
|
398
|
-
|
|
399
|
-
|
|
411
|
+
DE1[:, iwl] = (k1i[2, :] / (k1[2])).real * S.absolute(Rs) ** 2 + (
|
|
412
|
+
k1i[2, :] / (k1[2] * n1**2)
|
|
413
|
+
).real * S.absolute(Rp) ** 2
|
|
414
|
+
DE3[:, iwl] = (k3i[2, :] / (k1[2])).real * S.absolute(Ts) ** 2 + (
|
|
415
|
+
k3i[2, :] / (k1[2] * n3**2)
|
|
416
|
+
).real * S.absolute(Tp) ** 2
|
|
400
417
|
|
|
401
418
|
# save the results
|
|
402
419
|
self.DE1 = DE1
|
|
@@ -416,14 +433,18 @@ class IsotropicRCWA(RCWA):
|
|
|
416
433
|
# raw_input('press enter to close the graph...')
|
|
417
434
|
|
|
418
435
|
def __str__(self):
|
|
419
|
-
return
|
|
420
|
-
|
|
436
|
+
return (
|
|
437
|
+
"ISOTROPIC RCWA SOLVER\n\n%s\n\nLAMBDA = %g\nalpha = %g\ndelta = %g\npsi = %g\nphi = %g\nn = %d"
|
|
438
|
+
% (
|
|
439
|
+
self.multilayer.__str__(),
|
|
421
440
|
self.LAMBDA,
|
|
422
441
|
self.alpha,
|
|
423
442
|
self.delta,
|
|
424
443
|
self.psi,
|
|
425
444
|
self.phi,
|
|
426
|
-
self.n
|
|
445
|
+
self.n,
|
|
446
|
+
)
|
|
447
|
+
)
|
|
427
448
|
|
|
428
449
|
|
|
429
450
|
class AnisotropicRCWA(RCWA):
|
|
@@ -461,20 +482,22 @@ class AnisotropicRCWA(RCWA):
|
|
|
461
482
|
DEE1 = S.zeros_like(DEO1)
|
|
462
483
|
DEE3 = S.zeros_like(DEO1)
|
|
463
484
|
|
|
464
|
-
c1 = S.array([1
|
|
465
|
-
c3 = S.array([1
|
|
485
|
+
c1 = S.array([1.0, 0.0, 0.0])
|
|
486
|
+
c3 = S.array([1.0, 0.0, 0.0])
|
|
466
487
|
# grating on the xy plane
|
|
467
|
-
K = 2 * pi / LAMBDA *
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
S.cos(alpha)])
|
|
488
|
+
K = 2 * pi / LAMBDA * S.array([S.sin(phi), 0.0, S.cos(phi)], dtype=complex)
|
|
489
|
+
dirk1 = S.array(
|
|
490
|
+
[S.sin(alpha) * S.cos(delta), S.sin(alpha) * S.sin(delta), S.cos(alpha)]
|
|
491
|
+
)
|
|
472
492
|
|
|
473
493
|
# D polarization vector
|
|
474
|
-
u = S.array(
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
494
|
+
u = S.array(
|
|
495
|
+
[
|
|
496
|
+
S.cos(psi) * S.cos(alpha) * S.cos(delta) - S.sin(psi) * S.sin(delta),
|
|
497
|
+
S.cos(psi) * S.cos(alpha) * S.sin(delta) + S.sin(psi) * S.cos(delta),
|
|
498
|
+
-S.cos(psi) * S.sin(alpha),
|
|
499
|
+
]
|
|
500
|
+
)
|
|
478
501
|
|
|
479
502
|
kO1i = S.zeros((3, i.size), dtype=complex)
|
|
480
503
|
kE1i = S.zeros_like(kO1i)
|
|
@@ -487,7 +510,6 @@ class AnisotropicRCWA(RCWA):
|
|
|
487
510
|
dlt = (i == 0).astype(int)
|
|
488
511
|
|
|
489
512
|
for iwl, wl in enumerate(self.wls):
|
|
490
|
-
|
|
491
513
|
nO1 = nE1 = multilayer[0].mat.n(wl).item()
|
|
492
514
|
nO3 = nE3 = multilayer[-1].mat.n(wl).item()
|
|
493
515
|
|
|
@@ -508,39 +530,26 @@ class AnisotropicRCWA(RCWA):
|
|
|
508
530
|
|
|
509
531
|
kO1i[0, :] = k1[0] - i * K[0]
|
|
510
532
|
kO1i[1, :] = k1[1] * S.ones_like(i)
|
|
511
|
-
kO1i[2, :] = -
|
|
512
|
-
dispersion_relation_ordinary(kO1i[0, :], kO1i[1, :], k, nO1)
|
|
533
|
+
kO1i[2, :] = -dispersion_relation_ordinary(kO1i[0, :], kO1i[1, :], k, nO1)
|
|
513
534
|
|
|
514
535
|
kE1i[0, :] = kO1i[0, :]
|
|
515
536
|
kE1i[1, :] = kO1i[1, :]
|
|
516
|
-
kE1i[2,
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
kE1i[1,
|
|
520
|
-
:],
|
|
521
|
-
k,
|
|
522
|
-
nO1,
|
|
523
|
-
nE1,
|
|
524
|
-
c1)
|
|
537
|
+
kE1i[2, :] = -dispersion_relation_extraordinary(
|
|
538
|
+
kE1i[0, :], kE1i[1, :], k, nO1, nE1, c1
|
|
539
|
+
)
|
|
525
540
|
|
|
526
541
|
kO3i[0, :] = kO1i[0, :]
|
|
527
542
|
kO3i[1, :] = kO1i[1, :]
|
|
528
|
-
kO3i[
|
|
529
|
-
2, :] = dispersion_relation_ordinary(
|
|
530
|
-
kO3i[
|
|
531
|
-
0, :], kO3i[
|
|
532
|
-
1, :], k, nO3)
|
|
543
|
+
kO3i[2, :] = dispersion_relation_ordinary(kO3i[0, :], kO3i[1, :], k, nO3)
|
|
533
544
|
|
|
534
545
|
kE3i[0, :] = kO1i[0, :]
|
|
535
546
|
kE3i[1, :] = kO1i[1, :]
|
|
536
|
-
kE3i[
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
0, :], kE3i[
|
|
540
|
-
1, :], k, nO3, nE3, c3)
|
|
547
|
+
kE3i[2, :] = dispersion_relation_extraordinary(
|
|
548
|
+
kE3i[0, :], kE3i[1, :], k, nO3, nE3, c3
|
|
549
|
+
)
|
|
541
550
|
|
|
542
551
|
# k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [k1[2] - i * K[2]]]
|
|
543
|
-
k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [-
|
|
552
|
+
k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [-i * K[2]]]
|
|
544
553
|
|
|
545
554
|
# aliases for constant wavevectors
|
|
546
555
|
kx = kO1i[0, :] # o kE1i(1,;), tanto e' lo stesso
|
|
@@ -581,8 +590,12 @@ class AnisotropicRCWA(RCWA):
|
|
|
581
590
|
ETE = c3[2] * Kx - c3[0] * KE3z
|
|
582
591
|
FTE = c3[0] * Ky - c3[1] * Kx
|
|
583
592
|
|
|
584
|
-
b = S.r_[
|
|
585
|
-
|
|
593
|
+
b = S.r_[
|
|
594
|
+
u[0] * dlt,
|
|
595
|
+
u[1] * dlt,
|
|
596
|
+
(k1[1] / k * u[2] - k1[2] / k * u[1]) * dlt,
|
|
597
|
+
(k1[2] / k * u[0] - k1[0] / k * u[2]) * dlt,
|
|
598
|
+
]
|
|
586
599
|
Ky_CRO_1 = ky / k * CRO_1
|
|
587
600
|
Ky_CRE_1 = ky / k * CRE_1
|
|
588
601
|
Kx_CRO_1 = kx[:, S.newaxis] / k * CRO_1
|
|
@@ -595,10 +608,16 @@ class AnisotropicRCWA(RCWA):
|
|
|
595
608
|
MR42 = S.dot(Kx_CRO_1, BRO)
|
|
596
609
|
MR43 = S.dot(Kx_CRE_1, ARE) + KE1z
|
|
597
610
|
MR44 = S.dot(Kx_CRE_1, BRE)
|
|
598
|
-
MR = S.asarray(
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
611
|
+
MR = S.asarray(
|
|
612
|
+
S.bmat(
|
|
613
|
+
[
|
|
614
|
+
[I, ZERO, I, ZERO],
|
|
615
|
+
[ZERO, I, ZERO, I],
|
|
616
|
+
[MR31, MR32, MR33, MR34],
|
|
617
|
+
[MR41, MR42, MR43, MR44],
|
|
618
|
+
]
|
|
619
|
+
)
|
|
620
|
+
)
|
|
602
621
|
|
|
603
622
|
Ky_CTO_1 = ky / k * CTO_1
|
|
604
623
|
Ky_CTE_1 = ky / k * CTE_1
|
|
@@ -612,45 +631,49 @@ class AnisotropicRCWA(RCWA):
|
|
|
612
631
|
MT42 = S.dot(Kx_CTO_1, BTO)
|
|
613
632
|
MT43 = S.dot(Kx_CTE_1, ATE) + KE3z
|
|
614
633
|
MT44 = S.dot(Kx_CTE_1, BTE)
|
|
615
|
-
MT = S.asarray(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
634
|
+
MT = S.asarray(
|
|
635
|
+
S.bmat(
|
|
636
|
+
[
|
|
637
|
+
[I, ZERO, I, ZERO],
|
|
638
|
+
[ZERO, I, ZERO, I],
|
|
639
|
+
[MT31, MT32, MT33, MT34],
|
|
640
|
+
[MT41, MT42, MT43, MT44],
|
|
641
|
+
]
|
|
642
|
+
)
|
|
643
|
+
)
|
|
619
644
|
|
|
620
645
|
Mp.fill(0.0)
|
|
621
646
|
M.fill(0.0)
|
|
622
647
|
|
|
623
648
|
for nlayer in range(nlayers - 2, 0, -1): # internal layers
|
|
624
|
-
|
|
625
649
|
layer = multilayer[nlayer]
|
|
626
650
|
thickness = layer.thickness
|
|
627
651
|
|
|
628
|
-
EPS2, EPS21 = layer.getEPSFourierCoeffs(
|
|
629
|
-
wl, n, anisotropic=True)
|
|
652
|
+
EPS2, EPS21 = layer.getEPSFourierCoeffs(wl, n, anisotropic=True)
|
|
630
653
|
|
|
631
654
|
# Exx = S.squeeze(EPS2[0, 0, :])
|
|
632
655
|
# Exx = toeplitz(S.flipud(Exx[0:hmax + 1]), Exx[hmax:])
|
|
633
656
|
Exy = S.squeeze(EPS2[0, 1, :])
|
|
634
|
-
Exy = toeplitz(S.flipud(Exy[0:hmax + 1]), Exy[hmax:])
|
|
657
|
+
Exy = toeplitz(S.flipud(Exy[0 : hmax + 1]), Exy[hmax:])
|
|
635
658
|
Exz = S.squeeze(EPS2[0, 2, :])
|
|
636
|
-
Exz = toeplitz(S.flipud(Exz[0:hmax + 1]), Exz[hmax:])
|
|
659
|
+
Exz = toeplitz(S.flipud(Exz[0 : hmax + 1]), Exz[hmax:])
|
|
637
660
|
|
|
638
661
|
Eyx = S.squeeze(EPS2[1, 0, :])
|
|
639
|
-
Eyx = toeplitz(S.flipud(Eyx[0:hmax + 1]), Eyx[hmax:])
|
|
662
|
+
Eyx = toeplitz(S.flipud(Eyx[0 : hmax + 1]), Eyx[hmax:])
|
|
640
663
|
Eyy = S.squeeze(EPS2[1, 1, :])
|
|
641
|
-
Eyy = toeplitz(S.flipud(Eyy[0:hmax + 1]), Eyy[hmax:])
|
|
664
|
+
Eyy = toeplitz(S.flipud(Eyy[0 : hmax + 1]), Eyy[hmax:])
|
|
642
665
|
Eyz = S.squeeze(EPS2[1, 2, :])
|
|
643
|
-
Eyz = toeplitz(S.flipud(Eyz[0:hmax + 1]), Eyz[hmax:])
|
|
666
|
+
Eyz = toeplitz(S.flipud(Eyz[0 : hmax + 1]), Eyz[hmax:])
|
|
644
667
|
|
|
645
668
|
Ezx = S.squeeze(EPS2[2, 0, :])
|
|
646
|
-
Ezx = toeplitz(S.flipud(Ezx[0:hmax + 1]), Ezx[hmax:])
|
|
669
|
+
Ezx = toeplitz(S.flipud(Ezx[0 : hmax + 1]), Ezx[hmax:])
|
|
647
670
|
Ezy = S.squeeze(EPS2[2, 1, :])
|
|
648
|
-
Ezy = toeplitz(S.flipud(Ezy[0:hmax + 1]), Ezy[hmax:])
|
|
671
|
+
Ezy = toeplitz(S.flipud(Ezy[0 : hmax + 1]), Ezy[hmax:])
|
|
649
672
|
Ezz = S.squeeze(EPS2[2, 2, :])
|
|
650
|
-
Ezz = toeplitz(S.flipud(Ezz[0:hmax + 1]), Ezz[hmax:])
|
|
673
|
+
Ezz = toeplitz(S.flipud(Ezz[0 : hmax + 1]), Ezz[hmax:])
|
|
651
674
|
|
|
652
675
|
Exx_1 = S.squeeze(EPS21[0, 0, :])
|
|
653
|
-
Exx_1 = toeplitz(S.flipud(Exx_1[0:hmax + 1]), Exx_1[hmax:])
|
|
676
|
+
Exx_1 = toeplitz(S.flipud(Exx_1[0 : hmax + 1]), Exx_1[hmax:])
|
|
654
677
|
Exx_1_1 = inv(Exx_1)
|
|
655
678
|
|
|
656
679
|
# lalanne
|
|
@@ -675,11 +698,16 @@ class AnisotropicRCWA(RCWA):
|
|
|
675
698
|
H42 = -S.dot(Kx, Ky) - Eyx + S.dot(Eyz_Ezz_1, Ezx)
|
|
676
699
|
H43 = -1j * S.dot(Eyz_Ezz_1, Kx)
|
|
677
700
|
H44 = 1j * S.dot(Eyz_Ezz_1, Ky)
|
|
678
|
-
H = 1j * S.diag(S.repeat(S.diag(Kz), 4)) +
|
|
679
|
-
S.
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
701
|
+
H = 1j * S.diag(S.repeat(S.diag(Kz), 4)) + S.asarray(
|
|
702
|
+
S.bmat(
|
|
703
|
+
[
|
|
704
|
+
[H11, H12, H13, H14],
|
|
705
|
+
[H21, H22, H23, H24],
|
|
706
|
+
[H31, H32, H33, H34],
|
|
707
|
+
[H41, H42, H43, H44],
|
|
708
|
+
]
|
|
709
|
+
)
|
|
710
|
+
)
|
|
683
711
|
|
|
684
712
|
q, W = eig(H)
|
|
685
713
|
W1, W2, W3, W4 = S.split(W, 4)
|
|
@@ -721,20 +749,56 @@ class AnisotropicRCWA(RCWA):
|
|
|
721
749
|
|
|
722
750
|
Mtot = S.eye(4 * nood, dtype=complex)
|
|
723
751
|
for nlayer in range(1, nlayers - 1):
|
|
724
|
-
Mtot = S.dot(
|
|
725
|
-
S.dot(Mtot, Mp[:, :, nlayer]), inv(M[:, :, nlayer]))
|
|
752
|
+
Mtot = S.dot(S.dot(Mtot, Mp[:, :, nlayer]), inv(M[:, :, nlayer]))
|
|
726
753
|
|
|
727
754
|
BC_b = S.r_[b, S.zeros_like(b)]
|
|
728
755
|
BC_A1 = S.c_[-MR, S.dot(Mtot, MT)]
|
|
729
|
-
BC_A2 = S.asarray(
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
756
|
+
BC_A2 = S.asarray(
|
|
757
|
+
S.bmat(
|
|
758
|
+
[
|
|
759
|
+
[
|
|
760
|
+
(c1[0] * I - c1[2] * S.dot(CRO_1, ARO)),
|
|
761
|
+
(c1[1] * I - c1[2] * S.dot(CRO_1, BRO)),
|
|
762
|
+
ZERO,
|
|
763
|
+
ZERO,
|
|
764
|
+
ZERO,
|
|
765
|
+
ZERO,
|
|
766
|
+
ZERO,
|
|
767
|
+
ZERO,
|
|
768
|
+
],
|
|
769
|
+
[
|
|
770
|
+
ZERO,
|
|
771
|
+
ZERO,
|
|
772
|
+
(DRE - S.dot(S.dot(FRE, CRE_1), ARE)),
|
|
773
|
+
(ERE - S.dot(S.dot(FRE, CRE_1), BRE)),
|
|
774
|
+
ZERO,
|
|
775
|
+
ZERO,
|
|
776
|
+
ZERO,
|
|
777
|
+
ZERO,
|
|
778
|
+
],
|
|
779
|
+
[
|
|
780
|
+
ZERO,
|
|
781
|
+
ZERO,
|
|
782
|
+
ZERO,
|
|
783
|
+
ZERO,
|
|
784
|
+
(c3[0] * I - c3[2] * S.dot(CTO_1, ATO)),
|
|
785
|
+
(c3[1] * I - c3[2] * S.dot(CTO_1, BTO)),
|
|
786
|
+
ZERO,
|
|
787
|
+
ZERO,
|
|
788
|
+
],
|
|
789
|
+
[
|
|
790
|
+
ZERO,
|
|
791
|
+
ZERO,
|
|
792
|
+
ZERO,
|
|
793
|
+
ZERO,
|
|
794
|
+
ZERO,
|
|
795
|
+
ZERO,
|
|
796
|
+
(DTE - S.dot(S.dot(FTE, CTE_1), ATE)),
|
|
797
|
+
(ETE - S.dot(S.dot(FTE, CTE_1), BTE)),
|
|
798
|
+
],
|
|
799
|
+
]
|
|
800
|
+
)
|
|
801
|
+
)
|
|
738
802
|
|
|
739
803
|
BC_A = S.r_[BC_A1, BC_A2]
|
|
740
804
|
|
|
@@ -748,14 +812,34 @@ class AnisotropicRCWA(RCWA):
|
|
|
748
812
|
TEz = -S.dot(CTE_1, (S.dot(ATE, TEx) + S.dot(BTE, TEy)))
|
|
749
813
|
|
|
750
814
|
denom = (k1[2] - S.dot(u, k1) * u[2]).real
|
|
751
|
-
DEO1[:, iwl] =
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
815
|
+
DEO1[:, iwl] = (
|
|
816
|
+
-(
|
|
817
|
+
(S.absolute(ROx) ** 2 + S.absolute(ROy) ** 2 + S.absolute(ROz) ** 2)
|
|
818
|
+
* S.conj(kO1i[2, :])
|
|
819
|
+
- (ROx * kO1i[0, :] + ROy * kO1i[1, :] + ROz * kO1i[2, :])
|
|
820
|
+
* S.conj(ROz)
|
|
821
|
+
).real
|
|
822
|
+
/ denom
|
|
823
|
+
)
|
|
824
|
+
DEE1[:, iwl] = (
|
|
825
|
+
-(
|
|
826
|
+
(S.absolute(REx) ** 2 + S.absolute(REy) ** 2 + S.absolute(REz) ** 2)
|
|
827
|
+
* S.conj(kE1i[2, :])
|
|
828
|
+
- (REx * kE1i[0, :] + REy * kE1i[1, :] + REz * kE1i[2, :])
|
|
829
|
+
* S.conj(REz)
|
|
830
|
+
).real
|
|
831
|
+
/ denom
|
|
832
|
+
)
|
|
833
|
+
DEO3[:, iwl] = (
|
|
834
|
+
(S.absolute(TOx) ** 2 + S.absolute(TOy) ** 2 + S.absolute(TOz) ** 2)
|
|
835
|
+
* S.conj(kO3i[2, :])
|
|
836
|
+
- (TOx * kO3i[0, :] + TOy * kO3i[1, :] + TOz * kO3i[2, :]) * S.conj(TOz)
|
|
837
|
+
).real / denom
|
|
838
|
+
DEE3[:, iwl] = (
|
|
839
|
+
(S.absolute(TEx) ** 2 + S.absolute(TEy) ** 2 + S.absolute(TEz) ** 2)
|
|
840
|
+
* S.conj(kE3i[2, :])
|
|
841
|
+
- (TEx * kE3i[0, :] + TEy * kE3i[1, :] + TEz * kE3i[2, :]) * S.conj(TEz)
|
|
842
|
+
).real / denom
|
|
759
843
|
|
|
760
844
|
# save the results
|
|
761
845
|
self.DEO1 = DEO1
|
|
@@ -779,11 +863,15 @@ class AnisotropicRCWA(RCWA):
|
|
|
779
863
|
# raw_input('press enter to close the graph...')
|
|
780
864
|
|
|
781
865
|
def __str__(self):
|
|
782
|
-
return
|
|
783
|
-
|
|
866
|
+
return (
|
|
867
|
+
"ANISOTROPIC RCWA SOLVER\n\n%s\n\nLAMBDA = %g\nalpha = %g\ndelta = %g\npsi = %g\nphi = %g\nn = %d"
|
|
868
|
+
% (
|
|
869
|
+
self.multilayer.__str__(),
|
|
784
870
|
self.LAMBDA,
|
|
785
871
|
self.alpha,
|
|
786
872
|
self.delta,
|
|
787
873
|
self.psi,
|
|
788
874
|
self.phi,
|
|
789
|
-
self.n
|
|
875
|
+
self.n,
|
|
876
|
+
)
|
|
877
|
+
)
|