xraydb 0.2.0

X-ray reference data for the elements: absorption edges, emission lines, and Elam/Chantler cross-sections
Documentation

xraydb-rs

X-ray reference data for the elements in Rust. A pure-Rust port of the XrayDB project.

The complete database — elements, absorption edges, emission lines, Elam and Chantler cross-sections, Waasmaier–Kirfel form factors — is compiled into your binary as a 3 MB zstd blob and decoded lazily on first use. No runtime data files, no network access.

Install

[dependencies]
xraydb = "0.2"

Usage

use xraydb::{CrossSectionKind, XrayDb};

let db = XrayDb::try_new()?;

// Element facts — symbol, name, or Z all work as identifiers
assert_eq!(db.atomic_number("Fe")?, 26);
assert_eq!(db.symbol("iron")?, "Fe");
assert_eq!(db.atomic_name("26")?, "iron");

// Absorption edges
assert_eq!(db.xray_edge("Fe", "K")?.energy, 7112.0);

// Mass attenuation from the Elam tables (cm²/g)
let mu = db.mu_elam_at("Fe", 10_000.0, CrossSectionKind::Total)?;

// Compound attenuation (1/cm), by formula and density
let mu_water = db.material_mu_at("H2O", 1.0, 10_000.0, CrossSectionKind::Total)?;
assert!((mu_water - 5.33).abs() < 0.05);

// Anomalous scattering factors from the Chantler tables
let f1 = db.f1_chantler_at("Fe", 10_000.0)?;
let f2 = db.f2_chantler_at("Fe", 10_000.0)?;

// Refractive index decrements: n = 1 - delta - i*beta
let n = db.xray_delta_beta("SiO2", 2.2, 10_000.0)?;
println!("delta={:.3e} beta={:.3e} atlen={:.3} cm", n.delta, n.beta, n.attenuation_length_cm);
# Ok::<(), xraydb::XrayDbError>(())

Scalar and batch forms

Every array-valued calculation has an _at scalar counterpart that allocates nothing. Use the batch form when you have many energies — it resolves the element and its table rows once for the whole slice.

# use xraydb::{CrossSectionKind, XrayDb};
# let db = XrayDb::try_new()?;
let energies: Vec<f64> = (0..500).map(|i| 5_000.0 + 20.0 * i as f64).collect();
let mu = db.mu_elam("Fe", &energies, CrossSectionKind::Total)?;
assert_eq!(mu.len(), energies.len());
# Ok::<(), xraydb::XrayDbError>(())

Chemical formulas

One parser serves the whole crate, so anything material_mu accepts, xray_delta_beta accepts too.

Notation Example
plain H2O
nested groups Mn(SO4)2(H2O)7
fractional stoichiometry Fe0.7Mg0.3O, Fe.7Mg.3O
scientific notation Zn1.e-5Fe3O4
fractional group multipliers (N2)0.7808(O2)0.2095
weight-percent mixtures Ru1wt%SiO2
deuterium alias D2O (counted as hydrogen)

Named materials

# use xraydb::{CrossSectionKind, XrayDb};
# let db = XrayDb::try_new()?;
let kapton = db.find_material("kapton").expect("in the materials table");
assert_eq!(kapton.formula, "C22H10N2O5");
assert_eq!(kapton.density, 1.42);

// Density is taken from the table unless you override it
let mu = db.material_mu_named("kapton", &[10_000.0], CrossSectionKind::Total, None)?;
# Ok::<(), xraydb::XrayDbError>(())

Optics (feature optics)

Crystal Darwin widths and mirror/multilayer reflectivity. Parameter structs with Default keep call sites readable.

[dependencies]
xraydb = { version = "0.2", features = ["optics"] }
# #[cfg(feature = "optics")] {
use xraydb::{DarwinParams, MirrorParams, XrayDb};

let db = XrayDb::try_new()?;

let dw = db.darwin_width(DarwinParams {
    energy: 10_000.0,
    crystal: "Si",
    hkl: (1, 1, 1),
    ..Default::default()
})?.expect("Si(111) diffracts at 10 keV");
println!("Darwin width: {:.2} eV FWHM", dw.energy_fwhm);

let angles: Vec<f64> = (1..100).map(|i| i as f64 * 0.1e-3).collect();
let refl = db.mirror_reflectivity(MirrorParams {
    formula: "Pt",
    theta: &angles,
    energy: 10_000.0,
    density: 21.45,
    roughness: 5.0,
    ..Default::default()
})?;
# }
# Ok::<(), xraydb::XrayDbError>(())

Energy clamping

Following upstream XrayDB, energies outside a table's range are clamped to its endpoints rather than rejected. Check first with XrayDb::elam_energy_range() and db.chantler_energy_range(element).

Command-line tool

cargo install --path xraydb-cli    # installs `xraydb`

xraydb element Fe
xraydb edges Fe
xraydb lines Cu --level K
xraydb mu H2O --density 1.0 --energy 5000:15000/11
xraydb delta-beta SiO2 --density 2.2 --energy 10000
xraydb guess-edge --energy 7100
xraydb materials

Energies accept a single value, a comma list, start:stop:step, or start:stop/count (log-spaced). Add --json or --csv for machine-readable output.

For scripts and agents

The CLI is designed to be driven programmatically as well as typed:

xraydb commands --json      # every subcommand, argument, enum value, and default
  • --json works on every subcommand, including commands itself, so an agent can discover the whole interface in one call instead of parsing --help prose.
  • With --json, failures are also JSON, written to stderr as {"error": "...", "context": [...]}. Without it, errors stay plain text.
  • On failure stdout is left empty, so a consumer parsing stdout never sees partial output.
  • Exit code is 0 on success and 1 on error. A broken pipe (| head) exits 0.
  • Colour is only emitted to a TTY, and NO_COLOR disables it.

Browser demo

A zero-dependency demo page with a periodic-table selector and live cross-section plots:

wasm-pack build --target web --release xraydb-wasm --out-dir ../web/pkg
python3 -m http.server -d web 8080

Then open http://localhost:8080. See web/README.md.

Workspace Structure

Crate Description
xraydb-data Shared serde data model (#![no_std])
xraydb-generate Binary that parses raw data sources into compressed binary format
xraydb-lib Main library crate (xraydb) with embedded compressed data
xraydb-wasm WASM bindings via wasm-bindgen
xraydb-cli xraydb command-line tool
web/ Browser demo built on xraydb-wasm

Performance

Typical timings on an M-series Mac, release build (see cargo bench):

Operation Time
f2_chantler_at ~120 ns
mu_elam_at ~113 ns
xray_edge ~78 ns
xray_delta_beta ~1.1 µs
mu_elam batch of 200 ~7 µs

Development

cargo test --all-features
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --all --check

Install the pre-commit hook (runs fmt, clippy, and tests):

git config core.hooksPath .githooks

The library contains no unsafe (#![forbid(unsafe_code)]) and no unwrap/expect outside test code (lint-enforced).

Regenerating the data

git clone https://github.com/xraypy/XrayDB.git XrayDB
cargo run -p xraydb-generate --release

Attribution

The X-ray data used in this project comes from the XrayDB project by Matt Newville et al., which is placed in the public domain (CC0 1.0). This Rust port is an independent reimplementation.

Data sources include:

  • Elam/Ravel/Sieber tables — photoabsorption, scattering, and emission line data
  • Chantler tables — anomalous scattering factors (f', f'') and mass attenuation coefficients
  • Waasmaier-Kirfel coefficients — elastic (Thomson) scattering factors f0

License

Dual-licensed under MIT and Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.

The underlying X-ray data is in the public domain (CC0 1.0) from the XrayDB project.