Skip to content

Design

treams-rs follows treams' numerical conventions and adds analytic gradients. Four goals shape the code:

  • treams numerics. Mode order, normalization and the helicity convention follow treams at a pinned commit (see conventions). Where treams-rs differs, the differences page says how and why.
  • Native gradients. Every differentiable operation has a hand-derived first-order pullback in Rust: a function that turns the gradient with respect to an output into gradients with respect to the inputs (see analytic pullbacks).
  • Speed. Numerical loops run in compiled Rust. Independent items run in parallel when this reduces runtime (see performance).
  • A Python-free core. The Rust crate treams-core depends on faer, nalgebra, Rayon and a few special-function crates, and on no Python package. cargo test checks it without an interpreter.

Layers

Layer Code Role
1. Rust core crates/treams-core Numerical kernels and their analytic pullbacks
2. Bindings crates/treams-py, imported as treams_rs._native Array conversion, input checks, the global interpreter lock (GIL), the floating-point guard and pullback contexts
3. Python package treams_rs Physics objects (TMatrix, Cluster, SMatrix, waves), the treams-style numerical namespaces (special, sw, cw, pw, lattice, coeffs, misc, ebcm, io) and the records of treams_rs.diff
4. Framework adapters treams_rs.advect, treams_rs.jax, treams_rs.torch, treams_rs.autograd Physics objects that hold framework arrays, and native records as framework operations

The Python API selects optional adapters from its inputs. The core never sees a Python object. The adapters reach native code only through the records of treams_rs.diff. Inside the core, modules form six levels: numerical support (linalg, fpenv, numerics), special functions, lattice sums, wave families, scattering (coeffs, tmatrix, ebcm, cluster) and planar S-matrices (smatrix). A module uses only its own and lower levels.

Crosswalk

The table pairs Rust modules with their Python and treams counterparts. A dash marks a module without a counterpart.

Rust module treams_rs namespace treams Contents
special treams_rs.special treams.special Bessel, Legendre and Wigner functions, coordinate transforms, incomplete gamma and Kambe integrals
lattice treams_rs.lattice, treams_rs.misc.firstbrillouin* treams.lattice, treams.misc.firstbrillouin* Lattice sums and lattice geometry
sw treams_rs.sw, treams_rs.special.tl_vsw_* treams.sw, treams.special.tl_vsw_* Spherical modes, translation coefficients, expansion matrices and the conversion of chains to cylindrical waves
cw treams_rs.cw, treams_rs.special.tl_vcw treams.cw, treams.special.tl_vcw Cylindrical modes, translation coefficients, expansion matrices and the conversion to spherical waves
pw treams_rs.pw, treams_rs.misc.wave_vec_z treams.pw, treams.misc.wave_vec_z Plane-wave polarizations, fields and multipole expansions
basis treams_rs.SphericalBasis, treams_rs.CylindricalBasis treams.SphericalWaveBasis, treams.CylindricalWaveBasis Multipole bases and the expansion gradients that both families share
rotation treams_rs.sw.rotate, treams_rs.cw.rotate, treams_rs.operators.Rotate treams.sw.rotate, treams.cw.rotate, treams.Rotate Rotation coefficients and rotation matrices of multipole bases
channels treams_rs.sw.periodic_to_pw, treams_rs.cw.periodic_to_pw treams.sw.periodic_to_pw, treams.cw.periodic_to_pw Plane-wave channels of periodic arrays
vectorwaves treams_rs.special.vsh_*, vsw_*, vcw_*, vpw_*, sph_harm treams.special.vsh_*, vsw_*, vcw_*, vpw_*, sph_harm Vector spherical harmonics and vector spherical, cylindrical and plane waves
fields treams_rs.operators.efield treams.efield Electric fields of multipole expansions at sample points
coeffs treams_rs.coeffs, treams_rs.Material, treams_rs.misc.refractive_index treams.coeffs, treams.Material, treams.misc.refractive_index Mie coefficients of multilayer spheres and cylinders, and materials
tmatrix treams_rs.TMatrix, treams_rs.CylindricalTMatrix treams.TMatrix, treams.TMatrixC T-matrices of single spheres and cylinders, and the cd, db and chi metrics
ebcm treams_rs.ebcm treams.ebcm Q-matrices of the extended boundary condition method
cluster treams_rs.Cluster, treams_rs.iterative treams.TMatrix.cluster, treams.TMatrix.interaction Multiple scattering in particle clusters, dense and matrix-free
smatrix treams_rs.SMatrix, treams_rs.coeffs.fresnel treams.SMatrices, treams.coeffs.fresnel Planar S-matrices: interfaces, layer stacks, composition, illumination, transmittance and bands
linalg treams_rs.diff.solve, svdvals, eig - Dense LU, SVD and eigensystems with pullbacks, and restarted GMRES
numerics - - Forward-mode jets, broadcasting and parallel thresholds
fpenv - - A guard that keeps subnormal numbers when the caller flushes them to zero
threads treams_rs.set_num_threads, threads, thread_info - The thread budget and the fork-safe pool that runs every parallel region

Who owns what

  • Rust core: all numerical work and every derivative. A Rust function checks the physical validity of its inputs and returns a typed Error.
  • Bindings: conversion between NumPy arrays and Rust types, releasing the GIL during numerical work, the floating-point guard of every entry point (see floating-point environment) and the context objects that hold reusable derivative data. A Rust error becomes a ValueError, except Error::OutOfMemory, which becomes a MemoryError. Some allocation paths still abort on failure (memory limits).
  • Python package: bases, k0, media, polarization conventions, lattices, Bloch vectors, named results and the numerical calls behind physics methods.
  • Framework adapters: composition only. They wrap native records as Advect, JAX, PyTorch or HIPS Autograd operations and add no numerical code (see framework adapters).

The bindings keep the GIL for scalar calls of microsecond-scale functions, such as one Bessel value: releasing and taking it back costs about 0.09 µs, 5-9% of such a call.

What treams-rs leaves out

  • Array annotations. treams attaches basis, k0 and material to arrays and carries them through NumPy arithmetic (.ann, .relax). treams-rs objects keep them as attributes, and plain arithmetic returns plain NumPy values (see Python API design).
  • Global configuration. treams reads treams.config.POLTYPE. treams-rs takes the polarization convention as an argument, helicity by default.
  • Fallback to treams. treams-rs never imports treams. An unsupported case raises an error. treams serves only as a test reference.

Dense and matrix-free cluster solves

A dense solve with requested illuminations factors I - T C once and solves only the requested right-hand sides. Here T holds the particle T-matrices and C the translations between particles. The factor never changes, so any number of pullback records share it (cluster::InteractionFactor).

The matrix-free solver (cluster::IterativeSphereCluster, Python iterative.SphereCluster) applies the pair translations on demand and solves the forward and the adjoint system with restarted GMRES. It sums the gradients of radii, positions and materials pair by pair, so it never forms the coupling matrix or its gradient. Both paths share the Mie coefficients, the translation plans and the gradient convention. Large clusters explains when to use which.