Skip to content

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; material is the particle or layer material. Planar networks have a negative_medium (below) and a positive_medium (above).
  • polarization: the convention of the channels, "helicity" (default) or "parity" (treams poltype). pol is 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; treams modetype), 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 as medium.
  • cylinder_tmatrix: infinite z cylinder; specify kz and mmax and use cross_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. Specify negative_medium and positive_medium for exterior media. PlaneWavePorts.default([0, 0]) gives normal-incidence ports. Pass a physical plane_wave to network.power(incident) to select direction and helicity by name; the incident side follows its propagation. The result has named transmission, reflection and absorption. Reverse incidence uses a -z wave without reversing layer order. Raw amplitudes follow ports.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. .array holds 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 of medium.
  • poltype: treams name of polarization.

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 of medium.
  • poltype: treams name of polarization.

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 of polarization.

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_axis is 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 in cascade.

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. .array holds 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 of medium.
  • poltype: treams name of polarization.

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_axis is 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_axis is 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, None before 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