Skip to content

Commit dc1123e

Browse files
author
Thibaut Louis
committed
change the implementation of the filter to make it more modular, also include option for sigurd filtering method
1 parent 81df1c3 commit dc1123e

File tree

2 files changed

+160
-68
lines changed

2 files changed

+160
-68
lines changed

pspy/so_map_preprocessing.py

Lines changed: 106 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,125 @@
11
import numpy as np, pylab as plt
22
from pspy import flat_tools, pspy_utils
3+
from pixell import enmap, utils
34

4-
def kspace_filter(map, vk_mask=None, hk_mask=None, window=None, normalize=False):
5-
filtered_map = map.copy()
6-
7-
ft = flat_tools.fft_from_so_map(map, normalize=normalize)
8-
if window is not None:
9-
ft = flat_tools.get_ffts(map, window, normalize=normalize)
10-
5+
def build_std_filter(shape, wcs, vk_mask, hk_mask, dtype=np.float64):
6+
ly, lx = enmap.laxes(shape, wcs, method="auto")
7+
ly = ly.astype(dtype)
8+
lx = lx.astype(dtype)
9+
filter = enmap.ones(shape[-2:], wcs, dtype)
1110
if vk_mask is not None:
12-
id_vk = np.where((ft.lx > vk_mask[0]) & (ft.lx < vk_mask[1]))
11+
id_vk = np.where((lx > vk_mask[0]) & (lx < vk_mask[1]))
1312
if hk_mask is not None:
14-
id_hk = np.where((ft.ly > hk_mask[0]) & (ft.ly < hk_mask[1]))
15-
16-
if map.ncomp == 1:
17-
if vk_mask is not None:
18-
ft.kmap[: , id_vk] = 0.
19-
if hk_mask is not None:
20-
ft.kmap[id_hk , :] = 0.
21-
22-
if map.ncomp == 3:
23-
for i in range(3):
24-
if vk_mask is not None:
25-
ft.kmap[i, : , id_vk] = 0.
26-
if hk_mask is not None:
27-
ft.kmap[i, id_hk , :] = 0.
28-
29-
filtered_map.data[:] = ft.map_from_fft(normalize=normalize)
13+
id_hk = np.where((ly > hk_mask[0]) & (ly < hk_mask[1]))
14+
filter[:, id_vk] = 0
15+
filter[id_hk, :] = 0
16+
return filter
17+
18+
def apply_std_filter(imap, filter):
19+
filtered_map = imap.copy()
20+
if imap.ncomp == 1:
21+
filtered_map.data = enmap.ifft(filter*enmap.fft(imap.data)).real
22+
else:
23+
for i in range(imap.ncomp):
24+
filtered_map.data[i] = enmap.ifft(filter*enmap.fft(imap.data[i])).real
25+
3026
return filtered_map
3127

28+
def build_sigurd_filter(shape, wcs, lbounds, dtype=np.float64):
29+
ly, lx = enmap.laxes(shape, wcs, method="auto")
30+
ly = ly.astype(dtype)
31+
lx = lx.astype(dtype)
32+
lbounds = np.asarray(lbounds)
33+
if lbounds.ndim < 2:
34+
lbounds = np.broadcast_to(lbounds, (1,2))
35+
if lbounds.ndim > 2 or lbounds.shape[-1] != 2:
36+
raise ValueError("lbounds must be [:,{ly,lx}]")
37+
filter = enmap.ones(shape[-2:], wcs, dtype)
38+
# Apply the filters
39+
for i , (ycut, xcut) in enumerate(lbounds):
40+
filter *= 1-(np.exp(-0.5*(ly/ycut)**2)[:,None]*np.exp(-0.5*(lx/xcut)**2)[None,:])
41+
return filter
3242

