flipcosmo 1.0.0__py3-none-any.whl → 1.2.1__py3-none-any.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.
- docs/conf.py +154 -0
- flip/__init__.py +4 -11
- flip/covariance/__init__.py +7 -8
- flip/covariance/analytical/__init__.py +11 -0
- flip/covariance/{adamsblake17plane → analytical/adamsblake17}/coefficients.py +1 -1
- flip/covariance/{adamsblake17plane → analytical/adamsblake17}/fisher_terms.py +1 -1
- flip/covariance/{adamsblake17 → analytical/adamsblake17}/flip_terms.py +0 -1
- flip/covariance/{adamsblake17 → analytical/adamsblake17plane}/coefficients.py +1 -1
- flip/covariance/{adamsblake17 → analytical/adamsblake17plane}/fisher_terms.py +1 -1
- flip/covariance/{adamsblake17plane → analytical/adamsblake17plane}/flip_terms.py +0 -1
- flip/covariance/{adamsblake17plane → analytical/adamsblake17plane}/generator.py +103 -19
- flip/covariance/{adamsblake20 → analytical/adamsblake20}/coefficients.py +1 -1
- flip/covariance/{adamsblake20 → analytical/adamsblake20}/fisher_terms.py +1 -1
- flip/covariance/{adamsblake20 → analytical/adamsblake20}/flip_terms.py +0 -1
- flip/covariance/{carreres23 → analytical/carreres23}/coefficients.py +1 -4
- flip/covariance/{ravouxnoanchor25 → analytical/carreres23}/fisher_terms.py +1 -1
- flip/covariance/{carreres23 → analytical/carreres23}/flip_terms.py +0 -1
- flip/covariance/analytical/carreres23/generator.py +198 -0
- flip/covariance/analytical/genericzdep/__init__.py +5 -0
- flip/covariance/analytical/genericzdep/coefficients.py +53 -0
- flip/covariance/analytical/genericzdep/flip_terms.py +99 -0
- flip/covariance/{lai22 → analytical/lai22}/coefficients.py +2 -3
- flip/covariance/{lai22 → analytical/lai22}/fisher_terms.py +1 -1
- flip/covariance/{lai22 → analytical/lai22}/flip_terms.py +0 -1
- flip/covariance/{lai22 → analytical/lai22}/generator.py +263 -58
- flip/covariance/{lai22 → analytical/lai22}/symbolic.py +55 -19
- flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/coefficients.py +1 -1
- flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/fisher_terms.py +1 -1
- flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/flip_terms.py +0 -1
- flip/covariance/{ravouxnoanchor25 → analytical/ravouxnoanchor25}/coefficients.py +3 -2
- flip/covariance/{carreres23 → analytical/ravouxnoanchor25}/fisher_terms.py +1 -1
- flip/covariance/{ravouxnoanchor25 → analytical/ravouxnoanchor25}/flip_terms.py +0 -9
- flip/covariance/{rcrk24 → analytical/rcrk24}/coefficients.py +6 -6
- flip/covariance/{rcrk24 → analytical/rcrk24}/fisher_terms.py +7 -9
- flip/covariance/{rcrk24 → analytical/rcrk24}/flip_terms.py +0 -8
- flip/covariance/contraction.py +82 -40
- flip/covariance/cov_utils.py +89 -81
- flip/covariance/covariance.py +172 -141
- flip/covariance/emulators/__init__.py +1 -1
- flip/covariance/emulators/generator.py +73 -3
- flip/covariance/emulators/gpmatrix.py +40 -1
- flip/covariance/emulators/nnmatrix.py +57 -1
- flip/covariance/emulators/skgpmatrix.py +125 -0
- flip/covariance/fisher.py +307 -0
- flip/{fit_utils.py → covariance/fit_utils.py} +185 -10
- flip/{fitter.py → covariance/fitter.py} +151 -125
- flip/covariance/generator.py +82 -106
- flip/{likelihood.py → covariance/likelihood.py} +286 -64
- flip/{plot_utils.py → covariance/plot_utils.py} +79 -4
- flip/covariance/symbolic.py +89 -44
- flip/data/__init__.py +1 -1
- flip/data/data_density.parquet +0 -0
- flip/data/data_velocity.parquet +0 -0
- flip/data/{grid_window_m.parquet → data_window_density.parquet} +0 -0
- flip/{gridding.py → data/gridding.py} +125 -130
- flip/data/load_data_test.py +102 -0
- flip/data/power_spectrum_mm.txt +2 -2
- flip/data/power_spectrum_mt.txt +2 -2
- flip/data/power_spectrum_tt.txt +2 -2
- flip/data/test_covariance_reference_values.json +145 -0
- flip/data/test_e2e_reference_values.json +14 -0
- flip/data_vector/basic.py +118 -101
- flip/data_vector/cosmo_utils.py +18 -0
- flip/data_vector/galaxypv_vectors.py +58 -94
- flip/data_vector/snia_vectors.py +60 -3
- flip/data_vector/vector_utils.py +47 -1
- flip/power_spectra/class_engine.py +36 -1
- flip/power_spectra/cosmoprimo_engine.py +37 -2
- flip/power_spectra/generator.py +47 -25
- flip/power_spectra/models.py +30 -31
- flip/power_spectra/pyccl_engine.py +36 -1
- flip/simulation/__init__.py +0 -0
- flip/utils.py +62 -91
- flipcosmo-1.2.1.dist-info/METADATA +78 -0
- flipcosmo-1.2.1.dist-info/RECORD +109 -0
- {flipcosmo-1.0.0.dist-info → flipcosmo-1.2.1.dist-info}/WHEEL +1 -1
- flipcosmo-1.2.1.dist-info/top_level.txt +7 -0
- scripts/flip_compute_correlation_model.py +70 -0
- scripts/flip_compute_power_spectra.py +50 -0
- scripts/flip_fisher_forecast_velocity.py +70 -0
- scripts/flip_fisher_rcrk24.py +164 -0
- scripts/flip_launch_minuit_density_fit.py +91 -0
- scripts/flip_launch_minuit_full_fit.py +117 -0
- scripts/flip_launch_minuit_velocity_fit.py +78 -0
- scripts/flip_launch_minuit_velocity_fit_full.py +107 -0
- scripts/flip_launch_minuit_velocity_fit_interpolation.py +93 -0
- test/refresh_reference_values.py +43 -0
- test/test_covariance_assembly.py +102 -0
- test/test_covariance_reference_values.py +125 -0
- test/test_covariance_utils.py +34 -0
- test/test_e2e_density.py +50 -0
- test/test_e2e_joint.py +65 -0
- test/test_e2e_velocity.py +53 -0
- test/test_likelihood_inversions.py +31 -0
- flip/covariance/carreres23/generator.py +0 -132
- flip/data/density_data.parquet +0 -0
- flip/data/velocity_data.parquet +0 -0
- flip/fisher.py +0 -190
- flipcosmo-1.0.0.dist-info/METADATA +0 -32
- flipcosmo-1.0.0.dist-info/RECORD +0 -82
- flipcosmo-1.0.0.dist-info/top_level.txt +0 -1
- /flip/{config.py → _config.py} +0 -0
- /flip/covariance/{adamsblake17 → analytical/adamsblake17}/__init__.py +0 -0
- /flip/covariance/{adamsblake17plane → analytical/adamsblake17plane}/__init__.py +0 -0
- /flip/covariance/{adamsblake20 → analytical/adamsblake20}/__init__.py +0 -0
- /flip/covariance/{carreres23 → analytical/carreres23}/__init__.py +0 -0
- /flip/covariance/{lai22 → analytical/lai22}/__init__.py +0 -0
- /flip/covariance/{lai22 → analytical/lai22}/h_terms.py +0 -0
- /flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/__init__.py +0 -0
- /flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/flip_terms_lmax.py +0 -0
- /flip/covariance/{ravouxnoanchor25 → analytical/ravouxnoanchor25}/__init__.py +0 -0
- /flip/covariance/{rcrk24 → analytical/rcrk24}/__init__.py +0 -0
- {flipcosmo-1.0.0.dist-info → flipcosmo-1.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -9,35 +9,64 @@ from scipy.interpolate import interp1d
|
|
|
9
9
|
from scipy.special import factorial, spherical_jn
|
|
10
10
|
|
|
11
11
|
from flip.covariance import cov_utils
|
|
12
|
-
from flip.covariance.lai22 import h_terms
|
|
13
12
|
|
|
14
13
|
|
|
15
|
-
def compute_correlation_coefficient_simple_integration(p, q,
|
|
16
|
-
"""
|
|
17
|
-
|
|
14
|
+
def compute_correlation_coefficient_simple_integration(p, q, ell, r, k, pk):
|
|
15
|
+
"""Compute correlation coefficient via direct integration.
|
|
16
|
+
|
|
17
|
+
Implements Lai et al. formalism with the ``(2π^2)`` factor inside the
|
|
18
|
+
integrand. The small-scale velocity dispersion (``sigma_u``) should be
|
|
19
|
+
applied to ``pk`` upstream when required.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
p: Power of k from derivative order on point 1.
|
|
23
|
+
q: Power of k from derivative order on point 2.
|
|
24
|
+
ell: Spherical Bessel order.
|
|
25
|
+
r: Separation values at which to evaluate.
|
|
26
|
+
k: Wavenumbers.
|
|
27
|
+
pk: Power spectrum values at ``k``.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Array of correlation coefficient values at separations ``r``.
|
|
31
|
+
"""
|
|
18
32
|
kr = np.outer(k, r)
|
|
19
|
-
integrand =
|
|
33
|
+
integrand = (
|
|
34
|
+
spherical_jn(ell, kr).T * k**2 * k ** (2 * (p + q)) * pk / (2 * np.pi**2)
|
|
35
|
+
)
|
|
20
36
|
return integrate.simpson(integrand, x=k)
|
|
21
37
|
|
|
22
38
|
|
|
23
39
|
def compute_correlation_coefficient_hankel(
|
|
24
|
-
p, q,
|
|
40
|
+
p, q, ell, r, k, pk, hankel_overhead_coefficient=2
|
|
25
41
|
):
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
"""Compute correlation coefficient using FFTLog Hankel transform.
|
|
43
|
+
|
|
44
|
+
Uses cosmoprimo's ``PowerToCorrelation`` to accelerate the computation.
|
|
45
|
+
Falls back to direct integration for small ``r`` values where the Hankel
|
|
46
|
+
result may be unreliable, controlled by ``hankel_overhead_coefficient``.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
p: Power of k from derivative order on point 1.
|
|
50
|
+
q: Power of k from derivative order on point 2.
|
|
51
|
+
ell: Spherical Bessel order.
|
|
52
|
+
r: Separation values.
|
|
53
|
+
k: Wavenumbers.
|
|
54
|
+
pk: Power spectrum values.
|
|
55
|
+
hankel_overhead_coefficient: Safety margin for the small-``r`` mask.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Array of correlation coefficient values at separations ``r``.
|
|
30
59
|
"""
|
|
31
60
|
integrand = k ** (2 * (p + q)) * pk
|
|
32
|
-
Hankel = cosmoprimo.fftlog.PowerToCorrelation(k, ell=
|
|
61
|
+
Hankel = cosmoprimo.fftlog.PowerToCorrelation(k, ell=ell, q=0, complex=False)
|
|
33
62
|
Hankel.set_fft_engine("numpy")
|
|
34
63
|
r_hankel, xi_hankel = Hankel(integrand)
|
|
35
64
|
mask = r < np.min(r_hankel) * hankel_overhead_coefficient
|
|
36
65
|
output = np.empty_like(r)
|
|
37
66
|
output[mask] = compute_correlation_coefficient_simple_integration(
|
|
38
|
-
p, q,
|
|
67
|
+
p, q, ell, r[mask], k, pk
|
|
39
68
|
)
|
|
40
|
-
output[~mask] = (-1) ** (
|
|
69
|
+
output[~mask] = (-1) ** (ell // 2) * interp1d(r_hankel, xi_hankel)(r[~mask])
|
|
41
70
|
return output
|
|
42
71
|
|
|
43
72
|
|
|
@@ -53,6 +82,23 @@ def compute_cov_vv(
|
|
|
53
82
|
hankel=True,
|
|
54
83
|
los_definition="bisector",
|
|
55
84
|
):
|
|
85
|
+
"""Compute velocity-velocity covariance in Lai22 wide-angle formalism.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
ra: Right ascensions of objects (radians).
|
|
89
|
+
dec: Declinations of objects (radians).
|
|
90
|
+
comoving_distance: Comoving distances of objects.
|
|
91
|
+
wavenumber_tt: Wavenumbers for velocity-velocity spectrum.
|
|
92
|
+
power_spectrum_tt: P_tt values at ``wavenumber_tt``.
|
|
93
|
+
grid_window_v_tt: Optional window function applied to ``P_tt``.
|
|
94
|
+
size_batch: Batch size for pair processing.
|
|
95
|
+
number_worker: Number of parallel workers (1 for serial).
|
|
96
|
+
hankel: If True, use Hankel transform acceleration where applicable.
|
|
97
|
+
los_definition: Line-of-sight definition ("bisector").
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Flattened covariance vector with the diagonal term at index 0 followed by upper-triangle terms.
|
|
101
|
+
"""
|
|
56
102
|
if grid_window_v_tt is not None:
|
|
57
103
|
power_spectrum_tt = power_spectrum_tt * grid_window_v_tt**2
|
|
58
104
|
|
|
@@ -92,18 +138,29 @@ def compute_cov_vv(
|
|
|
92
138
|
|
|
93
139
|
|
|
94
140
|
def coefficient_vv(wavenumber, power_spectrum_tt, coord, hankel=True):
|
|
141
|
+
"""Coefficient contributing to vv covariance for a given separation.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
wavenumber: Wavenumbers array.
|
|
145
|
+
power_spectrum_tt: Velocity-velocity power spectrum at ``wavenumber``.
|
|
146
|
+
coord: Tuple/list ``(r, theta, phi)`` separation coordinates.
|
|
147
|
+
hankel: If True, use Hankel transform; else use direct integration.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Scalar covariance contribution at the provided separation.
|
|
151
|
+
"""
|
|
95
152
|
result = 0
|
|
96
|
-
for
|
|
153
|
+
for ell in [0, 2]:
|
|
97
154
|
if hankel:
|
|
98
155
|
correlation = compute_correlation_coefficient_hankel(
|
|
99
|
-
-0.5, -0.5,
|
|
156
|
+
-0.5, -0.5, ell, coord[0], wavenumber, power_spectrum_tt
|
|
100
157
|
)
|
|
101
158
|
else:
|
|
102
159
|
correlation = compute_correlation_coefficient_simple_integration(
|
|
103
|
-
-0.5, -0.5,
|
|
160
|
+
-0.5, -0.5, ell, coord[0], wavenumber, power_spectrum_tt
|
|
104
161
|
)
|
|
105
|
-
h_function = eval(f"h_terms.H_vv_l{
|
|
106
|
-
result = result + np.real(1j ** (
|
|
162
|
+
h_function = eval(f"h_terms.H_vv_l{ell}")(coord[1], coord[2])
|
|
163
|
+
result = result + np.real(1j ** (ell)) * correlation * h_function
|
|
107
164
|
return result
|
|
108
165
|
|
|
109
166
|
|
|
@@ -129,6 +186,36 @@ def compute_cov_gg(
|
|
|
129
186
|
hankel=True,
|
|
130
187
|
los_definition="bisector",
|
|
131
188
|
):
|
|
189
|
+
"""Compute density-density covariance terms for Lai22 wide-angle.
|
|
190
|
+
|
|
191
|
+
Builds per-``m`` contributions for b², f² and bf components using sums over
|
|
192
|
+
``p,q,ℓ`` multipoles with optional damping on the matter-matter spectrum.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
pmax: Maximum p index.
|
|
196
|
+
qmax: Maximum q index.
|
|
197
|
+
ra: Right ascensions (radians).
|
|
198
|
+
dec: Declinations (radians).
|
|
199
|
+
comoving_distance: Comoving distances.
|
|
200
|
+
wavenumber_mm: Wavenumbers for matter-matter spectrum.
|
|
201
|
+
wavenumber_mt: Wavenumbers for matter-velocity spectrum.
|
|
202
|
+
wavenumber_tt: Wavenumbers for velocity-velocity spectrum.
|
|
203
|
+
power_spectrum_mm: P_mm at ``wavenumber_mm``.
|
|
204
|
+
power_spectrum_mt: P_mv at ``wavenumber_mt``.
|
|
205
|
+
power_spectrum_tt: P_vv at ``wavenumber_tt``.
|
|
206
|
+
grid_window_m_mm: Optional window for P_mm.
|
|
207
|
+
grid_window_m_mt: Optional window for P_mv.
|
|
208
|
+
grid_window_v_mt: Optional velocity window multiplying P_mv.
|
|
209
|
+
grid_window_v_tt: Optional window for P_vv.
|
|
210
|
+
size_batch: Batch size for pair processing.
|
|
211
|
+
number_worker: Number of workers (1 for serial).
|
|
212
|
+
sig_damp_mm_gg_m: Damping scale for P_mm high-k suppression in gg b² terms.
|
|
213
|
+
hankel: Use Hankel transform acceleration when True.
|
|
214
|
+
los_definition: Line-of-sight definition ("bisector").
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Tuple ``(m_index, cov_gg_b2, cov_gg_f2, cov_gg_bf)`` with lists of flattened per-m covariance vectors (variance inserted at index 0).
|
|
218
|
+
"""
|
|
132
219
|
if grid_window_m_mm is not None:
|
|
133
220
|
power_spectrum_mm = power_spectrum_mm * grid_window_m_mm**2
|
|
134
221
|
|
|
@@ -298,6 +385,26 @@ def compute_cov_gg_add(
|
|
|
298
385
|
hankel=True,
|
|
299
386
|
los_definition="bisector",
|
|
300
387
|
):
|
|
388
|
+
"""Compute additional gg b² terms only (e.g. for additive components).
|
|
389
|
+
|
|
390
|
+
Args:
|
|
391
|
+
pmax: Maximum p index.
|
|
392
|
+
qmax: Maximum q index.
|
|
393
|
+
ra: Right ascensions (radians).
|
|
394
|
+
dec: Declinations (radians).
|
|
395
|
+
comoving_distance: Comoving distances.
|
|
396
|
+
wavenumber_mm: Wavenumbers for matter-matter spectrum.
|
|
397
|
+
power_spectrum_mm: P_mm values.
|
|
398
|
+
grid_window_m_mm: Optional window for P_mm.
|
|
399
|
+
size_batch: Batch size for pair processing.
|
|
400
|
+
number_worker: Number of workers.
|
|
401
|
+
sig_damp_mm_gg_m: Damping scale for P_mm high-k suppression.
|
|
402
|
+
hankel: Use Hankel transform acceleration when True.
|
|
403
|
+
los_definition: Line-of-sight definition.
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
Tuple ``(m_index, cov_gg_b2_add)`` with flattened covariance vectors including variance at index 0.
|
|
407
|
+
"""
|
|
301
408
|
if grid_window_m_mm is not None:
|
|
302
409
|
power_spectrum_mm = power_spectrum_mm * grid_window_m_mm**2
|
|
303
410
|
|
|
@@ -383,6 +490,21 @@ def coefficient_gg_b2_m(
|
|
|
383
490
|
coord,
|
|
384
491
|
hankel=True,
|
|
385
492
|
):
|
|
493
|
+
"""b² coefficient for gg block at fixed m.
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
wavenumber_mm: Wavenumbers for P_mm.
|
|
497
|
+
power_spectrum_mm: P_mm values (with optional damping applied inside).
|
|
498
|
+
iter_pq: Array of all (p, q) combinations.
|
|
499
|
+
sum_iter_pq: Array of ``2*(p+q)`` per (p, q) used for m filtering.
|
|
500
|
+
m_value: Even m index for basis term.
|
|
501
|
+
sig_damp_mm_gg_m: Damping scale for P_mm when ``m_value != 0``.
|
|
502
|
+
coord: Separation coordinates ``(r, theta, phi)``.
|
|
503
|
+
hankel: Use Hankel transform acceleration when True.
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
Scalar contribution for the given separation.
|
|
507
|
+
"""
|
|
386
508
|
if (sig_damp_mm_gg_m is not None) and (m_value != 0):
|
|
387
509
|
power_spectrum_mm = power_spectrum_mm * np.exp(
|
|
388
510
|
-((wavenumber_mm * sig_damp_mm_gg_m) ** 4) / 2
|
|
@@ -392,18 +514,18 @@ def coefficient_gg_b2_m(
|
|
|
392
514
|
for pq in pq_index:
|
|
393
515
|
p, q = pq[0], pq[1]
|
|
394
516
|
lmax = 2 * (p + q + 1)
|
|
395
|
-
for
|
|
517
|
+
for ell in range(0, lmax + 1, 2):
|
|
396
518
|
if hankel:
|
|
397
519
|
correlation = compute_correlation_coefficient_hankel(
|
|
398
|
-
p, q,
|
|
520
|
+
p, q, ell, coord[0], wavenumber_mm, power_spectrum_mm
|
|
399
521
|
)
|
|
400
522
|
else:
|
|
401
523
|
correlation = compute_correlation_coefficient_simple_integration(
|
|
402
|
-
p, q,
|
|
524
|
+
p, q, ell, coord[0], wavenumber_mm, power_spectrum_mm
|
|
403
525
|
)
|
|
404
|
-
h_function = eval(f"h_terms.H_gg_l{
|
|
526
|
+
h_function = eval(f"h_terms.H_gg_l{ell}_p{p}_q{q}")(coord[1], coord[2])
|
|
405
527
|
coeff = (
|
|
406
|
-
np.real(1j ** (
|
|
528
|
+
np.real(1j ** (ell))
|
|
407
529
|
* ((-1) ** (p + q))
|
|
408
530
|
/ (2 ** (p + q) * factorial(p) * factorial(q))
|
|
409
531
|
)
|
|
@@ -420,23 +542,30 @@ def coefficient_gg_f2_m(
|
|
|
420
542
|
coord,
|
|
421
543
|
hankel=True,
|
|
422
544
|
):
|
|
545
|
+
"""f² coefficient for gg block at fixed m.
|
|
546
|
+
|
|
547
|
+
Args mirror those of ``coefficient_gg_b2_m`` but using P_tt and h-terms shifted by +1.
|
|
548
|
+
|
|
549
|
+
Returns:
|
|
550
|
+
Scalar contribution for the given separation.
|
|
551
|
+
"""
|
|
423
552
|
result = 0
|
|
424
553
|
pq_index = iter_pq[sum_iter_pq == m_value]
|
|
425
554
|
for pq in pq_index:
|
|
426
555
|
p, q = pq[0], pq[1]
|
|
427
556
|
lmax = 2 * (p + q + 1)
|
|
428
|
-
for
|
|
557
|
+
for ell in range(0, lmax + 1, 2):
|
|
429
558
|
if hankel:
|
|
430
559
|
correlation = compute_correlation_coefficient_hankel(
|
|
431
|
-
p, q,
|
|
560
|
+
p, q, ell, coord[0], wavenumber_tt, power_spectrum_tt
|
|
432
561
|
)
|
|
433
562
|
else:
|
|
434
563
|
correlation = compute_correlation_coefficient_simple_integration(
|
|
435
|
-
p, q,
|
|
564
|
+
p, q, ell, coord[0], wavenumber_tt, power_spectrum_tt
|
|
436
565
|
)
|
|
437
|
-
h_function = eval(f"h_terms.H_gg_l{
|
|
566
|
+
h_function = eval(f"h_terms.H_gg_l{ell}_p{p+1}_q{q+1}")(coord[1], coord[2])
|
|
438
567
|
coeff = (
|
|
439
|
-
np.real(1j ** (
|
|
568
|
+
np.real(1j ** (ell))
|
|
440
569
|
* ((-1) ** (p + q))
|
|
441
570
|
/ (2 ** (p + q) * factorial(p) * factorial(q))
|
|
442
571
|
)
|
|
@@ -453,25 +582,34 @@ def coefficient_gg_bf_m(
|
|
|
453
582
|
coord,
|
|
454
583
|
hankel=True,
|
|
455
584
|
):
|
|
585
|
+
"""bf cross coefficient for gg block at fixed m.
|
|
586
|
+
|
|
587
|
+
Combines the two h-terms with indices (p+1,q) and (p,q+1).
|
|
588
|
+
|
|
589
|
+
Args mirror those of ``coefficient_gg_b2_m`` but using P_mt.
|
|
590
|
+
|
|
591
|
+
Returns:
|
|
592
|
+
Scalar contribution for the given separation.
|
|
593
|
+
"""
|
|
456
594
|
result = 0
|
|
457
595
|
pq_index = iter_pq[sum_iter_pq == m_value]
|
|
458
596
|
for pq in pq_index:
|
|
459
597
|
p, q = pq[0], pq[1]
|
|
460
598
|
lmax = 2 * (p + q + 1)
|
|
461
|
-
for
|
|
599
|
+
for ell in range(0, lmax + 1, 2):
|
|
462
600
|
if hankel:
|
|
463
601
|
correlation = compute_correlation_coefficient_hankel(
|
|
464
|
-
p, q,
|
|
602
|
+
p, q, ell, coord[0], wavenumber_mt, power_spectrum_mt
|
|
465
603
|
)
|
|
466
604
|
else:
|
|
467
605
|
correlation = compute_correlation_coefficient_simple_integration(
|
|
468
|
-
p, q,
|
|
606
|
+
p, q, ell, coord[0], wavenumber_mt, power_spectrum_mt
|
|
469
607
|
)
|
|
470
|
-
h_function = eval(f"h_terms.H_gg_l{
|
|
608
|
+
h_function = eval(f"h_terms.H_gg_l{ell}_p{p+1}_q{q}")(
|
|
471
609
|
coord[1], coord[2]
|
|
472
|
-
) + eval(f"h_terms.H_gg_l{
|
|
610
|
+
) + eval(f"h_terms.H_gg_l{ell}_p{p}_q{q+1}")(coord[1], coord[2])
|
|
473
611
|
coeff = (
|
|
474
|
-
np.real(1j ** (
|
|
612
|
+
np.real(1j ** (ell))
|
|
475
613
|
* ((-1) ** (p + q))
|
|
476
614
|
/ (2 ** (p + q) * factorial(p) * factorial(q))
|
|
477
615
|
)
|
|
@@ -499,6 +637,23 @@ def compute_cov_gv(
|
|
|
499
637
|
hankel=True,
|
|
500
638
|
los_definition="bisector",
|
|
501
639
|
):
|
|
640
|
+
"""Compute density-velocity covariance terms for Lai22 wide-angle.
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
pmax: Maximum p index.
|
|
644
|
+
ra_g, dec_g, comoving_distance_g: Galaxy coordinates and distances.
|
|
645
|
+
ra_v, dec_v, comoving_distance_v: Velocity coordinates and distances.
|
|
646
|
+
wavenumber_mt, wavenumber_tt: Wavenumbers for cross and velocity spectra.
|
|
647
|
+
power_spectrum_mt, power_spectrum_tt: Corresponding spectra values.
|
|
648
|
+
grid_window_m_mt, grid_window_v_mt, grid_window_v_tt: Optional windows.
|
|
649
|
+
size_batch: Batch size.
|
|
650
|
+
number_worker: Number of workers.
|
|
651
|
+
hankel: Use Hankel acceleration when True.
|
|
652
|
+
los_definition: Line-of-sight definition.
|
|
653
|
+
|
|
654
|
+
Returns:
|
|
655
|
+
Tuple ``(m_index, cov_gv_f2, cov_gv_bf)`` with lists of flattened covariance vectors.
|
|
656
|
+
"""
|
|
502
657
|
if grid_window_m_mt is not None:
|
|
503
658
|
power_spectrum_mt = power_spectrum_mt * grid_window_m_mt
|
|
504
659
|
|
|
@@ -597,19 +752,31 @@ def coefficient_gv_f2_p(
|
|
|
597
752
|
coord,
|
|
598
753
|
hankel=True,
|
|
599
754
|
):
|
|
755
|
+
"""f² coefficient for gv block at fixed p.
|
|
756
|
+
|
|
757
|
+
Args:
|
|
758
|
+
wavenumber_tt: Wavenumbers for P_tt.
|
|
759
|
+
power_spectrum_tt: P_tt values.
|
|
760
|
+
p: p index.
|
|
761
|
+
coord: Separation coordinates ``(r, theta, phi)``.
|
|
762
|
+
hankel: Use Hankel acceleration when True.
|
|
763
|
+
|
|
764
|
+
Returns:
|
|
765
|
+
Scalar contribution for the given separation.
|
|
766
|
+
"""
|
|
600
767
|
result = 0
|
|
601
768
|
lmax = 2 * (p + 1)
|
|
602
|
-
for
|
|
769
|
+
for ell in range(1, lmax + 1, 2):
|
|
603
770
|
if hankel:
|
|
604
771
|
correlation = compute_correlation_coefficient_hankel(
|
|
605
|
-
p, -0.5,
|
|
772
|
+
p, -0.5, ell, coord[0], wavenumber_tt, power_spectrum_tt
|
|
606
773
|
)
|
|
607
774
|
else:
|
|
608
775
|
correlation = compute_correlation_coefficient_simple_integration(
|
|
609
|
-
p, -0.5,
|
|
776
|
+
p, -0.5, ell, coord[0], wavenumber_tt, power_spectrum_tt
|
|
610
777
|
)
|
|
611
|
-
h_function = eval(f"h_terms.H_gv_l{
|
|
612
|
-
coeff = np.real(1j ** (
|
|
778
|
+
h_function = eval(f"h_terms.H_gv_l{ell}_p{p+1}")(coord[1], coord[2])
|
|
779
|
+
coeff = np.real(1j ** (ell + 1)) * ((-1) ** p) / (2**p * factorial(p))
|
|
613
780
|
result = result + coeff * correlation * h_function
|
|
614
781
|
return result
|
|
615
782
|
|
|
@@ -621,24 +788,39 @@ def coefficient_gv_bf_p(
|
|
|
621
788
|
coord,
|
|
622
789
|
hankel=True,
|
|
623
790
|
):
|
|
791
|
+
"""bf cross coefficient for gv block at fixed p.
|
|
792
|
+
|
|
793
|
+
Args mirror those of ``coefficient_gv_f2_p`` but using P_mt and different h-term.
|
|
794
|
+
|
|
795
|
+
Returns:
|
|
796
|
+
Scalar contribution for the given separation.
|
|
797
|
+
"""
|
|
624
798
|
result = 0
|
|
625
799
|
lmax = 2 * (p + 1)
|
|
626
|
-
for
|
|
800
|
+
for ell in range(1, lmax + 1, 2):
|
|
627
801
|
if hankel:
|
|
628
802
|
correlation = compute_correlation_coefficient_hankel(
|
|
629
|
-
p, -0.5,
|
|
803
|
+
p, -0.5, ell, coord[0], wavenumber_mt, power_spectrum_mt
|
|
630
804
|
)
|
|
631
805
|
else:
|
|
632
806
|
correlation = compute_correlation_coefficient_simple_integration(
|
|
633
|
-
p, -0.5,
|
|
807
|
+
p, -0.5, ell, coord[0], wavenumber_mt, power_spectrum_mt
|
|
634
808
|
)
|
|
635
|
-
h_function = eval(f"h_terms.H_gv_l{
|
|
636
|
-
coeff = np.real(1j ** (
|
|
809
|
+
h_function = eval(f"h_terms.H_gv_l{ell}_p{p}")(coord[1], coord[2])
|
|
810
|
+
coeff = np.real(1j ** (ell + 1)) * ((-1) ** p) / (2**p * factorial(p))
|
|
637
811
|
result = result + coeff * correlation * h_function
|
|
638
812
|
return result
|
|
639
813
|
|
|
640
814
|
|
|
641
815
|
def return_matrix_covariance(cov):
|
|
816
|
+
"""Convert flattened covariance vector (variance + upper triangle) to matrix.
|
|
817
|
+
|
|
818
|
+
Args:
|
|
819
|
+
cov: 1D array with diagonal at index 0 and upper-triangle entries following.
|
|
820
|
+
|
|
821
|
+
Returns:
|
|
822
|
+
Square covariance matrix reconstructed from the flattened representation.
|
|
823
|
+
"""
|
|
642
824
|
variance_val = cov[0]
|
|
643
825
|
|
|
644
826
|
non_diagonal_cov = np.delete(cov, 0)
|
|
@@ -656,6 +838,14 @@ def return_matrix_covariance(cov):
|
|
|
656
838
|
|
|
657
839
|
|
|
658
840
|
def return_correlation_matrix(cov):
|
|
841
|
+
"""Compute correlation matrix from covariance matrix.
|
|
842
|
+
|
|
843
|
+
Args:
|
|
844
|
+
cov: Square covariance matrix.
|
|
845
|
+
|
|
846
|
+
Returns:
|
|
847
|
+
Correlation matrix with unit diagonal.
|
|
848
|
+
"""
|
|
659
849
|
sigma = np.sqrt(np.diag(cov))
|
|
660
850
|
corr_matrix = cov / np.outer(sigma, sigma)
|
|
661
851
|
return corr_matrix
|
|
@@ -687,6 +877,24 @@ def compute_all_matrices(
|
|
|
687
877
|
number_worker=1,
|
|
688
878
|
hankel=True,
|
|
689
879
|
):
|
|
880
|
+
"""Compute all Lai22 covariance blocks and assemble matrices.
|
|
881
|
+
|
|
882
|
+
Args:
|
|
883
|
+
ra_density, dec_density, rcom_density: Galaxy coordinates and distances.
|
|
884
|
+
ra_vel, dec_vel, rcom_vel: Velocity coordinates and distances.
|
|
885
|
+
wavenumber_mm, wavenumber_mt, wavenumber_tt: Wavenumber grids.
|
|
886
|
+
power_spectrum_gg_mm, power_spectrum_gg_mt, power_spectrum_gg_tt: Spectra for gg terms.
|
|
887
|
+
power_spectrum_gv_mt, power_spectrum_gv_tt: Spectra for gv terms.
|
|
888
|
+
power_spectrum_vv_tt: Spectrum for vv term.
|
|
889
|
+
grid_window_*: Optional window functions.
|
|
890
|
+
pmax, qmax: Max indices for expansions.
|
|
891
|
+
size_batch: Batch size.
|
|
892
|
+
number_worker: Parallel workers.
|
|
893
|
+
hankel: Use Hankel acceleration when True.
|
|
894
|
+
|
|
895
|
+
Returns:
|
|
896
|
+
Tuple of matrices and indices: ``(cov_gg_b2_m, cov_gg_bf_m, cov_gg_f2_m, m_index_gg, cov_gv_bf_m, cov_gv_f2_m, m_index_gv, cov_vv)``.
|
|
897
|
+
"""
|
|
690
898
|
m_index_gg, cov_gg_b2, cov_gg_f2, cov_gg_bf = compute_cov_gg(
|
|
691
899
|
pmax,
|
|
692
900
|
qmax,
|
|
@@ -780,22 +988,21 @@ def generate_covariance(
|
|
|
780
988
|
qmax=3,
|
|
781
989
|
**kwargs,
|
|
782
990
|
):
|
|
783
|
-
"""
|
|
784
|
-
|
|
991
|
+
"""Generate Lai22 covariance blocks for requested model kind.
|
|
992
|
+
|
|
993
|
+
Wide-angle definition follows the bisector as in Lai et al. (2022).
|
|
785
994
|
|
|
786
995
|
Args:
|
|
787
|
-
model_kind:
|
|
788
|
-
power_spectrum_dict:
|
|
789
|
-
coordinates_velocity:
|
|
790
|
-
coordinates_density:
|
|
791
|
-
pmax:
|
|
792
|
-
qmax:
|
|
793
|
-
|
|
794
|
-
**kwargs: Pass keyword arguments to the function
|
|
795
|
-
: Define the model type
|
|
996
|
+
model_kind: One of ``"density"``, ``"velocity"``, ``"full"``, ``"density_velocity"`` indicating which blocks to compute.
|
|
997
|
+
power_spectrum_dict: Dict containing required spectra for gg/gv/vv blocks.
|
|
998
|
+
coordinates_velocity: Tuple ``(ra, dec, rcom)`` for velocity tracers.
|
|
999
|
+
coordinates_density: Tuple ``(ra, dec, rcom)`` for density tracers.
|
|
1000
|
+
pmax: Maximum p index.
|
|
1001
|
+
qmax: Maximum q index.
|
|
1002
|
+
**kwargs: Extra options forwarded to lower-level functions (e.g., windowing, batching, hankel).
|
|
796
1003
|
|
|
797
1004
|
Returns:
|
|
798
|
-
|
|
1005
|
+
Tuple ``(covariance_dict, number_densities, number_velocities, los_definition)``.
|
|
799
1006
|
"""
|
|
800
1007
|
|
|
801
1008
|
los_definition = "bisector"
|
|
@@ -858,11 +1065,9 @@ def generate_covariance(
|
|
|
858
1065
|
**kwargs,
|
|
859
1066
|
)
|
|
860
1067
|
|
|
861
|
-
redshift_dict = None
|
|
862
1068
|
return (
|
|
863
1069
|
covariance_dict,
|
|
864
1070
|
number_densities,
|
|
865
1071
|
number_velocities,
|
|
866
1072
|
los_definition,
|
|
867
|
-
redshift_dict,
|
|
868
1073
|
)
|
|
@@ -8,9 +8,17 @@ from sympy.simplify.fu import TR8
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def simplify_h(H, max_simplification=20):
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
"""Iteratively simplify a symbolic expression for H terms.
|
|
12
|
+
|
|
13
|
+
Applies ``TR8`` and factoring repeatedly up to ``max_simplification`` times
|
|
14
|
+
or until convergence. See SymPy docs on simplification strategies.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
H: SymPy expression representing an H term.
|
|
18
|
+
max_simplification: Maximum number of iterations to apply.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Simplified SymPy expression.
|
|
14
22
|
"""
|
|
15
23
|
H_simplified = sy.factor(TR8(H))
|
|
16
24
|
i = 0
|
|
@@ -20,7 +28,20 @@ def simplify_h(H, max_simplification=20):
|
|
|
20
28
|
return H_simplified
|
|
21
29
|
|
|
22
30
|
|
|
23
|
-
def generate_h_term(
|
|
31
|
+
def generate_h_term(ell, p, q):
|
|
32
|
+
"""Generate the H term for Lai22 wide-angle coefficients.
|
|
33
|
+
|
|
34
|
+
Constructs the angular function ``H_{ℓ}^{p,q}(θ,ϕ)`` using Gaunt integrals
|
|
35
|
+
and Legendre polynomials, then simplifies the symbolic result.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
ell: Multipole order ℓ (integer).
|
|
39
|
+
p: Half-integer or integer index for point 1 (interpreted as rational).
|
|
40
|
+
q: Half-integer or integer index for point 2 (interpreted as rational).
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
SymPy expression of ``H(θ, ϕ)``.
|
|
44
|
+
"""
|
|
24
45
|
theta, phi = sy.symbols("theta phi")
|
|
25
46
|
mu = sy.symbols("mu")
|
|
26
47
|
l1max = int(2 * p + 1)
|
|
@@ -50,12 +71,12 @@ def generate_h_term(l, p, q):
|
|
|
50
71
|
|
|
51
72
|
h_sum = 0
|
|
52
73
|
|
|
53
|
-
for m in range(-
|
|
74
|
+
for m in range(-ell, ell + 1):
|
|
54
75
|
for m1 in range(-l1, l1 + 1):
|
|
55
76
|
for m2 in range(-l2, l2 + 1):
|
|
56
|
-
sum_term = wigner.gaunt(
|
|
77
|
+
sum_term = wigner.gaunt(ell, l1, l2, m, m1, m2)
|
|
57
78
|
sum_term *= (
|
|
58
|
-
sy.Ynm(
|
|
79
|
+
sy.Ynm(ell, m, sy.pi - phi, 0)
|
|
59
80
|
* sy.Ynm(l1, m1, theta / 2, 0)
|
|
60
81
|
* sy.Ynm(l2, m2, theta / 2, sy.pi)
|
|
61
82
|
)
|
|
@@ -68,12 +89,27 @@ def generate_h_term(l, p, q):
|
|
|
68
89
|
|
|
69
90
|
|
|
70
91
|
def write_h_terms(pmax, qmax, filename="./h_terms.py", number_worker=1):
|
|
92
|
+
"""Generate and write H-term Python functions to a file.
|
|
93
|
+
|
|
94
|
+
Produces three sets of functions: gg with even ℓ up to ``2(p+q+1)``, gv with
|
|
95
|
+
odd ℓ up to ``2(p+1)``, and vv with even ℓ up to 2. The functions are
|
|
96
|
+
emitted as NumPy-evaluable code via ``pycode``.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
pmax: Maximum p index.
|
|
100
|
+
qmax: Maximum q index.
|
|
101
|
+
filename: Output Python file path for the generated H-term functions.
|
|
102
|
+
number_worker: Number of workers for parallel generation.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
None. Writes functions to ``filename``.
|
|
106
|
+
"""
|
|
71
107
|
params_pool = []
|
|
72
108
|
for p in range(pmax + 1):
|
|
73
109
|
for q in range(qmax + 1):
|
|
74
110
|
lmax = 2 * (p + q + 1)
|
|
75
|
-
for
|
|
76
|
-
params_pool.append([
|
|
111
|
+
for ell in range(0, lmax + 1, 2):
|
|
112
|
+
params_pool.append([ell, p, q])
|
|
77
113
|
|
|
78
114
|
if number_worker == 1:
|
|
79
115
|
output_H_gg = [generate_h_term(*param) for param in params_pool]
|
|
@@ -84,8 +120,8 @@ def write_h_terms(pmax, qmax, filename="./h_terms.py", number_worker=1):
|
|
|
84
120
|
params_pool = []
|
|
85
121
|
for p in range(pmax + 1):
|
|
86
122
|
lmax = 2 * (p + 1)
|
|
87
|
-
for
|
|
88
|
-
params_pool.append([
|
|
123
|
+
for ell in range(1, lmax + 1, 2):
|
|
124
|
+
params_pool.append([ell, p, 1 / 2])
|
|
89
125
|
|
|
90
126
|
if number_worker == 1:
|
|
91
127
|
output_H_gv = [generate_h_term(*param) for param in params_pool]
|
|
@@ -95,8 +131,8 @@ def write_h_terms(pmax, qmax, filename="./h_terms.py", number_worker=1):
|
|
|
95
131
|
|
|
96
132
|
params_pool = []
|
|
97
133
|
lmax = 2
|
|
98
|
-
for
|
|
99
|
-
params_pool.append([
|
|
134
|
+
for ell in range(0, lmax + 1, 2):
|
|
135
|
+
params_pool.append([ell, 1 / 2, 1 / 2])
|
|
100
136
|
|
|
101
137
|
if number_worker == 1:
|
|
102
138
|
output_H_vv = [generate_h_term(*param) for param in params_pool]
|
|
@@ -114,10 +150,10 @@ def write_h_terms(pmax, qmax, filename="./h_terms.py", number_worker=1):
|
|
|
114
150
|
for p in range(pmax + 1):
|
|
115
151
|
for q in range(qmax + 1):
|
|
116
152
|
lmax = 2 * (p + q + 1)
|
|
117
|
-
for
|
|
153
|
+
for ell in range(0, lmax + 1, 2):
|
|
118
154
|
H_txt = pycode(output_H_gg[i]).replace("math.", "np.")
|
|
119
155
|
i = i + 1
|
|
120
|
-
f.write(f"def H_gg_l{
|
|
156
|
+
f.write(f"def H_gg_l{ell}_p{p}_q{q}(theta,phi):\n")
|
|
121
157
|
f.write(f" return({H_txt})\n")
|
|
122
158
|
f.write("\n")
|
|
123
159
|
|
|
@@ -126,10 +162,10 @@ def write_h_terms(pmax, qmax, filename="./h_terms.py", number_worker=1):
|
|
|
126
162
|
i = 0
|
|
127
163
|
for p in range(pmax + 1):
|
|
128
164
|
lmax = 2 * (p + 1)
|
|
129
|
-
for
|
|
165
|
+
for ell in range(1, lmax + 1, 2):
|
|
130
166
|
H_txt = pycode(output_H_gv[i]).replace("math.", "np.")
|
|
131
167
|
i = i + 1
|
|
132
|
-
f.write(f"def H_gv_l{
|
|
168
|
+
f.write(f"def H_gv_l{ell}_p{p}(theta,phi):\n")
|
|
133
169
|
f.write(f" return({H_txt})\n")
|
|
134
170
|
f.write("\n")
|
|
135
171
|
|
|
@@ -137,10 +173,10 @@ def write_h_terms(pmax, qmax, filename="./h_terms.py", number_worker=1):
|
|
|
137
173
|
f.write("# Velocity-Velocity \n")
|
|
138
174
|
lmax = 2
|
|
139
175
|
i = 0
|
|
140
|
-
for
|
|
176
|
+
for ell in range(0, lmax + 1, 2):
|
|
141
177
|
H_txt = pycode(output_H_vv[i]).replace("math.", "np.")
|
|
142
178
|
i = i + 1
|
|
143
|
-
f.write(f"def H_vv_l{
|
|
179
|
+
f.write(f"def H_vv_l{ell}(theta,phi):\n")
|
|
144
180
|
f.write(f" return({H_txt})\n")
|
|
145
181
|
f.write("\n")
|
|
146
182
|
|