ElectroMagneticPython 2.2.1__py3-none-any.whl → 2.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- EMpy/RCWA.py +32 -12
- EMpy/__init__.py +10 -2
- EMpy/_version.py +24 -0
- EMpy/constants.py +0 -2
- EMpy/devices.py +8 -32
- EMpy/materials.py +1 -8
- EMpy/modesolvers/FD.py +34 -76
- EMpy/modesolvers/FMM.py +24 -23
- EMpy/modesolvers/__init__.py +1 -0
- EMpy/modesolvers/geometries.py +8 -9
- EMpy/transfer_matrix.py +10 -6
- EMpy/utils.py +12 -26
- electromagneticpython-2.2.4.dist-info/METADATA +99 -0
- electromagneticpython-2.2.4.dist-info/RECORD +45 -0
- {ElectroMagneticPython-2.2.1.dist-info → electromagneticpython-2.2.4.dist-info}/WHEEL +1 -1
- electromagneticpython-2.2.4.dist-info/top_level.txt +4 -0
- examples/ex_APRR.py +18 -0
- examples/ex_NRR.py +40 -0
- examples/ex_RCWA.py +95 -0
- examples/ex_RCWA_2.py +52 -0
- examples/ex_RCWA_3.py +58 -0
- examples/ex_SRR.py +23 -0
- examples/ex_laser_etch_monitor.py +241 -0
- examples/ex_modesolver.py +68 -0
- examples/ex_modesolver_2.py +58 -0
- examples/ex_modesolver_3.py +48 -0
- examples/ex_modesolver_4.py +43 -0
- examples/ex_modesolver_dch.py +296 -0
- examples/ex_modesolver_dch_anis.py +318 -0
- examples/ex_transfer_matrix.py +82 -0
- examples/ex_transfer_matrix_2.py +44 -0
- examples/ex_transfer_matrix_2.py.png +0 -0
- examples/ex_transfer_matrix_3.py +60 -0
- examples/lc_data.dat +27 -0
- examples/nk.py +1468 -0
- scripts/FDTD.py +741 -0
- tests/devices_test.py +31 -0
- tests/materials_test.py +1 -1
- tests/modesolvers_test.py +36 -0
- tests/transfer_matrix_test.py +134 -0
- tests/utils_test.py +9 -5
- EMpy/version.py +0 -1
- ElectroMagneticPython-2.2.1.dist-info/METADATA +0 -109
- ElectroMagneticPython-2.2.1.dist-info/RECORD +0 -22
- ElectroMagneticPython-2.2.1.dist-info/top_level.txt +0 -2
- {ElectroMagneticPython-2.2.1.dist-info → electromagneticpython-2.2.4.dist-info/licenses}/LICENSE +0 -0
examples/ex_RCWA_3.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Rigorous Coupled Wave Analysis example."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from matplotlib import pyplot as plt
|
|
5
|
+
import numpy
|
|
6
|
+
|
|
7
|
+
import EMpy
|
|
8
|
+
from EMpy.materials import IsotropicMaterial, RefractiveIndex
|
|
9
|
+
|
|
10
|
+
alpha = EMpy.utils.deg2rad(30.0)
|
|
11
|
+
delta = EMpy.utils.deg2rad(45.0)
|
|
12
|
+
psi = EMpy.utils.deg2rad(0.0) # TE
|
|
13
|
+
phi = EMpy.utils.deg2rad(90.0)
|
|
14
|
+
|
|
15
|
+
wls = numpy.linspace(1.5495e-6, 1.550e-6, 101)
|
|
16
|
+
|
|
17
|
+
LAMBDA = 1.0e-6 # grating periodicity
|
|
18
|
+
n = 3 # orders of diffraction
|
|
19
|
+
|
|
20
|
+
Top = IsotropicMaterial("Top", n0=RefractiveIndex(n0_const=1.0))
|
|
21
|
+
Bottom = IsotropicMaterial("Bottom", n0=RefractiveIndex(n0_const=3.47))
|
|
22
|
+
|
|
23
|
+
multilayer = EMpy.utils.Multilayer(
|
|
24
|
+
[
|
|
25
|
+
EMpy.utils.Layer(Top, numpy.inf),
|
|
26
|
+
EMpy.utils.BinaryGrating(Top, Bottom, 0.4, LAMBDA, 0.01),
|
|
27
|
+
EMpy.utils.Layer(Bottom, numpy.inf),
|
|
28
|
+
]
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
solution = EMpy.RCWA.IsotropicRCWA(multilayer, alpha, delta, psi, phi, n).solve(wls)
|
|
32
|
+
|
|
33
|
+
plt.plot(
|
|
34
|
+
wls,
|
|
35
|
+
solution.DE1[n, :],
|
|
36
|
+
"ko-",
|
|
37
|
+
wls,
|
|
38
|
+
solution.DE3[n, :],
|
|
39
|
+
"ro-",
|
|
40
|
+
wls,
|
|
41
|
+
solution.DE1[n - 1, :],
|
|
42
|
+
"kx-",
|
|
43
|
+
wls,
|
|
44
|
+
solution.DE3[n - 1, :],
|
|
45
|
+
"rx-",
|
|
46
|
+
wls,
|
|
47
|
+
solution.DE1[n + 1, :],
|
|
48
|
+
"k.-",
|
|
49
|
+
wls,
|
|
50
|
+
solution.DE3[n + 1, :],
|
|
51
|
+
"r.-",
|
|
52
|
+
)
|
|
53
|
+
plt.xlabel("wavelength /m")
|
|
54
|
+
plt.ylabel("diffraction efficiency")
|
|
55
|
+
plt.legend(("DE1:0", "DE3:0", "DE1:-1", "DE3:-1", "DE1:+1", "DE3:+1"))
|
|
56
|
+
plt.axis("tight")
|
|
57
|
+
plt.ylim([0, 1])
|
|
58
|
+
plt.show()
|
examples/ex_SRR.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Single ring resonator example."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from matplotlib import pyplot as plt
|
|
5
|
+
import numpy
|
|
6
|
+
|
|
7
|
+
import EMpy
|
|
8
|
+
|
|
9
|
+
wls = numpy.linspace(1.53e-6, 1.56e-6, 1000)
|
|
10
|
+
K1 = EMpy.devices.Coupler(wls, numpy.sqrt(0.08), 1.0)
|
|
11
|
+
K2 = EMpy.devices.Coupler(wls, numpy.sqrt(0.08), 1.0)
|
|
12
|
+
l1 = numpy.pi * 5e-6
|
|
13
|
+
l2 = numpy.pi * 5e-6
|
|
14
|
+
SWG = EMpy.devices.SWG(488, 220, 25).solve(wls)
|
|
15
|
+
SRR = EMpy.devices.SRR(K1, K2, SWG.neff, l1, l2).solve()
|
|
16
|
+
|
|
17
|
+
plt.plot(wls, numpy.absolute(SRR.THRU), "r.-", wls, numpy.absolute(SRR.DROP), "g.-")
|
|
18
|
+
plt.axis("tight")
|
|
19
|
+
plt.ylim([0, 1])
|
|
20
|
+
plt.xlabel("wavelength /m")
|
|
21
|
+
plt.ylabel("power")
|
|
22
|
+
plt.legend(("THRU", "DROP"))
|
|
23
|
+
plt.show()
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Transfer matrix example: Laser Etch Monitor/End-point detection.
|
|
4
|
+
Built for Electromagnetic Python by Lorenzo Bolla:
|
|
5
|
+
http://lbolla.github.io/EMpy/
|
|
6
|
+
|
|
7
|
+
Simulate a laser etch monitor (aka. laser endpoint detection):
|
|
8
|
+
Calculate the reflectivity of a thin-film stack as the stack is
|
|
9
|
+
progressively thinned by etching from one side. Finally, plot
|
|
10
|
+
reflectivity vs. etch depth at a single wavelength, as is often
|
|
11
|
+
used to determine end-points during reactive ion/plasma etching.
|
|
12
|
+
For more info, see Oxford Plasma's page on the technique:
|
|
13
|
+
http://www.oxfordplasma.de/technols/li.htm
|
|
14
|
+
|
|
15
|
+
Requires file `nk.py` for wavelength-dependent refractive index/loss models.
|
|
16
|
+
|
|
17
|
+
Author: Demis D. John, March 2017 (demis.john@gmail.com)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from copy import copy, deepcopy
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
from matplotlib import pyplot as plt
|
|
24
|
+
import numpy
|
|
25
|
+
|
|
26
|
+
import EMpy
|
|
27
|
+
|
|
28
|
+
# file of refractive indices, takes wavelengths in Microns!!
|
|
29
|
+
import nk
|
|
30
|
+
|
|
31
|
+
# Simulation Parameters
|
|
32
|
+
# laser monitor wavelength
|
|
33
|
+
wl_lasermon = 670e-9
|
|
34
|
+
# how much to etch before acquiring new laser monitor reflectivity
|
|
35
|
+
EtchStep = 10e-9
|
|
36
|
+
|
|
37
|
+
wls = numpy.array([wl_lasermon - 1e-9, wl_lasermon, wl_lasermon + 1e-9])
|
|
38
|
+
theta_inc = EMpy.utils.deg2rad(0) # incidence angle
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Define some helper functions
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def find_nearest(a, a0):
|
|
45
|
+
"""Return element in ndArray `a` that has value closest to the
|
|
46
|
+
scalar value `a0`."""
|
|
47
|
+
idx = numpy.abs(a - a0).argmin()
|
|
48
|
+
return a.flat[idx]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def arg_find_nearest(a, a0):
|
|
52
|
+
"""Return index to element in ndArray `a` that has value closest
|
|
53
|
+
to the scalar value `a0`."""
|
|
54
|
+
idx = numpy.abs(a - a0).argmin()
|
|
55
|
+
return idx
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def count_noninf(multilayer):
|
|
59
|
+
"""Return number of non-infinite layers in an EMpy Multilayer
|
|
60
|
+
object."""
|
|
61
|
+
out = 0
|
|
62
|
+
for x in multilayer:
|
|
63
|
+
out = out + 0 if numpy.isinf(x.thickness) else out + 1
|
|
64
|
+
return out
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def arg_inf(multilayer):
|
|
68
|
+
"""Return index to layers with infinite-thickness in an EMpy Multilayer object."""
|
|
69
|
+
out = []
|
|
70
|
+
for ix, x in enumerate(multilayer):
|
|
71
|
+
if numpy.isinf(x.thickness):
|
|
72
|
+
out.append(ix)
|
|
73
|
+
return out
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# Define some materials
|
|
77
|
+
|
|
78
|
+
# Define RefractiveIndex functions, then Material objects.
|
|
79
|
+
n_air = 1.0 # constant vs. wavelength
|
|
80
|
+
mat_air = EMpy.materials.IsotropicMaterial(
|
|
81
|
+
"air", EMpy.materials.RefractiveIndex(n0_const=n_air)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
n_SiN = 1.997 # Silicon Nitride (Si3N4)
|
|
85
|
+
mat_SiN = EMpy.materials.IsotropicMaterial(
|
|
86
|
+
"Si3N4", EMpy.materials.RefractiveIndex(n0_const=n_SiN)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# RIX functions from file, taking wavelength in microns:
|
|
91
|
+
# Covert to microns, request loss as complex refractive index
|
|
92
|
+
def n_GaAs(w):
|
|
93
|
+
return nk.GaAs_interp(w * 1e6, k=True)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
mat_GaAs = EMpy.materials.IsotropicMaterial(
|
|
97
|
+
"GaAs", EMpy.materials.RefractiveIndex(n0_func=n_GaAs)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# Function from file, AlGaAs with 95% Aluminum
|
|
102
|
+
def n_AlGaAs95(w):
|
|
103
|
+
return nk.AlGaAs_interp(0.95, w * 1e6, k=True)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
mat_AlGaAs95 = EMpy.materials.IsotropicMaterial(
|
|
107
|
+
"Al95Ga05As", EMpy.materials.RefractiveIndex(n0_func=n_AlGaAs95)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# DBR mirror periods, at 1/4-wavelength thicknesses
|
|
112
|
+
wl_center = 1100e-9
|
|
113
|
+
d_GaAs_DBR = wl_center / n_GaAs(wl_center)[0].real / 4
|
|
114
|
+
d_AlGaAs_DBR = wl_center / n_AlGaAs95(wl_center)[0].real / 4
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# Build the Multilayer stack
|
|
118
|
+
# Build from top to bottom - ie. topmost layer (closest to laser
|
|
119
|
+
# monitor) first, substrate last. Must include infinite-thickness
|
|
120
|
+
# layers on top & bottom for air & substrate, respectively.
|
|
121
|
+
|
|
122
|
+
Layer = EMpy.utils.Layer # shortcut
|
|
123
|
+
|
|
124
|
+
# define the layers (material, thickness) we will use in the stack:
|
|
125
|
+
air = Layer(mat_air, numpy.inf)
|
|
126
|
+
SiN = Layer(mat_SiN, 300e-9)
|
|
127
|
+
GaAs_DBR = Layer(mat_GaAs, d_GaAs_DBR)
|
|
128
|
+
AlGaAs_DBR = Layer(mat_AlGaAs95, d_AlGaAs_DBR)
|
|
129
|
+
GaAs_core = Layer(mat_GaAs, 551.75e-9)
|
|
130
|
+
AlGaAs_spacer = Layer(mat_AlGaAs95, 500e-9)
|
|
131
|
+
GaAs_spacer = Layer(mat_GaAs, 300e-9)
|
|
132
|
+
GaAs_substrate = Layer(mat_GaAs, numpy.inf)
|
|
133
|
+
|
|
134
|
+
# Use lists to enable periodic structures etc.
|
|
135
|
+
# Make sure to include infinite-thickness layers on ends
|
|
136
|
+
layers_ = (
|
|
137
|
+
[air]
|
|
138
|
+
+ [SiN]
|
|
139
|
+
+ 5 * [GaAs_DBR, AlGaAs_DBR]
|
|
140
|
+
+ [GaAs_core]
|
|
141
|
+
+ 5 * [AlGaAs_DBR, GaAs_DBR]
|
|
142
|
+
+ [AlGaAs_spacer]
|
|
143
|
+
+ [GaAs_spacer]
|
|
144
|
+
+ [GaAs_substrate]
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Create EMpy MultiLayer stack.
|
|
148
|
+
# Must dereference the lists from each other via copy(), otherwise altering
|
|
149
|
+
# one layer during etching also affects other repeated Layers
|
|
150
|
+
layers = EMpy.utils.Multilayer([copy(l) for l in layers_])
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# setup etching loop
|
|
154
|
+
EtchStep_current = EtchStep # how much left to etch in current loop iteration
|
|
155
|
+
go = True # while loop switch
|
|
156
|
+
i = -1 # while loop counter
|
|
157
|
+
etchedlayers = [] # save stacks of etched layers
|
|
158
|
+
solutions = [] # IsotropicTransferMatrix object storing R/T solutions
|
|
159
|
+
EtchSteps = [] # x-axis data
|
|
160
|
+
Rlaser = [] # y-axis data - reflectivity
|
|
161
|
+
RefrIdx = [] # y-axis data - refractive index
|
|
162
|
+
# get index to laser-monitor wavelength in `wls` array
|
|
163
|
+
wlidx = arg_find_nearest(wls, wl_lasermon)
|
|
164
|
+
# 0 if etching away from first layer in list, -1 if etching from last
|
|
165
|
+
# layer appended
|
|
166
|
+
idxtemp = 0
|
|
167
|
+
|
|
168
|
+
print("Etching...")
|
|
169
|
+
while go is True:
|
|
170
|
+
# keep reducing thickness/removing layers until last layer is too thin
|
|
171
|
+
i = i + 1
|
|
172
|
+
|
|
173
|
+
# print a small progress bar
|
|
174
|
+
sys.stdout.write(".")
|
|
175
|
+
sys.stdout.flush()
|
|
176
|
+
|
|
177
|
+
if count_noninf(layers) > 0:
|
|
178
|
+
# at least one infinite-thickness layer should still be left
|
|
179
|
+
|
|
180
|
+
if i <= 0:
|
|
181
|
+
# first iteration: analyze unetched structure
|
|
182
|
+
EtchStep_current = 0.0
|
|
183
|
+
indexno = idxtemp
|
|
184
|
+
else:
|
|
185
|
+
# point to non-infinite layers for etching:
|
|
186
|
+
while numpy.isinf(layers[idxtemp].thickness):
|
|
187
|
+
idxtemp = idxtemp + 1 # assumes etching from 1st layer in list
|
|
188
|
+
indexno = idxtemp
|
|
189
|
+
|
|
190
|
+
if layers[indexno].thickness <= EtchStep_current:
|
|
191
|
+
# next layer is thinner than etch step
|
|
192
|
+
# Reduce etch step + remove this layer:
|
|
193
|
+
EtchStep_current = EtchStep_current - layers[indexno].thickness
|
|
194
|
+
layers.pop(indexno)
|
|
195
|
+
|
|
196
|
+
elif layers[indexno].thickness > EtchStep_current:
|
|
197
|
+
# etch increment ends within next layer
|
|
198
|
+
# reduce layer thickness & solve & save data points:
|
|
199
|
+
layers[indexno].thickness = layers[indexno].thickness - EtchStep_current
|
|
200
|
+
# add this layer stack to the list
|
|
201
|
+
etchedlayers.append(deepcopy(layers))
|
|
202
|
+
# get RefrIndex in this layer
|
|
203
|
+
RefrIdx.append(etchedlayers[-1][idxtemp].mat.n(wl_lasermon).real)
|
|
204
|
+
if i <= 0:
|
|
205
|
+
# for 1st iteration: unetched layer
|
|
206
|
+
EtchSteps.append(0.0)
|
|
207
|
+
else:
|
|
208
|
+
EtchSteps.append(EtchSteps[-1] + EtchStep) # Add x-axis point
|
|
209
|
+
EtchStep_current = EtchStep # reset EtchStep_current
|
|
210
|
+
|
|
211
|
+
# solve for reflectivity at laser monitor wavelength
|
|
212
|
+
solutions.append(
|
|
213
|
+
EMpy.transfer_matrix.IsotropicTransferMatrix(
|
|
214
|
+
etchedlayers[-1], theta_inc
|
|
215
|
+
).solve(wls)
|
|
216
|
+
)
|
|
217
|
+
Rlaser.append(solutions[-1].Rs[wlidx])
|
|
218
|
+
else:
|
|
219
|
+
# No non-infinte layers left, end the loop
|
|
220
|
+
go = False
|
|
221
|
+
|
|
222
|
+
print("\n")
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# Plots:
|
|
226
|
+
fig1, [ax1, ax2] = plt.subplots(nrows=2, ncols=1, sharex=True)
|
|
227
|
+
ax1.set_title(r"Reflectivity at $\lambda = %0.1fnm$" % (wls[wlidx] * 1e9))
|
|
228
|
+
|
|
229
|
+
# plot refractive index vs. depth
|
|
230
|
+
ax1.plot(numpy.array(EtchSteps) * 1e9, RefrIdx, "-g")
|
|
231
|
+
ax1.set_ylabel("Refractive Index")
|
|
232
|
+
ax1.grid(True)
|
|
233
|
+
|
|
234
|
+
# plot reflectivity vs. depth
|
|
235
|
+
ax2.plot(numpy.array(EtchSteps) * 1e9, numpy.array(Rlaser) * 100, "-")
|
|
236
|
+
ax2.set_ylabel("Laser Reflectivity (%)")
|
|
237
|
+
ax2.set_xlabel("Etch Depth (nm)")
|
|
238
|
+
ax2.grid(True)
|
|
239
|
+
|
|
240
|
+
fig1.show()
|
|
241
|
+
plt.show()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Fully vectorial finite-difference mode solver example."""
|
|
2
|
+
|
|
3
|
+
from matplotlib import pyplot as plt
|
|
4
|
+
import numpy
|
|
5
|
+
|
|
6
|
+
import EMpy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def epsfunc(x_, y_):
|
|
10
|
+
"""Return a matrix describing a 2d material.
|
|
11
|
+
|
|
12
|
+
:param x_: x values
|
|
13
|
+
:param y_: y values
|
|
14
|
+
:return: 2d-matrix
|
|
15
|
+
"""
|
|
16
|
+
xx, yy = numpy.meshgrid(x_, y_)
|
|
17
|
+
return numpy.where(
|
|
18
|
+
(numpy.abs(xx.T - 1.24e-6) <= 0.24e-6) * (numpy.abs(yy.T - 1.11e-6) <= 0.11e-6),
|
|
19
|
+
3.4757**2,
|
|
20
|
+
1.446**2,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
wl = 1.55e-6
|
|
25
|
+
x = numpy.linspace(0, 2.48e-6, 125)
|
|
26
|
+
y = numpy.linspace(0, 2.22e-6, 112)
|
|
27
|
+
|
|
28
|
+
neigs = 2
|
|
29
|
+
tol = 1e-8
|
|
30
|
+
boundary = "0000"
|
|
31
|
+
|
|
32
|
+
solver = EMpy.modesolvers.FD.VFDModeSolver(wl, x, y, epsfunc, boundary).solve(
|
|
33
|
+
neigs, tol
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
fig = plt.figure()
|
|
37
|
+
|
|
38
|
+
fig.add_subplot(1, 3, 1)
|
|
39
|
+
Ex = numpy.transpose(solver.modes[0].get_field("Ex", x, y))
|
|
40
|
+
plt.contourf(x, y, abs(Ex), 50)
|
|
41
|
+
plt.title("Ex")
|
|
42
|
+
|
|
43
|
+
fig.add_subplot(1, 3, 2)
|
|
44
|
+
Ey = numpy.transpose(solver.modes[0].get_field("Ey", x, y))
|
|
45
|
+
plt.contourf(x, y, abs(Ey), 50)
|
|
46
|
+
plt.title("Ey")
|
|
47
|
+
|
|
48
|
+
fig.add_subplot(1, 3, 3)
|
|
49
|
+
Ez = numpy.transpose(solver.modes[0].get_field("Ez", x, y))
|
|
50
|
+
plt.contourf(x, y, abs(Ez), 50)
|
|
51
|
+
plt.title("Ez")
|
|
52
|
+
|
|
53
|
+
fig.add_subplot(1, 3, 1)
|
|
54
|
+
Hx = numpy.transpose(solver.modes[0].get_field("Hx", x, y))
|
|
55
|
+
plt.contourf(x, y, abs(Hx), 50)
|
|
56
|
+
plt.title("Hx")
|
|
57
|
+
|
|
58
|
+
fig.add_subplot(1, 3, 2)
|
|
59
|
+
Hy = numpy.transpose(solver.modes[0].get_field("Hy", x, y))
|
|
60
|
+
plt.contourf(x, y, abs(Hy), 50)
|
|
61
|
+
plt.title("Hy")
|
|
62
|
+
|
|
63
|
+
fig.add_subplot(1, 3, 3)
|
|
64
|
+
Hz = numpy.transpose(solver.modes[0].get_field("Hz", x, y))
|
|
65
|
+
plt.contourf(x, y, abs(Hz), 50)
|
|
66
|
+
plt.title("Hz")
|
|
67
|
+
|
|
68
|
+
plt.show()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Fully vectorial finite-difference mode solver example."""
|
|
2
|
+
|
|
3
|
+
from matplotlib import pyplot as plt
|
|
4
|
+
|
|
5
|
+
import EMpy
|
|
6
|
+
|
|
7
|
+
mat1 = EMpy.materials.IsotropicMaterial(
|
|
8
|
+
"SiN", n0=EMpy.materials.RefractiveIndex(n0_const=1.97)
|
|
9
|
+
)
|
|
10
|
+
mat2 = EMpy.materials.IsotropicMaterial(
|
|
11
|
+
"Si", n0=EMpy.materials.RefractiveIndex(n0_const=3.4757)
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
l1 = EMpy.utils.Layer(mat1, 4.1e-6)
|
|
15
|
+
l21 = EMpy.utils.Layer(mat1, 2e-6)
|
|
16
|
+
l22 = EMpy.utils.Layer(mat2, 0.1e-6)
|
|
17
|
+
|
|
18
|
+
w = 0.5e-6
|
|
19
|
+
|
|
20
|
+
d = EMpy.utils.EMpy.utils.CrossSection(
|
|
21
|
+
[
|
|
22
|
+
EMpy.utils.Slice(2e-6, [l1]),
|
|
23
|
+
EMpy.utils.Slice(w, [l21, l22, l21]),
|
|
24
|
+
EMpy.utils.Slice(2e-6, [l1]),
|
|
25
|
+
]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
nx_points_per_region = (20, 10, 20)
|
|
29
|
+
ny_points_per_region = (20, 20, 20)
|
|
30
|
+
|
|
31
|
+
X, Y = d.grid(nx_points_per_region, ny_points_per_region)
|
|
32
|
+
eps = d.epsfunc(X, Y, 1.55e-6)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def epsfunc(x, y):
|
|
36
|
+
return d.epsfunc(x, y, wl)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
wl = 1.55e-6
|
|
40
|
+
|
|
41
|
+
neigs = 2
|
|
42
|
+
tol = 1e-8
|
|
43
|
+
boundary = "0000"
|
|
44
|
+
|
|
45
|
+
solver = EMpy.modesolvers.FD.VFDModeSolver(wl, X, Y, epsfunc, boundary).solve(
|
|
46
|
+
neigs, tol
|
|
47
|
+
)
|
|
48
|
+
fig = plt.figure()
|
|
49
|
+
fig.add_subplot(1, 3, 1)
|
|
50
|
+
plt.contourf(abs(solver.modes[0].Ex), 50)
|
|
51
|
+
plt.title("Ex")
|
|
52
|
+
fig.add_subplot(1, 3, 2)
|
|
53
|
+
plt.contourf(abs(solver.modes[0].Ey), 50)
|
|
54
|
+
plt.title("Ey")
|
|
55
|
+
fig.add_subplot(1, 3, 3)
|
|
56
|
+
plt.contourf(abs(solver.modes[0].Ez), 50)
|
|
57
|
+
plt.title("Ez")
|
|
58
|
+
plt.show()
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Fully vectorial finite-difference mode solver example."""
|
|
2
|
+
|
|
3
|
+
from matplotlib import pyplot as plt
|
|
4
|
+
import numpy
|
|
5
|
+
|
|
6
|
+
import EMpy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def epsfunc(x_, y_):
|
|
10
|
+
"""Similar to ex_modesolver.py, but using anisotropic eps."""
|
|
11
|
+
eps = numpy.zeros((len(x_), len(y_), 5))
|
|
12
|
+
for ix, xx in enumerate(x_):
|
|
13
|
+
for iy, yy in enumerate(y_):
|
|
14
|
+
if abs(xx - 1.24e-6) <= 0.24e-6 and abs(yy - 1.11e-6) <= 0.11e-6:
|
|
15
|
+
a = 3.4757**2
|
|
16
|
+
b = 1 # some xy value
|
|
17
|
+
# eps_xx, xy, yx, yy, zz
|
|
18
|
+
eps[ix, iy, :] = [a, b, b, a, a]
|
|
19
|
+
else:
|
|
20
|
+
a = 1.446**2
|
|
21
|
+
# isotropic
|
|
22
|
+
eps[ix, iy, :] = [a, 0, 0, a, a]
|
|
23
|
+
return eps
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
wl = 1.55e-6
|
|
27
|
+
x = numpy.linspace(0, 2.48e-6, 125)
|
|
28
|
+
y = numpy.linspace(0, 2.22e-6, 112)
|
|
29
|
+
|
|
30
|
+
neigs = 2
|
|
31
|
+
tol = 1e-8
|
|
32
|
+
boundary = "0000"
|
|
33
|
+
|
|
34
|
+
solver = EMpy.modesolvers.FD.VFDModeSolver(wl, x, y, epsfunc, boundary).solve(
|
|
35
|
+
neigs, tol
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
fig = plt.figure()
|
|
39
|
+
fig.add_subplot(1, 3, 1)
|
|
40
|
+
plt.contourf(abs(solver.modes[0].Ex), 50)
|
|
41
|
+
plt.title("Ex")
|
|
42
|
+
fig.add_subplot(1, 3, 2)
|
|
43
|
+
plt.contourf(abs(solver.modes[0].Ey), 50)
|
|
44
|
+
plt.title("Ey")
|
|
45
|
+
fig.add_subplot(1, 3, 3)
|
|
46
|
+
plt.contourf(abs(solver.modes[0].Ez), 50)
|
|
47
|
+
plt.title("Ez")
|
|
48
|
+
plt.show()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Semi-vectorial finite-difference mode solver example."""
|
|
2
|
+
|
|
3
|
+
from matplotlib import pyplot as plt
|
|
4
|
+
import numpy
|
|
5
|
+
|
|
6
|
+
import EMpy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def epsfunc(x_, y_):
|
|
10
|
+
"""Return a matrix describing a 2d material.
|
|
11
|
+
|
|
12
|
+
:param x_: x values
|
|
13
|
+
:param y_: y values
|
|
14
|
+
:return: 2d-matrix
|
|
15
|
+
"""
|
|
16
|
+
xx, yy = numpy.meshgrid(x_, y_)
|
|
17
|
+
return numpy.where(
|
|
18
|
+
(numpy.abs(xx.T - 1.24e-6) <= 0.24e-6) * (numpy.abs(yy.T - 1.11e-6) <= 0.11e-6),
|
|
19
|
+
3.4757**2,
|
|
20
|
+
1.446**2,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
wl = 1.55e-6
|
|
25
|
+
x = numpy.linspace(0, 2.48e-6, 125)
|
|
26
|
+
y = numpy.linspace(0, 2.22e-6, 112)
|
|
27
|
+
|
|
28
|
+
neigs = 2
|
|
29
|
+
tol = 1e-8
|
|
30
|
+
boundary = "0000"
|
|
31
|
+
|
|
32
|
+
solver = EMpy.modesolvers.FD.SVFDModeSolver(wl, x, y, epsfunc, boundary).solve(
|
|
33
|
+
neigs, tol
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
fig = plt.figure()
|
|
37
|
+
fig.add_subplot(1, 2, 1)
|
|
38
|
+
plt.contourf(abs(solver.Ex[0]), 50)
|
|
39
|
+
plt.title("Ex first mode")
|
|
40
|
+
fig.add_subplot(1, 2, 2)
|
|
41
|
+
plt.contourf(abs(solver.Ex[1]), 50)
|
|
42
|
+
plt.title("Ex second mode")
|
|
43
|
+
plt.show()
|