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/transfer_matrix.py
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"""Transfer matrix for isotropic and anisotropic multilayer.
|
|
2
|
+
|
|
3
|
+
The transfer matrix algorithms is used to compute the power reflected
|
|
4
|
+
and transmitted by a multilayer.
|
|
5
|
+
The multilayer can be made of isotropic and anisotropic layers, with
|
|
6
|
+
any thickness.
|
|
7
|
+
Two versions of the algorithm are present: an isotropic one and an
|
|
8
|
+
anisotropic one.
|
|
9
|
+
"""
|
|
10
|
+
__author__ = "Lorenzo Bolla"
|
|
11
|
+
|
|
12
|
+
import scipy as S
|
|
13
|
+
from scipy.linalg import inv
|
|
14
|
+
from EMpy.utils import snell, norm
|
|
15
|
+
from EMpy.constants import c, mu0
|
|
16
|
+
|
|
17
|
+
# import Gnuplot
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TransferMatrix:
|
|
21
|
+
|
|
22
|
+
"""Class to handle the transfer matrix solvers."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, multilayer):
|
|
25
|
+
"""Set the multilayer.
|
|
26
|
+
|
|
27
|
+
INPUT
|
|
28
|
+
multilayer = Multilayer obj describing the sequence of layers.
|
|
29
|
+
"""
|
|
30
|
+
self.setMultilayer(multilayer)
|
|
31
|
+
|
|
32
|
+
def setMultilayer(self, m):
|
|
33
|
+
self.multilayer = m.simplify()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class IsotropicTransferMatrix(TransferMatrix):
|
|
37
|
+
def __init__(self, multilayer, theta_inc):
|
|
38
|
+
"""Set the multilayer and the incident angle.
|
|
39
|
+
|
|
40
|
+
INPUT
|
|
41
|
+
multilayer = Multilayer obj describing the sequence of layers.
|
|
42
|
+
theta_inc = angle of the incident wave (in radiant) wrt the
|
|
43
|
+
normal.
|
|
44
|
+
"""
|
|
45
|
+
if not multilayer.isIsotropic():
|
|
46
|
+
raise ValueError(
|
|
47
|
+
"Cannot use IsotropicTransferMatrix with anisotropic multilayer"
|
|
48
|
+
)
|
|
49
|
+
TransferMatrix.__init__(self, multilayer)
|
|
50
|
+
self.theta_inc = theta_inc
|
|
51
|
+
|
|
52
|
+
def solve(self, wls):
|
|
53
|
+
"""Isotropic solver.
|
|
54
|
+
|
|
55
|
+
INPUT
|
|
56
|
+
wls = wavelengths to scan (any asarray-able object).
|
|
57
|
+
|
|
58
|
+
OUTPUT
|
|
59
|
+
self.Rs, self.Ts, self.Rp, self.Tp = power reflected and
|
|
60
|
+
transmitted on s and p polarizations.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
self.wls = S.asarray(wls)
|
|
64
|
+
|
|
65
|
+
multilayer = self.multilayer
|
|
66
|
+
theta_inc = self.theta_inc
|
|
67
|
+
|
|
68
|
+
nlayers = len(multilayer)
|
|
69
|
+
d = S.array([l.thickness for l in multilayer]).ravel()
|
|
70
|
+
|
|
71
|
+
Rs = S.zeros_like(self.wls)
|
|
72
|
+
Ts = S.zeros_like(self.wls)
|
|
73
|
+
Rp = S.zeros_like(self.wls)
|
|
74
|
+
Tp = S.zeros_like(self.wls)
|
|
75
|
+
|
|
76
|
+
Dp = S.zeros((2, 2), dtype=complex)
|
|
77
|
+
Ds = S.zeros((2, 2), dtype=complex)
|
|
78
|
+
P = S.zeros((2, 2), dtype=complex)
|
|
79
|
+
Ms = S.zeros((2, 2), dtype=complex)
|
|
80
|
+
Mp = S.zeros((2, 2), dtype=complex)
|
|
81
|
+
k = S.zeros((nlayers, 2), dtype=complex)
|
|
82
|
+
|
|
83
|
+
ntot = S.zeros((self.wls.size, nlayers), dtype=complex)
|
|
84
|
+
for i, l in enumerate(multilayer):
|
|
85
|
+
# ntot[:,i] = l.mat.n(self.wls,l.mat.T0)
|
|
86
|
+
ntot[:, i] = l.mat.n(self.wls, l.mat.toc.T0)
|
|
87
|
+
|
|
88
|
+
for iwl, wl in enumerate(self.wls):
|
|
89
|
+
|
|
90
|
+
n = ntot[iwl, :]
|
|
91
|
+
theta = snell(theta_inc, n)
|
|
92
|
+
|
|
93
|
+
k[:, 0] = 2 * S.pi * n / wl * S.cos(theta)
|
|
94
|
+
k[:, 1] = 2 * S.pi * n / wl * S.sin(theta)
|
|
95
|
+
|
|
96
|
+
Ds = [[1.0, 1.0], [n[0] * S.cos(theta[0]), -n[0] * S.cos(theta[0])]]
|
|
97
|
+
Dp = [[S.cos(theta[0]), S.cos(theta[0])], [n[0], -n[0]]]
|
|
98
|
+
Ms = inv(Ds)
|
|
99
|
+
Mp = inv(Dp)
|
|
100
|
+
|
|
101
|
+
for nn, dd, tt, kk in zip(n[1:-1], d[1:-1], theta[1:-1], k[1:-1, 0]):
|
|
102
|
+
|
|
103
|
+
Ds = [[1.0, 1.0], [nn * S.cos(tt), -nn * S.cos(tt)]]
|
|
104
|
+
Dp = [[S.cos(tt), S.cos(tt)], [nn, -nn]]
|
|
105
|
+
phi = kk * dd
|
|
106
|
+
P = [[S.exp(1j * phi), 0], [0, S.exp(-1j * phi)]]
|
|
107
|
+
Ms = S.dot(Ms, S.dot(Ds, S.dot(P, inv(Ds))))
|
|
108
|
+
Mp = S.dot(Mp, S.dot(Dp, S.dot(P, inv(Dp))))
|
|
109
|
+
|
|
110
|
+
Ds = [[1.0, 1.0], [n[-1] * S.cos(theta[-1]), -n[-1] * S.cos(theta[-1])]]
|
|
111
|
+
Dp = [[S.cos(theta[-1]), S.cos(theta[-1])], [n[-1], -n[-1]]]
|
|
112
|
+
Ms = S.dot(Ms, Ds)
|
|
113
|
+
Mp = S.dot(Mp, Dp)
|
|
114
|
+
|
|
115
|
+
rs = Ms[1, 0] / Ms[0, 0]
|
|
116
|
+
ts = 1.0 / Ms[0, 0]
|
|
117
|
+
|
|
118
|
+
rp = Mp[1, 0] / Mp[0, 0]
|
|
119
|
+
tp = 1.0 / Mp[0, 0]
|
|
120
|
+
|
|
121
|
+
Rs[iwl] = S.absolute(rs) ** 2
|
|
122
|
+
Ts[iwl] = (
|
|
123
|
+
S.absolute((n[-1] * S.cos(theta[-1])) / (n[0] * S.cos(theta[0])))
|
|
124
|
+
* S.absolute(ts) ** 2
|
|
125
|
+
)
|
|
126
|
+
Rp[iwl] = S.absolute(rp) ** 2
|
|
127
|
+
Tp[iwl] = (
|
|
128
|
+
S.absolute((n[-1] * S.cos(theta[-1])) / (n[0] * S.cos(theta[0])))
|
|
129
|
+
* S.absolute(tp) ** 2
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
self.Rs = Rs
|
|
133
|
+
self.Ts = Ts
|
|
134
|
+
self.Rp = Rp
|
|
135
|
+
self.Tp = Tp
|
|
136
|
+
return self
|
|
137
|
+
|
|
138
|
+
# def plot(self):
|
|
139
|
+
# """Plot the solution."""
|
|
140
|
+
# g = Gnuplot.Gnuplot()
|
|
141
|
+
# g('set xlabel "$\lambda$"')
|
|
142
|
+
# g('set ylabel "power"')
|
|
143
|
+
# g('set yrange [0:1]')
|
|
144
|
+
# g('set data style linespoints')
|
|
145
|
+
# g.plot(Gnuplot.Data(self.wls, self.Rs, with_ = 'linespoints', title = 'Rs'), \
|
|
146
|
+
# Gnuplot.Data(self.wls, self.Ts, with_ = 'linespoints', title = 'Ts'), \
|
|
147
|
+
# Gnuplot.Data(self.wls, self.Rp, with_ = 'linespoints', title = 'Rp'), \
|
|
148
|
+
# Gnuplot.Data(self.wls, self.Tp, with_ = 'linespoints', title = 'Tp'))
|
|
149
|
+
# raw_input('press enter to close the graph...')
|
|
150
|
+
|
|
151
|
+
def __str__(self):
|
|
152
|
+
return "ISOTROPIC TRANSFER MATRIX SOLVER\n\n%s\n\ntheta inc = %g" % (
|
|
153
|
+
self.multilayer.__str__(),
|
|
154
|
+
self.theta_inc,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class AnisotropicTransferMatrix(TransferMatrix):
|
|
159
|
+
def __init__(self, multilayer, theta_inc_x, theta_inc_y):
|
|
160
|
+
"""Set the multilayer and the incident angle.
|
|
161
|
+
|
|
162
|
+
INPUT
|
|
163
|
+
multilayer = Multilayer obj describing the sequence of layers.
|
|
164
|
+
theta_inc_x and theta_inc_y = angles of the incident wave (in
|
|
165
|
+
radiant) wrt the normal.
|
|
166
|
+
"""
|
|
167
|
+
TransferMatrix.__init__(self, multilayer)
|
|
168
|
+
self.theta_inc_x = theta_inc_x
|
|
169
|
+
self.theta_inc_y = theta_inc_y
|
|
170
|
+
|
|
171
|
+
def solve(self, wls):
|
|
172
|
+
"""Anisotropic solver.
|
|
173
|
+
|
|
174
|
+
INPUT
|
|
175
|
+
wls = wavelengths to scan (any asarray-able object).
|
|
176
|
+
|
|
177
|
+
OUTPUT
|
|
178
|
+
self.R, self.T = power reflected and transmitted.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
self.wls = S.asarray(wls)
|
|
182
|
+
|
|
183
|
+
multilayer = self.multilayer
|
|
184
|
+
theta_inc_x = self.theta_inc_x
|
|
185
|
+
theta_inc_y = self.theta_inc_y
|
|
186
|
+
|
|
187
|
+
def find_roots(wl, epsilon, alpha, beta):
|
|
188
|
+
"""Find roots of characteristic equation.
|
|
189
|
+
|
|
190
|
+
Given a wavelength, a 3x3 tensor epsilon and the tangential components
|
|
191
|
+
of the wavevector k = (alpha,beta,gamma_i), returns the 4 possible
|
|
192
|
+
gamma_i, i = 1,2,3,4 that satisfy the boundary conditions.
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
omega = 2.0 * S.pi * c / wl
|
|
196
|
+
K = omega**2 * mu0 * epsilon
|
|
197
|
+
|
|
198
|
+
k0 = 2.0 * S.pi / wl
|
|
199
|
+
K /= k0**2
|
|
200
|
+
alpha /= k0
|
|
201
|
+
beta /= k0
|
|
202
|
+
|
|
203
|
+
alpha2 = alpha**2
|
|
204
|
+
alpha3 = alpha**3
|
|
205
|
+
alpha4 = alpha**4
|
|
206
|
+
beta2 = beta**2
|
|
207
|
+
beta3 = beta**3
|
|
208
|
+
beta4 = beta**4
|
|
209
|
+
|
|
210
|
+
coeff = [
|
|
211
|
+
K[2, 2],
|
|
212
|
+
alpha * (K[0, 2] + K[2, 0]) + beta * (K[1, 2] + K[2, 1]),
|
|
213
|
+
alpha2 * (K[0, 0] + K[2, 2])
|
|
214
|
+
+ alpha * beta * (K[1, 0] + K[0, 1])
|
|
215
|
+
+ beta2 * (K[1, 1] + K[2, 2])
|
|
216
|
+
+ (
|
|
217
|
+
K[0, 2] * K[2, 0]
|
|
218
|
+
+ K[1, 2] * K[2, 1]
|
|
219
|
+
- K[0, 0] * K[2, 2]
|
|
220
|
+
- K[1, 1] * K[2, 2]
|
|
221
|
+
),
|
|
222
|
+
alpha3 * (K[0, 2] + K[2, 0])
|
|
223
|
+
+ beta3 * (K[1, 2] + K[2, 1])
|
|
224
|
+
+ alpha2 * beta * (K[1, 2] + K[2, 1])
|
|
225
|
+
+ alpha * beta2 * (K[0, 2] + K[2, 0])
|
|
226
|
+
+ alpha
|
|
227
|
+
* (
|
|
228
|
+
K[0, 1] * K[1, 2]
|
|
229
|
+
+ K[1, 0] * K[2, 1]
|
|
230
|
+
- K[0, 2] * K[1, 1]
|
|
231
|
+
- K[2, 0] * K[1, 1]
|
|
232
|
+
)
|
|
233
|
+
+ beta
|
|
234
|
+
* (
|
|
235
|
+
K[0, 1] * K[2, 0]
|
|
236
|
+
+ K[1, 0] * K[0, 2]
|
|
237
|
+
- K[0, 0] * K[1, 2]
|
|
238
|
+
- K[0, 0] * K[2, 1]
|
|
239
|
+
),
|
|
240
|
+
alpha4 * (K[0, 0])
|
|
241
|
+
+ beta4 * (K[1, 1])
|
|
242
|
+
+ alpha3 * beta * (K[0, 1] + K[1, 0])
|
|
243
|
+
+ alpha * beta3 * (K[0, 1] + K[1, 0])
|
|
244
|
+
+ alpha2 * beta2 * (K[0, 0] + K[1, 1])
|
|
245
|
+
+ alpha2
|
|
246
|
+
* (
|
|
247
|
+
K[0, 1] * K[1, 0]
|
|
248
|
+
+ K[0, 2] * K[2, 0]
|
|
249
|
+
- K[0, 0] * K[2, 2]
|
|
250
|
+
- K[0, 0] * K[1, 1]
|
|
251
|
+
)
|
|
252
|
+
+ beta2
|
|
253
|
+
* (
|
|
254
|
+
K[0, 1] * K[1, 0]
|
|
255
|
+
+ K[1, 2] * K[2, 1]
|
|
256
|
+
- K[0, 0] * K[1, 1]
|
|
257
|
+
- K[1, 1] * K[2, 2]
|
|
258
|
+
)
|
|
259
|
+
+ alpha
|
|
260
|
+
* beta
|
|
261
|
+
* (
|
|
262
|
+
K[0, 2] * K[2, 1]
|
|
263
|
+
+ K[2, 0] * K[1, 2]
|
|
264
|
+
- K[0, 1] * K[2, 2]
|
|
265
|
+
- K[1, 0] * K[2, 2]
|
|
266
|
+
)
|
|
267
|
+
+ K[0, 0] * K[1, 1] * K[2, 2]
|
|
268
|
+
- K[0, 0] * K[1, 2] * K[2, 1]
|
|
269
|
+
- K[1, 0] * K[0, 1] * K[2, 2]
|
|
270
|
+
+ K[1, 0] * K[0, 2] * K[2, 1]
|
|
271
|
+
+ K[2, 0] * K[0, 1] * K[1, 2]
|
|
272
|
+
- K[2, 0] * K[0, 2] * K[1, 1],
|
|
273
|
+
]
|
|
274
|
+
|
|
275
|
+
gamma = S.roots(coeff)
|
|
276
|
+
tmp = S.sort_complex(gamma)
|
|
277
|
+
gamma = tmp[[3, 0, 2, 1]] # convention
|
|
278
|
+
|
|
279
|
+
k = (
|
|
280
|
+
k0
|
|
281
|
+
* S.array(
|
|
282
|
+
[alpha * S.ones(gamma.shape), beta * S.ones(gamma.shape), gamma]
|
|
283
|
+
).T
|
|
284
|
+
)
|
|
285
|
+
v = S.zeros((4, 3), dtype=complex)
|
|
286
|
+
|
|
287
|
+
for i, g in enumerate(gamma):
|
|
288
|
+
|
|
289
|
+
# H = K + [
|
|
290
|
+
# [-beta2 - g ** 2, alpha * beta, alpha * g],
|
|
291
|
+
# [alpha * beta, -alpha2 - g ** 2, beta * g],
|
|
292
|
+
# [alpha * g, beta * g, -alpha2 - beta2],
|
|
293
|
+
# ]
|
|
294
|
+
v[i, :] = [
|
|
295
|
+
(K[1, 1] - alpha2 - g**2) * (K[2, 2] - alpha2 - beta2)
|
|
296
|
+
- (K[1, 2] + beta * g) ** 2,
|
|
297
|
+
(K[1, 2] + beta * g) * (K[2, 0] + alpha * g)
|
|
298
|
+
- (K[0, 1] + alpha * beta) * (K[2, 2] - alpha2 - beta2),
|
|
299
|
+
(K[0, 1] + alpha * beta) * (K[1, 2] + beta * g)
|
|
300
|
+
- (K[0, 2] + alpha * g) * (K[1, 1] - alpha2 - g**2),
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
p3 = v[0, :]
|
|
304
|
+
p3 /= norm(p3)
|
|
305
|
+
p4 = v[1, :]
|
|
306
|
+
p4 /= norm(p4)
|
|
307
|
+
p1 = S.cross(p3, k[0, :])
|
|
308
|
+
p1 /= norm(p1)
|
|
309
|
+
p2 = S.cross(p4, k[1, :])
|
|
310
|
+
p2 /= norm(p2)
|
|
311
|
+
|
|
312
|
+
p = S.array([p1, p2, p3, p4])
|
|
313
|
+
q = wl / (2.0 * S.pi * mu0 * c) * S.cross(k, p)
|
|
314
|
+
|
|
315
|
+
return k, p, q
|
|
316
|
+
|
|
317
|
+
nlayers = len(multilayer)
|
|
318
|
+
d = S.asarray([l.thickness for l in multilayer])
|
|
319
|
+
|
|
320
|
+
# R and T are real, because they are powers
|
|
321
|
+
# r and t are complex!
|
|
322
|
+
R = S.zeros((2, 2, self.wls.size))
|
|
323
|
+
T = S.zeros((2, 2, self.wls.size))
|
|
324
|
+
|
|
325
|
+
epstot = S.zeros((3, 3, self.wls.size, nlayers), dtype=complex)
|
|
326
|
+
for i, l in enumerate(multilayer):
|
|
327
|
+
epstot[:, :, :, i] = l.mat.epsilonTensor(self.wls)
|
|
328
|
+
|
|
329
|
+
for iwl, wl in enumerate(self.wls):
|
|
330
|
+
|
|
331
|
+
epsilon = epstot[:, :, iwl, :]
|
|
332
|
+
|
|
333
|
+
kx = 2 * S.pi / wl * S.sin(theta_inc_x)
|
|
334
|
+
ky = 2 * S.pi / wl * S.sin(theta_inc_y)
|
|
335
|
+
x = S.array([1, 0, 0], dtype=float)
|
|
336
|
+
y = S.array([0, 1, 0], dtype=float)
|
|
337
|
+
# z = S.array([0, 0, 1], dtype=float)
|
|
338
|
+
k = S.zeros((4, 3, nlayers), dtype=complex)
|
|
339
|
+
p = S.zeros((4, 3, nlayers), dtype=complex)
|
|
340
|
+
q = S.zeros((4, 3, nlayers), dtype=complex)
|
|
341
|
+
D = S.zeros((4, 4, nlayers), dtype=complex)
|
|
342
|
+
P = S.zeros((4, 4, nlayers), dtype=complex)
|
|
343
|
+
|
|
344
|
+
for i in range(nlayers):
|
|
345
|
+
|
|
346
|
+
k[:, :, i], p[:, :, i], q[:, :, i] = find_roots(
|
|
347
|
+
wl, epsilon[:, :, i], kx, ky
|
|
348
|
+
)
|
|
349
|
+
D[:, :, i] = [
|
|
350
|
+
[
|
|
351
|
+
S.dot(x, p[0, :, i]),
|
|
352
|
+
S.dot(x, p[1, :, i]),
|
|
353
|
+
S.dot(x, p[2, :, i]),
|
|
354
|
+
S.dot(x, p[3, :, i]),
|
|
355
|
+
],
|
|
356
|
+
[
|
|
357
|
+
S.dot(y, q[0, :, i]),
|
|
358
|
+
S.dot(y, q[1, :, i]),
|
|
359
|
+
S.dot(y, q[2, :, i]),
|
|
360
|
+
S.dot(y, q[3, :, i]),
|
|
361
|
+
],
|
|
362
|
+
[
|
|
363
|
+
S.dot(y, p[0, :, i]),
|
|
364
|
+
S.dot(y, p[1, :, i]),
|
|
365
|
+
S.dot(y, p[2, :, i]),
|
|
366
|
+
S.dot(y, p[3, :, i]),
|
|
367
|
+
],
|
|
368
|
+
[
|
|
369
|
+
S.dot(x, q[0, :, i]),
|
|
370
|
+
S.dot(x, q[1, :, i]),
|
|
371
|
+
S.dot(x, q[2, :, i]),
|
|
372
|
+
S.dot(x, q[3, :, i]),
|
|
373
|
+
],
|
|
374
|
+
]
|
|
375
|
+
|
|
376
|
+
for i in range(1, nlayers - 1):
|
|
377
|
+
P[:, :, i] = S.diag(S.exp(1j * k[:, 2, i] * d[i]))
|
|
378
|
+
|
|
379
|
+
M = inv(D[:, :, 0])
|
|
380
|
+
for i in range(1, nlayers - 1):
|
|
381
|
+
M = S.dot(M, S.dot(D[:, :, i], S.dot(P[:, :, i], inv(D[:, :, i]))))
|
|
382
|
+
M = S.dot(M, D[:, :, -1])
|
|
383
|
+
|
|
384
|
+
deltaM = M[0, 0] * M[2, 2] - M[0, 2] * M[2, 0]
|
|
385
|
+
|
|
386
|
+
# reflectance matrix (from yeh_electromagnetic)
|
|
387
|
+
# r = [rss rsp; rps rpp]
|
|
388
|
+
r = (
|
|
389
|
+
S.array(
|
|
390
|
+
[
|
|
391
|
+
[
|
|
392
|
+
M[1, 0] * M[2, 2] - M[1, 2] * M[2, 0],
|
|
393
|
+
M[3, 0] * M[2, 2] - M[3, 2] * M[2, 0],
|
|
394
|
+
],
|
|
395
|
+
[
|
|
396
|
+
M[0, 0] * M[1, 2] - M[1, 0] * M[0, 2],
|
|
397
|
+
M[0, 0] * M[3, 2] - M[3, 0] * M[0, 2],
|
|
398
|
+
],
|
|
399
|
+
],
|
|
400
|
+
dtype=complex,
|
|
401
|
+
)
|
|
402
|
+
/ deltaM
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
# transmittance matrix (from yeh_electromagnetic)
|
|
406
|
+
# t = [tss tsp; tps tpp]
|
|
407
|
+
t = S.array([[M[2, 2], -M[2, 0]], [-M[0, 2], M[0, 0]]]) / deltaM
|
|
408
|
+
|
|
409
|
+
# P_t/P_inc = |E_t|**2/|E_inc|**2 . k_t_z/k_inc_z
|
|
410
|
+
T[:, :, iwl] = (S.absolute(t) ** 2 * k[0, 2, -1] / k[0, 2, 0]).real
|
|
411
|
+
|
|
412
|
+
# P_r/P_inc = |E_r|**2/|E_inc|**2
|
|
413
|
+
R[:, :, iwl] = S.absolute(r) ** 2
|
|
414
|
+
|
|
415
|
+
self.R = R
|
|
416
|
+
self.T = T
|
|
417
|
+
return self
|
|
418
|
+
|
|
419
|
+
def __str__(self):
|
|
420
|
+
return (
|
|
421
|
+
"ANISOTROPIC TRANSFER MATRIX SOLVER\n\n%s\n\ntheta inc x = %g\ntheta inc y = %g"
|
|
422
|
+
% (self.multilayer.__str__(), self.theta_inc_x, self.theta_inc_y)
|
|
423
|
+
)
|