# Substrate thickness, buffer layers, and overall simulation domain size
t_sub = 2 * wl0 / n_SiO2
z_buffer1 = wl0 / n_SiO2 / 2
z_buffer2 = wl0 / 2
sim_size = (P, P, h + z_buffer1 + z_buffer2)
sim_center_z = -z_buffer1 + sim_size[2] / 2
# Build an elliptical (optionally rotated) pillar, extruded to height h
def make_pillar(D1, D2, center=(0, 0), N_point=360, name="pillar", rotate=0):
dtheta = 2 * np.pi / N_point
theta = dtheta * np.arange(N_point)
x = D1 / 2 * np.cos(theta)
y = D2 / 2 * np.sin(theta)
x_rot = np.cos(rotate) * x - np.sin(rotate) * y
y_rot = np.sin(rotate) * x + np.cos(rotate) * y
vertices = np.column_stack([x_rot + center[0], y_rot + center[1]])
pillar = td.Structure(
geometry=td.PolySlab(vertices=vertices, slab_bounds=(0, h), axis=2),
medium=aSi,
name=name,
)
return pillar
# SiO2 substrate slab
substrate = td.Structure(
geometry=td.Box(center=(0, 0, -t_sub / 2), size=(td.inf, td.inf, t_sub)),
medium=SiO2,
name="substrate",
)
# Assemble a periodic unit-cell simulation for a single pillar
def make_unitcell_sim(D1, D2, aux_mnt=False):
pillar = make_pillar(D1, D2)
# Normally incident, x-polarized plane wave source
pw_source = td.PlaneWave(
center=(0, 0, -z_buffer1 / 4),
size=(td.inf, td.inf, 0),
source_time=td.GaussianPulse(freq0=f0, fwidth=fwidth),
direction="+",
)
# Transmission monitor above the pillar
mnt_trans = td.FieldMonitor(
center=(0, 0, h + z_buffer2 / 2),
size=(td.inf, td.inf, 0),
freqs=[f0],
name="trans",
)
# Optional reflection and field-profile monitors, for visualization only
mnts_aux = (
[
td.FieldMonitor(
center=(0, 0, -z_buffer1 / 2),
size=(td.inf, td.inf, 0),
freqs=[f0],
name="refl",
),
td.FieldMonitor(
center=(0, 0, 0), size=(td.inf, 0, td.inf), freqs=[f0], name="field_xz"
),
td.FieldMonitor(
center=(0, 0, 0), size=(0, td.inf, td.inf), freqs=[f0], name="field_yz"
),
]
if aux_mnt
else []
)
# Local mesh refinement around the pillar
dl = wl0 / n_aSi / 40
mos = td.MeshOverrideStructure(
geometry=pillar.geometry.bounding_box, dl=(dl, dl, dl)
)
grid_spec = td.GridSpec.auto(
wavelength=wl0,
min_steps_per_wvl=20,
override_structures=[mos],
snapping_points=[(0, 0, pw_source.center[2]), (0, 0, mnt_trans.center[2])],
)
# Periodic boundaries in-plane, PML along propagation
boundary_spec = td.BoundarySpec(
x=td.Boundary(minus=td.Periodic(), plus=td.Periodic()),
y=td.Boundary(minus=td.Periodic(), plus=td.Periodic()),
z=td.Boundary(minus=td.PML(), plus=td.PML()),
)
# Assemble and return the unit-cell simulation
return td.Simulation(
size=sim_size,
center=(0, 0, sim_center_z),
structures=[substrate, pillar],
sources=[pw_source],
monitors=[mnt_trans] + mnts_aux,
grid_spec=grid_spec,
boundary_spec=boundary_spec,
run_time=td.RunTimeSpec(quality_factor=50),
symmetry=(-1, 1, 0), # x-pol incidence
)