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.
Files changed (113) hide show
  1. docs/conf.py +154 -0
  2. flip/__init__.py +4 -11
  3. flip/covariance/__init__.py +7 -8
  4. flip/covariance/analytical/__init__.py +11 -0
  5. flip/covariance/{adamsblake17plane → analytical/adamsblake17}/coefficients.py +1 -1
  6. flip/covariance/{adamsblake17plane → analytical/adamsblake17}/fisher_terms.py +1 -1
  7. flip/covariance/{adamsblake17 → analytical/adamsblake17}/flip_terms.py +0 -1
  8. flip/covariance/{adamsblake17 → analytical/adamsblake17plane}/coefficients.py +1 -1
  9. flip/covariance/{adamsblake17 → analytical/adamsblake17plane}/fisher_terms.py +1 -1
  10. flip/covariance/{adamsblake17plane → analytical/adamsblake17plane}/flip_terms.py +0 -1
  11. flip/covariance/{adamsblake17plane → analytical/adamsblake17plane}/generator.py +103 -19
  12. flip/covariance/{adamsblake20 → analytical/adamsblake20}/coefficients.py +1 -1
  13. flip/covariance/{adamsblake20 → analytical/adamsblake20}/fisher_terms.py +1 -1
  14. flip/covariance/{adamsblake20 → analytical/adamsblake20}/flip_terms.py +0 -1
  15. flip/covariance/{carreres23 → analytical/carreres23}/coefficients.py +1 -4
  16. flip/covariance/{ravouxnoanchor25 → analytical/carreres23}/fisher_terms.py +1 -1
  17. flip/covariance/{carreres23 → analytical/carreres23}/flip_terms.py +0 -1
  18. flip/covariance/analytical/carreres23/generator.py +198 -0
  19. flip/covariance/analytical/genericzdep/__init__.py +5 -0
  20. flip/covariance/analytical/genericzdep/coefficients.py +53 -0
  21. flip/covariance/analytical/genericzdep/flip_terms.py +99 -0
  22. flip/covariance/{lai22 → analytical/lai22}/coefficients.py +2 -3
  23. flip/covariance/{lai22 → analytical/lai22}/fisher_terms.py +1 -1
  24. flip/covariance/{lai22 → analytical/lai22}/flip_terms.py +0 -1
  25. flip/covariance/{lai22 → analytical/lai22}/generator.py +263 -58
  26. flip/covariance/{lai22 → analytical/lai22}/symbolic.py +55 -19
  27. flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/coefficients.py +1 -1
  28. flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/fisher_terms.py +1 -1
  29. flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/flip_terms.py +0 -1
  30. flip/covariance/{ravouxnoanchor25 → analytical/ravouxnoanchor25}/coefficients.py +3 -2
  31. flip/covariance/{carreres23 → analytical/ravouxnoanchor25}/fisher_terms.py +1 -1
  32. flip/covariance/{ravouxnoanchor25 → analytical/ravouxnoanchor25}/flip_terms.py +0 -9
  33. flip/covariance/{rcrk24 → analytical/rcrk24}/coefficients.py +6 -6
  34. flip/covariance/{rcrk24 → analytical/rcrk24}/fisher_terms.py +7 -9
  35. flip/covariance/{rcrk24 → analytical/rcrk24}/flip_terms.py +0 -8
  36. flip/covariance/contraction.py +82 -40
  37. flip/covariance/cov_utils.py +89 -81
  38. flip/covariance/covariance.py +172 -141
  39. flip/covariance/emulators/__init__.py +1 -1
  40. flip/covariance/emulators/generator.py +73 -3
  41. flip/covariance/emulators/gpmatrix.py +40 -1
  42. flip/covariance/emulators/nnmatrix.py +57 -1
  43. flip/covariance/emulators/skgpmatrix.py +125 -0
  44. flip/covariance/fisher.py +307 -0
  45. flip/{fit_utils.py → covariance/fit_utils.py} +185 -10
  46. flip/{fitter.py → covariance/fitter.py} +151 -125
  47. flip/covariance/generator.py +82 -106
  48. flip/{likelihood.py → covariance/likelihood.py} +286 -64
  49. flip/{plot_utils.py → covariance/plot_utils.py} +79 -4
  50. flip/covariance/symbolic.py +89 -44
  51. flip/data/__init__.py +1 -1
  52. flip/data/data_density.parquet +0 -0
  53. flip/data/data_velocity.parquet +0 -0
  54. flip/data/{grid_window_m.parquet → data_window_density.parquet} +0 -0
  55. flip/{gridding.py → data/gridding.py} +125 -130
  56. flip/data/load_data_test.py +102 -0
  57. flip/data/power_spectrum_mm.txt +2 -2
  58. flip/data/power_spectrum_mt.txt +2 -2
  59. flip/data/power_spectrum_tt.txt +2 -2
  60. flip/data/test_covariance_reference_values.json +145 -0
  61. flip/data/test_e2e_reference_values.json +14 -0
  62. flip/data_vector/basic.py +118 -101
  63. flip/data_vector/cosmo_utils.py +18 -0
  64. flip/data_vector/galaxypv_vectors.py +58 -94
  65. flip/data_vector/snia_vectors.py +60 -3
  66. flip/data_vector/vector_utils.py +47 -1
  67. flip/power_spectra/class_engine.py +36 -1
  68. flip/power_spectra/cosmoprimo_engine.py +37 -2
  69. flip/power_spectra/generator.py +47 -25
  70. flip/power_spectra/models.py +30 -31
  71. flip/power_spectra/pyccl_engine.py +36 -1
  72. flip/simulation/__init__.py +0 -0
  73. flip/utils.py +62 -91
  74. flipcosmo-1.2.1.dist-info/METADATA +78 -0
  75. flipcosmo-1.2.1.dist-info/RECORD +109 -0
  76. {flipcosmo-1.0.0.dist-info → flipcosmo-1.2.1.dist-info}/WHEEL +1 -1
  77. flipcosmo-1.2.1.dist-info/top_level.txt +7 -0
  78. scripts/flip_compute_correlation_model.py +70 -0
  79. scripts/flip_compute_power_spectra.py +50 -0
  80. scripts/flip_fisher_forecast_velocity.py +70 -0
  81. scripts/flip_fisher_rcrk24.py +164 -0
  82. scripts/flip_launch_minuit_density_fit.py +91 -0
  83. scripts/flip_launch_minuit_full_fit.py +117 -0
  84. scripts/flip_launch_minuit_velocity_fit.py +78 -0
  85. scripts/flip_launch_minuit_velocity_fit_full.py +107 -0
  86. scripts/flip_launch_minuit_velocity_fit_interpolation.py +93 -0
  87. test/refresh_reference_values.py +43 -0
  88. test/test_covariance_assembly.py +102 -0
  89. test/test_covariance_reference_values.py +125 -0
  90. test/test_covariance_utils.py +34 -0
  91. test/test_e2e_density.py +50 -0
  92. test/test_e2e_joint.py +65 -0
  93. test/test_e2e_velocity.py +53 -0
  94. test/test_likelihood_inversions.py +31 -0
  95. flip/covariance/carreres23/generator.py +0 -132
  96. flip/data/density_data.parquet +0 -0
  97. flip/data/velocity_data.parquet +0 -0
  98. flip/fisher.py +0 -190
  99. flipcosmo-1.0.0.dist-info/METADATA +0 -32
  100. flipcosmo-1.0.0.dist-info/RECORD +0 -82
  101. flipcosmo-1.0.0.dist-info/top_level.txt +0 -1
  102. /flip/{config.py → _config.py} +0 -0
  103. /flip/covariance/{adamsblake17 → analytical/adamsblake17}/__init__.py +0 -0
  104. /flip/covariance/{adamsblake17plane → analytical/adamsblake17plane}/__init__.py +0 -0
  105. /flip/covariance/{adamsblake20 → analytical/adamsblake20}/__init__.py +0 -0
  106. /flip/covariance/{carreres23 → analytical/carreres23}/__init__.py +0 -0
  107. /flip/covariance/{lai22 → analytical/lai22}/__init__.py +0 -0
  108. /flip/covariance/{lai22 → analytical/lai22}/h_terms.py +0 -0
  109. /flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/__init__.py +0 -0
  110. /flip/covariance/{ravouxcarreres → analytical/ravouxcarreres}/flip_terms_lmax.py +0 -0
  111. /flip/covariance/{ravouxnoanchor25 → analytical/ravouxnoanchor25}/__init__.py +0 -0
  112. /flip/covariance/{rcrk24 → analytical/rcrk24}/__init__.py +0 -0
  113. {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, l, r, k, pk):
