Skip to main content

RDF-Rust

Partial and total radial distribution functions (PRDF / RDF) for crystal structures, with native support for partially occupied sites.

⚙️ Rust backend, 🐍 Python frontend. The neighbour search, the histogramming and the CIF parsing run in compiled Rust, in parallel across cores. You call it from Python and get NumPy arrays back.

  • 🚀 ~100× faster than Matminer on a single core, and ~340× faster on four cores: 13,720 atoms in 144 ms (42 ms on four cores) instead of 14.3 s.
  • ⚡ ~2× faster than Vesin, core for core (1.5–2.2×).
  • 💾 Under 1 MB of memory at any size. Matminer needs 3.2 GB and Vesin 454 MB for the same 13,720 atoms.
  • 🧩 Partial occupancies handled directly: no supercell, no random seed.

🌐 Online app

Use it in the browser, nothing to install: prdf-xrdlicious.streamlit.app

prdf_app.py in this repository is that app: the XRDlicious (P)RDF calculator, with RDF-Rust, Vesin and Matminer as selectable methods. To run it locally:

pip install -r requirements.txt
streamlit run prdf_app.py

Install

pip install rdf-rust

Example

import rdfrust

s = rdfrust.read("BaSrTiO3.cif")                 # reports disorder on stderr
r, partials, total = s.prdf(cutoff=10.0, bin_size=0.1, n_threads=0)

partials[("Ba", "O")]     # numpy array, g_BaO(r)
total                     # number-weighted total RDF
r                         # left edge of each bin

cutoff is the maximum pair length r_max in Å, bin_size the histogram width, and n_threads=0 uses every core. A complete runnable script is in examples/run_prdf.py.

Every element pair is computed automatically: there is no element list to pass. A five-element alloy gives all 25 partials, keyed as (A, B) tuples.

📈 Saving plots

Add save_plots and the curves are also written to a folder as clean figures, with the numbers in a CSV. It is off by default.

s.prdf(cutoff=10.0, bin_size=0.1, save_plots="rdf_plots", title="BaSrTiO3")

This writes total_rdf.png, partial_rdfs.png (all pairs together), one partial_A-B.png per pair, and rdf.csv. Needs matplotlib (pip install "rdf-rust[plot]").

🎞️ MD trajectories

Multi-frame XYZ files, as written by MD codes, are read directly. Choose how often a frame is analysed with every:

res = rdfrust.trajectory_prdf(
    "md_run.xyz",
    cutoff=10.0, bin_size=0.05,
    every=5,                  # every 5th frame
    save_plots="md_rdf",      # averages, animations and CSVs
)
res.total, res.partials       # averaged over the frames used
res.total_per_frame           # every frame, shape (n_frames, n_bins)

With save_plots it writes the trajectory-averaged total and partial RDFs (with the frame-to-frame spread shaded), an animation of every analysed frame (total_rdf_animation.gif, partial_rdfs_animation.gif), and the data as CSV.

  • Frames with their own Lattice="..." keep their own box, so NPT runs work.
  • Plain XYZ has no cell: pass it with cell=[a, b, c] or a 3×3 matrix.
  • Unwrapped coordinates (atoms outside the box) are handled.
  • start and stop limit the frame range; skipped frames are not parsed, so every=10 on a long run stays fast.

A runnable demo that writes and analyses a small trajectory: examples/md_trajectory.py.

🚀 Speed and 💾 memory

RDF-Rust on 1 thread (serial, like Matminer and Vesin) and on 4 threads:

1 thread 4 threads
Speed-up, 1 thread Speed-up, 4 threads
Time, 1 thread Time, 4 threads

Peak memory

atoms Matminer Vesin ⚡ RDF-Rust, 1 thread 🚀 RDF-Rust, 4 threads 💾 RDF-Rust memory
320 313 ms / 77 MB 15 ms / 10 MB 6.3 ms 1.8 ms < 1 MB
2,560 2,840 ms / 592 MB 47 ms / 93 MB 25 ms 6.6 ms < 1 MB
13,720 14,322 ms / 3,178 MB 276 ms / 454 MB 144 ms 42 ms < 1 MB

Memory stays flat because pairs go straight from the neighbour search into the histogram and are never stored. Matminer and Vesin keep every pair distance, so their memory grows with the structure.

Results match Matminer to 3.6 × 10⁻¹⁵ (double-precision noise). Full numbers, structure types, thread scaling and the data behind every figure: BENCHMARKS.md.

🧩 Partial occupancies

How it works: each site i carries an occupancy $c_i^A$ for every species A on it. A pair of sites (i, j) within the cutoff adds $c_i^A c_j^B$ to the A–B histogram, instead of 1. Normalising by the number of A atoms, $N_A = \sum_i c_i^A$, gives

$$g_{AB}(r) = \frac{1}{N_A}\sum_{i \neq j} c_i^A c_j^B \frac{\delta(r - r_{ij})}{4\pi r^2 \Delta r}$$