33-
def analytical_tf(map, binning_file, lmax, vk_mask=None, hk_mask=None):
34-
import time
35-
t = time.time()
36-
ft = flat_tools.fft_from_so_map(map)
37-
ft.create_kspace_mask(vertical_stripe=vk_mask, horizontal_stripe=hk_mask)
38-
lmap = ft.lmap
39-
kmask = ft.kmask
40-
twod_index = lmap.copy()
43+
def apply_sigurd_filter(imap, ivar, filter, tol=1e-4, ref=0.9):
44+
"""Filter enmap imap with the given 2d fourier filter while
45+
weithing spatially with ivar"""
46+
47+
filtered_map = imap.copy()
48+
rhs = enmap.ifft((1-filter)*enmap.fft(imap.data*ivar)).real
49+
div = enmap.ifft((1-filter)*enmap.fft(ivar)).real
50+
# Avoid division by very low values
51+
div = np.maximum(div, np.percentile(ivar[::10,::10],ref*100)*tol)
52+
filtered_map.data = imap.data - rhs/div
53+
return filtered_map
4154

55+
def analytical_tf(map, filter, binning_file, lmax):
56+
lmap = enmap.modlmap(map.data.shape, map.data.wcs, method="auto")
57+
twod_index = lmap.copy()
4258
bin_lo, bin_hi, bin_c, bin_size = pspy_utils.read_binning_file(binning_file, lmax)
4359
nbins = len(bin_lo)
44-
print(lmap.shape)
4560
tf = np.zeros(nbins)
46-
print("init tf", time.time()-t)
4761
for ii in range(nbins):
48-
id = np.where( (lmap >= bin_lo[ii]) & (lmap <= bin_hi[ii]))
62+
id = np.where((lmap >= bin_lo[ii]) & (lmap <= bin_hi[ii]))
4963
twod_index *= 0
5064
twod_index[id] = 1
5165
bin_area = np.sum(twod_index)
52-
masked_bin_area= np.sum(twod_index * kmask)
66+
masked_bin_area= np.sum(twod_index * filter)
5367
tf[ii] = masked_bin_area / bin_area
54-
print("loop", time.time()-t)
5568

5669
return bin_c, tf
70+
71+
72+
73+
#def analytical_tf_old(map, binning_file, lmax, vk_mask=None, hk_mask=None):
74+
# import time
75+
# t = time.time()
76+
# ft = flat_tools.fft_from_so_map(map)
77+
# ft.create_kspace_mask(vertical_stripe=vk_mask, horizontal_stripe=hk_mask)
78+
# lmap = ft.lmap
79+
# kmask = ft.kmask
80+
# twod_index = lmap.copy()
81+
82+
# bin_lo, bin_hi, bin_c, bin_size = pspy_utils.read_binning_file(binning_file, lmax)
83+
# nbins = len(bin_lo)
84+
# print(lmap.shape)
85+
# tf = np.zeros(nbins)
86+
# print("init tf", time.time()-t)
87+
# for ii in range(nbins):
88+
# id = np.where( (lmap >= bin_lo[ii]) & (lmap <= bin_hi[ii]))
89+
# twod_index *= 0
90+
# twod_index[id] = 1
91+
# bin_area = np.sum(twod_index)
92+
# masked_bin_area= np.sum(twod_index * kmask)
93+
# tf[ii] = masked_bin_area / bin_area
94+
# print("loop", time.time()-t)
95+
96+
# return bin_c, tf
97+
98+
99+
#def kspace_filter_old(map, vk_mask=None, hk_mask=None, window=None, normalize=False):
100+
# filtered_map = map.copy()
101+
102+
# ft = flat_tools.fft_from_so_map(map, normalize=normalize)
103+
# if window is not None:
104+
# ft = flat_tools.get_ffts(map, window, normalize=normalize)
105+
106+
# if vk_mask is not None:
107+
# id_vk = np.where((ft.lx > vk_mask[0]) & (ft.lx < vk_mask[1]))
108+
# if hk_mask is not None:
109+
# id_hk = np.where((ft.ly > hk_mask[0]) & (ft.ly < hk_mask[1]))
110+
111+
# if map.ncomp == 1:
112+
# if vk_mask is not None:
113+
# ft.kmap[: , id_vk] = 0.
114+
# if hk_mask is not None:
115+
# ft.kmap[id_hk , :] = 0.
116+
117+
# if map.ncomp == 3:
118+
# for i in range(3):
119+
# if vk_mask is not None:
120+
# ft.kmap[i, : , id_vk] = 0.
121+
# if hk_mask is not None:
122+
# ft.kmap[i, id_hk , :] = 0.
123+
124+
# filtered_map.data[:] = ft.map_from_fft(normalize=normalize)
125+
# return filtered_map