16
- """ " Here the sigma_u is added to pk later.
17
- The (2*np.pi**2) is added here in the Lai et al. formalism."""
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 = spherical_jn(l, kr).T * k**2 * k ** (2 * (p + q)) * pk / (2 * np.pi**2)
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, l, r, k, pk, hankel_overhead_coefficient=2
40
+ p, q, ell, r, k, pk, hankel_overhead_coefficient=2
25
41
  ):
26
- """Highly decrease time and memory consumption.
27
- Cosmoprimo prefactor is removed here
28
- When r is too small for the hankel range, standard integration is used.
29
- To avoid edge effects when using hankel, the mask have an overhead
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=l, q=0, complex=False)
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, l, r[mask], k, pk
67
+ p, q, ell, r[mask], k, pk
39
68
  )
40
- output[~mask] = (-1) ** (l // 2) * interp1d(r_hankel, xi_hankel)(r[~mask])
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 l in [0, 2]:
153
+ for ell in [0, 2]:
97
154
  if hankel:
98
155
  correlation = compute_correlation_coefficient_hankel(
99
- -0.5, -0.5, l, coord[0], wavenumber, power_spectrum_tt
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, l, coord[0], wavenumber, power_spectrum_tt
160
+ -0.5, -0.5, ell, coord[0], wavenumber, power_spectrum_tt
104
161
  )
105
- h_function = eval(f"h_terms.H_vv_l{l}")(coord[1], coord[2])
106
- result = result + np.real(1j ** (l)) * correlation * h_function
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 l in range(0, lmax + 1, 2):
517
+ for ell in range(0, lmax + 1, 2):
396
518
  if hankel:
397
519
  correlation = compute_correlation_coefficient_hankel(
398
- p, q, l, coord[0], wavenumber_mm, power_spectrum_mm
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, l, coord[0], wavenumber_mm, power_spectrum_mm
524
+ p, q, ell, coord[0], wavenumber_mm, power_spectrum_mm
403
525
  )
404
- h_function = eval(f"h_terms.H_gg_l{l}_p{p}_q{q}")(coord[1], coord[2])
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 ** (l))
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 l in range(0, lmax + 1, 2):
557
+ for ell in range(0, lmax + 1, 2):
429
558
  if hankel:
430
559
  correlation = compute_correlation_coefficient_hankel(
431
- p, q, l, coord[0], wavenumber_tt, power_spectrum_tt
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, l, coord[0], wavenumber_tt, power_spectrum_tt
564
+ p, q, ell, coord[0], wavenumber_tt, power_spectrum_tt
436
565
  )
437
- h_function = eval(f"h_terms.H_gg_l{l}_p{p+1}_q{q+1}")(coord[1], coord[2])
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 ** (l))
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 l in range(0, lmax + 1, 2):
599
+ for ell in range(0, lmax + 1, 2):
462
600
  if hankel:
463
601
  correlation = compute_correlation_coefficient_hankel(
464
- p, q, l, coord[0], wavenumber_mt, power_spectrum_mt
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, l, coord[0], wavenumber_mt, power_spectrum_mt
606
+ p, q, ell, coord[0], wavenumber_mt, power_spectrum_mt
469
607
  )
470
- h_function = eval(f"h_terms.H_gg_l{l}_p{p+1}_q{q}")(
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{l}_p{p}_q{q+1}")(coord[1], coord[2])
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 ** (l))
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 l in range(1, lmax + 1, 2):
769
+ for ell in range(1, lmax + 1, 2):
603
770
  if hankel:
604
771
  correlation = compute_correlation_coefficient_hankel(
605
- p, -0.5, l, coord[0], wavenumber_tt, power_spectrum_tt
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, l, coord[0], wavenumber_tt, power_spectrum_tt
776
+ p, -0.5, ell, coord[0], wavenumber_tt, power_spectrum_tt
610
777
  )
611
- h_function = eval(f"h_terms.H_gv_l{l}_p{p+1}")(coord[1], coord[2])
612
- coeff = np.real(1j ** (l + 1)) * ((-1) ** p) / (2**p * factorial(p))
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 l in range(1, lmax + 1, 2):
800
+ for ell in range(1, lmax + 1, 2):
627
801
  if hankel:
628
802
  correlation = compute_correlation_coefficient_hankel(
629
- p, -0.5, l, coord[0], wavenumber_mt, power_spectrum_mt
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, l, coord[0], wavenumber_mt, power_spectrum_mt
807
+ p, -0.5, ell, coord[0], wavenumber_mt, power_spectrum_mt
634
808
  )
635
- h_function = eval(f"h_terms.H_gv_l{l}_p{p}")(coord[1], coord[2])
636
- coeff = np.real(1j ** (l + 1)) * ((-1) ** p) / (2**p * factorial(p))
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
- The generate_covariance function generates the covariance matrix for a given model type.
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: Determine which covariance matrices are computed
788
- power_spectrum_dict: Pass the power spectrum of the density and velocity fields
789
- coordinates_velocity: Pass the coordinates of the velocity field
790
- coordinates_density: Define the coordinates of the density field
791
- pmax: Set the maximum order of legendre polynomials used to compute the covariance matrix
792
- qmax: Set the maximum order of legendre polynomials used in the expansion
793
- Wide angle defined in Lai et al. 2022 by the bisector.
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
- A dictionary of covariance matrices, the number of density points and the number of velocity points
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
- """simplification tests with https://docs.sympy.org/latest/tutorials/intro-tutorial/simplification.html
12
- https://docs.sympy.org/latest/modules/simplify/simplify.html#ratsimpmodprime
13
- https://docs.sympy.org/dev/modules/simplify/fu.html#sympy.simplify.fu
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(l, p, q):
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(-l, l + 1):
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(l, l1, l2, m, m1, m2)
77
+ sum_term = wigner.gaunt(ell, l1, l2, m, m1, m2)
57
78
  sum_term *= (
58
- sy.Ynm(l, m, sy.pi - phi, 0)
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 l in range(0, lmax + 1, 2):
76
- params_pool.append([l, p, q])
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 l in range(1, lmax + 1, 2):
88
- params_pool.append([l, p, 1 / 2])
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 l in range(0, lmax + 1, 2):
99
- params_pool.append([l, 1 / 2, 1 / 2])
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 l in range(0, lmax + 1, 2):
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{l}_p{p}_q{q}(theta,phi):\n")
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 l in range(1, lmax + 1, 2):
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{l}_p{p}(theta,phi):\n")
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 l in range(0, lmax + 1, 2):
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{l}(theta,phi):\n")
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
 
@@ -2,7 +2,7 @@ def get_coefficients(
2
2
  parameter_values_dict,
3
3
  model_kind,
4
4
  variant=None,
5
- redshift_dict=None,
5
+ covariance_prefactor_dict=None,
6
6
  ):
7
7
  coefficients_dict = {}
8
8
  if model_kind in ["density", "full", "density_velocity"]:
@@ -5,7 +5,7 @@ def get_partial_derivative_coefficients(
5
5
  model_kind,
6
6
  parameter_values_dict,
7
7
  variant=None,
8
- redshift_dict=None,
8
+ covariance_prefactor_dict=None,
9
9
  ):
10
10
  if model_kind == "density":
11
11
  return get_partial_derivative_coefficients_density(