Source code for firecrown.likelihood.gauss_family.statistic.binned_cluster_number_counts
"""This module holds classes needed to predict the binned cluster number counts.
The binned cluster number counts statistic predicts the number of galaxy
clusters within a single redshift and mass bin.
"""
from __future__ import annotations
from typing import Optional
import numpy as np
import sacc
from firecrown.likelihood.gauss_family.statistic.source.source import SourceSystematic
from firecrown.likelihood.gauss_family.statistic.statistic import (
DataVector,
Statistic,
TheoryVector,
)
from firecrown.modeling_tools import ModelingTools
from firecrown.models.cluster.abundance_data import AbundanceData
from firecrown.models.cluster.binning import SaccBin
from firecrown.models.cluster.properties import ClusterProperty
from firecrown.models.cluster.recipes.cluster_recipe import ClusterRecipe
[docs]class BinnedClusterNumberCounts(Statistic):
"""The Binned Cluster Number Counts statistic.
This class will make a prediction for the number of clusters in a z, mass bin
and compare that prediction to the data provided in the sacc file.
"""
def __init__(
self,
cluster_properties: ClusterProperty,
survey_name: str,
cluster_recipe: ClusterRecipe,
systematics: Optional[list[SourceSystematic]] = None,
):
super().__init__()
self.systematics = systematics or []
self.theory_vector: Optional[TheoryVector] = None
self.cluster_properties = cluster_properties
self.survey_name = survey_name
self.cluster_recipe = cluster_recipe
self.data_vector = DataVector.from_list([])
self.sky_area = 0.0
self.bins: list[SaccBin] = []
[docs] def read(self, sacc_data: sacc.Sacc) -> None:
"""Read the data for this statistic and mark it as ready for use."""
# Build the data vector and indices needed for the likelihood
if self.cluster_properties == ClusterProperty.NONE:
raise ValueError("You must specify at least one cluster property.")
sacc_adapter = AbundanceData(sacc_data)
self.sky_area = sacc_adapter.get_survey_tracer(self.survey_name).sky_area
data, indices = sacc_adapter.get_observed_data_and_indices_by_survey(
self.survey_name, self.cluster_properties
)
self.data_vector = DataVector.from_list(data)
self.sacc_indices = np.array(indices)
self.bins = sacc_adapter.get_bin_edges(
self.survey_name, self.cluster_properties
)
for bin_edge in self.bins:
if bin_edge.dimension != self.bins[0].dimension:
raise ValueError(
"The cluster number counts statistic requires all bins to be the "
"same dimension."
)
super().read(sacc_data)
[docs] def get_data_vector(self) -> DataVector:
"""Gets the statistic data vector."""
assert self.data_vector is not None
return self.data_vector
[docs] def _compute_theory_vector(self, tools: ModelingTools) -> TheoryVector:
"""Compute a statistic from sources, concrete implementation."""
assert tools.cluster_abundance is not None
theory_vector_list: list[float] = []
cluster_counts = []
cluster_counts = self.get_binned_cluster_counts(tools)
for cl_property in ClusterProperty:
include_prop = cl_property & self.cluster_properties
if not include_prop:
continue
if cl_property == ClusterProperty.COUNTS:
theory_vector_list += cluster_counts
continue
theory_vector_list += self.get_binned_cluster_property(
tools, cluster_counts, cl_property
)
return TheoryVector.from_list(theory_vector_list)
[docs] def get_binned_cluster_property(
self,
tools: ModelingTools,
cluster_counts: list[float],
cluster_properties: ClusterProperty,
) -> list[float]:
"""Computes the mean mass of clusters in each bin.
Using the data from the sacc file, this function evaluates the likelihood for
a single point of the parameter space, and returns the predicted mean mass of
the clusters in each bin.
"""
assert tools.cluster_abundance is not None
mean_values = []
for this_bin, counts in zip(self.bins, cluster_counts):
total_observable = self.cluster_recipe.evaluate_theory_prediction(
tools.cluster_abundance, this_bin, self.sky_area, cluster_properties
)
cluster_counts.append(counts)
mean_observable = total_observable / counts
mean_values.append(mean_observable)
return mean_values
[docs] def get_binned_cluster_counts(self, tools: ModelingTools) -> list[float]:
"""Computes the number of clusters in each bin.
Using the data from the sacc file, this function evaluates the likelihood for
a single point of the parameter space, and returns the predicted number of
clusters in each bin.
"""
assert tools.cluster_abundance is not None
cluster_counts = []
for this_bin in self.bins:
counts = self.cluster_recipe.evaluate_theory_prediction(
tools.cluster_abundance, this_bin, self.sky_area
)
cluster_counts.append(counts)
return cluster_counts