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, tail="zero") interpolates a measured/theoretical \(\xi(r)\).

  • Default interpolator: hybrid power-law. Across table intervals where both \(\xi\) values are positive it is linear in \(\log\xi\) vs \(\log r\)\(\xi(r)\) is steeply falling and approximately power-law there, so this is near-exact, whereas the older log-linear scheme overestimated the convex curve between bins and biased the model monopole high by ~1.4%. Across any interval touching \(\xi \le 0\) it switches to linear in \(\xi\) (vs \(\log r\)), so tabulated negative values (the post-BAO regime, halo-exclusion dips) are reproduced exactly at the nodes and bridged with the correct sign — never discarded or replaced by a positive power law.
  • Out-of-range policy: constant (edge) extrapolation below \(r_\min\) (so the \([1+\xi]\) streaming weight keeps clustering on small scales). Above \(r_\max\), the tail argument selects the behaviour:
    • tail="zero" (default) — \(\xi\to0\);
    • tail="power" — continue the power law of the trailing consistent-sign points (slope clamped weakly falling so it cannot grow; a table ending negative gets a decaying negative tail, \(\xi\to0^-\)).
  • Use tail="power" when your table is short relative to \(\sqrt{s_{\perp,\max}^2 + (|s_\parallel|_{\max} + y_\text{pad})^2}\) (the largest \(r\) the integral samples). A hard \(\xi\to0\) truncation there discards real large-scale power and biases the quadrupole at the largest separations (it left \(\xi_2\) ~3% / 3\(\sigma\) high at \(s\approx45\,h^{-1}\)Mpc against high-S/N halos).
from liulu.physics.real_space import TabulatedXi
xi_real = TabulatedXi(r_table=r, xi_table=xi)               # log-log, xi->0 above r_max
xi_real = TabulatedXi(r_table=r, xi_table=xi, tail="power") # power-law tail (short tables)

# 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 — for \(\xi\) use tail="power"; for the velocity variances \(\sigma_r^2,\sigma_t^2\), which are typically still rising at \(r_\max\), continue the rise rather than freezing it (see liulu.numerics.extrapolation.extend_table). Querying outside the table emits a one-time RuntimeWarning describing the fill used.

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.