Skip to content

Commit c4ef573

Browse files
Merge pull request #163 from martinkilbinger/binned_masks
Binned masks
2 parents 6f6d826 + 8983187 commit c4ef573

3 files changed

Lines changed: 223 additions & 2 deletions

File tree

notebooks/demo_binned_mask.py

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# %%
2+
from IPython import get_ipython
3+
4+
# %%
5+
# enable autoreload for interactive sessions
6+
ipython = get_ipython()
7+
if ipython is not None:
8+
ipython.run_line_magic("load_ext", "autoreload")
9+
ipython.run_line_magic("autoreload", "2")
10+
ipython.run_line_magic("load_ext", "log_cell_time")
11+
# %%
12+
if ipython is not None:
13+
ipython.run_line_magic("matplotlib", "inline")
14+
15+
# %%
16+
import sys
17+
import os
18+
import numpy as np
19+
from astropy.io import fits
20+
import matplotlib.pylab as plt
21+
import healpy as hp
22+
import healsparse as hsp
23+
24+
from cs_util import plots as cs_plots
25+
from cs_util import cat as cs_cat
26+
27+
from sp_validation import run_joint_cat as sp_joint
28+
from sp_validation import util
29+
from sp_validation.basic import metacal
30+
from sp_validation import calibration
31+
import sp_validation.cat as cat
32+
33+
# %%
34+
# Initialize calibration class instance (for config and data)
35+
obj = sp_joint.CalibrateCat()
36+
37+
# %%
38+
# Read configuration file and set parameters
39+
config = obj.read_config_set_params("config_mask.yaml")
40+
41+
# %%
42+
# Get data. Set load_into_memory to False for very large files
43+
dat, dat_ext = obj.read_cat(load_into_memory=False)
44+
# %%
45+
# Additional parameters
46+
key_ra = "RA"
47+
key_dec = "Dec"
48+
49+
nside_min = 512
50+
nside_max = 16384
51+
52+
# %%
53+
# Create healsparse mask instance
54+
hsp_obj = sp_joint.ApplyHspMasks()
55+
56+
# %% Mask directory and aux mask file(s)
57+
hsp_obj._params["mask_dir"] = f"{os.environ['HOME']}/masks"
58+
hsp_obj._params["aux_mask_files"] = f"{hsp_obj._params['mask_dir']}/mask_r_nside131072_npoint.hsp"
59+
hsp_obj._params["aux_mask_labels"] = "npoint3"
60+
hsp_obj._params["verbose"] = True
61+
62+
# %%
63+
# Masks to use
64+
65+
# Bits
66+
hsp_obj._params["bits"] = 1+2+4+8+64+1024
67+
68+
# Index of base mask (e.g., coverage mask)
69+
label_base_mask = "npoint3"
70+
#label_base_mask = ""
71+
72+
# Names
73+
masks_to_apply = [
74+
"npoint3",
75+
"1_Faint_star_halos",
76+
"2_Bright_star_halos",
77+
"4_Stars",
78+
"8_Manual",
79+
"64_r",
80+
"1024_Maximask",
81+
]
82+
83+
# Load and initialise masks
84+
masks, labels = sp_joint.get_masks_from_config(
85+
config,
86+
dat,
87+
dat_ext,
88+
masks_to_apply=masks_to_apply,
89+
verbose=True
90+
)
91+
92+
# %%
93+
# if base mask: apply to all other masks
94+
if label_base_mask != "":
95+
96+
print(f"Applying base mask {label_base_mask} to all other masks:")
97+
98+
# Find base mask
99+
for mask in masks:
100+
if mask._col_name == label_base_mask:
101+
base_mask = mask._mask
102+
break
103+
104+
# Mask all others
105+
for mask in masks:
106+
if mask._col_name != label_base_mask:
107+
mask._mask = mask._mask & base_mask
108+
print(mask._col_name, "#True = ", sum(mask._mask), f"({100*sum(mask._mask)/len(mask._mask):.2f}%)")
109+
else:
110+
print("No base mask applied.")
111+
112+
# %%
113+
# Bin data
114+
115+
# Create array of nsides between min and max with powers of two
116+
nsides = np.array([2**i for i in range(int(np.log2(nside_min)), int(np.log2(nside_max))+1)])
117+
118+
# %%
119+
areas_deg2 = {}
120+
for mask in masks:
121+
122+
print(f"Mask: {mask._col_name}")
123+
areas_deg2[mask._col_name] = {}
124+
125+
# Apply mask to positions
126+
m = mask._mask
127+
128+
ra = dat[key_ra][m]
129+
dec = dat[key_dec][m]
130+
131+
for nside in nsides:
132+
133+
area_deg2 = cs_cat.get_binned_area(ra, dec, nside=nside)
134+
print(f"binned area (nside={nside}) ≈ {area_deg2:.3f} deg^2")
135+
areas_deg2[mask._col_name][nside] = area_deg2
136+
137+
# %%
138+
def save_areas(areas_deg2, filename):
139+
"""Save areas to a ASCII file.
140+
141+
Parameters
142+
----------
143+
areas_deg2 : dict
144+
Dictionary with mask names as keys and another dictionary as values.
145+
The inner dictionary has nsides as keys and areas in deg² as values.
146+
filename : str
147+
Output filename.
148+
"""
149+
with open(filename, 'w') as f:
150+
# Write header
151+
f.write("# Mask_name nside area_deg2\n")
152+
for mask_name, area_dict in areas_deg2.items():
153+
for nside, area in area_dict.items():
154+
f.write(f"{mask_name} {nside} {area:.6f}\n")
155+
156+
print(f"Wrote areas to {filename}")
157+
158+
# %%
159+
160+
# %%
161+
# Get area of hsp masks
162+
area_wcov_deg2 = {}
163+
if True:
164+
if label_base_mask != "":
165+
# Coverage = read aux file mask
166+
coverage = hsp.HealSparseMap.read(hsp_obj._params["aux_mask_files"])
167+
area_coverage = coverage.get_valid_area(degrees=True)
168+
area_wcov_deg2["npoint3"] = area_coverage
169+
170+
# Loop over other, bit-coded masks
171+
paths = hsp_obj.get_paths_bit_masks()
172+
for bit, path in paths.items():
173+
print(bit, path)
174+
hsp_mask = hsp.HealSparseMap.read(path)
175+
176+
if label_base_mask != "":
177+
# Apply coverage mask
178+
hsp_mask_wcov = coverage & (~hsp_mask)
179+
else:
180+
hsp_mask_wcov = ~hsp_mask
181+
182+
key = hsp_obj.get_mask_col_name(bit)
183+
area_wcov_deg2[key] = hsp_mask_wcov.get_valid_area(degrees=True)
184+
185+
# %%
186+
# Plot areas
187+
markers = ['o', 's', '^', 'v', 'D', 'x', '*']
188+
ls = ['dashed', 'dotted', 'dashdot', 'solid', (0, (3, 1, 1, 1)), (0, (5, 10)), (0, (1, 10))]
189+
fig, ax = plt.subplots(figsize=(8,8))
190+
plt.xticks(nsides, nsides)
191+
for idx, mask in enumerate(masks):
192+
label = mask._col_name
193+
area_dict = areas_deg2[label]
194+
nsides = np.array(list(area_dict.keys()))
195+
dx = cs_plots.dx(idx, len(masks))
196+
areas = np.array(list(area_dict.values()))
197+
ax.plot(nsides * dx, areas, marker=markers[idx], label=label, linestyle=ls[idx])
198+
ax.hlines(
199+
area_wcov_deg2[label],
200+
nsides[0]*0.8,
201+
nsides[-1]*1.1,
202+
colors='C'+str(idx),
203+
linestyles=ls[idx],
204+
)
205+
plt.legend()
206+
plt.xlabel("nside")
207+
plt.ylabel("binned area [deg²]")
208+
_ = plt.setp(ax.get_xticklabels(), rotation=90, ha="right", rotation_mode="anchor")
209+
# %%
210+
cs_plots.savefig("binned_hsp_areas.png")
211+
# %%
212+
# Add hsp values to dict of binned catalogue with new "hsp" key
213+
for key in areas_deg2:
214+
areas_deg2[key]["hsp"] = area_wcov_deg2[key]
215+
# %%
216+
# Write to disk
217+
save_areas(areas_deg2, "areas.txt")

