def make_objective_fdfd(eps: goos.Shape, stage: str, sim_3d: bool): dx = 20 if sim_3d: sim_z_extent = 2500 src_z_extent = 1000 pml_thickness = [10 * dx] * 6 timing_comp = 1 solver = "maxwell_cg" else: sim_z_extent = 0 src_z_extent = 20 pml_thickness = [10 * dx] * 4 + [0] * 2 timing_comp = 2 solver = "local_direct" sim = maxwell.fdfd_simulation( name="sim_{}".format(stage), wavelength=1550, eps=eps, solver=solver, sources=[ maxwell.WaveguideModeSource(center=[-1400, 0, 0], extents=[0, 2500, src_z_extent], normal=[1, 0, 0], mode_num=0, power=1), ], simulation_space=maxwell.SimulationSpace( mesh=maxwell.UniformMesh(dx=dx), sim_region=goos.Box3d( center=[0, 0, 0], extents=[4000, 4000, sim_z_extent], ), pml_thickness=pml_thickness), background=goos.material.Material(index=1.0), outputs=[ maxwell.Epsilon(name="eps"), maxwell.ElectricField(name="field"), maxwell.WaveguideModeOverlap(name="overlap", center=[0, 1400, 0], extents=[2500, 0, src_z_extent], normal=[0, 1, 0], mode_num=0, power=1), ], ) obj = goos.rename(-goos.abs(sim["overlap"]), name="obj_{}".format(stage)) return obj, sim
def make_objective(eps: goos.Shape, stage: str, sim_3d: bool): if sim_3d: sim_z_extent = 2500 solver_info = maxwell.MaxwellSolver(solver="maxwell_cg", err_thresh=1e-2) pml_thickness = [400] * 6 else: sim_z_extent = 40 solver_info = maxwell.DirectSolver() pml_thickness = [400, 400, 400, 400, 0, 0] sim = maxwell.fdfd_simulation( name="sim_{}".format(stage), wavelength=1550, eps=eps, solver_info=solver_info, sources=[ maxwell.WaveguideModeSource(center=[-1400, 0, 0], extents=[0, 2500, 1000], normal=[1, 0, 0], mode_num=0, power=1) ], simulation_space=maxwell.SimulationSpace( mesh=maxwell.UniformMesh(dx=40), sim_region=goos.Box3d( center=[0, 0, 0], extents=[4000, 4000, sim_z_extent], ), pml_thickness=pml_thickness), background=goos.material.Material(index=1.0), outputs=[ maxwell.Epsilon(name="eps"), maxwell.ElectricField(name="field"), maxwell.WaveguideModeOverlap(name="overlap", center=[0, 1400, 0], extents=[2500, 0, 1000], normal=[0, 1, 0], mode_num=0, power=1), ], ) obj = goos.rename(-goos.abs(sim["overlap"]), name="obj_{}".format(stage)) return obj, sim
def test_simulate_wg_opt(): with goos.OptimizationPlan() as plan: wg_in = goos.Cuboid(pos=goos.Constant([-2000, 0, 0]), extents=goos.Constant([3000, 800, 40]), material=goos.material.Material(index=3.45)) wg_out = goos.Cuboid(pos=goos.Constant([2000, 0, 0]), extents=goos.Constant([3000, 800, 40]), material=goos.material.Material(index=3.45)) def initializer(size): # Set the seed immediately before calling `random` to ensure # reproducibility. np.random.seed(247) return np.random.random(size) * 0.1 + np.ones(size) * 0.7 var, design = goos.pixelated_cont_shape( initializer=initializer, pos=goos.Constant([0, 0, 0]), extents=[1000, 800, 40], pixel_size=[40, 40, 40], material=goos.material.Material(index=1), material2=goos.material.Material(index=3.45), ) eps = goos.GroupShape([wg_in, wg_out, design]) sim = meep.FdtdSimulation( eps=eps, sources=[ meep.WaveguideModeSource( center=[-1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=2, power=1, wavelength=1550, bandwidth=100, ) ], sim_space=meep.SimulationSpace( dx=40, sim_region=goos.Box3d( center=[0, 0, 0], extents=[4000, 4000, 0], ), pml_thickness=[400, 400, 400, 400, 0, 0]), sim_timing=meep.SimulationTiming(stopping_conditions=[ meep.StopWhenFieldsDecayed( time_increment=50, component=2, pos=[0, 0, 0], threshold=1e-6, ) ], ), background=goos.material.Material(index=1.0), outputs=[ meep.Epsilon(wavelength=1550), meep.ElectricField(wavelength=1550), meep.WaveguideModeOverlap(wavelength=1550, center=[1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=0, power=1), ]) obj = -goos.abs(sim[2]) import meep as mp mp.quiet() goos.opt.scipy_minimize(obj, "L-BFGS-B", monitor_list=[obj], max_iters=5) plan.run() # Check that we can optimize. We choose something over 60% as # incorrect gradients will typically not reach this point. assert obj.get().array < -0.85 # As a final check, compare simulation results against Maxwell. # Note that dx = 40 for Meep is actually too innaccurate. We therefore # resimulate the final structure for both Meep and Maxwell. from spins.goos_sim import maxwell sim_fdfd = maxwell.fdfd_simulation( wavelength=1550, eps=eps, sources=[ maxwell.WaveguideModeSource( center=[-1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=2, power=1, ) ], simulation_space=maxwell.SimulationSpace( mesh=maxwell.UniformMesh(dx=20), sim_region=goos.Box3d( center=[0, 0, 0], extents=[4000, 4000, 0], ), pml_thickness=[400, 400, 400, 400, 0, 0]), background=goos.material.Material(index=1.0), outputs=[ maxwell.Epsilon(), maxwell.ElectricField(), maxwell.WaveguideModeOverlap(center=[1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=0, power=1), ], solver="local_direct") sim_fdtd_hi = meep.FdtdSimulation( eps=eps, sources=[ meep.WaveguideModeSource( center=[-1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=2, power=1, wavelength=1550, bandwidth=100, ) ], sim_space=meep.SimulationSpace( dx=20, sim_region=goos.Box3d( center=[0, 0, 0], extents=[4000, 4000, 0], ), pml_thickness=[400, 400, 400, 400, 0, 0]), sim_timing=meep.SimulationTiming(stopping_conditions=[ meep.StopWhenFieldsDecayed( time_increment=50, component=2, pos=[0, 0, 0], threshold=1e-6, ) ], ), background=goos.material.Material(index=1.0), outputs=[ meep.Epsilon(wavelength=1550), meep.ElectricField(wavelength=1550), meep.WaveguideModeOverlap(wavelength=1550, center=[1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=0, power=1), ]) fdtd_hi_power = goos.abs(sim_fdtd_hi[2])**2 fdfd_power = goos.abs(sim_fdfd[2])**2 # Check that power is correct within 0.5%. assert np.abs(fdfd_power.get().array - fdtd_hi_power.get().array) < 0.005
def test_simulate_wg_opt(): with goos.OptimizationPlan() as plan: wg_in = goos.Cuboid(pos=goos.Constant([-2000, 0, 0]), extents=goos.Constant([3000, 800, 220]), material=goos.material.Material(index=3.45)) wg_out = goos.Cuboid(pos=goos.Constant([2000, 0, 0]), extents=goos.Constant([3000, 800, 220]), material=goos.material.Material(index=3.45)) def initializer(size): # Set the seed immediately before calling `random` to ensure # reproducibility. np.random.seed(247) return np.random.random(size) * 0.1 + np.ones(size) * 0.5 var, design = goos.pixelated_cont_shape( initializer=initializer, pos=goos.Constant([0, 0, 0]), extents=[1000, 800, 220], pixel_size=[40, 40, 40], material=goos.material.Material(index=1), material2=goos.material.Material(index=3.45), ) eps = goos.GroupShape([wg_in, wg_out, design]) sim = maxwell.fdfd_simulation( eps=eps, wavelength=1550, solver="local_direct", sources=[ maxwell.WaveguideModeSource( center=[-1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=2, power=1, ) ], simulation_space=maxwell.SimulationSpace( mesh=maxwell.UniformMesh(dx=40), sim_region=goos.Box3d( center=[0, 0, 0], extents=[4000, 4000, 40], ), pml_thickness=[400, 400, 400, 400, 0, 0]), background=goos.material.Material(index=1.0), outputs=[ maxwell.Epsilon(), maxwell.ElectricField(), maxwell.WaveguideModeOverlap(wavelength=1550, center=[1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=0, power=1), ]) obj = -goos.abs(sim[2]) goos.opt.scipy_minimize(obj, "L-BFGS-B", monitor_list=[obj], max_iters=15) plan.run() assert obj.get().array < -0.90
def test_simulate_wg_opt_grad(): with goos.OptimizationPlan() as plan: wg_in = goos.Cuboid(pos=goos.Constant([-2000, 0, 0]), extents=goos.Constant([3000, 800, 220]), material=goos.material.Material(index=3.45)) wg_out = goos.Cuboid(pos=goos.Constant([2000, 0, 0]), extents=goos.Constant([3000, 800, 220]), material=goos.material.Material(index=3.45)) def initializer(size): # Set the seed immediately before calling `random` to ensure # reproducibility. np.random.seed(247) return np.random.random(size) var, design = goos.pixelated_cont_shape( initializer=initializer, pos=goos.Constant([0, 0, 0]), extents=[1000, 800, 220], pixel_size=[500, 400, 220], material=goos.material.Material(index=1), material2=goos.material.Material(index=3.45), ) eps = goos.GroupShape([wg_in, wg_out, design]) sim = maxwell.fdfd_simulation( eps=eps, wavelength=1550, solver="local_direct", sources=[ maxwell.WaveguideModeSource( center=[-1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=2, power=1, ) ], simulation_space=maxwell.SimulationSpace( mesh=maxwell.UniformMesh(dx=40), sim_region=goos.Box3d( center=[0, 0, 0], extents=[4000, 4000, 40], ), pml_thickness=[400, 400, 400, 400, 0, 0]), background=goos.material.Material(index=1.0), outputs=[ maxwell.Epsilon(), maxwell.ElectricField(), maxwell.WaveguideModeOverlap(wavelength=1550, center=[1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=0, power=1), ]) obj = -goos.abs(sim[2]) adjoint_grad = obj.get_grad([var])[0].array_grad # Calculate brute force gradient. var_val = var.get().array eps = 0.001 num_grad = np.zeros_like(var_val) for i in range(var_val.shape[0]): for j in range(var_val.shape[1]): temp_val = var_val.copy() temp_val[i, j] += eps var.set(temp_val) fplus = obj.get(run=True).array temp_val = var_val.copy() temp_val[i, j] -= eps var.set(temp_val) fminus = obj.get(run=True).array num_grad[i, j] = (fplus - fminus) / (2 * eps) np.testing.assert_array_almost_equal(adjoint_grad, num_grad, decimal=3)
def test_simulate_2d(): with goos.OptimizationPlan() as plan: sim_region = goos.Box3d(center=[0, 0, 0], extents=[4000, 4000, 40]) sim_mesh = maxwell.UniformMesh(dx=40) waveguide = goos.Cuboid(pos=goos.Constant([0, 0, 0]), extents=goos.Constant([6000, 500, 40]), material=goos.material.Material(index=3.45)) eps = maxwell.RenderShape(waveguide, region=sim_region, mesh=sim_mesh, background=goos.material.Material(index=1.0), wavelength=1550) sim = maxwell.SimulateNode( wavelength=1550, simulation_space=maxwell.SimulationSpace( sim_region=sim_region, mesh=sim_mesh, pml_thickness=[400, 400, 400, 400, 0, 0], ), eps=eps, sources=[ maxwell.WaveguideModeSource( center=[-500, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=0, power=1, ) ], solver_info=maxwell.DirectSolver(), outputs=[ maxwell.Epsilon(name="eps"), maxwell.ElectricField(name="fields"), maxwell.WaveguideModeOverlap(name="overlap_forward", wavelength=1550, center=[1000, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=0, power=1), maxwell.WaveguideModeOverlap(name="overlap_backward", wavelength=1550, center=[-1000, 0, 0], extents=[0, 2500, 0], normal=[-1, 0, 0], mode_num=0, power=1), maxwell.WaveguideModeOverlap(name="overlap_forward2", wavelength=1550, center=[0, 0, 0], extents=[0, 2500, 0], normal=[1, 0, 0], mode_num=0, power=1), ]) out = sim.get() # Power transmitted should be unity but numerical dispersion could # affect the actual transmitted power. assert np.abs(out[4].array)**2 >= 0.99 assert np.abs(out[4].array)**2 <= 1.01 # Check that waveguide power is roughly constant along waveguide. np.testing.assert_allclose(np.abs(out[2].array)**2, np.abs(out[4].array)**2, rtol=1e-2) # Check that we get minimal leakage of power flowing backwards. assert np.abs(out[3].array)**2 < 0.01