ElectroMagneticPython 2.1.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 +885 -0
- EMpy/__init__.py +39 -0
- EMpy/constants.py +25 -0
- EMpy/devices.py +1414 -0
- EMpy/materials.py +371 -0
- EMpy/modesolvers/FD.py +2536 -0
- EMpy/modesolvers/FMM.py +2422 -0
- EMpy/modesolvers/__init__.py +13 -0
- EMpy/modesolvers/geometries.py +231 -0
- EMpy/modesolvers/interface.py +71 -0
- EMpy/scattering.py +236 -0
- EMpy/transfer_matrix.py +423 -0
- EMpy/utils.py +1342 -0
- EMpy/version.py +1 -0
- ElectroMagneticPython-2.1.4.dist-info/LICENSE +21 -0
- ElectroMagneticPython-2.1.4.dist-info/METADATA +95 -0
- ElectroMagneticPython-2.1.4.dist-info/RECORD +22 -0
- ElectroMagneticPython-2.1.4.dist-info/WHEEL +5 -0
- ElectroMagneticPython-2.1.4.dist-info/top_level.txt +2 -0
- tests/__init__.py +1 -0
- tests/materials_test.py +60 -0
- tests/utils_test.py +23 -0
EMpy/RCWA.py
ADDED
|
@@ -0,0 +1,885 @@
|
|
|
1
|
+
"""Rigorous Coupled Wave Analysis.
|
|
2
|
+
|
|
3
|
+
The algorithm, described in Glytsis, "Three-dimensional (vector)
|
|
4
|
+
rigorous coupled-wave analysis of anisotropic grating diffraction",
|
|
5
|
+
JOSA A, 7(8), 1990, permits to find the diffraction efficiencies
|
|
6
|
+
(i.e. the power normalized to unity) reflected and transmitted by a
|
|
7
|
+
multilayer.
|
|
8
|
+
The multilayer can be made of isotropic or anisotropic layers and
|
|
9
|
+
binary gratings.
|
|
10
|
+
Two versions of the algorithm are present: an isotropic one, stable
|
|
11
|
+
for every diffraction order and layer thickness, and an anisotropic
|
|
12
|
+
one, only stable for low diffraction orders and thin layers.
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
__author__ = "Lorenzo Bolla"
|
|
16
|
+
|
|
17
|
+
import scipy as S
|
|
18
|
+
from scipy.linalg import toeplitz, inv, eig, solve as linsolve
|
|
19
|
+
from numpy import pi
|
|
20
|
+
|
|
21
|
+
from EMpy.utils import (
|
|
22
|
+
cond,
|
|
23
|
+
warning,
|
|
24
|
+
BinaryGrating,
|
|
25
|
+
SymmetricDoubleGrating,
|
|
26
|
+
AsymmetricDoubleGrating,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def dispersion_relation_ordinary(kx, ky, k, nO):
|
|
31
|
+
"""Dispersion relation for the ordinary wave.
|
|
32
|
+
|
|
33
|
+
NOTE
|
|
34
|
+
See eq. 15 in Glytsis, "Three-dimensional (vector) rigorous
|
|
35
|
+
coupled-wave analysis of anisotropic grating diffraction",
|
|
36
|
+
JOSA A, 7(8), 1990 Always give positive real or negative
|
|
37
|
+
imaginary.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
if kx.shape != ky.shape:
|
|
41
|
+
raise ValueError("kx and ky must have the same length")
|
|
42
|
+
|
|
43
|
+
delta = (k * nO) ** 2 - (kx**2 + ky**2)
|
|
44
|
+
kz = S.sqrt(delta)
|
|
45
|
+
|
|
46
|
+
# Adjust sign of real/imag part
|
|
47
|
+
kz.real = abs(kz.real)
|
|
48
|
+
kz.imag = -abs(kz.imag)
|
|
49
|
+
|
|
50
|
+
return kz
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def dispersion_relation_extraordinary(kx, ky, k, nO, nE, c):
|
|
54
|
+
"""Dispersion relation for the extraordinary wave.
|
|
55
|
+
|
|
56
|
+
NOTE
|
|
57
|
+
See eq. 16 in Glytsis, "Three-dimensional (vector) rigorous
|
|
58
|
+
coupled-wave analysis of anisotropic grating diffraction",
|
|
59
|
+
JOSA A, 7(8), 1990 Always give positive real or negative
|
|
60
|
+
imaginary.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
if kx.shape != ky.shape or c.size != 3:
|
|
64
|
+
raise ValueError(
|
|
65
|
+
"kx and ky must have the same length and c must have 3 components"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
kz = S.empty_like(kx)
|
|
69
|
+
|
|
70
|
+
for ii in range(0, kx.size):
|
|
71
|
+
|
|
72
|
+
alpha = nE**2 - nO**2
|
|
73
|
+
beta = kx[ii] / k * c[0] + ky[ii] / k * c[1]
|
|
74
|
+
|
|
75
|
+
# coeffs
|
|
76
|
+
C = S.array(
|
|
77
|
+
[
|
|
78
|
+
nO**2 + c[2] ** 2 * alpha,
|
|
79
|
+
2.0 * c[2] * beta * alpha,
|
|
80
|
+
nO**2 * (kx[ii] ** 2 + ky[ii] ** 2) / k**2
|
|
81
|
+
+ alpha * beta**2
|
|
82
|
+
- nO**2 * nE**2,
|
|
83
|
+
]
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# two solutions of type +x or -x, purely real or purely imag
|
|
87
|
+
tmp_kz = k * S.roots(C)
|
|
88
|
+
|
|
89
|
+
# get the negative imaginary part or the positive real one
|
|
90
|
+
if S.any(S.isreal(tmp_kz)):
|
|
91
|
+
kz[ii] = S.absolute(tmp_kz[0])
|
|
92
|
+
else:
|
|
93
|
+
kz[ii] = -1j * S.absolute(tmp_kz[0])
|
|
94
|
+
|
|
95
|
+
return kz
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class RCWA:
|
|
99
|
+
|
|
100
|
+
"""Class to handle the RCWA solvers.
|
|
101
|
+
|
|
102
|
+
NOTE
|
|
103
|
+
See Glytsis, "Three-dimensional (vector) rigorous coupled-wave
|
|
104
|
+
analysis of anisotropic grating diffraction", JOSA A, 7(8), 1990
|
|
105
|
+
|
|
106
|
+
The following variables, used throughout the code, have the following
|
|
107
|
+
meaning:
|
|
108
|
+
|
|
109
|
+
alpha: float
|
|
110
|
+
angle between wave vector k1 and xy plane, in radians
|
|
111
|
+
|
|
112
|
+
delta: float
|
|
113
|
+
angle between the y axis and the projection of k1 onto the xy
|
|
114
|
+
plane, in radians
|
|
115
|
+
|
|
116
|
+
psi: angle between the D vector of the plane wave and the xy plane,
|
|
117
|
+
in radians, TM: 0, TE: numpy.pi / 2
|
|
118
|
+
|
|
119
|
+
phi: angle between the grating vector K and y axis (in the xy plane),
|
|
120
|
+
in radians, the grating is modulated in the direction of the
|
|
121
|
+
grating vector.
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def __init__(self, multilayer, alpha, delta, psi, phi, n):
|
|
126
|
+
"""Set the multilayer, the angles of incidence and the diffraction order.
|
|
127
|
+
|
|
128
|
+
INPUT
|
|
129
|
+
multilayer = Multilayer obj describing the sequence of layers.
|
|
130
|
+
alpha, delta, psi, phi = angles of the incident wave (in
|
|
131
|
+
radiant).
|
|
132
|
+
n = orders of diffractions to retain in the computation.
|
|
133
|
+
"""
|
|
134
|
+
self.setMultilayer(multilayer)
|
|
135
|
+
self.LAMBDA = self.get_pitch()
|
|
136
|
+
self.alpha = alpha
|
|
137
|
+
self.delta = delta
|
|
138
|
+
self.psi = psi
|
|
139
|
+
self.phi = phi
|
|
140
|
+
self.n = n
|
|
141
|
+
|
|
142
|
+
def setMultilayer(self, m):
|
|
143
|
+
"""Set the multilayer, simplifying it first."""
|
|
144
|
+
self.multilayer = m.simplify()
|
|
145
|
+
|
|
146
|
+
def get_pitch(self):
|
|
147
|
+
"""Inspect the multilayer to check that all the binary
|
|
148
|
+
gratings present have the same pitch, and return it."""
|
|
149
|
+
idx = S.where(
|
|
150
|
+
[
|
|
151
|
+
(
|
|
152
|
+
isinstance(m, BinaryGrating)
|
|
153
|
+
| isinstance(m, SymmetricDoubleGrating)
|
|
154
|
+
| isinstance(m, AsymmetricDoubleGrating)
|
|
155
|
+
)
|
|
156
|
+
for m in self.multilayer
|
|
157
|
+
]
|
|
158
|
+
)[0]
|
|
159
|
+
if idx.size == 0:
|
|
160
|
+
# warning('no BinaryGratings: better use a simple transfer matrix.')
|
|
161
|
+
return 1.0 # return LAMBDA: any value will do
|
|
162
|
+
else:
|
|
163
|
+
# check that all the pitches are the same!
|
|
164
|
+
l = S.asarray([self.multilayer[i].pitch for i in idx])
|
|
165
|
+
if not S.all(l == l[0]):
|
|
166
|
+
raise ValueError("All the BinaryGratings must have the same pitch.")
|
|
167
|
+
else:
|
|
168
|
+
return l[0]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class IsotropicRCWA(RCWA):
|
|
172
|
+
|
|
173
|
+
"""Isotropic RCWA solver."""
|
|
174
|
+
|
|
175
|
+
def solve(self, wls):
|
|
176
|
+
"""Isotropic solver.
|
|
177
|
+
|
|
178
|
+
INPUT
|
|
179
|
+
wls = wavelengths to scan (any asarray-able object).
|
|
180
|
+
|
|
181
|
+
OUTPUT
|
|
182
|
+
self.DE1, self.DE3 = power reflected and transmitted.
|
|
183
|
+
|
|
184
|
+
NOTE
|
|
185
|
+
see:
|
|
186
|
+
Moharam, "Formulation for stable and efficient implementation
|
|
187
|
+
of the rigorous coupled-wave analysis of binary gratings",
|
|
188
|
+
JOSA A, 12(5), 1995
|
|
189
|
+
Lalanne, "Highly improved convergence of the coupled-wave
|
|
190
|
+
method for TM polarization", JOSA A, 13(4), 1996
|
|
191
|
+
Moharam, "Stable implementation of the rigorous coupled-wave
|
|
192
|
+
analysis for surface-relief gratings: enhanced trasmittance
|
|
193
|
+
matrix approach", JOSA A, 12(5), 1995
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
self.wls = S.atleast_1d(wls)
|
|
197
|
+
|
|
198
|
+
LAMBDA = self.LAMBDA
|
|
199
|
+
n = self.n
|
|
200
|
+
multilayer = self.multilayer
|
|
201
|
+
alpha = self.alpha
|
|
202
|
+
delta = self.delta
|
|
203
|
+
psi = self.psi
|
|
204
|
+
phi = self.phi
|
|
205
|
+
|
|
206
|
+
nlayers = len(multilayer)
|
|
207
|
+
i = S.arange(-n, n + 1)
|
|
208
|
+
nood = 2 * n + 1
|
|
209
|
+
hmax = nood - 1
|
|
210
|
+
|
|
211
|
+
# grating vector (on the xz plane)
|
|
212
|
+
# grating on the xy plane
|
|
213
|
+
K = 2 * pi / LAMBDA * S.array([S.sin(phi), 0.0, S.cos(phi)], dtype=complex)
|
|
214
|
+
|
|
215
|
+
DE1 = S.zeros((nood, self.wls.size))
|
|
216
|
+
DE3 = S.zeros_like(DE1)
|
|
217
|
+
|
|
218
|
+
dirk1 = S.array(
|
|
219
|
+
[S.sin(alpha) * S.cos(delta), S.sin(alpha) * S.sin(delta), S.cos(alpha)]
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# usefull matrices
|
|
223
|
+
I = S.eye(i.size)
|
|
224
|
+
I2 = S.eye(i.size * 2)
|
|
225
|
+
ZERO = S.zeros_like(I)
|
|
226
|
+
|
|
227
|
+
X = S.zeros((2 * nood, 2 * nood, nlayers), dtype=complex)
|
|
228
|
+
MTp1 = S.zeros((2 * nood, 2 * nood, nlayers), dtype=complex)
|
|
229
|
+
MTp2 = S.zeros_like(MTp1)
|
|
230
|
+
|
|
231
|
+
EPS2 = S.zeros(2 * hmax + 1, dtype=complex)
|
|
232
|
+
EPS21 = S.zeros_like(EPS2)
|
|
233
|
+
|
|
234
|
+
dlt = (i == 0).astype(int)
|
|
235
|
+
|
|
236
|
+
for iwl, wl in enumerate(self.wls):
|
|
237
|
+
|
|
238
|
+
# free space wavevector
|
|
239
|
+
k = 2 * pi / wl
|
|
240
|
+
|
|
241
|
+
n1 = multilayer[0].mat.n(wl).item()
|
|
242
|
+
n3 = multilayer[-1].mat.n(wl).item()
|
|
243
|
+
|
|
244
|
+
# incident plane wave wavevector
|
|
245
|
+
k1 = k * n1 * dirk1
|
|
246
|
+
|
|
247
|
+
# all the other wavevectors
|
|
248
|
+
tmp_x = k1[0] - i * K[0]
|
|
249
|
+
tmp_y = k1[1] * S.ones_like(i)
|
|
250
|
+
tmp_z = dispersion_relation_ordinary(tmp_x, tmp_y, k, n1)
|
|
251
|
+
k1i = S.r_[[tmp_x], [tmp_y], [tmp_z]]
|
|
252
|
+
|
|
253
|
+
# k2i = S.r_[[k1[0] - i*K[0]], [k1[1] - i * K[1]], [-i * K[2]]]
|
|
254
|
+
|
|
255
|
+
tmp_z = dispersion_relation_ordinary(tmp_x, tmp_y, k, n3)
|
|
256
|
+
k3i = S.r_[[k1i[0, :]], [k1i[1, :]], [tmp_z]]
|
|
257
|
+
|
|
258
|
+
# aliases for constant wavevectors
|
|
259
|
+
kx = k1i[0, :]
|
|
260
|
+
ky = k1[1]
|
|
261
|
+
|
|
262
|
+
# angles of reflection
|
|
263
|
+
# phi_i = S.arctan2(ky,kx)
|
|
264
|
+
phi_i = S.arctan2(ky, kx.real) # OKKIO
|
|
265
|
+
|
|
266
|
+
Kx = S.diag(kx / k)
|
|
267
|
+
Ky = ky / k * I
|
|
268
|
+
Z1 = S.diag(k1i[2, :] / (k * n1**2))
|
|
269
|
+
Y1 = S.diag(k1i[2, :] / k)
|
|
270
|
+
Z3 = S.diag(k3i[2, :] / (k * n3**2))
|
|
271
|
+
Y3 = S.diag(k3i[2, :] / k)
|
|
272
|
+
# Fc = S.diag(S.cos(phi_i))
|
|
273
|
+
fc = S.cos(phi_i)
|
|
274
|
+
# Fs = S.diag(S.sin(phi_i))
|
|
275
|
+
fs = S.sin(phi_i)
|
|
276
|
+
|
|
277
|
+
MR = S.asarray(
|
|
278
|
+
S.bmat([[I, ZERO], [-1j * Y1, ZERO], [ZERO, I], [ZERO, -1j * Z1]])
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
MT = S.asarray(
|
|
282
|
+
S.bmat([[I, ZERO], [1j * Y3, ZERO], [ZERO, I], [ZERO, 1j * Z3]])
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# internal layers (grating or layer)
|
|
286
|
+
X.fill(0.0)
|
|
287
|
+
MTp1.fill(0.0)
|
|
288
|
+
MTp2.fill(0.0)
|
|
289
|
+
for nlayer in range(nlayers - 2, 0, -1): # internal layers
|
|
290
|
+
|
|
291
|
+
layer = multilayer[nlayer]
|
|
292
|
+
d = layer.thickness
|
|
293
|
+
|
|
294
|
+
EPS2, EPS21 = layer.getEPSFourierCoeffs(wl, n, anisotropic=False)
|
|
295
|
+
|
|
296
|
+
E = toeplitz(EPS2[hmax::-1], EPS2[hmax:])
|
|
297
|
+
E1 = toeplitz(EPS21[hmax::-1], EPS21[hmax:])
|
|
298
|
+
E11 = inv(E1)
|
|
299
|
+
# B = S.dot(Kx, linsolve(E,Kx)) - I
|
|
300
|
+
B = kx[:, S.newaxis] / k * linsolve(E, Kx) - I
|
|
301
|
+
# A = S.dot(Kx, Kx) - E
|
|
302
|
+
A = S.diag((kx / k) ** 2) - E
|
|
303
|
+
|
|
304
|
+
# Note: solution bug alfredo
|
|
305
|
+
# randomizzo Kx un po' a caso finche' cond(A) e' piccolo (<1e10)
|
|
306
|
+
# soluzione sporca... :-(
|
|
307
|
+
# per certi kx, l'operatore di helmholtz ha 2 autovalori nulli e A, B
|
|
308
|
+
# non sono invertibili --> cambio leggermente i kx... ma dovrei invece
|
|
309
|
+
# trattare separatamente (analiticamente) questi casi
|
|
310
|
+
if cond(A) > 1e10:
|
|
311
|
+
warning("BAD CONDITIONING: randomization of kx")
|
|
312
|
+
while cond(A) > 1e10:
|
|
313
|
+
Kx = Kx * (1 + 1e-9 * S.rand())
|
|
314
|
+
B = kx[:, S.newaxis] / k * linsolve(E, Kx) - I
|
|
315
|
+
A = S.diag((kx / k) ** 2) - E
|
|
316
|
+
|
|
317
|
+
if S.absolute(K[2] / k) > 1e-10:
|
|
318
|
+
|
|
319
|
+
raise ValueError(
|
|
320
|
+
"First Order Helmholtz Operator not implemented, yet!"
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
elif ky == 0 or S.allclose(S.diag(Ky / ky * k), 1):
|
|
324
|
+
|
|
325
|
+
# lalanne
|
|
326
|
+
# H_U_reduced = S.dot(Ky, Ky) + A
|
|
327
|
+
H_U_reduced = (ky / k) ** 2 * I + A
|
|
328
|
+
# H_S_reduced = S.dot(Ky, Ky) + S.dot(Kx, linsolve(E, S.dot(Kx, E11))) - E11
|
|
329
|
+
H_S_reduced = (
|
|
330
|
+
(ky / k) ** 2 * I
|
|
331
|
+
+ kx[:, S.newaxis] / k * linsolve(E, kx[:, S.newaxis] / k * E11)
|
|
332
|
+
- E11
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
q1, W1 = eig(H_U_reduced)
|
|
336
|
+
q1 = S.sqrt(q1)
|
|
337
|
+
q2, W2 = eig(H_S_reduced)
|
|
338
|
+
q2 = S.sqrt(q2)
|
|
339
|
+
|
|
340
|
+
# boundary conditions
|
|
341
|
+
|
|
342
|
+
# V11 = S.dot(linsolve(A, W1), S.diag(q1))
|
|
343
|
+
V11 = linsolve(A, W1) * q1[S.newaxis, :]
|
|
344
|
+
V12 = (ky / k) * S.dot(linsolve(A, Kx), W2)
|
|
345
|
+
V21 = (ky / k) * S.dot(linsolve(B, Kx), linsolve(E, W1))
|
|
346
|
+
# V22 = S.dot(linsolve(B, W2), S.diag(q2))
|
|
347
|
+
V22 = linsolve(B, W2) * q2[S.newaxis, :]
|
|
348
|
+
|
|
349
|
+
# Vss = S.dot(Fc, V11)
|
|
350
|
+
Vss = fc[:, S.newaxis] * V11
|
|
351
|
+
# Wss = S.dot(Fc, W1) + S.dot(Fs, V21)
|
|
352
|
+
Wss = fc[:, S.newaxis] * W1 + fs[:, S.newaxis] * V21
|
|
353
|
+
# Vsp = S.dot(Fc, V12) - S.dot(Fs, W2)
|
|
354
|
+
Vsp = fc[:, S.newaxis] * V12 - fs[:, S.newaxis] * W2
|
|
355
|
+
# Wsp = S.dot(Fs, V22)
|
|
356
|
+
Wsp = fs[:, S.newaxis] * V22
|
|
357
|
+
# Wpp = S.dot(Fc, V22)
|
|
358
|
+
Wpp = fc[:, S.newaxis] * V22
|
|
359
|
+
# Vpp = S.dot(Fc, W2) + S.dot(Fs, V12)
|
|
360
|
+
Vpp = fc[:, S.newaxis] * W2 + fs[:, S.newaxis] * V12
|
|
361
|
+
# Wps = S.dot(Fc, V21) - S.dot(Fs, W1)
|
|
362
|
+
Wps = fc[:, S.newaxis] * V21 - fs[:, S.newaxis] * W1
|
|
363
|
+
# Vps = S.dot(Fs, V11)
|
|
364
|
+
Vps = fs[:, S.newaxis] * V11
|
|
365
|
+
|
|
366
|
+
Mc2bar = S.asarray(
|
|
367
|
+
S.bmat(
|
|
368
|
+
[
|
|
369
|
+
[Vss, Vsp, Vss, Vsp],
|
|
370
|
+
[Wss, Wsp, -Wss, -Wsp],
|
|
371
|
+
[Wps, Wpp, -Wps, -Wpp],
|
|
372
|
+
[Vps, Vpp, Vps, Vpp],
|
|
373
|
+
]
|
|
374
|
+
)
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
x = S.r_[S.exp(-k * q1 * d), S.exp(-k * q2 * d)]
|
|
378
|
+
|
|
379
|
+
# Mc1 = S.dot(Mc2bar, S.diag(S.r_[S.ones_like(x), x]))
|
|
380
|
+
xx = S.r_[S.ones_like(x), x]
|
|
381
|
+
Mc1 = Mc2bar * xx[S.newaxis, :]
|
|
382
|
+
|
|
383
|
+
X[:, :, nlayer] = S.diag(x)
|
|
384
|
+
|
|
385
|
+
MTp = linsolve(Mc2bar, MT)
|
|
386
|
+
MTp1[:, :, nlayer] = MTp[0 : 2 * nood, :]
|
|
387
|
+
MTp2 = MTp[2 * nood :, :]
|
|
388
|
+
|
|
389
|
+
MT = S.dot(
|
|
390
|
+
Mc1,
|
|
391
|
+
S.r_[
|
|
392
|
+
I2,
|
|
393
|
+
S.dot(MTp2, linsolve(MTp1[:, :, nlayer], X[:, :, nlayer])),
|
|
394
|
+
],
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
else:
|
|
398
|
+
|
|
399
|
+
ValueError("Second Order Helmholtz Operator not implemented, yet!")
|
|
400
|
+
|
|
401
|
+
# M = S.asarray(S.bmat([-MR, MT]))
|
|
402
|
+
M = S.c_[-MR, MT]
|
|
403
|
+
b = S.r_[
|
|
404
|
+
S.sin(psi) * dlt,
|
|
405
|
+
1j * S.sin(psi) * n1 * S.cos(alpha) * dlt,
|
|
406
|
+
-1j * S.cos(psi) * n1 * dlt,
|
|
407
|
+
S.cos(psi) * S.cos(alpha) * dlt,
|
|
408
|
+
]
|
|
409
|
+
|
|
410
|
+
x = linsolve(M, b)
|
|
411
|
+
R, T = S.split(x, 2)
|
|
412
|
+
Rs, Rp = S.split(R, 2)
|
|
413
|
+
for ii in range(1, nlayers - 1):
|
|
414
|
+
T = S.dot(linsolve(MTp1[:, :, ii], X[:, :, ii]), T)
|
|
415
|
+
Ts, Tp = S.split(T, 2)
|
|
416
|
+
|
|
417
|
+
DE1[:, iwl] = (k1i[2, :] / (k1[2])).real * S.absolute(Rs) ** 2 + (
|
|
418
|
+
k1i[2, :] / (k1[2] * n1**2)
|
|
419
|
+
).real * S.absolute(Rp) ** 2
|
|
420
|
+
DE3[:, iwl] = (k3i[2, :] / (k1[2])).real * S.absolute(Ts) ** 2 + (
|
|
421
|
+
k3i[2, :] / (k1[2] * n3**2)
|
|
422
|
+
).real * S.absolute(Tp) ** 2
|
|
423
|
+
|
|
424
|
+
# save the results
|
|
425
|
+
self.DE1 = DE1
|
|
426
|
+
self.DE3 = DE3
|
|
427
|
+
|
|
428
|
+
return self
|
|
429
|
+
|
|
430
|
+
# def plot(self):
|
|
431
|
+
# """Plot the diffraction efficiencies."""
|
|
432
|
+
# g = Gnuplot.Gnuplot()
|
|
433
|
+
# g('set xlabel "$\lambda$"')
|
|
434
|
+
# g('set ylabel "diffraction efficiency"')
|
|
435
|
+
# g('set yrange [0:1]')
|
|
436
|
+
# g('set data style linespoints')
|
|
437
|
+
# g.plot(Gnuplot.Data(self.wls, self.DE1[self.n,:], with_ = 'linespoints', title = 'DE1'), \
|
|
438
|
+
# Gnuplot.Data(self.wls, self.DE3[self.n,:], with_ = 'linespoints', title = 'DE3'))
|
|
439
|
+
# raw_input('press enter to close the graph...')
|
|
440
|
+
|
|
441
|
+
def __str__(self):
|
|
442
|
+
return (
|
|
443
|
+
"ISOTROPIC RCWA SOLVER\n\n%s\n\nLAMBDA = %g\nalpha = %g\ndelta = %g\npsi = %g\nphi = %g\nn = %d"
|
|
444
|
+
% (
|
|
445
|
+
self.multilayer.__str__(),
|
|
446
|
+
self.LAMBDA,
|
|
447
|
+
self.alpha,
|
|
448
|
+
self.delta,
|
|
449
|
+
self.psi,
|
|
450
|
+
self.phi,
|
|
451
|
+
self.n,
|
|
452
|
+
)
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
class AnisotropicRCWA(RCWA):
|
|
457
|
+
|
|
458
|
+
"""Anisotropic RCWA solver."""
|
|
459
|
+
|
|
460
|
+
def solve(self, wls):
|
|
461
|
+
"""Anisotropic solver.
|
|
462
|
+
|
|
463
|
+
INPUT
|
|
464
|
+
wls = wavelengths to scan (any asarray-able object).
|
|
465
|
+
|
|
466
|
+
OUTPUT
|
|
467
|
+
self.DEO1, self.DEE1, self.DEO3, self.DEE3 = power reflected
|
|
468
|
+
and transmitted.
|
|
469
|
+
"""
|
|
470
|
+
|
|
471
|
+
self.wls = S.atleast_1d(wls)
|
|
472
|
+
|
|
473
|
+
LAMBDA = self.LAMBDA
|
|
474
|
+
n = self.n
|
|
475
|
+
multilayer = self.multilayer
|
|
476
|
+
alpha = self.alpha
|
|
477
|
+
delta = self.delta
|
|
478
|
+
psi = self.psi
|
|
479
|
+
phi = self.phi
|
|
480
|
+
|
|
481
|
+
nlayers = len(multilayer)
|
|
482
|
+
i = S.arange(-n, n + 1)
|
|
483
|
+
nood = 2 * n + 1
|
|
484
|
+
hmax = nood - 1
|
|
485
|
+
|
|
486
|
+
DEO1 = S.zeros((nood, self.wls.size))
|
|
487
|
+
DEO3 = S.zeros_like(DEO1)
|
|
488
|
+
DEE1 = S.zeros_like(DEO1)
|
|
489
|
+
DEE3 = S.zeros_like(DEO1)
|
|
490
|
+
|
|
491
|
+
c1 = S.array([1.0, 0.0, 0.0])
|
|
492
|
+
c3 = S.array([1.0, 0.0, 0.0])
|
|
493
|
+
# grating on the xy plane
|
|
494
|
+
K = 2 * pi / LAMBDA * S.array([S.sin(phi), 0.0, S.cos(phi)], dtype=complex)
|
|
495
|
+
dirk1 = S.array(
|
|
496
|
+
[S.sin(alpha) * S.cos(delta), S.sin(alpha) * S.sin(delta), S.cos(alpha)]
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
# D polarization vector
|
|
500
|
+
u = S.array(
|
|
501
|
+
[
|
|
502
|
+
S.cos(psi) * S.cos(alpha) * S.cos(delta) - S.sin(psi) * S.sin(delta),
|
|
503
|
+
S.cos(psi) * S.cos(alpha) * S.sin(delta) + S.sin(psi) * S.cos(delta),
|
|
504
|
+
-S.cos(psi) * S.sin(alpha),
|
|
505
|
+
]
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
kO1i = S.zeros((3, i.size), dtype=complex)
|
|
509
|
+
kE1i = S.zeros_like(kO1i)
|
|
510
|
+
kO3i = S.zeros_like(kO1i)
|
|
511
|
+
kE3i = S.zeros_like(kO1i)
|
|
512
|
+
|
|
513
|
+
Mp = S.zeros((4 * nood, 4 * nood, nlayers), dtype=complex)
|
|
514
|
+
M = S.zeros((4 * nood, 4 * nood, nlayers), dtype=complex)
|
|
515
|
+
|
|
516
|
+
dlt = (i == 0).astype(int)
|
|
517
|
+
|
|
518
|
+
for iwl, wl in enumerate(self.wls):
|
|
519
|
+
|
|
520
|
+
nO1 = nE1 = multilayer[0].mat.n(wl).item()
|
|
521
|
+
nO3 = nE3 = multilayer[-1].mat.n(wl).item()
|
|
522
|
+
|
|
523
|
+
# wavevectors
|
|
524
|
+
k = 2 * pi / wl
|
|
525
|
+
|
|
526
|
+
eps1 = S.diag(S.asarray([nE1, nO1, nO1]) ** 2)
|
|
527
|
+
eps3 = S.diag(S.asarray([nE3, nO3, nO3]) ** 2)
|
|
528
|
+
|
|
529
|
+
# ordinary wave
|
|
530
|
+
abskO1 = k * nO1
|
|
531
|
+
# abskO3 = k * nO3
|
|
532
|
+
# extraordinary wave
|
|
533
|
+
# abskE1 = k * nO1 *nE1 / S.sqrt(nO1**2 + (nE1**2 - nO1**2) * S.dot(-c1, dirk1)**2)
|
|
534
|
+
# abskE3 = k * nO3 *nE3 / S.sqrt(nO3**2 + (nE3**2 - nO3**2) * S.dot(-c3, dirk1)**2)
|
|
535
|
+
|
|
536
|
+
k1 = abskO1 * dirk1
|
|
537
|
+
|
|
538
|
+
kO1i[0, :] = k1[0] - i * K[0]
|
|
539
|
+
kO1i[1, :] = k1[1] * S.ones_like(i)
|
|
540
|
+
kO1i[2, :] = -dispersion_relation_ordinary(kO1i[0, :], kO1i[1, :], k, nO1)
|
|
541
|
+
|
|
542
|
+
kE1i[0, :] = kO1i[0, :]
|
|
543
|
+
kE1i[1, :] = kO1i[1, :]
|
|
544
|
+
kE1i[2, :] = -dispersion_relation_extraordinary(
|
|
545
|
+
kE1i[0, :], kE1i[1, :], k, nO1, nE1, c1
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
kO3i[0, :] = kO1i[0, :]
|
|
549
|
+
kO3i[1, :] = kO1i[1, :]
|
|
550
|
+
kO3i[2, :] = dispersion_relation_ordinary(kO3i[0, :], kO3i[1, :], k, nO3)
|
|
551
|
+
|
|
552
|
+
kE3i[0, :] = kO1i[0, :]
|
|
553
|
+
kE3i[1, :] = kO1i[1, :]
|
|
554
|
+
kE3i[2, :] = dispersion_relation_extraordinary(
|
|
555
|
+
kE3i[0, :], kE3i[1, :], k, nO3, nE3, c3
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
# k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [k1[2] - i * K[2]]]
|
|
559
|
+
k2i = S.r_[[k1[0] - i * K[0]], [k1[1] - i * K[1]], [-i * K[2]]]
|
|
560
|
+
|
|
561
|
+
# aliases for constant wavevectors
|
|
562
|
+
kx = kO1i[0, :] # o kE1i(1,;), tanto e' lo stesso
|
|
563
|
+
ky = k1[1]
|
|
564
|
+
|
|
565
|
+
# matrices
|
|
566
|
+
I = S.eye(nood, dtype=complex)
|
|
567
|
+
ZERO = S.zeros((nood, nood), dtype=complex)
|
|
568
|
+
Kx = S.diag(kx / k)
|
|
569
|
+
Ky = ky / k * I
|
|
570
|
+
Kz = S.diag(k2i[2, :] / k)
|
|
571
|
+
KO1z = S.diag(kO1i[2, :] / k)
|
|
572
|
+
KE1z = S.diag(kE1i[2, :] / k)
|
|
573
|
+
KO3z = S.diag(kO3i[2, :] / k)
|
|
574
|
+
KE3z = S.diag(kE3i[2, :] / k)
|
|
575
|
+
|
|
576
|
+
ARO = Kx * eps1[0, 0] + Ky * eps1[1, 0] + KO1z * eps1[2, 0]
|
|
577
|
+
BRO = Kx * eps1[0, 1] + Ky * eps1[1, 1] + KO1z * eps1[2, 1]
|
|
578
|
+
CRO_1 = inv(Kx * eps1[0, 2] + Ky * eps1[1, 2] + KO1z * eps1[2, 2])
|
|
579
|
+
|
|
580
|
+
ARE = Kx * eps1[0, 0] + Ky * eps1[1, 0] + KE1z * eps1[2, 0]
|
|
581
|
+
BRE = Kx * eps1[0, 1] + Ky * eps1[1, 1] + KE1z * eps1[2, 1]
|
|
582
|
+
CRE_1 = inv(Kx * eps1[0, 2] + Ky * eps1[1, 2] + KE1z * eps1[2, 2])
|
|
583
|
+
|
|
584
|
+
ATO = Kx * eps3[0, 0] + Ky * eps3[1, 0] + KO3z * eps3[2, 0]
|
|
585
|
+
BTO = Kx * eps3[0, 1] + Ky * eps3[1, 1] + KO3z * eps3[2, 1]
|
|
586
|
+
CTO_1 = inv(Kx * eps3[0, 2] + Ky * eps3[1, 2] + KO3z * eps3[2, 2])
|
|
587
|
+
|
|
588
|
+
ATE = Kx * eps3[0, 0] + Ky * eps3[1, 0] + KE3z * eps3[2, 0]
|
|
589
|
+
BTE = Kx * eps3[0, 1] + Ky * eps3[1, 1] + KE3z * eps3[2, 1]
|
|
590
|
+
CTE_1 = inv(Kx * eps3[0, 2] + Ky * eps3[1, 2] + KE3z * eps3[2, 2])
|
|
591
|
+
|
|
592
|
+
DRE = c1[1] * KE1z - c1[2] * Ky
|
|
593
|
+
ERE = c1[2] * Kx - c1[0] * KE1z
|
|
594
|
+
FRE = c1[0] * Ky - c1[1] * Kx
|
|
595
|
+
|
|
596
|
+
DTE = c3[1] * KE3z - c3[2] * Ky
|
|
597
|
+
ETE = c3[2] * Kx - c3[0] * KE3z
|
|
598
|
+
FTE = c3[0] * Ky - c3[1] * Kx
|
|
599
|
+
|
|
600
|
+
b = S.r_[
|
|
601
|
+
u[0] * dlt,
|
|
602
|
+
u[1] * dlt,
|
|
603
|
+
(k1[1] / k * u[2] - k1[2] / k * u[1]) * dlt,
|
|
604
|
+
(k1[2] / k * u[0] - k1[0] / k * u[2]) * dlt,
|
|
605
|
+
]
|
|
606
|
+
Ky_CRO_1 = ky / k * CRO_1
|
|
607
|
+
Ky_CRE_1 = ky / k * CRE_1
|
|
608
|
+
Kx_CRO_1 = kx[:, S.newaxis] / k * CRO_1
|
|
609
|
+
Kx_CRE_1 = kx[:, S.newaxis] / k * CRE_1
|
|
610
|
+
MR31 = -S.dot(Ky_CRO_1, ARO)
|
|
611
|
+
MR32 = -S.dot(Ky_CRO_1, BRO) - KO1z
|
|
612
|
+
MR33 = -S.dot(Ky_CRE_1, ARE)
|
|
613
|
+
MR34 = -S.dot(Ky_CRE_1, BRE) - KE1z
|
|
614
|
+
MR41 = S.dot(Kx_CRO_1, ARO) + KO1z
|
|
615
|
+
MR42 = S.dot(Kx_CRO_1, BRO)
|
|
616
|
+
MR43 = S.dot(Kx_CRE_1, ARE) + KE1z
|
|
617
|
+
MR44 = S.dot(Kx_CRE_1, BRE)
|
|
618
|
+
MR = S.asarray(
|
|
619
|
+
S.bmat(
|
|
620
|
+
[
|
|
621
|
+
[I, ZERO, I, ZERO],
|
|
622
|
+
[ZERO, I, ZERO, I],
|
|
623
|
+
[MR31, MR32, MR33, MR34],
|
|
624
|
+
[MR41, MR42, MR43, MR44],
|
|
625
|
+
]
|
|
626
|
+
)
|
|
627
|
+
)
|
|
628
|
+
|
|
629
|
+
Ky_CTO_1 = ky / k * CTO_1
|
|
630
|
+
Ky_CTE_1 = ky / k * CTE_1
|
|
631
|
+
Kx_CTO_1 = kx[:, S.newaxis] / k * CTO_1
|
|
632
|
+
Kx_CTE_1 = kx[:, S.newaxis] / k * CTE_1
|
|
633
|
+
MT31 = -S.dot(Ky_CTO_1, ATO)
|
|
634
|
+
MT32 = -S.dot(Ky_CTO_1, BTO) - KO3z
|
|
635
|
+
MT33 = -S.dot(Ky_CTE_1, ATE)
|
|
636
|
+
MT34 = -S.dot(Ky_CTE_1, BTE) - KE3z
|
|
637
|
+
MT41 = S.dot(Kx_CTO_1, ATO) + KO3z
|
|
638
|
+
MT42 = S.dot(Kx_CTO_1, BTO)
|
|
639
|
+
MT43 = S.dot(Kx_CTE_1, ATE) + KE3z
|
|
640
|
+
MT44 = S.dot(Kx_CTE_1, BTE)
|
|
641
|
+
MT = S.asarray(
|
|
642
|
+
S.bmat(
|
|
643
|
+
[
|
|
644
|
+
[I, ZERO, I, ZERO],
|
|
645
|
+
[ZERO, I, ZERO, I],
|
|
646
|
+
[MT31, MT32, MT33, MT34],
|
|
647
|
+
[MT41, MT42, MT43, MT44],
|
|
648
|
+
]
|
|
649
|
+
)
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
Mp.fill(0.0)
|
|
653
|
+
M.fill(0.0)
|
|
654
|
+
|
|
655
|
+
for nlayer in range(nlayers - 2, 0, -1): # internal layers
|
|
656
|
+
|
|
657
|
+
layer = multilayer[nlayer]
|
|
658
|
+
thickness = layer.thickness
|
|
659
|
+
|
|
660
|
+
EPS2, EPS21 = layer.getEPSFourierCoeffs(wl, n, anisotropic=True)
|
|
661
|
+
|
|
662
|
+
# Exx = S.squeeze(EPS2[0, 0, :])
|
|
663
|
+
# Exx = toeplitz(S.flipud(Exx[0:hmax + 1]), Exx[hmax:])
|
|
664
|
+
Exy = S.squeeze(EPS2[0, 1, :])
|
|
665
|
+
Exy = toeplitz(S.flipud(Exy[0 : hmax + 1]), Exy[hmax:])
|
|
666
|
+
Exz = S.squeeze(EPS2[0, 2, :])
|
|
667
|
+
Exz = toeplitz(S.flipud(Exz[0 : hmax + 1]), Exz[hmax:])
|
|
668
|
+
|
|
669
|
+
Eyx = S.squeeze(EPS2[1, 0, :])
|
|
670
|
+
Eyx = toeplitz(S.flipud(Eyx[0 : hmax + 1]), Eyx[hmax:])
|
|
671
|
+
Eyy = S.squeeze(EPS2[1, 1, :])
|
|
672
|
+
Eyy = toeplitz(S.flipud(Eyy[0 : hmax + 1]), Eyy[hmax:])
|
|
673
|
+
Eyz = S.squeeze(EPS2[1, 2, :])
|
|
674
|
+
Eyz = toeplitz(S.flipud(Eyz[0 : hmax + 1]), Eyz[hmax:])
|
|
675
|
+
|
|
676
|
+
Ezx = S.squeeze(EPS2[2, 0, :])
|
|
677
|
+
Ezx = toeplitz(S.flipud(Ezx[0 : hmax + 1]), Ezx[hmax:])
|
|
678
|
+
Ezy = S.squeeze(EPS2[2, 1, :])
|
|
679
|
+
Ezy = toeplitz(S.flipud(Ezy[0 : hmax + 1]), Ezy[hmax:])
|
|
680
|
+
Ezz = S.squeeze(EPS2[2, 2, :])
|
|
681
|
+
Ezz = toeplitz(S.flipud(Ezz[0 : hmax + 1]), Ezz[hmax:])
|
|
682
|
+
|
|
683
|
+
Exx_1 = S.squeeze(EPS21[0, 0, :])
|
|
684
|
+
Exx_1 = toeplitz(S.flipud(Exx_1[0 : hmax + 1]), Exx_1[hmax:])
|
|
685
|
+
Exx_1_1 = inv(Exx_1)
|
|
686
|
+
|
|
687
|
+
# lalanne
|
|
688
|
+
Ezz_1 = inv(Ezz)
|
|
689
|
+
Ky_Ezz_1 = ky / k * Ezz_1
|
|
690
|
+
Kx_Ezz_1 = kx[:, S.newaxis] / k * Ezz_1
|
|
691
|
+
Exz_Ezz_1 = S.dot(Exz, Ezz_1)
|
|
692
|
+
Eyz_Ezz_1 = S.dot(Eyz, Ezz_1)
|
|
693
|
+
H11 = 1j * S.dot(Ky_Ezz_1, Ezy)
|
|
694
|
+
H12 = 1j * S.dot(Ky_Ezz_1, Ezx)
|
|
695
|
+
H13 = S.dot(Ky_Ezz_1, Kx)
|
|
696
|
+
H14 = I - S.dot(Ky_Ezz_1, Ky)
|
|
697
|
+
H21 = 1j * S.dot(Kx_Ezz_1, Ezy)
|
|
698
|
+
H22 = 1j * S.dot(Kx_Ezz_1, Ezx)
|
|
699
|
+
H23 = S.dot(Kx_Ezz_1, Kx) - I
|
|
700
|
+
H24 = -S.dot(Kx_Ezz_1, Ky)
|
|
701
|
+
H31 = S.dot(Kx, Ky) + Exy - S.dot(Exz_Ezz_1, Ezy)
|
|
702
|
+
H32 = Exx_1_1 - S.dot(Ky, Ky) - S.dot(Exz_Ezz_1, Ezx)
|
|
703
|
+
H33 = 1j * S.dot(Exz_Ezz_1, Kx)
|
|
704
|
+
H34 = -1j * S.dot(Exz_Ezz_1, Ky)
|
|
705
|
+
H41 = S.dot(Kx, Kx) - Eyy + S.dot(Eyz_Ezz_1, Ezy)
|
|
706
|
+
H42 = -S.dot(Kx, Ky) - Eyx + S.dot(Eyz_Ezz_1, Ezx)
|
|
707
|
+
H43 = -1j * S.dot(Eyz_Ezz_1, Kx)
|
|
708
|
+
H44 = 1j * S.dot(Eyz_Ezz_1, Ky)
|
|
709
|
+
H = 1j * S.diag(S.repeat(S.diag(Kz), 4)) + S.asarray(
|
|
710
|
+
S.bmat(
|
|
711
|
+
[
|
|
712
|
+
[H11, H12, H13, H14],
|
|
713
|
+
[H21, H22, H23, H24],
|
|
714
|
+
[H31, H32, H33, H34],
|
|
715
|
+
[H41, H42, H43, H44],
|
|
716
|
+
]
|
|
717
|
+
)
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
q, W = eig(H)
|
|
721
|
+
W1, W2, W3, W4 = S.split(W, 4)
|
|
722
|
+
|
|
723
|
+
#
|
|
724
|
+
# boundary conditions
|
|
725
|
+
#
|
|
726
|
+
# x = [R T]
|
|
727
|
+
# R = [ROx ROy REx REy]
|
|
728
|
+
# T = [TOx TOy TEx TEy]
|
|
729
|
+
# b + MR.R = M1p.c
|
|
730
|
+
# M1.c = M2p.c
|
|
731
|
+
# ...
|
|
732
|
+
# ML.c = MT.T
|
|
733
|
+
# therefore: b + MR.R = (M1p.M1^-1.M2p.M2^-1. ...).MT.T
|
|
734
|
+
# missing equations from (46)..(49) in glytsis_rigorous
|
|
735
|
+
# [b] = [-MR Mtot.MT] [R]
|
|
736
|
+
# [0] [...........] [T]
|
|
737
|
+
|
|
738
|
+
z = S.zeros_like(q)
|
|
739
|
+
z[S.where(q.real > 0)] = -thickness
|
|
740
|
+
D = S.exp(k * q * z)
|
|
741
|
+
Sy0 = W1 * D[S.newaxis, :]
|
|
742
|
+
Sx0 = W2 * D[S.newaxis, :]
|
|
743
|
+
Uy0 = W3 * D[S.newaxis, :]
|
|
744
|
+
Ux0 = W4 * D[S.newaxis, :]
|
|
745
|
+
|
|
746
|
+
z = thickness * S.ones_like(q)
|
|
747
|
+
z[S.where(q.real > 0)] = 0
|
|
748
|
+
D = S.exp(k * q * z)
|
|
749
|
+
D1 = S.exp(-1j * k2i[2, :] * thickness)
|
|
750
|
+
Syd = D1[:, S.newaxis] * W1 * D[S.newaxis, :]
|
|
751
|
+
Sxd = D1[:, S.newaxis] * W2 * D[S.newaxis, :]
|
|
752
|
+
Uyd = D1[:, S.newaxis] * W3 * D[S.newaxis, :]
|
|
753
|
+
Uxd = D1[:, S.newaxis] * W4 * D[S.newaxis, :]
|
|
754
|
+
|
|
755
|
+
Mp[:, :, nlayer] = S.r_[Sx0, Sy0, -1j * Ux0, -1j * Uy0]
|
|
756
|
+
M[:, :, nlayer] = S.r_[Sxd, Syd, -1j * Uxd, -1j * Uyd]
|
|
757
|
+
|
|
758
|
+
Mtot = S.eye(4 * nood, dtype=complex)
|
|
759
|
+
for nlayer in range(1, nlayers - 1):
|
|
760
|
+
Mtot = S.dot(S.dot(Mtot, Mp[:, :, nlayer]), inv(M[:, :, nlayer]))
|
|
761
|
+
|
|
762
|
+
BC_b = S.r_[b, S.zeros_like(b)]
|
|
763
|
+
BC_A1 = S.c_[-MR, S.dot(Mtot, MT)]
|
|
764
|
+
BC_A2 = S.asarray(
|
|
765
|
+
S.bmat(
|
|
766
|
+
[
|
|
767
|
+
[
|
|
768
|
+
(c1[0] * I - c1[2] * S.dot(CRO_1, ARO)),
|
|
769
|
+
(c1[1] * I - c1[2] * S.dot(CRO_1, BRO)),
|
|
770
|
+
ZERO,
|
|
771
|
+
ZERO,
|
|
772
|
+
ZERO,
|
|
773
|
+
ZERO,
|
|
774
|
+
ZERO,
|
|
775
|
+
ZERO,
|
|
776
|
+
],
|
|
777
|
+
[
|
|
778
|
+
ZERO,
|
|
779
|
+
ZERO,
|
|
780
|
+
(DRE - S.dot(S.dot(FRE, CRE_1), ARE)),
|
|
781
|
+
(ERE - S.dot(S.dot(FRE, CRE_1), BRE)),
|
|
782
|
+
ZERO,
|
|
783
|
+
ZERO,
|
|
784
|
+
ZERO,
|
|
785
|
+
ZERO,
|
|
786
|
+
],
|
|
787
|
+
[
|
|
788
|
+
ZERO,
|
|
789
|
+
ZERO,
|
|
790
|
+
ZERO,
|
|
791
|
+
ZERO,
|
|
792
|
+
(c3[0] * I - c3[2] * S.dot(CTO_1, ATO)),
|
|
793
|
+
(c3[1] * I - c3[2] * S.dot(CTO_1, BTO)),
|
|
794
|
+
ZERO,
|
|
795
|
+
ZERO,
|
|
796
|
+
],
|
|
797
|
+
[
|
|
798
|
+
ZERO,
|
|
799
|
+
ZERO,
|
|
800
|
+
ZERO,
|
|
801
|
+
ZERO,
|
|
802
|
+
ZERO,
|
|
803
|
+
ZERO,
|
|
804
|
+
(DTE - S.dot(S.dot(FTE, CTE_1), ATE)),
|
|
805
|
+
(ETE - S.dot(S.dot(FTE, CTE_1), BTE)),
|
|
806
|
+
],
|
|
807
|
+
]
|
|
808
|
+
)
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
BC_A = S.r_[BC_A1, BC_A2]
|
|
812
|
+
|
|
813
|
+
x = linsolve(BC_A, BC_b)
|
|
814
|
+
|
|
815
|
+
ROx, ROy, REx, REy, TOx, TOy, TEx, TEy = S.split(x, 8)
|
|
816
|
+
|
|
817
|
+
ROz = -S.dot(CRO_1, (S.dot(ARO, ROx) + S.dot(BRO, ROy)))
|
|
818
|
+
REz = -S.dot(CRE_1, (S.dot(ARE, REx) + S.dot(BRE, REy)))
|
|
819
|
+
TOz = -S.dot(CTO_1, (S.dot(ATO, TOx) + S.dot(BTO, TOy)))
|
|
820
|
+
TEz = -S.dot(CTE_1, (S.dot(ATE, TEx) + S.dot(BTE, TEy)))
|
|
821
|
+
|
|
822
|
+
denom = (k1[2] - S.dot(u, k1) * u[2]).real
|
|
823
|
+
DEO1[:, iwl] = (
|
|
824
|
+
-(
|
|
825
|
+
(S.absolute(ROx) ** 2 + S.absolute(ROy) ** 2 + S.absolute(ROz) ** 2)
|
|
826
|
+
* S.conj(kO1i[2, :])
|
|
827
|
+
- (ROx * kO1i[0, :] + ROy * kO1i[1, :] + ROz * kO1i[2, :])
|
|
828
|
+
* S.conj(ROz)
|
|
829
|
+
).real
|
|
830
|
+
/ denom
|
|
831
|
+
)
|
|
832
|
+
DEE1[:, iwl] = (
|
|
833
|
+
-(
|
|
834
|
+
(S.absolute(REx) ** 2 + S.absolute(REy) ** 2 + S.absolute(REz) ** 2)
|
|
835
|
+
* S.conj(kE1i[2, :])
|
|
836
|
+
- (REx * kE1i[0, :] + REy * kE1i[1, :] + REz * kE1i[2, :])
|
|
837
|
+
* S.conj(REz)
|
|
838
|
+
).real
|
|
839
|
+
/ denom
|
|
840
|
+
)
|
|
841
|
+
DEO3[:, iwl] = (
|
|
842
|
+
(S.absolute(TOx) ** 2 + S.absolute(TOy) ** 2 + S.absolute(TOz) ** 2)
|
|
843
|
+
* S.conj(kO3i[2, :])
|
|
844
|
+
- (TOx * kO3i[0, :] + TOy * kO3i[1, :] + TOz * kO3i[2, :]) * S.conj(TOz)
|
|
845
|
+
).real / denom
|
|
846
|
+
DEE3[:, iwl] = (
|
|
847
|
+
(S.absolute(TEx) ** 2 + S.absolute(TEy) ** 2 + S.absolute(TEz) ** 2)
|
|
848
|
+
* S.conj(kE3i[2, :])
|
|
849
|
+
- (TEx * kE3i[0, :] + TEy * kE3i[1, :] + TEz * kE3i[2, :]) * S.conj(TEz)
|
|
850
|
+
).real / denom
|
|
851
|
+
|
|
852
|
+
# save the results
|
|
853
|
+
self.DEO1 = DEO1
|
|
854
|
+
self.DEE1 = DEE1
|
|
855
|
+
self.DEO3 = DEO3
|
|
856
|
+
self.DEE3 = DEE3
|
|
857
|
+
|
|
858
|
+
return self
|
|
859
|
+
|
|
860
|
+
# def plot(self):
|
|
861
|
+
# """Plot the diffraction efficiencies."""
|
|
862
|
+
# g = Gnuplot.Gnuplot()
|
|
863
|
+
# g('set xlabel "$\lambda$"')
|
|
864
|
+
# g('set ylabel "diffraction efficiency"')
|
|
865
|
+
# g('set yrange [0:1]')
|
|
866
|
+
# g('set data style linespoints')
|
|
867
|
+
# g.plot(Gnuplot.Data(self.wls, self.DEO1[self.n,:], with_ = 'linespoints', title = 'DEO1'), \
|
|
868
|
+
# Gnuplot.Data(self.wls, self.DEO3[self.n,:], with_ = 'linespoints', title = 'DEO3'), \
|
|
869
|
+
# Gnuplot.Data(self.wls, self.DEE1[self.n,:], with_ = 'linespoints', title = 'DEE1'), \
|
|
870
|
+
# Gnuplot.Data(self.wls, self.DEE3[self.n,:], with_ = 'linespoints', title = 'DEE3'))
|
|
871
|
+
# raw_input('press enter to close the graph...')
|
|
872
|
+
|
|
873
|
+
def __str__(self):
|
|
874
|
+
return (
|
|
875
|
+
"ANISOTROPIC RCWA SOLVER\n\n%s\n\nLAMBDA = %g\nalpha = %g\ndelta = %g\npsi = %g\nphi = %g\nn = %d"
|
|
876
|
+
% (
|
|
877
|
+
self.multilayer.__str__(),
|
|
878
|
+
self.LAMBDA,
|
|
879
|
+
self.alpha,
|
|
880
|
+
self.delta,
|
|
881
|
+
self.psi,
|
|
882
|
+
self.phi,
|
|
883
|
+
self.n,
|
|
884
|
+
)
|
|
885
|
+
)
|