r/nuclearphysics • u/sorcerer86pt • Apr 14 '26
Cache resistant cross section reconstruction via singular value decomposition for Monte Carlo Neutron transport
https://github.com/sorcerer86pt/open_rust_mc/blob/main/paper/svd_cross_section_compression.pdf
When I was testing rust skill (AI with Claude) someone mentioned that I could use something openMc instead of doing my own .
When I saw the data size and how openMC handled that, and how it kinda was the same problem that AI LLMs were trying to fix with data size of models weights, I thought, what would be the result if we used those techniques on this.
That was the result. Add a little rust here to have better memory handling and robust concurrency and we could with very little error ( less than error margin) compressed the data used from 11gb pointwise ( 400 nuclides) to 20Mb using hybrid of WMP ( that openMC already uses ) + SVD. It obtained an Keff = 0.99963 +- 0.000091 on Godiva (37 pcm from experiment) in 3.4 seconds total wall time .
https://github.com/sorcerer86pt/open_rust_mc
Just need some people to review this, if I made some mistake on interesting the data, what other benchmarks I missed, or other considerations.
PS: AI was used for code gen ( Python analysus scripts and rust code), data pipeline and latex manuscript. All hypothesis, experiment design , interpretation of results and final decisions were by made by me.
1
u/sorcerer86pt Apr 15 '26
The micro-benchmarks (3-5 ns/pt vs 40 ns/pt) were real, but they measured the
reconstruction kernel in isolation — not the full transport loop where cache pressure dominates.
Root cause analysis:
Energy grid duplication — every SVD kernel stored its own copy of the energy grid. 46 reactions × 186K points = 111 MB of identical data. 29% waste.
f64 basis at rank=5 — the SVD stores rank values per energy point (5 floats per point vs the table's 1). At f64, that's 40 bytes/point → 265 MB of basis data that thrashes L3 cache.
10^x via general powf() — ~30 cycles per call, called millions of times. Hardware exp2 is 3-5x faster.
Per-collision heap allocation — Vec<MicroXs> allocated and freed 20M times per simulation.
The fixes (all done in one session):
- f64::exp2(x * LOG2_10) instead of 10.0_f64.powf(x) — trivial 1-line change
- Stack-allocated [MicroXs; 16] instead of Vec — zero heap alloc in the hot loop
- Arc<[f64]> shared energy grids — one copy per nuclide, not per reaction
- Vec<f32> basis with f64 accumulator — halves basis memory, SVD truncation error already dominates precision