1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
import math
import matplotlib.pyplot as plt
import numpy as np
import meep as mp
# True: plot the scattered fields in the extended air region adjacent to the grating
# False: plot the diffraction spectra based on a 1d cross section of the scattered fields
field_profile = True
resolution = 50 # pixels/μm
dpml = 1.0 # PML thickness
dsub = 2.0 # substrate thickness
dpad = 1.0 # flat-surface padding
gp = 1.0 # grating periodicity
gh = 0.5 # grating height
gdc = 0.5 # grating duty cycle
num_cells = 5 # number of grating unit cells
# air region thickness adjacent to grating
dair = 10 if field_profile else dpad
wvl = 0.5 # center wavelength
fcen = 1 / wvl # center frequency
k_point = mp.Vector3()
glass = mp.Medium(index=1.5)
pml_layers = [mp.PML(thickness=dpml)]
symmetries = [mp.Mirror(mp.Y)]
sx = dpml + dsub + gh + dair + dpml
sy = dpml + dpad + num_cells * gp + dpad + dpml
cell_size = mp.Vector3(sx, sy)
src_pt = mp.Vector3(-0.5 * sx + dpml + 0.5 * dsub)
sources = [
mp.Source(
mp.GaussianSource(fcen, fwidth=0.2 * fcen, is_integrated=True),
component=mp.Ez,
center=src_pt,
size=mp.Vector3(y=sy),
)
]
geometry = [
mp.Block(
material=glass,
size=mp.Vector3(dpml + dsub, mp.inf, mp.inf),
center=mp.Vector3(-0.5 * sx + 0.5 * (dpml + dsub)),
)
]
sim = mp.Simulation(
resolution=resolution,
cell_size=cell_size,
boundary_layers=pml_layers,
geometry=geometry,
k_point=k_point,
sources=sources,
symmetries=symmetries,
)
mon_pt = mp.Vector3(0.5 * sx - dpml - 0.5 * dair)
near_fields = sim.add_dft_fields(
[mp.Ez],
fcen,
0,
1,
center=mon_pt,
size=mp.Vector3(dair if field_profile else 0, sy - 2 * dpml),
)
sim.run(until_after_sources=100)
flat_dft = sim.get_dft_array(near_fields, mp.Ez, 0)
sim.reset_meep()
geometry.extend(
mp.Block(
material=glass,
size=mp.Vector3(gh, gdc * gp, mp.inf),
center=mp.Vector3(
-0.5 * sx + dpml + dsub + 0.5 * gh, -0.5 * sy + dpml + dpad + (j + 0.5) * gp
),
)
for j in range(num_cells)
)
sim = mp.Simulation(
resolution=resolution,
cell_size=cell_size,
boundary_layers=pml_layers,
geometry=geometry,
k_point=k_point,
sources=sources,
symmetries=symmetries,
)
near_fields = sim.add_dft_fields(
[mp.Ez],
fcen,
0,
1,
center=mon_pt,
size=mp.Vector3(dair if field_profile else 0, sy - 2 * dpml),
)
sim.run(until_after_sources=100)
grating_dft = sim.get_dft_array(near_fields, mp.Ez, 0)
scattered_field = grating_dft - flat_dft
scattered_amplitude = np.abs(scattered_field) ** 2
[x, y, z, w] = sim.get_array_metadata(dft_cell=near_fields)
if field_profile:
if mp.am_master():
plt.figure(dpi=150)
plt.pcolormesh(
x,
y,
np.rot90(scattered_amplitude),
cmap="inferno",
shading="gouraud",
vmin=0,
vmax=scattered_amplitude.max(),
)
plt.gca().set_aspect("equal")
plt.xlabel("x (μm)")
plt.ylabel("y (μm)")
# ensure that the height of the colobar matches that of the plot
from mpl_toolkits.axes_grid1 import make_axes_locatable
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(cax=cax)
plt.tight_layout()
plt.show()
else:
ky = np.fft.fftshift(np.fft.fftfreq(len(scattered_field), 1 / resolution))
FT_scattered_field = np.fft.fftshift(np.fft.fft(scattered_field))
if mp.am_master():
plt.figure(dpi=150)
plt.subplots_adjust(hspace=0.3)
plt.subplot(2, 1, 1)
plt.plot(y, scattered_amplitude, "bo-")
plt.xlabel("y (μm)")
plt.ylabel("field amplitude")
plt.subplot(2, 1, 2)
plt.plot(ky, np.abs(FT_scattered_field) ** 2, "ro-")
plt.gca().ticklabel_format(axis="y", style="sci", scilimits=(0, 0))
plt.xlabel(r"wavevector k$_y$, 2π (μm)$^{-1}$")
plt.ylabel("Fourier transform")
plt.gca().set_xlim([-3, 3])
plt.tight_layout(pad=1.0)
plt.show()
|