def _test_1d(self, sym): # A z=30 cell, split into three fragments of size 10 each, with a block # covering the middle fragment. # flux covering first fragment, near2far covering second, force covering third dft_vecs = make_dft_vecs( [mp.FluxRegion(mp.Vector3(z=-10), size=mp.Vector3(z=10))], [mp.Near2FarRegion(mp.Vector3(), size=mp.Vector3(z=10))], [mp.ForceRegion(mp.Vector3(z=10), direction=mp.X, size=mp.Vector3(z=10))] ) fs = self.get_fragment_stats(mp.Vector3(z=10), mp.Vector3(z=30), 1, dft_vecs=dft_vecs, sym=sym) self.assertEqual(len(fs), 3) # First and last fragments have no geometry, only default_material for i in [0, 2]: self.check_stats(fs[i], 0, 0, 0, 0, 0) # Second fragment contains entire block sym_factor = 2 if sym else 1 self.check_stats(fs[1], a_eps=100 / sym_factor, a_mu=100 / sym_factor, nonlin=300 / sym_factor, susc=300 / sym_factor, cond=300 / sym_factor) # Check DFT regions self.assertEqual(fs[0].num_dft_pixels, 10240) self.assertEqual(fs[1].num_dft_pixels, 17120) self.assertEqual(fs[2].num_dft_pixels, 23840)
def _test_1d(self, sym, pml=[]): # A z=30 cell, with a size 10 block in the middle. # flux covering first 10 units, near2far covering second 10, and force covering third dft_vecs = make_dft_vecs( [mp.FluxRegion(mp.Vector3(z=-10), size=mp.Vector3(z=10))], [mp.Near2FarRegion(mp.Vector3(), size=mp.Vector3(z=10))], [ mp.ForceRegion( mp.Vector3(z=10), direction=mp.X, size=mp.Vector3(z=10)) ]) fs = self.get_fragment_stats(mp.Vector3(z=10), mp.Vector3(z=30), 1, dft_vecs=dft_vecs, sym=sym, pml=pml) sym_factor = 2 if sym else 1 self.check_stats(fs, a_eps=100 / sym_factor, a_mu=100 / sym_factor, nonlin=300 / sym_factor, susc=300 / sym_factor, cond=300 / sym_factor) # Check DFT regions self.assertEqual(fs.num_dft_pixels, 40800) self.fs = fs
def _test_3d(self, sym): # A 30 x 30 x 30 cell with a 10 x 10 x 10 block placed at the center, split # into 27 10 x 10 x 10 fragments # flux covering lower-front-left fragment, near2far covering lower-middle-left, # force covering lower-back-left dft_vecs = make_dft_vecs( [mp.FluxRegion(mp.Vector3(-10, -10, -10), size=mp.Vector3(10, 10, 10))], [mp.Near2FarRegion(mp.Vector3(-10, -10, 0), size=mp.Vector3(10, 10, 10))], [mp.ForceRegion(mp.Vector3(-10, -10, 10), direction=mp.X, size=mp.Vector3(10, 10, 10))] ) fs = self.get_fragment_stats(mp.Vector3(10, 10, 10), mp.Vector3(30, 30, 30), 3, dft_vecs=dft_vecs, sym=sym) self.assertEqual(len(fs), 27) # All fragments besides the middle one have no geometry, only default_material for i in range(27): if i == 13: continue self.check_stats(fs[i], 0, 0, 0, 0, 0) # Middle fragments contains entire block idx = 13 sym_factor = 8 if sym else 1 self.check_stats(fs[idx], a_eps=10000 / sym_factor, a_mu=10000 / sym_factor, nonlin=30000 / sym_factor, susc=30000 / sym_factor, cond=30000 / sym_factor) # Check DFT regions self.assertEqual(fs[0].num_dft_pixels, 256000) self.assertEqual(fs[1].num_dft_pixels, 428000) self.assertEqual(fs[2].num_dft_pixels, 596000)
def setUp(self): resolution = 20 cell = mp.Vector3(10, 10) pml_layers = mp.PML(1.0) fcen = 1.0 df = 1.0 sources = mp.Source(src=mp.GaussianSource(fcen, fwidth=df), center=mp.Vector3(), component=mp.Ez) self.sim = mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=[pml_layers], sources=[sources]) fr = mp.ForceRegion(mp.Vector3(y=1.27), direction=mp.Y, size=mp.Vector3(4.38)) self.myforce = self.sim.add_force(fcen, 0, 1, fr, decimation_factor=1) self.myforce_decimated = self.sim.add_force(fcen, 0, 1, fr, decimation_factor=10)
def _test_2d(self, sym): # A 30 x 30 cell, with a 10 x 10 block in the middle, split into 9 10 x 10 fragments. # flux covering top-left fragment, near2far covering top-middle, force covering top-right dft_vecs = make_dft_vecs( [mp.FluxRegion(mp.Vector3(-10, 10), size=mp.Vector3(10, 10))], [mp.Near2FarRegion(mp.Vector3(0, 10), size=mp.Vector3(10, 10))], [ mp.ForceRegion(mp.Vector3(10, 10), direction=mp.X, size=mp.Vector3(10, 10)) ]) fs = self.get_fragment_stats(mp.Vector3(10, 10), mp.Vector3(30, 30), 2, dft_vecs=dft_vecs, sym=sym) self.assertEqual(len(fs), 9) # Check fragment boxes self.assertEqual(fs[0].box.low.x, -15) self.assertEqual(fs[0].box.low.y, -15) self.assertEqual(fs[0].box.high.x, -5) self.assertEqual(fs[0].box.high.y, -5) self.assertEqual(fs[1].box.low.x, -15) self.assertEqual(fs[1].box.low.y, -5) self.assertEqual(fs[1].box.high.x, -5) self.assertEqual(fs[1].box.high.y, 5) self.assertEqual(fs[2].box.low.x, -15) self.assertEqual(fs[2].box.low.y, 5) self.assertEqual(fs[2].box.high.x, -5) self.assertEqual(fs[2].box.high.y, 15) # All fragments besides the middle one have no geometry, only default_material for i in [0, 1, 2, 3, 5, 6, 7, 8]: self.check_stats(fs[i], 0, 0, 0, 0, 0) # Middle fragment contains entire block idx = 4 sym_factor = 4 if sym else 1 self.check_stats(fs[idx], a_eps=10000 / sym_factor, a_mu=10000 / sym_factor, nonlin=30000 / sym_factor, susc=30000 / sym_factor, cond=30000 / sym_factor) # Check DFT regions for i in [0, 3, 6]: self.assertEqual(fs[i].num_dft_pixels, 0) self.assertEqual(fs[1].num_dft_pixels, 8224) self.assertEqual(fs[4].num_dft_pixels, 11792) self.assertEqual(fs[7].num_dft_pixels, 21824) self.assertEqual(fs[2].num_dft_pixels, 411200) self.assertEqual(fs[5].num_dft_pixels, 589600) self.assertEqual(fs[8].num_dft_pixels, 1091200)
def _test_3d(self, sym, pml=[]): # A 30 x 30 x 30 cell with a 10 x 10 x 10 block placed at the center # flux covering lower-front-left 10x10x10, near2far covering lower-middle-left, # force covering lower-back-left dft_vecs = make_dft_vecs([ mp.FluxRegion(mp.Vector3(-10, -10, -10), size=mp.Vector3(10, 10, 10)) ], [ mp.Near2FarRegion(mp.Vector3(-10, -10, 0), size=mp.Vector3(10, 10, 10)) ], [ mp.ForceRegion(mp.Vector3(-10, -10, 10), direction=mp.X, size=mp.Vector3(10, 10, 10)) ]) fs = self.get_fragment_stats(mp.Vector3(10, 10, 10), mp.Vector3(30, 30, 30), 3, dft_vecs=dft_vecs, sym=sym, pml=pml) sym_factor = 8 if sym else 1 self.check_stats(fs, a_eps=1000000 / sym_factor, a_mu=1000000 / sym_factor, nonlin=3000000 / sym_factor, susc=3000000 / sym_factor, cond=3000000 / sym_factor) # Check DFT regions self.assertEqual(fs.num_dft_pixels, 102000000) self.fs = fs
def test_cyl(self): # A 30 x 30 cell, with a 10 x 10 block in the middle # flux covering top-left fragment, near2far covering top-middle, force covering top-right dft_vecs = make_dft_vecs([ mp.FluxRegion(mp.Vector3(-10, z=10), size=mp.Vector3(10, z=10)) ], [mp.Near2FarRegion(mp.Vector3(0, z=10), size=mp.Vector3(10, z=10))], [ mp.ForceRegion(mp.Vector3(10, z=10), direction=mp.X, size=mp.Vector3(10, z=10)) ]) fs = self.get_fragment_stats(mp.Vector3(10, 0, 10), mp.Vector3(30, 0, 30), mp.CYLINDRICAL, dft_vecs=dft_vecs) self.assertEqual(fs.box.low.x, -15) self.assertEqual(fs.box.low.z, -15) self.assertEqual(fs.box.high.x, 15) self.assertEqual(fs.box.high.z, 15) self.check_stats(fs, a_eps=10000, a_mu=10000, nonlin=30000, susc=30000, cond=30000) self.assertEqual(fs.num_dft_pixels, 2040000)
def _test_2d(self, sym, pml=[]): # A 30 x 30 cell, with a 10 x 10 block in the middle # flux covering top-left 10x10, near2far covering top-middle 10x10, force covering top-right dft_vecs = make_dft_vecs( [mp.FluxRegion(mp.Vector3(-10, 10), size=mp.Vector3(10, 10))], [mp.Near2FarRegion(mp.Vector3(0, 10), size=mp.Vector3(10, 10))], [mp.ForceRegion(mp.Vector3(10, 10), direction=mp.X, size=mp.Vector3(10, 10))] ) fs = self.get_fragment_stats(mp.Vector3(10, 10), mp.Vector3(30, 30), 2, dft_vecs=dft_vecs, sym=sym, pml=pml) # Check fragment boxes self.assertEqual(fs.box.low.x, -15) self.assertEqual(fs.box.low.y, -15) self.assertEqual(fs.box.high.x, 15) self.assertEqual(fs.box.high.y, 15) # Middle fragment contains entire block sym_factor = 4 if sym else 1 self.check_stats(fs, a_eps=90000 / sym_factor, a_mu=90000 / sym_factor, nonlin=30000 / sym_factor, susc=30000 / sym_factor, cond=30000 / sym_factor) # Check DFT regions self.assertEqual(fs.num_dft_pixels, 2040000) self.fs = fs
def test_cyl(self): # A 30 x 30 cell, with a 10 x 10 block in the middle, split into 9 10 x 10 fragments. # flux covering top-left fragment, near2far covering top-middle, force covering top-right dft_vecs = make_dft_vecs([ mp.FluxRegion(mp.Vector3(-10, z=10), size=mp.Vector3(10, z=10)) ], [mp.Near2FarRegion(mp.Vector3(0, z=10), size=mp.Vector3(10, z=10))], [ mp.ForceRegion(mp.Vector3(10, z=10), mp.X, size=mp.Vector3(10, z=10)) ]) fs = self.get_fragment_stats(mp.Vector3(10, 0, 10), mp.Vector3(30, 0, 30), mp.CYLINDRICAL, dft_vecs=dft_vecs) self.assertEqual(len(fs), 9) # Check fragment boxes self.assertEqual(fs[0].box.low.x, -15) self.assertEqual(fs[0].box.low.z, -15) self.assertEqual(fs[0].box.high.x, -5) self.assertEqual(fs[0].box.high.z, -5) self.assertEqual(fs[1].box.low.x, -15) self.assertEqual(fs[1].box.low.z, -5) self.assertEqual(fs[1].box.high.x, -5) self.assertEqual(fs[1].box.high.z, 5) self.assertEqual(fs[2].box.low.x, -15) self.assertEqual(fs[2].box.low.z, 5) self.assertEqual(fs[2].box.high.x, -5) self.assertEqual(fs[2].box.high.z, 15) # All fragments besides the middle one have no geometry, only default_material for i in [0, 1, 2, 3, 5, 6, 7, 8]: self.check_stats(fs[i], 0, 0, 0, 0, 0) # Middle fragment contains entire block idx = 4 self.check_stats(fs[idx], a_eps=1000, a_mu=1000, nonlin=3000, susc=3000, cond=3000) # Check DFT regions for i in [0, 3, 6]: self.assertEqual(fs[i].num_dft_pixels, 0) self.assertEqual(fs[1].num_dft_pixels, 10240) self.assertEqual(fs[4].num_dft_pixels, 17120) self.assertEqual(fs[7].num_dft_pixels, 23840) self.assertEqual(fs[2].num_dft_pixels, 51200) self.assertEqual(fs[5].num_dft_pixels, 85600) self.assertEqual(fs[8].num_dft_pixels, 119200)
def force_box_2d(position, size, component): """create 4 force planes (2D) to calculate the component of a force""" force_x1 = meep.ForceRegion(center=position - meep.Vector3(0, size[1] / 2), size=meep.Vector3(size[0], 0), direction=component, weight=-1) force_x2 = meep.ForceRegion(center=position + meep.Vector3(0, size[1] / 2), size=meep.Vector3(size[0], 0), direction=component, weight=1) force_y1 = meep.ForceRegion(center=position - meep.Vector3(size[0] / 2, 0), size=meep.Vector3(0, size[1]), direction=component, weight=-1) force_y2 = meep.ForceRegion(center=position + meep.Vector3(size[0] / 2, 0), size=meep.Vector3(0, size[1]), direction=component, weight=1) return [force_x1, force_x2, force_y1, force_y2]
def force_box(position, size, component): """create 6 force planes to calculate the component of a force""" position = meep.Vector3(*position) size = meep.Vector3(*size) force_x1 = meep.ForceRegion(center=position - meep.Vector3(size[0] / 2, 0, 0), size=meep.Vector3(0, size[1], size[2]), weight=-1, direction=component) force_x2 = meep.ForceRegion(center=position + meep.Vector3(size[0] / 2, 0, 0), size=meep.Vector3(0, size[1], size[2]), weight=1, direction=component) force_y1 = meep.ForceRegion(center=position - meep.Vector3(0, size[1] / 2, 0), size=meep.Vector3(size[0], 0, size[2]), weight=-1, direction=component) force_y2 = meep.ForceRegion(center=position + meep.Vector3(0, size[1] / 2, 0), size=meep.Vector3(size[0], 0, size[2]), weight=1, direction=component) force_z1 = meep.ForceRegion(center=position - meep.Vector3(0, 0, size[2] / 2), size=meep.Vector3(size[0], size[1], 0), weight=-1, direction=component) force_z2 = meep.ForceRegion(center=position + meep.Vector3(0, 0, size[2] / 2), size=meep.Vector3(size[0], size[1], 0), weight=1, direction=component) return [force_x1, force_x2, force_y1, force_y2, force_z1, force_z2]
def main(args): resolution = 30 # pixels/μm Si = mp.Medium(index=3.45) dpml = 1.0 pml_layers = [mp.PML(dpml)] sx = 5 sy = 3 cell = mp.Vector3(sx + 2 * dpml, sy + 2 * dpml, 0) a = 1.0 # waveguide width s = args.s # waveguide separation distance geometry = [ mp.Block(center=mp.Vector3(-0.5 * (s + a)), size=mp.Vector3(a, a, mp.inf), material=Si), mp.Block(center=mp.Vector3(0.5 * (s + a)), size=mp.Vector3(a, a, mp.inf), material=Si) ] xodd = args.xodd symmetries = [ mp.Mirror(mp.X, phase=-1.0 if xodd else 1.0), mp.Mirror(mp.Y, phase=-1.0) ] k_point = mp.Vector3(z=0.5) fcen = 0.22 df = 0.06 sources = [ mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Ey, center=mp.Vector3(-0.5 * (s + a)), size=mp.Vector3(a, a)), mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Ey, center=mp.Vector3(0.5 * (s + a)), size=mp.Vector3(a, a), amplitude=-1.0 if xodd else 1.0) ] sim = mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=pml_layers, geometry=geometry, symmetries=symmetries, k_point=k_point, sources=sources) h = mp.Harminv(mp.Ey, mp.Vector3(0.5 * (s + a)), fcen, df) sim.run(mp.after_sources(h), until_after_sources=200) f = h.modes[0].freq print("freq:, {}, {}".format(s, f)) sim.reset_meep() eig_sources = [ mp.EigenModeSource(src=mp.GaussianSource(f, fwidth=df), size=mp.Vector3(a, a), center=mp.Vector3(-0.5 * (s + a)), eig_kpoint=k_point, eig_match_freq=True, eig_parity=mp.ODD_Y), mp.EigenModeSource(src=mp.GaussianSource(f, fwidth=df), size=mp.Vector3(a, a), center=mp.Vector3(0.5 * (s + a)), eig_kpoint=k_point, eig_match_freq=True, eig_parity=mp.ODD_Y, amplitude=-1.0 if xodd else 1.0) ] sim.change_sources(eig_sources) flux_reg = mp.FluxRegion(direction=mp.Z, center=mp.Vector3(), size=mp.Vector3(1.2 * (2 * a + s), 1.2 * a)) wvg_flux = sim.add_flux(f, 0, 1, flux_reg) force_reg1 = mp.ForceRegion(mp.Vector3(0.5 * s), direction=mp.X, weight=1.0, size=mp.Vector3(y=a)) force_reg2 = mp.ForceRegion(mp.Vector3(0.5 * s + a), direction=mp.X, weight=-1.0, size=mp.Vector3(y=a)) wvg_force = sim.add_force(f, 0, 1, force_reg1, force_reg2) sim.run(until_after_sources=5000) sim.display_fluxes(wvg_flux) sim.display_forces(wvg_force)
def parallel_waveguide(s, xodd): geometry = [ mp.Block(center=mp.Vector3(-0.5 * (s + a)), size=mp.Vector3(a, a, mp.inf), material=Si), mp.Block(center=mp.Vector3(0.5 * (s + a)), size=mp.Vector3(a, a, mp.inf), material=Si) ] symmetries = [ mp.Mirror(mp.X, phase=-1.0 if xodd else 1.0), mp.Mirror(mp.Y, phase=-1.0) ] sources = [ mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Ey, center=mp.Vector3(-0.5 * (s + a)), size=mp.Vector3(a, a)), mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Ey, center=mp.Vector3(0.5 * (s + a)), size=mp.Vector3(a, a), amplitude=-1.0 if xodd else 1.0) ] sim = mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=pml_layers, geometry=geometry, symmetries=symmetries, k_point=k_point, sources=sources) h = mp.Harminv(mp.Ey, mp.Vector3(0.5 * (s + a)), fcen, df) sim.run(mp.after_sources(h), until_after_sources=200) f = h.modes[0].freq print("freq:, {}, {}".format(s, f)) sim.reset_meep() eig_sources = [ mp.EigenModeSource(src=mp.GaussianSource(f, fwidth=df), size=mp.Vector3(a, a), center=mp.Vector3(-0.5 * (s + a)), direction=mp.Z, eig_kpoint=k_point, eig_match_freq=True, eig_parity=mp.ODD_Y), mp.EigenModeSource(src=mp.GaussianSource(f, fwidth=df), size=mp.Vector3(a, a), center=mp.Vector3(0.5 * (s + a)), direction=mp.Z, eig_kpoint=k_point, eig_match_freq=True, eig_parity=mp.ODD_Y, amplitude=-1.0 if xodd else 1.0) ] sim.change_sources(eig_sources) flux_reg = mp.FluxRegion(direction=mp.Z, center=mp.Vector3(), size=mp.Vector3(1.2 * (2 * a + s), 1.2 * a)) wvg_flux = sim.add_flux(f, 0, 1, flux_reg) force_reg1 = mp.ForceRegion(mp.Vector3(0.5 * s), direction=mp.X, weight=1.0, size=mp.Vector3(y=a)) force_reg2 = mp.ForceRegion(mp.Vector3(0.5 * s + a), direction=mp.X, weight=-1.0, size=mp.Vector3(y=a)) wvg_force = sim.add_force(f, 0, 1, force_reg1, force_reg2) sim.run(until_after_sources=5000) flux = mp.get_fluxes(wvg_flux)[0] force = mp.get_forces(wvg_force)[0] sim.reset_meep() return flux, force
component=mp.Ey, size=mp.Vector3(a, a), center=mp.Vector3(0.5 * (s + a)), eig_kpoint=k_point, eig_match_freq=True, eig_parity=mp.ODD_Y, amplitude=-1.0 if xodd else 1.0) ] sim.change_sources(new_sources) flx_reg = mp.FluxRegion(direction=mp.Z, center=mp.Vector3(), size=mp.Vector3(1.2 * (2 * a + s), 1.2 * a)) wvg_pwr = sim.add_flux(f, 0, 1, flx_reg) frc_reg1 = mp.ForceRegion(mp.Vector3(0.5 * s), mp.X, weight=1.0, size=mp.Vector3(y=a)) frc_reg2 = mp.ForceRegion(mp.Vector3(0.5 * s + a), mp.X, weight=-1.0, size=mp.Vector3(y=a)) wvg_force = sim.add_force(f, 0, 1, frc_reg1, frc_reg2) runtime = 5000 sim.run(until_after_sources=runtime) sim.display_fluxes(wvg_pwr) sim.display_forces(wvg_force)
def parallel_waveguide(s, xodd): geometry = [ mp.Block(center=mp.Vector3(-0.5 * (s + a)), size=mp.Vector3(a, a, mp.inf), material=Si), mp.Block(center=mp.Vector3(0.5 * (s + a)), size=mp.Vector3(a, a, mp.inf), material=Si) ] symmetries = [ mp.Mirror(mp.X, phase=-1 if xodd else 1), mp.Mirror(mp.Y, phase=-1) ] sim = mp.Simulation(resolution=resolution, cell_size=cell, geometry=geometry, boundary_layers=pml_layers, symmetries=symmetries, k_point=k_point) sim.init_sim() EigenmodeData = sim.get_eigenmode(0.22, mp.Z, mp.Volume(center=mp.Vector3(), size=mp.Vector3(sx, sy)), 2 if xodd else 1, k_point, match_frequency=False, parity=mp.ODD_Y) fcen = EigenmodeData.freq print("freq:, {}, {}, {}".format("xodd" if xodd else "xeven", s, fcen)) sim.reset_meep() eig_sources = [ mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=0.1 * fcen), size=mp.Vector3(sx, sy), center=mp.Vector3(), eig_band=2 if xodd else 1, eig_kpoint=k_point, eig_match_freq=False, eig_parity=mp.ODD_Y) ] sim.change_sources(eig_sources) flux_reg = mp.FluxRegion(direction=mp.Z, center=mp.Vector3(), size=mp.Vector3(sx, sy)) wvg_flux = sim.add_flux(fcen, 0, 1, flux_reg) force_reg1 = mp.ForceRegion(mp.Vector3(0.49 * s), direction=mp.X, weight=1, size=mp.Vector3(y=sy)) force_reg2 = mp.ForceRegion(mp.Vector3(0.5 * s + 1.01 * a), direction=mp.X, weight=-1, size=mp.Vector3(y=sy)) wvg_force = sim.add_force(fcen, 0, 1, force_reg1, force_reg2) sim.run(until_after_sources=1500) flux = mp.get_fluxes(wvg_flux)[0] force = mp.get_forces(wvg_force)[0] print("data:, {}, {}, {}, {}, {}".format("xodd" if xodd else "xeven", s, flux, force, -force / flux)) sim.reset_meep() return flux, force