treams_rs¶
T-matrix scattering with Rust numerics and analytic first-order derivatives.
Import as import treams_rs as tr. Lengths use any consistent unit;
k0 = 2*pi/vacuum_wavelength uses its inverse. Material numbers are relative
permittivities (epsilon), not refractive indices; use Material(epsilon, mu,
kappa) for magnetic/chiral media. Passive loss has positive imaginary epsilon.
Terms used throughout:
medium: the exterior (embedding) material;materialis the particle or layer material. Planar networks have anegative_medium(below) and apositive_medium(above).polarization: the convention of the channels,"helicity"(default) or"parity"(treamspoltype).polis the state of one channel, 0 or 1; in the helicity convention pol 1 is positive helicity.kind: the radial kind of multipole waves,"regular"or"singular"(outgoing; treamsmodetype), or the direction of plane-wave ports,"up"or"down".
The glossary defines every term: https://yaugenst.github.io/treams-rs/latest/reference/glossary/
A complete particle calculation:
import numpy as np
import treams_rs as tr
k0 = 2*np.pi/0.8
particle = tr.sphere_tmatrix(k0=k0, lmax=3, radius=0.12, material=3+0.02j)
incident = tr.plane_wave([0, 0, 1], "positive_helicity", k0=k0)
cross = particle.cross_sections(incident)
print(cross.scattering, cross.extinction, cross.absorption) # areas
points = [[0.3, 0.1, 0.4]]
total_e = incident.efield(points) + particle.scatter(incident).efield(points)
Choose the physical workflow:
multilayer_sphere_tmatrix: increasing radii, one material per finite layer, inside-out; exterior passed separately asmedium.cylinder_tmatrix: infinite z cylinder; specifykzandmmaxand usecross_widths(incident)for lengths instead of areas.Cluster(particles, positions=xyz).solve(): full finite multiple-scattering response;.scatter(incident)directly solves requested illuminations.solve_periodic(particle, lattice=cell, kpar=[0, 0]).to_smatrix(ports): periodic response in plane-wave channels, ready to combine with planar layers.slab/multilayer_slab/propagation/stack: layers ordered negative to positive z. Specifynegative_mediumandpositive_mediumfor exterior media.PlaneWavePorts.default([0, 0])gives normal-incidence ports. Pass a physicalplane_wavetonetwork.power(incident)to select direction and helicity by name; the incident side follows its propagation. The result has namedtransmission,reflectionandabsorption. Reverse incidence uses a -z wave without reversing layer order. Raw amplitudes followports.pol(1 means positive helicity, 0 means negative); inspect that array instead of assuming the order.
Sensitivity and optimization use the same API: framework inputs select their
adapter automatically. With the [advect] extra installed:
import advect as ad
import treams_rs as tr
def objective(radius):
particle = tr.sphere_tmatrix(k0=2.0, lmax=2, radius=radius, material=3.0)
incident = tr.plane_wave([0, 0, 1], "positive_helicity", k0=2.0)
return particle.cross_sections(incident).scattering
value, derivative = ad.value_and_grad(objective)(0.2)
Construct changing geometry/materials inside the objective and keep traced
values as framework arrays (advect.numpy); convert to float/NumPy only after
differentiation. Rust computes analytic gradients with respect to continuous
geometry, material and frequency; mode cutoffs, integer labels and topology stay
fixed. Advect, JAX, PyTorch and HIPS Autograd support CPU, first-order forward
and reverse mode with their documented dtype and transform limits. Higher
derivatives are unsupported. Plain Python and NumPy
inputs retain NumPy behavior, without loading optional frameworks. Explicit
advect, jax, torch and autograd namespaces remain available for
framework-specific record helpers. diff returns each value with a context
whose pullback gives input gradients and whose pushforward maps input
tangents to output tangents. Both actions can reuse the same context.
Offline help: python -m treams_rs shows this quickstart;
python -m treams_rs sphere_tmatrix or python -m treams_rs advect shows
focused help; python -m treams_rs --search cross lists matching names.
help(tr.sphere_tmatrix) also works. support_catalog() or explicit
python -m treams_rs --format json gives the complete source-derived catalog.
BandModes¶
Bloch wavenumbers along the basis normal and matching right eigenvectors.
Units: wavenumbers in inverse length, the unit of k0; eigenvectors
dimensionless, with eigenvectors[:, i] the mode of wavenumbers[i].
Fields are complex NumPy arrays for SMatrix.bands, and framework arrays in
advect, jax and torch.
BandModes.wavenumbers¶
BandModes.wavenumbers: T
BandModes.eigenvectors¶
BandModes.eigenvectors: T
CircularDichroism¶
Contrasts against opposite polarization, normalized by the respective summed powers.
Units: none; each contrast lies between -1 and 1.
CircularDichroism.transmission¶
CircularDichroism.transmission: float
CircularDichroism.outgoing_power¶
CircularDichroism.outgoing_power: float
Cluster¶
Unsolved finite collection of particle responses at Cartesian positions.
Construction only assembles particles. Solve creates a full coupled response; scatter computes requested illuminations. No numerical matrix multiplication is provided on an unsolved cluster.
Complete finite-scattering workflow:
import treams_rs as tr
particles = [tr.sphere_tmatrix(k0=2., lmax=2, radius=r, material=3.)
for r in (0.12, 0.16)]
system = tr.Cluster(particles, positions=[[0, 0, 0], [0.6, 0, 0]])
incident = tr.plane_wave([0, 0, 1], "positive_helicity", k0=2.)
response = system.solve()
cross = response.cross_sections(incident)
points = [[0.2, 0.1, 0.8]]
total_e = incident.efield(points) + response.scatter(incident).efield(points)
assert total_e.shape == (1, 3)
assert abs(cross.absorption) < 1e-12 # lossless materials
For fields alone, use system.scatter(incident).efield(points) and add
the incident field. For geometry/material gradients, construct changing
quantities inside the objective; their framework is selected automatically.
Cluster.basis¶
Cluster.basis: SphericalBasis | CylindricalBasis
Local multipole modes and their positions.
Cluster.k0¶
Cluster.k0: float
Vacuum angular wavenumber.
Cluster.medium¶
Cluster.medium: Material
Homogeneous exterior (embedding) medium.
Cluster.polarization¶
Cluster.polarization: str
Polarization channel convention: helicity or parity.
Cluster.__init__¶
Cluster(particles: Sequence[TMatrix] | Sequence[CylindricalTMatrix], *, positions: ArrayLike)
Cluster.solve¶
Cluster.solve() -> TMatrix | CylindricalTMatrix
Compute the complete coupled finite response, including multiple scattering.
Cluster.factor¶
Cluster.factor() -> ScatteringFactor
Factor once for repeated requested-source solves.
Cluster.scatter¶
Cluster.scatter(incident: ArrayLike | PlaneWave | Wave) -> Wave
Compute only the requested outgoing waves, including particle interactions.
CrossSections¶
Scattering and extinction cross sections; absorption is their difference.
Units: areas (length squared) from TMatrix and widths (length) from CylindricalTMatrix, in the length unit of 1/k0. Fields are floats for TMatrix and CylindricalTMatrix, and framework arrays in advect, jax and torch.
CrossSections.absorption¶
CrossSections.absorption: T
Extinguished power minus scattered power, with the same normalization.
CrossSections.scattering¶
CrossSections.scattering: T
CrossSections.extinction¶
CrossSections.extinction: T
CylindricalBasis¶
Ordered modes (pidx, kz, m, pol) around parallel z-directed axes.
Mirrors treams.CylindricalWaveBasis. Rows (kz, m, pol) imply
pidx=0. kz is a finite real axial wavenumber in inverse length units,
|m| <= 128 and pol is 0 or 1. The axis positions have shape (particles, 3)
in the matching length unit. Exact duplicate modes are removed in order.
The wave or operator that uses the basis sets the polarization convention:
helicity labels 0/1 mean negative/positive, parity labels
magnetic/electric.
CylindricalBasis.index¶
CylindricalBasis.index(mode: CylindricalMode, start: int=0, stop: int | None=None) -> int
Index of mode, like tuple.index; ValueError when it is absent.
CylindricalBasis.count¶
CylindricalBasis.count(mode: CylindricalMode) -> int
Number of times mode occurs: 0 or 1, because modes are distinct.
CylindricalBasis.isdisjoint¶
CylindricalBasis.isdisjoint(other: CylindricalBasis) -> bool
Whether the bases share no mode; both need one family and geometry.
CylindricalBasis.lattice¶
CylindricalBasis.lattice: Lattice | None = None
Lattice of a periodic arrangement, or None.
CylindricalBasis.kpar¶
CylindricalBasis.kpar: WaveVector | None = None
Bloch vector of a periodic arrangement, or None.
CylindricalBasis.modes¶
CylindricalBasis.modes: tuple[CylindricalMode, ...]
The mode labels, in order.
CylindricalBasis.__init__¶
CylindricalBasis(modes: Iterable[Sequence[float]], positions: ArrayLike=((0, 0, 0),))
CylindricalBasis.pidx¶
CylindricalBasis.pidx: NDArray[np.int64]
Particle index of each mode, shape (modes,).
A read-only column cached per basis, like pol; call .copy() to
edit it.
CylindricalBasis.m¶
CylindricalBasis.m: NDArray[np.int64]
Azimuthal order of each mode, shape (modes,).
A read-only column cached per basis, like pol; call .copy() to
edit it.
CylindricalBasis.pol¶
CylindricalBasis.pol: NDArray[np.int64]
Label pol (0 or 1) of each mode, shape (modes,); read-only and cached.
CylindricalBasis.isglobal¶
CylindricalBasis.isglobal: bool
Whether every mode has the same particle index.
CylindricalBasis.defaultdim¶
CylindricalBasis.defaultdim(nkz: int, mmax: int, nmax: int=1) -> int
Return 2*nkz*(2*mmax+1)*nmax channels for distinct axial labels.
CylindricalBasis.defaultmmax¶
CylindricalBasis.defaultmmax(dim: int, nkz: int=1, nmax: int=1) -> int
Invert defaultdim for positive nkz/nmax; reject incomplete mode sets.
CylindricalBasis.default¶
CylindricalBasis.default(kzs: ArrayLike, mmax: int, nmax: int=1, positions: ArrayLike | None=None) -> CylindricalBasis
Create pol 0 and 1 of orders -mmax..mmax for each axial label.
Kzs is a scalar or one-dimensional real wavenumber array. Order is particle, kz in input order, m, then pol=(1, 0); duplicate labels are removed. Require 0 <= mmax <= 128 and nmax >= 1. Positions have shape (nmax, 3), defaulting to zeros, in the length unit inverse to kzs.
CylindricalBasis.diffr_orders¶
CylindricalBasis.diffr_orders(kz: float, mmax: int, lattice: float | Lattice, bmax: float, nmax: int=1, positions: ArrayLike | None=None) -> CylindricalBasis
Modes at the axial diffraction orders of a chain with period along z.
Mirrors treams.CylindricalWaveBasis.diffr_orders. The axial
wavenumbers are kz + 2 pi j / period for every integer j with
|2 pi j / period| <= bmax, each with orders -mmax..mmax and both pol,
ordered as in default. lattice is the period or a 1D Lattice. The
basis keeps the lattice and the Bloch vector kz.
CylindricalBasis.kz¶
CylindricalBasis.kz: NDArray[np.float64]
Axial wavenumber label of each mode, shape (modes,).
A read-only column cached per basis, like pol; call .copy() to
edit it.
CylindricalBasis.zms¶
CylindricalBasis.zms: tuple[NDArray[np.float64], NDArray[np.int64], NDArray[np.int64]]
The columns (kz, m, pol), as treams' zms.
CylindricalTMatrix¶
Cylindrical T-matrix: regular incident coefficients to singular (outgoing) ones.
The treams counterpart is treams.TMatrixC. Rows and columns follow
basis, a CylindricalBasis with fixed real axial wavenumbers kz. Use
cylinder_tmatrix for concentric infinite cylinders and Cluster for
parallel cylinders. Cross widths have length units. scatter(incident)
returns the scattered Wave; array and @ give the coefficients.
Framework-valued inputs select their differentiation adapter automatically.
The treams-rs names come first. The treams names (xw, poltype,
changepoltype, ...) follow at the end of the class and call them.
Treat it as immutable: the constructor checks the metadata attributes once and never again.
CylindricalTMatrix.__init__¶
CylindricalTMatrix(arr: ArrayLike, *, k0: float, basis: CylindricalBasis | None=None, medium: MaterialLike | None=None, polarization: str | None=None, material: MaterialLike | None=None, poltype: str | None=None)
Copy a finite square matrix mapping regular to outgoing coefficients.
Args
arr: shape (modes, modes), outgoing rows and incident columns..arrayholds an owned, read-only complex128 copy.k0: positive vacuum angular wavenumber, in inverse units of the basis positions.basis: modes of the rows and columns, of the matrix's wave family. Omitted, it is the complete basis at one position for this dimension (with kz=0 for cylinders).medium: the embedding medium, vacuum by default.polarization: "helicity" (default) or "parity". A chiral medium needs "helicity".material: treams name ofmedium.poltype: treams name ofpolarization.
Give each quantity under one name.
CylindricalTMatrix.shape¶
CylindricalTMatrix.shape: tuple[int, ...]
Shape (modes, modes) of the matrix.
CylindricalTMatrix.ks¶
CylindricalTMatrix.ks: NDArray[np.complex128]
Embedding wavenumbers for labels (0, 1), shape (2,), in inverse length.
CylindricalTMatrix.isglobal¶
CylindricalTMatrix.isglobal: bool
Whether all multipoles of the basis share one position.
CylindricalTMatrix.scatter¶
CylindricalTMatrix.scatter(incident: ArrayLike | PlaneWave | Wave) -> Wave
Apply this solved response and retain outgoing-wave metadata.
Incident is a physical source, a (modes,) coefficient vector or a (modes, illuminations) coefficient batch. Raw coefficients are regular incident channels in this matrix's basis.
CylindricalTMatrix.select¶
CylindricalTMatrix.select(basis: CylindricalBasis) -> CylindricalTMatrix
Select the same subset of incoming and outgoing modes.
CylindricalTMatrix.in_basis¶
CylindricalTMatrix.in_basis(basis: CylindricalBasis) -> CylindricalTMatrix
Represent the same response in another multipole basis.
CylindricalTMatrix.with_polarization¶
CylindricalTMatrix.with_polarization(polarization: str) -> CylindricalTMatrix
Represent the same response in helicity or parity channels.
Every mode needs its partner of opposite polarization in the basis.
CylindricalTMatrix.valid_points¶
CylindricalTMatrix.valid_points(grid: ArrayLike, radii: ArrayLike) -> NDArray[np.bool_]
Points strictly outside the enclosing spheres or infinite cylinders.
CylindricalTMatrix.rotate¶
CylindricalTMatrix.rotate(phi: float, theta: float=0, psi: float=0) -> CylindricalTMatrix
Rotate the local multipole channels about their fixed positions.
The angles are z-y-z Euler angles in radians; cylindrical bases allow only theta=0.
CylindricalTMatrix.translate¶
CylindricalTMatrix.translate(r: ArrayLike) -> CylindricalTMatrix
Represent the same response about expansion positions shifted by r.
The displacement r has shape (3,), in units inverse to k0. Shifting the
positions by r equals moving the scatterer by -r. The result is
operators.translate(r) @ T @ operators.translate(-r) in this basis.
CylindricalTMatrix.material¶
CylindricalTMatrix.material: Material
treams name of medium.
CylindricalTMatrix.poltype¶
CylindricalTMatrix.poltype: str
treams name of polarization.
CylindricalTMatrix.changepoltype¶
CylindricalTMatrix.changepoltype(poltype: str | None=None) -> CylindricalTMatrix
treams name of with_polarization; omitting poltype switches convention.
CylindricalTMatrix.interaction¶
CylindricalTMatrix.interaction: _Interaction[CylindricalTMatrix]
Finite-cluster coupling with solve(), factor() and illuminate() methods.
Calling the object returns I-T*C. Solve builds the full coupled T-matrix; illuminate solves only supplied incident columns; factor keeps the LU factors for repeated calls. All use the current local matrix and basis positions.
CylindricalTMatrix.latticeinteraction¶
CylindricalTMatrix.latticeinteraction: _PeriodicInteraction[CylindricalTMatrix]
Periodic solve/factor/illuminate interface taking lattice and Bloch vector.
Returned responses are local periodic coefficients; isolated-particle cross-section formulas do not apply to them.
CylindricalTMatrix.permute¶
CylindricalTMatrix.permute(n: int=1) -> CylindricalTMatrix
Unsupported: cyclic coordinate permutations act on plane-wave ports.
Always raises TypeError; permute an SMatrix or plane-wave basis instead.
CylindricalTMatrix.medium¶
CylindricalTMatrix.medium: Material
Exterior propagation medium.
CylindricalTMatrix.polarization¶
CylindricalTMatrix.polarization: str
Polarization channel convention.
CylindricalTMatrix.modetype¶
CylindricalTMatrix.modetype = ('singular', 'regular')
treams annotation: singular (outgoing) rows, regular incident columns.
CylindricalTMatrix.expand¶
CylindricalTMatrix.expand(basis: CylindricalBasis) -> CylindricalTMatrix
Same as CylindricalTMatrix.in_basis.
Represent the same response in another multipole basis.
CylindricalTMatrix.expandlattice¶
CylindricalTMatrix.expandlattice = op.OperatorAttribute(op.ExpandLattice)
Periodic expansion into an optional destination basis. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
CylindricalTMatrix.krhos¶
CylindricalTMatrix.krhos: NDArray[np.complex128]
Per-mode radial wavenumbers, shape (modes,), with nonnegative imaginary part.
CylindricalTMatrix.cross_widths¶
CylindricalTMatrix.cross_widths(incident: ArrayLike | PlaneWave | Wave, *, flux: float=0.5) -> CrossSections[float]
Named scattering/extinction/absorption widths, in length units.
Evanescent outgoing orders stay in the solution but carry no far-field power. Evanescent illumination has no incident far-field flux and raises ValueError.
CylindricalTMatrix.cross_sections¶
CylindricalTMatrix.cross_sections(incident: ArrayLike | PlaneWave | Wave, *, flux: float=0.5) -> CrossSections[float]
Cross widths, in length units, for cylinders; cross_widths is the explicit name.
CylindricalTMatrix.average_cross_widths¶
CylindricalTMatrix.average_cross_widths: CrossSections[float]
Mean cross widths over azimuth and propagating axial/polarization channels.
Scattering is the mean radiated width over the same incoming ensemble.
CylindricalTMatrix.xw¶
CylindricalTMatrix.xw(illu: ArrayLike | PlaneWave, flux: float=0.5) -> tuple[float, float]
treams name of cross_widths, returning (scattering, extinction).
CylindricalTMatrix.xw_ext_avg¶
CylindricalTMatrix.xw_ext_avg: float
treams name of average_cross_widths.extinction.
CylindricalTMatrix.xw_sca_avg¶
CylindricalTMatrix.xw_sca_avg: float
treams name of average_cross_widths.scattering.
CylindricalTMatrix.cylinder¶
CylindricalTMatrix.cylinder(kzs: ArrayLike, mmax: int, k0: float, radii: ArrayLike, materials: Sequence[MaterialLike], poltype: str | None=None) -> CylindricalTMatrix
Construct concentric infinite cylinders around the z axis at the origin.
Kzs is a scalar or nonempty one-dimensional array of distinct finite real axial wavenumbers. Mmax (0..128) includes orders -mmax..mmax. K0 is the positive vacuum angular wavenumber, in the same inverse length units as kzs. Radii is a positive scalar or strictly increasing sequence of layer boundaries. Materials lists layers from the axis outward, followed by one exterior medium; entries follow the Material constructor.
For nkz supplied axial values, the dimension is 2*nkz*(2*mmax+1),
ordered by kz input order, then m and pol=(1, 0). Poltype selects
helicity/parity, defaulting to helicity; parity requires an
achiral exterior. diff.cylinder returns the same matrix in helicity
with a context for its gradients. cylinder_tmatrix and
multilayer_cylinder_tmatrix take keywords instead.
Lattice¶
Lattice vectors as rows, along named Cartesian axes.
Mirrors treams.Lattice. The array is a scalar period (1D), the
diagonal of 2 or 3 lengths, or a square 2x2 or 3x3 matrix of row vectors.
alignment names the Cartesian axes of the rows: "z" (default),
"x" or "y" in 1D; "xy" (default), "yz" or "zx" in 2D;
"xyz" in 3D. Lattice(lattice, "xy") selects the sublattice of a 3D
lattice along x and y. The Rust core computes the volume and the reciprocal
vectors.
Lattice.__init__¶
Lattice(arr: ArrayLike | Lattice, alignment: str | None=None)
Lattice.dim¶
Lattice.dim: int
Number of lattice dimensions, 1 to 3.
Lattice.volume¶
Lattice.volume: float
Signed pitch, area or volume.
Lattice.reciprocal¶
Lattice.reciprocal: NDArray[np.float64]
Reciprocal row vectors satisfying a @ b.T = 2 pi I.
Lattice.square¶
Lattice.square(pitch: float, alignment: str | None=None) -> Lattice
Square lattice with side pitch.
Args
pitch: Lattice constant.alignment: Plane of the lattice:"xy"(default),"yz"or"zx". The rows lie along its first and second axis.
Lattice.cubic¶
Lattice.cubic(pitch: float, alignment: str | None=None) -> Lattice
Cubic lattice with side pitch; the alignment can only be "xyz".
Lattice.rectangular¶
Lattice.rectangular(x: float, y: float, alignment: str | None=None) -> Lattice
Rectangular lattice with sides x and y.
Args
x: Length along the first axis of the alignment.y: Length along the second axis of the alignment.alignment: Plane of the lattice:"xy"(default),"yz"or"zx". The rows lie along its first and second axis.
Lattice.orthorhombic¶
Lattice.orthorhombic(x: float, y: float, z: float, alignment: str | None=None) -> Lattice
Orthorhombic lattice with sides x, y and z.
The alignment can only be "xyz".
Lattice.hexagonal¶
Lattice.hexagonal(pitch: float, height: float | None=None, alignment: str | None=None) -> Lattice
Hexagonal lattice with side pitch, 2D or, with height, 3D.
The rows are (pitch, 0) and (pitch/2, sqrt(3) pitch/2) in the plane of
the alignment. height adds the row (0, 0, height) and needs the
alignment "xyz".
Args
pitch: Lattice constant in the plane.height: Period along the third axis; None for a 2D lattice.alignment: Plane of a 2D lattice:"xy"(default),"yz"or"zx".
Lattice.permute¶
Lattice.permute(n: int=1) -> Lattice
Permute the axes cyclically, x -> y -> z, n times.
Lattice.rotate¶
Lattice.rotate(phi: float) -> Lattice
Rotate around z; the resulting span must remain Cartesian aligned.
Lattice.isdisjoint¶
Lattice.isdisjoint(other: Lattice) -> bool
Whether the two lattices share no Cartesian axis.
Lattice.alignment¶
Lattice.alignment: str
Cartesian axes of the rows, for example "xy".
Material¶
Isotropic reciprocal material with relative epsilon, mu and chirality kappa.
Mirrors treams.Material. All three parameters are dimensionless complex
scalars. A single scalar specifies epsilon with mu=1 and kappa=0; a
tuple/list specifies (epsilon, mu, kappa), with omitted trailing values
taking those defaults. Passing another Material copies its three values.
Instances are immutable. Call or iterate the object to get the parameters
in that order.
Material.__init__¶
Material(epsilon: Any=1, mu: Any=1, kappa: Any=0)
Material.from_refractive_index¶
Material.from_refractive_index(n: complex=1, impedance: complex | None=None, kappa: complex=0) -> Material
Construct epsilon=n/impedance and mu=n*impedance.
n is the mean refractive index and impedance is relative to vacuum.
Omitting impedance uses 1/n, giving mu=1. Kappa stays dimensionless.
Material.from_helicity_indices¶
Material.from_helicity_indices(ns: tuple[complex, complex]=(1, 1), impedance: complex | None=None) -> Material
Construct from negative/positive-helicity indices (n_minus, n_plus).
Their mean gives n and half their difference gives kappa. Omitting
impedance uses the same nonmagnetic convention as from_refractive_index.
Material.n¶
Material.n: complex
Square root of epsilon*mu, with sign chosen for nonnegative imaginary part.
Material.nmp¶
Material.nmp: NDArray[np.complex128]
Shape-(2,) complex128 refractive indices for the labels pol 0 and 1.
Start from the principal square root of epsilon*mu minus/plus kappa, then choose each sign for a nonnegative imaginary part. Array order is negative/positive helicity; default mode bases instead list label 1 first.
Material.impedance¶
Material.impedance: complex
Principal square root of mu/epsilon, relative to vacuum impedance.
Material.isreal¶
Material.isreal: bool
Whether epsilon, mu and kappa are all real, as for a lossless medium.
Material.ischiral¶
Material.ischiral: bool
Whether the chirality kappa is nonzero; parity channels need it zero.
Material.ks¶
Material.ks(k0: float) -> NDArray[np.complex128]
Return k0 * nmp in negative/positive-helicity order, shape (2,).
The vacuum angular wavenumber k0 is 2*pi/wavelength, in inverse units of the lengths used elsewhere in the simulation.
Material.kzs¶
Material.kzs(k0: float, kx: ArrayLike, ky: ArrayLike, pol: ArrayLike=(0, 1)) -> NDArray[np.complex128]
Axial wavevectors on the outgoing branch (nonnegative imaginary part).
Material.krhos¶
Material.krhos(k0: float, kz: ArrayLike, pol: ArrayLike=(0, 1)) -> NDArray[np.complex128]
Radial wavevectors on the same outgoing branch as kzs.
Material.epsilon¶
Material.epsilon: Any
Relative permittivity.
Material.mu¶
Material.mu: Any
Relative permeability.
Material.kappa¶
Material.kappa: Any
Chirality parameter, dimensionless.
PeriodicResponse¶
Solved Bloch-periodic response, distinct from an isolated-particle T-matrix.
Conversion methods use the solved array without another interaction solve. Isolated-particle cross-section formulas do not apply to this response.
PeriodicResponse.basis¶
PeriodicResponse.basis: SphericalBasis | CylindricalBasis
Local multipole modes and their positions.
PeriodicResponse.k0¶
PeriodicResponse.k0: float
Vacuum angular wavenumber.
PeriodicResponse.medium¶
PeriodicResponse.medium: Material
Homogeneous exterior (embedding) medium.
PeriodicResponse.polarization¶
PeriodicResponse.polarization: str
Polarization channel convention: helicity or parity.
PeriodicResponse.__init__¶
PeriodicResponse(local: TMatrix | CylindricalTMatrix, array: ArrayLike, *, lattice: ArrayLike, kpar: ArrayLike)
PeriodicResponse.scatter¶
PeriodicResponse.scatter(incident: ArrayLike | PlaneWave | Wave) -> PeriodicWave
Apply this solved response to reference-cell incident coefficients.
Supplied coefficients define the Bloch-periodic excitation via this response's kpar. A plane wave must match that Bloch vector modulo the reciprocal lattice; use a diffraction basis to construct such sources.
PeriodicResponse.to_smatrix¶
PeriodicResponse.to_smatrix(basis: PlaneWavePorts | None=None, *, diffraction_orders: ArrayLike | None=None, orders: ArrayLike | None=None) -> SMatrix
Convert to a fixed plane basis or explicit integer diffraction orders.
Spherical arrays take orders with shape (groups, 2), cylindrical arrays
a vector of orders within one axial sector. Each order includes both
helicities. orders is an alias of diffraction_orders.
PeriodicResponse.to_cylindrical¶
PeriodicResponse.to_cylindrical(basis: CylindricalBasis) -> CylindricalTMatrix
Convert a solved spherical z-periodic response to outgoing cylindrical modes.
A basis with several axes needs one axis per particle position; axis i then collects the waves of particle i only, as in treams.
PeriodicWave¶
Solved local-cell outgoing coefficients with Bloch-periodic geometry.
Local coefficients alone are not a finite radiating wave. Choose a plane-port or cylindrical representation with in_basis before evaluating fields.
PeriodicWave.basis¶
PeriodicWave.basis: SphericalBasis | CylindricalBasis
Local multipole modes and their positions.
PeriodicWave.k0¶
PeriodicWave.k0: float
Vacuum angular wavenumber.
PeriodicWave.medium¶
PeriodicWave.medium: Material
Homogeneous exterior (embedding) medium.
PeriodicWave.polarization¶
PeriodicWave.polarization: str
Polarization channel convention: helicity or parity.
PeriodicWave.__init__¶
PeriodicWave(local: Wave, lattice: ArrayLike, kpar: ArrayLike)
PeriodicWave.coefficients¶
PeriodicWave.coefficients: NDArray[np.complex128]
Read-only outgoing coefficients of the reference cell.
PeriodicWave.in_basis¶
PeriodicWave.in_basis(basis: PlaneWavePorts | CylindricalBasis | SphericalBasis, *, kind: str) -> Wave
Represent all cells in plane ports, cylindrical waves or local regular modes.
kind has no default because a periodic wave has no default radial
kind: choose "up" or "down" for plane ports and "regular" or
"singular" for multipole bases. Field evaluation is valid in the
exterior region of that expansion.
Diffraction orders must match the lattice and Bloch vector. A
cylindrical basis with several axes needs one axis per particle
position, as in to_cylindrical.
PlaneWave¶
An incident plane wave with two amplitudes, ordered by pol index 0, 1.
The treams counterpart is the PhysicsArray that treams.plane_wave
returns. The treams-rs names come first; the treams names
(material, poltype, modetype, expand) follow at the end of
the class and call them.
Treat it as immutable: the constructor checks the metadata attributes once and never again.
PlaneWave.efield¶
PlaneWave.efield(r: ArrayLike) -> NDArray[np.complex128]
Cartesian electric samples (..., 3), or (..., 3, illuminations) for a batch.
PlaneWave.hfield¶
PlaneWave.hfield(r: ArrayLike) -> NDArray[np.complex128]
Cartesian magnetic samples (..., 3), or (..., 3, illuminations) for a batch.
PlaneWave.dfield¶
PlaneWave.dfield(r: ArrayLike) -> NDArray[np.complex128]
Cartesian displacement samples (..., 3), or (..., 3, illuminations).
PlaneWave.bfield¶
PlaneWave.bfield(r: ArrayLike) -> NDArray[np.complex128]
Cartesian flux-density samples (..., 3), or (..., 3, illuminations).
PlaneWave.gfield¶
PlaneWave.gfield(pol: int, r: ArrayLike) -> NDArray[np.complex128]
Riemann-Silberstein G samples (..., 3[, illuminations]), upstream scaling.
PlaneWave.ffield¶
PlaneWave.ffield(pol: int, r: ArrayLike) -> NDArray[np.complex128]
Riemann-Silberstein F samples (..., 3[, illuminations]) with chiral weights.
PlaneWave.__init__¶
PlaneWave(kvec: ArrayLike, pol: ArrayLike, *, k0: float, medium: MaterialLike | None=None, polarization: str | None=None, material: MaterialLike | None=None, poltype: str | None=None)
Construct a plane wave from its direction and polarization state.
Args
kvec: three finite components of the propagation direction; only the direction counts.pol: the pol index 0 or 1, two amplitudes for pol 0 and 1, or three Cartesian electric components.k0: positive vacuum angular wavenumber.medium: the propagation medium, vacuum by default.polarization: "helicity" (default) or "parity".material: treams name ofmedium.poltype: treams name ofpolarization.
Give each quantity under one name. plane_wave also accepts the
named states "positive_helicity" and "negative_helicity".
PlaneWave.coefficients¶
PlaneWave.coefficients: NDArray[np.complex128]
Read-only polarization amplitudes in negative/positive label order.
PlaneWave.with_polarization¶
PlaneWave.with_polarization(polarization: str) -> PlaneWave
Represent the same plane wave with helicity or parity amplitudes.
PlaneWave.in_basis¶
PlaneWave.in_basis(basis: SphericalBasis | CylindricalBasis | PlaneWavePorts | PlaneWaveBasis) -> Wave
Expand into a typed regular multipole wave or directional plane wave.
PlaneWave.basis¶
PlaneWave.basis: PlaneWaveBasis
The two plane-wave modes of the direction, pol 0 then pol 1.
PlaneWave.array¶
PlaneWave.array: NDArray[np.complex128]
The two amplitudes, shape (2,), ordered by pol index 0, 1.
PlaneWave.kvecs¶
PlaneWave.kvecs: NDArray[np.complex128]
Wave vectors in the medium, shape (2, 3), one row per pol index.
PlaneWave.material¶
PlaneWave.material: Material
treams name of medium.
PlaneWave.poltype¶
PlaneWave.poltype: str
treams name of polarization.
PlaneWave.expand¶
PlaneWave.expand(basis: SphericalBasis | CylindricalBasis | PlaneWavePorts | PlaneWaveBasis) -> NDArray[np.complex128]
Coefficients only of in_basis(basis).
PlaneWave.medium¶
PlaneWave.medium: Material
Homogeneous propagation medium.
PlaneWave.polarization¶
PlaneWave.polarization: str
Polarization basis convention: helicity or parity.
PlaneWave.kind¶
PlaneWave.kind = 'up'
Always "up": the basis lists the wave's own direction.
PlaneWave.modetype¶
PlaneWave.modetype = 'up'
Same as PlaneWave.kind.
Always "up": the basis lists the wave's own direction.
PlaneWaveBasis¶
Ordered plane modes (qx, qy, qz, pol) with complex unit directions.
Mirrors treams.PlaneWaveBasisByUnitVector. Directions are normalized by
the algebraic norm sqrt(q.q), without complex conjugation; zero or null
directions are invalid. Labels pol are 0 or 1; the wave or operator that
uses the basis sets the polarization convention. The basis stores
directions, not wavevectors; kvecs scales them with k0 and the medium.
Exact duplicate rows are removed in order.
PlaneWaveBasis.index¶
PlaneWaveBasis.index(mode: tuple[complex, complex, complex, int], start: int=0, stop: int | None=None) -> int
Index of mode, like tuple.index; ValueError when it is absent.
PlaneWaveBasis.count¶
PlaneWaveBasis.count(mode: tuple[complex, complex, complex, int]) -> int
Number of times mode occurs: 0 or 1, because modes are distinct.
PlaneWaveBasis.isdisjoint¶
PlaneWaveBasis.isdisjoint(other: PlaneWaveBasis) -> bool
Whether the bases share no mode; both need one family and geometry.
PlaneWaveBasis.lattice¶
PlaneWaveBasis.lattice: Lattice | None = None
Lattice of a periodic arrangement, or None.
PlaneWaveBasis.kpar¶
PlaneWaveBasis.kpar: WaveVector | None = None
Bloch vector of a periodic arrangement, or None.
PlaneWaveBasis.modes¶
PlaneWaveBasis.modes: tuple[tuple[complex, complex, complex, int], ...]
The mode labels, in order.
PlaneWaveBasis.__init__¶
PlaneWaveBasis(modes: Iterable[Sequence[complex]])
PlaneWaveBasis.qx¶
PlaneWaveBasis.qx: NDArray[np.complex128]
x component of each unit direction, shape (modes,).
PlaneWaveBasis.qy¶
PlaneWaveBasis.qy: NDArray[np.complex128]
y component of each unit direction, shape (modes,).
PlaneWaveBasis.qz¶
PlaneWaveBasis.qz: NDArray[np.complex128]
z component of each unit direction, shape (modes,).
PlaneWaveBasis.pol¶
PlaneWaveBasis.pol: NDArray[np.int64]
Label pol (0 or 1) of each mode, shape (modes,); read-only and cached.
PlaneWaveBasis.default¶
PlaneWaveBasis.default(kvecs: ArrayLike) -> PlaneWaveBasis
Normalize shape-(n, 3) directions and include pol 0 and 1.
A single shape-(3,) vector is accepted. Each direction contributes labels (1, 0), in that order. Complex directions allow evanescent waves.
PlaneWaveBasis.kvecs¶
PlaneWaveBasis.kvecs(k0: float, material: MaterialLike=1, modetype: str | None=None) -> tuple[NDArray[np.complex128], NDArray[np.complex128], NDArray[np.complex128]]
Return (kx, ky, kz), each shape (modes,), in inverse length units.
Each direction is scaled by its medium wavenumber at the vacuum angular
wavenumber k0. The direction fixes the propagation, so modetype has no
effect; it is accepted for a signature shared with PlaneWavePorts.kvecs.
PlaneWaveBasis.rotate¶
PlaneWaveBasis.rotate(phi: float) -> PlaneWaveBasis
Rotate direction labels around z, preserving their pol labels.
Quarter turns are exact, matching the rotated lattice metadata.
PlaneWaveBasis.permute¶
PlaneWaveBasis.permute(n: int=1) -> PlaneWaveBasis
Permute the direction components cyclically, x -> y -> z, n times.
Labels pol stay; lattice and Bloch vector permute along.
PlaneWaveBasis.bycomp¶
PlaneWaveBasis.bycomp(k0: float, alignment: str='xy', material: MaterialLike=1) -> PlaneWavePorts
The same modes as PlaneWavePorts, which store two wavevector components.
Mirrors treams.PlaneWaveBasisByUnitVector.bycomp. The components named
by alignment ("xy", "yz" or "zx") of every wavevector at
k0 in material must be real.
PlaneWaveBasis.isglobal¶
PlaneWaveBasis.isglobal = True
Always True: plane waves have no expansion positions.
PlaneWavePorts¶
Ordered plane modes (k1, k2, pol) storing two real wavevector components.
Mirrors treams.PlaneWaveBasisByComp. The alignment "xy", "yz"
or "zx" names the stored Cartesian components (k1, k2), in inverse
length units. Labels pol are 0 or 1; the wave or operator that uses the
basis sets the polarization convention. kvecs adds the third component
from k0, the medium and the direction up or down, including evanescent
waves. Exact duplicate modes are removed in order.
PlaneWavePorts.index¶
PlaneWavePorts.index(mode: tuple[float, float, int], start: int=0, stop: int | None=None) -> int
Index of mode, like tuple.index; ValueError when it is absent.
PlaneWavePorts.count¶
PlaneWavePorts.count(mode: tuple[float, float, int]) -> int
Number of times mode occurs: 0 or 1, because modes are distinct.
PlaneWavePorts.isdisjoint¶
PlaneWavePorts.isdisjoint(other: PlaneWavePorts) -> bool
Whether the bases share no mode; both need one family and geometry.
PlaneWavePorts.lattice¶
PlaneWavePorts.lattice: Lattice | None = None
Lattice of a periodic arrangement, or None.
PlaneWavePorts.kpar¶
PlaneWavePorts.kpar: WaveVector | None = None
Bloch vector of a periodic arrangement, or None.
PlaneWavePorts.modes¶
PlaneWavePorts.modes: tuple[tuple[float, float, int], ...]
The mode labels, in order.
PlaneWavePorts.__init__¶
PlaneWavePorts(modes: Iterable[Sequence[float]], alignment: str='xy')
PlaneWavePorts.default¶
PlaneWavePorts.default(kpars: ArrayLike, alignment: str='xy') -> PlaneWavePorts
Include labels (1, 0) for each shape-(n, 2) transverse wavevector.
A single shape-(2,) pair is accepted. Components are real and dimensional, in the Cartesian order specified by alignment (xy, yz or zx).
PlaneWavePorts.diffr_orders¶
PlaneWavePorts.diffr_orders(kpar: ArrayLike, lattice: ArrayLike, bmax: float, *, alignment: str | None=None) -> PlaneWavePorts
Pol 0 and 1 of all reciprocal vectors with length <= bmax.
The cutoff applies before adding the Bloch vector. Opposite diffraction orders are adjacent, following treams ordering for rectangular lattices.
PlaneWavePorts.normal_axis¶
PlaneWavePorts.normal_axis: int
Cartesian axis normal to the stored component plane.
PlaneWavePorts.components¶
PlaneWavePorts.components: NDArray[np.float64]
The two real stored components, in alignment order.
PlaneWavePorts.kx¶
PlaneWavePorts.kx: NDArray[np.float64] | None
x component of each wavevector, shape (modes,); None if not stored.
PlaneWavePorts.ky¶
PlaneWavePorts.ky: NDArray[np.float64] | None
y component of each wavevector, shape (modes,); None if not stored.
PlaneWavePorts.kz¶
PlaneWavePorts.kz: NDArray[np.float64] | None
z component of each wavevector, shape (modes,); None if not stored.
PlaneWavePorts.rotate¶
PlaneWavePorts.rotate(phi: float) -> PlaneWavePorts
Rotate xy direction labels around z, preserving their pol labels.
Quarter turns are exact, matching the rotated lattice metadata.
PlaneWavePorts.permute¶
PlaneWavePorts.permute(n: int=1) -> PlaneWavePorts
Permute the alignment cyclically, xy -> yz -> zx, n times.
The stored components and labels pol stay; lattice and Bloch vector permute along.
PlaneWavePorts.pol¶
PlaneWavePorts.pol: NDArray[np.int64]
Label pol (0 or 1) of each mode, shape (modes,); read-only and cached.
PlaneWavePorts.kvecs¶
PlaneWavePorts.kvecs(k0: float, material: MaterialLike=1, modetype: str='up') -> tuple[NDArray[np.complex128], NDArray[np.complex128], NDArray[np.complex128]]
Return (kx, ky, kz), each shape (modes,), at vacuum wavenumber k0.
The missing normal component uses the medium's outgoing square-root
branch. modetype='down' reverses that component; 'up' keeps it.
Stored transverse components remain unchanged, in inverse length units.
PlaneWavePorts.byunitvector¶
PlaneWavePorts.byunitvector(k0: float, material: MaterialLike=1, modetype: str='up') -> PlaneWaveBasis
The same modes as a PlaneWaveBasis of unit directions.
Mirrors treams.PlaneWaveBasisByComp.byunitvector. The third component
comes from k0, material and modetype ("up" or "down"), as
in kvecs.
PlaneWavePorts.isglobal¶
PlaneWavePorts.isglobal = True
Always True: plane waves have no expansion positions.
PowerBalance¶
Transmitted and reflected power as fractions of the incident power.
Units: none; a lossless network gives transmission + reflection = 1. Fields are floats for SMatrix.power, and framework arrays in advect, jax and torch.
PowerBalance.absorption¶
PowerBalance.absorption: T
Fraction not carried by transmitted or reflected power.
PowerBalance.transmission¶
PowerBalance.transmission: T
PowerBalance.reflection¶
PowerBalance.reflection: T
SMatrix¶
Planar two-port network: four scattering blocks of plane-wave ports.
The treams counterpart is treams.SMatrices; one block is a
ScatteringBlock (treams.SMatrix). array has shape (2, 2, n, n):
the first index is the outgoing direction and the second the incoming
one, 0 for up (towards the positive side) and 1 for down.
positive_medium (above) and negative_medium (below) are the
exterior media on either side of the basis normal. interface,
slab, stack and the module-level factories take media and layers
from the negative to the positive side; the treams material pair is
(positive side, negative side).
The treams-rs names come first. The treams names (add,
illuminate, tr, material, ...) follow at the end of the class
and call them.
Treat it as immutable: the constructor checks the metadata attributes once and never again.
SMatrix.__init__¶
SMatrix(smats: ArrayLike, *, k0: float, basis: PlaneWavePorts, positive_medium: MaterialLike | None=None, negative_medium: MaterialLike | None=None, polarization: str | None=None, material: MaterialLike | tuple[MaterialLike, MaterialLike] | None=None, poltype: str | None=None)
Copy the four blocks of a two-port network.
Args
smats: shape (2, 2, n, n) with n = len(basis). The first index is the outgoing direction (0 up, 1 down), the second the incoming one.k0: positive vacuum angular wavenumber.basis: the plane-wave ports of every block.positive_medium: exterior medium on the positive side (above), vacuum by default.negative_medium: exterior medium on the negative side (below), vacuum by default.polarization: "helicity" (default) or "parity".material: treams name of the media: one medium for both sides, or the pair (positive side, negative side).poltype: treams name ofpolarization.
Give each quantity under one name.
SMatrix.block¶
SMatrix.block(outgoing: int | str, incoming: int | str) -> ScatteringBlock
Read-only block view with port metadata, sharing this stack's storage.
Numeric indexing remains an ndarray view for inexpensive numerical work. Name physical sides with positive/negative, for example block(outgoing="positive", incoming="negative") is forward transmission. Numeric 0/1 and up/down specify propagation directions instead.
SMatrix.positive_medium¶
SMatrix.positive_medium: Material
Exterior medium on the positive side of the basis normal.
SMatrix.negative_medium¶
SMatrix.negative_medium: Material
Exterior medium on the negative side of the basis normal.
SMatrix.cascade¶
SMatrix.cascade(next_layer: SMatrix) -> SMatrix
Place the next layer on the positive side and compose all reflections.
Args
next_layer: an SMatrix with the same ports, k0 and polarization. Its negative medium must equal this network's positive medium.
Returns the network from this negative medium to the positive medium of
next_layer.
SMatrix.with_polarization¶
SMatrix.with_polarization(polarization: str) -> SMatrix
Express the same scattering response in another polarization convention.
Every port needs its partner of opposite polarization in the basis.
SMatrix.transfer_matrix¶
SMatrix.transfer_matrix() -> NDArray[np.complex128]
Transfer matrix for repeating a cell along the basis normal.
The outer media must match. Strongly evanescent channels can make a transfer matrix ill-conditioned; finite-stack composition remains in S form.
SMatrix.bands¶
SMatrix.bands(*, period: float) -> BandModes[NDArray[np.complex128]]
Bloch wavenumbers and eigenvectors of the repeated cell along the basis normal.
Args
period: positive cell length along the normal, in units inverse to k0. The outer media must match.
SMatrix.power¶
SMatrix.power(incident: ArrayLike | PlaneWave | Wave, *, side: str | None=None) -> PowerBalance[float]
Transmission, reflection and absorption fractions for one illumination.
Args
incident: a PlaneWave, a Wave in these ports, or n coefficients of one illumination, ordered like the ports.side: the exterior the light comes from, "negative" or "positive". Physical waves infer it from their propagation direction; raw arrays default to "negative".
Returns fractions of the incident power, so transmission + reflection + absorption = 1.
SMatrix.circular_dichroism¶
SMatrix.circular_dichroism(incident: ArrayLike | PlaneWave | Wave, *, side: str | None=None) -> CircularDichroism
Named transmission and total-outgoing-power polarization contrasts.
SMatrix.scatter¶
SMatrix.scatter(*, negative: ArrayLike | PlaneWave | Wave | None=None, positive: ArrayLike | PlaneWave | Wave | None=None) -> ScatteredPorts[Wave]
Outgoing waves for incidence from either or both named exterior sides.
Each supplied source is one illumination; coherent two-sided illumination is accepted. Evaluate fields on the corresponding exterior side.
SMatrix.interface¶
SMatrix.interface(basis: PlaneWavePorts, k0: float, materials: Sequence[MaterialLike], poltype: str | None=None) -> SMatrix
Planar interface between two media, normal to the basis normal.
Args
basis: the plane-wave ports;basis.normal_axisis the normal.k0: positive vacuum angular wavenumber, in inverse length units.materials: two media ordered negative side, positive side (below, above); each follows the Material constructor.poltype: "helicity" (default) or "parity"; parity needs achiral media.
interface(negative_medium=..., positive_medium=...) takes keywords
instead.
SMatrix.propagation¶
SMatrix.propagation(r: ArrayLike, basis: PlaneWavePorts, k0: float, material: MaterialLike=1, poltype: str | None=None) -> SMatrix
Homogeneous propagation through one medium.
Args
r: distance along the basis normal, or a Cartesian displacement of shape (3,), in units inverse to k0.basis: the plane-wave ports.k0: positive vacuum angular wavenumber.material: the homogeneous medium, vacuum by default.poltype: "helicity" (default) or "parity".
propagation(distance=..., medium=...) takes keywords instead.
SMatrix.stack¶
SMatrix.stack(items: Sequence[SMatrix]) -> SMatrix
Cascade networks in order from the negative to the positive side.
Args
items: at least one SMatrix; each sits on the positive side of the one before, as incascade.
SMatrix.slab¶
SMatrix.slab(thickness: ArrayLike, basis: PlaneWavePorts, k0: float, materials: Sequence[MaterialLike], poltype: str | None=None) -> SMatrix
Planar layers between two exterior media.
Args
thickness: one nonnegative thickness per layer (a scalar for one layer), in units inverse to k0.basis: the plane-wave ports.k0: positive vacuum angular wavenumber.materials: len(thickness) + 2 media from the negative to the positive side: the negative exterior, each layer, then the positive exterior.poltype: "helicity" (default) or "parity".
Both polarizations propagate inside the stack, including channels absent
from the requested ports. The result keeps the selected input and output
ports. slab and multilayer_slab take keywords instead.
SMatrix.double¶
SMatrix.double(n: int=1) -> SMatrix
Cascade the network with itself n times, giving 2**n copies.
Args
n: nonnegative number of doublings. The outer media must match.
SMatrix.rotate¶
SMatrix.rotate(phi: float, theta: float=0, psi: float=0) -> SMatrix
Rotate xy plane-wave labels and their periodic metadata around z.
SMatrix.translate¶
SMatrix.translate(r: ArrayLike) -> SMatrix
Shift the reference position of every port by r, shape (3,).
Each block gains diagonal plane-wave phase factors on both sides.
SMatrix.permute¶
SMatrix.permute(n: int=1) -> SMatrix
Cyclic coordinate change of both ports and their polarization frames.
Each block becomes F_i S_ij G_j with the forward polarization change F_i of its outgoing ports and the inverse change G_j of its incoming ports.
SMatrix.material¶
SMatrix.material: tuple[Material, Material]
treams order: (positive side, negative side); prefer positive_medium/negative_medium.
SMatrix.poltype¶
SMatrix.poltype: str
treams name of polarization.
SMatrix.changepoltype¶
SMatrix.changepoltype(poltype: str | None=None) -> SMatrix
treams name of with_polarization; omitting poltype switches convention.
SMatrix.add¶
SMatrix.add(upper: SMatrix) -> SMatrix
treams name of cascade.
SMatrix.illuminate¶
SMatrix.illuminate(illu: ArrayLike | PlaneWave | Wave, illu2: ArrayLike | PlaneWave | Wave | None=None, *, modetype: str | None=None, smat: SMatrix | None=None) -> tuple[NDArray[np.complex128], ...]
treams name of scatter, returning coefficient arrays.
With smat, also returns the internal up/down coefficients below that
adjacent stack.
SMatrix.tr¶
SMatrix.tr(illu: ArrayLike | PlaneWave | Wave, *, modetype: str | None=None) -> tuple[float, float]
treams name of power, returning (transmission, reflection).
SMatrix.cd¶
SMatrix.cd(illu: ArrayLike | PlaneWave | Wave, *, modetype: str | None=None) -> tuple[float, float]
treams name of circular_dichroism, returning the two contrasts.
These are (T_opposite-T)/(T_opposite+T) and ((T+R)_opposite-(T+R))/((T+R)_opposite+(T+R)).
SMatrix.bands_kz¶
SMatrix.bands_kz(az: float) -> tuple[NDArray[np.complex128], NDArray[np.complex128]]
treams name of bands(period=az), returning (kz, eigenvectors).
kz lies along the basis normal, which is x or y for yz or zx bases.
SMatrix.polarization¶
SMatrix.polarization: str
Polarization channel convention.
SMatrix.periodic¶
SMatrix.periodic() -> NDArray[np.complex128]
Same as SMatrix.transfer_matrix.
Transfer matrix for repeating a cell along the basis normal.
The outer media must match. Strongly evanescent channels can make a transfer matrix ill-conditioned; finite-stack composition remains in S form.
ScatteredPorts¶
Outgoing waves on the positive and negative side of the stack normal.
Units: plane-wave amplitudes in the normalization of the incident wave. Fields are Wave objects for SMatrix.scatter, and PortWave objects in advect, jax and torch.
ScatteredPorts.positive¶
ScatteredPorts.positive: W
ScatteredPorts.negative¶
ScatteredPorts.negative: W
ScatteringBlock¶
One scattering block with explicit input and output port metadata.
The treams counterpart is treams.SMatrix, one block of the network
that treams calls SMatrices. It keeps the treams attribute names of
PhysicsArray. Blocks from SMatrix.block store material and modetype as
pairs (outgoing ports, incoming ports); a block built directly stores what
it is given. poltype is one polarization convention for both sides.
ScatteringBlock.__init__¶
ScatteringBlock(arr: ArrayLike, *, k0: float, basis: PlaneWavePorts, material: MaterialLike | tuple[MaterialLike, MaterialLike]=1, poltype: str | None=None, modetype: tuple[str, str]=('up', 'up')) -> None
ScatteringBlock.shape¶
ScatteringBlock.shape: tuple[int, ...]
Shape of array.
ScatteringBlock.ndim¶
ScatteringBlock.ndim: int
Number of dimensions of array.
ScatteringBlock.changepoltype¶
ScatteringBlock.changepoltype = op.OperatorAttribute(op.ChangePoltype)
Helicity/parity conversion; omission selects the opposite input convention. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.rotate¶
ScatteringBlock.rotate = op.OperatorAttribute(op.Rotate)
Euler rotation with an exact inverse obtained by reversing the angles. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.translate¶
ScatteringBlock.translate = op.OperatorAttribute(op.Translate)
Translation with the inverse displacement in the reversed basis pair. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.expand¶
ScatteringBlock.expand = op.OperatorAttribute(op.Expand)
Expand into a destination basis, obtaining the source from keyword metadata. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.expandlattice¶
ScatteringBlock.expandlattice = op.OperatorAttribute(op.ExpandLattice)
Periodic expansion into an optional destination basis. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.permute¶
ScatteringBlock.permute = op.OperatorAttribute(op.Permute)
Cyclic plane-wave coordinate permutation. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.efield¶
ScatteringBlock.efield = op.OperatorAttribute(op.EField)
Electric field evaluation. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.hfield¶
ScatteringBlock.hfield = op.OperatorAttribute(op.HField)
Magnetic field evaluation. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.dfield¶
ScatteringBlock.dfield = op.OperatorAttribute(op.DField)
Displacement field evaluation. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.bfield¶
ScatteringBlock.bfield = op.OperatorAttribute(op.BField)
Magnetic flux density evaluation. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.gfield¶
ScatteringBlock.gfield = op.OperatorAttribute(op.GField)
Riemann-Silberstein field G, with explicit helicity and sample points. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringBlock.ffield¶
ScatteringBlock.ffield = op.OperatorAttribute(op.FField)
Riemann-Silberstein field F, with explicit helicity and sample points. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
ScatteringFactor¶
Reusable dense factor for requested finite-cluster illuminations.
ScatteringFactor.__init__¶
ScatteringFactor(local: TMatrix | CylindricalTMatrix, factor: _native.InteractionFactor)
ScatteringFactor.scatter¶
ScatteringFactor.scatter(incident: ArrayLike | PlaneWave | Wave) -> Any
Solve one source or a (modes, illuminations) batch with the stored LU factors.
SphericalBasis¶
Ordered modes (pidx, l, m, pol) and Cartesian expansion positions.
Mirrors treams.SphericalWaveBasis. Rows (l, m, pol) imply pidx=0.
Positions have shape (particles, 3) in the simulation's length unit; a
shape-(3,) position is also accepted. Require 1 <= l <= 128, -l <= m <= l
and pol in {0, 1}. Exact duplicate modes are removed in order. The wave or
operator that uses the basis sets the polarization convention: helicity
labels 0/1 mean negative/positive, parity labels magnetic/electric.
Selecting modes keeps the positions.
SphericalBasis.index¶
SphericalBasis.index(mode: SphericalMode, start: int=0, stop: int | None=None) -> int
Index of mode, like tuple.index; ValueError when it is absent.
SphericalBasis.count¶
SphericalBasis.count(mode: SphericalMode) -> int
Number of times mode occurs: 0 or 1, because modes are distinct.
SphericalBasis.isdisjoint¶
SphericalBasis.isdisjoint(other: SphericalBasis) -> bool
Whether the bases share no mode; both need one family and geometry.
SphericalBasis.lattice¶
SphericalBasis.lattice: Lattice | None = None
Lattice of a periodic arrangement, or None.
SphericalBasis.kpar¶
SphericalBasis.kpar: WaveVector | None = None
Bloch vector of a periodic arrangement, or None.
SphericalBasis.modes¶
SphericalBasis.modes: tuple[SphericalMode, ...]
The mode labels, in order.
SphericalBasis.__init__¶
SphericalBasis(modes: Iterable[Sequence[float]], positions: ArrayLike=((0, 0, 0),))
SphericalBasis.pidx¶
SphericalBasis.pidx: NDArray[np.int64]
Particle index of each mode, shape (modes,).
A read-only column cached per basis, like pol; call .copy() to
edit it.
SphericalBasis.m¶
SphericalBasis.m: NDArray[np.int64]
Azimuthal order of each mode, shape (modes,).
A read-only column cached per basis, like pol; call .copy() to
edit it.
SphericalBasis.pol¶
SphericalBasis.pol: NDArray[np.int64]
Label pol (0 or 1) of each mode, shape (modes,); read-only and cached.
SphericalBasis.isglobal¶
SphericalBasis.isglobal: bool
Whether every mode has the same particle index.
SphericalBasis.defaultdim¶
SphericalBasis.defaultdim(lmax: int, nmax: int=1) -> int
Return 2*lmax*(lmax+2)*nmax channels for a complete default basis.
SphericalBasis.defaultlmax¶
SphericalBasis.defaultlmax(dim: int, nmax: int=1) -> int
Invert defaultdim; reject dimensions that omit part of a mode shell.
SphericalBasis.default¶
SphericalBasis.default(lmax: int, nmax: int=1, positions: ArrayLike | None=None) -> SphericalBasis
Create complete spherical mode shells at nmax expansion positions.
Order is particle, l=1..lmax, m=-l..l, then pol=(1, 0). The dimension is
2*lmax*(lmax+2)*nmax. Require 0 <= lmax <= 128 and nmax >= 1; lmax=0
makes an empty basis. Positions have shape (nmax, 3), defaulting to zeros,
and use the simulation's length unit.
SphericalBasis.ebcm¶
SphericalBasis.ebcm(lmax: int, nmax: int=1, mmax: int=-1, positions: ArrayLike | None=None) -> SphericalBasis
Complete mode shells in EBCM order: particle, then m, degree and pol=(1, 0).
Mirrors treams.SphericalWaveBasis.ebcm. Orders run over -mmax..mmax
and degrees over max(1, |m|)..lmax; mmax=-1 uses lmax. Require
0 <= mmax <= lmax <= 128 and nmax >= 1. Positions have shape (nmax, 3),
zeros by default.
SphericalBasis.l¶
SphericalBasis.l: NDArray[np.int64]
Degree of each mode, shape (modes,).
A read-only column cached per basis, like pol; call .copy() to
edit it.
SphericalBasis.lms¶
SphericalBasis.lms: tuple[NDArray[np.int64], NDArray[np.int64], NDArray[np.int64]]
The columns (l, m, pol), as treams' lms.
TMatrix¶
Spherical T-matrix: regular incident coefficients to singular (outgoing) ones.
The treams counterpart is treams.TMatrix. Build one with
sphere_tmatrix, multilayer_sphere_tmatrix or Cluster.solve, or
from a square array. Rows and columns follow basis, a SphericalBasis.
scatter(incident) returns the scattered Wave; array and @ give
the coefficients. Framework-valued inputs select their differentiation
adapter automatically.
The treams-rs names come first. The treams names (xs, cd,
poltype, changepoltype, ...) follow at the end of the class and
call them.
Treat it as immutable: the constructor checks the metadata attributes once and never again.
TMatrix.__init__¶
TMatrix(arr: ArrayLike, *, k0: float, basis: SphericalBasis | None=None, medium: MaterialLike | None=None, polarization: str | None=None, material: MaterialLike | None=None, poltype: str | None=None)
Copy a finite square matrix mapping regular to outgoing coefficients.
Args
arr: shape (modes, modes), outgoing rows and incident columns..arrayholds an owned, read-only complex128 copy.k0: positive vacuum angular wavenumber, in inverse units of the basis positions.basis: modes of the rows and columns, of the matrix's wave family. Omitted, it is the complete basis at one position for this dimension (with kz=0 for cylinders).medium: the embedding medium, vacuum by default.polarization: "helicity" (default) or "parity". A chiral medium needs "helicity".material: treams name ofmedium.poltype: treams name ofpolarization.
Give each quantity under one name.
TMatrix.shape¶
TMatrix.shape: tuple[int, ...]
Shape (modes, modes) of the matrix.
TMatrix.ks¶
TMatrix.ks: NDArray[np.complex128]
Embedding wavenumbers for labels (0, 1), shape (2,), in inverse length.
TMatrix.isglobal¶
TMatrix.isglobal: bool
Whether all multipoles of the basis share one position.
TMatrix.scatter¶
TMatrix.scatter(incident: ArrayLike | PlaneWave | Wave) -> Wave
Apply this solved response and retain outgoing-wave metadata.
Incident is a physical source, a (modes,) coefficient vector or a (modes, illuminations) coefficient batch. Raw coefficients are regular incident channels in this matrix's basis.
TMatrix.select¶
TMatrix.select(basis: SphericalBasis) -> TMatrix
Select the same subset of incoming and outgoing modes.
TMatrix.in_basis¶
TMatrix.in_basis(basis: SphericalBasis) -> TMatrix
Represent the same response in another multipole basis.
TMatrix.with_polarization¶
TMatrix.with_polarization(polarization: str) -> TMatrix
Represent the same response in helicity or parity channels.
Every mode needs its partner of opposite polarization in the basis.
TMatrix.valid_points¶
TMatrix.valid_points(grid: ArrayLike, radii: ArrayLike) -> NDArray[np.bool_]
Points strictly outside the enclosing spheres or infinite cylinders.
TMatrix.rotate¶
TMatrix.rotate(phi: float, theta: float=0, psi: float=0) -> TMatrix
Rotate the local multipole channels about their fixed positions.
The angles are z-y-z Euler angles in radians; cylindrical bases allow only theta=0.
TMatrix.translate¶
TMatrix.translate(r: ArrayLike) -> TMatrix
Represent the same response about expansion positions shifted by r.
The displacement r has shape (3,), in units inverse to k0. Shifting the
positions by r equals moving the scatterer by -r. The result is
operators.translate(r) @ T @ operators.translate(-r) in this basis.
TMatrix.material¶
TMatrix.material: Material
treams name of medium.
TMatrix.poltype¶
TMatrix.poltype: str
treams name of polarization.
TMatrix.changepoltype¶
TMatrix.changepoltype(poltype: str | None=None) -> TMatrix
treams name of with_polarization; omitting poltype switches convention.
TMatrix.interaction¶
TMatrix.interaction: _Interaction[TMatrix]
Finite-cluster coupling with solve(), factor() and illuminate() methods.
Calling the object returns I-T*C. Solve builds the full coupled T-matrix; illuminate solves only supplied incident columns; factor keeps the LU factors for repeated calls. All use the current local matrix and basis positions.
TMatrix.latticeinteraction¶
TMatrix.latticeinteraction: _PeriodicInteraction[TMatrix]
Periodic solve/factor/illuminate interface taking lattice and Bloch vector.
Returned responses are local periodic coefficients; isolated-particle cross-section formulas do not apply to them.
TMatrix.permute¶
TMatrix.permute(n: int=1) -> TMatrix
Unsupported: cyclic coordinate permutations act on plane-wave ports.
Always raises TypeError; permute an SMatrix or plane-wave basis instead.
TMatrix.medium¶
TMatrix.medium: Material
Exterior propagation medium.
TMatrix.polarization¶
TMatrix.polarization: str
Polarization channel convention.
TMatrix.modetype¶
TMatrix.modetype = ('singular', 'regular')
treams annotation: singular (outgoing) rows, regular incident columns.
TMatrix.expand¶
TMatrix.expand(basis: SphericalBasis) -> TMatrix
Same as TMatrix.in_basis.
Represent the same response in another multipole basis.
TMatrix.expandlattice¶
TMatrix.expandlattice = op.OperatorAttribute(op.ExpandLattice)
Periodic expansion into an optional destination basis. Bound OperatorAttribute: call applies to the owning object; .eval returns the operator matrix.
TMatrix.cross_sections¶
TMatrix.cross_sections(incident: ArrayLike | PlaneWave | Wave, *, flux: float=0.5) -> CrossSections[float]
Named scattering/extinction/absorption cross sections in squared length units.
Incident is a matching PlaneWave or Wave, or a (modes,) regular coefficient vector. Flux is its finite positive incident flux in the field normalization. The exterior must be nonabsorbing with propagating helicity wavenumbers. A solved finite cluster may keep several positions.
TMatrix.average_cross_sections¶
TMatrix.average_cross_sections: CrossSections[float]
Rotationally and polarization-averaged cross sections in squared length units.
Requires one position and a nonabsorbing propagating exterior. Expand a solved cluster to a global basis before taking this average.
TMatrix.circular_dichroism¶
TMatrix.circular_dichroism: float
Rotationally averaged absorption circular dichroism.
TMatrix.duality_breaking¶
TMatrix.duality_breaking: float
Fraction of scattering that changes helicity.
TMatrix.electromagnetic_chirality¶
TMatrix.electromagnetic_chirality: float
Normalized electromagnetic chirality from helicity-block singular values.
TMatrix.xs¶
TMatrix.xs(illu: ArrayLike | PlaneWave, flux: float=0.5) -> tuple[float, float]
treams name of cross_sections, returning (scattering, extinction).
TMatrix.xs_ext_avg¶
TMatrix.xs_ext_avg: float
treams name of average_cross_sections.extinction.
TMatrix.xs_sca_avg¶
TMatrix.xs_sca_avg: float
treams name of average_cross_sections.scattering.
TMatrix.sphere¶
TMatrix.sphere(lmax: int, k0: float, radii: ArrayLike, materials: Sequence[MaterialLike], poltype: str | None=None) -> TMatrix
Construct a concentric multilayer, optionally chiral sphere at the origin.
Lmax is the maximum spherical degree (1..128); k0 is the positive vacuum angular wavenumber. Radii is a positive scalar or strictly increasing one-dimensional sequence of layer boundaries, in units inverse to k0. Materials contains one entry per layer plus the exterior medium, ordered from the center outward. Each entry follows the Material constructor.
Returns a matrix with dimension 2*lmax*(lmax+2) and default spherical
ordering (l, m, pol=(1, 0)). Poltype selects helicity/parity, defaulting to
helicity; parity requires an achiral exterior. diff.sphere returns
the same matrix in helicity with a context for its gradients.
sphere_tmatrix and multilayer_sphere_tmatrix take keywords instead.
TMatrix.cd¶
TMatrix.cd() -> float
Same as TMatrix.circular_dichroism.
Rotationally averaged absorption circular dichroism.
TMatrix.db¶
TMatrix.db() -> float
Same as TMatrix.duality_breaking.
Fraction of scattering that changes helicity.
TMatrix.chi¶
TMatrix.chi() -> float
Same as TMatrix.electromagnetic_chirality.
Normalized electromagnetic chirality from helicity-block singular values.
Wave¶
Physical wave amplitudes with explicit basis, medium and kind.
The treams counterpart is the PhysicsArray that treams.spherical_wave
and the other wave functions return. kind is the radial kind of
multipoles (regular or singular) or the direction of plane-wave ports (up
or down). Fields use weighted Rust kernels and never form the full
sample-by-mode operator. Use coefficients for numerical work;
framework-valued inputs retain their gradients. A batch keeps one
illumination per column.
The treams-rs names come first. The treams names (material,
poltype, modetype, expand, ...) follow at the end of the class
and call them.
Treat it as immutable: the constructor checks the metadata attributes once and never again.
Wave.efield¶
Wave.efield(r: ArrayLike) -> NDArray[np.complex128]
Cartesian electric samples (..., 3), or (..., 3, illuminations) for a batch.
Wave.hfield¶
Wave.hfield(r: ArrayLike) -> NDArray[np.complex128]
Cartesian magnetic samples (..., 3), or (..., 3, illuminations) for a batch.
Wave.dfield¶
Wave.dfield(r: ArrayLike) -> NDArray[np.complex128]
Cartesian displacement samples (..., 3), or (..., 3, illuminations).
Wave.bfield¶
Wave.bfield(r: ArrayLike) -> NDArray[np.complex128]
Cartesian flux-density samples (..., 3), or (..., 3, illuminations).
Wave.gfield¶
Wave.gfield(pol: int, r: ArrayLike) -> NDArray[np.complex128]
Riemann-Silberstein G samples (..., 3[, illuminations]), upstream scaling.
Wave.ffield¶
Wave.ffield(pol: int, r: ArrayLike) -> NDArray[np.complex128]
Riemann-Silberstein F samples (..., 3[, illuminations]) with chiral weights.
Wave.__init__¶
Wave(coefficients: ArrayLike, *, basis: Basis, k0: float, material: MaterialLike | None=None, modetype: str | None=None, poltype: str | None=None, medium: MaterialLike | None=None, kind: str | None=None, polarization: str | None=None)
Construct wave amplitudes with explicit basis, medium and radial/directional kind.
Kind is regular/singular for multipoles and up/down for plane ports. Coefficients have shape (modes,) or (modes, illuminations). Polarization is helicity/parity. Material, modetype and poltype are the treams names of medium, kind and polarization; give each quantity under one name.
Wave.coefficients¶
Wave.coefficients: NDArray[np.complex128]
Read-only amplitudes, shape (modes,) or (modes, illuminations).
Wave.in_basis¶
Wave.in_basis(basis: Basis, *, kind: str | None=None) -> Wave
Represent this field in another basis, retaining physical metadata.
Kind is regular/singular for multipoles, up/down for plane-wave ports. Omission preserves the current kind within a family; plane-to-multipole conversion produces regular waves. Truncated bases are approximations.
Wave.with_polarization¶
Wave.with_polarization(polarization: str) -> Wave
Represent the same physical wave in helicity or parity channels.
Every mode needs its partner of opposite polarization in the basis.
Wave.material¶
Wave.material: Material
treams name of medium.
Wave.poltype¶
Wave.poltype: str
treams name of polarization.
Wave.modetype¶
Wave.modetype: str
treams name of kind.
Wave.changepoltype¶
Wave.changepoltype(poltype: str | None=None) -> Wave
treams name of with_polarization; omitting poltype switches convention.
Wave.expand¶
Wave.expand(basis: Basis, *, modetype: str='regular') -> NDArray[np.complex128]
Coefficients only of in_basis(basis, kind=modetype).
Wave.basis¶
Wave.basis: Basis
Wave.array¶
Wave.array: NDArray[np.complex128]
Wave.medium¶
Wave.medium: Material
Homogeneous medium in which this wave is represented.
Wave.polarization¶
Wave.polarization: str
Polarization convention: helicity or parity.
Wave.kind¶
Wave.kind: str
Radial kind (regular or singular) of multipoles, or port direction (up or down).
WaveVector¶
Partial Cartesian wavevector; NaN marks an unspecified component.
Mirrors treams.WaveVector. Three values give (kx, ky, kz); one or two
values give the components along alignment ("z" or "xy" by
default), and the others are NaN. & combines compatible constraints;
| keeps only the common ones.
WaveVector.__init__¶
WaveVector(seq: ArrayLike | WaveVector=(), alignment: str | None=None)
WaveVector.isdisjoint¶
WaveVector.isdisjoint(other: ArrayLike | WaveVector) -> bool
Whether no component is specified in both wavevectors.
WaveVector.permute¶
WaveVector.permute(n: int=1) -> WaveVector
Permute the components cyclically, x -> y -> z, n times.
WaveVector.rotate¶
WaveVector.rotate(phi: float) -> WaveVector
Rotate around z without discarding partial wavevector constraints.
chirality_density¶
chirality_density(basis: PlaneWavePorts, k0: float, material: MaterialLike=1, poltype: str | None=None, z: ArrayLike=(0.0, 0.0)) -> tuple[NDArray[np.complex128], NDArray[np.complex128], NDArray[np.complex128]]
Up/down/coherent-cross forms of 2 Re(E* . i Z H), along the basis normal.
Equal endpoints evaluate at that plane. z gives coordinates along the normal. For amplitudes u,d the density is Re(u U u + d D d + d* X u). X can be complex for a shifted interval. Differs from treams; see Differences from treams: plane-wave chirality interval.
cylinder_tmatrix¶
cylinder_tmatrix(*, k0: float, kz: ArrayLike, mmax: int, radius: float, material: MaterialLike, medium: MaterialLike=1, polarization: str='helicity') -> CylindricalTMatrix
Homogeneous infinite z cylinder; kz is one or more real axial wavenumbers.
cylindrical_wave¶
cylindrical_wave(kz: float, m: int, pol: int, *, k0: float, basis: CylindricalBasis | None=None, material: MaterialLike | None=None, modetype: str | None=None, poltype: str | None=None, medium: MaterialLike | None=None, kind: str | None=None, polarization: str | None=None) -> Wave
One cylindrical mode in a global basis, with fixed real axial label kz.
get_num_threads¶
get_num_threads() -> int
Return the worker-thread budget of the next native parallel call.
interface¶
interface(*, basis: PlaneWavePorts, k0: float, negative_medium: MaterialLike, positive_medium: MaterialLike, polarization: str='helicity') -> SMatrix
Planar interface between the negative and the positive medium.
Args
basis: the plane-wave ports;basis.normal_axisis the normal.k0: positive vacuum angular wavenumber, in inverse length units.negative_medium: the medium on the negative side (below).positive_medium: the medium on the positive side (above).polarization: "helicity" (default) or "parity"; parity needs achiral media.
multilayer_cylinder_tmatrix¶
multilayer_cylinder_tmatrix(*, k0: float, kz: ArrayLike, mmax: int, radii: ArrayLike, materials: Sequence[MaterialLike], medium: MaterialLike=1, polarization: str='helicity') -> CylindricalTMatrix
Concentric infinite cylinders; materials run outward, excluding the medium.
multilayer_slab¶
multilayer_slab(*, basis: PlaneWavePorts, k0: float, thicknesses: ArrayLike, materials: Sequence[MaterialLike], negative_medium: MaterialLike=1, positive_medium: MaterialLike=1, polarization: str='helicity') -> SMatrix
Planar layers ordered from the negative to the positive side.
Args
basis: the plane-wave ports;basis.normal_axisis the normal.k0: positive vacuum angular wavenumber, in inverse length units.thicknesses: one nonnegative thickness per layer, in units inverse to k0.materials: one medium per layer, in the same order.negative_medium: exterior medium on the negative side, vacuum by default.positive_medium: exterior medium on the positive side, vacuum by default.polarization: "helicity" (default) or "parity".
multilayer_sphere_tmatrix¶
multilayer_sphere_tmatrix(*, k0: float, lmax: int, radii: ArrayLike, materials: Sequence[MaterialLike], medium: MaterialLike=1, polarization: str='helicity') -> TMatrix
Concentric layers ordered inside-out; one material per positive increasing radius.
plane_wave¶
plane_wave(kvec: ArrayLike | None=None, pol: ArrayLike | str | None=None, *, k0: float, material: MaterialLike | None=None, poltype: str | None=None, direction: ArrayLike | None=None, medium: MaterialLike | None=None, polarization: str | None=None) -> PlaneWave
Define a plane wave from direction, polarization state pol, k0 and medium.
Direction is normalized, independently of the vacuum angular wavenumber k0.
The state pol is "positive_helicity"/"negative_helicity", a
pol index 0 or 1, a pair of channel amplitudes, or three Cartesian
electric components. A named helicity selects the helicity convention.
polarization is the convention, "helicity" or "parity".
kvec, material and poltype are the treams names of direction, medium and
polarization; give each quantity under one name.
plane_wave_angle¶
plane_wave_angle(theta: float, phi: float, pol: ArrayLike | str, *, k0: float, material: MaterialLike | None=None, poltype: str | None=None, medium: MaterialLike | None=None, polarization: str | None=None) -> PlaneWave
Define an incident plane wave by polar and azimuthal angles in radians.
Takes the same pol, medium and polarization keywords as plane_wave.
poynting_avg_z¶
poynting_avg_z(basis: PlaneWavePorts, k0: float, material: MaterialLike=1, poltype: str | None=None) -> tuple[NDArray[np.complex128], NDArray[np.complex128]]
Upstream-compatible axial forms, with treams normalization and branches.
These retain treams' parity normalization and complex-medium conventions;
they are not physical Poynting-flux matrices for arbitrary media. Use
SMatrix.power for transmitted/reflected power or sample E and H for
the local physical flux 0.5 * real(E cross conj(H)).
propagation¶
propagation(*, distance: ArrayLike, basis: PlaneWavePorts, k0: float, medium: MaterialLike=1, polarization: str='helicity') -> SMatrix
Homogeneous propagation by a normal distance or Cartesian displacement.
Args
distance: distance along the basis normal, or a Cartesian displacement of shape (3,), in units inverse to k0.basis: the plane-wave ports.k0: positive vacuum angular wavenumber.medium: the homogeneous medium, vacuum by default.polarization: "helicity" (default) or "parity".
set_num_threads¶
set_num_threads(threads: int | None) -> None
Set the process-wide worker-thread budget; None restores the default.
threads must be a positive integer. A parallel region that has started
finishes on its pool; later regions use the new budget. A budget above the
available CPUs is honored with a ThreadingWarning, issued before the
budget changes, because oversubscription slows dense linear algebra. Forked
children inherit the budget and build their own pool of that size.
Examples
>>> import treams_rs as tr
>>> tr.set_num_threads(1)
>>> tr.get_num_threads()
1
>>> tr.set_num_threads(None)
slab¶
slab(*, basis: PlaneWavePorts, k0: float, thickness: float, material: MaterialLike, negative_medium: MaterialLike=1, positive_medium: MaterialLike=1, polarization: str='helicity') -> SMatrix
One homogeneous layer between explicitly named exterior media.
basis=PlaneWavePorts.default([0, 0]) supplies normal-incidence channels.
k0 is 2*pi/vacuum_wavelength; thickness uses the matching length unit.
material is the layer permittivity or Material(epsilon, mu, kappa).
Exterior media default to vacuum. Pass a physical plane wave to
network.power(incident) for named transmission, reflection and absorption
fractions; its direction selects the illuminated side. For derivatives use
this same function inside your autodiff framework's gradient calculation;
the thickness, frequency or material selects its adapter automatically.
A lossy chiral layer distinguishes the two helicities:
import numpy as np
import treams_rs as tr
k0 = 2*np.pi/0.8
ports = tr.PlaneWavePorts.default([0, 0])
network = tr.slab(basis=ports, k0=k0, thickness=0.17,
material=tr.Material(2.3+0.08j, 1, 0.2+0.01j))
incident = tr.plane_wave([0, 0, 1], "positive_helicity", k0=k0)
power = network.power(incident)
# Explicit amplitudes use the actual channel labels, not an assumed order.
positive = (ports.pol == 1).astype(complex)
np.testing.assert_allclose(power.transmission,
network.power(positive).transmission)
negative = tr.plane_wave([0, 0, 1], "negative_helicity", k0=k0)
assert abs(power.transmission - network.power(negative).transmission) > 0.01
solve_periodic¶
solve_periodic(unit_cell: TMatrix | CylindricalTMatrix | Cluster, *, lattice: ArrayLike, kpar: ArrayLike, eta: complex=0) -> PeriodicResponse
Solve cell interactions once at a fixed lattice and Bloch wavevector.
The unit cell contains isolated particles (a single T-matrix or an unsolved Cluster). Do not pass an already coupled cluster response. Lattice lengths, basis positions and inverse k0 use the same units. The lattice sums use the Ewald method, which splits each sum into a real-space and a reciprocal-space series; eta sets that split, and 0 picks it automatically.
A subwavelength square array, optionally combined with planar layers:
import treams_rs as tr
k0 = 2.0
cell = tr.Lattice.square(0.9)
particle = tr.sphere_tmatrix(k0=k0, lmax=2, radius=0.12, material=3.)
response = tr.solve_periodic(particle, lattice=cell, kpar=[0, 0])
ports = tr.PlaneWavePorts.default([0, 0]) # zeroth order, both helicities
array = response.to_smatrix(ports)
layer = tr.slab(k0=k0, basis=ports, thickness=0.2, material=2.)
gap = tr.propagation(k0=k0, basis=ports, distance=0.3)
network = tr.stack([layer, gap, array]) # negative to positive z
wave = tr.plane_wave([0, 0, 1], "positive_helicity", k0=k0)
power = network.power(wave, side="negative")
assert abs(power.transmission + power.reflection - 1) < 1e-10
Include every open diffraction order for shorter wavelengths or larger
periods; PlaneWavePorts.diffr_orders constructs those mode channels.
The propagation distance ends at the array's particle-center plane.
sphere_tmatrix¶
sphere_tmatrix(*, k0: float, lmax: int, radius: float, material: MaterialLike, medium: MaterialLike=1, polarization: str='helicity') -> TMatrix
Homogeneous sphere response, ready for illumination or cluster assembly.
k0=2*pi/vacuum_wavelength; radius and 1/k0 share a length unit.
material is a permittivity or Material(epsilon, mu, kappa); medium
is the exterior, vacuum by default. lmax is the fixed multipole cutoff.
Use response.cross_sections(plane_wave(...)) for named scattering,
extinction and absorption areas, response.average_cross_sections for
rotational/polarization averages, or response.scatter(wave).efield(xyz)
for scattered fields. Framework-valued parameters retain their gradients.
spherical_wave¶
spherical_wave(l: int, m: int, pol: int, *, k0: float, basis: SphericalBasis | None=None, material: MaterialLike | None=None, modetype: str | None=None, poltype: str | None=None, medium: MaterialLike | None=None, kind: str | None=None, polarization: str | None=None) -> Wave
One spherical mode in a global basis (positive helicity is pol=1).
stack¶
stack(layers: Sequence[SMatrix]) -> SMatrix
Cascade layers in order from negative to positive side of their normal.
support_catalog¶
support_catalog() -> dict[str, Any]
Return a JSON-serializable, version-matched public API and backend catalog.
api contains public definitions, root re-exports, class members (including treams-rs inheritance),
declared attributes/descriptors, and callable aliases. Inherited NumPy methods and incidental imports are
excluded. pullbacks lists the methods on an annotated returned context;
an empty list does not promise automatic differentiation through that API.
Static parameters and derivative ordering are stated in each source docstring
and signature. Use diff or a framework adapter to request derivatives.
backends describes execution support. Optional dependency versions only
establish installation, not compatible devices or a configured framework.
returned_python_types lists the private classes that public members
return, such as the solver of TMatrix.interaction, with their methods.
upstream maps the treams names that treams-rs spells differently:
names covers the treams top level and members the members of treams
objects, each as {"target": name or None, "note": text}.
No optional framework is imported, and this function also works from a wheel without a checkout or network. Reading source is diagnostic work, never part of the numerical hot path.
Examples
>>> import treams_rs as tr
>>> catalog = tr.support_catalog()
>>> catalog["schema_version"]
1
>>> catalog["backends"]["cpu"]["compiled"]
True
thread_info¶
thread_info() -> dict[str, Any]
Return the thread budget, where it came from, and the pool state.
Keys:
threads: the budget of the next parallel call.source:"set_num_threads", the environment variable that set the budget, or"available_parallelism".available: the CPUs this process may use.pool_threads: the workers of the current pool,Nonebefore the first parallel call of this process.forked: whether this process was forked after treams-rs was loaded; it then builds a pool of its own.diagnostics: ignored, oversubscribing or limiting settings.environment: the variables consulted, in precedence order.
Never starts the pool.
Examples
>>> import treams_rs as tr
>>> tr.thread_info()["threads"] >= 1
True
threads¶
threads(n: int | None) -> Iterator[None]
Set the process-wide worker-thread budget for the with block.
Restores the previous budget on exit, like
threadpoolctl.threadpool_limits. The budget is process-wide, not
thread-local: other Python threads that call treams-rs inside the block use
it too. Alternating between two budgets reuses their pools.
Blocks in different Python threads must not overlap: each restores the
budget it saw on entry, in exit order. For a thread pool, call
set_num_threads(k) once before starting the workers.
Examples
>>> import treams_rs as tr
>>> with tr.threads(1):
... tr.get_num_threads()
1