Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 57 additions & 13 deletions scripts/xip_xim.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def params_default():

params = {
"input_path": "shape_catalog_ngmix.fits",
"tomo_bin1": None,
"tomo_bin2": None,
"key_ra": "RA",
"key_dec": "DEC",
"key_e1": "e1",
Expand All @@ -30,20 +32,27 @@ def params_default():
"theta_max": 200,
"n_theta": 20,
"output_path": "./xip_xim.txt",
"key_tomo_bin_col": "tomo_bin_id",
}

short_options = {
"input_path": "-i",
"output_path": "-o",
"tomo_bin1": "-b1",
"tomo_bin2": "-b2",
}

types = {
"sign_e1": "int",
"sign_e2": "int",
"tomo_bin1": "int",
"tomo_bin2": "int",
}

help_strings = {
"input_path": "shear catalogue input path, default={}",
"tomo_bin1": "First tomographic bin, default={} (non-tomographic)",
"tomo_bin2": "Second tomographic bin, default={} (non-tomographic)",
"key_ra": "column name for right ascension, default={}",
"key_dec": "column name for declination, default={}",
"key_e1": "column name for ellipticity component 1, default={}",
Expand All @@ -54,6 +63,7 @@ def params_default():
"theta_max": "maximum angular scale [arcmin], default={}",
"n_theta": "number of angular scales, default={}",
"output_path": "output path, default={}",
"key_tomo_bin_col": "column name for tomography bin, default={}",
}

return params, short_options, types, help_strings
Expand Down Expand Up @@ -132,18 +142,52 @@ def main(argv=None):
"Signs for ellipticity components ="
+ f" ({params['sign_e1']:+d}, {params['sign_e2']:+d})"
)
g1 = data[params["key_e1"]] * params["sign_e1"]
g2 = data[params["key_e2"]] * params["sign_e2"]
cat = treecorr.Catalog(
ra=data[params["key_ra"]],
dec=data[params["key_dec"]],
g1=g1,
g2=g2,
w=data["w"],
ra_units=coord_units,
dec_units=coord_units,
)

tomographic = params["tomo_bin1"] is not None and params["tomo_bin2"] is not None
cat2 = None
if tomographic:
if params["verbose"]:
print(
f"Calculating 2PCF for tomographic bins {params['tomo_bin1']} and {params['tomo_bin2']}"
)
tomo_bin1_idx = data[params["key_tomo_bin_col"]] == params["tomo_bin1"]
tomo_bin2_idx = data[params["key_tomo_bin_col"]] == params["tomo_bin2"]

g1 = data[params["key_e1"]] * params["sign_e1"]
g2 = data[params["key_e2"]] * params["sign_e2"]

