rexafs for Python
Published user guide · Versioned API reference
Process X-ray absorption spectra with Rust and work with the results as NumPy
arrays. Start with Spectrum(energy, mu).fft(); configure only what you need.
Energy is in eV, k/q in Å⁻¹, and R in Å.
Install
We recommend uv to manage an analysis project's Python version, dependencies and commands. CPython 3.10–3.14 is supported; start a Python 3.12 project with the stable package:
uv init --python 3.12 rexafs-analysis
cd rexafs-analysis
uv add rexafs==0.2.11 numpy
uv run python -c "import rexafs; print(rexafs.__version__)"
uv add records dependencies in pyproject.toml and resolves their versions in
uv.lock. uv run uses the project's .venv automatically; no shell activation
is needed. Commit pyproject.toml, .python-version and uv.lock with your
analysis, and leave .venv out of version control. NumPy is listed explicitly
because the examples import it. See uv's project guide.
PyPI provides platform wheels. Rust is needed only when building rexafs from source. Starting with 0.2.12, macOS wheels support Apple Silicon only; Linux x64 and Windows x64 wheels remain available. Intel Mac users can retain 0.2.11. New Intel wheels and Intel source-build qualification are discontinued.
Version note: keyword constructors, direct configuration setters and
XrayFFTR were added in 0.2.5. The basic example also works in 0.2.4.
Load and process a spectrum
Save this as analyze.py inside the project, beside your data file:
import numpy as np
from rexafs import Spectrum
# Two whitespace-delimited columns: energy in eV and absorption mu.
data = np.loadtxt("spectrum.dat")
spectrum = Spectrum(data[:, 0], data[:, 1]).fft()
r, magnitude = spectrum.r(), spectrum.chir_mag()
print(spectrum.e0(), r, magnitude)
Run it with uv run python analyze.py. In your editor, select the Python
interpreter from this project's .venv for completion and hover help.
For QAS transmission files, rexafs.io.read_qas_transmission(path) returns a
Spectrum using mu = ln(I0 / It), the natural logarithm of incident intensity
I0 divided by transmitted intensity It. Both intensities must be positive and
in matching units; this produces optical depth rather than an absolute absorption
coefficient. The first three whitespace-delimited columns are energy, I0 and
It; # starts a comment and additional columns are ignored. Do not use this
reader on a file that already contains mu. It accepts str or pathlib.Path:
from rexafs import io
spectrum = io.read_qas_transmission("Ru_QAS.dat").fft()
File/parse failures raise RuntimeError. The reader sorts energy and calculated
mu together when needed, retaining duplicate energy rows. It does not enforce
positive intensities or finite ratios; processing rejects non-finite data, and
duplicates can require cleanup for the selected numerical stage. Check the raw
intensities before analysis. The array constructor instead rejects unordered
or duplicate energy values.
normalize(), calc_background(), fft() and ifft() return the same spectrum.
Missing prerequisite stages run automatically. Results are copied NumPy float64
arrays; a result is None until its stage has run. Check for None when using a
result in typed code. Input lists, arrays and strided views are accepted and
copied; input energy must be finite and strictly increasing, with matching mu.
Configure only the parameters you need
from rexafs import AUTOBK, PrePostEdge, XrayFFTF, XrayFFTR
spectrum.set_normalization_method(PrePostEdge(pre_edge_end=-30.0))
spectrum.set_background_method(AUTOBK(rbkg=1.0))
spectrum.set_fft(XrayFFTF(kmin=2.0, kmax=12.0, kweight=2.0)).fft()
# Optional: isolate an R range and back-transform it.
spectrum.set_ifft(XrayFFTR(rmin=1.0, rmax=3.0, dr=0.5)).ifft()
q, filtered_chi = spectrum.q(), spectrum.chiq()
These ranges are examples; choose them for your data. Constructors take named
arguments, which editors can complete. Fields remain mutable, so existing code
such as background = AUTOBK(); background.rbkg = 1.2 still works.
BackgroundMethod.AUTOBK(background) and
NormalizationMethod.PrePostEdge(parameters) remain available for Rust-style
algorithm selection; passing settings directly is the shorter equivalent.
| Settings | Recommended starting values |
|---|---|
PrePostEdge() |
Automatically choose E0, fit ranges and polynomial order from the spectrum |
AUTOBK() |
rbkg=1.0, kstep=0.05, kweight=1, window="Hanning", solver="LinearDirect", clamp_scale_policy="FixedPenalty", clamp_lambda=0.001 |
XrayFFTF() |
kmin=2.0, kmax=15.0, kweight=2.0, dk=1.0, window="KaiserBessel", nfft=2048, grid="Input" |
XrayFFTR() |
rmin=0.0, rmax=20.0, dr=1.0, rweight=0.0, qmax_out=10.0, nfft=2048, automatic kstep |
Omitting an argument preserves its constructor default. None requests automatic
resolution for optional fields; this can differ from the constructor default
(for example, XrayFFTF(kmax=None) uses the measured upper k limit).
PrePostEdge() follows Rust PrePostEdge::new(), whose ranges are automatic,
rather than the fixed ranges in Rust PrePostEdge::default().
Setters copy settings and clear affected results. Editing the original settings
later requires calling the setter again. set_e0(eV) clears normalization and
all later results; set_fft() preserves chi(k); set_ifft() preserves chi(R).
Calling a stage explicitly recomputes it. See the shared API guide.
Some automatic values, including fit ranges and FFT spacings, are retained inside
the spectrum on subsequent calls; clearing results does not reset them to None.
AUTOBK's automatic kmax and nknots are instead calculated from each input.
The original settings
object remains unchanged. For example, after changing the background k spacing,
reassign forward and inverse settings so their automatic spacings are inferred
again:
# Requires 0.2.5 or later; continue with the spectrum above.
spectrum.set_background_method(AUTOBK(kstep=0.1))
spectrum.set_fft(XrayFFTF(kstep=None))
spectrum.set_ifft(XrayFFTR(kstep=None)).ifft()
Apply the same principle to a new scan with a different normalization range: reassign fresh automatic normalization settings instead of retaining the prior scan's resolved bounds. The generated member help explains these choices.
What the calculations mean
Normalization subtracts a fitted pre-edge baseline and divides absorption by its edge step. AUTOBK estimates the smooth background to obtain the EXAFS oscillations, chi(k). The Fourier transform weights and windows those oscillations to display them against R; its peaks are not automatically phase-corrected bond lengths. An inverse transform filters selected R contributions back into q space.
The forward code multiplies an unnormalized, negative-exponent FFT by
kstep / sqrt(pi), with no extra division by FFT length. For dimensionless chi
and forward exponent w, chi(R) has units Å⁻⁽ʷ⁺¹⁾; the default w=2 gives
Å⁻³. The real inverse retains the forward weighting and window, so with default
inverse rweight=0, its signal has units Å⁻ʷ and is generally not the original
unweighted chi(k).
The processing theory guide explains the equations, symbols, units, assumptions and implementation choices, with scientific references. Use the fitting-statistics guide when interpreting structural fits and uncertainties.
Completion, hover help and errors
The installed package includes py.typed, annotated .pyi files and native
runtime docstrings. Select the project's .venv interpreter in your editor
(Pylance/Pyright, for example). Hover over parameters for units, defaults and
behavior; help(AUTOBK) and help(Spectrum.fft) also work in a terminal.
FTWindow, FFTGrid, AUTOBKSolver and AUTOBKClampScalePolicy are Literal
type aliases, so editors suggest supported strings and flag invalid choices.
Invalid inputs/normalization raise ValueError; background/FFT failures raise
RuntimeError. Stages release the GIL during Rust computation. The public API
is rexafs; _core is an implementation detail.
Build from source
Packaging since 0.2.6: the Python binding enables PyO3's abi3-py310
feature, sharing one wheel per platform across GIL-enabled CPython 3.10–3.14.
The published 0.2.5 wheels remain unchanged. The release workflow tests the same
wheel on every supported interpreter with its minimum available NumPy wheel
and the latest compatible NumPy. Free-threaded Python is not qualified.
See the release checks
and PyO3's stable ABI guide.
From the repository root, with the pinned Rust toolchain installed, use an
isolated build environment. This development workflow uses uv venv and
uv run --no-project so installing the local extension does not change the
library's dependency manifest with analysis-project dependencies:
uv venv --python 3.14
uv pip install maturin numpy
uv run --no-project maturin develop --release --locked
uv run --no-project python py-rexafs/tests/test_api.py
EXAFS fitting, groups, structures, plotting and direct ReFEFF calculation remain
Rust/desktop APIs. ILPBkg remains an unimplemented selector. The historical empty
MBACK selector lacks absorber/edge identity; the configured MBack API (since 0.2.10)
below implements the full atomic match. See AUTOBK defaults
and FFT grid compatibility.
Licensed under MIT OR Apache-2.0.
Universal measurement reader (since 0.2.6)
Version 0.2.6 adds content-detected beamline text, CSV, Athena, XTUNES and HDF5 import through the shared Rust reader. Read a document, inspect its scans, columns, units and warnings, then select a signal mapping. Ambiguous channels require explicit selection; detector images require reduction before creating an absorption spectrum. Reading performs no processing or corrections. See the reader guide for language examples, unit conversions, dataset selection, fixture coverage and limits. This API is not included in the published 0.2.5 packages.
Larix 1.0 session import is available in the shared reader since 0.2.6, including stored absorption, complex saved arrays and inert session metadata. See the Larix import guide.
Column selections accept exact, case-sensitive names as well as zero-based indices.
For a QAS file, use measurement.arrays(energy="energy", i0="i0", it="it")
for transmission, iff="iff" instead of it for fluorescence, or
i0="it", it="ir" for the reference. The same keywords work with .spectrum().
Duplicate names require indices. Omit energy_unit to preserve detected axis
calibration, or explicitly override it with "eV" or "keV".
Scalar measurements (since 0.2.10)
Version 0.2.10 adds a one-call measurement API:
result = spectrum.measure("mean", (-20.0, 30.0), space="flat")
print(result.value, result.unit)
Omit space for normalized absorption. Energy bounds are offsets from E₀;
origin="absolute" selects absolute energy in eV. Missing prerequisite stages
run on a private copy without changing the spectrum. Point, maximum, integral
and mean are supported, with strict coverage checks. See the
measurement guide for k/R units, optional
independent errors, numerical meaning and the equivalent Rust/TypeScript calls.
This scalar operation is separate from rexafs.io.Measurement, the input-file
reader. The installed wheel includes result types and editor help.
Full MBACK normalization (since 0.2.10)
from rexafs import MBack
model = MBack("Cu", "K", pre_edge=(-200, -50), post_edge=(100, 800))
result = model.fit(energy, mu)
norm, flat = result.norm, result.flat
spectrum.set_normalization_method(model).normalize()
Energy and E₀-relative ranges use eV; norm and flat are separate dimensionless
outputs. Degree 2 and no erfc are the defaults. Offline atomic data load
automatically. Inputs and model are unchanged by fit; assigning settings to a
spectrum copies them. spectrum.mback_result() retrieves its full result, or
None after invalidation. Inspect resolved ranges and warnings. result.definition
pins the original atomic reference for replay. See the
MBACK guide for equations, assumptions and optional
background terms. Runtime atomic-data notices are included in rexafs/licenses/atomic.
Cauchy wavelets (since 0.2.10)
from rexafs import Wavelet
wavelet_map = spectrum.wavelet(Wavelet((2, 12)))
image = wavelet_map.magnitude # Independent NumPy matrix: R rows, k columns
region = wavelet_map.integral((4, 10), (1, 3))
print(region.value, region.unit)
The k interval uses Å⁻¹; R uses Å and is not phase-corrected. Missing normalization
and background stages run on a private copy. Defaults are weight 2, order 100,
k spacing 0.05 Å⁻¹, R up to 6 Å and no taper. Use named options to change them,
for example Wavelet((2, 12), rmax=4). model.calculate(k, chi) also accepts
original unweighted χ(k). The wavelet guide explains
native-grid integrals, slices, ownership, JSON replay and scientific limitations.
Fluorescence over-absorption (since 0.2.10)
from rexafs import FluorescenceCorrection
model = FluorescenceCorrection("CuO", "Cu", "K", line="Ka1", angles=(45, 45))
corrected = spectrum.correct_fluorescence(model)
corrected.normalize()
Supply the complete sample composition, detected emission and measured incident/exit angles from the sample surface, in degrees. The angles above are examples. Internal normalization is automatic; final normalization is separate. The original spectrum stays unchanged. The corrected spectrum retains its history and XANES-only restriction through edits. Known transmission and repeated correction fail. See the correction guide for the homogeneous thick-sample assumptions, diagnostics, replay and array API.
XANES peak fitting (since 0.2.10)
PeakFit and Spectrum.fit_peaks fit named peaks, absorption steps and baseline
terms through the native core. The default representation is normalized
absorption, with energy bounds relative to E₀ in eV. Results retain component
curves, termination and conditional uncertainty diagnostics. The model does not
select a peak count or identify chemical species. See the
XANES fitting guide for binding examples, area/width
conventions, constraints and interpretation limits.
Metadata
Release files for rexafs 0.2.14
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rexafs-0.2.14.tar.gz | 4.0 MB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rexafs-0.2.14-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| rexafs-0.2.14-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| rexafs-0.2.14-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 27.0 MB
Release files / rexafs-0.2.14.tar.gz
| Download URL | rexafs-0.2.14.tar.gz |
|---|---|
| Size | 4.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4e2f2c0f0e25276ddbb61f90d61319f96fe6612f8b258b9f6d27e9972a3c8dd9
|
|
BLAKE2b-256 checksum How to use checksums |
32e3ff92246a69b89339525d489bd172f8907ebd362fde7a58240868ea18cf88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / rexafs-0.2.14-cp310-abi3-win_amd64.whl
| Download URL | rexafs-0.2.14-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 8.3 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
bd6304ebc3afc84f9a5ad181fa69fe55a6058194ec94f5e1ef0cfb7ecffad063
|
|
BLAKE2b-256 checksum How to use checksums |
a195cf71f6d00337c455f22764f87f2423bb6660681d7d948c22e2ed23d9c4b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / rexafs-0.2.14-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | rexafs-0.2.14-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 7.9 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
ab84b4382a9bf6032c5f26ea75e1633ed858a99ee033e43a602060e8c599a2cd
|
|
BLAKE2b-256 checksum How to use checksums |
24a7e91ee4de918f5f98394af772b32dd13d04e9e5cd9e6cde5452358edee902
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / rexafs-0.2.14-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | rexafs-0.2.14-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 6.8 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
1c355ed21af9124c7c5846cc58239d1337761aa8713b700dd037098e068ae20e
|
|
BLAKE2b-256 checksum How to use checksums |
4ef3e1a20baaf4157f8627178f50abbb09056f28ebadefba6fc676b440528625
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log