clenspy.kernels.lensing_kernel.LensingKernel

class clenspy.kernels.lensing_kernel.LensingKernel(survey, cosmology, unity=False)[source]

Bases: object

Source-averaged \(\Sigma_{\rm crit}\) weights for one survey.

NOTE: units and conventions are the module’s – comoving \(\Sigma_{\rm crit}\), h-free, Msun/Mpc^2.

NOTE: the constructor stores and computes nothing. The interpolant over \(z_l\) is built on first use of kernel_z, so constructing this object is free.

Parameters:
  • survey (object) – Anything satisfying the ~clenspy.protocols.Survey protocol – clenspy.survey.Survey in practice. Stored verbatim.

  • cosmology (astropy.cosmology.Cosmology) – The world model. Stored verbatim.

  • unity (bool, optional) –

    If True, mean_inverse_sigma_crit returns 1 everywhere, so every downstream consumer emits \(\Delta\Sigma\) instead of \(\gamma_t\) (default: False).

    NOTE: this is the clean protocol seam, and it is what the y3 pipeline’s unity=T option does – it is how a \(\Delta\Sigma\) data vector is compared against a model written for shear, with no second code path.

__init__(survey, cosmology, unity=False)[source]
Parameters:

unity (bool)

Return type:

None

Methods

__init__(survey, cosmology[, unity])

f_src_behind(z_halo[, min_separation, n_nodes])

Fraction of sources behind \(z_h\), dimensionless.

kernel_z(z_lens[, delta_z])

mean_inverse_sigma_crit, interpolated over \(z_l\).

mean_inverse_sigma_crit(z_lens[, delta_z])

\(\langle\Sigma_{\rm crit}^{-1}\rangle(z_l)\) [Mpc^2/Msun].

mean_sigma_crit(z_halo[, min_separation, ...])

\(\langle\Sigma_{\rm crit}\rangle(z_h)\) [Msun/Mpc^2 comoving].

q_sigma(z_lens, z_halo[, min_separation, ...])

The \(\Sigma_{\rm crit}\)-weighted kernel \(q_\Sigma(z_l; z_h)\).

mean_inverse_sigma_crit(z_lens, delta_z=0.0)[source]

\(\langle\Sigma_{\rm crit}^{-1}\rangle(z_l)\) [Mpc^2/Msun].

\[\langle\Sigma_{\rm crit}^{-1}\rangle(z_l) = \int\! dz_s\; p(z_s + \Delta z)\, \max\!\left[0,\, \Sigma_{\rm crit}^{-1}(z_l, z_s)\right]\]

The inverse is averaged, which is not the inverse of mean_sigma_crit and differs from it by the source weighting.

Parameters:
  • z_lens (float or array-like) – Lens redshift(s).

  • delta_z (float, optional) – Photo-z bias shifting the source \(p(z)\), as \(p(z_s + \Delta z)\). A nuisance parameter, marginalised over, so it is an argument (default: 0).

Returns:

np.ndarray – The average, or ones if unity – see the class NOTE.

kernel_z(z_lens, delta_z=0.0)[source]

mean_inverse_sigma_crit, interpolated over \(z_l\).

Same quantity, evaluated on a _N_ZL_NODES grid once and interpolated after – which is what a Limber integral over \(\chi\) wants, since it evaluates the kernel at every node.

NOTE: the grid spans \([z_s^{\min}, z_s^{\max}]\), and the interpolant is not extrapolated: outside it the result is zero, because a lens behind every source is unlensed.

NOTE: cached on the instance keyed by delta_z, so sweeping a photo-z bias does not silently reuse the wrong grid.

Parameters:

delta_z (float)

q_sigma(z_lens, z_halo, min_separation=None, n_nodes=None)[source]

The \(\Sigma_{\rm crit}\)-weighted kernel \(q_\Sigma(z_l; z_h)\).

\[q_\Sigma(z_l; z_h) = \int\! dz_s\; p(z_s)\, \frac{\Sigma_{\rm crit}(z_h, z_s)} {\Sigma_{\rm crit}(z_l, z_s)}\]

NOTE: cutoff-defined. The integrand diverges as \(z_s \to z_h\), so the value depends on min_separation (floored at MIN_LENS_SOURCE_SEPARATION) and, through the endpoint’s trapezoid weight, on n_nodes. Both default to the values the frozen covariance reference was built with. The frozen reference is itself signed: for \(z_s\) between \(z_l\) and \(z_h\) the ratio changes sign, and its q_sigma runs from -2.29 to +3.91. That is the definition, not a bug – do not clamp it.

