diff --git a/crow/__init__.py b/crow/__init__.py index 0dc6f45..2effa7a 100644 --- a/crow/__init__.py +++ b/crow/__init__.py @@ -8,4 +8,4 @@ from .recipes.binned_grid import GridBinnedClusterRecipe from .recipes.binned_parent import BinnedClusterRecipe -__version__ = "1.0.2" +__version__ = "1.0.4" diff --git a/crow/recipes/binned_exact.py b/crow/recipes/binned_exact.py index 1f2dbe1..2982dfa 100644 --- a/crow/recipes/binned_exact.py +++ b/crow/recipes/binned_exact.py @@ -308,9 +308,10 @@ def evaluate_theory_prediction_lensing_profile( self, z_edges, log_proxy_edges, - radius_centers, + distance_centers, sky_area: float, average_on: None | ClusterProperty = None, + distance_units: str = "mpc", ) -> float: """Evaluate the theory prediction for this cluster recipe. @@ -320,7 +321,20 @@ def evaluate_theory_prediction_lensing_profile( """ assert len(log_proxy_edges) == 2, "log_proxy_edges should be size 2" assert len(z_edges) == 2, "z_edges should be size 2" - + if distance_units.lower() == "arcmin": + distance_centers_rad = distance_centers * np.pi / (180.0 * 60.0) + z_bin_mean = (z_edges[1] + z_edges[0]) / 2.0 + a = 1.0 / (1.0 + z_bin_mean) + radius_centers = ( + self.cluster_theory.cosmo.angular_diameter_distance(a) + * distance_centers_rad + ) + elif distance_units.lower() == "mpc": + radius_centers = distance_centers + else: + raise ValueError( + f"Unknown distance_units='{distance_units}'. Expected 'arcmin' or 'mpc'." + ) if self.purity == None: self.integrator.integral_bounds = [ self.mass_interval, diff --git a/crow/recipes/binned_grid.py b/crow/recipes/binned_grid.py index 20e1ebd..57188fe 100644 --- a/crow/recipes/binned_grid.py +++ b/crow/recipes/binned_grid.py @@ -357,14 +357,28 @@ def evaluate_theory_prediction_lensing_profile( self, z_edges: tuple[float, float], log_proxy_edges: tuple[float, float], - radius_centers: np.ndarray, + distance_centers: np.ndarray, sky_area: float, average_on: None | ClusterProperty = None, + distance_units: str = "mpc", ) -> float: r"""Evaluate the theoretical prediction for the average lensing profile (..:math:`\langle\Delta\Sigma(R)\rangle` or ..:math:`\langle g_t(R)\rangle`) in the provided bin.""" - + if distance_units.lower() == "arcmin": + distance_centers_rad = distance_centers * np.pi / (180.0 * 60.0) + z_bin_mean = (z_edges[1] + z_edges[0]) / 2.0 + a = 1.0 / (1.0 + z_bin_mean) + radius_centers = ( + self.cluster_theory.cosmo.angular_diameter_distance(a) + * distance_centers_rad + ) + elif distance_units.lower() == "mpc": + radius_centers = distance_centers + else: + raise ValueError( + f"Unknown distance_units='{distance_units}'. Expected 'arcmin' or 'mpc'." + ) if not (average_on & (ClusterProperty.DELTASIGMA | ClusterProperty.SHEAR)): # Raise a ValueError if the necessary flags are not present raise ValueError( diff --git a/crow/recipes/binned_parent.py b/crow/recipes/binned_parent.py index 226f626..ad5531f 100644 --- a/crow/recipes/binned_parent.py +++ b/crow/recipes/binned_parent.py @@ -97,9 +97,10 @@ def evaluate_theory_prediction_lensing_profile( self, z_edges, mass_proxy_edges, - radius_centers, + distance_centers, sky_area: float, average_on: None | ClusterProperty = None, + distance_units: str = "mpc", ) -> float: """Evaluate the theory prediction for this cluster recipe. diff --git a/tests/test_recipe_binned_shear_profile.py b/tests/test_recipe_binned_shear_profile.py index 8437f5d..8c3c57f 100644 --- a/tests/test_recipe_binned_shear_profile.py +++ b/tests/test_recipe_binned_shear_profile.py @@ -255,6 +255,58 @@ def test_evaluates_theory_prediction_returns_value( assert prediction_c > 0 +def test_evaluates_theory_prediction_different_bins( + binned_exact_deltasigma: ExactBinnedClusterRecipe, + binned_grid_gt: GridBinnedClusterRecipe, +): + + mass_proxy_edges = (2, 5) + mass_proxy_edges_err = (2, 5, 6) + z_edges = (0.5, 1) + z_edges_err = (0.5, 1.0, 1.2) + radius_center = np.atleast_1d(1.5) + sky_area = 360**2 + average_on = ClusterProperty.DELTASIGMA + + z_bin_mean = (z_edges[1] + z_edges[0]) / 2.0 + a = 1.0 / (1.0 + z_bin_mean) + angular_center_arcmin = ( + radius_center + / binned_exact_deltasigma.cluster_theory.cosmo.angular_diameter_distance(a) + * 180.0 + / np.pi + * 60.0 + ) + # test exact deltasigma + prediction_rad = binned_exact_deltasigma.evaluate_theory_prediction_lensing_profile( + z_edges, mass_proxy_edges, radius_center, sky_area, average_on, "mpc" + ) + prediction_ang = binned_exact_deltasigma.evaluate_theory_prediction_lensing_profile( + z_edges, mass_proxy_edges, angular_center_arcmin, sky_area, average_on, "arcmin" + ) + rel_tol = 1.0e-4 + assert np.all(np.abs(prediction_rad - prediction_ang) < rel_tol) + # test grid reduced shear + average_on = ClusterProperty.SHEAR + prediction_rad = binned_grid_gt.evaluate_theory_prediction_lensing_profile( + z_edges, mass_proxy_edges, radius_center, sky_area, average_on, "mpc" + ) + prediction_ang = binned_grid_gt.evaluate_theory_prediction_lensing_profile( + z_edges, mass_proxy_edges, angular_center_arcmin, sky_area, average_on, "arcmin" + ) + rel_tol = 1.0e-4 + assert np.all(np.abs(prediction_rad - prediction_ang) < rel_tol) + + with pytest.raises(ValueError, match="Unknown distance_units='rad'"): + binned_exact_deltasigma.evaluate_theory_prediction_lensing_profile( + z_edges, mass_proxy_edges, radius_center, sky_area, average_on, "rad" + ) + with pytest.raises(ValueError, match="Unknown distance_units='rad'"): + binned_grid_gt.evaluate_theory_prediction_lensing_profile( + z_edges, mass_proxy_edges, radius_center, sky_area, average_on, "rad" + ) + + def test_grid_shear_matches_exact_within_tolerance( binned_exact_deltasigma: ExactBinnedClusterRecipe, binned_grid_deltasigma: GridBinnedClusterRecipe,