src/sp_validation/run_joint_cat.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,6 @@ def sky_plots(dat, masks, labels, zoom_ra, zoom_dec):
12381238
plot_area_mask(ra, dec, zoom, mask=m_halos)
12391239

12401240

1241-
12421241
def plot_area_mask(ra, dec, zoom, mask=None):
12431242
"""Plot Area Mask.
12441243
@@ -1601,7 +1600,6 @@ def get_masks_from_config(
16011600

16021601
# Loop over mask information in this section
16031602
for mask_params in mask_list:
1604-
value = mask_params["value"]
16051603

16061604
use_this_mask = False
16071605
if masks_to_apply is not None:
@@ -1612,6 +1610,7 @@ def get_masks_from_config(
16121610

16131611
if use_this_mask:
16141612
# Ensure 'range' kind has exactly two values
1613+
value = mask_params["value"]
16151614
if mask_params["kind"] == "range" and (
16161615
not isinstance(value, list) or len(value) != 2
16171616
):

src/sp_validation/util.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ def millify(n):
4242
)
4343

4444
return f'{n / 10**(3 * millidx):.0f}{millnames[millidx]}'
45+
46+
47+
def print_millified(msg, n):
48+
49+
print(f"{msg} = {n} = {millify(n)}")

0 commit comments

Comments
 (0)