Files
modeconverter/unit_cell/unit_cell_param_sweep.py

204 lines
5.7 KiB
Python

import meep as mp
mp.verbosity(0)
import numpy as np
import matplotlib.pyplot as plt
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()
resolution = 50 # pixels/unit length
wvl_min = 1.5
wvl_max = 1.6
wvl_cen = 0.5*(wvl_min+wvl_max)
fmin = 1/wvl_max
fmax = 1/wvl_min
fcen = 1/wvl_cen
df = fmax-fmin
nfreq = 20
dpml = 1.0 #PML thickness
dsub = 1.5 + wvl_cen #substrate thickness
dpad = dsub #padding between cell and PML
k_point = mp.Vector3(0,0,0) #used for PBC
n_si = 3.45 #silicon refractive index
si = mp.Medium(index=n_si)
n_sio2 = 1.45
sio2 = mp.Medium(index=n_sio2)
n_air = 1.0 #air refractive index
air = mp.Medium(index=n_air)
P = 0.7 #unit cell pitch
h = 0.9 #pillar height
def unitCell_paramsweep(D):
print("Rank {}: Running simulation for diameter {}".format(rank, D))
sim_x_size = dpml + dsub + dpad + dpml
sim_z_size = P
sim_y_size = P
cell_size = mp.Vector3(sim_x_size, sim_y_size, sim_z_size)
source_position = mp.Vector3(-wvl_cen,0,0) #source position in the middle of the substrate
source = mp.Source(
mp.GaussianSource(fcen, fwidth=df),
component = mp.Ez,
center = source_position,
size = mp.Vector3(0, sim_y_size, sim_z_size),
)
pml_layers = [mp.PML(dpml,direction=mp.X)]
monitor_position = mp.Vector3(h + wvl_cen,0,0)
obs_point = monitor_position
stop_cond = mp.stop_when_fields_decayed(50, mp.Ez, obs_point, 1e-9)
#stop_cond = 10
sim = mp.Simulation(
resolution = resolution,
cell_size = cell_size,
boundary_layers = pml_layers,
k_point = k_point,
default_material = sio2,
sources = [source],
)
flux_mon = sim.add_flux(
fcen,
df,
nfreq,
mp.FluxRegion(center=monitor_position, size=mp.Vector3(0, sim_y_size, sim_z_size))
)
sim.run(until_after_sources=stop_cond)
input_flux = mp.get_fluxes(flux_mon)
sim.reset_meep()
pillar_geo = mp.Cylinder(
material = si,
radius = D/2,
height = h,
center = mp.Vector3(h/2,0,0),
axis=mp.Vector3(1,0,0),
)
substrate_geo = mp.Block(
material = sio2,
size = mp.Vector3(dsub+dpml, mp.inf, mp.inf),
center = mp.Vector3(-(dsub+dpml)/2,0,0),
)
geometries = [substrate_geo, pillar_geo]
sim = mp.Simulation(
resolution = resolution,
cell_size = cell_size,
boundary_layers = pml_layers,
geometry = geometries,
k_point = k_point,
sources = [source],
)
mode_mon = sim.add_flux(
fcen, df, nfreq, mp.FluxRegion(center=monitor_position, size=mp.Vector3(0, sim_y_size, sim_z_size))
)
sim.run(until_after_sources=stop_cond)
freqs = mp.get_eigenmode_freqs(mode_mon)
res = sim.get_eigenmode_coefficients(
mode_mon, [1], eig_parity=mp.ODD_Z + mp.EVEN_Y
)
coeffs = res.alpha
mode_wvl = [1/freqs[nf] for nf in range(nfreq)]
mode_tran = [abs(coeffs[0,nf,0])**2 / input_flux[nf] for nf in range(nfreq)]
mode_phase = [np.angle(coeffs[0,nf,0]) for nf in range(nfreq)]
return mode_wvl, mode_tran, mode_phase
if rank == 0:
diameters = np.linspace(0.1, 0.6, 24)
else:
diameters = None
diameters = comm.bcast(diameters, root=0)
local_diameters = np.array_split(diameters, size)[rank]
local_indices = np.array_split(np.arange(len(diameters)), size)[rank]
local_mode_tran_arr = np.zeros((len(diameters), nfreq))
local_mode_phase_arr = np.zeros((len(diameters), nfreq))
for local_i, (global_i, D) in enumerate(zip(local_indices,local_diameters)):
mode_wvl, mode_tran, mode_phase = unitCell_paramsweep(D)
local_mode_tran_arr[global_i,:] = mode_tran
local_mode_phase_arr[global_i,:] = mode_phase
mode_tran_arr = comm.gather(local_mode_tran_arr, root=0)
mode_phase_arr = comm.gather(local_mode_phase_arr, root=0)
if rank == 0:
final_mode_tran_arr = np.zeros((len(diameters), nfreq))
final_mode_phase_arr = np.zeros((len(diameters), nfreq))
num_diameters_per_rank = len(diameters) // size
for i in range(0, size):
for j in range(num_diameters_per_rank):
global_index = i * num_diameters_per_rank + j
final_mode_tran_arr[global_index, :] = mode_tran_arr[i][global_index, :]
final_mode_phase_arr[global_index, :] = mode_phase_arr[i][global_index, :]
np.save("unit_cell_param_sweep_diameters.npy", diameters)
np.save("unit_cell_param_sweep_mode_wvl.npy", mode_wvl)
np.save("unit_cell_param_sweep_mode_tran.npy", final_mode_tran_arr)
np.save("unit_cell_param_sweep_mode_phase.npy", final_mode_phase_arr)
plt.figure()
plt.subplot(1,2,1)
plt.pcolormesh(
mode_wvl,
diameters,
final_mode_tran_arr,
cmap='hot_r',
shading='gouraud',
vmin=0,
vmax=final_mode_tran_arr.max(),
)
plt.axis([wvl_min, wvl_max, diameters[0], diameters[-1]])
plt.xlabel("Wavelength (um)")
plt.xticks([t for t in np.linspace(wvl_min, wvl_max, 3)])
plt.ylabel("Pillar Diameter (um)")
plt.title("Transmission")
cbar=plt.colorbar()
cbar.set_ticks([t for t in np.arange(0, 1.2, 0.2)])
plt.subplot(1,2,2)
plt.pcolormesh(
mode_wvl,
diameters,
final_mode_phase_arr,
cmap='RdBu',
shading='gouraud',
vmin=final_mode_phase_arr.min(),
vmax=final_mode_phase_arr.max(),
)
plt.axis([wvl_min, wvl_max, diameters[0], diameters[-1]])
plt.xlabel("Wavelength (um)")
plt.xticks([t for t in np.linspace(wvl_min, wvl_max, 3)])
plt.ylabel("Pillar Diameter (um)")
plt.title("phase")
cbar=plt.colorbar()
cbar.set_ticks([t for t in np.arange(-3, 4, 1)])
plt.subplots_adjust(wspace=0.5)
plt.savefig("unit_cell_param_sweep.pdf")