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 make_objective_fdtd(eps: goos.Shape, stage: str, sim_3d: bool): if sim_3d: sim_z_extent = 2500 src_z_extent = 1000 pml_thickness = [400, 400, 400, 400, 400, 400] # Dominant E-component is Ey. timing_comp = 1 # Simulate across 4 cores. sim_cores = 4 else: sim_z_extent = 0 src_z_extent = 0 # No PMLs in the vertical direction for 2D. pml_thickness = [400, 400, 400, 400, 0, 0] # Dominant E-component is Ez. timing_comp = 2 # Simulate using only a single CPU. sim_cores = 1 sim = meep.fdtd_simulation( name="sim_{}".format(stage), eps=eps, sources=[ meep.WaveguideModeSource(center=[-1400, 0, 0], extents=[0, 2500, src_z_extent], normal=[1, 0, 0], mode_num=0, power=1, wavelength=1550, bandwidth=100), ], sim_space=meep.SimulationSpace(dx=20, sim_region=goos.Box3d( center=[0, 0, 0], extents=[4000, 4000, sim_z_extent], ), pml_thickness=pml_thickness), # `SimulationTiming` handles termination condition for FDTD. # In this case, we rely on Meep's `stop_when_fields_decayed` which # waits until the field component indexed by `timing_comp` # at pos (0, 0, 0) has decayed (after the source has finished). sim_timing=meep.SimulationTiming(stopping_conditions=[ meep.StopWhenFieldsDecayed( time_increment=100, component=timing_comp, pos=[0, 0, 0], threshold=1e-4, ) ]), background=goos.material.Material(index=1.0), outputs=[ meep.Epsilon(name="eps", wavelength=1550), meep.ElectricField(name="field", wavelength=1550), meep.WaveguideModeOverlap(name="overlap", wavelength=1550, center=[0, 1400, 0], extents=[2500, 0, src_z_extent], normal=[0, 1, 0], mode_num=0, power=1), ], sim_cores=sim_cores, ) obj = goos.rename(-goos.abs(sim["overlap"]), name="obj_{}".format(stage)) return obj, sim
def make_objective(eps: goos.Shape, stage: str, params: Options): """Creates the objective. The function sets up the simulation and the objective function for the grating optimization. The simulation is a FDFD simulation with a Gaussian beam source that couples into a the waveguide. The optimization minimizes `(1 - coupling_eff)**2` where `coupling_eff` is the fiber-to-chip coupling efficiency. Args: eps: The permittivity distribution, including the waveguide and grating. stage: Name of the optimization stage. Used to name the nodes. params: Options for the optimization problem. Returns: A tuple `(obj, sim)` where `obj` is the objective and `sim` is the simulation. """ solver = "local_direct" sim_left_x = -params.wg_len sim_right_x = params.coupler_len + params.buffer_len pml_thick = params.dx * 10 sim_z_center = (params.wg_thickness / 2 + params.beam_dist - params.box_size) / 2 sim_z_extent = (params.wg_thickness + params.beam_dist + params.box_size + 2000 + pml_thick * 2) sim = maxwell.fdfd_simulation( name="sim_{}".format(stage), wavelength=params.wlen, eps=eps, solver=solver, sources=[ maxwell.GaussianSource( w0=params.beam_width / 2, center=[ params.coupler_len / 2, 0, params.wg_thickness / 2 + params.beam_dist ], extents=[params.beam_extents, 0, 0], normal=[0, 0, -1], power=1, theta=np.deg2rad(params.source_angle_deg), psi=np.pi / 2, polarization_angle=0, normalize_by_sim=True) ], simulation_space=maxwell.SimulationSpace( mesh=maxwell.UniformMesh(dx=params.dx), sim_region=goos.Box3d( center=[(sim_left_x + sim_right_x) / 2, 0, sim_z_center], extents=[sim_right_x - sim_left_x, 0, sim_z_extent], ), pml_thickness=[pml_thick, pml_thick, 0, 0, pml_thick, pml_thick]), background=goos.material.Material(index=params.eps_bg), outputs=[ maxwell.Epsilon(name="eps"), maxwell.ElectricField(name="field"), maxwell.WaveguideModeOverlap(name="overlap", center=[-params.wg_len / 2, 0, 0], extents=[0, 1000, 2000], normal=[-1, 0, 0], mode_num=0, power=1), ], ) obj = (1 - goos.abs(sim["overlap"]))**2 obj = goos.rename(obj, 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 make_objective(eps: goos.Shape, stage: str): sim_z_extent = 1800 simcenter_positon_z = 300 sources_wx = 8000 sources_wy = 8000 solver_info = maxwell.MaxwellSolver(solver="maxwell_cg", err_thresh=1e-2) pml_thickness = [400, 400, 400, 400, 400, 400] sources_position_z = 800 wavelength = 635 background = goos.material.Material(index=1.0) simulation_space = maxwell.SimulationSpace( mesh=maxwell.UniformMesh(dx=50), sim_region=goos.Box3d( center=[0, 0, simcenter_positon_z], extents=[10000, 10000, sim_z_extent], ), pml_thickness=pml_thickness) sources1 = [ maxwell.LaguerreGaussianSource(w0=1400, center=[0, 0, sources_position_z], beam_center=[0, 0, sources_position_z], extents=[sources_wx, sources_wy, 0], normal=[0, 0, -1], theta=0, psi=0, m=2, p=0, polarization_angle=0, power=1), ] sources2 = [ maxwell.LaguerreGaussianSource(w0=1400, center=[0, 0, sources_position_z], beam_center=[0, 0, sources_position_z], extents=[sources_wx, sources_wy, 0], normal=[0, 0, -1], theta=0, psi=0, m=3, p=0, polarization_angle=0, power=1), ] sources3 = [ maxwell.LaguerreGaussianSource(w0=1400, center=[0, 0, sources_position_z], beam_center=[0, 0, sources_position_z], extents=[sources_wx, sources_wy, 0], normal=[0, 0, -1], theta=0, psi=0, m=-3, p=0, polarization_angle=0, power=1), ] sources4 = [ maxwell.LaguerreGaussianSource(w0=1400, center=[0, 0, sources_position_z], beam_center=[0, 0, sources_position_z], extents=[sources_wx, sources_wy, 0], normal=[0, 0, -1], theta=0, psi=0, m=-2, p=0, polarization_angle=0, power=1), ] sources5 = [ maxwell.LaguerreGaussianSource(w0=1400, center=[0, 0, sources_position_z], beam_center=[0, 0, sources_position_z], extents=[sources_wx, sources_wy, 0], normal=[0, 0, -1], theta=0, psi=0, m=1, p=0, polarization_angle=0, power=1), ] sources6 = [ maxwell.LaguerreGaussianSource(w0=1400, center=[0, 0, sources_position_z], beam_center=[0, 0, sources_position_z], extents=[sources_wx, sources_wy, 0], normal=[0, 0, -1], theta=0, psi=0, m=-1, p=0, polarization_angle=0, power=1), ] sources7 = [ maxwell.LaguerreGaussianSource(w0=1400, center=[0, 0, sources_position_z], beam_center=[0, 0, sources_position_z], extents=[sources_wx, sources_wy, 0], normal=[0, 0, -1], theta=0, psi=0, m=0, p=0, polarization_angle=0, power=1), ] outputs = [ maxwell.Epsilon(name="eps"), maxwell.ElectricField(name="field"), maxwell.WaveguideModeOverlap(name="overlap1", center=[1600, -4500, 0], extents=[800, 0, 400], normal=[0, -1, 0], mode_num=0, power=1), maxwell.WaveguideModeOverlap(name="overlap2", center=[-1600, -4500, 0], extents=[800, 0, 400], normal=[0, -1, 0], mode_num=0, power=1), maxwell.WaveguideModeOverlap(name="overlap3", center=[1600, 4500, 0], extents=[800, 0, 400], normal=[0, 1, 0], mode_num=0, power=1), maxwell.WaveguideModeOverlap(name="overlap4", center=[-1600, 4500, 0], extents=[800, 0, 400], normal=[0, 1, 0], mode_num=0, power=1), maxwell.WaveguideModeOverlap(name="overlap5", center=[4500, -1600, 0], extents=[0, 800, 400], normal=[1, 0, 0], mode_num=0, power=1), maxwell.WaveguideModeOverlap(name="overlap6", center=[4500, 1600, 0], extents=[0, 800, 400], normal=[1, 0, 0], mode_num=0, power=1), maxwell.WaveguideModeOverlap(name="overlap7", center=[-4500, 0, 0], extents=[0, 800, 400], normal=[-1, 0, 0], mode_num=0, power=1), ] sim1 = maxwell.fdfd_simulation( name="sim1_{}".format(stage), wavelength=wavelength, eps=eps, solver_info=solver_info, sources=sources1, simulation_space=simulation_space, background=background, outputs=outputs, ) sim2 = maxwell.fdfd_simulation( name="sim2_{}".format(stage), wavelength=wavelength, eps=eps, solver_info=solver_info, sources=sources2, simulation_space=simulation_space, background=background, outputs=outputs, ) sim3 = maxwell.fdfd_simulation( name="sim3_{}".format(stage), wavelength=wavelength, eps=eps, solver_info=solver_info, sources=sources3, simulation_space=simulation_space, background=background, outputs=outputs, ) sim4 = maxwell.fdfd_simulation( name="sim4_{}".format(stage), wavelength=wavelength, eps=eps, solver_info=solver_info, sources=sources4, simulation_space=simulation_space, background=background, outputs=outputs, ) sim5 = maxwell.fdfd_simulation( name="sim5_{}".format(stage), wavelength=wavelength, eps=eps, solver_info=solver_info, sources=sources5, simulation_space=simulation_space, background=background, outputs=outputs, ) sim6 = maxwell.fdfd_simulation( name="sim6_{}".format(stage), wavelength=wavelength, eps=eps, solver_info=solver_info, sources=sources6, simulation_space=simulation_space, background=background, outputs=outputs, ) sim7 = maxwell.fdfd_simulation( name="sim7_{}".format(stage), wavelength=wavelength, eps=eps, solver_info=solver_info, sources=sources7, simulation_space=simulation_space, background=background, outputs=outputs, ) obj1 = goos.rename( ((goos.abs(sim1["overlap1"]) - 12)**2 + goos.abs(sim1["overlap2"])**2 + goos.abs(sim1["overlap3"])**2 + goos.abs(sim1["overlap4"])**2 + goos.abs(sim1["overlap5"])**2 + goos.abs(sim1["overlap6"])**2 + goos.abs(sim1["overlap7"])**2), name="obj1_{}".format(stage)) obj2 = goos.rename( (goos.abs(sim2["overlap1"])**2 + (goos.abs(sim2["overlap2"]) - 12)**2 + goos.abs(sim2["overlap3"])**2 + goos.abs(sim2["overlap4"])**2 + goos.abs(sim2["overlap5"])**2 + goos.abs(sim2["overlap6"])**2 + goos.abs(sim2["overlap7"])**2), name="obj2_{}".format(stage)) obj3 = goos.rename( (goos.abs(sim3["overlap1"])**2 + goos.abs(sim3["overlap2"])**2 + (goos.abs(sim3["overlap3"]) - 12)**2 + goos.abs(sim3["overlap4"])**2 + goos.abs(sim3["overlap5"])**2 + goos.abs(sim3["overlap6"])**2 + goos.abs(sim3["overlap7"])**2), name="obj3_{}".format(stage)) obj4 = goos.rename( (goos.abs(sim4["overlap1"])**2 + goos.abs(sim4["overlap2"])**2 + goos.abs(sim4["overlap3"])**2 + (goos.abs(sim4["overlap4"]) - 12)**2 + goos.abs(sim4["overlap5"])**2 + goos.abs(sim4["overlap6"])**2 + goos.abs(sim4["overlap7"])**2), name="obj4_{}".format(stage)) obj5 = goos.rename( (goos.abs(sim5["overlap1"])**2 + goos.abs(sim5["overlap2"])**2 + goos.abs(sim5["overlap3"])**2 + goos.abs(sim5["overlap4"])**2 + (goos.abs(sim5["overlap5"]) - 12)**2 + goos.abs(sim5["overlap6"])**2 + goos.abs(sim5["overlap7"])**2), name="obj5_{}".format(stage)) obj6 = goos.rename( (goos.abs(sim6["overlap1"])**2 + goos.abs(sim6["overlap2"])**2 + goos.abs(sim6["overlap3"])**2 + goos.abs(sim6["overlap4"])**2 + goos.abs(sim6["overlap5"])**2 + (goos.abs(sim6["overlap6"]) - 12)**2 + goos.abs(sim6["overlap7"])**2), name="obj5_{}".format(stage)) obj7 = goos.rename( (goos.abs(sim7["overlap1"])**2 + goos.abs(sim7["overlap2"])**2 + goos.abs(sim7["overlap3"])**2 + goos.abs(sim7["overlap4"])**2 + goos.abs(sim7["overlap5"])**2 + goos.abs(sim7["overlap6"])**2 + (goos.abs(sim7["overlap7"]) - 12)**2), name="obj5_{}".format(stage)) obj = obj1 + obj2 + obj3 + obj4 + 2 * obj5 + 2 * obj6 + 8 * obj7 return obj, sim1, sim2, sim3, sim4, sim5, sim6, sim7
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)