Pairwise velocity moments — vel_m10 … vel_c22, vel_binned¶
Eight central moments of the radial pairwise velocity between halo mass-bin
pairs, on a radial grid — plus a derived recipe (vel_binned) that aggregates
them exactly onto arbitrary mass bins.
m10 = reg.predict("vel_m10", "LCDM", 0.25, [0.31, 0.677, 0.967, 0.83]) # (1, 91, 37)
art = reg.load("vel_m10", "LCDM", 0.25)
art.pair_keys # 91 mass-bin pairs
art.r # 37 radial bins over [0, 150] Mpc/h (wide grid)
- Keys:
vel_m10,vel_c20,vel_c02,vel_c12,vel_c30,vel_c40,vel_c04,vel_c22(trained), andvel_binned(derived). - Output:
(1, 91, 37)— 91 mass-pair × 37 radial bins (trimmed columns NaN). - Mass bins: 13 adaptive bins over log₁₀M ∈ [12.5, 14.2] — 0.1 dex over [12.5, 13.5), 0.25 dex over [13.5, 14.0), cap [14.0, 14.2) — giving 91 ordered pairs. The high-mass cap is signal-to-noise motivated.
- Radial grid: 37 wide bins — roughly log-spaced 1–2.5 Mpc/h widths below 15 Mpc/h, 5 Mpc/h above (adopted 2026-07-06 after a bin-width exploration: 20–30% less noise per bin, better held-out accuracy for all eight moments, and the averaging systematic stays below the noise; the earlier 72-bin quasi-log grid is retired).
Moments¶
| Moment | Meaning | Sign | Transform |
|---|---|---|---|
m10 |
mean radial infall | signed | arcsinh |
c20 |
variance ∥ | + | log |
c02 |
variance ⊥ | + | log |
c12 |
skew cross term | signed | arcsinh |
c30 |
skew ∥ | signed | arcsinh |
c40, c04, c22 |
4th-order | + | log |
Representation & accuracy¶
Each moment is a weighted-PCA GP (n_components = 16, n_restarts = 10)
under the per-moment transform above (log for positive moments, arcsinh
for signed) — the transform is what holds the high-order moments at the noise
floor. Every emulator carries a frozen-seed ε de-bias correction built on the
13-bin columns (vel_fine_seed_debias.py).
The honest per-emulator numbers (in-sample and interior corner-excluded LOO χ)
live in the manifest: reg.entry("vel_c20", gravity, 0.25)["accuracy"]. The
end-to-end acceptance test is the aggregated recipe at the 5-box fiducial:
χ 0.46–0.94 (ΛCDM) and 0.80–1.81 (f(R), all 8 moments; the
maximum is the fourth-order c04 — the signal-weighted infill repaired
the formerly-worst c02, and the 2026-07-15 admission slotted c12 in
at 0.99–1.13). Against fiducial boxes that do not
share the design's random seeds, the shipped emulators read χ 0.43–0.72
(ΛCDM holdout boxes 19–30) and 1.1–2.3 (f(R), 25 boxes on 2.2× tighter
error bars) — with the correction off those jump to 1.9–2.8 / 2.5–4.3 and
become 68–94% coherent, which is the shared-seed offset the correction
removes (evidence: registration_widea/vel_indepseed_oos.json).
χ, not fractional error
Velocity moments cross zero, so fractional error is meaningless. Accuracy is quoted as χ = residual / SEM; χ < 1 means at or below the simulation noise floor.
vel_binned — arbitrary mass bins¶
The trained surfaces live on the 13-bin grid; vel_binned aggregates all
eight moments onto your mass bins through the exact raw-moment
pair-count algebra (weights n_a n_b (1 + ξ_hh^ab(r)) modelled from the
hmf + bias/ξ emulators; weight-model error vs measured pair counts:
median 2–6×10⁻⁴):
res = reg.predict("vel_binned", "LCDM", 0.25, th,
mass_edges=[12.5, 13.0, 13.5], # each edge ON the 13-bin grid
moments=("m10", "c20"))
res["moments"]["m10"] # (Nbin, Nbin, 37); res["r"], res["validity"]
Edges must be built from whole fine-grid cells — whole-bin aggregation is what keeps the conversion exact.
f(R) — all 8 moments¶
The f(R) velocity moments are registered (z = 0.25) for all eight
moments, as seed-paired boosts composed onto the ΛCDM emulator: log-ratio
for the positive 4th moments (c40, c04, c22), additive-arcsinh for
c20/c02/c12/c30; m10 uses the direct 5-parameter GP. The per-box
seed-paired difference cancels most of the cosmic variance.
vel_c12/fRn1 was the late arrival (registered 2026-07-15): its first
boost — fitted on the retired 72-bin narrow grid with a noise-scaled
transform — failed the aggregation acceptance test in 2026-07 and the
moment shipped ΛCDM-only for two weeks. Re-tested on the current wide
bins with the family's plain additive-arcsinh transform it passes every
test: interior LOO χ = 1.51 (in-family), fiducial aggregation χ = 1.24
(ceiling 2.5), independent-seed 25-box aggregation χ = 1.53 with the
seed correction on (family range 1.1–2.3). Until then the recipe
returned NaN for f(R) c12; that behaviour survives only as a fallback
if no f(R) vel_c12 resolves from the registry.
f(R) is intrinsically harder (a fifth parameter over the same design
points): at the wide binning the boosts' design-interior LOO sits at
χ ≈ 1.3–1.9 (at the retired narrow binning the noisy fourth moments ran up
to χ ≈ 7) — a design-sampling limit (the direct GP is worse), not a
representation failure. The five signal-weighted supplemental pairs
(imodel 68–72) now train the c02, c20 and c12 boosts (interior LOO
2.03→1.57, 1.89→1.59, and 1.51 for the newly admitted c12); the other
four f(R) moments keep design-only training — augmenting them tests
worse (blanket augmentation would take m10 from χ 1.43 to 2.58). All
ΛCDM moments train on the augmented set. See f(R) gravity.
Rejected levers (don't re-explore)¶
Established on the campaign-era measurements (scripts now in git history):
- Standardized moments (kurtosis
c40/c20², etc.): the dimensionless ratio cancels ~4× of the across-box variance, but reconstructing the raw moment re-injects it — no deployable gain for the raw moments. - r_max trimming: trimming the large-r tail makes LOO χ worse for every moment; the full r-range carries signal and the SEM-weighted PCA already down-weights the noisy columns. (Bin-width choices, by contrast, paid off twice: the first exploration replaced the linear 2.5 Mpc/h grid, which lost 2–23× the noise floor below r = 10, with a quasi-log one; the second, 2026-07, widened it to the current 37 bins.)
Evidence scripts¶
vel_fine_lcdm_eval.py, vel_fine_frn1_eval.py, vel_fine_recon_gate.py,
vel_rbin_explore.py, vel_rwidth_explore.py,
vel_widea_vs_logb_fiducial.py, vel_frn1_indepseed_oos.py,
vel_fine_seed_debias.py,
vel_fine_register.py, plot_velocity_fine.py. (The retired
0.5-dex-era scripts — vel_validation.py, velocity_ablation.py,
plot_velocity.py, … — live in git history.)