tutorials/tuto_kspace_filter.py

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@
1818
apo_radius_degree = 2
1919
niter = 0
2020
lmax = 2000
21-
nsims = 4
21+
nsims = 30
2222

23-
vk_mask = [-90, 90]
24-
hk_mask = [-50, 50]
2523

2624
test_dir = "result_kspace"
2725
try:
@@ -45,6 +43,21 @@
4543
window = (window,window)
4644
mbb_inv, Bbl = so_mcm.mcm_and_bbl_spin0and2(window, binning_file, lmax=lmax, type="Dl", niter=niter)
4745

46+
# we build two different filters and compute the analytical 1d binned spectra they correspond to
47+
48+
vk_mask = [-90, 90]
49+
hk_mask = [-50, 50]
50+
filter_std = so_map_preprocessing.build_std_filter(template.data.shape, template.data.wcs, vk_mask, hk_mask, dtype=np.float64)
51+
52+
lbounds = [4000, 5]
53+
filter_sig = so_map_preprocessing.build_sigurd_filter(template.data.shape, template.data.wcs, lbounds, dtype=np.float64)
54+
55+
56+
lb, analytic_tf_std = so_map_preprocessing.analytical_tf(template, filter_std, binning_file, lmax)
57+
lb, analytic_tf_sig = so_map_preprocessing.analytical_tf(template, filter_sig, binning_file, lmax)
58+
59+
60+
4861

4962
# Let's run nsims, and apply the transfer function, we will compute both the SPHT and the FFT of the initial and filtered maps.
5063
# Then we compute the associated 1d and 2d power spectra, we will store the value of the resulting
@@ -56,23 +69,27 @@
5669
spectra_2d = ["II", "IQ", "IU", "QI", "QQ", "QU", "UI", "UQ", "UU"]
5770
Db_list = {}
5871
p2d_list = {}
59-
for spec in spectra:
60-
Db_list["standard", spec] = []
61-
Db_list["filtered", spec] = []
62-
for spec in spectra_2d:
63-
p2d_list["standard", spec] = []
64-
p2d_list["filtered", spec] = []
65-
72+
73+
runs = ["sig_filtered", "std_filtered", "no_filter"]
74+
75+
for run in runs:
76+
for (spec, spec2d) in zip(spectra, spectra_2d):
77+
Db_list[run, spec] = []
78+
p2d_list[run, spec2d] = []
79+
6680

6781
for iii in range(nsims):
6882
print("sim number %03d" % iii)
69-
for run in ["standard", "filtered"]:
83+
for run in runs:
7084
cmb = template.synfast(clfile)
7185

7286
if iii == 0: cmb.plot(file_name="%s/cmb"%(test_dir))
73-
if run == "filtered":
74-
cmb = so_map_preprocessing.kspace_filter(cmb, vk_mask=vk_mask, hk_mask=hk_mask, normalize="phys")
87+
if run == "std_filtered":
88+
cmb = so_map_preprocessing.apply_std_filter(cmb, filter_std)
7589
if iii == 0: cmb.plot(file_name="%s/cmb_filter"%(test_dir))
90+
elif run == "sig_filtered":
91+
cmb = so_map_preprocessing.apply_sigurd_filter(cmb, binary.data, filter_sig, tol=1e-4, ref=0.9)
92+
if iii == 0: cmb.plot(file_name="%s/cmb_sigurd_filter"%(test_dir))
7693

