Planar layers and S-matrices¶
An SMatrix is the scattering matrix of a planar two-port network: it maps the
waves arriving at both sides to the waves leaving both sides. The sides are
named after the z axis of the ports' basis:
- the negative side, below (z < 0), with medium
negative_medium; - the positive side, above, with medium
positive_medium.
SMatrix in treams
treams calls this whole network SMatrices, and calls one of its four
blocks an SMatrix. In treams-rs one block is a ScatteringBlock. See
Coming from treams.
Building a network¶
| Function | Builds |
|---|---|
interface(basis=, k0=, negative_medium=, positive_medium=) |
one flat interface |
slab(basis=, k0=, thickness=, material=) |
one homogeneous layer |
multilayer_slab(basis=, k0=, thicknesses=, materials=) |
layers from the negative to the positive side |
propagation(distance=, basis=, k0=) |
a gap of homogeneous medium |
PeriodicResponse.to_smatrix(ports) |
a periodic array; see Periodic arrays |
stack([first, second, ...]) |
the networks in order from the negative to the positive side |
The basis is a PlaneWavePorts: PlaneWavePorts.default([0, 0]) holds the
two pol values at normal incidence; PlaneWavePorts.diffr_orders holds the
diffraction orders of a lattice.
import numpy as np
import treams_rs as tr
ports = tr.PlaneWavePorts.default([0, 0])
glass = tr.interface(basis=ports, k0=1.0, negative_medium=1, positive_medium=2.25)
incident = tr.plane_wave(direction=[0, 0, 1], pol="positive_helicity", k0=1.0)
power = glass.power(incident)
# Fresnel reflectance at normal incidence from n = 1 to n = 1.5.
np.testing.assert_allclose(power.reflection, ((1 - 1.5) / (1 + 1.5)) ** 2)
two = tr.multilayer_slab(
basis=ports, k0=1.0, thicknesses=[0.3, 0.4], materials=[2.25, 4]
)
layers = [
tr.slab(basis=ports, k0=1.0, thickness=d, material=e)
for d, e in ((0.3, 2.25), (0.4, 4))
]
np.testing.assert_allclose(two.array, tr.stack(layers).array, atol=1e-15)
Results¶
| Method | Returns |
|---|---|
power(incident) |
PowerBalance(transmission, reflection) as fractions of the incident power |
scatter(negative=..., positive=...) |
ScatteredPorts(negative, positive): the waves leaving each side |
block("positive", "negative") |
one ScatteringBlock: the waves leaving the first side for waves arriving from the second; this one is the transmission upwards |
circular_dichroism(incident) |
the contrasts of transmission and total outgoing power between the two helicities |
bands(period=...) |
BandModes(wavenumbers, eigenvectors) of the network repeated along z |
transfer_matrix() |
the transfer matrix of one period |
power and scatter read the incident side from the direction of the wave: a
wave with a positive z component arrives from the negative side. A wave from
above uses direction=[0, 0, -1] and the positive medium; the layer order stays
the same.
import numpy as np
import treams_rs as tr
ports = tr.PlaneWavePorts.default([0, 0])
glass = tr.interface(basis=ports, k0=1.0, negative_medium=1, positive_medium=2.25)
transmission = np.asarray(glass.block("positive", "negative"))
# The field transmission coefficient 2 n1 / (n1 + n2), the same for both pols.
np.testing.assert_allclose(transmission, 0.8 * np.eye(2), atol=1e-15)
from_above = tr.plane_wave(
direction=[0, 0, -1], pol="positive_helicity", k0=1.0, medium=2.25
)
np.testing.assert_allclose(glass.power(from_above).reflection, 0.04)
layer = tr.slab(basis=ports, k0=1.0, thickness=0.5, material=2.25)
bands = layer.bands(period=0.5)
# A period filled with one material carries waves with kz = +-n k0 = +-1.5.
np.testing.assert_allclose(np.sort(bands.wavenumbers.real), [-1.5, -1.5, 1.5, 1.5])
cascade joins two networks like stack does for a list. The treams method
names add, illuminate, tr, cd, periodic and bands_kz call these
methods; the name map lists them.