diff --git a/GLOSSARY.md b/GLOSSARY.md index 701ef3e26..c28a61ae6 100644 --- a/GLOSSARY.md +++ b/GLOSSARY.md @@ -1,6 +1,6 @@ -# Firecrown API, Dependency, and Release Language +# Firecrown Language -Terms used when assessing Firecrown dependencies and the compatibility of releases and pull requests. +Terms used when assessing Firecrown dependencies, release compatibility, and scientific test expectations. ## Language @@ -33,3 +33,11 @@ An advisory, technically non-blocking sample of environment rebuildability for a **API policy verdict**: The target-dependent interpretation of a completed static public API comparison: no detected breaking changes, informational breaking changes on `master`, or rejection of detected breaking changes on a support target. The verdict is distinct from whether analysis and reporting succeeded; missing analysis or reporting is not evidence of compatibility, and no detected breaks does not establish complete behavioral compatibility. + +## SACC Test Language + +**SACC fixture expectation**: +A reference redshift distribution or angular spectrum retaining the inputs supplied to SACC, or copies of those inputs, for comparison with extracted results. + +**Synthetic SACC observation**: +A supplied test value for a recognized SACC observable, such as an angular power spectrum, angular correlation, or windowed bandpower. It is neither a survey measurement nor necessarily a theory prediction or physically plausible realization; a value with an unknown data-type label has no established observable interpretation. diff --git a/firecrown/likelihood/_gaussfamily.py b/firecrown/likelihood/_gaussfamily.py index 7bd11e94b..a02068dfa 100644 --- a/firecrown/likelihood/_gaussfamily.py +++ b/firecrown/likelihood/_gaussfamily.py @@ -170,8 +170,8 @@ def __init__( self.cholesky: None | npt.NDArray[np.float64] = None self.inv_cov: None | npt.NDArray[np.float64] = None self.cov_index_map: None | dict[int, int] = None - self.theory_vector: None | npt.NDArray[np.double] = None - self.data_vector: None | npt.NDArray[np.double] = None + self.theory_vector: None | npt.NDArray[np.float64] = None + self.data_vector: None | npt.NDArray[np.float64] = None self._use_cholesky_for_chisq: bool = use_cholesky @classmethod diff --git a/firecrown/likelihood/_gaussian_pointmass.py b/firecrown/likelihood/_gaussian_pointmass.py index cf1027881..8086113bf 100644 --- a/firecrown/likelihood/_gaussian_pointmass.py +++ b/firecrown/likelihood/_gaussian_pointmass.py @@ -399,10 +399,10 @@ def _prepare_integrand(self, cosmo: pyccl.Cosmology) -> np.ndarray: # Cosmology calculations sc_valid = pyccl.sigma_critical(cosmo, a_lens=aL_all, a_source=aS_all) - sc = np.full(mask.shape, np.nan, dtype=float) + sc = np.full(mask.shape, np.nan, dtype=np.float64) sc[mask] = sc_valid D_l_valid = pyccl.angular_diameter_distance(cosmo, a_l)[z_l > 0] - D_l = np.full(z_l.shape, np.nan, dtype=float) + D_l = np.full(z_l.shape, np.nan, dtype=np.float64) D_l[z_l > 0] = D_l_valid D_l = D_l[:, None] integrand = 1.0 / sc / (D_l * D_l) @@ -448,7 +448,6 @@ def _build_V(self, betas: np.ndarray) -> np.ndarray: V = np.zeros((len(row_src_idx), len(lens_tracers))) valid = (row_lens_idx >= 0) & (row_src_idx >= 0) - beta_rows = np.zeros(valid.sum(), dtype=float) beta_rows = betas[row_lens_idx[valid], row_src_idx[valid]] V[valid, row_lens_idx[valid]] = beta_rows / (theta[valid] ** 2) return V diff --git a/tests/_types.py b/tests/_types.py index 6e3b8eafa..666adabbb 100644 --- a/tests/_types.py +++ b/tests/_types.py @@ -1,6 +1,10 @@ -"""Shared types for test fixtures.""" +"""Shared types for test fixtures. -from typing import TypeAlias, TypedDict +Expected arrays retain the inputs supplied to SACC, or copies of those inputs. +""" + +from dataclasses import dataclass +from typing import TypedDict from numcosmo_py import Nc import numpy as np @@ -9,22 +13,150 @@ from firecrown.metadata_types import TracerNames -RedshiftDistribution: TypeAlias = tuple[ - npt.NDArray[np.float64], npt.NDArray[np.float64] -] -"""Sampled redshift distribution as (z, dndz), without a normalization guarantee.""" - -WindowedAngularPowerSpectrum: TypeAlias = tuple[ - npt.NDArray[np.int64], npt.NDArray[np.float64], sacc.BandpowerWindow -] -"""Window ell grid, measured bandpowers, and their bandpower window.""" - -SaccGalaxyWindowedFixture: TypeAlias = tuple[ - sacc.Sacc, - dict[str, RedshiftDistribution], - dict[tuple[TracerNames, str], WindowedAngularPowerSpectrum], -] -"""SACC data, distributions by tracer name, and spectra by tracer pair/data type.""" + +@dataclass(frozen=True, kw_only=True) +class SampledRedshiftDistribution: + """Sampled redshift coordinates and unnormalized number density. + + :param z: Sampled redshift coordinates. + :param dndz: Number-density values on the redshift grid; not normalized. + """ + + z: npt.NDArray[np.float64] + dndz: npt.NDArray[np.float64] + + +@dataclass(frozen=True, kw_only=True) +class SaccGalaxyDistributionFixture: + """SACC tracer data and its sampled redshift distributions. + + :param sacc_data: SACC data used by production extraction and construction. + :param distributions: Redshift distributions keyed by tracer name. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + + +# Harmonic and real-space cross-bin records have distinct types because they +# represent different physical observables. Their shared fields can evolve +# independently as fixture values become more physically realistic. +@dataclass(frozen=True, kw_only=True) +class SaccHarmonicCrossBinFixture: + """Harmonic cross-bin SACC data and expected redshift distributions. + + Both tracer distributions share their original redshift coordinate array, + but retain distinct unnormalized number densities. No measurement metadata + is inferred here; consumers still exercise production extraction. + + :param sacc_data: Unwindowed harmonic SACC data for the two tracers. + :param distributions: Sampled redshift distributions keyed by tracer name. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + + +@dataclass(frozen=True, kw_only=True) +class SaccRealCrossBinFixture: + """Real cross-bin SACC data and expected redshift distributions. + + Both tracer distributions share their original redshift coordinate array, + but retain distinct unnormalized number densities. No measurement metadata + is inferred here; consumers still exercise production extraction. + + :param sacc_data: Unwindowed real-space SACC data for the two tracers. + :param distributions: Sampled redshift distributions keyed by tracer name. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + + +@dataclass(frozen=True, kw_only=True) +class HarmonicAngularPowerSpectrum: + """Unwindowed harmonic coordinates and synthetic observations. + + :param ells: Integer multipoles for the synthetic observations. + :param cells: Synthetic observed values, not survey data or theory predictions. + """ + + ells: npt.NDArray[np.int64] + cells: npt.NDArray[np.float64] + + +@dataclass(frozen=True, kw_only=True) +class SaccGalaxyHarmonicFixture: + """Harmonic SACC data with named expected distributions and spectra. + + :param sacc_data: SACC data used by production extraction and construction. + :param distributions: Redshift distributions keyed by tracer name. + :param spectra: Synthetic spectra keyed by ordered tracer names and data type. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + spectra: dict[tuple[TracerNames, str], HarmonicAngularPowerSpectrum] + + +@dataclass(frozen=True, kw_only=True) +class RealAngularCorrelation: + """Unwindowed angular coordinates and synthetic observations. + + :param thetas: Angular coordinates for the observations. + :param xis: Synthetic correlations, not survey data or theory predictions. + """ + + thetas: npt.NDArray[np.float64] + xis: npt.NDArray[np.float64] + + +@dataclass(frozen=True, kw_only=True) +class SaccGalaxyRealFixture: + """Real SACC data with named expected distributions and correlations. + + :param sacc_data: SACC data used by production extraction and construction. + :param distributions: Redshift distributions keyed by tracer name. + :param spectra: Synthetic correlations keyed by ordered tracer names and data type. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + spectra: dict[tuple[TracerNames, str], RealAngularCorrelation] + + +@dataclass(frozen=True, kw_only=True) +class WindowedAngularPowerSpectrum: + """Window support, synthetic bandpowers, and their shared window. + + Support multipoles need not match the number of bandpowers. + SACC observation labels are weighted support sums, not the support grid + or normalized band centers. + + :param support_ells: Integer multipoles on which the window is defined. + :param bandpowers: Synthetic observed values, not survey data or predictions; + one per window column. + :param window: SACC BandpowerWindow shared with the fixture's data points; + its values are support multipoles and its weights are unnormalized. + """ + + support_ells: npt.NDArray[np.int64] + bandpowers: npt.NDArray[np.float64] + window: sacc.BandpowerWindow + + +@dataclass(frozen=True, kw_only=True) +class SaccGalaxyWindowedFixture: + """Windowed SACC data with named expected distributions and spectra. + + :param sacc_data: SACC data used by production extraction and construction. + :param distributions: Redshift distributions keyed by tracer name. + :param spectra: Windowed spectra keyed by ordered tracer names and data type. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + spectra: dict[tuple[TracerNames, str], WindowedAngularPowerSpectrum] class NumCosmoCosmologyFixture(TypedDict): diff --git a/tests/conftest.py b/tests/conftest.py index 09ac02881..736915555 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,6 +7,7 @@ # pylint: disable=too-many-lines import ast import sys +from dataclasses import dataclass from itertools import product from typing import Callable, assert_never @@ -44,8 +45,15 @@ from firecrown.updatable import ParamsMap, get_default_params_map from firecrown.utils import upper_triangle_indices from tests._types import ( - RedshiftDistribution, + HarmonicAngularPowerSpectrum, + RealAngularCorrelation, + SaccGalaxyDistributionFixture, + SaccGalaxyHarmonicFixture, + SaccGalaxyRealFixture, SaccGalaxyWindowedFixture, + SaccHarmonicCrossBinFixture, + SaccRealCrossBinFixture, + SampledRedshiftDistribution, WindowedAngularPowerSpectrum, ) @@ -387,16 +395,35 @@ def fixture_all_real_bins() -> list[TomographicBin]: ] +@dataclass(frozen=True, kw_only=True) +class HarmonicWindowFunction: + """Harmonic window with its ell grid, weight matrix, and band labels. + + :param ell_grid: Integer multipoles on which the window weights are defined. + :param weights: Weight matrix with one row per ell and one column per band. + :param band_labels: Float labels, one per weight column. + """ + + ell_grid: npt.NDArray[np.int64] + weights: npt.NDArray[np.float64] + band_labels: npt.NDArray[np.float64] + + @pytest.fixture(name="window_1") -def fixture_window_1() -> ( - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64], npt.NDArray[np.float64]] -): - """Generate a Window object with 100 ells.""" +def fixture_window_1() -> HarmonicWindowFunction: + """Generate a harmonic window with 100 ells and four bands. + + :returns: The ell grid, weight matrix, and band labels for the window. + """ ells = np.array(np.linspace(0, 100, 100), dtype=np.int64) weights = np.ones(400).reshape(-1, 4) - window_ells = np.array([0, 1, 2, 3], dtype=np.float64) + band_labels = np.array([0, 1, 2, 3], dtype=np.float64) - return ells, weights, window_ells + return HarmonicWindowFunction( + ell_grid=ells, + weights=weights, + band_labels=band_labels, + ) @pytest.fixture(name="harmonic_two_point_xy") @@ -431,17 +458,20 @@ def fixture_real_two_point_xy( @pytest.fixture(name="two_point_cwindow") def fixture_two_point_cwindow( - window_1: tuple[ - npt.NDArray[np.int64], npt.NDArray[np.float64], npt.NDArray[np.float64] - ], + window_1: HarmonicWindowFunction, harmonic_two_point_xy: TwoPointXY, ) -> TwoPointHarmonic: - """Generate a TwoPointXY object with 100 ells.""" + """Generate a TwoPointHarmonic with 100 ells and four bands. + + :param window_1: Harmonic window supplying the ell grid, weights, and labels. + :param harmonic_two_point_xy: Harmonic TwoPointXY metadata for the measurement. + :returns: A TwoPointHarmonic carrying the windowed ell grid. + """ two_point = TwoPointHarmonic( XY=harmonic_two_point_xy, - ells=window_1[0], - window=window_1[1], - window_ells=window_1[2], + ells=window_1.ell_grid, + window=window_1.weights, + window_ells=window_1.band_labels, ) return two_point @@ -591,8 +621,11 @@ def fixture_cluster_sacc_data() -> sacc.Sacc: @pytest.fixture(name="sacc_galaxy_cells_src0_src0", scope="module") -def fixture_sacc_galaxy_cells_src0_src0() -> tuple[sacc.Sacc, TomographicBin]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_cells_src0_src0() -> SaccGalaxyHarmonicFixture: + """Build unwindowed source-source SACC data and named expectations. + + :returns: SACC data, the copied source distribution, and its synthetic spectrum. + """ sacc_data = sacc.Sacc() z = np.linspace(0, 1.0, 256) + 0.05 @@ -601,39 +634,41 @@ def fixture_sacc_galaxy_cells_src0_src0() -> tuple[sacc.Sacc, TomographicBin]: dndz = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src0", z, dndz) - Cells = np.random.normal(size=ells.shape[0]) + Cells: npt.NDArray[np.float64] = np.asarray(np.random.normal(size=ells.shape[0])) sacc_data.add_ell_cl("galaxy_shear_cl_ee", "src0", "src0", ells, Cells) cov = np.diag(np.ones_like(Cells) * 0.01) sacc_data.add_covariance(cov) - expected_bin = TomographicBin( - bin_name="src0", - z=z.copy(), - dndz=dndz.copy(), - measurements={Galaxies.SHEAR_E}, + return SaccGalaxyHarmonicFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z.copy(), dndz=dndz.copy()) + }, + spectra={ + (TracerNames("src0", "src0"), "galaxy_shear_cl_ee"): ( + HarmonicAngularPowerSpectrum(ells=ells, cells=Cells) + ) + }, ) - return sacc_data, expected_bin @pytest.fixture(name="sacc_galaxy_cells_src0_src1", scope="module") -def fixture_sacc_galaxy_cells_src0_src1() -> tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], -]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_cells_src0_src1() -> SaccHarmonicCrossBinFixture: + """Build source-source harmonic data and named redshift expectations. - z = np.linspace(0, 1.0, 256) + 0.05 + :returns: SACC data and src0/src1 distributions sharing the redshift grid. + """ + + z: npt.NDArray[np.float64] = np.linspace(0, 1.0, 256) + 0.05 ells = np.unique(np.logspace(1, 3, 10).astype(np.int64)) sacc_data = sacc.Sacc() - dndz0 = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) + dndz0: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src0", z, dndz0) - dndz1 = np.exp(-0.5 * (z - 0.7) ** 2 / 0.05 / 0.05) + dndz1: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.7) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src1", z, dndz1) Cells = np.random.normal(size=ells.shape[0]) @@ -642,12 +677,21 @@ def fixture_sacc_galaxy_cells_src0_src1() -> tuple[ cov = np.diag(np.ones_like(Cells) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, dndz0, dndz1 + return SaccHarmonicCrossBinFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z, dndz=dndz0), + "src1": SampledRedshiftDistribution(z=z, dndz=dndz1), + }, + ) @pytest.fixture(name="sacc_galaxy_cells_lens0_lens0", scope="module") -def fixture_sacc_galaxy_cells_lens0_lens0() -> tuple[sacc.Sacc, TomographicBin]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_cells_lens0_lens0() -> SaccGalaxyHarmonicFixture: + """Build unwindowed lens-lens SACC data and named expectations. + + :returns: SACC data, the copied lens distribution, and its synthetic spectrum. + """ sacc_data = sacc.Sacc() z = np.linspace(0, 1.0, 256) + 0.05 @@ -656,37 +700,39 @@ def fixture_sacc_galaxy_cells_lens0_lens0() -> tuple[sacc.Sacc, TomographicBin]: dndz = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz) - Cells = np.random.normal(size=ells.shape[0]) + Cells: npt.NDArray[np.float64] = np.asarray(np.random.normal(size=ells.shape[0])) sacc_data.add_ell_cl("galaxy_density_cl", "lens0", "lens0", ells, Cells) cov = np.diag(np.ones_like(Cells) * 0.01) sacc_data.add_covariance(cov) - expected_bin = TomographicBin( - bin_name="lens0", - z=z.copy(), - dndz=dndz.copy(), - measurements={Galaxies.COUNTS}, + return SaccGalaxyHarmonicFixture( + sacc_data=sacc_data, + distributions={ + "lens0": SampledRedshiftDistribution(z=z.copy(), dndz=dndz.copy()) + }, + spectra={ + (TracerNames("lens0", "lens0"), "galaxy_density_cl"): ( + HarmonicAngularPowerSpectrum(ells=ells, cells=Cells) + ) + }, ) - return sacc_data, expected_bin @pytest.fixture(name="sacc_galaxy_cells_lens0_lens1") -def fixture_sacc_galaxy_cells_lens0_lens1() -> tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], -]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_cells_lens0_lens1() -> SaccHarmonicCrossBinFixture: + """Build lens-lens harmonic data and named redshift expectations. + + :returns: SACC data and lens0/lens1 distributions sharing the redshift grid. + """ sacc_data = sacc.Sacc() - z = np.linspace(0, 1.0, 256) + 0.05 + z: npt.NDArray[np.float64] = np.linspace(0, 1.0, 256) + 0.05 ells = np.unique(np.logspace(1, 3, 10).astype(np.int64)) - dndz0 = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) + dndz0: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz0) - dndz1 = np.exp(-0.5 * (z - 0.6) ** 2 / 0.05 / 0.05) + dndz1: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.6) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens1", z, dndz1) Cells = np.random.normal(size=ells.shape[0]) @@ -695,12 +741,21 @@ def fixture_sacc_galaxy_cells_lens0_lens1() -> tuple[ cov = np.diag(np.ones_like(Cells) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, dndz0, dndz1 + return SaccHarmonicCrossBinFixture( + sacc_data=sacc_data, + distributions={ + "lens0": SampledRedshiftDistribution(z=z, dndz=dndz0), + "lens1": SampledRedshiftDistribution(z=z, dndz=dndz1), + }, + ) @pytest.fixture(name="sacc_galaxy_xis_lens0_lens0") -def fixture_sacc_galaxy_xis_lens0_lens0() -> tuple[sacc.Sacc, TomographicBin]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_xis_lens0_lens0() -> SaccGalaxyRealFixture: + """Build unwindowed lens-lens real SACC data and named expectations. + + :returns: SACC data, the copied lens distribution, and its synthetic correlation. + """ sacc_data = sacc.Sacc() z = np.linspace(0, 1.0, 256) + 0.05 @@ -709,37 +764,39 @@ def fixture_sacc_galaxy_xis_lens0_lens0() -> tuple[sacc.Sacc, TomographicBin]: dndz = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz) - xis = np.random.normal(size=thetas.shape[0]) + xis: npt.NDArray[np.float64] = np.asarray(np.random.normal(size=thetas.shape[0])) sacc_data.add_theta_xi("galaxy_density_xi", "lens0", "lens0", thetas, xis) cov = np.diag(np.ones_like(xis) * 0.01) sacc_data.add_covariance(cov) - expected_bin = TomographicBin( - bin_name="lens0", - z=z.copy(), - dndz=dndz.copy(), - measurements={Galaxies.COUNTS}, + return SaccGalaxyRealFixture( + sacc_data=sacc_data, + distributions={ + "lens0": SampledRedshiftDistribution(z=z.copy(), dndz=dndz.copy()) + }, + spectra={ + (TracerNames("lens0", "lens0"), "galaxy_density_xi"): ( + RealAngularCorrelation(thetas=thetas, xis=xis) + ) + }, ) - return sacc_data, expected_bin @pytest.fixture(name="sacc_galaxy_xis_lens0_lens1") -def fixture_sacc_galaxy_xis_lens0_lens1() -> tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], -]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_xis_lens0_lens1() -> SaccRealCrossBinFixture: + """Build lens-lens real data and named redshift expectations. + + :returns: SACC data and lens0/lens1 distributions sharing the redshift grid. + """ sacc_data = sacc.Sacc() - z = np.linspace(0, 1.0, 256) + 0.05 + z: npt.NDArray[np.float64] = np.linspace(0, 1.0, 256) + 0.05 thetas = np.linspace(0.0, 2.0 * np.pi, 20) - dndz0 = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) + dndz0: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz0) - dndz1 = np.exp(-0.5 * (z - 0.6) ** 2 / 0.05 / 0.05) + dndz1: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.6) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens1", z, dndz1) xis = np.random.normal(size=thetas.shape[0]) @@ -748,26 +805,30 @@ def fixture_sacc_galaxy_xis_lens0_lens1() -> tuple[ cov = np.diag(np.ones_like(xis) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, dndz0, dndz1 + return SaccRealCrossBinFixture( + sacc_data=sacc_data, + distributions={ + "lens0": SampledRedshiftDistribution(z=z, dndz=dndz0), + "lens1": SampledRedshiftDistribution(z=z, dndz=dndz1), + }, + ) @pytest.fixture(name="sacc_galaxy_cells_src0_lens0") -def fixture_sacc_galaxy_cells_src0_lens0() -> tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], -]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_cells_src0_lens0() -> SaccHarmonicCrossBinFixture: + """Build source-lens harmonic data and named redshift expectations. + + :returns: SACC data and src0/lens0 distributions sharing the redshift grid. + """ sacc_data = sacc.Sacc() - z = np.linspace(0, 1.0, 256) + 0.05 + z: npt.NDArray[np.float64] = np.linspace(0, 1.0, 256) + 0.05 ells = np.unique(np.logspace(1, 3, 10).astype(np.int64)) - dndz0 = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) + dndz0: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src0", z, dndz0) - dndz1 = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) + dndz1: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz1) Cells = np.random.normal(size=ells.shape[0]) @@ -776,26 +837,30 @@ def fixture_sacc_galaxy_cells_src0_lens0() -> tuple[ cov = np.diag(np.ones_like(Cells) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, dndz0, dndz1 + return SaccHarmonicCrossBinFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z, dndz=dndz0), + "lens0": SampledRedshiftDistribution(z=z, dndz=dndz1), + }, + ) @pytest.fixture(name="sacc_galaxy_xis_src0_lens0") -def fixture_sacc_galaxy_xis_src0_lens0() -> tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], -]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_xis_src0_lens0() -> SaccRealCrossBinFixture: + """Build source-lens real data and named redshift expectations. + + :returns: SACC data and src0/lens0 distributions sharing the redshift grid. + """ sacc_data = sacc.Sacc() - z = np.linspace(0, 1.0, 256) + 0.05 + z: npt.NDArray[np.float64] = np.linspace(0, 1.0, 256) + 0.05 thetas = np.linspace(0.0, 2.0 * np.pi, 20) - dndz0 = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) + dndz0: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src0", z, dndz0) - dndz1 = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) + dndz1: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz1) xis = np.random.normal(size=thetas.shape[0]) @@ -804,21 +869,24 @@ def fixture_sacc_galaxy_xis_src0_lens0() -> tuple[ cov = np.diag(np.ones_like(xis) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, dndz0, dndz1 + return SaccRealCrossBinFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z, dndz=dndz0), + "lens0": SampledRedshiftDistribution(z=z, dndz=dndz1), + }, + ) @pytest.fixture(name="sacc_galaxy_cells", scope="module") -def fixture_sacc_galaxy_cells() -> tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]] - ], -]: - """Fixture for a SACC data without window functions. +def fixture_sacc_galaxy_cells() -> SaccGalaxyHarmonicFixture: + """Build unwindowed harmonic SACC data and named expectations. + + Module-scoped because SACC objects are expensive to create. Consumers must + copy SACC before mutation; expected grids remain shared between records. - Module-scoped because SACC objects are expensive to create and are - read-only in tests. + :returns: SACC data, sampled redshift distributions by tracer name, and + measured cells by ordered tracer pair and data type. """ sacc_data = sacc.Sacc() @@ -828,29 +896,26 @@ def fixture_sacc_galaxy_cells() -> tuple[ src_bins_centers = np.linspace(0.25, 0.75, 5) lens_bins_centers = np.linspace(0.1, 0.6, 5) - tracers: dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]] = {} - tracer_pairs: dict[ - tuple[TracerNames, str], tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]] - ] = {} + tracers: dict[str, SampledRedshiftDistribution] = {} + tracer_pairs: dict[tuple[TracerNames, str], HarmonicAngularPowerSpectrum] = {} for i, mn in enumerate(src_bins_centers): - dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) + dndz: npt.NDArray[np.float64] = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", f"src{i}", z, dndz) - tracers[f"src{i}"] = (z, dndz) + tracers[f"src{i}"] = SampledRedshiftDistribution(z=z, dndz=dndz) for i, mn in enumerate(lens_bins_centers): dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", f"lens{i}", z, dndz) - tracers[f"lens{i}"] = (z, dndz) + tracers[f"lens{i}"] = SampledRedshiftDistribution(z=z, dndz=dndz) dv = [] for i, j in upper_triangle_indices(len(src_bins_centers)): - Cells = np.array(np.random.normal(size=ells.shape[0])) + Cells: npt.NDArray[np.float64] = np.array(np.random.normal(size=ells.shape[0])) sacc_data.add_ell_cl("galaxy_shear_cl_ee", f"src{i}", f"src{j}", ells, Cells) tracer_pairs[(TracerNames(f"src{i}", f"src{j}"), "galaxy_shear_cl_ee")] = ( - ells, - Cells, + HarmonicAngularPowerSpectrum(ells=ells, cells=Cells) ) dv.append(Cells) @@ -858,8 +923,7 @@ def fixture_sacc_galaxy_cells() -> tuple[ Cells = np.array(np.random.normal(size=ells.shape[0])) sacc_data.add_ell_cl("galaxy_density_cl", f"lens{i}", f"lens{j}", ells, Cells) tracer_pairs[(TracerNames(f"lens{i}", f"lens{j}"), "galaxy_density_cl")] = ( - ells, - Cells, + HarmonicAngularPowerSpectrum(ells=ells, cells=Cells) ) dv.append(Cells) @@ -870,10 +934,7 @@ def fixture_sacc_galaxy_cells() -> tuple[ ) tracer_pairs[ (TracerNames(f"src{i}", f"lens{j}"), "galaxy_shearDensity_cl_e") - ] = ( - ells, - Cells, - ) + ] = HarmonicAngularPowerSpectrum(ells=ells, cells=Cells) dv.append(Cells) delta_v = np.concatenate(dv, axis=0) @@ -881,15 +942,22 @@ def fixture_sacc_galaxy_cells() -> tuple[ sacc_data.add_covariance(cov) - return sacc_data, tracers, tracer_pairs + return SaccGalaxyHarmonicFixture( + sacc_data=sacc_data, distributions=tracers, spectra=tracer_pairs + ) @pytest.fixture(name="sacc_galaxy_cwindows", scope="module") def fixture_sacc_galaxy_cwindows() -> SaccGalaxyWindowedFixture: - """Fixture for a SACC data with window functions. + """Build windowed SACC data and named expectations. + + Module-scoped because SACC objects are expensive to create. Expected grids + remain shared between records, and windows are shared with SACC data points. + Ten support multipoles yield five measured bandpowers; SACC observation + labels are unnormalized weighted sums of the support multipoles. - Module-scoped because SACC objects are expensive to create and are - read-only in tests. + :returns: SACC data, sampled redshift distributions by tracer name, and + windowed spectra by ordered tracer pair and data type. """ sacc_data = sacc.Sacc() @@ -900,18 +968,18 @@ def fixture_sacc_galaxy_cwindows() -> SaccGalaxyWindowedFixture: src_bins_centers = np.linspace(0.25, 0.75, 5) lens_bins_centers = np.linspace(0.1, 0.6, 5) - tracers: dict[str, RedshiftDistribution] = {} + tracers: dict[str, SampledRedshiftDistribution] = {} tracer_pairs: dict[tuple[TracerNames, str], WindowedAngularPowerSpectrum] = {} for i, mn in enumerate(src_bins_centers): - dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) + dndz: npt.NDArray[np.float64] = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", f"src{i}", z, dndz) - tracers[f"src{i}"] = (z, dndz) + tracers[f"src{i}"] = SampledRedshiftDistribution(z=z, dndz=dndz) for i, mn in enumerate(lens_bins_centers): dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", f"lens{i}", z, dndz) - tracers[f"lens{i}"] = (z, dndz) + tracers[f"lens{i}"] = SampledRedshiftDistribution(z=z, dndz=dndz) for i, j in upper_triangle_indices(len(src_bins_centers)): weights = ( @@ -920,7 +988,7 @@ def fixture_sacc_galaxy_cwindows() -> SaccGalaxyWindowedFixture: + np.eye(ells.shape[0], nobs, k=-5, dtype=np.float64) ) window = sacc.BandpowerWindow(ells, weights) - Cells = np.random.normal(size=nobs) + Cells: npt.NDArray[np.float64] = np.random.normal(size=nobs) sacc_data.add_ell_cl( "galaxy_shear_cl_ee", f"src{i}", @@ -930,9 +998,9 @@ def fixture_sacc_galaxy_cwindows() -> SaccGalaxyWindowedFixture: window=window, ) tracer_pairs[(TracerNames(f"src{i}", f"src{j}"), "galaxy_shear_cl_ee")] = ( - ells, - Cells, - window, + WindowedAngularPowerSpectrum( + support_ells=ells, bandpowers=Cells, window=window + ) ) for i, j in upper_triangle_indices(len(lens_bins_centers)): @@ -952,9 +1020,9 @@ def fixture_sacc_galaxy_cwindows() -> SaccGalaxyWindowedFixture: window=window, ) tracer_pairs[(TracerNames(f"lens{i}", f"lens{j}"), "galaxy_density_cl")] = ( - ells, - Cells, - window, + WindowedAngularPowerSpectrum( + support_ells=ells, bandpowers=Cells, window=window + ) ) for i, j in product(range(len(src_bins_centers)), range(len(lens_bins_centers))): @@ -975,30 +1043,26 @@ def fixture_sacc_galaxy_cwindows() -> SaccGalaxyWindowedFixture: ) tracer_pairs[ (TracerNames(f"src{i}", f"lens{j}"), "galaxy_shearDensity_cl_e") - ] = ( - ells, - Cells, - window, + ] = WindowedAngularPowerSpectrum( + support_ells=ells, bandpowers=Cells, window=window ) sacc_data.add_covariance(np.identity(len(sacc_data)) * 0.01) - return sacc_data, tracers, tracer_pairs + return SaccGalaxyWindowedFixture( + sacc_data=sacc_data, distributions=tracers, spectra=tracer_pairs + ) @pytest.fixture(name="sacc_galaxy_xis", scope="module") -def fixture_sacc_galaxy_xis() -> tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], -]: - """Fixture for a SACC data without window functions. +def fixture_sacc_galaxy_xis() -> SaccGalaxyRealFixture: + """Build unwindowed real SACC data and named expectations. + + Module-scoped because SACC objects are expensive to create. Consumers must + copy SACC before mutation; expected grids remain shared between records. - Module-scoped because SACC objects are expensive to create and are - read-only in tests. + :returns: SACC data, sampled redshift distributions by tracer name, and + measured xis by ordered tracer pair and data type. """ z = (np.linspace(0, 1.0, 256) + 0.05).astype(np.float64) @@ -1009,29 +1073,26 @@ def fixture_sacc_galaxy_xis() -> tuple[ src_bins_centers = np.linspace(0.25, 0.75, 5) lens_bins_centers = np.linspace(0.1, 0.6, 5) - tracers: dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]] = {} - tracer_pairs: dict[ - tuple[TracerNames, str], tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]] - ] = {} + tracers: dict[str, SampledRedshiftDistribution] = {} + tracer_pairs: dict[tuple[TracerNames, str], RealAngularCorrelation] = {} for i, mn in enumerate(src_bins_centers): - dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) + dndz: npt.NDArray[np.float64] = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", f"src{i}", z, dndz) - tracers[f"src{i}"] = (z, dndz) + tracers[f"src{i}"] = SampledRedshiftDistribution(z=z, dndz=dndz) for i, mn in enumerate(lens_bins_centers): dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", f"lens{i}", z, dndz) - tracers[f"lens{i}"] = (z, dndz) + tracers[f"lens{i}"] = SampledRedshiftDistribution(z=z, dndz=dndz) dv = [] for i, j in upper_triangle_indices(len(lens_bins_centers)): - xis = np.array(np.random.normal(size=thetas.shape[0])) + xis: npt.NDArray[np.float64] = np.array(np.random.normal(size=thetas.shape[0])) sacc_data.add_theta_xi("galaxy_density_xi", f"lens{i}", f"lens{j}", thetas, xis) tracer_pairs[(TracerNames(f"lens{i}", f"lens{j}"), "galaxy_density_xi")] = ( - thetas, - xis, + RealAngularCorrelation(thetas=thetas, xis=xis) ) dv.append(xis) @@ -1042,10 +1103,7 @@ def fixture_sacc_galaxy_xis() -> tuple[ ) tracer_pairs[ (TracerNames(f"src{i}", f"lens{j}"), "galaxy_shearDensity_xi_t") - ] = ( - thetas, - xis, - ) + ] = RealAngularCorrelation(thetas=thetas, xis=xis) dv.append(xis) for i, j in upper_triangle_indices(len(src_bins_centers)): @@ -1054,8 +1112,7 @@ def fixture_sacc_galaxy_xis() -> tuple[ "galaxy_shear_xi_minus", f"src{i}", f"src{j}", thetas, xis ) tracer_pairs[(TracerNames(f"src{i}", f"src{j}"), "galaxy_shear_xi_minus")] = ( - thetas, - xis, + RealAngularCorrelation(thetas=thetas, xis=xis) ) dv.append(xis) for i, j in upper_triangle_indices(len(src_bins_centers)): @@ -1064,8 +1121,7 @@ def fixture_sacc_galaxy_xis() -> tuple[ "galaxy_shear_xi_plus", f"src{i}", f"src{j}", thetas, xis ) tracer_pairs[(TracerNames(f"src{i}", f"src{j}"), "galaxy_shear_xi_plus")] = ( - thetas, - xis, + RealAngularCorrelation(thetas=thetas, xis=xis) ) dv.append(xis) @@ -1074,19 +1130,21 @@ def fixture_sacc_galaxy_xis() -> tuple[ sacc_data.add_covariance(cov) - return sacc_data, tracers, tracer_pairs + return SaccGalaxyRealFixture( + sacc_data=sacc_data, distributions=tracers, spectra=tracer_pairs + ) @pytest.fixture(name="sacc_galaxy_xis_inverted") -def fixture_sacc_galaxy_xis_inverted() -> tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], -]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_xis_inverted() -> SaccGalaxyRealFixture: + """Build inverted real SACC data and named expectations. + + Preserve the intentionally reversed tracer conventions for correction tests. + Expected grids remain shared between records. + + :returns: SACC data, sampled redshift distributions by tracer name, and + measured xis by the original inverted tracer-pair and data-type keys. + """ z = (np.linspace(0, 1.0, 256) + 0.05).astype(np.float64) thetas = np.linspace(0.0, 2.0 * np.pi, 20, dtype=np.float64) @@ -1096,29 +1154,26 @@ def fixture_sacc_galaxy_xis_inverted() -> tuple[ src_bins_centers = np.linspace(0.25, 0.75, 5) lens_bins_centers = np.linspace(0.1, 0.6, 5) - tracers: dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]] = {} - tracer_pairs: dict[ - tuple[TracerNames, str], tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]] - ] = {} + tracers: dict[str, SampledRedshiftDistribution] = {} + tracer_pairs: dict[tuple[TracerNames, str], RealAngularCorrelation] = {} for i, mn in enumerate(src_bins_centers): - dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) + dndz: npt.NDArray[np.float64] = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", f"src{i}", z, dndz) - tracers[f"src{i}"] = (z, dndz) + tracers[f"src{i}"] = SampledRedshiftDistribution(z=z, dndz=dndz) for i, mn in enumerate(lens_bins_centers): dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", f"lens{i}", z, dndz) - tracers[f"lens{i}"] = (z, dndz) + tracers[f"lens{i}"] = SampledRedshiftDistribution(z=z, dndz=dndz) dv = [] for i, j in upper_triangle_indices(len(lens_bins_centers)): - xis = np.array(np.random.normal(size=thetas.shape[0])) + xis: npt.NDArray[np.float64] = np.array(np.random.normal(size=thetas.shape[0])) sacc_data.add_theta_xi("galaxy_density_xi", f"lens{j}", f"lens{i}", thetas, xis) tracer_pairs[(TracerNames(f"lens{j}", f"lens{i}"), "galaxy_density_xi")] = ( - thetas, - xis, + RealAngularCorrelation(thetas=thetas, xis=xis) ) dv.append(xis) @@ -1129,10 +1184,7 @@ def fixture_sacc_galaxy_xis_inverted() -> tuple[ ) tracer_pairs[ (TracerNames(f"lens{j}", f"src{i}"), "galaxy_shearDensity_xi_t") - ] = ( - thetas, - xis, - ) + ] = RealAngularCorrelation(thetas=thetas, xis=xis) dv.append(xis) for i, j in upper_triangle_indices(len(src_bins_centers)): @@ -1141,8 +1193,7 @@ def fixture_sacc_galaxy_xis_inverted() -> tuple[ "galaxy_shear_xi_minus", f"src{j}", f"src{i}", thetas, xis ) tracer_pairs[(TracerNames(f"src{j}", f"src{i}"), "galaxy_shear_xi_minus")] = ( - thetas, - xis, + RealAngularCorrelation(thetas=thetas, xis=xis) ) dv.append(xis) for i, j in upper_triangle_indices(len(src_bins_centers)): @@ -1151,8 +1202,7 @@ def fixture_sacc_galaxy_xis_inverted() -> tuple[ "galaxy_shear_xi_plus", f"src{j}", f"src{i}", thetas, xis ) tracer_pairs[(TracerNames(f"src{j}", f"src{i}"), "galaxy_shear_xi_plus")] = ( - thetas, - xis, + RealAngularCorrelation(thetas=thetas, xis=xis) ) dv.append(xis) @@ -1161,7 +1211,9 @@ def fixture_sacc_galaxy_xis_inverted() -> tuple[ sacc_data.add_covariance(cov) - return sacc_data, tracers, tracer_pairs + return SaccGalaxyRealFixture( + sacc_data=sacc_data, distributions=tracers, spectra=tracer_pairs + ) @pytest.fixture(name="sacc_galaxy_cells_order_convention") @@ -1185,8 +1237,11 @@ def fixture_sacc_galaxy_cells_order_convention() -> sacc.Sacc: @pytest.fixture(name="sacc_galaxy_cells_src0_src0_no_data") -def fixture_sacc_galaxy_cells_src0_src0_no_data() -> tuple[sacc.Sacc, TomographicBin]: - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_cells_src0_src0_no_data() -> SaccGalaxyDistributionFixture: + """Build source SACC tracer data without two-point observations. + + :returns: SACC data and the copied source distribution. + """ sacc_data = sacc.Sacc() z = np.linspace(0, 1.0, 256) + 0.05 @@ -1194,13 +1249,12 @@ def fixture_sacc_galaxy_cells_src0_src0_no_data() -> tuple[sacc.Sacc, Tomographi dndz = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src0", z, dndz) - expected_bin = TomographicBin( - bin_name="src0", - z=z.copy(), - dndz=dndz.copy(), - measurements={Galaxies.SHEAR_E}, + return SaccGalaxyDistributionFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z.copy(), dndz=dndz.copy()) + }, ) - return sacc_data, expected_bin @pytest.fixture(name="sacc_galaxy_lens0_no_two_point_data") @@ -1225,8 +1279,11 @@ def fixture_sacc_galaxy_lens0_no_two_point_data() -> sacc.Sacc: @pytest.fixture(name="sacc_galaxy_cells_src0_src0_window") -def fixture_sacc_galaxy_cells_src0_src0_window() -> tuple[sacc.Sacc, TomographicBin]: - """Fixture for a SACC data with a window function.""" +def fixture_sacc_galaxy_cells_src0_src0_window() -> SaccGalaxyWindowedFixture: + """Build windowed source-source SACC data and named expectations. + + :returns: SACC data, the copied source distribution, and its synthetic bandpowers. + """ sacc_data = sacc.Sacc() z = np.linspace(0, 1.0, 256) + 0.05 @@ -1238,7 +1295,7 @@ def fixture_sacc_galaxy_cells_src0_src0_window() -> tuple[sacc.Sacc, Tomographic # Making a diagonal window function window = sacc.BandpowerWindow(ells, np.diag(np.ones_like(ells))) - Cells = np.random.normal(size=ells.shape[0]) + Cells: npt.NDArray[np.float64] = np.asarray(np.random.normal(size=ells.shape[0])) sacc_data.add_ell_cl( "galaxy_shear_cl_ee", "src0", "src0", ells, Cells, window=window ) @@ -1246,18 +1303,27 @@ def fixture_sacc_galaxy_cells_src0_src0_window() -> tuple[sacc.Sacc, Tomographic cov = np.diag(np.ones_like(Cells) * 0.01) sacc_data.add_covariance(cov) - expected_bin = TomographicBin( - bin_name="src0", - z=z.copy(), - dndz=dndz.copy(), - measurements={Galaxies.SHEAR_E}, + return SaccGalaxyWindowedFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z.copy(), dndz=dndz.copy()) + }, + spectra={ + (TracerNames("src0", "src0"), "galaxy_shear_cl_ee"): ( + WindowedAngularPowerSpectrum( + support_ells=ells, bandpowers=Cells, window=window + ) + ) + }, ) - return sacc_data, expected_bin @pytest.fixture(name="sacc_galaxy_cells_src0_src0_no_window") -def fixture_sacc_galaxy_cells_src0_src0_no_window() -> tuple[sacc.Sacc, TomographicBin]: - """Fixture for a SACC data without a window function.""" +def fixture_sacc_galaxy_cells_src0_src0_no_window() -> SaccGalaxyHarmonicFixture: + """Build unwindowed source-source SACC data and named expectations. + + :returns: SACC data, the copied source distribution, and its synthetic spectrum. + """ sacc_data = sacc.Sacc() z = np.linspace(0, 1.0, 256) + 0.05 @@ -1272,20 +1338,25 @@ def fixture_sacc_galaxy_cells_src0_src0_no_window() -> tuple[sacc.Sacc, Tomograp cov = np.diag(np.ones_like(Cells) * 0.01) sacc_data.add_covariance(cov) - expected_bin = TomographicBin( - bin_name="src0", - z=z.copy(), - dndz=dndz.copy(), - measurements={Galaxies.SHEAR_E}, + return SaccGalaxyHarmonicFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z.copy(), dndz=dndz.copy()) + }, + spectra={ + (TracerNames("src0", "src0"), "galaxy_shear_cl_ee"): ( + HarmonicAngularPowerSpectrum(ells=ells, cells=Cells) + ) + }, ) - return sacc_data, expected_bin @pytest.fixture(name="sacc_galaxy_xis_lens0_lens0_real") -def fixture_sacc_galaxy_xis_lens0_lens0_real() -> ( - tuple[sacc.Sacc, np.ndarray, np.ndarray] -): - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_xis_lens0_lens0_real() -> SaccGalaxyRealFixture: + """Build unwindowed lens-lens real SACC data and named expectations. + + :returns: SACC data, the lens distribution, and its synthetic correlation. + """ sacc_data = sacc.Sacc() z = np.linspace(0, 1.0, 256) + 0.05 @@ -1294,13 +1365,21 @@ def fixture_sacc_galaxy_xis_lens0_lens0_real() -> ( dndz = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz) - xis = np.random.normal(size=thetas.shape[0]) + xis: npt.NDArray[np.float64] = np.asarray(np.random.normal(size=thetas.shape[0])) sacc_data.add_theta_xi("galaxy_density_xi", "lens0", "lens0", thetas, xis) cov = np.diag(np.ones_like(xis) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, thetas + return SaccGalaxyRealFixture( + sacc_data=sacc_data, + distributions={"lens0": SampledRedshiftDistribution(z=z, dndz=dndz)}, + spectra={ + (TracerNames("lens0", "lens0"), "galaxy_density_xi"): ( + RealAngularCorrelation(thetas=thetas, xis=xis) + ) + }, + ) @pytest.fixture(name="wl_factory") @@ -1531,20 +1610,22 @@ def fixture_optimized_harmonic_two_point_xy( # Optimized versions of dependent fixtures @pytest.fixture(name="optimized_two_point_cwindow") def fixture_optimized_two_point_cwindow( - window_1: tuple[ - npt.NDArray[np.int64], npt.NDArray[np.float64], npt.NDArray[np.float64] - ], + window_1: HarmonicWindowFunction, optimized_harmonic_two_point_xy: TwoPointXY, ) -> TwoPointHarmonic: - """Generate a TwoPointXY object with zero skipped tests. + """Generate a TwoPointHarmonic using compatible measurement pairs. Uses optimized fixtures that pre-filter for valid measurement pairs. + + :param window_1: Harmonic window supplying the ell grid, weights, and labels. + :param optimized_harmonic_two_point_xy: Pre-filtered harmonic TwoPointXY metadata. + :returns: A TwoPointHarmonic carrying the windowed ell grid. """ two_point = TwoPointHarmonic( XY=optimized_harmonic_two_point_xy, - ells=window_1[0], - window=window_1[1], - window_ells=window_1[2], + ells=window_1.ell_grid, + window=window_1.weights, + window_ells=window_1.band_labels, ) return two_point diff --git a/tests/likelihood/gauss_family/statistic/source/test_source.py b/tests/likelihood/gauss_family/statistic/source/test_source.py index 624f5b64b..a7a196720 100644 --- a/tests/likelihood/gauss_family/statistic/source/test_source.py +++ b/tests/likelihood/gauss_family/statistic/source/test_source.py @@ -30,9 +30,9 @@ from firecrown.likelihood.number_counts._args import NumberCountsArgs from firecrown.likelihood.weak_lensing import WeakLensingArgs from firecrown.metadata_functions import extract_all_tracers_tomographic_bins -from firecrown.metadata_types import TomographicBin from firecrown.modeling_tools import ModelingTools from firecrown.updatable import ParamsMap, get_default_params +from tests._types import SaccGalaxyHarmonicFixture @pytest.fixture( @@ -188,16 +188,17 @@ def test_trivial_source_select_field() -> None: def test_weak_lensing_source_init( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, tools_with_vanilla_cosmology: ModelingTools, ) -> None: - sacc_data, expected_bin = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data + expected_distribution = sacc_galaxy_cells_src0_src0.distributions["src0"] source = wl.WeakLensing(sacc_tracer="src0") source.read(sacc_data) - assert_allclose(source.tracer_args.z, expected_bin.z) - assert_allclose(source.tracer_args.dndz, expected_bin.dndz) + assert_allclose(source.tracer_args.z, expected_distribution.z) + assert_allclose(source.tracer_args.dndz, expected_distribution.dndz) source.update(ParamsMap()) ts = source.get_tracers(tools_with_vanilla_cosmology) assert len(ts) == 1 @@ -207,9 +208,9 @@ def test_weak_lensing_source_init( def test_weak_lensing_source_create_ready( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data all_tracers = extract_all_tracers_tomographic_bins(sacc_data) src0 = next((obj for obj in all_tracers if obj.bin_name == "src0"), None) @@ -225,9 +226,9 @@ def test_weak_lensing_source_create_ready( def test_weak_lensing_source_factory( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data all_tracers = extract_all_tracers_tomographic_bins(sacc_data) src0 = next((obj for obj in all_tracers if obj.bin_name == "src0"), None) @@ -244,9 +245,9 @@ def test_weak_lensing_source_factory( def test_weak_lensing_source_factory_cache( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data all_tracers = extract_all_tracers_tomographic_bins(sacc_data) src0 = next((obj for obj in all_tracers if obj.bin_name == "src0"), None) @@ -260,10 +261,10 @@ def test_weak_lensing_source_factory_cache( @pytest.mark.parametrize("include_z_dependence", [True, False]) def test_weak_lensing_source_factory_global_systematics( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, include_z_dependence: bool, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data all_tracers = extract_all_tracers_tomographic_bins(sacc_data) src0 = next((obj for obj in all_tracers if obj.bin_name == "src0"), None) @@ -293,9 +294,9 @@ def test_weak_lensing_source_factory_global_systematics( def test_weak_lensing_source_init_wrong_name( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data source = wl.WeakLensing(sacc_tracer="src10") with pytest.raises(KeyError, match="src10"): @@ -303,17 +304,18 @@ def test_weak_lensing_source_init_wrong_name( def test_number_counts_source_init( - sacc_galaxy_cells_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_lens0_lens0: SaccGalaxyHarmonicFixture, tools_with_vanilla_cosmology: ModelingTools, ) -> None: - sacc_data, expected_bin = sacc_galaxy_cells_lens0_lens0 + sacc_data = sacc_galaxy_cells_lens0_lens0.sacc_data + expected_distribution = sacc_galaxy_cells_lens0_lens0.distributions["lens0"] source = nc.NumberCounts(sacc_tracer="lens0") source.read(sacc_data) - assert_allclose(source.tracer_args.z, expected_bin.z) - assert_allclose(source.tracer_args.dndz, expected_bin.dndz) + assert_allclose(source.tracer_args.z, expected_distribution.z) + assert_allclose(source.tracer_args.dndz, expected_distribution.dndz) source.update(ParamsMap(lens0_bias=1.1)) dp = source.get_derived_parameters() assert dp is not None @@ -323,9 +325,9 @@ def test_number_counts_source_init( def test_number_counts_source_create_ready( - sacc_galaxy_cells_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_lens0_lens0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_lens0_lens0 + sacc_data = sacc_galaxy_cells_lens0_lens0.sacc_data all_tracers = extract_all_tracers_tomographic_bins(sacc_data) lens0 = next((obj for obj in all_tracers if obj.bin_name == "lens0"), None) @@ -341,9 +343,9 @@ def test_number_counts_source_create_ready( def test_number_counts_source_factory( - sacc_galaxy_cells_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_lens0_lens0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_lens0_lens0 + sacc_data = sacc_galaxy_cells_lens0_lens0.sacc_data all_tracers = extract_all_tracers_tomographic_bins(sacc_data) lens0 = next((obj for obj in all_tracers if obj.bin_name == "lens0"), None) @@ -360,9 +362,9 @@ def test_number_counts_source_factory( def test_number_counts_source_factory_cache( - sacc_galaxy_cells_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_lens0_lens0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_lens0_lens0 + sacc_data = sacc_galaxy_cells_lens0_lens0.sacc_data all_tracers = extract_all_tracers_tomographic_bins(sacc_data) lens0 = next((obj for obj in all_tracers if obj.bin_name == "lens0"), None) @@ -375,9 +377,9 @@ def test_number_counts_source_factory_cache( def test_number_counts_source_factory_global_systematics( - sacc_galaxy_cells_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_lens0_lens0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_lens0_lens0 + sacc_data = sacc_galaxy_cells_lens0_lens0.sacc_data all_tracers = extract_all_tracers_tomographic_bins(sacc_data) lens0 = next((obj for obj in all_tracers if obj.bin_name == "lens0"), None) @@ -403,9 +405,9 @@ def test_number_counts_source_factory_global_systematics( def test_number_counts_source_init_wrong_name( - sacc_galaxy_cells_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_lens0_lens0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_lens0_lens0 + sacc_data = sacc_galaxy_cells_lens0_lens0.sacc_data source = nc.NumberCounts(sacc_tracer="lens10") with pytest.raises(KeyError, match="lens10"): diff --git a/tests/likelihood/gauss_family/statistic/test_two_point.py b/tests/likelihood/gauss_family/statistic/test_two_point.py index d285e4b88..ae7d49891 100644 --- a/tests/likelihood/gauss_family/statistic/test_two_point.py +++ b/tests/likelihood/gauss_family/statistic/test_two_point.py @@ -48,6 +48,12 @@ from firecrown.modeling_tools import ModelingTools from firecrown.models.two_point import TwoPointTheory from firecrown.updatable import ParamsMap, get_default_params_map +from tests._types import ( + SaccGalaxyDistributionFixture, + SaccGalaxyHarmonicFixture, + SaccGalaxyRealFixture, + SaccGalaxyWindowedFixture, +) @pytest.fixture(name="include_rsd", params=[True, False], ids=["rsd", "no_rsd"]) @@ -156,15 +162,15 @@ def test_tracer_names() -> None: def test_two_point_src0_src0_window_parameterized( window_fixture: str, - sacc_galaxy_cells_src0_src0_window: tuple[sacc.Sacc, TomographicBin], - sacc_galaxy_cells_src0_src0_no_window: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0_window: SaccGalaxyWindowedFixture, + sacc_galaxy_cells_src0_src0_no_window: SaccGalaxyHarmonicFixture, ) -> None: """Test TwoPoint theory calculations are repeatable for both window scenarios.""" if window_fixture == "with_window": - sacc_data, _ = sacc_galaxy_cells_src0_src0_window + sacc_data = sacc_galaxy_cells_src0_src0_window.sacc_data expected_window = True else: # no_window - sacc_data, _ = sacc_galaxy_cells_src0_src0_no_window + sacc_data = sacc_galaxy_cells_src0_src0_no_window.sacc_data expected_window = False src0 = WeakLensing(sacc_tracer="src0") @@ -215,11 +221,11 @@ def test_two_point_generate_ell_or_theta() -> None: def test_two_point_src0_src0_no_data_binning( - sacc_galaxy_cells_src0_src0_no_data: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0_no_data: SaccGalaxyDistributionFixture, binning_type: str, ) -> None: """Test TwoPoint with different binning types when no data is present.""" - sacc_data, _ = sacc_galaxy_cells_src0_src0_no_data + sacc_data = sacc_galaxy_cells_src0_src0_no_data.sacc_data src0 = WeakLensing(sacc_tracer="src0") @@ -344,9 +350,9 @@ def test_two_point_theory_construction() -> None: def test_two_point_lens0_lens0_config( - sacc_galaxy_xis_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_xis_lens0_lens0: SaccGalaxyRealFixture, ) -> None: - sacc_data, _ = sacc_galaxy_xis_lens0_lens0 + sacc_data = sacc_galaxy_xis_lens0_lens0.sacc_data src0 = NumberCounts(sacc_tracer="lens0") @@ -378,9 +384,9 @@ def test_two_point_lens0_lens0_config( def test_two_point_src0_src0_no_data_error( - sacc_galaxy_cells_src0_src0_no_data: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0_no_data: SaccGalaxyDistributionFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0_no_data + sacc_data = sacc_galaxy_cells_src0_src0_no_data.sacc_data src0 = WeakLensing(sacc_tracer="src0") @@ -418,9 +424,9 @@ def test_two_point_lens0_lens0_requires_theta_config_without_measurements( def test_two_point_src0_src0_data_and_conf_warn( - sacc_galaxy_cells_src0_src0_window: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0_window: SaccGalaxyWindowedFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0_window + sacc_data = sacc_galaxy_cells_src0_src0_window.sacc_data src0 = WeakLensing(sacc_tracer="src0") @@ -443,9 +449,9 @@ def test_two_point_src0_src0_data_and_conf_warn( def test_two_point_lens0_lens0_data_and_conf_warn( - sacc_galaxy_xis_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_xis_lens0_lens0: SaccGalaxyRealFixture, ) -> None: - sacc_data, _ = sacc_galaxy_xis_lens0_lens0 + sacc_data = sacc_galaxy_xis_lens0_lens0.sacc_data src0 = NumberCounts(sacc_tracer="lens0") @@ -726,12 +732,12 @@ def test_apply_interp_when_serialization_error() -> None: def test_two_point_src0_src0_window_aiw( - sacc_galaxy_cells_src0_src0_window: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0_window: SaccGalaxyWindowedFixture, apply_interp_when: tp.ApplyInterpolationWhen, ) -> None: """This test also makes sure that TwoPoint theory calculations are repeatable.""" - sacc_data, _ = sacc_galaxy_cells_src0_src0_window + sacc_data = sacc_galaxy_cells_src0_src0_window.sacc_data src0 = WeakLensing(sacc_tracer="src0") @@ -760,10 +766,10 @@ def test_two_point_src0_src0_window_aiw( def test_two_point_src0_src0_no_window_aiw( - sacc_galaxy_cells_src0_src0_no_window: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0_no_window: SaccGalaxyHarmonicFixture, apply_interp_when: tp.ApplyInterpolationWhen, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0_no_window + sacc_data = sacc_galaxy_cells_src0_src0_no_window.sacc_data src0 = WeakLensing(sacc_tracer="src0") @@ -794,10 +800,19 @@ def test_two_point_src0_src0_no_window_aiw( def test_two_point_src0_src0_real_aiw( - sacc_galaxy_xis_lens0_lens0_real: tuple[object, ...], + sacc_galaxy_xis_lens0_lens0_real: SaccGalaxyRealFixture, apply_interp_when: tp.ApplyInterpolationWhen, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis_lens0_lens0_real + """Check a real-space lens0-lens0 TwoPoint computes a finite theory vector. + + Reads the SACC data from the real-space fixture and computes the theory + vector. The cell count matches ``ells_for_xi`` only when the REAL + interpolation flag is set. The redshift and angular arrays are unused. + + :param sacc_galaxy_xis_lens0_lens0_real: Real-space SACC fixture. + :param apply_interp_when: When to apply interpolation. + """ + sacc_data = sacc_galaxy_xis_lens0_lens0_real.sacc_data lens0 = WeakLensing(sacc_tracer="lens0") statistic = tp.TwoPoint( diff --git a/tests/likelihood/gauss_family/test_const_gaussian.py b/tests/likelihood/gauss_family/test_const_gaussian.py index 927d7fdb7..1ed671f94 100644 --- a/tests/likelihood/gauss_family/test_const_gaussian.py +++ b/tests/likelihood/gauss_family/test_const_gaussian.py @@ -522,7 +522,12 @@ def test_create_ready( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, _ = sacc_galaxy_cwindows + """Create a ready Gaussian likelihood from extracted windowed measurements. + + :param sacc_galaxy_cwindows: Windowed SACC data for measurement extraction. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data two_point_harmonics = extract_all_harmonic_data(sacc_data) two_points = TwoPoint.from_measurement(two_point_harmonics, tp_factory) @@ -537,7 +542,12 @@ def test_create_ready_wrong_size( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, _ = sacc_galaxy_cwindows + """Reject a covariance too small for the extracted windowed measurements. + + :param sacc_galaxy_cwindows: Windowed SACC data for measurement extraction. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data two_point_harmonics = extract_all_harmonic_data(sacc_data) two_points = TwoPoint.from_measurement(two_point_harmonics, tp_factory) diff --git a/tests/likelihood/gauss_family/test_const_gaussianPM.py b/tests/likelihood/gauss_family/test_const_gaussianPM.py index 39555533e..4892af974 100644 --- a/tests/likelihood/gauss_family/test_const_gaussianPM.py +++ b/tests/likelihood/gauss_family/test_const_gaussianPM.py @@ -583,7 +583,12 @@ def test_create_ready( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, _ = sacc_galaxy_cwindows + """Create a ready point-mass likelihood from extracted windowed measurements. + + :param sacc_galaxy_cwindows: Windowed SACC data for measurement extraction. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data two_point_harmonics = extract_all_harmonic_data(sacc_data) two_points = TwoPoint.from_measurement(two_point_harmonics, tp_factory) @@ -598,7 +603,12 @@ def test_create_ready_wrong_size( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, _ = sacc_galaxy_cwindows + """Reject a covariance too small for the extracted windowed measurements. + + :param sacc_galaxy_cwindows: Windowed SACC data for measurement extraction. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data two_point_harmonics = extract_all_harmonic_data(sacc_data) two_points = TwoPoint.from_measurement(two_point_harmonics, tp_factory) diff --git a/tests/metadata/test_metadata_two_point.py b/tests/metadata/test_metadata_two_point.py index bc08e4958..b5fc7a8e4 100644 --- a/tests/metadata/test_metadata_two_point.py +++ b/tests/metadata/test_metadata_two_point.py @@ -5,7 +5,6 @@ import dataclasses import numpy as np -import numpy.typing as npt import pytest import sacc from numpy.testing import assert_array_equal @@ -46,6 +45,7 @@ from firecrown.metadata_types._sacc_type_string import ( _type_to_sacc_string_real as real, ) +from tests._types import SaccHarmonicCrossBinFixture, SaccRealCrossBinFixture def test_inferred_galaxy_z_dist() -> None: @@ -1135,20 +1135,17 @@ def test_make_two_point_xy_sacc_convention_explanation() -> None: def test_extract_all_real_metadata_indices_no_swap( - sacc_galaxy_xis_src0_lens0: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_xis_src0_lens0: SaccRealCrossBinFixture, ) -> None: """Test extract_all_real_metadata_indices with no tracer swap needed. This test verifies that when tracers are in the correct order according to the SACC convention (measurement type order matches tracer order), no swap is performed. + + :param sacc_galaxy_xis_src0_lens0: Source-lens real SACC data and expectations. """ - sacc_data, _, _, _ = sacc_galaxy_xis_src0_lens0 + sacc_data = sacc_galaxy_xis_src0_lens0.sacc_data indices = extract_all_real_metadata_indices(sacc_data) @@ -1340,20 +1337,17 @@ def test_extract_all_real_metadata_indices_multiple_combinations() -> None: def test_extract_all_harmonic_metadata_indices_no_swap( - sacc_galaxy_cells_src0_lens0: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_cells_src0_lens0: SaccHarmonicCrossBinFixture, ) -> None: """Test extract_all_harmonic_metadata_indices with no tracer swap needed. This test verifies that when tracers are in the correct order according to the SACC convention (measurement type order matches tracer order), no swap is performed. + + :param sacc_galaxy_cells_src0_lens0: Source-lens harmonic SACC expectations. """ - sacc_data, _, _, _ = sacc_galaxy_cells_src0_lens0 + sacc_data = sacc_galaxy_cells_src0_lens0.sacc_data indices = extract_all_harmonic_metadata_indices(sacc_data) diff --git a/tests/metadata/test_metadata_two_point_sacc.py b/tests/metadata/test_metadata_two_point_sacc.py index af69a5412..4bcf10e3b 100644 --- a/tests/metadata/test_metadata_two_point_sacc.py +++ b/tests/metadata/test_metadata_two_point_sacc.py @@ -5,6 +5,7 @@ import re import warnings +from dataclasses import dataclass import numpy as np import numpy.typing as npt @@ -58,16 +59,70 @@ _type_to_sacc_string_real, ) from firecrown.updatable import ParamsMap -from tests._types import SaccGalaxyWindowedFixture +from tests._types import ( + SampledRedshiftDistribution, + SaccGalaxyHarmonicFixture, + SaccGalaxyRealFixture, + SaccGalaxyWindowedFixture, + SaccHarmonicCrossBinFixture, + SaccRealCrossBinFixture, +) # pylint: disable=too-many-lines +# These rejection fixtures retain distinct harmonic and real-space types so +# their values can evolve to reflect the respective physical observables while +# preserving the intentionally invalid three-tracer inputs. +@dataclass(frozen=True, kw_only=True) +class SaccRealThreeTracerFixture: + """Real SACC data with an intentionally invalid three-tracer correlation. + + :param sacc_data: SACC data retaining the three-tracer rejection input. + :param distributions: Input redshift distributions keyed by tracer name. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + + +@dataclass(frozen=True, kw_only=True) +class SaccHarmonicThreeTracerFixture: + """Harmonic SACC data with an intentionally invalid three-tracer correlation. + + :param sacc_data: SACC data retaining the three-tracer rejection input. + :param distributions: Input redshift distributions keyed by tracer name. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + + +@dataclass(frozen=True, kw_only=True) +class SaccInvalidDataTypeFixture: + """SACC data and raw inputs for an intentionally invalid data type. + + :param sacc_data: SACC data retaining the unsupported data type. + :param distributions: Sampled redshift distributions keyed by tracer name. + :param ells: Integer multipole coordinates used for the data points. + :param values: Raw values for the invalid data points, with no physical meaning. + """ + + sacc_data: sacc.Sacc + distributions: dict[str, SampledRedshiftDistribution] + ells: npt.NDArray[np.int64] + values: npt.NDArray[np.float64] + + @pytest.fixture(name="sacc_galaxy_src0_src0_invalid_data_type") def fixture_sacc_galaxy_src0_src0_invalid_data_type( recwarn: pytest.WarningsRecorder, -) -> tuple[sacc.Sacc, np.ndarray, np.ndarray]: - """Fixture for a SACC data without window functions.""" +) -> SaccInvalidDataTypeFixture: + """Build unwindowed SACC data with an intentionally invalid data type. + + :param recwarn: Recorder for SACC's unknown-data-type warning. + :returns: Invalid SACC data, sampled distribution, multipoles, and raw values. + """ sacc_data = sacc.Sacc() z = np.linspace(0, 1.0, 50) + 0.05 @@ -76,8 +131,8 @@ def fixture_sacc_galaxy_src0_src0_invalid_data_type( dndz = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src0", z, dndz) - Cells = np.random.normal(size=ells.shape[0]) - sacc_data.add_ell_cl("this_type_is_invalid", "src0", "src0", ells, Cells) + values: npt.NDArray[np.float64] = np.asarray(np.random.normal(size=ells.shape[0])) + sacc_data.add_ell_cl("this_type_is_invalid", "src0", "src0", ells, values) warning = next(iter(recwarn), None) if warning is not None: assert isinstance(warning.message, UserWarning) @@ -85,29 +140,36 @@ def fixture_sacc_galaxy_src0_src0_invalid_data_type( r"Unknown data_type value this_type_is_invalid\.", str(warning.message) ) - cov = np.diag(np.ones_like(Cells) * 0.01) + cov = np.diag(np.ones_like(values) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, dndz + return SaccInvalidDataTypeFixture( + sacc_data=sacc_data, + distributions={"src0": SampledRedshiftDistribution(z=z, dndz=dndz)}, + ells=ells, + values=values, + ) @pytest.fixture(name="sacc_galaxy_xis_three_tracers") -def fixture_sacc_galaxy_xis_three_tracers() -> ( - tuple[sacc.Sacc, np.ndarray, np.ndarray, np.ndarray, np.ndarray] -): - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_xis_three_tracers() -> SaccRealThreeTracerFixture: + """Build unwindowed real-space SACC data with a three-tracer correlation. + + :returns: SACC data and input src0/lens0/lens1 distributions sharing + their original redshift grid and retaining distinct number densities. + """ sacc_data = sacc.Sacc() - z = np.linspace(0, 1.0, 50) + 0.05 + z: npt.NDArray[np.float64] = np.linspace(0, 1.0, 50) + 0.05 thetas = np.linspace(0.0, 2.0 * np.pi, 20) - dndz0 = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) + dndz0: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src0", z, dndz0) - dndz1 = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) + dndz1: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz1) - dndz2 = np.exp(-0.5 * (z - 0.9) ** 2 / 0.05 / 0.05) + dndz2: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.9) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens1", z, dndz2) # We have to coerce the return type of np.random.normal to np.array, @@ -121,26 +183,35 @@ def fixture_sacc_galaxy_xis_three_tracers() -> ( cov = np.diag(np.ones_like(xis) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, dndz0, dndz1, dndz2 + return SaccRealThreeTracerFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z, dndz=dndz0), + "lens0": SampledRedshiftDistribution(z=z, dndz=dndz1), + "lens1": SampledRedshiftDistribution(z=z, dndz=dndz2), + }, + ) @pytest.fixture(name="sacc_galaxy_cells_three_tracers") -def fixture_sacc_galaxy_cells_three_tracers() -> ( - tuple[sacc.Sacc, np.ndarray, np.ndarray, np.ndarray, np.ndarray] -): - """Fixture for a SACC data without window functions.""" +def fixture_sacc_galaxy_cells_three_tracers() -> SaccHarmonicThreeTracerFixture: + """Build unwindowed harmonic SACC data with a three-tracer correlation. + + :returns: SACC data and input src0/lens0/lens1 distributions sharing + their original redshift grid and retaining distinct number densities. + """ sacc_data = sacc.Sacc() - z = np.linspace(0, 1.0, 50) + 0.05 + z: npt.NDArray[np.float64] = np.linspace(0, 1.0, 50) + 0.05 ells = np.unique(np.logspace(1, 3, 10).astype(np.int64)) - dndz0 = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) + dndz0: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.5) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "src0", z, dndz0) - dndz1 = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) + dndz1: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.1) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens0", z, dndz1) - dndz2 = np.exp(-0.5 * (z - 0.9) ** 2 / 0.05 / 0.05) + dndz2: npt.NDArray[np.float64] = np.exp(-0.5 * (z - 0.9) ** 2 / 0.05 / 0.05) sacc_data.add_tracer("NZ", "lens1", z, dndz2) # We have to coerce the return type of np.random.normal to np.array, @@ -154,175 +225,181 @@ def fixture_sacc_galaxy_cells_three_tracers() -> ( cov = np.diag(np.ones_like(Cells) * 0.01) sacc_data.add_covariance(cov) - return sacc_data, z, dndz0, dndz1, dndz2 + return SaccHarmonicThreeTracerFixture( + sacc_data=sacc_data, + distributions={ + "src0": SampledRedshiftDistribution(z=z, dndz=dndz0), + "lens0": SampledRedshiftDistribution(z=z, dndz=dndz1), + "lens1": SampledRedshiftDistribution(z=z, dndz=dndz2), + }, + ) def test_extract_all_tracers_cells( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, tracers, _ = sacc_galaxy_cells + """Extract harmonic tracer distributions matching the fixture inputs. + + :param sacc_galaxy_cells: Harmonic SACC data and named expected distributions. + """ + sacc_data = sacc_galaxy_cells.sacc_data + tracers = sacc_galaxy_cells.distributions assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) for tracer in all_tracers: orig_tracer = tracers[tracer.bin_name] - assert_array_equal(tracer.z, orig_tracer[0]) - assert_array_equal(tracer.dndz, orig_tracer[1]) + assert_array_equal(tracer.z, orig_tracer.z) + assert_array_equal(tracer.dndz, orig_tracer.dndz) def test_extract_all_tracers_xis( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, tracers, _ = sacc_galaxy_xis + """Extract real tracer distributions matching the fixture inputs. + + :param sacc_galaxy_xis: Real SACC data and named expected distributions. + """ + sacc_data = sacc_galaxy_xis.sacc_data + tracers = sacc_galaxy_xis.distributions assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) for tracer in all_tracers: orig_tracer = tracers[tracer.bin_name] - assert_array_equal(tracer.z, orig_tracer[0]) - assert_array_equal(tracer.dndz, orig_tracer[1]) + assert_array_equal(tracer.z, orig_tracer.z) + assert_array_equal(tracer.dndz, orig_tracer.dndz) def test_extract_all_tracers_cells_src0_src0( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, expected_bin = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data + expected_distribution = sacc_galaxy_cells_src0_src0.distributions["src0"] assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) assert len(all_tracers) == 1 for tracer in all_tracers: - assert_array_equal(tracer.z, expected_bin.z) - assert_array_equal(tracer.dndz, expected_bin.dndz) + assert_array_equal(tracer.z, expected_distribution.z) + assert_array_equal(tracer.dndz, expected_distribution.dndz) assert tracer.bin_name == "src0" assert tracer.measurements == {Galaxies.SHEAR_E} def test_extract_all_tracers_cells_src0_src1( - sacc_galaxy_cells_src0_src1: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_cells_src0_src1: SaccHarmonicCrossBinFixture, ) -> None: - sacc_data, z, dndz0, dndz1 = sacc_galaxy_cells_src0_src1 + """Extract both source distributions without changing their harmonic roles. + + :param sacc_galaxy_cells_src0_src1: Source-source SACC data and expectations. + """ + sacc_data = sacc_galaxy_cells_src0_src1.sacc_data + distributions = sacc_galaxy_cells_src0_src1.distributions assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) assert len(all_tracers) == 2 for tracer in all_tracers: - assert_array_equal(tracer.z, z) + assert_array_equal(tracer.z, distributions[tracer.bin_name].z) assert tracer.measurements == {Galaxies.SHEAR_E} if tracer.bin_name == "src0": - assert_array_equal(tracer.dndz, dndz0) + assert_array_equal(tracer.dndz, distributions["src0"].dndz) elif tracer.bin_name == "src1": - assert_array_equal(tracer.dndz, dndz1) + assert_array_equal(tracer.dndz, distributions["src1"].dndz) def test_extract_all_tracers_cells_lens0_lens0( - sacc_galaxy_cells_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_lens0_lens0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, expected_bin = sacc_galaxy_cells_lens0_lens0 + sacc_data = sacc_galaxy_cells_lens0_lens0.sacc_data + expected_distribution = sacc_galaxy_cells_lens0_lens0.distributions["lens0"] assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) assert len(all_tracers) == 1 for tracer in all_tracers: - assert_array_equal(tracer.z, expected_bin.z) - assert_array_equal(tracer.dndz, expected_bin.dndz) + assert_array_equal(tracer.z, expected_distribution.z) + assert_array_equal(tracer.dndz, expected_distribution.dndz) assert tracer.bin_name == "lens0" assert tracer.measurements == {Galaxies.COUNTS} def test_extract_all_tracers_cells_lens0_lens1( - sacc_galaxy_cells_lens0_lens1: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_cells_lens0_lens1: SaccHarmonicCrossBinFixture, ) -> None: - sacc_data, z, dndz0, dndz1 = sacc_galaxy_cells_lens0_lens1 + """Extract both lens distributions without changing their harmonic roles. + + :param sacc_galaxy_cells_lens0_lens1: Lens-lens SACC data and expectations. + """ + sacc_data = sacc_galaxy_cells_lens0_lens1.sacc_data + distributions = sacc_galaxy_cells_lens0_lens1.distributions assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) assert len(all_tracers) == 2 for tracer in all_tracers: - assert_array_equal(tracer.z, z) + assert_array_equal(tracer.z, distributions[tracer.bin_name].z) assert tracer.measurements == {Galaxies.COUNTS} if tracer.bin_name == "lens0": - assert_array_equal(tracer.dndz, dndz0) + assert_array_equal(tracer.dndz, distributions["lens0"].dndz) elif tracer.bin_name == "lens1": - assert_array_equal(tracer.dndz, dndz1) + assert_array_equal(tracer.dndz, distributions["lens1"].dndz) def test_extract_all_tracers_xis_lens0_lens0( - sacc_galaxy_xis_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_xis_lens0_lens0: SaccGalaxyRealFixture, ) -> None: - sacc_data, expected_bin = sacc_galaxy_xis_lens0_lens0 + sacc_data = sacc_galaxy_xis_lens0_lens0.sacc_data + expected_distribution = sacc_galaxy_xis_lens0_lens0.distributions["lens0"] assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) assert len(all_tracers) == 1 for tracer in all_tracers: - assert_array_equal(tracer.z, expected_bin.z) - assert_array_equal(tracer.dndz, expected_bin.dndz) + assert_array_equal(tracer.z, expected_distribution.z) + assert_array_equal(tracer.dndz, expected_distribution.dndz) assert tracer.bin_name == "lens0" assert tracer.measurements == {Galaxies.COUNTS} def test_extract_all_tracers_xis_lens0_lens1( - sacc_galaxy_xis_lens0_lens1: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_xis_lens0_lens1: SaccRealCrossBinFixture, ) -> None: - sacc_data, z, dndz0, dndz1 = sacc_galaxy_xis_lens0_lens1 + """Extract both lens distributions without changing their real-space roles. + + :param sacc_galaxy_xis_lens0_lens1: Lens-lens SACC data and expectations. + """ + sacc_data = sacc_galaxy_xis_lens0_lens1.sacc_data + distributions = sacc_galaxy_xis_lens0_lens1.distributions assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) assert len(all_tracers) == 2 for tracer in all_tracers: - assert_array_equal(tracer.z, z) + assert_array_equal(tracer.z, distributions[tracer.bin_name].z) assert tracer.measurements == {Galaxies.COUNTS} if tracer.bin_name == "lens0": - assert_array_equal(tracer.dndz, dndz0) + assert_array_equal(tracer.dndz, distributions["lens0"].dndz) elif tracer.bin_name == "lens1": - assert_array_equal(tracer.dndz, dndz1) + assert_array_equal(tracer.dndz, distributions["lens1"].dndz) def test_extract_all_trace_cells_src0_lens0( - sacc_galaxy_cells_src0_lens0: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_cells_src0_lens0: SaccHarmonicCrossBinFixture, ) -> None: - sacc_data, z, dndz0, dndz1 = sacc_galaxy_cells_src0_lens0 + """Extract source and lens distributions with distinct harmonic roles. + + :param sacc_galaxy_cells_src0_lens0: Source-lens SACC data and expectations. + """ + sacc_data = sacc_galaxy_cells_src0_lens0.sacc_data + distributions = sacc_galaxy_cells_src0_lens0.distributions assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) @@ -330,24 +407,24 @@ def test_extract_all_trace_cells_src0_lens0( for tracer in all_tracers: if tracer.bin_name == "src0": - assert_array_equal(tracer.z, z) - assert_array_equal(tracer.dndz, dndz0) + assert_array_equal(tracer.z, distributions["src0"].z) + assert_array_equal(tracer.dndz, distributions["src0"].dndz) assert tracer.measurements == {Galaxies.SHEAR_E} elif tracer.bin_name == "lens0": - assert_array_equal(tracer.z, z) - assert_array_equal(tracer.dndz, dndz1) + assert_array_equal(tracer.z, distributions["lens0"].z) + assert_array_equal(tracer.dndz, distributions["lens0"].dndz) assert tracer.measurements == {Galaxies.COUNTS} def test_extract_all_trace_xis_src0_lens0( - sacc_galaxy_xis_src0_lens0: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_xis_src0_lens0: SaccRealCrossBinFixture, ) -> None: - sacc_data, z, dndz0, dndz1 = sacc_galaxy_xis_src0_lens0 + """Extract source and lens distributions with distinct real-space roles. + + :param sacc_galaxy_xis_src0_lens0: Source-lens SACC data and expectations. + """ + sacc_data = sacc_galaxy_xis_src0_lens0.sacc_data + distributions = sacc_galaxy_xis_src0_lens0.distributions assert sacc_data is not None all_tracers = extract_all_tracers_tomographic_bins(sacc_data) @@ -355,19 +432,23 @@ def test_extract_all_trace_xis_src0_lens0( for tracer in all_tracers: if tracer.bin_name == "src0": - assert_array_equal(tracer.z, z) - assert_array_equal(tracer.dndz, dndz0) + assert_array_equal(tracer.z, distributions["src0"].z) + assert_array_equal(tracer.dndz, distributions["src0"].dndz) assert tracer.measurements == {Galaxies.SHEAR_T} elif tracer.bin_name == "lens0": - assert_array_equal(tracer.z, z) - assert_array_equal(tracer.dndz, dndz1) + assert_array_equal(tracer.z, distributions["lens0"].z) + assert_array_equal(tracer.dndz, distributions["lens0"].dndz) assert tracer.measurements == {Galaxies.COUNTS} def test_extract_all_tracers_invalid_data_type( - sacc_galaxy_src0_src0_invalid_data_type: tuple[sacc.Sacc, np.ndarray, np.ndarray], + sacc_galaxy_src0_src0_invalid_data_type: SaccInvalidDataTypeFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_src0_src0_invalid_data_type + """Reject a tracer whose only data points have an unsupported data type. + + :param sacc_galaxy_src0_src0_invalid_data_type: Invalid SACC data and raw inputs. + """ + sacc_data = sacc_galaxy_src0_src0_invalid_data_type.sacc_data assert sacc_data is not None with pytest.raises( ValueError, match="Tracer src0 does not have data points associated with it." @@ -555,16 +636,14 @@ def test_extract_all_tracers_projected_fields_map_tracer_without_data() -> None: def test_extract_all_metadata_index_harmonics( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cells + """Extract harmonic indices for every expected tracer pair and data type. + + :param sacc_galaxy_cells: Harmonic SACC data and expected spectra. + """ + sacc_data = sacc_galaxy_cells.sacc_data + tracer_pairs = sacc_galaxy_cells.spectra all_data = extract_all_harmonic_metadata_indices(sacc_data) assert len(all_data) == len(tracer_pairs) @@ -575,16 +654,14 @@ def test_extract_all_metadata_index_harmonics( def test_extract_all_metadata_index_harmonics_by_type( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cells + """Filter harmonic metadata indices to the requested shear data type. + + :param sacc_galaxy_cells: Harmonic SACC data and expected spectra. + """ + sacc_data = sacc_galaxy_cells.sacc_data + tracer_pairs = sacc_galaxy_cells.spectra all_data = extract_all_harmonic_metadata_indices( sacc_data, allowed_data_type=["galaxy_shear_cl_ee"] @@ -597,16 +674,14 @@ def test_extract_all_metadata_index_harmonics_by_type( def test_extract_all_metadata_index_reals( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_xis + """Extract real metadata indices for every input spectrum. + + :param sacc_galaxy_xis: Real SACC data and expected spectra. + """ + sacc_data = sacc_galaxy_xis.sacc_data + tracer_pairs = sacc_galaxy_xis.spectra all_data = extract_all_real_metadata_indices(sacc_data) assert len(all_data) == len(tracer_pairs) @@ -617,16 +692,14 @@ def test_extract_all_metadata_index_reals( def test_extract_all_metadata_index_reals_by_type( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_xis + """Filter real metadata indices to the requested density data type. + + :param sacc_galaxy_xis: Real SACC data and expected spectra. + """ + sacc_data = sacc_galaxy_xis.sacc_data + tracer_pairs = sacc_galaxy_xis.spectra all_data = extract_all_real_metadata_indices( sacc_data, allowed_data_type=["galaxy_density_xi"] @@ -639,9 +712,9 @@ def test_extract_all_metadata_index_reals_by_type( def test_extract_no_window( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _ = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data indices = np.array([0, 1, 2], dtype=np.int64) with warnings.catch_warnings(): @@ -654,15 +727,14 @@ def test_extract_no_window( def test_extract_all_data_types_three_tracers_reals( - sacc_galaxy_xis_three_tracers: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_xis_three_tracers: SaccRealThreeTracerFixture, ) -> None: - sacc_data, _, _, _, _ = sacc_galaxy_xis_three_tracers + """Reject real-space metadata for a correlation containing three tracers. + + :param sacc_galaxy_xis_three_tracers: Real SACC data and input + redshift distributions for src0, lens0, and lens1. + """ + sacc_data = sacc_galaxy_xis_three_tracers.sacc_data with pytest.raises( ValueError, @@ -675,15 +747,14 @@ def test_extract_all_data_types_three_tracers_reals( def test_extract_all_data_types_three_tracers_harmonics( - sacc_galaxy_cells_three_tracers: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_cells_three_tracers: SaccHarmonicThreeTracerFixture, ) -> None: - sacc_data, _, _, _, _ = sacc_galaxy_cells_three_tracers + """Reject harmonic metadata for a correlation containing three tracers. + + :param sacc_galaxy_cells_three_tracers: Harmonic SACC data and input + redshift distributions for src0, lens0, and lens1. + """ + sacc_data = sacc_galaxy_cells_three_tracers.sacc_data with pytest.raises( ValueError, @@ -696,16 +767,14 @@ def test_extract_all_data_types_three_tracers_harmonics( def test_extract_all_photoz_bin_combinations_reals( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_xis + """Recover expected real bin combinations and their SACC names. + + :param sacc_galaxy_xis: Real SACC data and expected spectra. + """ + sacc_data = sacc_galaxy_xis.sacc_data + tracer_pairs = sacc_galaxy_xis.spectra # We build all possible combinations of tracers all_bin_combs = extract_all_photoz_bin_combinations(sacc_data) @@ -730,16 +799,14 @@ def test_extract_all_photoz_bin_combinations_reals( def test_extract_all_photoz_bin_combinations_harmonics( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cells + """Recover expected harmonic bin combinations and their SACC names. + + :param sacc_galaxy_cells: Harmonic SACC data and expected spectra. + """ + sacc_data = sacc_galaxy_cells.sacc_data + tracer_pairs = sacc_galaxy_cells.spectra # We build all possible combinations of tracers all_bin_combs = extract_all_photoz_bin_combinations(sacc_data) @@ -766,16 +833,13 @@ def test_extract_all_photoz_bin_combinations_harmonics( def test_make_harmonics( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cells + """Construct harmonic metadata from extracted bin combinations and multipoles. + + :param sacc_galaxy_cells: Harmonic SACC data used to extract bin combinations. + """ + sacc_data = sacc_galaxy_cells.sacc_data ells = np.unique(np.logspace(1, 3, 10).astype(np.int64)) all_bin_combs = extract_all_photoz_bin_combinations(sacc_data) @@ -790,16 +854,13 @@ def test_make_harmonics( def test_make_reals( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis + """Construct real metadata from extracted bin combinations and angular grids. + + :param sacc_galaxy_xis: Real SACC data used to extract bin combinations. + """ + sacc_data = sacc_galaxy_xis.sacc_data thetas = np.linspace(0.0, 2.0 * np.pi, 20, dtype=np.float64) all_bin_combs = extract_all_photoz_bin_combinations(sacc_data) @@ -815,16 +876,14 @@ def test_make_reals( @pytest.mark.slow def test_extract_all_harmonic_data( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cells + """Extract consistent harmonic measurements matching the fixture inputs. + + :param sacc_galaxy_cells: Harmonic SACC data and named expected spectra. + """ + sacc_data = sacc_galaxy_cells.sacc_data + tracer_pairs = sacc_galaxy_cells.spectra two_point_harmonics = extract_all_harmonic_data(sacc_data) assert len(two_point_harmonics) == len(tracer_pairs) @@ -835,9 +894,9 @@ def test_extract_all_harmonic_data( tracer_names = TracerNames(metadata.XY.x.bin_name, metadata.XY.y.bin_name) assert (tracer_names, metadata.get_sacc_name()) in tracer_pairs - ells, Cell = tracer_pairs[(tracer_names, metadata.get_sacc_name())] - assert_array_equal(metadata.ells, ells) - assert_array_equal(two_point.data, Cell) + spectrum = tracer_pairs[(tracer_names, metadata.get_sacc_name())] + assert_array_equal(metadata.ells, spectrum.ells) + assert_array_equal(two_point.data, spectrum.cells) check_two_point_consistence_harmonic(two_point_harmonics) @@ -846,7 +905,12 @@ def test_extract_all_harmonic_data( def test_extract_all_harmonic_with_window_data( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cwindows + """Extract windowed measurements matching the input support and bandpowers. + + :param sacc_galaxy_cwindows: Windowed SACC data and named expected spectra. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data + tracer_pairs = sacc_galaxy_cwindows.spectra two_point_harmonics = extract_all_harmonic_data(sacc_data) assert len(two_point_harmonics) == len(tracer_pairs) @@ -857,9 +921,10 @@ def test_extract_all_harmonic_with_window_data( tracer_names = TracerNames(metadata.XY.x.bin_name, metadata.XY.y.bin_name) assert (tracer_names, metadata.get_sacc_name()) in tracer_pairs - ells, Cell, window = tracer_pairs[(tracer_names, metadata.get_sacc_name())] - assert_array_equal(metadata.ells, ells) - assert_array_equal(two_point.data, Cell) + spectrum = tracer_pairs[(tracer_names, metadata.get_sacc_name())] + window = spectrum.window + assert_array_equal(metadata.ells, spectrum.support_ells) + assert_array_equal(two_point.data, spectrum.bandpowers) assert metadata.window is not None assert_array_equal(metadata.window, window.weight / window.weight.sum(axis=0)) @@ -870,16 +935,14 @@ def test_extract_all_harmonic_with_window_data( @pytest.mark.slow def test_extract_all_real_data( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_xis + """Extract consistent real measurements matching the fixture inputs. + + :param sacc_galaxy_xis: Real SACC data and named expected spectra. + """ + sacc_data = sacc_galaxy_xis.sacc_data + tracer_pairs = sacc_galaxy_xis.spectra two_point_xis = extract_all_real_data(sacc_data) assert len(two_point_xis) == len(tracer_pairs) @@ -890,25 +953,24 @@ def test_extract_all_real_data( tracer_names = TracerNames(metadata.XY.x.bin_name, metadata.XY.y.bin_name) assert (tracer_names, metadata.get_sacc_name()) in tracer_pairs - thetas, xi = tracer_pairs[(tracer_names, metadata.get_sacc_name())] - assert_array_equal(metadata.thetas, thetas) - assert_array_equal(two_point.data, xi) + spectrum = tracer_pairs[(tracer_names, metadata.get_sacc_name())] + assert_array_equal(metadata.thetas, spectrum.thetas) + assert_array_equal(two_point.data, spectrum.xis) check_two_point_consistence_real(two_point_xis) def test_constructor_harmonic_metadata( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cells + """Construct TwoPoint statistics from extracted harmonic metadata. + + :param sacc_galaxy_cells: Harmonic SACC data and expected spectra. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_cells.sacc_data + tracer_pairs = sacc_galaxy_cells.spectra two_point_harmonics = extract_all_harmonic_metadata(sacc_data) @@ -920,22 +982,21 @@ def test_constructor_harmonic_metadata( tracer_pairs_key = (two_point.sacc_tracers, two_point.sacc_data_type) assert tracer_pairs_key in tracer_pairs assert two_point.ells is not None - assert_array_equal(two_point.ells, tracer_pairs[tracer_pairs_key][0]) + assert_array_equal(two_point.ells, tracer_pairs[tracer_pairs_key].ells) @pytest.mark.slow def test_constructor_harmonic_data( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cells + """Construct TwoPoint statistics matching the input harmonic measurements. + + :param sacc_galaxy_cells: Harmonic SACC data and expected spectra. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_cells.sacc_data + tracer_pairs = sacc_galaxy_cells.spectra two_point_harmonics = extract_all_harmonic_data(sacc_data) @@ -948,9 +1009,9 @@ def test_constructor_harmonic_data( tracer_pairs_key = (two_point.sacc_tracers, two_point.sacc_data_type) assert tracer_pairs_key in tracer_pairs assert two_point.ells is not None - assert_array_equal(two_point.ells, tracer_pairs[tracer_pairs_key][0]) + assert_array_equal(two_point.ells, tracer_pairs[tracer_pairs_key].ells) assert_array_equal( - two_point.get_data_vector(), tracer_pairs[tracer_pairs_key][1] + two_point.get_data_vector(), tracer_pairs[tracer_pairs_key].cells ) @@ -958,7 +1019,13 @@ def test_constructor_harmonic_with_window_metadata( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cwindows + """Construct TwoPoint statistics from extracted windowed harmonic metadata. + + :param sacc_galaxy_cwindows: Windowed SACC data and its input windows. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data + tracer_pairs = sacc_galaxy_cwindows.spectra two_point_harmonics = extract_all_harmonic_metadata(sacc_data) @@ -969,7 +1036,7 @@ def test_constructor_harmonic_with_window_metadata( for two_point in two_points_new: tracer_pairs_key = (two_point.sacc_tracers, two_point.sacc_data_type) assert tracer_pairs_key in tracer_pairs - _, _, window = tracer_pairs[tracer_pairs_key] + window = tracer_pairs[tracer_pairs_key].window assert two_point.ells is not None assert two_point.window is not None assert_array_equal( @@ -982,8 +1049,11 @@ def test_constructor_harmonic_with_window_metadata( def test_extract_all_harmonic_metadata_normalize_true( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, ) -> None: - """Test that normalize=True normalizes windows in extract_all_harmonic_metadata.""" - sacc_data, _, _ = sacc_galaxy_cwindows + """Test that normalize=True normalizes windows in extract_all_harmonic_metadata. + + :param sacc_galaxy_cwindows: Windowed SACC data with unnormalized weights. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data two_point_harmonics = extract_all_harmonic_metadata(sacc_data, normalize=True) @@ -999,8 +1069,11 @@ def test_extract_all_harmonic_metadata_normalize_true( def test_extract_all_harmonic_metadata_normalize_false( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, ) -> None: - """Test that normalize=False keeps windows unnormalized.""" - sacc_data, _, _ = sacc_galaxy_cwindows + """Test that normalize=False keeps windows unnormalized. + + :param sacc_galaxy_cwindows: Windowed SACC data with unnormalized weights. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data two_point_harmonics = extract_all_harmonic_metadata(sacc_data, normalize=False) @@ -1020,8 +1093,11 @@ def test_extract_all_harmonic_metadata_normalize_false( def test_extract_all_harmonic_metadata_default_normalizes( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, ) -> None: - """Test that the default behavior (no normalize parameter) normalizes windows.""" - sacc_data, _, _ = sacc_galaxy_cwindows + """Test that the default behavior (no normalize parameter) normalizes windows. + + :param sacc_galaxy_cwindows: Windowed SACC data with unnormalized weights. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data two_point_harmonics = extract_all_harmonic_metadata(sacc_data) @@ -1170,7 +1246,13 @@ def test_constructor_harmonic_with_window_data( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_cwindows + """Construct TwoPoint statistics matching the input bandpowers and windows. + + :param sacc_galaxy_cwindows: Windowed SACC data and named expected spectra. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data + tracer_pairs = sacc_galaxy_cwindows.spectra two_point_harmonics = extract_all_harmonic_data(sacc_data) @@ -1182,9 +1264,10 @@ def test_constructor_harmonic_with_window_data( for two_point in two_points_new: tracer_pairs_key = (two_point.sacc_tracers, two_point.sacc_data_type) assert tracer_pairs_key in tracer_pairs - _, Cell, window = tracer_pairs[tracer_pairs_key] + spectrum = tracer_pairs[tracer_pairs_key] + window = spectrum.window assert two_point.ells is not None - assert_array_equal(two_point.get_data_vector(), Cell) + assert_array_equal(two_point.get_data_vector(), spectrum.bandpowers) assert two_point.window is not None assert_array_equal( two_point.window, @@ -1194,17 +1277,16 @@ def test_constructor_harmonic_with_window_data( def test_constructor_reals_metadata( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_xis + """Construct TwoPoint statistics from extracted real metadata. + + :param sacc_galaxy_xis: Real SACC data and expected spectra. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_xis.sacc_data + tracer_pairs = sacc_galaxy_xis.spectra two_point_reals = extract_all_real_metadata(sacc_data) @@ -1216,22 +1298,21 @@ def test_constructor_reals_metadata( tracer_pairs_key = (two_point.sacc_tracers, two_point.sacc_data_type) assert tracer_pairs_key in tracer_pairs assert two_point.thetas is not None - assert_array_equal(two_point.thetas, tracer_pairs[tracer_pairs_key][0]) + assert_array_equal(two_point.thetas, tracer_pairs[tracer_pairs_key].thetas) @pytest.mark.slow def test_constructor_reals_data( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, tp_factory: TwoPointFactory, ) -> None: - sacc_data, _, tracer_pairs = sacc_galaxy_xis + """Construct TwoPoint statistics matching the input real measurements. + + :param sacc_galaxy_xis: Real SACC data and expected spectra. + :param tp_factory: Factory for the statistics' sources. + """ + sacc_data = sacc_galaxy_xis.sacc_data + tracer_pairs = sacc_galaxy_xis.spectra two_point_reals = extract_all_real_data(sacc_data) @@ -1244,25 +1325,24 @@ def test_constructor_reals_data( tracer_pairs_key = (two_point.sacc_tracers, two_point.sacc_data_type) assert tracer_pairs_key in tracer_pairs assert two_point.thetas is not None - assert_array_equal(two_point.thetas, tracer_pairs[tracer_pairs_key][0]) + assert_array_equal(two_point.thetas, tracer_pairs[tracer_pairs_key].thetas) assert_array_equal( - two_point.get_data_vector(), tracer_pairs[tracer_pairs_key][1] + two_point.get_data_vector(), tracer_pairs[tracer_pairs_key].xis ) def test_compare_constructors_harmonic( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, tp_factory: TwoPointFactory, tools_with_vanilla_cosmology: ModelingTools, ) -> None: - sacc_data, _, _ = sacc_galaxy_cells + """Compare harmonic measurement construction with the original SACC read path. + + :param sacc_galaxy_cells: Harmonic SACC data for both construction paths. + :param tp_factory: Factory for the statistics' sources. + :param tools_with_vanilla_cosmology: Tools for comparing theory vectors. + """ + sacc_data = sacc_galaxy_cells.sacc_data two_point_harmonics = extract_all_harmonic_data(sacc_data) @@ -1310,7 +1390,13 @@ def test_compare_constructors_harmonic_with_window( tp_factory: TwoPointFactory, tools_with_vanilla_cosmology: ModelingTools, ) -> None: - sacc_data, _, _ = sacc_galaxy_cwindows + """Compare windowed measurement construction with the original SACC read path. + + :param sacc_galaxy_cwindows: Windowed SACC data for both construction paths. + :param tp_factory: Factory for the statistics' sources. + :param tools_with_vanilla_cosmology: Tools for comparing theory vectors. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data two_point_harmonics = extract_all_harmonic_data(sacc_data) @@ -1360,18 +1446,17 @@ def test_compare_constructors_harmonic_with_window( def test_compare_constructors_reals( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, tp_factory: TwoPointFactory, tools_with_vanilla_cosmology: ModelingTools, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis + """Compare real measurement construction with the original SACC read path. + + :param sacc_galaxy_xis: Real SACC data for both construction paths. + :param tp_factory: Factory for the statistics' sources. + :param tools_with_vanilla_cosmology: Tools for comparing theory vectors. + """ + sacc_data = sacc_galaxy_xis.sacc_data two_point_xis = extract_all_real_data(sacc_data) @@ -1415,16 +1500,17 @@ def test_compare_constructors_reals( def test_extract_all_data_harmonic_no_cov( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cells + """Reject missing covariance without mutating the shared harmonic fixture. + + :param sacc_galaxy_cells: Shared harmonic SACC data and named expectations. + """ + shared_sacc = sacc_galaxy_cells.sacc_data + shared_covariance = shared_sacc.covariance + assert shared_covariance is not None + expected_covariance = shared_covariance.dense.copy() + sacc_data = shared_sacc.copy() sacc_data.covariance = None with pytest.raises( ValueError, @@ -1432,18 +1518,23 @@ def test_extract_all_data_harmonic_no_cov( ): _ = extract_all_harmonic_data(sacc_data) + assert sacc_data.covariance is None + assert shared_sacc.covariance is shared_covariance + assert_array_equal(shared_sacc.covariance.dense, expected_covariance) + def test_extract_all_data_real_no_cov( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis + """Reject missing covariance without mutating the shared real fixture. + + :param sacc_galaxy_xis: Shared real SACC data and named expectations. + """ + shared_sacc = sacc_galaxy_xis.sacc_data + shared_covariance = shared_sacc.covariance + assert shared_covariance is not None + expected_covariance = shared_covariance.dense.copy() + sacc_data = shared_sacc.copy() sacc_data.covariance = None with pytest.raises( ValueError, @@ -1451,6 +1542,10 @@ def test_extract_all_data_real_no_cov( ): _ = extract_all_real_data(sacc_data) + assert sacc_data.covariance is None + assert shared_sacc.covariance is shared_covariance + assert_array_equal(shared_sacc.covariance.dense, expected_covariance) + def test_make_all_photoz_bin_combinations_with_cmb_basic() -> None: """Test basic functionality of make_all_photoz_bin_combinations_with_cmb.""" @@ -2241,17 +2336,13 @@ def test_make_all_photoz_bin_combinations_with_cmb_empty() -> None: def test_extract_all_photoz_bin_combinations_with_selector( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test extract_all_photoz_bin_combinations with bin_pair_selector.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test extract_all_photoz_bin_combinations with bin_pair_selector. + + :param sacc_galaxy_cells: Harmonic SACC data to filter by bin pair. + """ + sacc_data = sacc_galaxy_cells.sacc_data # Without selector - should get all combinations all_combinations = extract_all_photoz_bin_combinations(sacc_data) @@ -2272,17 +2363,13 @@ def test_extract_all_photoz_bin_combinations_with_selector( def test_extract_all_photoz_bin_combinations_with_source_selector( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test extract_all_photoz_bin_combinations with source bin selector.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test extract_all_photoz_bin_combinations with source bin selector. + + :param sacc_galaxy_cells: Harmonic SACC data to filter to source measurements. + """ + sacc_data = sacc_galaxy_cells.sacc_data # With source selector - should only get source (shear) measurements source_selector = SourceBinPairSelector() @@ -2300,17 +2387,13 @@ def test_extract_all_photoz_bin_combinations_with_source_selector( def test_extract_all_photoz_bin_combinations_with_lens_selector( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test extract_all_photoz_bin_combinations with lens bin selector.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test extract_all_photoz_bin_combinations with lens bin selector. + + :param sacc_galaxy_cells: Harmonic SACC data to filter to lens measurements. + """ + sacc_data = sacc_galaxy_cells.sacc_data # With lens selector - should only get lens (counts) measurements lens_selector = LensBinPairSelector() @@ -2327,17 +2410,13 @@ def test_extract_all_photoz_bin_combinations_with_lens_selector( def test_extract_all_harmonic_metadata_with_selector( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test extract_all_harmonic_metadata with bin_pair_selector.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test extract_all_harmonic_metadata with bin_pair_selector. + + :param sacc_galaxy_cells: Harmonic SACC data to filter by bin pair. + """ + sacc_data = sacc_galaxy_cells.sacc_data # Without selector - should get all metadata all_metadata = extract_all_harmonic_metadata(sacc_data) @@ -2363,17 +2442,13 @@ def test_extract_all_harmonic_metadata_with_selector( def test_extract_all_harmonic_metadata_with_source_selector( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test extract_all_harmonic_metadata with source bin selector.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test extract_all_harmonic_metadata with source bin selector. + + :param sacc_galaxy_cells: Harmonic SACC data to filter to source measurements. + """ + sacc_data = sacc_galaxy_cells.sacc_data # With source selector - should only get source (shear) measurements source_selector = SourceBinPairSelector() @@ -2389,17 +2464,13 @@ def test_extract_all_harmonic_metadata_with_source_selector( def test_extract_all_harmonic_metadata_with_combined_selector( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test extract_all_harmonic_metadata with combined selectors.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test extract_all_harmonic_metadata with combined selectors. + + :param sacc_galaxy_cells: Harmonic SACC data to filter by combined selectors. + """ + sacc_data = sacc_galaxy_cells.sacc_data # Combine auto-name and auto-measurement selectors combined_selector = AutoNameBinPairSelector() & AutoMeasurementBinPairSelector() @@ -2416,17 +2487,13 @@ def test_extract_all_harmonic_metadata_with_combined_selector( def test_extract_all_real_metadata_with_selector( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - """Test extract_all_real_metadata with bin_pair_selector.""" - sacc_data, _, _ = sacc_galaxy_xis + """Test extract_all_real_metadata with bin_pair_selector. + + :param sacc_galaxy_xis: Real SACC data to filter by auto-correlation. + """ + sacc_data = sacc_galaxy_xis.sacc_data # Without selector - should get all metadata all_metadata = extract_all_real_metadata(sacc_data) @@ -2452,17 +2519,13 @@ def test_extract_all_real_metadata_with_selector( def test_extract_all_real_metadata_with_lens_selector( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - """Test extract_all_real_metadata with lens bin selector.""" - sacc_data, _, _ = sacc_galaxy_xis + """Test extract_all_real_metadata with lens bin selector. + + :param sacc_galaxy_xis: Real SACC data to filter by lens measurements. + """ + sacc_data = sacc_galaxy_xis.sacc_data # With lens selector - should only get lens (counts) measurements lens_selector = LensBinPairSelector() @@ -2479,17 +2542,13 @@ def test_extract_all_real_metadata_with_lens_selector( def test_extract_all_real_metadata_with_combined_selector( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - """Test extract_all_real_metadata with combined selectors.""" - sacc_data, _, _ = sacc_galaxy_xis + """Test extract_all_real_metadata with combined selectors. + + :param sacc_galaxy_xis: Real SACC data to filter by combined selectors. + """ + sacc_data = sacc_galaxy_xis.sacc_data # Combine auto-name and lens selectors combined_selector = AutoNameBinPairSelector() & LensBinPairSelector() @@ -2507,17 +2566,13 @@ def test_extract_all_real_metadata_with_combined_selector( def test_extract_all_harmonic_metadata_with_not_selector( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test extract_all_harmonic_metadata with NOT selector.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test extract_all_harmonic_metadata with NOT selector. + + :param sacc_galaxy_cells: Harmonic SACC data to filter by an inverted selector. + """ + sacc_data = sacc_galaxy_cells.sacc_data # Get all metadata all_metadata = extract_all_harmonic_metadata(sacc_data) @@ -2543,17 +2598,13 @@ def test_extract_all_harmonic_metadata_with_not_selector( def test_extract_all_real_metadata_with_or_selector( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - """Test extract_all_real_metadata with OR selector.""" - sacc_data, _, _ = sacc_galaxy_xis + """Test extract_all_real_metadata with OR selector. + + :param sacc_galaxy_xis: Real SACC data to filter by alternative selectors. + """ + sacc_data = sacc_galaxy_xis.sacc_data # Get all tracers to find specific bin names tracers = extract_all_tracers_tomographic_bins(sacc_data) @@ -2584,17 +2635,13 @@ def test_extract_all_real_metadata_with_or_selector( def test_extract_with_selector_empty_result( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test that selector can result in empty extraction.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test that selector can result in empty extraction. + + :param sacc_galaxy_cells: Harmonic SACC data to filter to nonexistent bins. + """ + sacc_data = sacc_galaxy_cells.sacc_data # Create selector for non-existent bin names impossible_selector = NamedBinPairSelector(names=[("nonexistent1", "nonexistent2")]) @@ -2612,17 +2659,13 @@ def test_extract_with_selector_empty_result( def test_extract_with_selector_preserves_data_quality( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - """Test that using selector doesn't affect data quality of extracted metadata.""" - sacc_data, _, _ = sacc_galaxy_cells + """Test that using selector doesn't affect data quality of extracted metadata. + + :param sacc_galaxy_cells: Harmonic SACC data for filtered and full extraction. + """ + sacc_data = sacc_galaxy_cells.sacc_data # Extract without selector all_metadata = extract_all_harmonic_metadata(sacc_data) diff --git a/tests/metadata/test_metadata_two_point_types.py b/tests/metadata/test_metadata_two_point_types.py index 53c4b3e40..aa0ff8e3e 100644 --- a/tests/metadata/test_metadata_two_point_types.py +++ b/tests/metadata/test_metadata_two_point_types.py @@ -9,7 +9,6 @@ from unittest.mock import MagicMock import numpy as np -import numpy.typing as npt import pytest import sacc import sacc_name_mapping as snm @@ -34,7 +33,6 @@ Clusters, Galaxies, Measurement, - TomographicBin, TracerNames, TwoPointHarmonic, TwoPointReal, @@ -62,7 +60,12 @@ from firecrown.metadata_types._sacc_type_string import ( _type_to_sacc_string_real as real, ) -from tests._types import SaccGalaxyWindowedFixture +from tests._types import ( + SaccGalaxyHarmonicFixture, + SaccGalaxyRealFixture, + SaccGalaxyWindowedFixture, + SaccRealCrossBinFixture, +) def test_order_enums() -> None: @@ -197,16 +200,13 @@ def test_measurement_is_compatible() -> None: def test_extract_all_tracers_types_cells( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cells + """Verify harmonic tracers have the expected lens and source measurements. + + :param sacc_galaxy_cells: Harmonic SACC data with named expectations. + """ + sacc_data = sacc_galaxy_cells.sacc_data tracers, _ = extract_all_measured_types(sacc_data) @@ -222,7 +222,11 @@ def test_extract_all_tracers_types_cells( def test_extract_all_tracers_types_cwindows( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cwindows + """Verify windowed tracers retain their lens and source measurement meanings. + + :param sacc_galaxy_cwindows: Windowed SACC data with named expectations. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data tracers, _ = extract_all_measured_types(sacc_data) @@ -236,16 +240,13 @@ def test_extract_all_tracers_types_cwindows( def test_extract_all_tracers_types_reals( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis + """Verify real tracers retain their lens and source measurement meanings. + + :param sacc_galaxy_xis: Real SACC data with named expectations. + """ + sacc_data = sacc_galaxy_xis.sacc_data tracers, _ = extract_all_measured_types(sacc_data) @@ -262,16 +263,13 @@ def test_extract_all_tracers_types_reals( def test_extract_all_tracers_types_reals_inverted( - sacc_galaxy_xis_inverted: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis_inverted: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis_inverted + """Correct inverted real tracer conventions while preserving measurement types. + + :param sacc_galaxy_xis_inverted: Inverted real SACC data and named expectations. + """ + sacc_data = sacc_galaxy_xis_inverted.sacc_data with pytest.warns(DeprecationWarning, match="AUTO-CORRECTION PERFORMED"): tracers, _ = extract_all_measured_types(sacc_data) @@ -288,16 +286,13 @@ def test_extract_all_tracers_types_reals_inverted( def test_extract_all_tracers_types_cells_include_maybe( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cells + """Verify repeated harmonic measured-type extraction returns equal results. + + :param sacc_galaxy_cells: Harmonic SACC data with named expectations. + """ + sacc_data = sacc_galaxy_cells.sacc_data assert extract_all_measured_types(sacc_data) == extract_all_measured_types( sacc_data @@ -307,7 +302,11 @@ def test_extract_all_tracers_types_cells_include_maybe( def test_extract_all_tracers_types_cwindows_include_maybe( sacc_galaxy_cwindows: SaccGalaxyWindowedFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cwindows + """Verify repeated windowed measured-type extraction returns equal results. + + :param sacc_galaxy_cwindows: Windowed SACC data with named expectations. + """ + sacc_data = sacc_galaxy_cwindows.sacc_data assert extract_all_measured_types(sacc_data) == extract_all_measured_types( sacc_data @@ -315,16 +314,13 @@ def test_extract_all_tracers_types_cwindows_include_maybe( def test_extract_all_tracers_types_xi_thetas_include_maybe( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis + """Verify repeated real measured-type extraction returns equal results. + + :param sacc_galaxy_xis: Real SACC data with named expectations. + """ + sacc_data = sacc_galaxy_xis.sacc_data assert extract_all_measured_types(sacc_data) == extract_all_measured_types( sacc_data @@ -412,16 +408,13 @@ def test_check_two_point_consistence_real_harmonic( def test_check_two_point_consistence_harmonic_mixing_cov( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cells + """Verify harmonic consistency rejects measurements with mixed covariance names. + + :param sacc_galaxy_cells: Harmonic SACC data with named expectations. + """ + sacc_data = sacc_galaxy_cells.sacc_data tpms = extract_all_harmonic_data(sacc_data) @@ -438,16 +431,13 @@ def test_check_two_point_consistence_harmonic_mixing_cov( def test_check_two_point_consistence_real_mixing_cov( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis + """Verify real consistency rejects measurements with mixed covariance names. + + :param sacc_galaxy_xis: Real SACC data with named expectations. + """ + sacc_data = sacc_galaxy_xis.sacc_data tpms = extract_all_real_data(sacc_data) tpms[0] = replace(tpms[0], covariance_name="wrong_cov_name") @@ -463,16 +453,13 @@ def test_check_two_point_consistence_real_mixing_cov( def test_check_two_point_consistence_harmonic_non_unique_indices( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cells + """Verify harmonic consistency rejects repeated indices within a measurement. + + :param sacc_galaxy_cells: Harmonic SACC data with named expectations. + """ + sacc_data = sacc_galaxy_cells.sacc_data tpms = extract_all_harmonic_data(sacc_data) @@ -488,16 +475,13 @@ def test_check_two_point_consistence_harmonic_non_unique_indices( def test_check_two_point_consistence_real_non_unique_indices( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis + """Verify real consistency rejects repeated indices within a measurement. + + :param sacc_galaxy_xis: Real SACC data with named expectations. + """ + sacc_data = sacc_galaxy_xis.sacc_data tpms = extract_all_real_data(sacc_data) new_indices = tpms[0].indices @@ -512,16 +496,13 @@ def test_check_two_point_consistence_real_non_unique_indices( def test_check_two_point_consistence_harmonic_indices_overlap( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_cells + """Verify harmonic consistency rejects indices shared between measurements. + + :param sacc_galaxy_cells: Harmonic SACC data with named expectations. + """ + sacc_data = sacc_galaxy_cells.sacc_data tpms = extract_all_harmonic_data(sacc_data) @@ -537,16 +518,13 @@ def test_check_two_point_consistence_harmonic_indices_overlap( def test_check_two_point_consistence_real_indices_overlap( - sacc_galaxy_xis: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_xis: SaccGalaxyRealFixture, ) -> None: - sacc_data, _, _ = sacc_galaxy_xis + """Verify real consistency rejects indices shared between measurements. + + :param sacc_galaxy_xis: Real SACC data with named expectations. + """ + sacc_data = sacc_galaxy_xis.sacc_data tpms = extract_all_real_data(sacc_data) @@ -719,21 +697,16 @@ def test_measurements_types_multiple_galaxy_and_cmb() -> None: def test_extract_all_measured_mixed_types_with_genuinely_mixed_tracers( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: """Test extract_all_measured_types with allow_mixed_types=True on mixed tracers. This test verifies that when allow_mixed_types=True, the function permits tracers to have multiple measurement types without raising an error. + + :param sacc_galaxy_cells: Harmonic SACC data with named expectations. """ - sacc_data, _, _ = sacc_galaxy_cells + sacc_data = sacc_galaxy_cells.sacc_data # This should NOT raise an error even though src/lens tracers may have # mixed types from different measurement combinations @@ -747,14 +720,14 @@ def test_extract_all_measured_mixed_types_with_genuinely_mixed_tracers( def test_extract_all_measured_mixed_types_galaxy_only( - sacc_galaxy_cells_src0_src0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_src0_src0: SaccGalaxyHarmonicFixture, ) -> None: """Test extract_all_measured_types with allow_mixed_types=True on single type. This test verifies that tracers with only one measurement type work correctly with allow_mixed_types=True. """ - sacc_data, _ = sacc_galaxy_cells_src0_src0 + sacc_data = sacc_galaxy_cells_src0_src0.sacc_data result, _ = extract_all_measured_types(sacc_data, allow_mixed_types=True) @@ -763,14 +736,14 @@ def test_extract_all_measured_mixed_types_galaxy_only( def test_extract_all_measured_mixed_types_density_only( - sacc_galaxy_cells_lens0_lens0: tuple[sacc.Sacc, TomographicBin], + sacc_galaxy_cells_lens0_lens0: SaccGalaxyHarmonicFixture, ) -> None: """Test extract_all_measured_types with allow_mixed_types=True on density. Verifies that galaxy density (COUNTS) measurements work correctly with allow_mixed_types=True. """ - sacc_data, _ = sacc_galaxy_cells_lens0_lens0 + sacc_data = sacc_galaxy_cells_lens0_lens0.sacc_data result, _ = extract_all_measured_types(sacc_data, allow_mixed_types=True) @@ -779,19 +752,16 @@ def test_extract_all_measured_mixed_types_density_only( def test_extract_all_measured_mixed_types_mixed_real_space( - sacc_galaxy_xis_src0_lens0: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_xis_src0_lens0: SaccRealCrossBinFixture, ) -> None: """Test extract_all_measured_types with allow_mixed_types=True on real-space data. This test verifies behavior with real-space data (xi correlations) when mixed types are allowed. + + :param sacc_galaxy_xis_src0_lens0: Source-lens real SACC data and expectations. """ - sacc_data, _, _, _ = sacc_galaxy_xis_src0_lens0 + sacc_data = sacc_galaxy_xis_src0_lens0.sacc_data result, _ = extract_all_measured_types(sacc_data, allow_mixed_types=True) @@ -928,22 +898,17 @@ def test_extract_all_measured_mixed_types_multiple_measurements_same_tracer() -> def test_extract_all_measured_types_allow_mixed_types_vs_false( - sacc_galaxy_cells: tuple[ - sacc.Sacc, - dict[str, tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]], - dict[ - tuple[TracerNames, str], - tuple[npt.NDArray[np.int64], npt.NDArray[np.float64]], - ], - ], + sacc_galaxy_cells: SaccGalaxyHarmonicFixture, ) -> None: """Test the difference between allow_mixed_types=True and False. This test verifies that with allow_mixed_types=False, we may get an error (after potential auto-correction attempts), while with allow_mixed_types=True, we get results without error. + + :param sacc_galaxy_cells: Harmonic SACC data with named expectations. """ - sacc_data, _, _ = sacc_galaxy_cells + sacc_data = sacc_galaxy_cells.sacc_data # Try with allow_mixed_types=True - should work without error result_true = extract_all_measured_types(sacc_data, allow_mixed_types=True) diff --git a/tests/test_bug_413.py b/tests/test_bug_413.py index 40c44b724..9a7d64a44 100644 --- a/tests/test_bug_413.py +++ b/tests/test_bug_413.py @@ -2,8 +2,6 @@ from typing import Tuple -import numpy as np -import numpy.typing as npt import pyccl import sacc @@ -16,6 +14,7 @@ from firecrown.modeling_tools import ModelingTools from firecrown.models.two_point import calculate_pk from firecrown.updatable import get_default_params_map +from tests._types import SaccRealCrossBinFixture def make_twopoint_with_optional_systematics( @@ -79,17 +78,16 @@ def make_twopoint_with_optional_systematics( def test_calculate_pk( - sacc_galaxy_xis_lens0_lens1: tuple[ - sacc.Sacc, - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ], + sacc_galaxy_xis_lens0_lens1: SaccRealCrossBinFixture, ) -> None: + """Preserve power-spectrum symmetry when only one source has PT systematics. + + :param sacc_galaxy_xis_lens0_lens1: Lens-lens real SACC data and expectations. + """ # Set up a TwoPoint object in which the first source has a PT systematic # and the second source doe not have a PT systematic. - sacc_data, _, _, _ = sacc_galaxy_xis_lens0_lens1 + sacc_data = sacc_galaxy_xis_lens0_lens1.sacc_data a, b, _, tools = make_twopoint_with_optional_systematics(sacc_data, True, False) diff --git a/tests/test_modeling_tools_ccl_factory.py b/tests/test_modeling_tools_ccl_factory.py index af276c416..421a7cc04 100644 --- a/tests/test_modeling_tools_ccl_factory.py +++ b/tests/test_modeling_tools_ccl_factory.py @@ -21,6 +21,7 @@ CCLSplineParams, ModelingTools, MuSigmaModel, + PowerSpec, PoweSpecAmplitudeParameter, ) from firecrown.updatable import ParamsMap, get_default_params_map @@ -160,15 +161,17 @@ def fixture_ccl_spline_params( * (1 / (1 + (K_GRID / (0.1 * 0.05)) ** (3 * 0.96)) * A_GRID) ) -BACKGROUND = { +BACKGROUND: CCLCalculatorArgs = { "background": {"a": A_ARRAY, "chi": CHI_ARRAY, "h_over_h0": H_OVER_H0_ARRAY} } -PK_LINEAR = { +# Partial fragments: no existing schema describes a single calculator-argument +# key, and a new partial variant is out of scope, so keep the open mapping. +PK_LINEAR: dict[str, PowerSpec] = { "pk_linear": {"k": K_ARRAY, "a": A_ARRAY, "delta_matter:delta_matter": PK_ARRAY} } -PK_NONLIN = { +PK_NONLIN: dict[str, PowerSpec] = { "pk_nonlin": { "k": np.linspace(0.1, 1.0, 100), "a": np.linspace(0.1, 1.0, 100), diff --git a/tests/test_scale_cuts_with_window.py b/tests/test_scale_cuts_with_window.py index 297df7c07..c41f307c1 100644 --- a/tests/test_scale_cuts_with_window.py +++ b/tests/test_scale_cuts_with_window.py @@ -1,5 +1,6 @@ """Test that the scale cuts with bandpower windows work correctly.""" +from dataclasses import dataclass from pathlib import Path import numpy as np @@ -23,18 +24,39 @@ from firecrown.utils import base_model_from_yaml, upper_triangle_indices +@dataclass(frozen=True, kw_only=True) +class ScaleCutWindowFunction: + """Window weights, support multipoles, and geometric bin centers. + + :param weights: Column-normalized weights, one row per support multipole and + one column per bin. + :param support_ells: Integer multipoles on which the window is sampled. + :param bin_centers: Geometric means of adjacent bin edges, used as SACC + observation labels; not weighted means of the window support. + """ + + weights: npt.NDArray[np.float64] + support_ells: npt.NDArray[np.int64] + bin_centers: npt.NDArray[np.float64] + + @pytest.fixture(name="window_function_data", scope="module") -def fixture_window_function() -> ( - tuple[npt.NDArray[np.float64], npt.NDArray[np.int64], npt.NDArray[np.float64]] -): - """Generate window function data.""" +def fixture_window_function() -> ScaleCutWindowFunction: + """Generate a normalized window on 800 multipoles for five bins. + + :returns: Window weights, support multipoles, and geometric bin centers. + """ n_ell_bin = 5 ell_bin_edges = np.geomspace(10, 500, n_ell_bin + 1) - ell_bin_centers = np.sqrt(ell_bin_edges[:-1] * ell_bin_edges[1:]) + ell_bin_centers: npt.NDArray[np.float64] = np.sqrt( + ell_bin_edges[:-1] * ell_bin_edges[1:] + ) ell_bin_widths = np.diff(ell_bin_edges) - ell_window = np.arange(800) - window_function = np.zeros((ell_window.shape[0], n_ell_bin)) + ell_window: npt.NDArray[np.int64] = np.arange(800) + window_function: npt.NDArray[np.float64] = np.zeros( + (ell_window.shape[0], n_ell_bin) + ) for i, (mu_ell, sigma_ell) in enumerate(zip(ell_bin_centers, ell_bin_widths)): window_function[:, i] = np.exp( -0.5 * (ell_window - mu_ell) ** 2 / (sigma_ell) ** 2 @@ -42,41 +64,62 @@ def fixture_window_function() -> ( window_function = window_function / window_function.sum(axis=0, keepdims=True) - return window_function, ell_window, ell_bin_centers + return ScaleCutWindowFunction( + weights=window_function, + support_ells=ell_window, + bin_centers=ell_bin_centers, + ) + + +@dataclass(frozen=True, kw_only=True) +class ScaleCutBandpowerPrediction: + """CCL bandpowers used as SACC measurements and their scale-cut window. + + :param bandpowers: CCL predictions projected through the normalized window, + one value per bin, also used as the fixture's SACC measurements. + :param window: Shared normalized weights, support multipoles, and geometric + bin centers. + """ + + bandpowers: npt.NDArray[np.float64] + window: ScaleCutWindowFunction + + +@dataclass(frozen=True, kw_only=True) +class ScaleCutSaccFixture: + """Cosmic-shear SACC data with its input CCL bandpowers and cosmology. + + :param sacc_data: Windowed SACC measurements for production likelihood loading. + :param spectra: Input CCL bandpowers keyed by ordered tracer-pair names. + :param cosmology: Cosmology used to generate the CCL tracers and predictions. + """ + + sacc_data: sacc.Sacc + spectra: dict[str, ScaleCutBandpowerPrediction] + cosmology: ccl.Cosmology @pytest.fixture(name="minimal_3x2pt_sacc", scope="module") def fixture_minimal_3x2pt_sacc( - window_function_data: tuple[ - npt.NDArray[np.float64], npt.NDArray[np.int64], npt.NDArray[np.float64] - ], -) -> tuple[ - sacc.Sacc, - dict[ - str, - tuple[ - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.int64], - npt.NDArray[np.float64], - ], - ], - ccl.Cosmology, -]: - """Generate SACC data with window functions. - At the moment, this only adds cosmic shear data.""" + window_function_data: ScaleCutWindowFunction, +) -> ScaleCutSaccFixture: + """Generate SACC data with window functions for cosmic shear only. + + :param window_function_data: Window weights, support, and observation centers. + :returns: SACC data, input CCL bandpowers with window data, and cosmology. + """ sacc_data = sacc.Sacc() z = (np.linspace(0, 4.0, 256) + 0.05).astype(np.float64) src_bins_centers = np.linspace(0.25, 0.75, 2) - ccl_tracers = {} - ccl_cell = {} + ccl_tracers: dict[str, ccl.WeakLensingTracer] = {} + ccl_cell: dict[str, ScaleCutBandpowerPrediction] = {} cosmo = ccl.CosmologyVanillaLCDM() for i, mn in enumerate(src_bins_centers): - dndz = np.exp(-0.5 * (z - mn) ** 2 / 0.05**2) + dndz: npt.NDArray[np.float64] = np.exp(-0.5 * (z - mn) ** 2 / 0.05**2) sacc_data.add_tracer("NZ", f"src{i}", z, dndz) ccl_tracers[f"src{i}"] = ccl.WeakLensingTracer( cosmo=cosmo, @@ -84,32 +127,32 @@ def fixture_minimal_3x2pt_sacc( ) for i, j in upper_triangle_indices(len(src_bins_centers)): - window = sacc.BandpowerWindow(window_function_data[1], window_function_data[0]) - Cell = ccl.angular_cl( + window = sacc.BandpowerWindow( + window_function_data.support_ells, window_function_data.weights + ) + Cell: npt.NDArray[np.float64] = ccl.angular_cl( cosmo=cosmo, tracer1=ccl_tracers[f"src{i}"], tracer2=ccl_tracers[f"src{j}"], - ell=window_function_data[1], + ell=window_function_data.support_ells, ) - Cell_binned = window_function_data[0].T @ Cell + Cell_binned: npt.NDArray[np.float64] = window_function_data.weights.T @ Cell sacc_data.add_ell_cl( data_type="galaxy_shear_cl_ee", tracer1=f"src{i}", tracer2=f"src{j}", - ell=window_function_data[2], + ell=window_function_data.bin_centers, x=Cell_binned, window=window, ) - ccl_cell[f"src{i}-src{j}"] = ( - Cell_binned, - window_function_data[2], - window_function_data[1], - window_function_data[0], + ccl_cell[f"src{i}-src{j}"] = ScaleCutBandpowerPrediction( + bandpowers=Cell_binned, + window=window_function_data, ) sacc_data.add_covariance(np.identity(len(sacc_data)) * 0.01) - return sacc_data, ccl_cell, cosmo + return ScaleCutSaccFixture(sacc_data=sacc_data, spectra=ccl_cell, cosmology=cosmo) @pytest.fixture( @@ -137,24 +180,19 @@ def fixture_cut(request: pytest.FixtureRequest) -> tuple[str, str, int]: def test_scale_cuts_with_bandpower_window_label( - minimal_3x2pt_sacc: tuple[ - sacc.Sacc, - dict[ - str, - tuple[ - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.int64], - npt.NDArray[np.float64], - ], - ], - ccl.Cosmology, - ], + minimal_3x2pt_sacc: ScaleCutSaccFixture, cut: tuple[str, str, int], tmp_path: Path, ) -> None: - """Test that the scale cuts with bandpower windows work correctly.""" - sacc_data, ccl_cell, cosmo = minimal_3x2pt_sacc + """Test scale cuts selected by bandpower window labels. + + :param minimal_3x2pt_sacc: SACC data, input CCL bandpowers, and cosmology. + :param cut: Ordered tracer names and upper multipole threshold. + :param tmp_path: Directory for the SACC file loaded by the likelihood factory. + """ + sacc_data = minimal_3x2pt_sacc.sacc_data + ccl_cell = minimal_3x2pt_sacc.spectra + cosmo = minimal_3x2pt_sacc.cosmology tp_factory = base_model_from_yaml(TwoPointFactory, two_point_yaml) @@ -204,8 +242,12 @@ def test_scale_cuts_with_bandpower_window_label( ccl_cell_cut_data_vector = np.concatenate( [ - cell if name != f"{cut[0]}-{cut[1]}" else cell[window_ell < cut[2]] - for name, (cell, window_ell, _, _) in ccl_cell.items() + ( + spectrum.bandpowers + if name != f"{cut[0]}-{cut[1]}" + else spectrum.bandpowers[spectrum.window.bin_centers < cut[2]] + ) + for name, spectrum in ccl_cell.items() ] ) # Check that the shapes match (i.e. that the correct data points are selected) @@ -223,25 +265,21 @@ def test_scale_cuts_with_bandpower_window_label( ], ) def test_scale_cuts_with_bandpower_window_support( - minimal_3x2pt_sacc: tuple[ - sacc.Sacc, - dict[ - str, - tuple[ - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.int64], - npt.NDArray[np.float64], - ], - ], - ccl.Cosmology, - ], + minimal_3x2pt_sacc: ScaleCutSaccFixture, cut: tuple[str, str, int], method: tuple[TwoPointFilterMethod, float], tmp_path: Path, ) -> None: - """Test that the scale cuts with bandpower windows work correctly.""" - sacc_data, ccl_cell, cosmo = minimal_3x2pt_sacc + """Test scale cuts selected by cumulative bandpower window support. + + :param minimal_3x2pt_sacc: SACC data, input CCL bandpowers, and cosmology. + :param cut: Ordered tracer names and upper multipole threshold. + :param method: Filter method and required fraction of window support. + :param tmp_path: Directory for the SACC file loaded by the likelihood factory. + """ + sacc_data = minimal_3x2pt_sacc.sacc_data + ccl_cell = minimal_3x2pt_sacc.spectra + cosmo = minimal_3x2pt_sacc.cosmology tp_factory = base_model_from_yaml(TwoPointFactory, two_point_yaml) @@ -292,11 +330,16 @@ def test_scale_cuts_with_bandpower_window_support( ccl_cell_cut_data_vector = np.concatenate( [ ( - cell + spectrum.bandpowers if name != f"{cut[0]}-{cut[1]}" - else cell[window[ell < cut[2]].sum(axis=0) >= method[1]] + else spectrum.bandpowers[ + spectrum.window.weights[spectrum.window.support_ells < cut[2]].sum( + axis=0 + ) + >= method[1] + ] ) - for name, (cell, _, ell, window) in ccl_cell.items() + for name, spectrum in ccl_cell.items() ] ) # Check that the shapes match (i.e. that the correct data points are selected) diff --git a/tests/test_sync_deps_cli.py b/tests/test_sync_deps_cli.py index 0b93e5219..11ee11161 100644 --- a/tests/test_sync_deps_cli.py +++ b/tests/test_sync_deps_cli.py @@ -2,6 +2,7 @@ from __future__ import annotations +from dataclasses import dataclass import hashlib from pathlib import Path import shutil @@ -20,6 +21,24 @@ ] +@dataclass(frozen=True, kw_only=True) +class RequirementCase: + """Identify a manifest requirement and its selected lock route. + + Field names clarify roles but cannot statically distinguish swapped strings. + + :param group: Manifest group containing the requirement. + :param identity: Logical manifest identity, independent of the locked name. + :param locked_name: Package name selected in the lock for the given manager. + :param manager: Installation manager for that locked selection. + """ + + group: str + identity: str + locked_name: str + manager: str + + def _run_cli(root: Path, *args: str) -> subprocess.CompletedProcess[str]: """Run the copied production script against the isolated repository. @@ -439,18 +458,45 @@ def test_cli_check_rejects_wrong_python_identity( @pytest.mark.parametrize( "requirement", [ - ("runtime", "sample", "sample-conda", "conda"), - ("runtime", "pip-runtime", "pip_runtime", "pip"), - ("workarounds", "workaround", "workaround-conda", "conda"), - ("workarounds", "pip-workaround", "pip_workaround", "pip"), - ("devenv", "dev-tool", "dev-tool-conda", "conda"), - ("devenv", "pip-dev", "pip_dev", "pip"), + RequirementCase( + group="runtime", + identity="sample", + locked_name="sample-conda", + manager="conda", + ), + RequirementCase( + group="runtime", + identity="pip-runtime", + locked_name="pip_runtime", + manager="pip", + ), + RequirementCase( + group="workarounds", + identity="workaround", + locked_name="workaround-conda", + manager="conda", + ), + RequirementCase( + group="workarounds", + identity="pip-workaround", + locked_name="pip_workaround", + manager="pip", + ), + RequirementCase( + group="devenv", + identity="dev-tool", + locked_name="dev-tool-conda", + manager="conda", + ), + RequirementCase( + group="devenv", identity="pip-dev", locked_name="pip_dev", manager="pip" + ), ], ) def test_cli_check_validates_each_requirement_in_each_environment( locked_repository: Path, environment: tuple[str, str], - requirement: tuple[str, str, str, str], + requirement: RequirementCase, ) -> None: """Compatible selections elsewhere cannot mask one incompatible selection. @@ -459,11 +505,10 @@ def test_cli_check_validates_each_requirement_in_each_environment( :param requirement: Group, logical identity, locked name and manager to constrain. """ python, platform = environment - group, identity, name, manager = requirement manifest_path = locked_repository / "dependencies.yaml" manifest = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) - for entry in manifest[group]: - if entry["name"] == identity: + for entry in manifest[requirement.group]: + if entry["name"] == requirement.identity: entry["version"] = ">=1,<2" manifest_path.write_text( yaml.safe_dump(manifest, sort_keys=False), encoding="utf-8" @@ -473,12 +518,21 @@ def test_cli_check_validates_each_requirement_in_each_environment( compatible = _run_cli(locked_repository, "--check") assert compatible.returncode == 0, compatible.stderr assert _snapshot(locked_repository) == before - _set_locked_version(locked_repository, environment, name, manager, "0.9") + _set_locked_version( + locked_repository, + environment, + requirement.locked_name, + requirement.manager, + "0.9", + ) before = _snapshot(locked_repository) incompatible = _run_cli(locked_repository, "--check") assert incompatible.returncode == 1 assert f"Python {python} / {platform}" in incompatible.stderr - assert f"{group} requirement {identity} ({manager}:{name})" in incompatible.stderr + assert ( + f"{requirement.group} requirement {requirement.identity} " + f"({requirement.manager}:{requirement.locked_name})" + ) in incompatible.stderr assert "locked 0.9, requires >=1,<2" in incompatible.stderr assert _snapshot(locked_repository) == before