WAVELENGTH_UM = 1.55
FREQ0 = C_0 / WAVELENGTH_UM
silicon = td.Medium(permittivity=3.48**2)
cladding = td.Medium(permittivity=1.44**2)
MODELS = {
"simple_strip": dict(title="Simple Strip", width=0.50, thickness=0.22,
domain=(4.3, 3.02), mode_plane=(4.3, 3.02), target_neff=2.6),
"sidewall_angle": dict(title="Sidewall Angle", width=0.50, thickness=0.22, sidewall_angle_deg=10.0,
domain=(4.3, 3.02), mode_plane=(4.3, 3.02), target_neff=2.6),
"narrow_edge_coupler_tip": dict(title="Narrow Edge Coupler Tip", width=0.19, thickness=0.22,
domain=(7.0, 5.0), mode_plane=(7.0, 5.0), target_neff=1.8),
"waveguide_bend": dict(title="Waveguide Bend", width=0.50, thickness=0.22, bend_radius=5.0,
domain=(7.22, 4.94), mode_plane=(7.22, 4.94), target_neff=2.45),
}
STEPS = list(range(10, 101, 10))
def build_geometry(model_key):
m = MODELS[model_key]
if "sidewall_angle_deg" in m:
half_width = m["width"] / 2
return td.PolySlab(
vertices=[(-half_width, -2.0), (half_width, -2.0), (half_width, 2.0), (-half_width, 2.0)],
axis=2, slab_bounds=(-m["thickness"] / 2, m["thickness"] / 2),
sidewall_angle=np.deg2rad(m["sidewall_angle_deg"]),
)
return td.Box(center=(0, 0, 0), size=(m["width"], td.inf, m["thickness"]))
def build_mode_simulation(model_key, steps_per_wvl):
m = MODELS[model_key]
sim = td.Simulation(
center=(0, 0, 0), size=(m["domain"][0], 4.0, m["domain"][1]), medium=cladding,
structures=[td.Structure(geometry=build_geometry(model_key), medium=silicon)],
grid_spec=td.GridSpec.auto(min_steps_per_wvl=steps_per_wvl, wavelength=WAVELENGTH_UM),
boundary_spec=td.BoundarySpec.all_sides(boundary=td.Periodic()),
run_time=1e-12, subpixel=td.SubpixelSpec(dielectric=td.PolarizedAveraging()),
)
mode_spec_kwargs = dict(num_modes=1, target_neff=m["target_neff"])
if "bend_radius" in m:
mode_spec_kwargs.update(bend_radius=m["bend_radius"], bend_axis=1, num_pml=(12, 12), precision="double")
return td.ModeSimulation.from_simulation(
simulation=sim, plane=td.Box(center=(0, 0, 0), size=(m["mode_plane"][0], 0, m["mode_plane"][1])),
mode_spec=td.ModeSpec(**mode_spec_kwargs), freqs=[FREQ0],
)
# Narrow edge coupler tip: the weakly confined tip mode converges far faster with a mesh
# override refining a small box around the core plus snapping points on the tip corners,
# instead of a uniform grid. Sweep the override cell size dl (not min_steps_per_wvl).
NEC_TIP_HALF = (0.19 / 2, 0.22 / 2)
NEC_SNAP_POINTS = [(sx * NEC_TIP_HALF[0], 0.0, sz * NEC_TIP_HALF[1]) for sx in (-1, 1) for sz in (-1, 1)]
NEC_OVERRIDE_BOX = 0.5
NEC_BACKGROUND_STEPS = 10
NEC_DL_NM = [45, 30, 20, 14, 10, 7, 5, 3.6, 2.7, 2.0]
def build_nec_mode_simulation(dl_um):
m = MODELS["narrow_edge_coupler_tip"]
override = td.MeshOverrideStructure(
geometry=td.Box(center=(0, 0, 0), size=(NEC_OVERRIDE_BOX, td.inf, NEC_OVERRIDE_BOX)),
dl=(dl_um, None, dl_um),
)
sim = td.Simulation(
center=(0, 0, 0), size=(m["domain"][0], 4.0, m["domain"][1]), medium=cladding,
structures=[td.Structure(geometry=build_geometry("narrow_edge_coupler_tip"), medium=silicon)],
grid_spec=td.GridSpec.auto(min_steps_per_wvl=NEC_BACKGROUND_STEPS, wavelength=WAVELENGTH_UM,
override_structures=[override], snapping_points=NEC_SNAP_POINTS),
boundary_spec=td.BoundarySpec.all_sides(boundary=td.Periodic()),
run_time=1e-12, subpixel=td.SubpixelSpec(dielectric=td.PolarizedAveraging()),
)
return td.ModeSimulation.from_simulation(
simulation=sim, plane=td.Box(center=(0, 0, 0), size=(m["mode_plane"][0], 0, m["mode_plane"][1])),
mode_spec=td.ModeSpec(num_modes=1, target_neff=m["target_neff"]), freqs=[FREQ0],
)