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 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
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: cosmock
3
+ Version: 0.0.1
4
+ Requires-Python: >=3.10
5
+ License-File: LICENSE
6
+ Requires-Dist: numpy>=2.0
7
+ Requires-Dist: scipy>=1.15
8
+ Requires-Dist: joblib>=1.2
9
+ Requires-Dist: healpy>=1.16
10
+ Dynamic: license-file
@@ -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,8 @@
1
+ from typing import NamedTuple
2
+ import numpy as np
3
+
4
+ class NonlinParameters(NamedTuple):
5
+ lbda: np.ndarray
6
+ N: int
7
+ Cl_Gauss: np.ndarray
8
+ mapshape: tuple
@@ -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,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: cosmock
3
+ Version: 0.0.1
4
+ Requires-Python: >=3.10
5
+ License-File: LICENSE
6
+ Requires-Dist: numpy>=2.0
7
+ Requires-Dist: scipy>=1.15
8
+ Requires-Dist: joblib>=1.2
9
+ Requires-Dist: healpy>=1.16
10
+ Dynamic: license-file
@@ -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,4 @@
1
+ numpy>=2.0
2
+ scipy>=1.15
3
+ joblib>=1.2
4
+ healpy>=1.16
@@ -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
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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"]