cat1 = treecorr.Catalog(
ra=data[params["key_ra"]][tomo_bin1_idx],
dec=data[params["key_dec"]][tomo_bin1_idx],
g1=g1[tomo_bin1_idx],
g2=g2[tomo_bin1_idx],
w=data["w"][tomo_bin1_idx],
ra_units=coord_units,
dec_units=coord_units,
)
if params["tomo_bin1"] != params["tomo_bin2"]:
cat2 = treecorr.Catalog(
ra=data[params["key_ra"]][tomo_bin2_idx],
dec=data[params["key_dec"]][tomo_bin2_idx],
g1=g1[tomo_bin2_idx],
g2=g2[tomo_bin2_idx],
w=data["w"][tomo_bin2_idx],
ra_units=coord_units,
dec_units=coord_units,
)
else:
if params["verbose"]:
print("Calculating non-tomographic 2PCF")
g1 = data[params["key_e1"]] * params["sign_e1"]
g2 = data[params["key_e2"]] * params["sign_e2"]
cat1 = treecorr.Catalog(
ra=data[params["key_ra"]],
dec=data[params["key_dec"]],
g1=g1,
g2=g2,
w=data["w"],
ra_units=coord_units,
dec_units=coord_units,
)
# Set treecorr config info for correlation
sep_units = "arcmin"
TreeCorrConfig = {
Expand All @@ -159,7 +203,7 @@ def main(argv=None):
# Compute correlation
if params["verbose"]:
print("Correlating...")
gg.process(cat, cat)
gg.process(cat1, cat2=cat2)

# Write to file
if params["verbose"]:
Expand Down
92 changes: 58 additions & 34 deletions src/sp_validation/cosmo_val/cosebis.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def calculate_cosebis(
cov_path=None,
scale_cuts=None,
evaluate_all_scale_cuts=False,
compute_tomography=False,
min_sep=None,
max_sep=None,
nbins=None,
Expand Down Expand Up @@ -68,6 +69,8 @@ def calculate_cosebis(
If True, evaluates COSEBIs for all possible scale cut combinations
using the reporting binning parameters. Ignored when scale_cuts is
provided. Defaults to False.
compute_tomography : bool, optional
If True, computes COSEBIs for all tomographic bin combinations. Defaults to False.s
min_sep : float, optional
Minimum separation for reporting binning (only used when
evaluate_all_scale_cuts=True). Defaults to self.treecorr_config["min_sep"].
Expand Down Expand Up @@ -99,44 +102,63 @@ def calculate_cosebis(
f"Computing fine-binned 2PCF with {nbins_int} bins from {min_sep_int} to "
f"{max_sep_int} arcmin"
)
gg = self.calculate_2pcf(version, npatch=npatch, **treecorr_config)

if scale_cuts is not None:
# Explicit scale cuts provided
print(f"Evaluating {len(scale_cuts)} explicit scale cuts")
results = calculate_cosebis(
gg=gg, nmodes=nmodes, scale_cuts=scale_cuts, cov_path=cov_path
)
elif evaluate_all_scale_cuts:
# Use reporting binning parameters or inherit from class config
binning = self._binning(min_sep, max_sep, nbins)
min_sep, max_sep, nbins = (
binning["min_sep"],
binning["max_sep"],
binning["nbins"],
)
ggs = self.calculate_2pcf(
version,
npatch=npatch,
compute_tomography=compute_tomography,
**treecorr_config,
)
results = {
bin_key: None for bin_key in ggs.keys()
} # Initialize results dictionary

# Generate scale cuts using np.geomspace (no TreeCorr needed)
bin_edges = np.geomspace(min_sep, max_sep, nbins + 1)
generated_cuts = [
(bin_edges[start], bin_edges[stop])
for start in range(nbins)
for stop in range(start + 1, nbins + 1)
]
for bin_key in ggs.keys():
# LG TO-DO: account for tomographic scale-cuts
if scale_cuts is not None:
# Explicit scale cuts provided
print(f"Evaluating {len(scale_cuts)} explicit scale cuts")
results[bin_key] = calculate_cosebis(
gg=ggs[bin_key],
nmodes=nmodes,
scale_cuts=scale_cuts,
cov_path=cov_path,
)
elif evaluate_all_scale_cuts:
# Use reporting binning parameters or inherit from class config
binning = self._binning(min_sep, max_sep, nbins)
min_sep, max_sep, nbins = (
binning["min_sep"],
binning["max_sep"],
binning["nbins"],
)

print(f"Evaluating {len(generated_cuts)} scale cut combinations")
# Generate scale cuts using np.geomspace (no TreeCorr needed)
bin_edges = np.geomspace(min_sep, max_sep, nbins + 1)
generated_cuts = [
(bin_edges[start], bin_edges[stop])
for start in range(nbins)
for stop in range(start + 1, nbins + 1)
]

# Call b_modes function with scale cuts list
results = calculate_cosebis(
gg=gg, nmodes=nmodes, scale_cuts=generated_cuts, cov_path=cov_path
)
else:
# Single scale cut behavior: use full range
results = calculate_cosebis(
gg=gg, nmodes=nmodes, scale_cuts=None, cov_path=cov_path
)
# Extract single results dict from scale_cuts dictionary
results = next(iter(results.values()))
print(f"Evaluating {len(generated_cuts)} scale cut combinations")

# Call b_modes function with scale cuts list
results = calculate_cosebis(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rebinding clobbers the accumulator dict initialized above (results = {bin_key: None …}), and then line 161's results[bin_key] = results self-references — even the plain non-tomo single-scale-cut case returns a mangled dict. A differently-named inner variable (res = calculate_cosebis(...); results[bin_key] = res) should fix it — same in the else branch below.

gg=ggs[bin_key],
nmodes=nmodes,
scale_cuts=generated_cuts,
cov_path=cov_path,
)
else:
# Single scale cut behavior: use full range
results = calculate_cosebis(
gg=ggs[bin_key], nmodes=nmodes, scale_cuts=None, cov_path=cov_path
)
# Extract single results dict from scale_cuts dictionary
results = next(iter(results.values()))

results[bin_key] = results # Store results for this bin_key

return results

Expand All @@ -152,6 +174,7 @@ def plot_cosebis(
cov_path=None,
scale_cuts=None, # Explicit scale cuts
evaluate_all_scale_cuts=False, # Grid-based scale cuts
compute_tomography=False,
min_sep=None,
max_sep=None,
nbins=None, # Reporting binning
Expand Down Expand Up @@ -228,6 +251,7 @@ def plot_cosebis(
cov_path=cov_path,
scale_cuts=scale_cuts,
evaluate_all_scale_cuts=evaluate_all_scale_cuts,
compute_tomography=False, # LG: Hardcoded to False for now

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine to leave for the future PR — just noting plot_cosebis also still assumes the old un-binned return shape of calculate_cosebis (results are now one level deeper, even non-tomographically), so COSEBIs plotting is broken until that pass; worth a TODO so it's not a surprise.

min_sep=min_sep,
max_sep=max_sep,
nbins=nbins,
Expand Down
41 changes: 30 additions & 11 deletions src/sp_validation/cosmo_val/pure_eb.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def calculate_pure_eb(
max_sep_int=300,
nbins_int=100,
npatch=256,
compute_tomography=False,
var_method="jackknife",
cov_path_int=None,
cosmo_cov=None,
Expand Down Expand Up @@ -61,6 +62,8 @@ def calculate_pure_eb(
npatch : int, optional
Number of patches for the jackknife or bootstrap resampling. Defaults to
the value in self.npatch if not provided.
compute_tomography : bool, optional
Whether to compute tomographic (cross-bin) pure E/B modes. Defaults to False.
var_method : str, optional
Variance estimation method. Defaults to "jackknife".
cov_path_int : str, optional
Expand Down Expand Up @@ -109,26 +112,42 @@ def calculate_pure_eb(
treecorr_config_int = self._binning(min_sep_int, max_sep_int, nbins_int)

# Calculate correlation functions
gg = self.calculate_2pcf(version, npatch=npatch, **treecorr_config)
gg_int = self.calculate_2pcf(version, npatch=npatch, **treecorr_config_int)
ggs = self.calculate_2pcf(
version,
npatch=npatch,
compute_tomography=compute_tomography,
**treecorr_config,
)
ggs_int = self.calculate_2pcf(
version,
npatch=npatch,
compute_tomography=compute_tomography,
**treecorr_config_int,
)

# Get redshift distribution if using analytic covariance
# LG TO-DO: check tomographic redshift distribution handling
z_dist = (
np.column_stack(self.get_redshift(version))
if cov_path_int is not None
else None
)

# Delegate to b_modes module
results = calculate_pure_eb_correlation(
gg=gg,
gg_int=gg_int,
var_method=var_method,
cov_path_int=cov_path_int,
cosmo_cov=cosmo_cov,
n_samples=n_samples,
z_dist=z_dist,
)
results = {
bin_key: None for bin_key in ggs.keys()
} # Initialize results dictionary

for bin_key in ggs.keys():
results[bin_key] = calculate_pure_eb_correlation(
gg=ggs[bin_key],
gg_int=ggs_int[bin_key],
var_method=var_method,
cov_path_int=cov_path_int,
cosmo_cov=cosmo_cov,
n_samples=n_samples,
z_dist=z_dist,
)

return results

Expand Down
Loading
Loading