Skip to content

Inputs & interpolation

The streaming integral repeatedly evaluates \(\xi(r)\) and the velocity moments at \(r\) values between your tabulated points, and sometimes just outside the table. How those tables are interpolated and extrapolated has a real, measurable effect on the prediction — this page covers the choices and the safe defaults.

Real-space correlation xi(r)

TabulatedXi(r_table, xi_table, interpolator=None) interpolates a measured/theoretical \(\xi(r)\).

  • Default interpolator: log–log (linear in \(\log\xi\) vs \(\log r\)). \(\xi(r)\) is steeply falling and approximately power-law on these scales, so log–log is near-exact, whereas the older log-linear scheme overestimates the convex curve between bins and biased the model monopole high by ~1.4%. log–log falls back to log-linear wherever \(\xi \le 0\).
  • Out-of-range policy: constant (edge) extrapolation below \(r_\min\) (so the \([1+\xi]\) streaming weight keeps clustering on small scales) and \(\xi\to0\) above \(r_\max\) (its physical large-separation limit).
from liulu.physics.real_space import TabulatedXi
xi_real = TabulatedXi(r_table=r, xi_table=xi)          # log-log by default

# from a power spectrum instead:
from liulu.physics.real_space import LinearTheoryXi, HalofitXi
xi_real = LinearTheoryXi(k=k, pk=pk)                   # Hankel transform of P(k)

Extend the table to cover the integral's range

The integral samples \(r\) up to \(\sqrt{s_{\perp,\max}^2 + y_\text{max}^2}\). Make sure your \(\xi(r)\) and moment tables span that range (or rely on the documented edge behaviour); querying outside the table emits a one-time RuntimeWarning.

Pairwise velocity moments

TabulatedMoments accepts the convenient dispersion/shape inputs and stores canonical central moments:

from liulu.physics.pairwise_velocity import TabulatedMoments
moments = TabulatedMoments(
    r_table=r,
    v_r=v_r,            # mean radial pairwise velocity  -> m_10
    sigma_r=sigma_r,    # radial dispersion              -> c_20 = sigma_r^2
    sigma_t=sigma_t,    # tangential dispersion          -> c_02 = sigma_t^2
    gamma_r=gamma_r,    # radial skewness                -> c_30
    kappa_r=kappa_r,    # radial excess kurtosis         -> c_40
    kappa_t=kappa_t,    # tangential excess kurtosis     -> c_04
    c_12_table=None,    # cross moment; defaults to 0
    c_22_table=None,    # cross moment; defaults to c_20*c_02 (independence)
)

Only v_r, sigma_r, sigma_t are required (Gaussian level). The higher moments are needed for the skew-\(t\)/GH PDFs; unspecified ones default to the Gaussian + independence values.

Dispersions must not collapse to zero below the table

Moments use edge extrapolation below \(r_\min\), so the dispersions plateau rather than dropping to zero. (A zero variance would make the PDF a delta and silently drop those pairs from the integral.) This is deliberate — see the interpolation tests.

Interpolation routines

The pure-numerics interpolators live in liulu.numerics.interpolation:

function space use
loglog_interp linear in \((\log r, \log y)\) power-law positive data (xi(r) default)
log_linear_interp linear in \(\log r\), linear in \(y\) data that can be negative (velocities)
log_spline_interp cubic spline in \(\log r\) smooth data needing curvature

All share the same out-of-range policy: a scalar fill_value, or a (below, above) tuple, where either side may be "edge" for constant extrapolation. Out-of-range queries emit a stable, deduplicated RuntimeWarning (silence with warn=False).

You can inject any of these into TabulatedXi(..., interpolator=...) if you need to override the default.