orpheus-npcf 0.2.1__cp310-cp310-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orpheus/__init__.py +9 -0
- orpheus/catalog.py +1216 -0
- orpheus/covariance.py +153 -0
- orpheus/direct.py +1091 -0
- orpheus/flat2dgrid.py +68 -0
- orpheus/npcf_base.py +766 -0
- orpheus/npcf_fourth.py +1716 -0
- orpheus/npcf_second.py +620 -0
- orpheus/npcf_third.py +1684 -0
- orpheus/orpheus_clib.cpython-310-x86_64-linux-gnu.so +0 -0
- orpheus/patchutils.py +369 -0
- orpheus/utils.py +198 -0
- orpheus_npcf-0.2.1.dist-info/METADATA +67 -0
- orpheus_npcf-0.2.1.dist-info/RECORD +19 -0
- orpheus_npcf-0.2.1.dist-info/WHEEL +5 -0
- orpheus_npcf-0.2.1.dist-info/licenses/LICENSE +674 -0
- orpheus_npcf-0.2.1.dist-info/sboms/auditwheel.cdx.json +1 -0
- orpheus_npcf-0.2.1.dist-info/top_level.txt +1 -0
- orpheus_npcf.libs/libgomp-8949ffbe.so.1.0.0 +0 -0
orpheus/npcf_fourth.py
ADDED
|
@@ -0,0 +1,1716 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import ctypes as ct
|
|
3
|
+
from functools import reduce
|
|
4
|
+
import operator
|
|
5
|
+
from scipy.interpolate import interp1d
|
|
6
|
+
|
|
7
|
+
from .utils import flatlist, gen_thetacombis_fourthorder, gen_n2n3indices_Upsfourth
|
|
8
|
+
from .npcf_base import BinnedNPCF
|
|
9
|
+
from .npcf_second import GGCorrelation
|
|
10
|
+
|
|
11
|
+
__all__ = ["NNNNCorrelation_NoTomo", "GGGGCorrelation_NoTomo"]
|
|
12
|
+
|
|
13
|
+
class NNNNCorrelation_NoTomo(BinnedNPCF):
|
|
14
|
+
r""" Class containing methods to measure and and obtain statistics that are built
|
|
15
|
+
from nontomographic fourth-order scalar correlation functions.
|
|
16
|
+
|
|
17
|
+
Attributes
|
|
18
|
+
----------
|
|
19
|
+
min_sep: float
|
|
20
|
+
The smallest distance of each vertex for which the NPCF is computed.
|
|
21
|
+
max_sep: float
|
|
22
|
+
The largest distance of each vertex for which the NPCF is computed.
|
|
23
|
+
thetabatchsize_max: int, optional
|
|
24
|
+
The largest number of radial bin combinations that are processed in parallel.
|
|
25
|
+
Defaults to ``10 000``.
|
|
26
|
+
|
|
27
|
+
Notes
|
|
28
|
+
-----
|
|
29
|
+
Inherits all other parameters and attributes from :class:`BinnedNPCF`.
|
|
30
|
+
Additional child-specific parameters can be passed via ``kwargs``.
|
|
31
|
+
Either ``nbinsr`` or ``binsize`` has to be provided to fix the binning scheme .
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, min_sep, max_sep, verbose=False, thetabatchsize_max=10000, method="Tree", **kwargs):
|
|
36
|
+
super().__init__(order=4, spins=np.array([0,0,0,0], dtype=np.int32),
|
|
37
|
+
n_cfs=1, min_sep=min_sep, max_sep=max_sep,
|
|
38
|
+
method=method, methods_avail=["Tree"], **kwargs)
|
|
39
|
+
|
|
40
|
+
self.thetabatchsize_max = thetabatchsize_max
|
|
41
|
+
self.nbinsz = 1
|
|
42
|
+
self.nzcombis = 1
|
|
43
|
+
|
|
44
|
+
def process(self, cat, statistics="all", tofile=False, apply_edge_correction=False,
|
|
45
|
+
lowmem=True, mapradii=None, batchsize=None, custom_thetacombis=None, cutlen=2**31-1):
|
|
46
|
+
r"""
|
|
47
|
+
Arguments:
|
|
48
|
+
|
|
49
|
+
Logic works as follows:
|
|
50
|
+
* Keyword 'statistics' \in [4pcf_real, 4pcf_multipoles, N4, Nap4, Nap4, Nap4c, allNap, all4pcf, all]
|
|
51
|
+
* - If 4pcf_multipoles in statistics --> save 4pcf_multipoles
|
|
52
|
+
* - If 4pcf_real in statistics --> save 4pcf_real
|
|
53
|
+
* - If only N4 in statistics --> Do not save any 4pcf. This is really the lowmem case.
|
|
54
|
+
* - allNap, all4pcf, all are abbreviations as expected
|
|
55
|
+
* If lowmem=True, uses the inefficient, but lowmem function for computation and output statistics
|
|
56
|
+
from there as wanted.
|
|
57
|
+
* If lowmem=False, use the fast functions to do the 4pcf multipole computation and do
|
|
58
|
+
the potential conversions lateron.
|
|
59
|
+
* Default lowmem to None and
|
|
60
|
+
* - Set to true if any aperture statistics is in stats or we will run into mem error
|
|
61
|
+
* - Set to false otherwise
|
|
62
|
+
* - Raise error if lowmen=False and we will have more that 2^31-1 elements at any stage of the computation
|
|
63
|
+
|
|
64
|
+
custom_thetacombis: array of inds which theta combis will be selected
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
## Preparations ##
|
|
68
|
+
# Build list of statistics to be calculated
|
|
69
|
+
statistics_avail_4pcf = ["4pcf_real", "4pcf_multipole"]
|
|
70
|
+
statistics_avail_nap4 = ["N4", "Nap4", "N4c", "Nap4c"]
|
|
71
|
+
statistics_avail_comp = ["allNap", "all4pcf", "all"]
|
|
72
|
+
statistics_avail_phys = statistics_avail_4pcf + statistics_avail_nap4
|
|
73
|
+
statistics_avail = statistics_avail_4pcf + statistics_avail_nap4 + statistics_avail_comp
|
|
74
|
+
_statistics = []
|
|
75
|
+
hasintegratedstats = False
|
|
76
|
+
_strbadstats = lambda stat: ("The statistics `%s` has not been implemented yet. "%stat +
|
|
77
|
+
"Currently supported statistics are:\n" + str(statistics_avail))
|
|
78
|
+
if type(statistics) not in [list, str]:
|
|
79
|
+
raise ValueError("The parameter `statistics` should either be a list or a string.")
|
|
80
|
+
if type(statistics) is str:
|
|
81
|
+
if statistics not in statistics_avail:
|
|
82
|
+
raise ValueError(_strbadstats)
|
|
83
|
+
statistics = [statistics]
|
|
84
|
+
if type(statistics) is list:
|
|
85
|
+
if "all" in statistics:
|
|
86
|
+
_statistics = statistics_avail_phys
|
|
87
|
+
elif "all4pcf" in statistics:
|
|
88
|
+
_statistics.append(statistics_avail_4pcf)
|
|
89
|
+
elif "allNap" in statistics:
|
|
90
|
+
_statistics.append(statistics_avail_nap4)
|
|
91
|
+
_statistics = flatlist(_statistics)
|
|
92
|
+
for stat in statistics:
|
|
93
|
+
if stat not in statistics_avail:
|
|
94
|
+
raise ValueError(_strbadstats)
|
|
95
|
+
if stat in statistics_avail_phys and stat not in _statistics:
|
|
96
|
+
_statistics.append(stat)
|
|
97
|
+
statistics = list(set(flatlist(_statistics)))
|
|
98
|
+
for stat in statistics:
|
|
99
|
+
if stat in statistics_avail_nap4:
|
|
100
|
+
hasintegratedstats = True
|
|
101
|
+
|
|
102
|
+
# Check if the output will fit in memory
|
|
103
|
+
if "4pcf_multipole" in statistics:
|
|
104
|
+
_nvals = self.nzcombis*(2*self.nmaxs[0]+1)*(2*self.nmaxs[1]+1)*self.nbinsr**3
|
|
105
|
+
if _nvals>cutlen:
|
|
106
|
+
raise ValueError(("4pcf in multipole basis will cause memory overflow " +
|
|
107
|
+
"(requiring %.2fx10^9 > %.2fx10^9 elements)\n"%(_nvals/1e9, cutlen/1e9) +
|
|
108
|
+
"If you are solely interested in integrated statistics (like Map4), you" +
|
|
109
|
+
"only need to add those to the `statistics` argument."))
|
|
110
|
+
if "4pcf_real" in statistics:
|
|
111
|
+
_nvals = self.nzcombis*self.nbinsphi[0]*self.nbinsphi[1]*self.nbinsr**3
|
|
112
|
+
if _nvals>cutlen:
|
|
113
|
+
raise ValueError(("4pcf in real basis will cause memory overflow " +
|
|
114
|
+
"(requiring %.2fx10^9 > %.2fx10^9 elements)\n"%(_nvals/1e9, cutlen/1e9) +
|
|
115
|
+
"If you are solely interested in integrated statistics (like Map4), you" +
|
|
116
|
+
"only need to add those to the `statistics` argument."))
|
|
117
|
+
|
|
118
|
+
# Decide on whether to use low-mem functions or not
|
|
119
|
+
if hasintegratedstats:
|
|
120
|
+
if lowmem in [False, None]:
|
|
121
|
+
if not lowmem:
|
|
122
|
+
print("Low-memory computation enforced for integrated measures of the 4pcf. " +
|
|
123
|
+
"Set `lowmem` from `%s` to `True`"%str(lowmem))
|
|
124
|
+
lowmem = True
|
|
125
|
+
else:
|
|
126
|
+
if lowmem in [None, False]:
|
|
127
|
+
maxlen = 0
|
|
128
|
+
_lowmem = False
|
|
129
|
+
if "4pcf_multipole" in statistics:
|
|
130
|
+
_nvals = self.nzcombis*(2*self.nmaxs[0]+1)*(2*self.nmaxs[1]+1)*self.nbinsr**3
|
|
131
|
+
if _nvals > cutlen:
|
|
132
|
+
if not lowmem:
|
|
133
|
+
print("Switching to low-memory computation of 4pcf in multipole basis.")
|
|
134
|
+
lowmem = True
|
|
135
|
+
else:
|
|
136
|
+
lowmem = False
|
|
137
|
+
if "4pcf_real" in statistics:
|
|
138
|
+
nvals = self.nzcombis*self.nbinsphi[0]*self.nbinsphi[1]*self.nbinsr**3
|
|
139
|
+
if _nvals > cutlen:
|
|
140
|
+
if not lowmem:
|
|
141
|
+
print("Switching to low-memory computation of 4pcf in real basis.")
|
|
142
|
+
lowmem = True
|
|
143
|
+
else:
|
|
144
|
+
lowmem = False
|
|
145
|
+
|
|
146
|
+
# Misc checks
|
|
147
|
+
self._checkcats(cat, self.spins)
|
|
148
|
+
|
|
149
|
+
## Build args for wrapped functions ##
|
|
150
|
+
# Shortcuts
|
|
151
|
+
_nmax = self.nmaxs[0]
|
|
152
|
+
_nnvals = (2*_nmax+1)*(2*_nmax+1)
|
|
153
|
+
_nbinsr3 = self.nbinsr*self.nbinsr*self.nbinsr
|
|
154
|
+
_nphis = len(self.phis[0])
|
|
155
|
+
sc = (2*_nmax+1,2*_nmax+1,self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr)
|
|
156
|
+
szr = (self.nbinsz, self.nbinsr)
|
|
157
|
+
s4pcf = (self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr,_nphis,_nphis)
|
|
158
|
+
# Init default args
|
|
159
|
+
bin_centers = np.zeros(self.nbinsz*self.nbinsr).astype(np.float64)
|
|
160
|
+
if not cat.hasspatialhash:
|
|
161
|
+
cat.build_spatialhash(dpix=max(1.,self.max_sep//10.))
|
|
162
|
+
nregions = np.int32(len(np.argwhere(cat.index_matcher>-1).flatten()))
|
|
163
|
+
args_basecat = (cat.isinner.astype(np.float64), cat.weight, cat.pos1, cat.pos2,
|
|
164
|
+
np.int32(cat.ngal), )
|
|
165
|
+
args_hash = (cat.index_matcher, cat.pixs_galind_bounds, cat.pix_gals, nregions,
|
|
166
|
+
np.float64(cat.pix1_start), np.float64(cat.pix1_d), np.int32(cat.pix1_n),
|
|
167
|
+
np.float64(cat.pix2_start), np.float64(cat.pix2_d), np.int32(cat.pix2_n), )
|
|
168
|
+
|
|
169
|
+
# Init optional args
|
|
170
|
+
__lenflag = 10
|
|
171
|
+
__fillflag = -1
|
|
172
|
+
if "4pcf_multipole" in statistics:
|
|
173
|
+
N_n = np.zeros(_nnvals*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
174
|
+
alloc_4pcfmultipoles = 1
|
|
175
|
+
else:
|
|
176
|
+
N_n = __fillflag*np.zeros(__lenflag).astype(np.complex128)
|
|
177
|
+
alloc_4pcfmultipoles = 0
|
|
178
|
+
if "4pcf_real" in statistics:
|
|
179
|
+
fourpcf = np.zeros(_nphis*_nphis*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
180
|
+
alloc_4pcfreal = 1
|
|
181
|
+
else:
|
|
182
|
+
fourpcf = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
183
|
+
alloc_4pcfreal = 0
|
|
184
|
+
if hasintegratedstats:
|
|
185
|
+
if mapradii is None:
|
|
186
|
+
raise ValueError("Aperture radii need to be specified in variable `mapradii`.")
|
|
187
|
+
mapradii = mapradii.astype(np.float64)
|
|
188
|
+
N4correlators = np.zeros(self.nzcombis*len(mapradii)).astype(np.complex128)
|
|
189
|
+
else:
|
|
190
|
+
mapradii = __fillflag*np.ones(__lenflag).astype(np.float64)
|
|
191
|
+
N4correlators = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# Build args based on chosen methods
|
|
195
|
+
if self.method=="Discrete" and not lowmem:
|
|
196
|
+
raise NotImplementedError
|
|
197
|
+
if self.method=="Discrete" and lowmem:
|
|
198
|
+
raise NotImplementedError
|
|
199
|
+
if self.method=="Tree" and lowmem:
|
|
200
|
+
# Prepare mask for nonredundant theta- and multipole configurations
|
|
201
|
+
_resradial = gen_thetacombis_fourthorder(nbinsr=self.nbinsr, nthreads=self.nthreads, batchsize=batchsize,
|
|
202
|
+
batchsize_max=self.thetabatchsize_max, ordered=True, custom=custom_thetacombis,
|
|
203
|
+
verbose=self._verbose_python)
|
|
204
|
+
_, _, thetacombis_batches, cumnthetacombis_batches, nthetacombis_batches, nbatches = _resradial
|
|
205
|
+
assert(self.nmaxs[0]==self.nmaxs[1])
|
|
206
|
+
_resmultipoles = gen_n2n3indices_Upsfourth(self.nmaxs[0])
|
|
207
|
+
_shape, _inds, _n2s, _n3s = _resmultipoles
|
|
208
|
+
|
|
209
|
+
# Prepare reduced catalogs
|
|
210
|
+
cutfirst = np.int32(self.tree_resos[0]==0.)
|
|
211
|
+
mhash = cat.multihash(dpixs=self.tree_resos[cutfirst:], dpix_hash=self.tree_resos[-1],
|
|
212
|
+
shuffle=self.shuffle_pix, normed=False)
|
|
213
|
+
(ngal_resos, pos1s, pos2s, weights, zbins, isinners, allfields,
|
|
214
|
+
index_matchers, pixs_galind_bounds, pix_gals, dpixs1_true, dpixs2_true) = mhash
|
|
215
|
+
weight_resos = np.concatenate(weights).astype(np.float64)
|
|
216
|
+
pos1_resos = np.concatenate(pos1s).astype(np.float64)
|
|
217
|
+
pos2_resos = np.concatenate(pos2s).astype(np.float64)
|
|
218
|
+
zbin_resos = np.concatenate(zbins).astype(np.int32)
|
|
219
|
+
isinner_resos = np.concatenate(isinners).astype(np.float64)
|
|
220
|
+
index_matcher_resos = np.concatenate(index_matchers).astype(np.int32)
|
|
221
|
+
pixs_galind_bounds_resos = np.concatenate(pixs_galind_bounds).astype(np.int32)
|
|
222
|
+
pix_gals_resos = np.concatenate(pix_gals).astype(np.int32)
|
|
223
|
+
index_matcher_flat = np.argwhere(cat.index_matcher>-1).flatten()
|
|
224
|
+
nregions = len(index_matcher_flat)
|
|
225
|
+
# Build args
|
|
226
|
+
args_basesetup = (np.int32(_nmax),
|
|
227
|
+
np.float64(self.min_sep), np.float64(self.max_sep), np.int32(self.nbinsr),
|
|
228
|
+
np.int32(self.multicountcorr),
|
|
229
|
+
_inds, np.int32(len(_inds)), self.phis[0].astype(np.float64),
|
|
230
|
+
2*np.pi/_nphis*np.ones(_nphis, dtype=np.float64), np.int32(_nphis), )
|
|
231
|
+
args_resos = (np.int32(self.tree_nresos), self.tree_redges, np.array(ngal_resos, dtype=np.int32),
|
|
232
|
+
isinner_resos, weight_resos, pos1_resos, pos2_resos,
|
|
233
|
+
index_matcher_resos, pixs_galind_bounds_resos, pix_gals_resos, np.int32(nregions), )
|
|
234
|
+
args_hash = (np.float64(cat.pix1_start), np.float64(cat.pix1_d), np.int32(cat.pix1_n),
|
|
235
|
+
np.float64(cat.pix2_start), np.float64(cat.pix2_d), np.int32(cat.pix2_n), )
|
|
236
|
+
args_thetas = (thetacombis_batches, nthetacombis_batches, cumnthetacombis_batches, nbatches, )
|
|
237
|
+
args_nap4 = (mapradii, np.int32(len(mapradii)), N4correlators)
|
|
238
|
+
args_4pcf = (np.int32(alloc_4pcfmultipoles), np.int32(alloc_4pcfreal),
|
|
239
|
+
bin_centers, N_n, fourpcf)
|
|
240
|
+
args = (*args_basecat,
|
|
241
|
+
*args_basesetup,
|
|
242
|
+
*args_resos,
|
|
243
|
+
*args_hash,
|
|
244
|
+
*args_thetas,
|
|
245
|
+
np.int32(self.nthreads),
|
|
246
|
+
*args_nap4,
|
|
247
|
+
*args_4pcf)
|
|
248
|
+
func = self.clib.alloc_notomoNap4_tree_nnnn
|
|
249
|
+
|
|
250
|
+
# Optionally print the arguments
|
|
251
|
+
if self._verbose_debug:
|
|
252
|
+
print("We pass the following arguments:")
|
|
253
|
+
for elarg, arg in enumerate(args):
|
|
254
|
+
toprint = (elarg, type(arg),)
|
|
255
|
+
if isinstance(arg, np.ndarray):
|
|
256
|
+
toprint += (type(arg[0]), arg.shape)
|
|
257
|
+
try:
|
|
258
|
+
toprint += (func.argtypes[elarg], )
|
|
259
|
+
print(toprint)
|
|
260
|
+
print(arg)
|
|
261
|
+
except:
|
|
262
|
+
print("We did have a problem for arg %i"%elarg)
|
|
263
|
+
|
|
264
|
+
## Compute 4th order stats ##
|
|
265
|
+
func(*args)
|
|
266
|
+
|
|
267
|
+
## Massage the output ##
|
|
268
|
+
istatout = ()
|
|
269
|
+
self.bin_centers = bin_centers.reshape(szr)
|
|
270
|
+
self.bin_centers_mean = np.mean(self.bin_centers, axis=0)
|
|
271
|
+
if "4pcf_multipole" in statistics:
|
|
272
|
+
self.npcf_multipoles = N_n.reshape(sc)
|
|
273
|
+
if "4pcf_real" in statistics:
|
|
274
|
+
if lowmem:
|
|
275
|
+
self.npcf = fourpcf.reshape(s4pcf)
|
|
276
|
+
else:
|
|
277
|
+
if self._verbose_python:
|
|
278
|
+
print("Transforming output to real space basis")
|
|
279
|
+
self.multipoles2npcf_c()
|
|
280
|
+
if hasintegratedstats:
|
|
281
|
+
if "N4" in statistics:
|
|
282
|
+
istatout += (N4correlators.reshape((self.nzcombis,len(mapradii))), )
|
|
283
|
+
# TODO allocate map4, map4c etc.
|
|
284
|
+
|
|
285
|
+
return istatout
|
|
286
|
+
|
|
287
|
+
def multipoles2npcf_singlethetcombi(self, elthet1, elthet2, elthet3):
|
|
288
|
+
r""" Converts a 4PCF in the multipole basis in the real space basis for a fixed combination of radial bins.
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
--------
|
|
292
|
+
npcf_out: np.ndarray
|
|
293
|
+
Natural 4PCF components in the real-space basis for all angular combinations.
|
|
294
|
+
npcf_norm_out: np.ndarray
|
|
295
|
+
4PCF weighted counts in the real-space basis for all angular combinations.
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
_phis1 = self.phis[0].astype(np.float64)
|
|
299
|
+
_phis2 = self.phis[1].astype(np.float64)
|
|
300
|
+
_nphis1 = len(self.phis[0])
|
|
301
|
+
_nphis2 = len(self.phis[1])
|
|
302
|
+
nnvals, _, nzcombis, nbinsr, _, _ = np.shape(self.npcf_multipoles)
|
|
303
|
+
|
|
304
|
+
N_in = self.npcf_multipoles[...,elthet1,elthet2,elthet3].flatten()
|
|
305
|
+
npcf_out = np.zeros(nzcombis*_nphis1*_nphis2, dtype=np.complex128)
|
|
306
|
+
|
|
307
|
+
self.clib.multipoles2npcf_nnnn_singletheta(
|
|
308
|
+
N_in, self.nmaxs[0], self.nmaxs[1],
|
|
309
|
+
self.bin_centers_mean[elthet1], self.bin_centers_mean[elthet2], self.bin_centers_mean[elthet3],
|
|
310
|
+
_phis1, _phis2, _nphis1, _nphis2,
|
|
311
|
+
npcf_out)
|
|
312
|
+
|
|
313
|
+
return npcf_out.reshape(( _nphis1,_nphis2))
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
class GGGGCorrelation_NoTomo(BinnedNPCF):
|
|
317
|
+
r""" Class containing methods to measure and and obtain statistics that are built
|
|
318
|
+
from nontomographic fourth-order shear correlation functions.
|
|
319
|
+
|
|
320
|
+
Attributes
|
|
321
|
+
----------
|
|
322
|
+
min_sep: float
|
|
323
|
+
The smallest distance of each vertex for which the NPCF is computed.
|
|
324
|
+
max_sep: float
|
|
325
|
+
The largest distance of each vertex for which the NPCF is computed.
|
|
326
|
+
thetabatchsize_max: int, optional
|
|
327
|
+
The largest number of radial bin combinations that are processed in parallel.
|
|
328
|
+
Defaults to ``10 000``.
|
|
329
|
+
|
|
330
|
+
Notes
|
|
331
|
+
-----
|
|
332
|
+
Inherits all other parameters and attributes from :class:`BinnedNPCF`.
|
|
333
|
+
Additional child-specific parameters can be passed via ``kwargs``.
|
|
334
|
+
Either ``nbinsr`` or ``binsize`` has to be provided to fix the binning scheme .
|
|
335
|
+
|
|
336
|
+
"""
|
|
337
|
+
|
|
338
|
+
def __init__(self, min_sep, max_sep, thetabatchsize_max=10000, method="Tree", **kwargs):
|
|
339
|
+
|
|
340
|
+
super().__init__(order=4, spins=np.array([2,2,2,2], dtype=np.int32),
|
|
341
|
+
n_cfs=8, min_sep=min_sep, max_sep=max_sep,
|
|
342
|
+
method=method, methods_avail=["Discrete", "Tree"], **kwargs)
|
|
343
|
+
|
|
344
|
+
self.thetabatchsize_max = thetabatchsize_max
|
|
345
|
+
self.projection = None
|
|
346
|
+
self.projections_avail = [None, "X", "Centroid"]
|
|
347
|
+
self.proj_dict = {"X":0, "Centroid":1}
|
|
348
|
+
self.nbinsz = 1
|
|
349
|
+
self.nzcombis = 1
|
|
350
|
+
|
|
351
|
+
# (Add here any newly implemented projections)
|
|
352
|
+
self._initprojections(self)
|
|
353
|
+
self.project["X"]["Centroid"] = self._x2centroid
|
|
354
|
+
|
|
355
|
+
def process(self, cat, statistics="all", tofile=False, apply_edge_correction=False, projection="X",
|
|
356
|
+
lowmem=None, mapradii=None, batchsize=None, custom_thetacombis=None, cutlen=2**31-1):
|
|
357
|
+
r"""
|
|
358
|
+
Arguments:
|
|
359
|
+
|
|
360
|
+
Logic works as follows:
|
|
361
|
+
* Keyword 'statistics' \in [4pcf_real, 4pcf_multipoles, M4, Map4, M4c, Map4c, allMap, all4pcf, all]
|
|
362
|
+
* - If 4pcf_multipoles in statistics --> save 4pcf_multipoles
|
|
363
|
+
* - If 4pcf_real in statistics --> save 4pcf_real
|
|
364
|
+
* - If only M4 in statistics --> Do not save any 4pcf. This is really the lowmem case.
|
|
365
|
+
* - allMap, all4pcf, all are abbreviations as expected
|
|
366
|
+
* If lowmem=True, uses the inefficient, but lowmem function for computation and output statistics
|
|
367
|
+
from there as wanted.
|
|
368
|
+
* If lowmem=False, use the fast functions to do the 4pcf multipole computation and do
|
|
369
|
+
the potential conversions lateron.
|
|
370
|
+
* Default lowmem to None and
|
|
371
|
+
* - Set to true if any aperture statistics is in stats or we will run into mem error
|
|
372
|
+
* - Set to false otherwise
|
|
373
|
+
* - Raise error if lowmen=False and we will have more that 2^31-1 elements at any stage of the computation
|
|
374
|
+
|
|
375
|
+
custom_thetacombis: array of inds which theta combis will be selected
|
|
376
|
+
"""
|
|
377
|
+
|
|
378
|
+
## Preparations ##
|
|
379
|
+
# Build list of statistics to be calculated
|
|
380
|
+
statistics_avail_4pcf = ["4pcf_real", "4pcf_multipole"]
|
|
381
|
+
statistics_avail_map4 = ["M4", "Map4", "M4c", "Map4c"]
|
|
382
|
+
statistics_avail_comp = ["allMap", "all4pcf", "all"]
|
|
383
|
+
statistics_avail_phys = statistics_avail_4pcf + statistics_avail_map4
|
|
384
|
+
statistics_avail = statistics_avail_4pcf + statistics_avail_map4 + statistics_avail_comp
|
|
385
|
+
_statistics = []
|
|
386
|
+
hasintegratedstats = False
|
|
387
|
+
_strbadstats = lambda stat: ("The statistics `%s` has not been implemented yet. "%stat +
|
|
388
|
+
"Currently supported statistics are:\n" + str(statistics_avail))
|
|
389
|
+
if type(statistics) not in [list, str]:
|
|
390
|
+
raise ValueError("The parameter `statistics` should either be a list or a string.")
|
|
391
|
+
if type(statistics) is str:
|
|
392
|
+
if statistics not in statistics_avail:
|
|
393
|
+
raise ValueError(_strbadstats)
|
|
394
|
+
statistics = [statistics]
|
|
395
|
+
if type(statistics) is list:
|
|
396
|
+
if "all" in statistics:
|
|
397
|
+
_statistics = statistics_avail_phys
|
|
398
|
+
elif "all4pcf" in statistics:
|
|
399
|
+
_statistics.append(statistics_avail_4pcf)
|
|
400
|
+
elif "allMap" in statistics:
|
|
401
|
+
_statistics.append(statistics_avail_map4)
|
|
402
|
+
_statistics = flatlist(_statistics)
|
|
403
|
+
for stat in statistics:
|
|
404
|
+
if stat not in statistics_avail:
|
|
405
|
+
raise ValueError(_strbadstats)
|
|
406
|
+
if stat in statistics_avail_phys and stat not in _statistics:
|
|
407
|
+
_statistics.append(stat)
|
|
408
|
+
statistics = list(set(flatlist(_statistics)))
|
|
409
|
+
for stat in statistics:
|
|
410
|
+
if stat in statistics_avail_map4:
|
|
411
|
+
hasintegratedstats = True
|
|
412
|
+
|
|
413
|
+
# Check if the output will fit in memory
|
|
414
|
+
if "4pcf_multipole" in statistics:
|
|
415
|
+
_nvals = 8*self.nzcombis*(2*self.nmaxs[0]+1)*(2*self.nmaxs[1]+1)*self.nbinsr**3
|
|
416
|
+
if _nvals>cutlen:
|
|
417
|
+
raise ValueError(("4pcf in multipole basis will cause memory overflow " +
|
|
418
|
+
"(requiring %.2fx10^9 > %.2fx10^9 elements)\n"%(_nvals/1e9, cutlen/1e9) +
|
|
419
|
+
"If you are solely interested in integrated statistics (like Map4), you" +
|
|
420
|
+
"only need to add those to the `statistics` argument."))
|
|
421
|
+
if "4pcf_real" in statistics:
|
|
422
|
+
_nvals = 8*self.nzcombis*self.nbinsphi[0]*self.nbinsphi[1]*self.nbinsr**3
|
|
423
|
+
if _nvals>cutlen:
|
|
424
|
+
raise ValueError(("4pcf in real basis will cause memory overflow " +
|
|
425
|
+
"(requiring %.2fx10^9 > %.2fx10^9 elements)\n"%(_nvals/1e9, cutlen/1e9) +
|
|
426
|
+
"If you are solely interested in integrated statistics (like Map4), you" +
|
|
427
|
+
"only need to add those to the `statistics` argument."))
|
|
428
|
+
|
|
429
|
+
# Decide on whether to use low-mem functions or not
|
|
430
|
+
if hasintegratedstats:
|
|
431
|
+
if lowmem in [False, None]:
|
|
432
|
+
if not lowmem:
|
|
433
|
+
print("Low-memory computation enforced for integrated measures of the 4pcf. " +
|
|
434
|
+
"Set `lowmem` from `%s` to `True`"%str(lowmem))
|
|
435
|
+
lowmem = True
|
|
436
|
+
else:
|
|
437
|
+
if lowmem in [None, False]:
|
|
438
|
+
maxlen = 0
|
|
439
|
+
_lowmem = False
|
|
440
|
+
if "4pcf_multipole" in statistics:
|
|
441
|
+
_nvals = 8*self.nzcombis*(2*self.nmaxs[0]+1)*(2*self.nmaxs[1]+1)*self.nbinsr**3
|
|
442
|
+
if _nvals > cutlen:
|
|
443
|
+
if not lowmem:
|
|
444
|
+
print("Switching to low-memory computation of 4pcf in multipole basis.")
|
|
445
|
+
lowmem = True
|
|
446
|
+
else:
|
|
447
|
+
lowmem = False
|
|
448
|
+
if "4pcf_real" in statistics:
|
|
449
|
+
nvals = 8*self.nzcombis*self.nbinsphi[0]*self.nbinsphi[1]*self.nbinsr**3
|
|
450
|
+
if _nvals > cutlen:
|
|
451
|
+
if not lowmem:
|
|
452
|
+
print("Switching to low-memory computation of 4pcf in real basis.")
|
|
453
|
+
lowmem = True
|
|
454
|
+
else:
|
|
455
|
+
lowmem = False
|
|
456
|
+
|
|
457
|
+
# Misc checks
|
|
458
|
+
assert(projection in self.projections_avail)
|
|
459
|
+
self._checkcats(cat, self.spins)
|
|
460
|
+
i_projection = np.int32(self.proj_dict[projection])
|
|
461
|
+
|
|
462
|
+
## Build args for wrapped functions ##
|
|
463
|
+
# Shortcuts
|
|
464
|
+
_nmax = self.nmaxs[0]
|
|
465
|
+
_nnvals = (2*_nmax+1)*(2*_nmax+1)
|
|
466
|
+
_nbinsr3 = self.nbinsr*self.nbinsr*self.nbinsr
|
|
467
|
+
_nphis = len(self.phis[0])
|
|
468
|
+
sc = (8,2*_nmax+1,2*_nmax+1,self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr)
|
|
469
|
+
sn = (2*_nmax+1,2*_nmax+1,self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr)
|
|
470
|
+
szr = (self.nbinsz, self.nbinsr)
|
|
471
|
+
s4pcf = (8,self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr,_nphis,_nphis)
|
|
472
|
+
s4pcfn = (self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr,_nphis,_nphis)
|
|
473
|
+
# Init default args
|
|
474
|
+
bin_centers = np.zeros(self.nbinsz*self.nbinsr).astype(np.float64)
|
|
475
|
+
if not cat.hasspatialhash:
|
|
476
|
+
cat.build_spatialhash(dpix=max(1.,self.max_sep//10.))
|
|
477
|
+
nregions = np.int32(len(np.argwhere(cat.index_matcher>-1).flatten()))
|
|
478
|
+
args_basecat = (cat.isinner.astype(np.float64), cat.weight, cat.pos1, cat.pos2,
|
|
479
|
+
cat.tracer_1, cat.tracer_2, np.int32(cat.ngal), )
|
|
480
|
+
args_hash = (cat.index_matcher, cat.pixs_galind_bounds, cat.pix_gals, nregions,
|
|
481
|
+
np.float64(cat.pix1_start), np.float64(cat.pix1_d), np.int32(cat.pix1_n),
|
|
482
|
+
np.float64(cat.pix2_start), np.float64(cat.pix2_d), np.int32(cat.pix2_n), )
|
|
483
|
+
|
|
484
|
+
# Init optional args
|
|
485
|
+
__lenflag = 10
|
|
486
|
+
__fillflag = -1
|
|
487
|
+
if "4pcf_multipole" in statistics:
|
|
488
|
+
Upsilon_n = np.zeros(self.n_cfs*_nnvals*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
489
|
+
N_n = np.zeros(_nnvals*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
490
|
+
alloc_4pcfmultipoles = 1
|
|
491
|
+
else:
|
|
492
|
+
Upsilon_n = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
493
|
+
N_n = __fillflag*np.zeros(__lenflag).astype(np.complex128)
|
|
494
|
+
alloc_4pcfmultipoles = 0
|
|
495
|
+
if "4pcf_real" in statistics:
|
|
496
|
+
fourpcf = np.zeros(8*_nphis*_nphis*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
497
|
+
fourpcf_norm = np.zeros(_nphis*_nphis*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
498
|
+
alloc_4pcfreal = 1
|
|
499
|
+
else:
|
|
500
|
+
fourpcf = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
501
|
+
fourpcf_norm = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
502
|
+
alloc_4pcfreal = 0
|
|
503
|
+
if hasintegratedstats:
|
|
504
|
+
if mapradii is None:
|
|
505
|
+
raise ValueError("Aperture radii need to be specified in variable `mapradii`.")
|
|
506
|
+
mapradii = mapradii.astype(np.float64)
|
|
507
|
+
M4correlators = np.zeros(8*self.nzcombis*len(mapradii)).astype(np.complex128)
|
|
508
|
+
else:
|
|
509
|
+
mapradii = __fillflag*np.ones(__lenflag).astype(np.float64)
|
|
510
|
+
N4correlators = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
511
|
+
|
|
512
|
+
# Build args based on chosen methods
|
|
513
|
+
if self.method=="Discrete" and not lowmem:
|
|
514
|
+
args_basesetup = (np.int32(_nmax), np.float64(self.min_sep),
|
|
515
|
+
np.float64(self.max_sep), np.array([-1.]).astype(np.float64),
|
|
516
|
+
np.int32(self.nbinsr), np.int32(self.multicountcorr), )
|
|
517
|
+
args = (*args_basecat,
|
|
518
|
+
*args_basesetup,
|
|
519
|
+
*args_hash,
|
|
520
|
+
np.int32(self.nthreads),
|
|
521
|
+
np.int32(self._verbose_c+self._verbose_debug),
|
|
522
|
+
bin_centers,
|
|
523
|
+
Upsilon_n,
|
|
524
|
+
N_n)
|
|
525
|
+
func = self.clib.alloc_notomoGammans_discrete_gggg
|
|
526
|
+
if self.method=="Discrete" and lowmem:
|
|
527
|
+
_resradial = gen_thetacombis_fourthorder(nbinsr=self.nbinsr, nthreads=self.nthreads, batchsize=batchsize,
|
|
528
|
+
batchsize_max=self.thetabatchsize_max, ordered=True, custom=custom_thetacombis,
|
|
529
|
+
verbose=self._verbose_python)
|
|
530
|
+
_, _, thetacombis_batches, cumnthetacombis_batches, nthetacombis_batches, nbatches = _resradial
|
|
531
|
+
|
|
532
|
+
args_basesetup = (np.int32(_nmax),
|
|
533
|
+
np.float64(self.min_sep), np.float64(self.max_sep), np.int32(self.nbinsr),
|
|
534
|
+
np.int32(self.multicountcorr),
|
|
535
|
+
self.phis[0].astype(np.float64),
|
|
536
|
+
2*np.pi/_nphis*np.ones(_nphis, dtype=np.float64), np.int32(_nphis))
|
|
537
|
+
args_4pcf = (np.int32(alloc_4pcfmultipoles), np.int32(alloc_4pcfreal),
|
|
538
|
+
bin_centers, Upsilon_n, N_n, fourpcf, fourpcf_norm, )
|
|
539
|
+
args_thetas = (thetacombis_batches, nthetacombis_batches, cumnthetacombis_batches, nbatches, )
|
|
540
|
+
args_map4 = (mapradii, np.int32(len(mapradii)), M4correlators)
|
|
541
|
+
args = (*args_basecat,
|
|
542
|
+
*args_basesetup,
|
|
543
|
+
*args_hash,
|
|
544
|
+
*args_thetas,
|
|
545
|
+
np.int32(self.nthreads),
|
|
546
|
+
np.int32(self._verbose_c+self._verbose_debug),
|
|
547
|
+
i_projection,
|
|
548
|
+
*args_map4,
|
|
549
|
+
*args_4pcf)
|
|
550
|
+
func = self.clib.alloc_notomoMap4_disc_gggg
|
|
551
|
+
if self.method=="Tree":
|
|
552
|
+
# Prepare mask for nonredundant theta- and multipole configurations
|
|
553
|
+
_resradial = gen_thetacombis_fourthorder(nbinsr=self.nbinsr, nthreads=self.nthreads, batchsize=batchsize,
|
|
554
|
+
batchsize_max=self.thetabatchsize_max, ordered=True, custom=custom_thetacombis,
|
|
555
|
+
verbose=self._verbose_python*lowmem)
|
|
556
|
+
_, _, thetacombis_batches, cumnthetacombis_batches, nthetacombis_batches, nbatches = _resradial
|
|
557
|
+
assert(self.nmaxs[0]==self.nmaxs[1])
|
|
558
|
+
_resmultipoles = gen_n2n3indices_Upsfourth(self.nmaxs[0])
|
|
559
|
+
_shape, _inds, _n2s, _n3s = _resmultipoles
|
|
560
|
+
|
|
561
|
+
# Prepare reduced catalogs
|
|
562
|
+
cutfirst = np.int32(self.tree_resos[0]==0.)
|
|
563
|
+
mhash = cat.multihash(dpixs=self.tree_resos[cutfirst:], dpix_hash=self.tree_resos[-1],
|
|
564
|
+
shuffle=self.shuffle_pix, w2field=True, normed=True)
|
|
565
|
+
(ngal_resos, pos1s, pos2s, weights, zbins, isinners, allfields,
|
|
566
|
+
index_matchers, pixs_galind_bounds, pix_gals, dpixs1_true, dpixs2_true) = mhash
|
|
567
|
+
weight_resos = np.concatenate(weights).astype(np.float64)
|
|
568
|
+
pos1_resos = np.concatenate(pos1s).astype(np.float64)
|
|
569
|
+
pos2_resos = np.concatenate(pos2s).astype(np.float64)
|
|
570
|
+
zbin_resos = np.concatenate(zbins).astype(np.int32)
|
|
571
|
+
isinner_resos = np.concatenate(isinners).astype(np.float64)
|
|
572
|
+
e1_resos = np.concatenate([allfields[i][0] for i in range(len(allfields))]).astype(np.float64)
|
|
573
|
+
e2_resos = np.concatenate([allfields[i][1] for i in range(len(allfields))]).astype(np.float64)
|
|
574
|
+
index_matcher_resos = np.concatenate(index_matchers).astype(np.int32)
|
|
575
|
+
pixs_galind_bounds_resos = np.concatenate(pixs_galind_bounds).astype(np.int32)
|
|
576
|
+
pix_gals_resos = np.concatenate(pix_gals).astype(np.int32)
|
|
577
|
+
index_matcher_flat = np.argwhere(cat.index_matcher>-1).flatten()
|
|
578
|
+
nregions = len(index_matcher_flat)
|
|
579
|
+
if not lowmem:
|
|
580
|
+
args_basesetup = (np.int32(_nmax),
|
|
581
|
+
np.float64(self.min_sep), np.float64(self.max_sep), np.int32(self.nbinsr),
|
|
582
|
+
np.int32(cumnthetacombis_batches[-1]), np.int32(self.multicountcorr),
|
|
583
|
+
_inds, np.int32(len(_inds)),)
|
|
584
|
+
args_resos = (np.int32(self.tree_nresos), self.tree_redges, np.array(ngal_resos, dtype=np.int32),
|
|
585
|
+
isinner_resos, weight_resos, pos1_resos, pos2_resos, e1_resos, e2_resos,
|
|
586
|
+
index_matcher_resos, pixs_galind_bounds_resos, pix_gals_resos, np.int32(nregions), )
|
|
587
|
+
args_hash = (np.float64(cat.pix1_start), np.float64(cat.pix1_d), np.int32(cat.pix1_n),
|
|
588
|
+
np.float64(cat.pix2_start), np.float64(cat.pix2_d), np.int32(cat.pix2_n), )
|
|
589
|
+
args_out = ( bin_centers, Upsilon_n, N_n, )
|
|
590
|
+
args = (*args_basecat,
|
|
591
|
+
*args_basesetup,
|
|
592
|
+
*args_resos,
|
|
593
|
+
*args_hash,
|
|
594
|
+
np.int32(self.nthreads),
|
|
595
|
+
np.int32(self._verbose_c+self._verbose_debug),
|
|
596
|
+
*args_out)
|
|
597
|
+
func = self.clib.alloc_notomoGammans_tree_gggg
|
|
598
|
+
if lowmem:
|
|
599
|
+
# Build args
|
|
600
|
+
args_basesetup = (np.int32(_nmax),
|
|
601
|
+
np.float64(self.min_sep), np.float64(self.max_sep), np.int32(self.nbinsr),
|
|
602
|
+
np.int32(self.multicountcorr),
|
|
603
|
+
_inds, np.int32(len(_inds)), self.phis[0].astype(np.float64),
|
|
604
|
+
2*np.pi/_nphis*np.ones(_nphis, dtype=np.float64), np.int32(_nphis), )
|
|
605
|
+
args_resos = (np.int32(self.tree_nresos), self.tree_redges, np.array(ngal_resos, dtype=np.int32),
|
|
606
|
+
isinner_resos, weight_resos, pos1_resos, pos2_resos, e1_resos, e2_resos,
|
|
607
|
+
index_matcher_resos, pixs_galind_bounds_resos, pix_gals_resos, np.int32(nregions), )
|
|
608
|
+
args_hash = (np.float64(cat.pix1_start), np.float64(cat.pix1_d), np.int32(cat.pix1_n),
|
|
609
|
+
np.float64(cat.pix2_start), np.float64(cat.pix2_d), np.int32(cat.pix2_n), )
|
|
610
|
+
args_thetas = (thetacombis_batches, nthetacombis_batches, cumnthetacombis_batches, nbatches, )
|
|
611
|
+
args_map4 = (mapradii, np.int32(len(mapradii)), M4correlators)
|
|
612
|
+
args_4pcf = (np.int32(alloc_4pcfmultipoles), np.int32(alloc_4pcfreal),
|
|
613
|
+
bin_centers, Upsilon_n, N_n, fourpcf, fourpcf_norm, )
|
|
614
|
+
args = (*args_basecat,
|
|
615
|
+
*args_basesetup,
|
|
616
|
+
*args_resos,
|
|
617
|
+
*args_hash,
|
|
618
|
+
*args_thetas,
|
|
619
|
+
np.int32(self.nthreads),
|
|
620
|
+
np.int32(self._verbose_c+self._verbose_debug),
|
|
621
|
+
i_projection,
|
|
622
|
+
*args_map4,
|
|
623
|
+
*args_4pcf)
|
|
624
|
+
func = self.clib.alloc_notomoMap4_tree_gggg
|
|
625
|
+
|
|
626
|
+
# Optionally print the arguments
|
|
627
|
+
if self._verbose_debug:
|
|
628
|
+
print("We pass the following arguments:")
|
|
629
|
+
for elarg, arg in enumerate(args):
|
|
630
|
+
toprint = (elarg, type(arg),)
|
|
631
|
+
if isinstance(arg, np.ndarray):
|
|
632
|
+
toprint += (type(arg[0]), arg.shape)
|
|
633
|
+
try:
|
|
634
|
+
toprint += (func.argtypes[elarg], )
|
|
635
|
+
print(toprint)
|
|
636
|
+
print(arg)
|
|
637
|
+
except:
|
|
638
|
+
print("We did have a problem for arg %i"%elarg)
|
|
639
|
+
|
|
640
|
+
## Compute 4th order stats ##
|
|
641
|
+
func(*args)
|
|
642
|
+
self.projection = projection
|
|
643
|
+
|
|
644
|
+
## Massage the output ##
|
|
645
|
+
istatout = ()
|
|
646
|
+
self.bin_centers = bin_centers.reshape(szr)
|
|
647
|
+
self.bin_centers_mean = np.mean(self.bin_centers, axis=0)
|
|
648
|
+
if "4pcf_multipole" in statistics:
|
|
649
|
+
self.npcf_multipoles = Upsilon_n.reshape(sc)
|
|
650
|
+
self.npcf_multipoles_norm = N_n.reshape(sn)
|
|
651
|
+
if "4pcf_real" in statistics:
|
|
652
|
+
if lowmem:
|
|
653
|
+
self.npcf = fourpcf.reshape(s4pcf)
|
|
654
|
+
self.npcf_norm = fourpcf_norm.reshape(s4pcfn)
|
|
655
|
+
else:
|
|
656
|
+
if self._verbose_python:
|
|
657
|
+
print("Transforming output to real space basis")
|
|
658
|
+
self.multipoles2npcf_c(projection=projection)
|
|
659
|
+
if hasintegratedstats:
|
|
660
|
+
if "M4" in statistics:
|
|
661
|
+
istatout += (M4correlators.reshape((8,self.nzcombis,len(mapradii))), )
|
|
662
|
+
# TODO allocate map4, map4c etc.
|
|
663
|
+
|
|
664
|
+
return istatout
|
|
665
|
+
|
|
666
|
+
def multipoles2npcf_c(self, projection="X"):
|
|
667
|
+
r""" Converts a 4PCF in the multipole basis in the real space basis.
|
|
668
|
+
"""
|
|
669
|
+
assert((projection in self.proj_dict.keys()) and (projection in self.projections_avail))
|
|
670
|
+
|
|
671
|
+
_nzero1 = self.nmaxs[0]
|
|
672
|
+
_nzero2 = self.nmaxs[1]
|
|
673
|
+
_phis1 = self.phis[0].astype(np.float64)
|
|
674
|
+
_phis2 = self.phis[1].astype(np.float64)
|
|
675
|
+
_nphis1 = len(self.phis[0])
|
|
676
|
+
_nphis2 = len(self.phis[1])
|
|
677
|
+
ncfs, nnvals, _, nzcombis, nbinsr, _, _ = np.shape(self.npcf_multipoles)
|
|
678
|
+
|
|
679
|
+
shape_npcf = (self.n_cfs, nzcombis, nbinsr, nbinsr, nbinsr, _nphis1, _nphis2)
|
|
680
|
+
shape_npcf_norm = (nzcombis, nbinsr, nbinsr, nbinsr, _nphis1, _nphis2)
|
|
681
|
+
self.npcf = np.zeros(self.n_cfs*nzcombis*nbinsr*nbinsr*nbinsr*_nphis1*_nphis2, dtype=np.complex128)
|
|
682
|
+
self.npcf_norm = np.zeros(nzcombis*nbinsr*nbinsr*nbinsr*_nphis1*_nphis2, dtype=np.complex128)
|
|
683
|
+
self.clib.multipoles2npcf_gggg(self.npcf_multipoles.flatten(), self.npcf_multipoles_norm.flatten(),
|
|
684
|
+
self.bin_centers_mean.astype(np.float64), np.int32(self.proj_dict[projection]),
|
|
685
|
+
8, nbinsr, self.nmaxs[0].astype(np.int32), _phis1, _nphis1, _phis2, _nphis2,
|
|
686
|
+
self.nthreads, self.npcf, self.npcf_norm)
|
|
687
|
+
self.npcf = self.npcf.reshape(shape_npcf)
|
|
688
|
+
self.npcf_norm = self.npcf_norm.reshape(shape_npcf_norm)
|
|
689
|
+
self.projection = projection
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
def multipoles2npcf_singlethetcombi(self, elthet1, elthet2, elthet3, projection="X"):
|
|
693
|
+
r""" Converts a 4PCF in the multipole basis in the real space basis for a fixed combination of radial bins.
|
|
694
|
+
|
|
695
|
+
Returns:
|
|
696
|
+
--------
|
|
697
|
+
npcf_out: np.ndarray
|
|
698
|
+
Natural 4PCF components in the real-space bassi for all angular combinations.
|
|
699
|
+
npcf_norm_out: np.ndarray
|
|
700
|
+
4PCF weighted counts in the real-space bassi for all angular combinations.
|
|
701
|
+
"""
|
|
702
|
+
assert((projection in self.proj_dict.keys()) and (projection in self.projections_avail))
|
|
703
|
+
|
|
704
|
+
_phis1 = self.phis[0].astype(np.float64)
|
|
705
|
+
_phis2 = self.phis[1].astype(np.float64)
|
|
706
|
+
_nphis1 = len(self.phis[0])
|
|
707
|
+
_nphis2 = len(self.phis[1])
|
|
708
|
+
ncfs, nnvals, _, nzcombis, nbinsr, _, _ = np.shape(self.npcf_multipoles)
|
|
709
|
+
|
|
710
|
+
Upsilon_in = self.npcf_multipoles[...,elthet1,elthet2,elthet3].flatten()
|
|
711
|
+
N_in = self.npcf_multipoles_norm[...,elthet1,elthet2,elthet3].flatten()
|
|
712
|
+
npcf_out = np.zeros(self.n_cfs*nzcombis*_nphis1*_nphis2, dtype=np.complex128)
|
|
713
|
+
npcf_norm_out = np.zeros(nzcombis*_nphis1*_nphis2, dtype=np.complex128)
|
|
714
|
+
|
|
715
|
+
self.clib.multipoles2npcf_gggg_singletheta(
|
|
716
|
+
Upsilon_in, N_in, self.nmaxs[0], self.nmaxs[1],
|
|
717
|
+
self.bin_centers_mean[elthet1], self.bin_centers_mean[elthet2], self.bin_centers_mean[elthet3],
|
|
718
|
+
_phis1, _phis2, _nphis1, _nphis2,
|
|
719
|
+
np.int32(self.proj_dict[projection]), npcf_out, npcf_norm_out)
|
|
720
|
+
|
|
721
|
+
return npcf_out.reshape((self.n_cfs, _nphis1,_nphis2)), npcf_norm_out.reshape((_nphis1,_nphis2))
|
|
722
|
+
|
|
723
|
+
def multipoles2npcf_gggg_singletheta_nconvergence(self, elthet1, elthet2, elthet3, projection="X"):
|
|
724
|
+
r""" Checks convergence of the conversion between mutltipole-space and real space for a combination of radial bins.
|
|
725
|
+
|
|
726
|
+
Returns:
|
|
727
|
+
--------
|
|
728
|
+
npcf_out: np.ndarray
|
|
729
|
+
Natural 4PCF components in the real-space basis for all angular combinations.
|
|
730
|
+
npcf_norm_out: np.ndarray
|
|
731
|
+
4PCF weighted counts in the real-space basis for all angular combinations.
|
|
732
|
+
"""
|
|
733
|
+
assert((projection in self.proj_dict.keys()) and (projection in self.projections_avail))
|
|
734
|
+
|
|
735
|
+
_phis1 = self.phis[0].astype(np.float64)
|
|
736
|
+
_phis2 = self.phis[1].astype(np.float64)
|
|
737
|
+
_nphis1 = len(self.phis[0])
|
|
738
|
+
_nphis2 = len(self.phis[1])
|
|
739
|
+
|
|
740
|
+
ncfs, nnvals, _, nzcombis, nbinsr, _, _ = np.shape(self.npcf_multipoles)
|
|
741
|
+
|
|
742
|
+
Upsilon_in = self.npcf_multipoles[...,elthet1,elthet2,elthet3].flatten()
|
|
743
|
+
N_in = self.npcf_multipoles_norm[...,elthet1,elthet2,elthet3].flatten()
|
|
744
|
+
npcf_out = np.zeros(self.n_cfs*nzcombis*(self.nmaxs[0]+1)*(self.nmaxs[1]+1)*_nphis1*_nphis2, dtype=np.complex128)
|
|
745
|
+
npcf_norm_out = np.zeros(nzcombis*(self.nmaxs[0]+1)*(self.nmaxs[1]+1)*_nphis1*_nphis2, dtype=np.complex128)
|
|
746
|
+
|
|
747
|
+
self.clib.multipoles2npcf_gggg_singletheta_nconvergence(
|
|
748
|
+
Upsilon_in, N_in, self.nmaxs[0], self.nmaxs[1],
|
|
749
|
+
self.bin_centers_mean[elthet1], self.bin_centers_mean[elthet2], self.bin_centers_mean[elthet3],
|
|
750
|
+
_phis1, _phis2, _nphis1, _nphis2,
|
|
751
|
+
np.int32(self.proj_dict[projection]), npcf_out, npcf_norm_out)
|
|
752
|
+
|
|
753
|
+
npcf_out = npcf_out.reshape((self.n_cfs, self.nmaxs[0]+1, self.nmaxs[1]+1, _nphis1, _nphis2))
|
|
754
|
+
npcf_norm_out = npcf_norm_out.reshape((self.nmaxs[0]+1, self.nmaxs[1]+1, _nphis1, _nphis2))
|
|
755
|
+
|
|
756
|
+
return npcf_out, npcf_norm_out
|
|
757
|
+
|
|
758
|
+
def computeMap4(self, radii, nmax_trafo=None, basis='MapMx'):
|
|
759
|
+
r"""Computes the fourth-order aperture mass statistcs using the polynomial filter of Crittenden 2002."""
|
|
760
|
+
|
|
761
|
+
assert(basis in ['MapMx','MM*','both'])
|
|
762
|
+
|
|
763
|
+
if nmax_trafo is None:
|
|
764
|
+
nmax_trafo=self.nmaxs[0]
|
|
765
|
+
|
|
766
|
+
# Retrieve all the aperture measures in the MM* basis via the 5D transformation eqns
|
|
767
|
+
M4correlators = np.zeros(8*len(radii), dtype=np.complex128)
|
|
768
|
+
self.clib.fourpcfmultipoles2M4correlators(
|
|
769
|
+
np.int32(self.nmaxs[0]), np.int32(nmax_trafo),
|
|
770
|
+
self.bin_edges, self.bin_centers_mean, np.int32(self.nbinsr),
|
|
771
|
+
radii.astype(np.float64), np.int32(len(radii)),
|
|
772
|
+
self.phis[0].astype(np.float64), self.phis[1].astype(np.float64),
|
|
773
|
+
self.dphis[0].astype(np.float64), self.dphis[1].astype(np.float64),
|
|
774
|
+
len(self.phis[0]), len(self.phis[1]),
|
|
775
|
+
np.int32(self.proj_dict[self.projection]), np.int32(self.nthreads),
|
|
776
|
+
self.npcf_multipoles.flatten(), self.npcf_multipoles_norm.flatten(),
|
|
777
|
+
M4correlators)
|
|
778
|
+
res_MMStar = M4correlators.reshape((8,len(radii)))
|
|
779
|
+
|
|
780
|
+
# Allocate result
|
|
781
|
+
res = ()
|
|
782
|
+
if basis=='MM*' or basis=='both':
|
|
783
|
+
res += (res_MMStar, )
|
|
784
|
+
if basis=='MapMx' or basis=='both':
|
|
785
|
+
res += ( GGGGCorrelation_NoTomo.MMStar2MapMx_fourth(res_MMStar), )
|
|
786
|
+
|
|
787
|
+
return res
|
|
788
|
+
|
|
789
|
+
## PROJECTIONS ##
|
|
790
|
+
def projectnpcf(self, projection):
|
|
791
|
+
super()._projectnpcf(self, projection)
|
|
792
|
+
|
|
793
|
+
def _x2centroid(self):
|
|
794
|
+
gammas_cen = np.zeros_like(self.npcf)
|
|
795
|
+
pimod = lambda x: x%(2*np.pi) - 2*np.pi*(x%(2*np.pi)>=np.pi)
|
|
796
|
+
npcf_cen = np.zeros(self.npcf.shape, dtype=complex)
|
|
797
|
+
_centers = np.mean(self.bin_centers, axis=0)
|
|
798
|
+
for elb1, bin1 in enumerate(_centers):
|
|
799
|
+
for elb2, bin2 in enumerate(_centers):
|
|
800
|
+
for elb3, bin3 in enumerate(_centers):
|
|
801
|
+
phiexp = np.exp(1J*self.phis[0])
|
|
802
|
+
phiexp_c = np.exp(-1J*self.phis[0])
|
|
803
|
+
phi12grid, phi13grid = np.meshgrid(phiexp, phiexp)
|
|
804
|
+
phi12grid_c, phi13grid_c = np.meshgrid(phiexp_c, phiexp_c)
|
|
805
|
+
prod1 = (bin1 +bin2*phi12grid_c + bin3*phi13grid_c) /(bin1 + bin2*phi12grid + bin3*phi13grid) #q1
|
|
806
|
+
prod2 = (3*bin1 -bin2*phi12grid_c - bin3*phi13grid_c) /(3*bin1 - bin2*phi12grid - bin3*phi13grid) #q2
|
|
807
|
+
prod3 = (bin1 -3*bin2*phi12grid_c + bin3*phi13grid_c) /(bin1 - 3*bin2*phi12grid + bin3*phi13grid) #q3
|
|
808
|
+
prod4 = (bin1 +bin2*phi12grid_c - 3*bin3*phi13grid_c)/(bin1 + bin2*phi12grid - 3*bin3*phi13grid) #q4
|
|
809
|
+
prod1_inv = prod1.conj()/np.abs(prod1)
|
|
810
|
+
prod2_inv = prod2.conj()/np.abs(prod2)
|
|
811
|
+
prod3_inv = prod3.conj()/np.abs(prod3)
|
|
812
|
+
prod4_inv = prod4.conj()/np.abs(prod4)
|
|
813
|
+
rot_nom = np.zeros((8,len(self.phis[0]), len(self.phis[1])))
|
|
814
|
+
rot_nom[0] = pimod(np.angle(prod1 *prod2 *prod3 *prod4 * phi12grid**2 * phi13grid**3))
|
|
815
|
+
rot_nom[1] = pimod(np.angle(prod1_inv*prod2 *prod3 *prod4 * phi12grid**2 * phi13grid**1))
|
|
816
|
+
rot_nom[2] = pimod(np.angle(prod1 *prod2_inv*prod3 *prod4 * phi12grid**2 * phi13grid**3))
|
|
817
|
+
rot_nom[3] = pimod(np.angle(prod1 *prod2 *prod3_inv*prod4 * phi12grid_c**2 * phi13grid**3))
|
|
818
|
+
rot_nom[4] = pimod(np.angle(prod1 *prod2 *prod3 *prod4_inv * phi12grid**2 * phi13grid_c**1))
|
|
819
|
+
rot_nom[5] = pimod(np.angle(prod1_inv*prod2_inv*prod3 *prod4 * phi12grid**2 * phi13grid**1))
|
|
820
|
+
rot_nom[6] = pimod(np.angle(prod1_inv*prod2 *prod3_inv*prod4 * phi12grid_c**2 * phi13grid**1))
|
|
821
|
+
rot_nom[7] = pimod(np.angle(prod1_inv*prod2 *prod3 *prod4_inv * phi12grid**2 * phi13grid_c**3))
|
|
822
|
+
gammas_cen[:,:,elb1,elb2,elb3] = self.npcf[:,:,elb1,elb2,elb3]*np.exp(1j*rot_nom)[:,np.newaxis,:,:]
|
|
823
|
+
return gammas_cen
|
|
824
|
+
|
|
825
|
+
## GAUSSIAN-FIELD SPECIFIC FUNCTIONS ##
|
|
826
|
+
# Deprecate this as it has been ported to c
|
|
827
|
+
@staticmethod
|
|
828
|
+
def fourpcf_gauss_x(theta1, theta2, theta3, phi12, phi13, xipspl, ximspl):
|
|
829
|
+
""" Computes disconnected part of the 4pcf in the 'x'-projection
|
|
830
|
+
given a splined 2pcf
|
|
831
|
+
"""
|
|
832
|
+
allgammas = [None]*8
|
|
833
|
+
xprojs = [None]*8
|
|
834
|
+
y1 = theta1 * np.ones_like(phi12)
|
|
835
|
+
y2 = theta2*np.exp(1j*phi12)
|
|
836
|
+
y3 = theta3*np.exp(1j*phi13)
|
|
837
|
+
absy1 = np.abs(y1)
|
|
838
|
+
absy2 = np.abs(y2)
|
|
839
|
+
absy3 = np.abs(y3)
|
|
840
|
+
absy12 = np.abs(y2-y1)
|
|
841
|
+
absy13 = np.abs(y1-y3)
|
|
842
|
+
absy23 = np.abs(y3-y2)
|
|
843
|
+
q1 = -0.25*(y1+y2+y3)
|
|
844
|
+
q2 = 0.25*(3*y1-y2-y3)
|
|
845
|
+
q3 = 0.25*(3*y2-y3-y1)
|
|
846
|
+
q4 = 0.25*(3*y3-y1-y2)
|
|
847
|
+
q1c = q1.conj(); q2c = q2.conj(); q3c = q3.conj(); q4c = q4.conj();
|
|
848
|
+
y123_cub = (np.abs(y1)*np.abs(y2)*np.abs(y3))**3
|
|
849
|
+
ang1_4 = ((y1)/absy1)**4; ang2_4 = ((y2)/absy2)**4; ang3_4 = ((y3)/absy3)**4
|
|
850
|
+
ang12_4 = ((y2-y1)/absy12)**4; ang13_4 = ((y3-y1)/absy13)**4; ang23_4 = ((y3-y2)/absy23)**4;
|
|
851
|
+
xprojs[0] = (y1**3*y2**2*y3**3)/(np.abs(y1)**3*np.abs(y2)**2*np.abs(y3)**3)
|
|
852
|
+
xprojs[1] = (y1**1*y2**2*y3**1)/(np.abs(y1)**1*np.abs(y2)**2*np.abs(y3)**1)
|
|
853
|
+
xprojs[2] = (y1**-1*y2**2*y3**3)/(np.abs(y1)**-1*np.abs(y2)**2*np.abs(y3)**3)
|
|
854
|
+
xprojs[3] = (y1**3*y2**-2*y3**3)/(np.abs(y1)**3*np.abs(y2)**-2*np.abs(y3)**3)
|
|
855
|
+
xprojs[4] = (y1**3*y2**2*y3**-1)/(np.abs(y1)**3*np.abs(y2)**2*np.abs(y3)**-1)
|
|
856
|
+
xprojs[5] = (y1**-3*y2**2*y3**1)/(np.abs(y1)**-3*np.abs(y2)**2*np.abs(y3)**1)
|
|
857
|
+
xprojs[6] = (y1**1*y2**-2*y3**1)/(np.abs(y1)**1*np.abs(y2)**-2*np.abs(y3)**1)
|
|
858
|
+
xprojs[7] = (y1**1*y2**2*y3**-3)/(np.abs(y1)**1*np.abs(y2)**2*np.abs(y3)**-3)
|
|
859
|
+
allgammas[0] = 1./xprojs[0] * (
|
|
860
|
+
ang23_4 * ang1_4 * ximspl(absy23) * ximspl(absy1) +
|
|
861
|
+
ang13_4 * ang2_4 * ximspl(absy13) * ximspl(absy2) +
|
|
862
|
+
ang12_4 * ang3_4 * ximspl(absy12) * ximspl(absy3))
|
|
863
|
+
allgammas[1] = 1./xprojs[1] * (
|
|
864
|
+
ang23_4 * xipspl(absy1) * ximspl(absy23) +
|
|
865
|
+
ang13_4 * xipspl(absy2) * ximspl(absy13) +
|
|
866
|
+
ang12_4 * xipspl(absy3) * ximspl(absy12))
|
|
867
|
+
allgammas[2] = 1./xprojs[2] * (
|
|
868
|
+
ang23_4 * xipspl(absy1) * ximspl(absy23) +
|
|
869
|
+
ang2_4 * ximspl(absy2) * xipspl(absy13) +
|
|
870
|
+
ang3_4 * ximspl(absy3) * xipspl(absy12))
|
|
871
|
+
allgammas[3] = 1./xprojs[3] * (
|
|
872
|
+
ang1_4 * ximspl(absy1) * xipspl(absy23) +
|
|
873
|
+
ang13_4 * xipspl(absy2) * ximspl(absy13) +
|
|
874
|
+
ang3_4 * ximspl(absy3) * xipspl(absy12))
|
|
875
|
+
allgammas[4] = 1./xprojs[4] * (
|
|
876
|
+
ang1_4 * ximspl(absy1) * xipspl(absy23) +
|
|
877
|
+
ang2_4 * ximspl(absy2) * xipspl(absy13) +
|
|
878
|
+
ang12_4 * xipspl(absy3) * ximspl(absy12))
|
|
879
|
+
allgammas[5] = 1./xprojs[5] * (
|
|
880
|
+
ang1_4.conj() * ang23_4 * ximspl(absy23) * ximspl(absy1) +
|
|
881
|
+
xipspl(absy13) * xipspl(absy2) +
|
|
882
|
+
xipspl(absy12) * xipspl(absy3))
|
|
883
|
+
allgammas[6] = 1./xprojs[6] * (
|
|
884
|
+
xipspl(absy23) * xipspl(absy1) +
|
|
885
|
+
ang2_4.conj() * ang13_4 * ximspl(absy13) * ximspl(absy2) +
|
|
886
|
+
xipspl(absy12) * xipspl(absy3))
|
|
887
|
+
allgammas[7] = 1./xprojs[7] * (
|
|
888
|
+
xipspl(absy23) * xipspl(absy1) +
|
|
889
|
+
xipspl(absy13) * xipspl(absy2) +
|
|
890
|
+
ang3_4.conj() * ang12_4 * ximspl(absy12) * ximspl(absy3))
|
|
891
|
+
|
|
892
|
+
return allgammas
|
|
893
|
+
|
|
894
|
+
# Disconnected 4pcf from binned 2pcf (might want to deprecate this as it is a special case of nsubr==1)
|
|
895
|
+
def __gauss4pcf_analytic(self, theta1, theta2, theta3, xip_arr, xim_arr, thetamin_xi, thetamax_xi, dtheta_xi):
|
|
896
|
+
gausss_4pcf = np.zeros(8*len(self.phis[0])*len(self.phis[0]),dtype=np.complex128)
|
|
897
|
+
self.clib.gauss4pcf_analytic(theta1.astype(np.float64),
|
|
898
|
+
theta2.astype(np.float64),
|
|
899
|
+
theta3.astype(np.float64),
|
|
900
|
+
self.phis[0].astype(np.float64), np.int32(len(self.phis[0])),
|
|
901
|
+
xip_arr.astype(np.float64), xim_arr.astype(np.float64),
|
|
902
|
+
thetamin_xi, thetamax_xi, dtheta_xi,
|
|
903
|
+
gausss_4pcf)
|
|
904
|
+
return gausss_4pcf
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
# [Debug] Disconnected 4pcf from analytic 2pcf
|
|
908
|
+
def gauss4pcf_analytic(self, itheta1, itheta2, itheta3, nsubr,
|
|
909
|
+
xip_arr, xim_arr, thetamin_xi, thetamax_xi, dtheta_xi):
|
|
910
|
+
|
|
911
|
+
gauss_4pcf = np.zeros(8*self.nbinsphi[0]*self.nbinsphi[1],dtype=np.complex128)
|
|
912
|
+
|
|
913
|
+
self.clib.gauss4pcf_analytic_integrated(
|
|
914
|
+
np.int32(itheta1),
|
|
915
|
+
np.int32(itheta2),
|
|
916
|
+
np.int32(itheta3),
|
|
917
|
+
np.int32(nsubr),
|
|
918
|
+
self.bin_edges.astype(np.float64),
|
|
919
|
+
np.int32(self.nbinsr),
|
|
920
|
+
self.phis[0].astype(np.float64),
|
|
921
|
+
np.int32(self.nbinsphi[0]),
|
|
922
|
+
xip_arr.astype(np.float64),
|
|
923
|
+
xim_arr.astype(np.float64),
|
|
924
|
+
np.float64(thetamin_xi),
|
|
925
|
+
np.float64(thetamax_xi),
|
|
926
|
+
np.float64(dtheta_xi),
|
|
927
|
+
gauss_4pcf)
|
|
928
|
+
return gauss_4pcf.reshape((8, self.nbinsphi[0], self.nbinsphi[1]))
|
|
929
|
+
|
|
930
|
+
# Compute disconnected part of 4pcf in multiple basis
|
|
931
|
+
def gauss4pcf_multipolebasis(self, itheta1, itheta2, itheta3, nsubr,
|
|
932
|
+
xip_arr, xim_arr, thetamin_xi, thetamax_xi, dtheta_xi):
|
|
933
|
+
|
|
934
|
+
# Obtain integrated 4pcf
|
|
935
|
+
int_4pcf = self.gauss4pcf_analytic_integrated(itheta1, itheta2, itheta3, nsubr,
|
|
936
|
+
xip_arr, xim_arr,
|
|
937
|
+
thetamin_xi, thetamax_xi, dtheta_xi)
|
|
938
|
+
|
|
939
|
+
# Transform to multiple basis (cf eq xxx in P25)
|
|
940
|
+
phigrid1, phigrid2 = np.meshgrid(self.phis[0],self.phis[1])
|
|
941
|
+
gauss_multipoles = np.zeros((8,2*self.nmaxs[0]+1,2*self.nmaxs[1]+1),dtype=complex)
|
|
942
|
+
for eln2,n2 in enumerate(np.arange(-self.nmaxs[0],self.nmaxs[0]+1)):
|
|
943
|
+
fac1 = np.e**(-1J*n2*phigrid1)
|
|
944
|
+
for eln3,n3 in enumerate(np.arange(-self.nmaxs[1],self.nmaxs[1]+1)):
|
|
945
|
+
fac2 = np.e**(-1J*n3*phigrid2)
|
|
946
|
+
for elcomp in range(8):
|
|
947
|
+
gauss_multipoles[elcomp,eln2,eln3] = np.mean(int_4pcf[elcomp]*fac1*fac2)
|
|
948
|
+
|
|
949
|
+
return gauss_multipoles
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
def estimateMap4disc(self, cat, radii, basis='MapMx',fac_minsep=0.05, fac_maxsep=2., binsize=0.1, nsubr=3, nsubsample_filter=1):
|
|
953
|
+
""" Estimate disconnected part of fourth-order aperture statistics on a shape catalog. """
|
|
954
|
+
|
|
955
|
+
# Compute shear 2pcf from data
|
|
956
|
+
min_sep_disc = fac_minsep*self.min_sep
|
|
957
|
+
max_sep_disc = fac_maxsep*self.max_sep
|
|
958
|
+
binsize_disc = min(0.1,self.binsize)
|
|
959
|
+
ggcorr = GGCorrelation(min_sep=min_sep_disc, max_sep=max_sep_disc,binsize=binsize_disc,
|
|
960
|
+
rmin_pixsize=self.rmin_pixsize, tree_resos=self.tree_resos, nthreads=self.nthreads)
|
|
961
|
+
ggcorr.process(cat)
|
|
962
|
+
|
|
963
|
+
# Convert this to fourth-order aperture statistics
|
|
964
|
+
linarr = np.linspace(min_sep_disc,max_sep_disc,int(max_sep_disc/(binsize_disc*min_sep_disc)))
|
|
965
|
+
xip_spl = interp1d(x=ggcorr.bin_centers_mean,y=ggcorr.xip[0].real,fill_value=0,bounds_error=False)
|
|
966
|
+
xim_spl = interp1d(x=ggcorr.bin_centers_mean,y=ggcorr.xim[0].real,fill_value=0,bounds_error=False)
|
|
967
|
+
mapstat = self.Map4analytic(mapradii=radii,
|
|
968
|
+
xip_spl=xip_spl,
|
|
969
|
+
xim_spl=xim_spl,
|
|
970
|
+
thetamin_xi=linarr[0],
|
|
971
|
+
thetamax_xi=linarr[-1],
|
|
972
|
+
ntheta_xi=len(linarr),
|
|
973
|
+
nsubr=nsubr,nsubsample_filter=nsubsample_filter,basis=basis)
|
|
974
|
+
return mapstat
|
|
975
|
+
|
|
976
|
+
|
|
977
|
+
# Disconnected part of Map^4 from analytic 2pcf
|
|
978
|
+
# thetamin_xi, thetamax_xi, ntheta_xi is the linspaced array in which the xipm are passed to the external function
|
|
979
|
+
def Map4analytic(self, mapradii, xip_spl, xim_spl, thetamin_xi, thetamax_xi, ntheta_xi,
|
|
980
|
+
nsubr=1, nsubsample_filter=1, batchsize=None, basis='MapMx'):
|
|
981
|
+
|
|
982
|
+
self.nbinsz = 1
|
|
983
|
+
self.nzcombis = 1
|
|
984
|
+
_nmax = self.nmaxs[0]
|
|
985
|
+
_nnvals = (2*_nmax+1)*(2*_nmax+1)
|
|
986
|
+
_nbinsr3 = self.nbinsr*self.nbinsr*self.nbinsr
|
|
987
|
+
_nphis = len(self.phis[0])
|
|
988
|
+
bin_centers = np.zeros(self.nbinsz*self.nbinsr).astype(np.float64)
|
|
989
|
+
M4correlators = np.zeros(8*self.nzcombis*len(mapradii)).astype(np.complex128)
|
|
990
|
+
# Define the radial bin batches
|
|
991
|
+
if batchsize is None:
|
|
992
|
+
batchsize = min(_nbinsr3,min(10000,int(_nbinsr3/self.nthreads)))
|
|
993
|
+
if self._verbose_python:
|
|
994
|
+
print("Using batchsize of %i for radial bins"%batchsize)
|
|
995
|
+
nbatches = np.int32(_nbinsr3/batchsize)
|
|
996
|
+
thetacombis_batches = np.arange(_nbinsr3).astype(np.int32)
|
|
997
|
+
cumnthetacombis_batches = (np.arange(nbatches+1)*_nbinsr3/(nbatches)).astype(np.int32)
|
|
998
|
+
nthetacombis_batches = (cumnthetacombis_batches[1:]-cumnthetacombis_batches[:-1]).astype(np.int32)
|
|
999
|
+
cumnthetacombis_batches[-1] = _nbinsr3
|
|
1000
|
+
nthetacombis_batches[-1] = _nbinsr3-cumnthetacombis_batches[-2]
|
|
1001
|
+
thetacombis_batches = thetacombis_batches.flatten().astype(np.int32)
|
|
1002
|
+
nbatches = len(nthetacombis_batches)
|
|
1003
|
+
|
|
1004
|
+
args_4pcfsetup = (np.float64(self.min_sep), np.float64(self.max_sep), np.int32(self.nbinsr),
|
|
1005
|
+
self.phis[0].astype(np.float64),
|
|
1006
|
+
(self.phis[0][1]-self.phis[0][0])*np.ones(_nphis, dtype=np.float64), _nphis, np.int32(nsubr), )
|
|
1007
|
+
args_thetas = (thetacombis_batches, nthetacombis_batches, cumnthetacombis_batches, nbatches, )
|
|
1008
|
+
args_map4 = (mapradii.astype(np.float64), np.int32(len(mapradii)), )
|
|
1009
|
+
thetas_xi = np.linspace(thetamin_xi,thetamax_xi,ntheta_xi+1)
|
|
1010
|
+
args_xi = (xip_spl(thetas_xi), xim_spl(thetas_xi), thetamin_xi, thetamax_xi, ntheta_xi, nsubsample_filter, )
|
|
1011
|
+
args = (*args_4pcfsetup,
|
|
1012
|
+
*args_thetas,
|
|
1013
|
+
np.int32(self.nthreads),
|
|
1014
|
+
*args_map4,
|
|
1015
|
+
*args_xi,
|
|
1016
|
+
M4correlators)
|
|
1017
|
+
func = self.clib.alloc_notomoMap4_analytic
|
|
1018
|
+
|
|
1019
|
+
if self._verbose_debug:
|
|
1020
|
+
for elarg, arg in enumerate(args):
|
|
1021
|
+
toprint = (elarg, type(arg),)
|
|
1022
|
+
if isinstance(arg, np.ndarray):
|
|
1023
|
+
toprint += (type(arg[0]), arg.shape)
|
|
1024
|
+
try:
|
|
1025
|
+
toprint += (func.argtypes[elarg], )
|
|
1026
|
+
print(toprint)
|
|
1027
|
+
print(arg)
|
|
1028
|
+
except:
|
|
1029
|
+
print("We did have a problem for arg %i"%elarg)
|
|
1030
|
+
|
|
1031
|
+
func(*args)
|
|
1032
|
+
|
|
1033
|
+
res_MMStar = M4correlators.reshape((8,len(mapradii)))
|
|
1034
|
+
# Allocate result
|
|
1035
|
+
res = ()
|
|
1036
|
+
if basis=='MM*' or basis=='both':
|
|
1037
|
+
res += (res_MMStar, )
|
|
1038
|
+
if basis=='MapMx' or basis=='both':
|
|
1039
|
+
res += (GGGGCorrelation_NoTomo.MMStar2MapMx_fourth(res_MMStar), )
|
|
1040
|
+
|
|
1041
|
+
return res
|
|
1042
|
+
|
|
1043
|
+
def getMultipolesFromSymm(self, nmax_rec, itheta1, itheta2, itheta3, eltrafo):
|
|
1044
|
+
|
|
1045
|
+
nmax_alloc = 2*nmax_rec+1
|
|
1046
|
+
assert(nmax_alloc<=self.nmaxs[0])
|
|
1047
|
+
|
|
1048
|
+
# Only select relevant n1/n2 indices
|
|
1049
|
+
_dn = self.nmaxs[0]-nmax_alloc
|
|
1050
|
+
|
|
1051
|
+
_shape, _inds, _n2s, _n3s = gen_n2n3indices_Upsfourth(nmax_rec)
|
|
1052
|
+
Upsn_in = self.npcf_multipoles[:,_dn:-_dn,_dn:-_dn,0,itheta1,itheta2,itheta3].flatten()
|
|
1053
|
+
Nn_in = self.npcf_multipoles_norm[_dn:-_dn,_dn:-_dn,0,itheta1,itheta2,itheta3].flatten()
|
|
1054
|
+
Upsn_out = np.zeros(8*(2*nmax_rec+1)*(2*nmax_rec+1), dtype=np.complex128)
|
|
1055
|
+
Nn_out = np.zeros(1*(2*nmax_rec+1)*(2*nmax_rec+1), dtype=np.complex128)
|
|
1056
|
+
|
|
1057
|
+
self.clib.getMultipolesFromSymm(
|
|
1058
|
+
Upsn_in, Nn_in, nmax_rec, eltrafo, _inds, len(_inds), Upsn_out, Nn_out)
|
|
1059
|
+
|
|
1060
|
+
Upsn_out = Upsn_out.reshape((8,(2*nmax_rec+1),(2*nmax_rec+1)))
|
|
1061
|
+
Nn_out = Nn_out.reshape(((2*nmax_rec+1),(2*nmax_rec+1)))
|
|
1062
|
+
|
|
1063
|
+
return Upsn_out, Nn_out
|
|
1064
|
+
|
|
1065
|
+
## MISC HELPERS ##
|
|
1066
|
+
@staticmethod
|
|
1067
|
+
def MMStar2MapMx_fourth(res_MMStar):
|
|
1068
|
+
""" Transforms fourth-order aperture correlators to fourth-order aperture mass.
|
|
1069
|
+
See i.e. Eqs (32)-(36) in Silvestre-Rosello+ 2025 (arxiv.org/pdf/2509.07973).
|
|
1070
|
+
"""
|
|
1071
|
+
res_MapMx = np.zeros((16,*res_MMStar.shape[1:]))
|
|
1072
|
+
Mcorr2Map4_re = .125*np.array([[+1,+1,+1,+1,+1,+1,+1,+1],
|
|
1073
|
+
[-1,-1,-1,+1,+1,-1,+1,+1],
|
|
1074
|
+
[-1,-1,+1,-1,+1,+1,-1,+1],
|
|
1075
|
+
[-1,-1,+1,+1,-1,+1,+1,-1],
|
|
1076
|
+
[-1,+1,-1,-1,+1,+1,+1,-1],
|
|
1077
|
+
[-1,+1,-1,+1,-1,+1,-1,+1],
|
|
1078
|
+
[-1,+1,+1,-1,-1,-1,+1,+1],
|
|
1079
|
+
[+1,-1,-1,-1,-1,+1,+1,+1]])
|
|
1080
|
+
Mcorr2Map4_im = .125*np.array([[+1,-1,+1,+1,+1,-1,-1,-1],
|
|
1081
|
+
[+1,+1,-1,+1,+1,-1,+1,+1],
|
|
1082
|
+
[+1,+1,+1,-1,+1,+1,-1,+1],
|
|
1083
|
+
[+1,+1,+1,+1,-1,+1,+1,-1],
|
|
1084
|
+
[-1,-1,+1,+1,+1,+1,+1,+1],
|
|
1085
|
+
[-1,+1,-1,+1,+1,+1,-1,-1],
|
|
1086
|
+
[-1,+1,+1,-1,+1,-1,+1,-1],
|
|
1087
|
+
[-1,+1,+1,+1,-1,-1,-1,+1]])
|
|
1088
|
+
res_MapMx[[0,5,6,7,8,9,10,15]] = Mcorr2Map4_re@(res_MMStar.real)
|
|
1089
|
+
res_MapMx[[1,2,3,4,11,12,13,14]] = Mcorr2Map4_im@(res_MMStar.imag)
|
|
1090
|
+
return res_MapMx
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
class GNNNCorrelation_NoTomo(BinnedNPCF):
|
|
1094
|
+
def __init__(self, min_sep, max_sep, thetabatchsize_max=10000, **kwargs):
|
|
1095
|
+
r""" Class containing methods to measure and and obtain statistics that are built
|
|
1096
|
+
from third-order source-lens-lens (G3L) correlation functions.
|
|
1097
|
+
|
|
1098
|
+
Attributes
|
|
1099
|
+
----------
|
|
1100
|
+
min_sep: float
|
|
1101
|
+
The smallest distance of each vertex for which the NPCF is computed.
|
|
1102
|
+
max_sep: float
|
|
1103
|
+
The largest distance of each vertex for which the NPCF is computed.
|
|
1104
|
+
nbinsr: int, optional
|
|
1105
|
+
The number of radial bins for each vertex of the NPCF. If set to
|
|
1106
|
+
``None`` this attribute is inferred from the ``binsize`` attribute.
|
|
1107
|
+
binsize: int, optional
|
|
1108
|
+
The logarithmic slize of the radial bins for each vertex of the NPCF. If set to
|
|
1109
|
+
``None`` this attribute is inferred from the ``nbinsr`` attribute.
|
|
1110
|
+
nbinsphi: float, optional
|
|
1111
|
+
The number of angular bins for the NPCF in the real-space basis.
|
|
1112
|
+
Defaults to ``100``.
|
|
1113
|
+
nmaxs: list, optional
|
|
1114
|
+
The largest multipole component considered for the NPCF in the multipole basis.
|
|
1115
|
+
Defaults to ``30``.
|
|
1116
|
+
method: str, optional
|
|
1117
|
+
The method to be employed for the estimator. Defaults to ``DoubleTree``.
|
|
1118
|
+
multicountcorr: bool, optional
|
|
1119
|
+
Flag on whether to subtract of multiplets in which the same tracer appears more
|
|
1120
|
+
than once. Defaults to ``True``.
|
|
1121
|
+
shuffle_pix: int, optional
|
|
1122
|
+
Choice of how to define centers of the cells in the spatial hash structure.
|
|
1123
|
+
Defaults to ``1``, i.e. random positioning.
|
|
1124
|
+
tree_resos: list, optional
|
|
1125
|
+
The cell sizes of the hierarchical spatial hash structure
|
|
1126
|
+
tree_edges: list, optional
|
|
1127
|
+
List of radii where the tree changes resolution.
|
|
1128
|
+
rmin_pixsize: int, optional
|
|
1129
|
+
The limiting radial distance relative to the cell of the spatial hash
|
|
1130
|
+
after which one switches to the next hash in the hierarchy. Defaults to ``20``.
|
|
1131
|
+
resoshift_leafs: int, optional
|
|
1132
|
+
Allows for a difference in how the hierarchical spatial hash is traversed for
|
|
1133
|
+
pixels at the base of the NPCF and pixels at leafs. I.e. positive values indicate
|
|
1134
|
+
that leafs will be evaluated at a courser resolutions than the base. Defaults to ``0``.
|
|
1135
|
+
minresoind_leaf: int, optional
|
|
1136
|
+
Sets the smallest resolution in the spatial hash hierarchy which can be used to access
|
|
1137
|
+
tracers at leaf positions. If set to ``None`` uses the smallest specified cell size.
|
|
1138
|
+
Defaults to ``None``.
|
|
1139
|
+
maxresoind_leaf: int, optional
|
|
1140
|
+
Sets the largest resolution in the spatial hash hierarchy which can be used to access
|
|
1141
|
+
tracers at leaf positions. If set to ``None`` uses the largest specified cell size.
|
|
1142
|
+
Defaults to ``None``.
|
|
1143
|
+
nthreads: int, optional
|
|
1144
|
+
The number of openmp threads used for the reduction procedure. Defaults to ``16``.
|
|
1145
|
+
bin_centers: numpy.ndarray
|
|
1146
|
+
The centers of the radial bins for each combination of tomographic redshifts.
|
|
1147
|
+
bin_centers_mean: numpy.ndarray
|
|
1148
|
+
The centers of the radial bins averaged over all combination of tomographic redshifts.
|
|
1149
|
+
phis: list
|
|
1150
|
+
The bin centers for the N-2 angles describing the NPCF
|
|
1151
|
+
in the real-space basis.
|
|
1152
|
+
npcf: numpy.ndarray
|
|
1153
|
+
The natural components of the NPCF in the real space basis. The different axes
|
|
1154
|
+
are specified as follows: ``(component, zcombi, rbin_1, ..., rbin_N-1, phiin_1, phibin_N-2)``.
|
|
1155
|
+
npcf_norm: numpy.ndarray
|
|
1156
|
+
The normalization of the natural components of the NPCF in the real space basis. The different axes
|
|
1157
|
+
are specified as follows: ``(zcombi, rbin_1, ..., rbin_N-1, phiin_1, phibin_N-2)``.
|
|
1158
|
+
npcf_multipoles: numpy.ndarray
|
|
1159
|
+
The natural components of the NPCF in the multipole basis. The different axes
|
|
1160
|
+
are specified as follows: ``(component, zcombi, multipole_1, ..., multipole_N-2, rbin_1, ..., rbin_N-1)``.
|
|
1161
|
+
npcf_multipoles_norm: numpy.ndarray
|
|
1162
|
+
The normalization of the natural components of the NPCF in the multipole basis. The different axes
|
|
1163
|
+
are specified as follows: ``(zcombi, multipole_1, ..., multipole_N-2, rbin_1, ..., rbin_N-1)``.
|
|
1164
|
+
is_edge_corrected: bool, optional
|
|
1165
|
+
Flag signifying on wheter the NPCF multipoles have beed edge-corrected. Defaults to ``False``.
|
|
1166
|
+
"""
|
|
1167
|
+
super().__init__(4, [2,0,0,0], n_cfs=1, min_sep=min_sep, max_sep=max_sep, **kwargs)
|
|
1168
|
+
self.nmax = self.nmaxs[0]
|
|
1169
|
+
self.phi = self.phis[0]
|
|
1170
|
+
self.projection = None
|
|
1171
|
+
self.projections_avail = [None, "X"]
|
|
1172
|
+
self.proj_dict = {"X":0}
|
|
1173
|
+
self.nbinsz_source = 1 # This class does not handle any tomography at the moment, so I fix it here
|
|
1174
|
+
self.nbinsz_lens = 1 # This class does not handle any tomography at the moment, so I fix it here
|
|
1175
|
+
self.nzcombis = 1
|
|
1176
|
+
self.thetabatchsize_max = thetabatchsize_max
|
|
1177
|
+
|
|
1178
|
+
# (Add here any newly implemented projections)
|
|
1179
|
+
self._initprojections(self)
|
|
1180
|
+
|
|
1181
|
+
def process(self, cat_source, cat_lens, statistics="all", tofile=False, apply_edge_correction=False,
|
|
1182
|
+
dotomo_source=True, dotomo_lens=True,
|
|
1183
|
+
lowmem=None, apradii=None, batchsize=None, custom_thetacombis=None, cutlen=2**31-1):
|
|
1184
|
+
self._checkcats([cat_source, cat_lens, cat_lens, cat_lens], [2, 0, 0, 0])
|
|
1185
|
+
|
|
1186
|
+
# Checks for redshift binning
|
|
1187
|
+
if not dotomo_source:
|
|
1188
|
+
self.nbinsz_source = 1
|
|
1189
|
+
zbins_source = np.zeros(cat_source.ngal, dtype=np.int32)
|
|
1190
|
+
else:
|
|
1191
|
+
self.nbinsz_source = cat_source.nbinsz
|
|
1192
|
+
zbins_source = cat_source.zbins
|
|
1193
|
+
if not dotomo_lens:
|
|
1194
|
+
self.nbinsz_lens = 1
|
|
1195
|
+
zbins_lens = np.zeros(cat_lens.ngal, dtype=np.int32)
|
|
1196
|
+
else:
|
|
1197
|
+
self.nbinsz_lens = cat_lens.nbinsz
|
|
1198
|
+
zbins_lens= cat_lens.zbins
|
|
1199
|
+
|
|
1200
|
+
## Preparations ##
|
|
1201
|
+
# Some default argument resettings
|
|
1202
|
+
if self.method=='Discrete' and not lowmem:
|
|
1203
|
+
statistics = ['4pcf_multipole']
|
|
1204
|
+
|
|
1205
|
+
# Check memory requirements
|
|
1206
|
+
if not lowmem:
|
|
1207
|
+
_resradial = gen_thetacombis_fourthorder(nbinsr=self.nbinsr, nthreads=self.nthreads, batchsize=batchsize,
|
|
1208
|
+
batchsize_max=self.thetabatchsize_max, ordered=True, custom=custom_thetacombis,
|
|
1209
|
+
verbose=self._verbose_python*lowmem)
|
|
1210
|
+
nthetacombis_tot, _, _, _, _, _ = _resradial
|
|
1211
|
+
assert(self.nmaxs[0]==self.nmaxs[1])
|
|
1212
|
+
_resmultipoles = gen_n2n3indices_Upsfourth(self.nmaxs[0])
|
|
1213
|
+
_, _inds, _, _ = _resmultipoles
|
|
1214
|
+
ncache_required_out = self.nbinsr*self.nbinsr*self.nbinsr*(2*self.nmaxs[0]+1)*(2*self.nmaxs[1]+1)
|
|
1215
|
+
ncache_required_alloc = nthetacombis_tot*len(_inds)*self.nthreads
|
|
1216
|
+
if max(ncache_required_out,ncache_required_alloc)>2**31-1:
|
|
1217
|
+
raise ValueError("Required memory too large (%.2f / x 10^9 elements)"%(ncache_required_out/1e9,ncache_required_alloc/1e9))
|
|
1218
|
+
|
|
1219
|
+
# Build list of statistics to be calculated
|
|
1220
|
+
statistics_avail_4pcf = ["4pcf_real", "4pcf_multipole"]
|
|
1221
|
+
statistics_avail_mapnap3 = ["MN3", "MapNap3", "MN3cc", "MapNap3c"]
|
|
1222
|
+
statistics_avail_comp = ["allMapNap3", "all4pcf", "all"]
|
|
1223
|
+
statistics_avail_phys = statistics_avail_4pcf + statistics_avail_mapnap3
|
|
1224
|
+
statistics_avail = statistics_avail_4pcf + statistics_avail_mapnap3 + statistics_avail_comp
|
|
1225
|
+
_statistics = []
|
|
1226
|
+
hasintegratedstats = False
|
|
1227
|
+
_strbadstats = lambda stat: ("The statistics `%s` has not been implemented yet. "%stat +
|
|
1228
|
+
"Currently supported statistics are:\n" + str(statistics_avail))
|
|
1229
|
+
if type(statistics) not in [list, str]:
|
|
1230
|
+
raise ValueError("The parameter `statistics` should either be a list or a string.")
|
|
1231
|
+
if type(statistics) is str:
|
|
1232
|
+
if statistics not in statistics_avail:
|
|
1233
|
+
raise ValueError(_strbadstats)
|
|
1234
|
+
statistics = [statistics]
|
|
1235
|
+
if type(statistics) is list:
|
|
1236
|
+
if "all" in statistics:
|
|
1237
|
+
_statistics = statistics_avail_phys
|
|
1238
|
+
elif "all4pcf" in statistics:
|
|
1239
|
+
_statistics.append(statistics_avail_4pcf)
|
|
1240
|
+
elif "allMapNap3" in statistics:
|
|
1241
|
+
_statistics.append(statistics_avail_mapnap3)
|
|
1242
|
+
_statistics = flatlist(_statistics)
|
|
1243
|
+
for stat in statistics:
|
|
1244
|
+
if stat not in statistics_avail:
|
|
1245
|
+
raise ValueError(_strbadstats)
|
|
1246
|
+
if stat in statistics_avail_phys and stat not in _statistics:
|
|
1247
|
+
_statistics.append(stat)
|
|
1248
|
+
statistics = list(set(flatlist(_statistics)))
|
|
1249
|
+
for stat in statistics:
|
|
1250
|
+
if stat in statistics_avail_mapnap3:
|
|
1251
|
+
hasintegratedstats = True
|
|
1252
|
+
|
|
1253
|
+
# Init optional args
|
|
1254
|
+
__lenflag = 10
|
|
1255
|
+
__fillflag = -1
|
|
1256
|
+
_nmax = self.nmaxs[0]
|
|
1257
|
+
_nnvals = (2*_nmax+1)*(2*_nmax+1)
|
|
1258
|
+
_nbinsr3 = self.nbinsr*self.nbinsr*self.nbinsr
|
|
1259
|
+
_nphis = len(self.phis[0])
|
|
1260
|
+
_r2combis = self.nbinsr*self.nbinsr
|
|
1261
|
+
sc = (self.n_cfs, 2*self.nmax+1, 2*self.nmax+1, self.nzcombis, self.nbinsr, self.nbinsr, self.nbinsr)
|
|
1262
|
+
sn = (2*self.nmax+1,2*self.nmax+1,self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr)
|
|
1263
|
+
szr = (self.nbinsz_source, self.nbinsz_lens, self.nbinsr)
|
|
1264
|
+
s4pcf = (self.n_cfs,self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr,_nphis,_nphis)
|
|
1265
|
+
s4pcfn = (self.nzcombis,self.nbinsr,self.nbinsr,self.nbinsr,_nphis,_nphis)
|
|
1266
|
+
bin_centers = np.zeros(reduce(operator.mul, szr)).astype(np.float64)
|
|
1267
|
+
|
|
1268
|
+
if "4pcf_multipole" in statistics:
|
|
1269
|
+
Upsilon_n = np.zeros(self.n_cfs*_nnvals*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
1270
|
+
N_n = np.zeros(_nnvals*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
1271
|
+
alloc_4pcfmultipoles = 1
|
|
1272
|
+
else:
|
|
1273
|
+
Upsilon_n = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
1274
|
+
N_n = __fillflag*np.zeros(__lenflag).astype(np.complex128)
|
|
1275
|
+
alloc_4pcfmultipoles = 0
|
|
1276
|
+
if "4pcf_real" in statistics:
|
|
1277
|
+
fourpcf = np.zeros(1*_nphis*_nphis*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
1278
|
+
fourpcf_norm = np.zeros(_nphis*_nphis*self.nzcombis*_nbinsr3).astype(np.complex128)
|
|
1279
|
+
alloc_4pcfreal = 1
|
|
1280
|
+
else:
|
|
1281
|
+
fourpcf = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
1282
|
+
fourpcf_norm = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
1283
|
+
alloc_4pcfreal = 0
|
|
1284
|
+
if hasintegratedstats:
|
|
1285
|
+
if apradii is None:
|
|
1286
|
+
raise ValueError("Aperture radii need to be specified in variable `apradii`.")
|
|
1287
|
+
apradii = apradii.astype(np.float64)
|
|
1288
|
+
MN3correlators = np.zeros(1*self.nzcombis*len(apradii)).astype(np.complex128)
|
|
1289
|
+
else:
|
|
1290
|
+
apradii = __fillflag*np.ones(__lenflag).astype(np.float64)
|
|
1291
|
+
MN3correlators = __fillflag*np.ones(__lenflag).astype(np.complex128)
|
|
1292
|
+
|
|
1293
|
+
# Basic prep
|
|
1294
|
+
hash_dpix = max(1.,self.max_sep//10.)
|
|
1295
|
+
jointextent = list(cat_source._jointextent([cat_lens], extend=self.tree_resos[-1]))
|
|
1296
|
+
cat_source.build_spatialhash(dpix=hash_dpix, extent=jointextent)
|
|
1297
|
+
cat_lens.build_spatialhash(dpix=hash_dpix, extent=jointextent)
|
|
1298
|
+
|
|
1299
|
+
args_sourcecat = (cat_source.isinner.astype(np.float64), cat_source.weight.astype(np.float64),
|
|
1300
|
+
cat_source.pos1.astype(np.float64), cat_source.pos2.astype(np.float64),
|
|
1301
|
+
cat_source.tracer_1.astype(np.float64), cat_source.tracer_2.astype(np.float64),
|
|
1302
|
+
np.int32(cat_source.ngal), )
|
|
1303
|
+
args_basesetup = (np.int32(self.nmax), np.float64(self.min_sep), np.float64(self.max_sep),
|
|
1304
|
+
np.int32(self.nbinsr), np.int32(self.multicountcorr), )
|
|
1305
|
+
|
|
1306
|
+
|
|
1307
|
+
if self.method=="Discrete" and not lowmem:
|
|
1308
|
+
hash_dpix = max(1.,self.max_sep//10.)
|
|
1309
|
+
jointextent = list(cat_source._jointextent([cat_lens], extend=self.tree_resos[-1]))
|
|
1310
|
+
cat_source.build_spatialhash(dpix=hash_dpix, extent=jointextent)
|
|
1311
|
+
cat_lens.build_spatialhash(dpix=hash_dpix, extent=jointextent)
|
|
1312
|
+
nregions = np.int32(len(np.argwhere(cat_lens.index_matcher>-1).flatten()))
|
|
1313
|
+
args_lenscat = (cat_lens.weight.astype(np.float64),
|
|
1314
|
+
cat_lens.pos1.astype(np.float64), cat_lens.pos2.astype(np.float64), np.int32(cat_lens.ngal), )
|
|
1315
|
+
args_hash = (cat_lens.index_matcher, cat_lens.pixs_galind_bounds, cat_lens.pix_gals, nregions, )
|
|
1316
|
+
args_pix = (np.float64(cat_lens.pix1_start), np.float64(cat_lens.pix1_d), np.int32(cat_lens.pix1_n),
|
|
1317
|
+
np.float64(cat_lens.pix2_start), np.float64(cat_lens.pix2_d), np.int32(cat_lens.pix2_n), )
|
|
1318
|
+
args_4pcf = (bin_centers, Upsilon_n, N_n, )
|
|
1319
|
+
|
|
1320
|
+
args = (*args_sourcecat,
|
|
1321
|
+
*args_lenscat,
|
|
1322
|
+
*args_hash,
|
|
1323
|
+
*args_pix,
|
|
1324
|
+
*args_basesetup,
|
|
1325
|
+
np.int32(self.nthreads),
|
|
1326
|
+
*args_4pcf)
|
|
1327
|
+
func = self.clib.alloc_notomoGammans_discrete_gnnn
|
|
1328
|
+
|
|
1329
|
+
if self.method=="Tree":
|
|
1330
|
+
# Prepare mask for nonredundant theta- and multipole configurations
|
|
1331
|
+
_resradial = gen_thetacombis_fourthorder(nbinsr=self.nbinsr, nthreads=self.nthreads, batchsize=batchsize,
|
|
1332
|
+
batchsize_max=self.thetabatchsize_max, ordered=True, custom=custom_thetacombis,
|
|
1333
|
+
verbose=self._verbose_python*lowmem)
|
|
1334
|
+
nthetacombis_tot, _, thetacombis_batches, cumnthetacombis_batches, nthetacombis_batches, nbatches = _resradial
|
|
1335
|
+
assert(self.nmaxs[0]==self.nmaxs[1])
|
|
1336
|
+
_resmultipoles = gen_n2n3indices_Upsfourth(self.nmaxs[0])
|
|
1337
|
+
_shape, _inds, _n2s, _n3s = _resmultipoles
|
|
1338
|
+
|
|
1339
|
+
# Prepare reduced catalogs
|
|
1340
|
+
cutfirst = np.int32(self.tree_resos[0]==0.)
|
|
1341
|
+
mhash = cat_lens.multihash(dpixs=self.tree_resos[cutfirst:], dpix_hash=self.tree_resos[-1],
|
|
1342
|
+
shuffle=self.shuffle_pix, normed=True)
|
|
1343
|
+
(ngal_resos_lens, pos1s_lens, pos2s_lens, weights_lens, _, _, _,
|
|
1344
|
+
index_matchers_lens, pixs_galind_bounds_lens, pix_gals_lens, dpixs1_true_lens, dpixs2_true_lens) = mhash
|
|
1345
|
+
weight_resos_lens = np.concatenate(weights_lens).astype(np.float64)
|
|
1346
|
+
pos1_resos_lens = np.concatenate(pos1s_lens).astype(np.float64)
|
|
1347
|
+
pos2_resos_lens = np.concatenate(pos2s_lens).astype(np.float64)
|
|
1348
|
+
index_matcher_resos_lens = np.concatenate(index_matchers_lens).astype(np.int32)
|
|
1349
|
+
pixs_galind_bounds_resos_lens = np.concatenate(pixs_galind_bounds_lens).astype(np.int32)
|
|
1350
|
+
pix_gals_resos_lens = np.concatenate(pix_gals_lens).astype(np.int32)
|
|
1351
|
+
index_matcher_flat = np.argwhere(cat_source.index_matcher>-1).flatten()
|
|
1352
|
+
nregions = len(index_matcher_flat)
|
|
1353
|
+
|
|
1354
|
+
args_resos = (np.int32(self.tree_nresos), self.tree_redges, )
|
|
1355
|
+
args_resos_lens = (weight_resos_lens, pos1_resos_lens, pos2_resos_lens, np.asarray(ngal_resos_lens).astype(np.int32),)
|
|
1356
|
+
args_hash_source = (cat_source.index_matcher, cat_source.pixs_galind_bounds, cat_source.pix_gals, )
|
|
1357
|
+
args_mhash_lens = (index_matcher_resos_lens, pixs_galind_bounds_resos_lens, pix_gals_resos_lens, np.int32(nregions), )
|
|
1358
|
+
args_hash = (np.float64(cat_lens.pix1_start), np.float64(cat_lens.pix1_d), np.int32(cat_lens.pix1_n),
|
|
1359
|
+
np.float64(cat_lens.pix2_start), np.float64(cat_lens.pix2_d), np.int32(cat_lens.pix2_n), )
|
|
1360
|
+
if lowmem:
|
|
1361
|
+
# Build args
|
|
1362
|
+
args_indsetup = (_inds, np.int32(len(_inds)), self.phis[0].astype(np.float64),
|
|
1363
|
+
2*np.pi/_nphis*np.ones(_nphis, dtype=np.float64), np.int32(_nphis), )
|
|
1364
|
+
args_thetas = (thetacombis_batches, nthetacombis_batches, cumnthetacombis_batches, nbatches, )
|
|
1365
|
+
args_mapnap3 = (apradii, np.int32(len(apradii)), MN3correlators)
|
|
1366
|
+
args_4pcf = (np.int32(alloc_4pcfmultipoles), np.int32(alloc_4pcfreal),
|
|
1367
|
+
bin_centers, Upsilon_n, N_n, fourpcf, fourpcf_norm, )
|
|
1368
|
+
args = (*args_resos,
|
|
1369
|
+
*args_sourcecat,
|
|
1370
|
+
*args_resos_lens,
|
|
1371
|
+
*args_hash_source,
|
|
1372
|
+
*args_mhash_lens,
|
|
1373
|
+
*args_hash,
|
|
1374
|
+
*args_basesetup,
|
|
1375
|
+
*args_indsetup,
|
|
1376
|
+
*args_thetas,
|
|
1377
|
+
np.int32(self.nthreads),
|
|
1378
|
+
*args_mapnap3,
|
|
1379
|
+
*args_4pcf)
|
|
1380
|
+
func = self.clib.alloc_notomoMapNap3_tree_gnnn
|
|
1381
|
+
else:
|
|
1382
|
+
args_indsetup = (np.int32(nthetacombis_tot), _inds, np.int32(len(_inds)), )
|
|
1383
|
+
args_4pcf = (bin_centers, Upsilon_n, N_n, )
|
|
1384
|
+
args = (*args_resos,
|
|
1385
|
+
*args_sourcecat,
|
|
1386
|
+
*args_resos_lens,
|
|
1387
|
+
*args_hash_source,
|
|
1388
|
+
*args_mhash_lens,
|
|
1389
|
+
*args_hash,
|
|
1390
|
+
*args_basesetup,
|
|
1391
|
+
*args_indsetup,
|
|
1392
|
+
np.int32(self.nthreads),
|
|
1393
|
+
np.int32(self._verbose_c),
|
|
1394
|
+
*args_4pcf)
|
|
1395
|
+
func = self.clib.alloc_notomoGammans_tree_gnnn
|
|
1396
|
+
|
|
1397
|
+
if self._verbose_debug:
|
|
1398
|
+
for elarg, arg in enumerate(args):
|
|
1399
|
+
toprint = (elarg, type(arg),)
|
|
1400
|
+
if isinstance(arg, np.ndarray):
|
|
1401
|
+
toprint += (type(arg[0]), arg.shape)
|
|
1402
|
+
try:
|
|
1403
|
+
toprint += (func.argtypes[elarg], )
|
|
1404
|
+
except:
|
|
1405
|
+
print("Weird error for arg %i."%elarg)
|
|
1406
|
+
print(toprint)
|
|
1407
|
+
print(arg)
|
|
1408
|
+
|
|
1409
|
+
func(*args)
|
|
1410
|
+
|
|
1411
|
+
## Massage the output ##
|
|
1412
|
+
istatout = ()
|
|
1413
|
+
self.bin_centers = bin_centers.reshape(szr)
|
|
1414
|
+
self.bin_centers_mean = np.mean(self.bin_centers, axis=0)
|
|
1415
|
+
self.projection = "X"
|
|
1416
|
+
self.is_edge_corrected = False
|
|
1417
|
+
if "4pcf_multipole" in statistics:
|
|
1418
|
+
self.npcf_multipoles = Upsilon_n.reshape(sc)
|
|
1419
|
+
self.npcf_multipoles_norm = N_n.reshape(sn)
|
|
1420
|
+
if "4pcf_real" in statistics:
|
|
1421
|
+
if lowmem:
|
|
1422
|
+
self.npcf = fourpcf.reshape(s4pcf)
|
|
1423
|
+
self.npcf_norm = fourpcf_norm.reshape(s4pcfn)
|
|
1424
|
+
else:
|
|
1425
|
+
if self._verbose_python:
|
|
1426
|
+
print("Transforming output to real space basis")
|
|
1427
|
+
self.multipoles2npcf_c()
|
|
1428
|
+
if hasintegratedstats:
|
|
1429
|
+
if "MN3" in statistics:
|
|
1430
|
+
istatout += (MN3correlators.reshape((1,self.nzcombis,len(apradii))), )
|
|
1431
|
+
# TODO allocate map4, map4c etc.
|
|
1432
|
+
|
|
1433
|
+
if apply_edge_correction:
|
|
1434
|
+
self.edge_correction()
|
|
1435
|
+
|
|
1436
|
+
return istatout
|
|
1437
|
+
|
|
1438
|
+
# TODO:
|
|
1439
|
+
# * Include the z-weighting method
|
|
1440
|
+
# * Include the 2pcf as spline --> Should we also add an option to compute it here? Might be a mess
|
|
1441
|
+
# as then we also would need methods to properly distribute randoms...
|
|
1442
|
+
# * Do a voronoi-tesselation at the multipole level? Would be just 2D, but still might help? Eventually
|
|
1443
|
+
# bundle together cells s.t. tot_weight > theshold? However, this might then make the binning courser
|
|
1444
|
+
# for certain triangle configs(?)
|
|
1445
|
+
def multipoles2npcf(self):
|
|
1446
|
+
raise NotImplementedError
|
|
1447
|
+
|
|
1448
|
+
def multipoles2npcf_singlethetcombi(self, elthet1, elthet2, elthet3, projection="X"):
|
|
1449
|
+
r""" Converts a 4PCF in the multipole basis in the real space basis for a fixed combination of radial bins.
|
|
1450
|
+
|
|
1451
|
+
Returns:
|
|
1452
|
+
--------
|
|
1453
|
+
npcf_out: np.ndarray
|
|
1454
|
+
4PCF components in the real-space bassi for all angular combinations.
|
|
1455
|
+
npcf_norm_out: np.ndarray
|
|
1456
|
+
4PCF weighted counts in the real-space bassi for all angular combinations.
|
|
1457
|
+
"""
|
|
1458
|
+
assert((projection in self.proj_dict.keys()) and (projection in self.projections_avail))
|
|
1459
|
+
|
|
1460
|
+
_phis1 = self.phis[0].astype(np.float64)
|
|
1461
|
+
_phis2 = self.phis[1].astype(np.float64)
|
|
1462
|
+
_nphis1 = len(self.phis[0])
|
|
1463
|
+
_nphis2 = len(self.phis[1])
|
|
1464
|
+
ncfs, nnvals, _, nzcombis, nbinsr, _, _ = np.shape(self.npcf_multipoles)
|
|
1465
|
+
|
|
1466
|
+
Upsilon_in = self.npcf_multipoles[...,elthet1,elthet2,elthet3].flatten()
|
|
1467
|
+
N_in = self.npcf_multipoles_norm[...,elthet1,elthet2,elthet3].flatten()
|
|
1468
|
+
npcf_out = np.zeros(self.n_cfs*nzcombis*_nphis1*_nphis2, dtype=np.complex128)
|
|
1469
|
+
npcf_norm_out = np.zeros(nzcombis*_nphis1*_nphis2, dtype=np.complex128)
|
|
1470
|
+
|
|
1471
|
+
self.clib.multipoles2npcf_gnnn_singletheta(
|
|
1472
|
+
Upsilon_in, N_in, self.nmaxs[0], self.nmaxs[1],
|
|
1473
|
+
self.bin_centers_mean[elthet1], self.bin_centers_mean[elthet2], self.bin_centers_mean[elthet3],
|
|
1474
|
+
_phis1, _phis2, _nphis1, _nphis2,
|
|
1475
|
+
npcf_out, npcf_norm_out)
|
|
1476
|
+
|
|
1477
|
+
return npcf_out.reshape((self.n_cfs, _nphis1,_nphis2)), npcf_norm_out.reshape((_nphis1,_nphis2))
|
|
1478
|
+
|
|
1479
|
+
def multipoles2npcf_singletheta_nconvergence(self, elthet1, elthet2, elthet3):
|
|
1480
|
+
r""" Checks convergence of the conversion between mutltipole-space and real space for a combination of radial bins.
|
|
1481
|
+
|
|
1482
|
+
Returns:
|
|
1483
|
+
--------
|
|
1484
|
+
npcf_out: np.ndarray
|
|
1485
|
+
Natural 4PCF components in the real-space basis for all angular combinations.
|
|
1486
|
+
npcf_norm_out: np.ndarray
|
|
1487
|
+
4PCF weighted counts in the real-space basis for all angular combinations.
|
|
1488
|
+
"""
|
|
1489
|
+
|
|
1490
|
+
_phis1 = self.phis[0].astype(np.float64)
|
|
1491
|
+
_phis2 = self.phis[1].astype(np.float64)
|
|
1492
|
+
_nphis1 = len(self.phis[0])
|
|
1493
|
+
_nphis2 = len(self.phis[1])
|
|
1494
|
+
|
|
1495
|
+
ncfs, nnvals, _, nzcombis, nbinsr, _, _ = np.shape(self.npcf_multipoles)
|
|
1496
|
+
|
|
1497
|
+
Upsilon_in = self.npcf_multipoles[...,elthet1,elthet2,elthet3].flatten()
|
|
1498
|
+
N_in = self.npcf_multipoles_norm[...,elthet1,elthet2,elthet3].flatten()
|
|
1499
|
+
npcf_out = np.zeros(self.n_cfs*nzcombis*(self.nmaxs[0]+1)*(self.nmaxs[1]+1)*_nphis1*_nphis2, dtype=np.complex128)
|
|
1500
|
+
npcf_norm_out = np.zeros(nzcombis*(self.nmaxs[0]+1)*(self.nmaxs[1]+1)*_nphis1*_nphis2, dtype=np.complex128)
|
|
1501
|
+
|
|
1502
|
+
self.clib.multipoles2npcf_gnnn_singletheta_nconvergence(
|
|
1503
|
+
Upsilon_in, N_in, self.nmaxs[0], self.nmaxs[1],
|
|
1504
|
+
self.bin_centers_mean[elthet1], self.bin_centers_mean[elthet2], self.bin_centers_mean[elthet3],
|
|
1505
|
+
_phis1, _phis2, _nphis1, _nphis2,
|
|
1506
|
+
npcf_out, npcf_norm_out)
|
|
1507
|
+
|
|
1508
|
+
npcf_out = npcf_out.reshape((self.n_cfs, self.nmaxs[0]+1, self.nmaxs[1]+1, _nphis1, _nphis2))
|
|
1509
|
+
npcf_norm_out = npcf_norm_out.reshape((self.nmaxs[0]+1, self.nmaxs[1]+1, _nphis1, _nphis2))
|
|
1510
|
+
|
|
1511
|
+
return npcf_out, npcf_norm_out
|
|
1512
|
+
|
|
1513
|
+
|
|
1514
|
+
## PROJECTIONS ##
|
|
1515
|
+
def projectnpcf(self, projection):
|
|
1516
|
+
super()._projectnpcf(self, projection)
|
|
1517
|
+
|
|
1518
|
+
## INTEGRATED MEASURES ##
|
|
1519
|
+
def computeMapNap3(self, radii, nmax_trafo=None, basis='MapMx'):
|
|
1520
|
+
r"""Computes the fourth-order aperture statistcs using the polynomial filter of Crittenden 2002."""
|
|
1521
|
+
|
|
1522
|
+
assert(basis in ['MapMx','MM*','both'])
|
|
1523
|
+
|
|
1524
|
+
if nmax_trafo is None:
|
|
1525
|
+
nmax_trafo=self.nmaxs[0]
|
|
1526
|
+
|
|
1527
|
+
# Retrieve all the aperture measures in the MM* basis via the 5D transformation eqns
|
|
1528
|
+
MN3correlators = np.zeros(1*len(radii), dtype=np.complex128)
|
|
1529
|
+
self.clib.fourpcfmultipoles2MN3correlators(
|
|
1530
|
+
np.int32(self.nmaxs[0]), np.int32(nmax_trafo),
|
|
1531
|
+
self.bin_edges, self.bin_centers_mean, np.int32(self.nbinsr),
|
|
1532
|
+
radii.astype(np.float64), np.int32(len(radii)),
|
|
1533
|
+
self.phis[0].astype(np.float64), self.phis[1].astype(np.float64),
|
|
1534
|
+
self.dphis[0].astype(np.float64), self.dphis[1].astype(np.float64),
|
|
1535
|
+
len(self.phis[0]), len(self.phis[1]),
|
|
1536
|
+
np.int32(self.proj_dict[self.projection]), np.int32(self.nthreads),
|
|
1537
|
+
self.npcf_multipoles.flatten(), self.npcf_multipoles_norm.flatten(),
|
|
1538
|
+
MN3correlators)
|
|
1539
|
+
res_MMStar = MN3correlators.reshape((1,len(radii)))
|
|
1540
|
+
|
|
1541
|
+
# Allocate result (here the bases are really equivalent...)
|
|
1542
|
+
res = ()
|
|
1543
|
+
if basis=='MM*' or basis=='both':
|
|
1544
|
+
res += (res_MMStar, )
|
|
1545
|
+
if basis=='MapMx' or basis=='both':
|
|
1546
|
+
res += ( res_MMStar, )
|
|
1547
|
+
|
|
1548
|
+
return res
|
|
1549
|
+
|
|
1550
|
+
def MapNap3_corrections(self, apradii, xi_ng=None, Gtilde_third=None,
|
|
1551
|
+
include_second=True, include_third=True, basis='MapMx'):
|
|
1552
|
+
|
|
1553
|
+
if xi_ng is not None and include_second:
|
|
1554
|
+
# Check consistency
|
|
1555
|
+
pass
|
|
1556
|
+
if xi_ng is None and include_second:
|
|
1557
|
+
# Compute gamma_t via treecorr
|
|
1558
|
+
pass
|
|
1559
|
+
|
|
1560
|
+
if Gtilde_third is not None and include_third:
|
|
1561
|
+
# Check consistency
|
|
1562
|
+
pass
|
|
1563
|
+
if Gtilde_third is None and include_third:
|
|
1564
|
+
# Compute GNN via treecorr
|
|
1565
|
+
pass
|
|
1566
|
+
if xi_ng is None:
|
|
1567
|
+
xi_ng = np.zeros(self.nbinsr, dtype=np.float64)
|
|
1568
|
+
if Gtilde_third is None:
|
|
1569
|
+
Gtilde_third = np.zeros(self.nbinsr*self.nbinsr*self.nbinsphi,dtype=np.complex128)
|
|
1570
|
+
|
|
1571
|
+
# This block is similar to MapNap3_analytic
|
|
1572
|
+
self.nbinsz = 1
|
|
1573
|
+
self.nzcombis = 1
|
|
1574
|
+
_nphis = len(self.phis[0])
|
|
1575
|
+
MN3correlators = np.zeros(self.n_cfs*self.nzcombis*len(apradii)).astype(np.complex128)
|
|
1576
|
+
# Define the radial bin batches
|
|
1577
|
+
args_4pcfsetup = (self.bin_edges, self.bin_centers_mean, np.int32(self.nbinsr),
|
|
1578
|
+
self.phis[0].astype(np.float64),
|
|
1579
|
+
(self.phis[0][1]-self.phis[0][0])*np.ones(_nphis, dtype=np.float64), _nphis, np.int32(self.nmaxs[0]), )
|
|
1580
|
+
args_map4 = (apradii.astype(np.float64), np.int32(len(apradii)), )
|
|
1581
|
+
|
|
1582
|
+
args = (*args_4pcfsetup,
|
|
1583
|
+
np.int32(self.nthreads),
|
|
1584
|
+
*args_map4,
|
|
1585
|
+
xi_ng.astype(np.float64),
|
|
1586
|
+
Gtilde_third.flatten(),
|
|
1587
|
+
np.int32(include_second),
|
|
1588
|
+
np.int32(include_third),
|
|
1589
|
+
MN3correlators)
|
|
1590
|
+
func = self.clib.alloc_notomoMapNap3_corrections
|
|
1591
|
+
|
|
1592
|
+
if self._verbose_debug:
|
|
1593
|
+
for elarg, arg in enumerate(args):
|
|
1594
|
+
toprint = (elarg, type(arg),)
|
|
1595
|
+
if isinstance(arg, np.ndarray):
|
|
1596
|
+
toprint += (type(arg[0]), arg.shape)
|
|
1597
|
+
try:
|
|
1598
|
+
toprint += (func.argtypes[elarg], )
|
|
1599
|
+
print(toprint)
|
|
1600
|
+
print(arg)
|
|
1601
|
+
except:
|
|
1602
|
+
print("We did have a problem for arg %i"%elarg)
|
|
1603
|
+
|
|
1604
|
+
func(*args)
|
|
1605
|
+
|
|
1606
|
+
return MN3correlators.reshape((1,len(apradii)))
|
|
1607
|
+
|
|
1608
|
+
def gauss4pcf_analytic(self, itheta1, itheta2, itheta3, nsubr,
|
|
1609
|
+
xing_arr, xinn_arr, thetamin_xi, thetamax_xi, dtheta_xi):
|
|
1610
|
+
|
|
1611
|
+
gauss_4pcf = np.zeros(self.n_cfs*self.nbinsphi[0]*self.nbinsphi[1],dtype=np.complex128)
|
|
1612
|
+
|
|
1613
|
+
self.clib.gtilde4pcf_analytic_integrated(
|
|
1614
|
+
np.int32(itheta1),
|
|
1615
|
+
np.int32(itheta2),
|
|
1616
|
+
np.int32(itheta3),
|
|
1617
|
+
np.int32(nsubr),
|
|
1618
|
+
self.bin_edges.astype(np.float64),
|
|
1619
|
+
np.int32(self.nbinsr),
|
|
1620
|
+
self.phis[0].astype(np.float64),
|
|
1621
|
+
np.int32(self.nbinsphi[0]),
|
|
1622
|
+
xing_arr.astype(np.float64),
|
|
1623
|
+
xinn_arr.astype(np.float64),
|
|
1624
|
+
np.float64(thetamin_xi),
|
|
1625
|
+
np.float64(thetamax_xi),
|
|
1626
|
+
np.float64(dtheta_xi),
|
|
1627
|
+
gauss_4pcf)
|
|
1628
|
+
return gauss_4pcf.reshape((self.n_cfs, self.nbinsphi[0], self.nbinsphi[1]))
|
|
1629
|
+
|
|
1630
|
+
def gnnn_corrections(self, itheta1, itheta2, itheta3, xi_ng=None, Gtilde_third=None,
|
|
1631
|
+
include_second=True, include_third=True):
|
|
1632
|
+
|
|
1633
|
+
if xi_ng is None:
|
|
1634
|
+
xi_ng = np.zeros(self.nbinsr, dtype=np.float64)
|
|
1635
|
+
if Gtilde_third is None:
|
|
1636
|
+
Gtilde_third = np.zeros(self.nbinsr*self.nbinsr*self.nbinsphi,dtype=np.complex128)
|
|
1637
|
+
|
|
1638
|
+
corrs = np.zeros(self.n_cfs*self.nbinsphi[0]*self.nbinsphi[1],dtype=np.complex128)
|
|
1639
|
+
self.clib.gtilde4pcf_corrections(
|
|
1640
|
+
np.int32(itheta1),
|
|
1641
|
+
np.int32(itheta2),
|
|
1642
|
+
np.int32(itheta3),
|
|
1643
|
+
np.int32(self.nbinsr),
|
|
1644
|
+
self.phis[0].astype(np.float64),
|
|
1645
|
+
np.int32(self.nbinsphi[0]),
|
|
1646
|
+
np.int32(self.nmaxs[0]),
|
|
1647
|
+
np.int32(include_second),
|
|
1648
|
+
np.int32(include_third),
|
|
1649
|
+
xi_ng.astype(np.float64),
|
|
1650
|
+
Gtilde_third.flatten().astype(np.complex128),
|
|
1651
|
+
corrs)
|
|
1652
|
+
|
|
1653
|
+
return corrs.reshape((self.n_cfs, self.nbinsphi[0], self.nbinsphi[1]))
|
|
1654
|
+
|
|
1655
|
+
# Disconnected part of MapNap^3 from analytic 2pcfs
|
|
1656
|
+
# thetamin_xi, thetamax_xi, ntheta_xi is the linspaced array in which the xipm are passed to the external function
|
|
1657
|
+
def MapNap3analytic(self, mapradii, xing_spl, xinn_spl, thetamin_xi, thetamax_xi, ntheta_xi,
|
|
1658
|
+
nsubr=1, nsubsample_filter=1, batchsize=None, basis='MapMx'):
|
|
1659
|
+
|
|
1660
|
+
self.nbinsz = 1
|
|
1661
|
+
self.nzcombis = 1
|
|
1662
|
+
_nmax = self.nmaxs[0]
|
|
1663
|
+
_nnvals = (2*_nmax+1)*(2*_nmax+1)
|
|
1664
|
+
_nbinsr3 = self.nbinsr*self.nbinsr*self.nbinsr
|
|
1665
|
+
_nphis = len(self.phis[0])
|
|
1666
|
+
bin_centers = np.zeros(self.nbinsz*self.nbinsr).astype(np.float64)
|
|
1667
|
+
MN3correlators = np.zeros(self.n_cfs*self.nzcombis*len(mapradii)).astype(np.complex128)
|
|
1668
|
+
# Define the radial bin batches
|
|
1669
|
+
if batchsize is None:
|
|
1670
|
+
batchsize = min(_nbinsr3,min(10000,int(_nbinsr3/self.nthreads)))
|
|
1671
|
+
if self._verbose_python:
|
|
1672
|
+
print("Using batchsize of %i for radial bins"%batchsize)
|
|
1673
|
+
nbatches = np.int32(_nbinsr3/batchsize)
|
|
1674
|
+
thetacombis_batches = np.arange(_nbinsr3).astype(np.int32)
|
|
1675
|
+
cumnthetacombis_batches = (np.arange(nbatches+1)*_nbinsr3/(nbatches)).astype(np.int32)
|
|
1676
|
+
nthetacombis_batches = (cumnthetacombis_batches[1:]-cumnthetacombis_batches[:-1]).astype(np.int32)
|
|
1677
|
+
cumnthetacombis_batches[-1] = _nbinsr3
|
|
1678
|
+
nthetacombis_batches[-1] = _nbinsr3-cumnthetacombis_batches[-2]
|
|
1679
|
+
thetacombis_batches = thetacombis_batches.flatten().astype(np.int32)
|
|
1680
|
+
nbatches = len(nthetacombis_batches)
|
|
1681
|
+
|
|
1682
|
+
args_4pcfsetup = (np.float64(self.min_sep), np.float64(self.max_sep), np.int32(self.nbinsr),
|
|
1683
|
+
self.phis[0].astype(np.float64),
|
|
1684
|
+
(self.phis[0][1]-self.phis[0][0])*np.ones(_nphis, dtype=np.float64), _nphis, np.int32(nsubr), )
|
|
1685
|
+
args_thetas = (thetacombis_batches, nthetacombis_batches, cumnthetacombis_batches, nbatches, )
|
|
1686
|
+
args_map4 = (mapradii.astype(np.float64), np.int32(len(mapradii)), )
|
|
1687
|
+
thetas_xi = np.linspace(thetamin_xi,thetamax_xi,ntheta_xi+1)
|
|
1688
|
+
args_xi = (xing_spl(thetas_xi), xinn_spl(thetas_xi), thetamin_xi, thetamax_xi, ntheta_xi, nsubsample_filter, )
|
|
1689
|
+
args = (*args_4pcfsetup,
|
|
1690
|
+
*args_thetas,
|
|
1691
|
+
np.int32(self.nthreads),
|
|
1692
|
+
*args_map4,
|
|
1693
|
+
*args_xi,
|
|
1694
|
+
MN3correlators)
|
|
1695
|
+
func = self.clib.alloc_notomoMapNap3_analytic
|
|
1696
|
+
|
|
1697
|
+
if self._verbose_debug:
|
|
1698
|
+
for elarg, arg in enumerate(args):
|
|
1699
|
+
toprint = (elarg, type(arg),)
|
|
1700
|
+
if isinstance(arg, np.ndarray):
|
|
1701
|
+
toprint += (type(arg[0]), arg.shape)
|
|
1702
|
+
try:
|
|
1703
|
+
toprint += (func.argtypes[elarg], )
|
|
1704
|
+
print(toprint)
|
|
1705
|
+
print(arg)
|
|
1706
|
+
except:
|
|
1707
|
+
print("We did have a problem for arg %i"%elarg)
|
|
1708
|
+
|
|
1709
|
+
func(*args)
|
|
1710
|
+
|
|
1711
|
+
res_MMStar = MN3correlators.reshape((self.n_cfs,len(mapradii)))
|
|
1712
|
+
# Allocate result
|
|
1713
|
+
res = ()
|
|
1714
|
+
res += (res_MMStar, )
|
|
1715
|
+
|
|
1716
|
+
return res
|