Rust backend#
The computationally heavy parts of phono3py are implemented twice: as a C extension module and as a Rust extension module. The Rust path lives in the separate phonors package (built with maturin and PyO3) and is the default backend in phono3py v4. The C extension is still built and kept as a legacy backend that users can opt back into per call.
Installation#
phonors is a required runtime dependency of phono3py and is installed
automatically by pip install phono3py and by the
conda-forge phono3py package.
Pre-built wheels and conda packages are published for Linux, macOS, and
Windows on the supported Python versions, so no Rust toolchain is needed
for typical installations.
Building phonors from source (optional)#
To work against an unreleased phonors revision, clone the repository
alongside phono3py and build the extension in editable mode with
maturin develop:
% git clone https://github.com/phonopy/phonors.git
% cd phonors
% maturin develop --release
Requirements for a source build:
Optional: native CPU tuning#
By default, maturin develop --release builds with the Rust baseline
target (x86-64 v1 on x86_64, Armv8.0 on aarch64), so the resulting
module runs on any CPU of that architecture. For a local build that
will only run on the current machine, enabling the host CPU’s full
instruction set can recover a few percent of wall-clock:
% RUSTFLAGS='-C target-cpu=native' maturin develop --release
Usage#
The Rust backend is the default; no flag or keyword is required. To
opt back into the legacy C extension, pass --legacy-backend on the
command line or lang="C" on the Python API. See
Migrating from phono3py v3 to v4 for the full v3 -> v4 migration notes.
Command line#
% phono3py --br --mesh 11 11 11 # default: Rust
% phono3py --legacy-backend --br --mesh 11 11 11 # opt back into C
When the Rust backend is active, the run header prints
Rust backend (phonors) using rayon (N threads).
where N follows rayon’s defaults.
Python API#
The Phono3py constructor and the phono3py.load loader both accept
a lang keyword:
import phono3py
ph3 = phono3py.load("phono3py.yaml") # default: Rust
ph3 = phono3py.load("phono3py.yaml", lang="C") # opt back into C
The current value is exposed as the read-only Phono3py.lang
property. Valid values are "C" and "Rust" (default "Rust").
lang is threaded internally to every lang-aware consumer, including
BZGrid / GridMatrix, Interaction, the phonon solver
(dynamical-matrix construction; the eigh diagonalization stays in
Python/SciPy), ImagSelfEnergy, RealSelfEnergy, the RTA / LBTE
conductivity calculators, Isotope, and JointDos. No per-call
plumbing from the user side is required.
Thread pool#
The Rust kernels parallelize with rayon,
which uses its own thread pool. The thread count is controlled by
RAYON_NUM_THREADS (not OMP_NUM_THREADS, which only affects the C
path):
% RAYON_NUM_THREADS=8 phono3py ...
NumPy/SciPy BLAS multithreading used by phonon diagonalization is
independent and is controlled by the BLAS library’s own variables
(e.g. OPENBLAS_NUM_THREADS, MKL_NUM_THREADS).
Dispatch tracing#
To verify which backend a given code path is actually running on, set
PHONO3PY_TRACE_LANG=1 before launching:
% PHONO3PY_TRACE_LANG=1 phono3py ...
Each lang-aware call site emits one line to stderr, for example:
[phono3py.lang] dispatch name=Interaction.__init__ lang=Rust
The trace covers the following call sites:
Construction events, fired once per instance:
BZGrid.__init__,GridMatrix.__init__,Interaction.__init__,ImagSelfEnergy.__init__,RealSelfEnergy.__init__,Isotope.__init__,JointDos.__init__, andconductivity_calculator[rta|lbte].run_phonon_solver_rust, fired on every invocation of the Rust phonon solver (the C and Python phonon solvers are not traced).
The trace is silent by default. It is attached to a dedicated logger
(phono3py.lang) and is independent of the --loglevel /
log_level setting, so enabling it does not affect the rest of the
run log.
Batched grid-point path (opt-in)#
The RTA low-memory scattering path can optionally process several grid points per Rust call. This is disabled by default. It is useful on many-core machines where individual per-grid-point calls do not fully saturate the thread pool.
The batch size can be set either through
conductivity_calculator(..., rust_gp_batch_size=<int>) or through
the PHONO3PY_RUST_GP_BATCH_SIZE environment variable. Resolution
order:
The
rust_gp_batch_sizeargument if it is notNone.Otherwise the
PHONO3PY_RUST_GP_BATCH_SIZEenv var (default0).A value
<= 0falls back to the per-grid-point loop.
Example:
% PHONO3PY_RUST_GP_BATCH_SIZE=8 phono3py ...
The batched path applies only to the low-memory RTA solver and is
skipped automatically when read_gamma is set.
Building phono3py without the C extension#
For Rust-only deployments (or to validate that every dispatch site has a Rust path), phono3py can be installed with the C extension skipped:
% PHONO3PY_NO_C_EXT=1 pip install -e . -vvv
When the env var is set, CMakeLists.txt returns early and
phono3py._phono3py / phono3py._phononcalc are not built. At runtime,
Phono3py() and phono3py.load() detect the missing C extension, emit
a one-time [phono3py] C extension ... is not available; falling back to lang='Rust' ... message, and silently flip lang="C" requests to
lang="Rust". Since phonors is a required dependency, it is always
present; an informative ImportError is raised only if it has been
manually uninstalled.
To restore the C extension, simply rebuild without the env var:
% pip install -e . -vvv
Note
This option is intended for testing the Rust path and for packagers who want a Rust-only wheel. For day-to-day use the regular install (with the C extension) remains the recommended path.
Scope#
Rust kernels are wired through the lang dispatch for the following groups:
Grid construction (
BZGrid,GridMatrix: SNF, grid addresses and maps, reciprocal / transform rotations).Phonon-phonon interaction (
Interaction).Imaginary / real self energy (
ImagSelfEnergy,RealSelfEnergy), including the full-gamma variants reached throughis_full_pp,is_gamma_detail,read_pp,store_pp,use_ave_pp.Lattice thermal conductivity: standard RTA (low-memory path) and LBTE (both irreducible and reducible) run end-to-end on Rust.
Isotope scattering and joint DOS.
Known limitations#
Force constants. A Rust implementation of the fc3 kernel exists in
phonors, butPhono3py.produce_fc3still runs on the C / Python path because it goes through phonopy’sFCSolver, whose signature does not yet accept alanghint. Thelangparameter therefore does not yet reach this step.Dynamical-matrix diagonalization. LAPACK calls (phonon eigenproblem, collision-matrix diagonalization, pseudo-inverse in the direct solution) stay in Python/SciPy by design. They are not part of the Rust port.
If any of these code paths is reached with lang="Rust", phono3py
transparently uses the C (or Python) implementation for that step.
The Rust backend is exercised by the regular phono3py CI matrix on Linux, macOS, and Windows.