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
|
import meep as mp
import os
import argparse
resolution = 25 # pixels/um
examples_dir = os.path.realpath(os.path.dirname(__file__))
gdsII_file = os.path.join(examples_dir, 'coupler.gds')
CELL_LAYER = 0
PORT1_LAYER = 1
PORT2_LAYER = 2
PORT3_LAYER = 3
PORT4_LAYER = 4
SOURCE_LAYER = 5
UPPER_BRANCH_LAYER = 31
LOWER_BRANCH_LAYER = 32
default_d = 0.3
t_oxide = 1.0
t_Si = 0.22
t_air = 0.78
eps_oxide = 2.25
oxide = mp.Medium(epsilon=eps_oxide)
eps_silicon = 12
silicon=mp.Medium(epsilon=eps_silicon)
dpml = 1
lcen = 1.55
fcen = 1/lcen
df = 0.2*fcen
def main(args):
d = args.d
cell_thickness = dpml+t_oxide+t_Si+t_air+dpml
cell_zmax = 0.5*cell_thickness if args.three_d else 0
cell_zmin = -0.5*cell_thickness if args.three_d else 0
si_zmin = 0
si_zmax = t_Si if args.three_d else 0
# read cell size, volumes for source region and flux monitors,
# and coupler geometry from GDSII file
upper_branch = mp.get_GDSII_prisms(silicon, gdsII_file, UPPER_BRANCH_LAYER, si_zmin, si_zmax)
lower_branch = mp.get_GDSII_prisms(silicon, gdsII_file, LOWER_BRANCH_LAYER, si_zmin, si_zmax)
cell = mp.GDSII_vol(gdsII_file, CELL_LAYER, cell_zmin, cell_zmax)
p1 = mp.GDSII_vol(gdsII_file, PORT1_LAYER, si_zmin, si_zmax)
p2 = mp.GDSII_vol(gdsII_file, PORT2_LAYER, si_zmin, si_zmax)
p3 = mp.GDSII_vol(gdsII_file, PORT3_LAYER, si_zmin, si_zmax)
p4 = mp.GDSII_vol(gdsII_file, PORT4_LAYER, si_zmin, si_zmax)
src_vol = mp.GDSII_vol(gdsII_file, SOURCE_LAYER, si_zmin, si_zmax)
# displace upper and lower branches of coupler (as well as source and flux regions)
if d != default_d:
delta_y = 0.5*(d-default_d)
delta = mp.Vector3(y=delta_y)
p1.center += delta
p2.center -= delta
p3.center += delta
p4.center -= delta
src_vol.center += delta
cell.size += 2*delta
for np in range(len(lower_branch)):
lower_branch[np].center -= delta
for nv in range(len(lower_branch[np].vertices)):
lower_branch[np].vertices[nv] -= delta
for np in range(len(upper_branch)):
upper_branch[np].center += delta
for nv in range(len(upper_branch[np].vertices)):
upper_branch[np].vertices[nv] += delta
geometry = upper_branch+lower_branch
if args.three_d:
oxide_center = mp.Vector3(z=-0.5*t_oxide)
oxide_size = mp.Vector3(cell.size.x,cell.size.y,t_oxide)
oxide_layer = [mp.Block(material=oxide, center=oxide_center, size=oxide_size)]
geometry = geometry+oxide_layer
sources = [mp.EigenModeSource(src=mp.GaussianSource(fcen,fwidth=df),
size=src_vol.size,
center=src_vol.center,
eig_match_freq=True)]
sim = mp.Simulation(resolution=resolution,
cell_size=cell.size,
boundary_layers=[mp.PML(dpml)],
sources=sources,
geometry=geometry)
p1_region = mp.FluxRegion(volume=p1)
flux1 = sim.add_flux(fcen,0,1,p1_region)
p2_region = mp.FluxRegion(volume=p2)
flux2 = sim.add_flux(fcen,0,1,p2_region)
p3_region = mp.FluxRegion(volume=p3)
flux3 = sim.add_flux(fcen,0,1,p3_region)
p4_region = mp.FluxRegion(volume=p4)
flux4 = sim.add_flux(fcen,0,1,p4_region)
sim.run(until_after_sources=mp.stop_when_fields_decayed(50,mp.Ez,p3.center,1e-9))
p1_flux = mp.get_fluxes(flux1)
p2_flux = mp.get_fluxes(flux2)
p3_flux = mp.get_fluxes(flux3)
p4_flux = mp.get_fluxes(flux4)
mp.master_printf("data:, {}, {}, {}, {}".format(d,-p2_flux[0]/p1_flux[0],p3_flux[0]/p1_flux[0],p4_flux[0]/p1_flux[0]))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-d',type=float,default=0.1,help='branch separation (default: 0.1 um)')
parser.add_argument('--three_d',action='store_true',default=False,help='3d calculation? (default: False)')
args = parser.parse_args()
main(args)
|