cosmock 0.0.1__tar.gz
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.
- cosmock-0.0.1/LICENSE +21 -0
- cosmock-0.0.1/PKG-INFO +10 -0
- cosmock-0.0.1/README.md +12 -0
- cosmock-0.0.1/cosmock/Cls.py +169 -0
- cosmock-0.0.1/cosmock/Gn.py +31 -0
- cosmock-0.0.1/cosmock/__init__.py +1 -0
- cosmock-0.0.1/cosmock/fitter.py +181 -0
- cosmock-0.0.1/cosmock/mocker.py +82 -0
- cosmock-0.0.1/cosmock/structs.py +8 -0
- cosmock-0.0.1/cosmock/wrappers.py +52 -0
- cosmock-0.0.1/cosmock.egg-info/PKG-INFO +10 -0
- cosmock-0.0.1/cosmock.egg-info/SOURCES.txt +16 -0
- cosmock-0.0.1/cosmock.egg-info/dependency_links.txt +1 -0
- cosmock-0.0.1/cosmock.egg-info/requires.txt +4 -0
- cosmock-0.0.1/cosmock.egg-info/top_level.txt +1 -0
- cosmock-0.0.1/pyproject.toml +15 -0
- cosmock-0.0.1/setup.cfg +4 -0
- cosmock-0.0.1/tests/test_CG.py +14 -0
cosmock-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ivan Espinoza
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cosmock-0.0.1/PKG-INFO
ADDED
cosmock-0.0.1/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# cosmock
|
|
2
|
+
|
|
3
|
+
Mock-field generation tools for cosmological kappa maps, implementing the
|
|
4
|
+
formalism and algorithm presented in 2411.04759.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
Install the base package for fitting, transforms, and spectrum conversion:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
python -m pip install -e .
|
|
12
|
+
```
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from numpy.polynomial.hermite import hermgauss
|
|
3
|
+
from scipy.special import eval_legendre
|
|
4
|
+
from scipy.interpolate import interp1d
|
|
5
|
+
from joblib import Parallel, delayed
|
|
6
|
+
from .Gn import Gn
|
|
7
|
+
|
|
8
|
+
def get_gh_nodes_weights(n_nodes):
|
|
9
|
+
"""
|
|
10
|
+
Computes the quadrature points and weights to
|
|
11
|
+
solve integrals for the form I = E[f(x)] where x
|
|
12
|
+
is standard normal. So, to solve integral
|
|
13
|
+
simply do np.sum(y_weights * f(y_nodes)).
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
x : int
|
|
18
|
+
Number of quadrature points
|
|
19
|
+
|
|
20
|
+
Returns
|
|
21
|
+
-------
|
|
22
|
+
points_weights : tuple
|
|
23
|
+
Returns the quadrature points, weights.
|
|
24
|
+
"""
|
|
25
|
+
t, w = hermgauss(n_nodes)
|
|
26
|
+
y_nodes = np.sqrt(2.0) * t
|
|
27
|
+
y_weights = w / np.sqrt(np.pi)
|
|
28
|
+
return y_nodes, y_weights
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def F_gauss_hermite_single(N, params_i, params_j, xi_g,
|
|
32
|
+
n_nodes=40,
|
|
33
|
+
precomputed=None):
|
|
34
|
+
if precomputed is None:
|
|
35
|
+
y_nodes, y_weights = get_gh_nodes_weights(n_nodes)
|
|
36
|
+
else:
|
|
37
|
+
y_nodes, y_weights = precomputed
|
|
38
|
+
|
|
39
|
+
cov = np.array([[1.0, xi_g],
|
|
40
|
+
[xi_g, 1.0]])
|
|
41
|
+
L = np.linalg.cholesky(cov)
|
|
42
|
+
|
|
43
|
+
# We build tensor product nodes and weights
|
|
44
|
+
YI, YJ = np.meshgrid(y_nodes, y_nodes, indexing='ij')
|
|
45
|
+
WI, WJ = np.meshgrid(y_weights, y_weights, indexing='ij')
|
|
46
|
+
|
|
47
|
+
# We map to X coordinates
|
|
48
|
+
Ystack = np.stack([YI.ravel(), YJ.ravel()], axis=1)
|
|
49
|
+
Xstack = (L @ Ystack.T).T
|
|
50
|
+
|
|
51
|
+
xi_vals = Xstack[:, 0]
|
|
52
|
+
xj_vals = Xstack[:, 1]
|
|
53
|
+
|
|
54
|
+
Gn_i = Gn(xi_vals, N, params_i)
|
|
55
|
+
Gn_j = Gn(xj_vals, N, params_j)
|
|
56
|
+
|
|
57
|
+
integrand = Gn_i * Gn_j * (WI * WJ).ravel()
|
|
58
|
+
result = integrand.sum()
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
def build_lookup_table(N, params_i,params_j, xi_g_values, pre,nnodes=20):
|
|
62
|
+
results = []
|
|
63
|
+
for xi_g in xi_g_values:
|
|
64
|
+
result = F_gauss_hermite_single(N, params_i,params_j, xi_g, nnodes,pre)
|
|
65
|
+
results.append(result)
|
|
66
|
+
return np.array(results)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def C_NG_to_C_G(cl_NG, fitted_params, N_bins, N,
|
|
70
|
+
xig_grid_size=75, quad_order=3, Nnodes=16,
|
|
71
|
+
n_jobs=4, v=0):
|
|
72
|
+
"""
|
|
73
|
+
Converts non-Gaussian power spectrum to a gaussianized version
|
|
74
|
+
given the parameters
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
cl_NG : array
|
|
79
|
+
Non-Gaussian power spectrum
|
|
80
|
+
fitted_params : array
|
|
81
|
+
Parameters for Gn function for each z-bin
|
|
82
|
+
N_bins : int
|
|
83
|
+
Number of redshift bins
|
|
84
|
+
N : int
|
|
85
|
+
Parameter for Gn function
|
|
86
|
+
xig_grid_size : int, optional
|
|
87
|
+
Number of points in xi_g interpolation grid (default: 75)
|
|
88
|
+
quad_order : int, optional
|
|
89
|
+
Gauss-Legendre quadrature order multiplier (default: 3)
|
|
90
|
+
Total points = quad_order * lmax
|
|
91
|
+
Nnodes : int, optional
|
|
92
|
+
Number of Gauss-Hermite nodes for F integral (default: 16)
|
|
93
|
+
n_jobs : int, optional
|
|
94
|
+
Number of parallel jobs. -1 uses all cores (default: 4)
|
|
95
|
+
v : int, optional
|
|
96
|
+
Verbosity level for joblib (default: 0)
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
cl_G : array
|
|
101
|
+
Gaussian power spectrum
|
|
102
|
+
"""
|
|
103
|
+
cl_G = np.zeros_like(cl_NG)
|
|
104
|
+
|
|
105
|
+
# Determine number of quadrature points needed
|
|
106
|
+
lmax_cl = cl_NG.shape[-1] - 1
|
|
107
|
+
n_quad = quad_order * lmax_cl
|
|
108
|
+
|
|
109
|
+
# We compute Gauss-Legendre quadrature points and weights
|
|
110
|
+
mu, w = np.polynomial.legendre.leggauss(n_quad)
|
|
111
|
+
|
|
112
|
+
# Pre-compute Legendre polynomials, instead of computing them
|
|
113
|
+
# each time
|
|
114
|
+
ell_array = np.arange(lmax_cl + 1)
|
|
115
|
+
P_ell = np.array([eval_legendre(ell, mu) for ell in ell_array])
|
|
116
|
+
|
|
117
|
+
# Setup for lookup table
|
|
118
|
+
xi_g_grid = np.linspace(-0.99999, 0.99999, xig_grid_size)
|
|
119
|
+
pre = get_gh_nodes_weights(Nnodes)
|
|
120
|
+
|
|
121
|
+
def process_pair_optimized(i, j):
|
|
122
|
+
params_i = fitted_params[i]
|
|
123
|
+
params_j = fitted_params[j]
|
|
124
|
+
|
|
125
|
+
# Cl_NG -> xi_NG
|
|
126
|
+
ell_col = ell_array[:, np.newaxis]
|
|
127
|
+
arg = (2*ell_col + 1) * P_ell * cl_NG[i, j, :, np.newaxis]
|
|
128
|
+
xi_NG = np.sum(arg, axis=0) / (4*np.pi)
|
|
129
|
+
|
|
130
|
+
# xi_NG -> xi_G
|
|
131
|
+
# Only in the case N = 2 we have an analitycal relation.
|
|
132
|
+
# In the other cases, we have to build lookup table.
|
|
133
|
+
if N == 2:
|
|
134
|
+
alpha_i, beta_i = params_i
|
|
135
|
+
alpha_j, beta_j = params_j
|
|
136
|
+
xi_G = np.log(1 + xi_NG / (beta_i * beta_j)) / (alpha_i * alpha_j)
|
|
137
|
+
else:
|
|
138
|
+
F_values = build_lookup_table(N, params_i, params_j, xi_g_grid, pre, Nnodes)
|
|
139
|
+
F_to_xi_g = interp1d(F_values, xi_g_grid, kind='linear',
|
|
140
|
+
fill_value='extrapolate')
|
|
141
|
+
xi_G = F_to_xi_g(xi_NG)
|
|
142
|
+
|
|
143
|
+
# xi_G -> Cl_G
|
|
144
|
+
integrand = P_ell * xi_G[np.newaxis, :]
|
|
145
|
+
clG_ij = 2 * np.pi * np.sum(w[np.newaxis, :] * integrand, axis=1)
|
|
146
|
+
clG_ij[:2] = 1e-20
|
|
147
|
+
|
|
148
|
+
return i, j, clG_ij
|
|
149
|
+
|
|
150
|
+
# Generate list of pairs to process
|
|
151
|
+
pairs = [(i, j) for i in range(N_bins) for j in range(i + 1)]
|
|
152
|
+
|
|
153
|
+
# Parallel computation
|
|
154
|
+
results = Parallel(n_jobs=n_jobs, verbose=v)(
|
|
155
|
+
delayed(process_pair_optimized)(i, j) for i, j in pairs
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# We fill the cl_G array with our results.
|
|
159
|
+
for i, j, clG_ij in results:
|
|
160
|
+
cl_G[i, j] = clG_ij
|
|
161
|
+
cl_G[j, i] = clG_ij
|
|
162
|
+
|
|
163
|
+
# ell = 0,1 are zero. This gives problems
|
|
164
|
+
# Instead, we make a positive definite matrix
|
|
165
|
+
# with very small eigenvalues.
|
|
166
|
+
for l in [0, 1]:
|
|
167
|
+
cl_G[:, :, l] = 1e-20 * np.eye(N_bins)
|
|
168
|
+
|
|
169
|
+
return cl_G
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
def Gn(x, N, lbda):
|
|
4
|
+
"""
|
|
5
|
+
Evaluate Gn transformation at given x values
|
|
6
|
+
|
|
7
|
+
Parameters
|
|
8
|
+
----------
|
|
9
|
+
x : array of x values (standard normal inputs)
|
|
10
|
+
n : str, which G function to use ('2', '3', '4', '5')
|
|
11
|
+
params : array of parameters for the transformation
|
|
12
|
+
N_nodes : number of Gauss-Hermite quad points to compute
|
|
13
|
+
integral for normalization.
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
y : transformed values
|
|
18
|
+
"""
|
|
19
|
+
# Evaluate transformation
|
|
20
|
+
if N == 2:
|
|
21
|
+
alpha, beta = lbda
|
|
22
|
+
return beta * np.exp(alpha * x - 0.5 * alpha**2) - beta
|
|
23
|
+
|
|
24
|
+
elif N == 3:
|
|
25
|
+
a, b, c = lbda
|
|
26
|
+
arg = np.exp(a * x - 0.5 * a**2) + b*x + c
|
|
27
|
+
norm = 1/(1+c)
|
|
28
|
+
return norm * arg - 1
|
|
29
|
+
|
|
30
|
+
else:
|
|
31
|
+
raise ValueError(f"Unknown model type: {N}")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .wrappers import fit_parameters,generate_mocks
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from .Gn import Gn
|
|
3
|
+
from scipy.optimize import minimize
|
|
4
|
+
from scipy.stats import norm
|
|
5
|
+
|
|
6
|
+
def variance_from_Cl(Cl):
|
|
7
|
+
"""
|
|
8
|
+
Computes the variance of the field
|
|
9
|
+
as predicted by the cls.
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
Cl : array
|
|
14
|
+
Array of cls
|
|
15
|
+
ell_min : float
|
|
16
|
+
First ell to start calculation.
|
|
17
|
+
Defaults to ell=0.
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
variance : float
|
|
22
|
+
Variance of the field as predicted by cls.
|
|
23
|
+
"""
|
|
24
|
+
Cl = np.asarray(Cl)
|
|
25
|
+
ell = np.arange(len(Cl))
|
|
26
|
+
return np.sum((2*ell + 1) * Cl) / (4*np.pi)
|
|
27
|
+
|
|
28
|
+
def get_binned_data(x_data, y_data, x_range, n_bins):
|
|
29
|
+
"""
|
|
30
|
+
Bin x values and compute mean y within each bin
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
x_data : array of Gaussianized x values
|
|
35
|
+
y_data : array of corresponding y values
|
|
36
|
+
n_bins : number of bins
|
|
37
|
+
x_range : tuple (min, max) to keep
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
x_bin_centers : x value at center of each bin
|
|
42
|
+
y_bin_means : mean y value in each bin
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
mask = (x_data >= x_range[0]) & (x_data <= x_range[1])
|
|
46
|
+
x_filtered = x_data[mask]
|
|
47
|
+
y_filtered = y_data[mask]
|
|
48
|
+
|
|
49
|
+
# Create bins
|
|
50
|
+
bin_edges = np.linspace(x_filtered.min(), x_filtered.max(), n_bins + 1)
|
|
51
|
+
|
|
52
|
+
# Find which bin each x value belongs to
|
|
53
|
+
bin_indices = np.digitize(x_filtered, bin_edges) - 1
|
|
54
|
+
|
|
55
|
+
# Clip to valid range
|
|
56
|
+
bin_indices = np.clip(bin_indices, 0, n_bins - 1)
|
|
57
|
+
|
|
58
|
+
x_bin_centers = []
|
|
59
|
+
y_bin_means = []
|
|
60
|
+
|
|
61
|
+
for i in range(n_bins):
|
|
62
|
+
bin_mask = (bin_indices == i)
|
|
63
|
+
# We only want to include bins with data
|
|
64
|
+
if np.sum(bin_mask) > 0:
|
|
65
|
+
x_bin_centers.append(bin_edges[i:i+2].mean())
|
|
66
|
+
y_bin_means.append(y_filtered[bin_mask].mean())
|
|
67
|
+
|
|
68
|
+
return np.array(x_bin_centers), np.array(y_bin_means)
|
|
69
|
+
|
|
70
|
+
def empirical_cdf(map):
|
|
71
|
+
"""
|
|
72
|
+
Computes the CDF of a map
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
map : array of that represents map
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
sorted_map : x-coordinates of the CDF
|
|
81
|
+
cdf_values : y-coordinates of the CDF
|
|
82
|
+
"""
|
|
83
|
+
sorted_map = np.sort(map)
|
|
84
|
+
cdf_values = np.arange(1, len(sorted_map) + 1) / len(sorted_map)
|
|
85
|
+
cdf_values = np.clip(cdf_values, 1e-10, 1 - 1e-10)
|
|
86
|
+
|
|
87
|
+
return sorted_map, cdf_values
|
|
88
|
+
|
|
89
|
+
def histogramer2d(map,Nbins,x_range=(-4.5,4.5)):
|
|
90
|
+
"""
|
|
91
|
+
Given a NL field, computes the black triangles in
|
|
92
|
+
FIG 1 in 2411.04759
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
map : field that we want to model
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
x_avg : x value of triangle (standard normal)
|
|
101
|
+
y_avg : y value of triangle (NL field)
|
|
102
|
+
"""
|
|
103
|
+
y_data, cdf = empirical_cdf(map)
|
|
104
|
+
x_gaussianized = norm.ppf(cdf)
|
|
105
|
+
x_avg,y_avg = get_binned_data(x_gaussianized,y_data,x_range,Nbins)
|
|
106
|
+
return x_avg, y_avg
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def fit_gn_with_constraint(x_data, y_data, N, cls, initial_lbda = None):
|
|
110
|
+
"""
|
|
111
|
+
Fit a Gn transformation to (x, y) data points
|
|
112
|
+
in a self-consistent manner by also including
|
|
113
|
+
the variance as predicted by the power spectrum.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
x_data : array
|
|
118
|
+
array of x-values (standard normal)
|
|
119
|
+
y_data : array
|
|
120
|
+
array of y-values (NL field)
|
|
121
|
+
N : str
|
|
122
|
+
Which G function to use ('2' and '3' are the
|
|
123
|
+
only supported)
|
|
124
|
+
cls : array
|
|
125
|
+
The power spectrum of the field.
|
|
126
|
+
initial_lbda : array
|
|
127
|
+
Initialization. If None, defaults to ones.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
fitted_lbda : array
|
|
132
|
+
Best fit parameters.
|
|
133
|
+
"""
|
|
134
|
+
var = variance_from_Cl(cls)
|
|
135
|
+
|
|
136
|
+
def calc_constrained_lbda(unconstrained_lbda, var, N):
|
|
137
|
+
if N == 2:
|
|
138
|
+
beta = unconstrained_lbda[0]
|
|
139
|
+
alpha = np.sqrt(np.log(1 + var / beta**2))
|
|
140
|
+
return np.array([alpha, beta])
|
|
141
|
+
elif N == 3:
|
|
142
|
+
a, b = unconstrained_lbda
|
|
143
|
+
c = np.sqrt((np.exp(a**2) - 1 + 2*a*b + b**2) / var) - 1
|
|
144
|
+
return np.array([a, b, c])
|
|
145
|
+
else:
|
|
146
|
+
raise ValueError(f"Cannot do a constrained fit for G{N}.")
|
|
147
|
+
|
|
148
|
+
def cost_function(unconstrained_lbda):
|
|
149
|
+
"""Least squares cost"""
|
|
150
|
+
lbda = calc_constrained_lbda(unconstrained_lbda, var, N)
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
y_pred = Gn(x_data, N, lbda)
|
|
154
|
+
return np.sum((y_pred - y_data)**2)
|
|
155
|
+
except:
|
|
156
|
+
return np.inf
|
|
157
|
+
if initial_lbda is None:
|
|
158
|
+
if N == 2:
|
|
159
|
+
beta_grid = np.geomspace(1e-6, 1, 50)
|
|
160
|
+
cost_grid = np.array([cost_function([b]) for b in beta_grid])
|
|
161
|
+
beta_init = beta_grid[np.argmin(cost_grid)]
|
|
162
|
+
initial_lbda = np.array([beta_init, np.nan])
|
|
163
|
+
elif N == 3:
|
|
164
|
+
a_grid = np.linspace(0.01, 1.7, 25)
|
|
165
|
+
b_grid = np.linspace(0.01, 2.7, 25)
|
|
166
|
+
cost_grid = np.array([
|
|
167
|
+
[cost_function([aa, bb]) for aa in a_grid]
|
|
168
|
+
for bb in b_grid
|
|
169
|
+
])
|
|
170
|
+
j_min, i_min = np.unravel_index(np.argmin(cost_grid), cost_grid.shape)
|
|
171
|
+
initial_lbda = np.array([a_grid[i_min], b_grid[j_min], np.nan])
|
|
172
|
+
else:
|
|
173
|
+
initial_lbda = np.ones(int(N))
|
|
174
|
+
initial_unconstrained_lbda = initial_lbda[:int(N)-1]
|
|
175
|
+
|
|
176
|
+
result = minimize(
|
|
177
|
+
fun=cost_function,
|
|
178
|
+
x0=initial_unconstrained_lbda,
|
|
179
|
+
method='BFGS'
|
|
180
|
+
)
|
|
181
|
+
return calc_constrained_lbda(result.x, var, N)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import healpy as hp
|
|
3
|
+
from .Gn import Gn
|
|
4
|
+
|
|
5
|
+
def get_xlm(xlm_real, xlm_imag,gen_lmax,nbins):
|
|
6
|
+
ell, emm = hp.Alm.getlm(gen_lmax)
|
|
7
|
+
#==============================
|
|
8
|
+
_xlm_real = np.zeros((nbins, len(ell)))
|
|
9
|
+
_xlm_imag = np.zeros_like(_xlm_real)
|
|
10
|
+
_xlm_real[:,ell > 1] = xlm_real
|
|
11
|
+
_xlm_imag[:,(ell > 1) & (emm > 0)] = xlm_imag
|
|
12
|
+
xlm = _xlm_real + 1j * _xlm_imag
|
|
13
|
+
#==============================
|
|
14
|
+
return xlm
|
|
15
|
+
|
|
16
|
+
def generate_xlm(nbins,gen_lmax):
|
|
17
|
+
ell, emm = hp.Alm.getlm(gen_lmax)
|
|
18
|
+
xlm_real = np.random.normal(size=(nbins, (ell > 1).sum()))
|
|
19
|
+
xlm_imag = np.random.normal(size=(nbins, ((ell > 1) & (emm > 0)).sum()))
|
|
20
|
+
xlm = get_xlm(xlm_real, xlm_imag, gen_lmax, nbins)
|
|
21
|
+
return xlm, [xlm_real,xlm_imag]
|
|
22
|
+
|
|
23
|
+
def apply_cl_G(xlm, Cl_G, gen_lmax):
|
|
24
|
+
Cl_G_T = np.moveaxis(Cl_G, 2, 0)
|
|
25
|
+
L_T = np.linalg.cholesky(Cl_G_T)
|
|
26
|
+
L_G = np.moveaxis(L_T, 0, 2)
|
|
27
|
+
gen_ell, gen_emm = hp.Alm.getlm(gen_lmax)
|
|
28
|
+
L_expanded = L_G[:, :, gen_ell]
|
|
29
|
+
ylm_real = np.einsum('ijm,jm->im', L_expanded, xlm.real) / np.sqrt(2)
|
|
30
|
+
ylm_imag = np.einsum('ijm,jm->im', L_expanded, xlm.imag) / np.sqrt(2)
|
|
31
|
+
ylm_real = np.where(gen_emm == 0, ylm_real * np.sqrt(2), ylm_real)
|
|
32
|
+
ylm_imag = np.where(gen_emm == 0, 0.0, ylm_imag)
|
|
33
|
+
return ylm_real + 1j * ylm_imag
|
|
34
|
+
|
|
35
|
+
def get_y_maps(cl,nside,nbins,gen_lmax,xlms=None):
|
|
36
|
+
if xlms is not None:
|
|
37
|
+
xlm = xlms
|
|
38
|
+
_xlm = None
|
|
39
|
+
else:
|
|
40
|
+
xlm, _xlm = generate_xlm(nbins,gen_lmax)
|
|
41
|
+
y_lm, xlm = apply_cl_G(xlm, cl,gen_lmax), _xlm
|
|
42
|
+
y_maps = []
|
|
43
|
+
for i in range(nbins):
|
|
44
|
+
y_map = hp.alm2map(np.ascontiguousarray(y_lm[i]), nside, lmax=gen_lmax, pol=False)
|
|
45
|
+
y_maps.append(y_map)
|
|
46
|
+
return np.array(y_maps)
|
|
47
|
+
|
|
48
|
+
def get_kappa(y_maps,nbins,N,fitted_params):
|
|
49
|
+
k_list = []
|
|
50
|
+
for i in range(nbins):
|
|
51
|
+
k_nf = Gn(y_maps[i], N, fitted_params[i])
|
|
52
|
+
k = k_nf
|
|
53
|
+
k_list.append(k)
|
|
54
|
+
k_arr = np.array(k_list)
|
|
55
|
+
return k_arr
|
|
56
|
+
|
|
57
|
+
def get_kappa_pixwin(y_maps,nbins,N,fitted_params,nside,pixwinatell):
|
|
58
|
+
k_list = []
|
|
59
|
+
lmax = 2*nside
|
|
60
|
+
for i in range(nbins):
|
|
61
|
+
k_nf = Gn(y_maps[i], N, fitted_params[i])
|
|
62
|
+
k = k_nf
|
|
63
|
+
klm = hp.map2alm(k,lmax=lmax)
|
|
64
|
+
klm = klm * pixwinatell
|
|
65
|
+
k = hp.alm2map(klm,nside)
|
|
66
|
+
k_list.append(k)
|
|
67
|
+
k_arr = np.array(k_list)
|
|
68
|
+
|
|
69
|
+
return k_arr
|
|
70
|
+
|
|
71
|
+
def get_kappa_lm_pixwin(y_maps,nbins,N,fitted_params,nside,pixwinatell):
|
|
72
|
+
k_lm_list = []
|
|
73
|
+
lmax = 2*nside
|
|
74
|
+
for i in range(nbins):
|
|
75
|
+
k_nf = Gn(y_maps[i], N, fitted_params[i])
|
|
76
|
+
k = k_nf
|
|
77
|
+
klm = hp.map2alm(k,lmax=lmax)
|
|
78
|
+
klm = klm * pixwinatell
|
|
79
|
+
k_lm_list.append(klm)
|
|
80
|
+
k_lm_arr = np.array(k_lm_list)
|
|
81
|
+
|
|
82
|
+
return k_lm_arr
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import healpy as hp
|
|
3
|
+
from .structs import NonlinParameters
|
|
4
|
+
from .fitter import histogramer2d, fit_gn_with_constraint
|
|
5
|
+
from .Cls import C_NG_to_C_G
|
|
6
|
+
from .mocker import get_y_maps, get_kappa_pixwin
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def fit_parameters(maps, Cl_delta, N):
|
|
10
|
+
|
|
11
|
+
Nbins = maps.shape[0]
|
|
12
|
+
Nside = hp.npix2nside(maps.shape[1])
|
|
13
|
+
|
|
14
|
+
lbda = np.zeros((Nbins, N))
|
|
15
|
+
for i in range(Nbins):
|
|
16
|
+
x, y = histogramer2d(maps[i], 1000)
|
|
17
|
+
lbda[i] = fit_gn_with_constraint(x, y, N, Cl_delta[i,i,:3*Nside])
|
|
18
|
+
|
|
19
|
+
print(f'Done fitting the G{N} parameters')
|
|
20
|
+
|
|
21
|
+
Cl_G = C_NG_to_C_G(Cl_delta, lbda, Nbins, N)
|
|
22
|
+
Cl_G = Cl_G[:,:,:3*Nside]
|
|
23
|
+
|
|
24
|
+
print('Done finding the power spectrum of the underlying gaussian random field')
|
|
25
|
+
|
|
26
|
+
params = NonlinParameters(lbda = lbda, N = N, Cl_Gauss = Cl_G, mapshape = maps.shape)
|
|
27
|
+
|
|
28
|
+
return params
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def generate_mocks(params, Nmocks, pixwin=None):
|
|
32
|
+
|
|
33
|
+
lbda = params.lbda
|
|
34
|
+
N = params.N
|
|
35
|
+
Cl_G = params.Cl_Gauss
|
|
36
|
+
mapshape = params.mapshape
|
|
37
|
+
Nbins = mapshape[0]
|
|
38
|
+
Npix = mapshape[1]
|
|
39
|
+
Nside = hp.npix2nside(Npix)
|
|
40
|
+
gen_lmax = 3*Nside-1
|
|
41
|
+
lmax = 2*Nside
|
|
42
|
+
ell, emm = hp.Alm.getlm(lmax)
|
|
43
|
+
|
|
44
|
+
if pixwin is None:
|
|
45
|
+
pixwin = hp.pixwin(Nside, False, gen_lmax)
|
|
46
|
+
|
|
47
|
+
mocks = np.zeros((Nmocks, *mapshape))
|
|
48
|
+
for i in range(Nmocks):
|
|
49
|
+
y_map = get_y_maps(Cl_G, Nside, Nbins, gen_lmax)
|
|
50
|
+
mocks[i] = get_kappa_pixwin(y_map, Nbins, N, lbda, Nside, pixwin[ell])
|
|
51
|
+
|
|
52
|
+
return mocks
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
cosmock/Cls.py
|
|
5
|
+
cosmock/Gn.py
|
|
6
|
+
cosmock/__init__.py
|
|
7
|
+
cosmock/fitter.py
|
|
8
|
+
cosmock/mocker.py
|
|
9
|
+
cosmock/structs.py
|
|
10
|
+
cosmock/wrappers.py
|
|
11
|
+
cosmock.egg-info/PKG-INFO
|
|
12
|
+
cosmock.egg-info/SOURCES.txt
|
|
13
|
+
cosmock.egg-info/dependency_links.txt
|
|
14
|
+
cosmock.egg-info/requires.txt
|
|
15
|
+
cosmock.egg-info/top_level.txt
|
|
16
|
+
tests/test_CG.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cosmock
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cosmock"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
"numpy>=2.0",
|
|
12
|
+
"scipy>=1.15",
|
|
13
|
+
"joblib>=1.2",
|
|
14
|
+
"healpy>=1.16",
|
|
15
|
+
]
|
cosmock-0.0.1/setup.cfg
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import tomllib
|
|
3
|
+
|
|
4
|
+
import cosmock
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_public_api_imports():
|
|
8
|
+
assert "Gn" in cosmock.__all__
|
|
9
|
+
assert "C_NG_to_C_G" in cosmock.__all__
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_version_matches_pyproject():
|
|
13
|
+
pyproject = tomllib.loads(Path("pyproject.toml").read_text())
|
|
14
|
+
assert cosmock.__version__ == pyproject["project"]["version"]
|