Skip to Content
ArchitectureOverview

Architecture

The whole solver on one board: every layer, every kernel, every byte that moves.


Loading the architecture board…

How to read the board

Every element is one of five things, and the color tells you which: computation (orange) burns FLOPs, data movement (blue) burns memory bandwidth, memory (magenta) is long-lived state, interfaces (green) are the boundaries where config enters and results leave, and control (gray, dashed) orchestrates without touching bulk data. Click any element for its details, real file path, and cost; press Run to watch a measured solve propagate through the entire system.

The distinction between orange and blue is the whole point. On modern hardware this solver is memory-bandwidth-bound, not compute-bound: the design decisions worth studying are the blue ones.

Three punchlines

  1. Every GEMM crosses a precision boundary. Bulk storage can be f32, but every Gram matrix, projection, and eigensolve accumulates in f64. The upcast materializes an N×r copy before each GEMM, and the results are cast back after. Switch the board to the Precision view to see exactly where the casts live.
  2. Parallelism at job granularity, and deliberately OFF inside the GEMM. Sweep jobs run data-parallel under rayon, while inside one solve the dense algebra runs sequentially (Par::Seq): at 64×64 grids, thread synchronization made parallel GEMM 5 to 10 times slower. Knowing where parallelism does NOT pay is the harder half of the discipline.
  3. The operator is not a matrix. Applying the TE Maxwell operator IS six FFTs plus a real-space tensor contraction, working in preallocated scratch that stays hot in L2. No N²-sized object ever exists.

What mixed precision buys on real hardware

The first punchline deserves to be seen, not read. Below is the path every field element takes on a real desktop CPU: out of DRAM over a dual-channel bus, through three cache levels, into the FPU. Every lane moves its dots at the (damped) relative speed of the real thing, so you can watch the DRAM bus crawl while the L1 lane flies. Fields stay amber f32 all the way through storage and only widen to f64 at the white cast diamond; flip the storage toggle to f64 and every lane delivers half the elements:

8 B per element: twice the elements on every lane
Lane speeds are anchored to the L1 lane and square-root damped so the slow lanes stay watchable: at true scale the DRAM bus would run about ×94 slower than L1, not ×9.7. Latencies are approximate load-to-use figures for an i9-13900K (L1d 0.9 ns, L2 2.7 ns, L3 10 ns, dual-channel DDR5 ≈85 ns).

In the real solver the gap is even wider than this schematic suggests: the FLOP phases (FFTs, axpys, dots) are themselves memory-bound, so halving the storage width pushes the end-to-end speedup toward a clean 2×. Precision & Memory has the contract and the numbers.

Deep dives

Each layer of the board has its own page:

  • Geometry & Dielectric: typed lattices, analytic subpixel smoothing, and the O(N) ε arrays everything else consumes.
  • Matrix-Free Operators: the TM 2-FFT and TE 6-FFT apply pipelines, scratch reuse, preconditioners.
  • Eigensolver (LOBPCG): the iteration ring, cached blocks, lazy residual norms, SVQB, and the A·Q reuse trick.
  • Precision & Memory: the f32/f64 contract, what the casts cost, and why this is a bandwidth story.
  • Parallelism & Drivers: jobs-not-kernels, adaptive threading, the sequential k-loop, band tracking.
  • Interfaces: CLI, streaming Python (GIL released), and the WebAssembly build this site runs.

Codebase map

LayerCrate / moduleSizeSource
Storage & precisioncore::field, core::backendtraits + Field2D<R>field.rs 
FFT backendbackend-cpu1.1k LOClib.rs 
Geometrycore::{lattice, crystal, brillouin}typed lattices, k-pathslattice.rs 
Physicscore::{dielectric, operators}ε build + matrix-free Θmaxwell.rs 
Solvercore::eigensolverLOBPCG, SVQB, deflationeigensolver.rs 
Driverscore::drivers, core::band_trackingk-loop, warm startsbandstructure.rs 
Orchestrationbulk-driver (+-core)8.3k LOCdriver.rs 
Pythonpython (PyO3)3.4k LOCstreaming.rs 
Browserbackend-wasm1.2k LOCstreaming.rs 

The whole workspace is about 42k lines of Rust across 8 crates.

Last updated on