Array of spheres on a slab¶
Spheres with radius 100 nm, permittivity 4 and chirality parameter 0.05 form a square array with a period of 500 nm. They rest on a 10 nm slab with permittivity 3, so the plane of their centers lies 100 nm above the slab. A plane wave hits the structure from below at 17.5 degrees, with k_y = 0.3 k0 and its electric field along x. The S-matrix of the whole stack gives the transmitted and reflected power. Lengths are in nm; the frequency column is k0 / 2π, the inverse vacuum wavelength in 1/nm.
"""A square array of chiral spheres on a thin slab: transmission and reflection."""
import numpy as np
import treams_rs as tr
# Enlarge for a full spectrum: treams uses 100 frequencies.
FREQUENCIES = 5
# The sweep stops short of 1/350 nm^-1, where the diffraction order with
# k_y = 0.3 k0 + 2 pi / 500 starts to propagate and the lattice sum diverges.
k0s = 2 * np.pi * np.linspace(1 / 600, 1 / 350, FREQUENCIES, endpoint=False)
material_slab = 3
thickness = 10
material_sphere = tr.Material(4, 1, 0.05)
lattice = tr.Lattice.square(500)
radius = 100
lmax = 3
# Rows hold (T, R) for each frequency.
power = np.zeros((FREQUENCIES, 2))
for i, k0 in enumerate(k0s):
kpar = [0, 0.3 * k0]
sphere = tr.sphere_tmatrix(
k0=k0, lmax=lmax, radius=radius, material=material_sphere
)
spheres = tr.solve_periodic(sphere, lattice=lattice, kpar=kpar)
# Ports for the diffraction orders kpar + G with |G| <= 0.02 / nm.
ports = tr.PlaneWavePorts.diffr_orders(kpar, lattice, 0.02)
slab = tr.slab(k0=k0, basis=ports, thickness=thickness, material=material_slab)
# The array's S-matrix refers to the plane through the sphere centers,
# one radius above the slab.
gap = tr.propagation(k0=k0, basis=ports, distance=radius)
array = spheres.to_smatrix(ports)
total = tr.stack([slab, gap, array])
# A plane wave from below, with k_par = kpar and its electric field along x.
kz = np.sqrt(k0**2 - kpar[1] ** 2)
incident = tr.plane_wave(direction=[0, kpar[1], kz], pol=[1, 0, 0], k0=k0)
power[i] = total.power(incident)
if __name__ == "__main__":
print("Transmission T and reflection R at oblique incidence")
print(f"{'k0/(2 pi)':>13}{'T':>13}{'R':>13}")
for k0, (t, r) in zip(k0s, power, strict=True):
print(f"{k0 / (2 * np.pi):>13.6g}{t:>13.6g}{r:>13.6g}")
# Source: https://github.com/tfp-photonics/treams/blob/1f5d0d6ebb007288f28bc9e16f6d266e8b55dc39/docs/examples/array_spheres.py
# Adapted: reduced sizes, sweep ends before the diffraction threshold at 1/350,
# plotting removed.
# MIT license, copyright Dominik Beutel; see LICENSE.treams.
import numpy as np
import treams
k0s = 2 * np.pi * np.linspace(1 / 600, 1 / 350, 5, endpoint=False)
material_slab = 3
thickness = 10
material_sphere = treams.Material(4, 1, 0.05)
lattice = treams.Lattice.square(500)
radius = 100
lmax = 3
tr = np.zeros((len(k0s), 2))
for i, k0 in enumerate(k0s):
kpar = [0, 0.3 * k0]
spheres = treams.TMatrix.sphere(
lmax, k0, radius, [material_sphere, 1]
).latticeinteraction.solve(lattice, kpar)
pwb = treams.PlaneWaveBasisByComp.diffr_orders(kpar, lattice, 0.02)
plw = treams.plane_wave(kpar, [1, 0, 0], k0=k0, basis=pwb, material=1)
slab = treams.SMatrices.slab(thickness, pwb, k0, [1, material_slab, 1])
dist = treams.SMatrices.propagation([0, 0, radius], pwb, k0, 1)
array = treams.SMatrices.from_array(spheres, pwb)
total = treams.SMatrices.stack([slab, dist, array])
tr[i, :] = total.tr(plw)
Output¶
Transmission T and reflection R at oblique incidence
k0/(2 pi) T R
0.00166667 0.983848 0.0161521
0.00190476 0.992482 0.00751827
0.00214286 0.966577 0.0334227
0.00238095 0.920532 0.0794679
0.00261905 0.776883 0.223117
Differences from the treams version¶
solve_periodic(sphere, lattice=lattice, kpar=kpar)solves the array once; treams writesTMatrix.sphere(...).latticeinteraction.solve(lattice, kpar).to_smatrix(ports)turns the solved array into an S-matrix; treams writesSMatrices.from_array(spheres, pwb).propagation(distance=radius)takes the distance along z; treams takes the displacement[0, 0, radius], which treams-rs also accepts.plane_wavetakes the full propagation direction. treams takes the parallel wave vector together with the plane-wave basis of the ports.- Both scripts stop the sweep before 1/350 nm⁻¹. There the diffraction order
with k_y = 0.3 k0 + 2π / 500 nm turns from decaying to propagating, and the
lattice sum diverges. treams-rs raises a
ValueErrorat that frequency; treams returns a finite number.