Dimensionless. It is the weight with which structure at \(z_l\) contributes to a \(\Sigma\) measured around a halo at \(z_h\) – the ratio, not either factor alone, which is why the \(c^2/4\pi G\) cancels and only geometry survives.

NOTE: the source range starts at \(z_l\) + min_separation, keyed on the lens, not on the halo. So when \(z_l < z_h\) the range includes sources in front of the halo, where \(\chi_s - \chi_h < 0\) and \(\Sigma_{\rm crit}(z_h, z_s)\) is negative. The frozen reference keeps that sign – its q_sigma runs from -2.29 to +3.91 – so this is the definition and the integrand is not clamped. Clamping it, or keying the range on \(\max(z_l, z_h)\), changes the covariance.

NOTE: the same range choice puts the \(z_s = z_h\) pole inside the integral whenever \(z_l < z_h\). The trapezoid straddles it and returns a finite but grid-dependent number, which is where the \(\pm 4\) excursions come from. That is inherited from the reference definition, not introduced here.

NOTE: measured consequence: for \(z_l < z_h\) the value does not converge in n_nodes (z_h = 0.425, z_l = 0.153: -0.03, 0.44, 1.24, 0.68 at 100, 200, 400, 3200 nodes), and \(C_\ell^{\Sigma\Sigma}\) built from it changes by O(1) with the slab width. Restricting sources to \(z_s > z_h\) removes both; which restriction is intended is an open decision, see validation/covariance_review_REPORT.md and validation/diagnose_qsigma_pole.py. Default unchanged.

Parameters:
  • z_lens (float or array-like) – Redshift of the lensing structure.

  • z_halo (float) – Redshift of the halo the profile is measured around.

  • min_separation (float, int, optional) – The two conventions the value depends on; see MIN_LENS_SOURCE_SEPARATION.

  • n_nodes (float, int, optional) – The two conventions the value depends on; see MIN_LENS_SOURCE_SEPARATION.

mean_sigma_crit(z_halo, min_separation=None, n_nodes=None)[source]

\(\langle\Sigma_{\rm crit}\rangle(z_h)\) [Msun/Mpc^2 comoving].

\[\langle\Sigma_{\rm crit}\rangle(z_h) = \int_{z_h}\! dz_s\; p(z_s)\,\Sigma_{\rm crit}(z_h, z_s)\]

NOTE: cutoff-defined. Sources just behind the lens have unbounded \(\Sigma_{\rm crit}\), so without a floor the average does not exist; this returns the integral from \(z_h + \delta\), with \(\delta\) = min_separation (MIN_LENS_SOURCE_SEPARATION, 0.01, by default). For a given \(\delta\) it converges under Gauss-Legendre (96 nodes: 3e-11 even at 0.01); an earlier note here said refining the grid lowered the answer, but that was the trapezoid’s first interval, not the physics. The value does depend on \(\delta\) – 0.1 versus 0.01 changes it by up to a factor 5 – which is why the covariance pins it.

NOTE: not the reciprocal of mean_inverse_sigma_crit. Both are needed and they are different averages; see errata E.1 item 1. That one is convergent, which is the deeper reason to prefer it.

NOTE: not normalised by f_src_behind: the integral over the whole source distribution, with sources in front contributing zero, so it carries the behind-fraction implicitly. The covariance shape noise does not use this directly any more: since cluster-lensing-cov cddbb2a it uses the conditional average over lensed sources, mean_sigma_crit(z, 0.1) / f_src_behind(z, 0.1) (cut MIN_LENS_SOURCE_SEPARATION_NOISE), which LimberProjector.shape_noise_Sigma forms from this method.

f_src_behind(z_halo, min_separation=None, n_nodes=None)[source]

Fraction of sources behind \(z_h\), dimensionless.

\[f_{\rm src}(z_h) = \int_{z_h + \delta}^{z_s^{\max}}\! dz_s\; p(z_s)\]

Falls to zero at the top of the source distribution and is 1 below its bottom, since \(p(z_s)\) is normalised.

Parameters:
  • z_halo (float or array-like) – Lens redshift(s).

  • min_separation (float, optional) – The cut \(\delta\) (default MIN_LENS_SOURCE_SEPARATION, 0.01). The covariance shape noise passes MIN_LENS_SOURCE_SEPARATION_NOISE (0.1), as cluster-lensing-cov cddbb2a does.

  • n_nodes (int, optional) – Gauss-Legendre order (default N_ZS_GL).