7794
alm_cmb = sph_tools.get_alms(cmb, window, niter, lmax)
7895
fft_cmb = flat_tools.get_ffts(cmb, window, lmax)
@@ -97,48 +114,54 @@
97114

98115

99116
# First the 1d part with the associated transfer functions
100-
# we also compute a simple analytical version of the transfer function
101117

102-
lb, analytic_tf = so_map_preprocessing.analytical_tf(cmb, binning_file, lmax, vk_mask=vk_mask, hk_mask=hk_mask)
103118

104119
mean = {}
105120
std = {}
106121
for spec in spectra:
107-
108-
mean["standard", spec]= np.mean(Db_list["standard", spec], axis=0)
109-
mean["filtered", spec]= np.mean(Db_list["filtered", spec], axis=0)
110-
std["standard", spec]= np.std(Db_list["standard", spec], axis=0)
111-
std["filtered", spec]= np.std(Db_list["filtered", spec], axis=0)
112-
113-
plt.errorbar(lb, mean["standard", spec], std["standard", spec], fmt=".", label="standard")
114-
plt.errorbar(lb, mean["filtered", spec], std["filtered", spec], fmt=".", label="filtered")
122+
for run in runs:
123+
mean[run, spec]= np.mean(Db_list[run, spec], axis=0)
124+
std[run, spec]= np.std(Db_list[run, spec], axis=0)
125+
plt.errorbar(lb, mean[run, spec], std[run, spec], fmt=".", label=run)
126+
115127
plt.legend()
116128
plt.savefig("%s/spectra_%s.png" % (test_dir, spec))
117129
plt.clf()
118130
plt.close()
119131

120132

121133
if spec in ["TT", "EE", "TE", "BB"] :
122-
plt.plot(lb, analytic_tf)
123-
plt.plot(lb, mean["filtered", spec]/mean["standard", spec], ".")
134+
plt.plot(lb, analytic_tf_std, label = "std analytic")
135+
plt.plot(lb, analytic_tf_sig, label = "sigurd analytic")
136+
137+
plt.errorbar(lb, mean["std_filtered", spec]/mean["no_filter", spec], label="std filter", fmt=".")
138+
plt.errorbar(lb, mean["sig_filtered", spec]/mean["no_filter", spec], label="sigurd filter", fmt=".")
139+
140+
plt.legend()
124141
plt.savefig("%s/tf_%s.png" % (test_dir, spec))
125142
plt.clf()
126143
plt.close()
127144

128145

129-
plt.plot(lb, analytic_tf)
146+
plt.plot(lb, analytic_tf_std, label = "std analytic")
147+
plt.plot(lb, analytic_tf_sig, label = "sigurd analytic")
148+
130149
for spec in ["TT", "EE"] :
131-
plt.plot(lb, mean["filtered", spec]/mean["standard", spec], ".", label = spec)
150+
plt.plot(lb, mean["std_filtered", spec]/mean["no_filter", spec], ".", label = spec + "std")
151+
plt.plot(lb, mean["sig_filtered", spec]/mean["no_filter", spec], ".", label = spec + "sigurd")
152+
153+
plt.legend()
132154
plt.savefig("%s/tf_TT_and_EE.png" % (test_dir))
133155
plt.clf()
134156
plt.close()
135157

136158
# Now the 2d part with the plot of the effect of the filter
137159

138-
mean["standard"] = p2d_dict.copy()
139-
mean["filtered"] = p2d_dict.copy()
160+
161+
for run in runs:
162+
mean[run] = p2d_dict.copy()
140163
for spec in spectra_2d:
141-
for run in ["standard", "filtered"]:
164+
for run in runs:
142165
mean[run].powermap[spec] = np.mean(p2d_list[run, spec], axis=0)
143-
for run in ["standard", "filtered"]:
166+
for run in runs:
144167
mean[run].plot(power_of_ell=2, png_file="%s/%s" % (test_dir, run))

0 commit comments

Comments
 (0)