For AI agents¶
A dense, rule-oriented map of liulu for coding agents. Read this first, then
the specific page you need. The canonical spec is plan.md in the repo root;
the project working agreement is CLAUDE.md.
What this package is¶
A streaming-model RSD predictor: given real-space \(\xi(r)\) + pairwise velocity
moments + a velocity PDF, it returns redshift-space \(\xi^s(s_\perp,s_\parallel)\)
and multipoles \(\xi_0,\xi_2,\xi_4\). Entry point: from liulu import StreamingModel.
Hard architecture rules (do not violate)¶
liulu/physics/= astrophysical content only. Nonp.trapz,scipy.integrate, FFTs, or grid construction. New physics = new class inheriting an ABC inphysics/base.py.liulu/numerics/= pure numerics. No cosmological parameters, no knowledge of what \(\xi\) or \(\mathcal{P}\) mean. Signatures aref, a, b, tolstyle — never aCosmologyor moments object.liulu/model.pyis the only wiring point, via constructor injection.
Conventions (load-bearing)¶
- Units: Mpc/\(h\), km/s, \(aH\) in km/s/(Mpc/\(h\)). Convert only at I/O.
- Moments:
m_ij(about origin) /c_ij(central);i=radial,j=tangential order. Odd tangential orders are auto-zero. Dispatcher:moments.get_moment(r, r_order, t_order, mode). Do not add parallelsigma_*/gamma_*/kappa_*accessors — those are inputs toTabulatedMoments, converted toc_ij. - Geometry: integrate over
y(real-space LOS sep);r=sqrt(s_perp^2+y^2),v_los=aH*(s_par-y)*sign(y). PDF signaturepdf(v_los, r_perp, r_par)withr_par >= 0— pass|y|. - LOS projection (
physics/los_projection.py) is geometry, not a model — not an ABC. Extend by adding higherc_ijmethods, never by hand-unrolling.
Gotchas that have bitten before¶
- Compare to binned measurements with
multipoles_binned(s_edges), nevermultipoles(s_centres). A pair-count estimator (pycorr) reports the \(s^2\)-weighted bin average; centre evaluation over-predicts the steep \(\xi_0\) by ~1.7% (log bins) and is first-order wrong through the FoG \(\xi_2\) curvature/zero-crossing — on AbacusSummit it masqueraded as a ~15% "FoG failure" (truth: ~4%). Likewise tabulate \(\xi(r)\) at the pair-weighted separation (pycorrreturn_sep, ornumerics.binning.pair_weighted_centres), not the geometric centre (~−2% on steep \(\xi\)). The two artefacts cancelled on the DEGRACE grids — a sub-percent match can be two ~2% bugs hiding each other. n_y >= 300inStreamingModel. Below that the Fingers-of-God dip in \(\xi_2\) (\(s\sim3\)–\(5\)) is under-resolved and any fit/objective on it is biased.TabulatedXidefaults to log–log interpolation (near-exact for power-law \(\xi\)); log-linear overestimates the convex curve and biased the monopole ~1.4% high. Falls back to log-linear where \(\xi\le0\).- Above \(r_\max\),
TabulatedXi(tail=...):"zero"(default, \(\xi\to0\)) or"power"(power-law continuation, slope clamped negative). Use"power"for tables short vs the integral's \(r\) reach \(\sqrt{s_{\perp,\max}^2+y_\text{max}^2}\) — a hard \(\xi\to0\) truncation biases the large-\(s\) quadrupole (~3% / 3σ at \(s\approx45\)). Feed streaming-model inputs throughnumerics.extrapolation.extend_table("power"for \(\xi\),"rise"for the still-rising velocity variances,"edge"for mean infall + shape moments). - Moments edge-extrapolate below \(r_\min\) so dispersions plateau; a zero variance would collapse the PDF to a delta and silently drop pairs.
- Skew-t caches its \((\gamma_1,\gamma_2)\to(\alpha,\nu)\) table at
liulu/data/skewt_param_table.npz; bump_SKEWT_TABLE_VERSIONon format change. NIG needs no table (closed-form inversion). - When measuring moments with the external
PairVel.jl, setJULIA_NUM_THREADS=1— multithreaded PyJulia segfaults via a PyCall finalizer race.
Velocity PDF — settled recommendation¶
Use NIGPDF (analytic, zero-tuning, best four-moment shape). Do not
tune the GH class index: a constant \(\lambda\) calibrated on one simulation
(by PDF shape or by \(\xi_2\)) fails to transfer to another (DEGRACE-tuned
\(\lambda\simeq+0.2\)–\(0.3\) makes AbacusSummit worse than NIG), and a
scale-dependent \(\lambda(r)\) additionally overfits within a simulation. NIG
already saturates the measurable accuracy at \(s\gtrsim2.5\) Mpc/\(h\) (empirical-PDF
identity test); the only genuine headroom is the deep FoG, which needs a
measured/emulated PDF or \(>\)4 moments. Evidence: Validation.
Where things live¶
| need | file |
|---|---|
| driver / integral / multipoles | liulu/model.py |
| ABCs | liulu/physics/base.py |
xi(r) providers |
liulu/physics/real_space.py |
| pairwise moments | liulu/physics/pairwise_velocity.py |
| velocity PDFs | liulu/physics/velocity_pdf.py |
| LOS projection | liulu/physics/los_projection.py |
| interpolation | liulu/numerics/interpolation.py |
| bin geometry (pair-weighted centres) | liulu/numerics/binning.py |
| Hankel transforms | liulu/numerics/hankel.py |
| tests | liulu/tests/ |
| spec | plan.md |
Environment / commands¶
python -m pytest liulu/tests/ -v # tests (self-contained, no external data)
mkdocs build # this site
Run these in whatever Python environment the package is installed in — no specific environment manager is assumed.