This is the exact average over every random arrangement of the disordered sites, so no supercell, random seed or rounding of occupancies is needed. When all occupancies are 1 it is the ordinary RDF.

If you need an explicit ordered structure instead, for example to export it: ordered, info = s.expand_occupancies(max_sites=4096, seed=42).

Formats

format partial occupancies
CIF yes
VASP POSCAR / CONTCAR no
extended XYZ, single frame or trajectory no
plain XYZ trajectory (with cell=) no
anything else read through pymatgen or ASE, if installed

📖 How to cite

RDF-Rust is part of the XRDlicious project. If you use it, please cite:

  • XRDlicious: Lebeda, M. et al. XRDlicious: an interactive web-based platform for online calculation of diffraction patterns and radial distribution functions from crystal structures. Journal of Applied Crystallography 58(5) (2025). journals.iucr.org
  • XRD-Rust: Lebeda, M. et al. Rust-accelerated powder X-ray diffraction simulation for high-throughput and machine-learning-driven materials science. Journal of Applied Crystallography 59(4), 1344–1350 (2026). journals.iucr.org
  • RDF-Rust: this repository, github.com/bracerino/rdf-rust.

Tests

cargo test --lib     # Rust unit tests
pytest tests/ -q     # CIF, formats, neighbours, RDF, disorder physics

License

MIT

Metadata

Release files for rdf-rust 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rdf-rust 0.2.0
File Size Uploaded
rdf_rust-0.2.0.tar.gz 78.7 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for rdf-rust 0.2.0
File
rdf_rust-0.2.0-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details
rdf_rust-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.8 abi3 Linux glibc 2.17+ x86-64 Details
rdf_rust-0.2.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.8 abi3 Linux glibc 2.17+ ARM64 Details
rdf_rust-0.2.0-cp38-abi3-macosx_11_0_arm64.whl CPython 3.8 abi3 macOS 11.0+ ARM64 Details
rdf_rust-0.2.0-cp38-abi3-macosx_10_12_x86_64.whl CPython 3.8 abi3 macOS 10.12+ x86-64 Details

Total release size: 2.1 MB

Release files / rdf_rust-0.2.0.tar.gz

Download URL rdf_rust-0.2.0.tar.gz
Size 78.7 kB
Tags Source
SHA-256 checksum
How to use checksums
383415a7126baf49ed843b5bb26ecd235949e049a2bee225e364765fe7173652
BLAKE2b-256 checksum
How to use checksums
e2aab26b059bde012eed149ac553c3fcdcea6466fd1324d554ca8eb1d68eb103
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / rdf_rust-0.2.0-cp38-abi3-win_amd64.whl

Download URL rdf_rust-0.2.0-cp38-abi3-win_amd64.whl
Size 339.1 kB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
a67fb7553c702e49ec3cccb209c60938307e44742afd33ac26ee9cebcd82bac7
BLAKE2b-256 checksum
How to use checksums
d45d725ccbfb4604d62a3e06cde7c65ed83fd50e651871f0cd26f64bbbde99e1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / rdf_rust-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rdf_rust-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 457.5 kB
Tags CPython 3.8 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
aaca41c86734b19830e6ef54cfa7ef80a65d55e0b60115281e2cc3fbf5fe6244
BLAKE2b-256 checksum
How to use checksums
bbd6e772b30715e292f5f69351be6bda8310bf027c917787061a4759faac7a4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / rdf_rust-0.2.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL rdf_rust-0.2.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 438.4 kB
Tags CPython 3.8 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
dcc23f22a5c5ac9d81f16390997bb3da7fb41e9f14104e7971e91af19fe0fa4a
BLAKE2b-256 checksum
How to use checksums
50bb215069a52f1c4fb25811ca7e4c78d0e89572456b356dd9993d5aac82a743
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / rdf_rust-0.2.0-cp38-abi3-macosx_11_0_arm64.whl

Download URL rdf_rust-0.2.0-cp38-abi3-macosx_11_0_arm64.whl
Size 403.2 kB
Tags CPython 3.8 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e6adf82b459c35565a87b334b7697efd3b264edfbeafe9b53924876d1c07e4f9
BLAKE2b-256 checksum
How to use checksums
d7719970497915b8dcc8418684e456559112b5fb8b5fbac582b7a41006f438ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / rdf_rust-0.2.0-cp38-abi3-macosx_10_12_x86_64.whl

Download URL rdf_rust-0.2.0-cp38-abi3-macosx_10_12_x86_64.whl
Size 427.5 kB
Tags CPython 3.8 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
a08973400609c688502c5f8c6e7cd5eb2f218cecbfeb1de6dea07caae73fabc4
BLAKE2b-256 checksum
How to use checksums
c12067c0e8368b9edfc9f3f2f9e30d274260e24a84b3bef526ad70d49823df45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.3.0

6 release files

This release

0.2.0 This release

6 release files

0.1.0

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page