Differentiable multiplet simulations for X-ray spectroscopy in PyTorch.
multitorch computes L-edge X-ray absorption (XAS), emission (XES), and
resonant inelastic X-ray scattering (RIXS) spectra for 3d transition
metal complexes using crystal-field and charge-transfer multiplet theory.
The entire pipeline — from Wigner coupling coefficients through
Hamiltonian diagonalization to broadened spectra — runs in pure PyTorch
with float64 precision and full torch.autograd support.
- Differentiable end-to-end — gradients flow from physical parameters (Slater reduction, spin-orbit coupling, crystal field, charge transfer) through eigenvalues and transition matrices to the final spectrum
- No Fortran runtime — all physics computed natively in Python/PyTorch; pre-computed angular coefficients are bundled as package data
- XAS, XES, RIXS — L-edge absorption, emission, and 2D resonant inelastic scattering maps via the Kramers-Heisenberg kernel
- Validated — 477 tests; numerical agreement with the established
Cowan/ttmult Fortran suite across 9 Ti-Ni fixtures (cosine similarity
= 0.97)
- GPU-ready — tensors move to any PyTorch device
git clone https://github.com/follmerlab/multitorch.git
cd multitorch
pip install -e .Requirements: Python >= 3.10, PyTorch >= 2.2, NumPy, SciPy.
Optional extras:
pip install -e ".[plot]"# adds matplotlib
pip install -e ".[notebook]"# adds matplotlib + jupyter
pip install -e ".[dev]"# adds pytest, pytest-cov, sympyOr with conda:
conda env create -f requirements/environment.yml
conda activate multi
pip install -e .importtorchfrommultitorchimportcalcXAS# Ni2+ L-edge XAS in D4h symmetryx, y=calcXAS(
element="Ni", valence="ii", sym="d4h", edge="l",
cf={"tendq": 1.0, "ds": 0.0, "dt": 0.01},
slater=0.8, soc=1.0, T=300,
)
# Plotimportmatplotlib.pyplotaspltplt.plot(x.numpy(), y.detach().numpy())
plt.xlabel("Energy (eV)")
plt.ylabel("Intensity")
plt.show()slater=torch.tensor(0.8, dtype=torch.float64, requires_grad=True)
x, y=calcXAS(
element="Ni", valence="ii", sym="d4h", edge="l",
cf={}, slater=slater, soc=1.0,
)
# Gradient of the spectrum w.r.t. Slater reductionloss=y.sum()
loss.backward()
print(slater.grad) # d(spectrum)/d(slater)frommultitorchimportcalcRIXSrixs_map=calcRIXS(
"multitorch/data/fixtures/nid8ct/nid8ct.ban_out", # absorption"multitorch/data/fixtures/nid8ct/nid8ct.ban_out", # emission
)| Function | Description |
|---|---|
calcXAS(element, valence, sym, edge, cf, ...) | Compute XAS from physical parameters (differentiable) |
calcXAS(..., ban_output_path=...) | Compute XAS from a pre-computed .ban_out file |
calcRIXS(ban_abs_path, ban_ems_path, ...) | 2D RIXS map via Kramers-Heisenberg |
calcXES(...) | X-ray emission spectrum |
calcDOC(...) | Ground-state configuration weights |
getXAS(ban_output_path, ...) | Convenience wrapper for file-based XAS |
preload_fixture(fixture_dir) | Cache parsed fixture for fast parameter sweeps |
calcXAS_cached(fixture, ...) | XAS from a cached fixture (no file I/O per call) |
All functions are importable from multitorch directly:
frommultitorchimportcalcXAS, calcRIXS, calcDOC, getXASFour tutorial notebooks in notebooks/:
| Notebook | Description |
|---|---|
01_quickstart | One-call spectrum with broadening parameter sweep |
02_pipeline_walkthrough | Layer-by-layer: Wigner symbols -> Hamiltonian -> sticks -> spectrum |
03_parameter_exploration | Ti-Ni L-edge series, 10Dq/Slater sweeps with autograd |
04_rixs_quickstart | 2D RIXS maps, line cuts, autograd through the kernel |
pip install -e ".[notebook]"
jupyter lab notebooks/Physical parameters (slater, soc, cf, delta)
|
v
Atomic scaling (multitorch.atomic)
|
v
Angular coefficients (multitorch.angular) -- Wigner 3j/6j, CFP, RME
|
v
Hamiltonian assembly + diagonalization (multitorch.hamiltonian)
|
v
Boltzmann stick spectrum (multitorch.spectrum.sticks)
|
v
Pseudo-Voigt broadening (multitorch.spectrum.broaden)
|
v
(x, y) spectrum tensors -- autograd-compatible
pytest tests/ -q477 tests covering Wigner primitives, file parsers, angular RME construction, Hamiltonian eigenvalues, spectral broadening, autograd gradients, and end-to-end parity with Fortran reference outputs.
multitorch implements the multiplet theory described in:
- F.M.F. de Groot, "Multiplet effects in X-ray spectroscopy," Coordination Chemistry Reviews 249 (2005) 31-63
- R.D. Cowan, The Theory of Atomic Structure and Spectra (University of California Press, 1981)
The computational approach follows the Cowan/Butler/ttmult framework, replacing the Fortran numerical core with differentiable PyTorch tensors while preserving numerical agreement.
MIT -- see LICENSE.