42 this->
m1 + other.
m1, this->
m2 + other.
m2, this->
M + other.
M
44 return sph_order_triplet;
48 return (this->
m1 == 0) && (this->
m2 == 0) && (this->
M == 0);
53 (this->
m1 + other.
m1 == 0) &&
54 (this->
m2 + other.
m2 == 0) &&
55 (this->
M + other.
M == 0);
64 int ell1,
int ell2,
int ELL,
int m1,
int m2,
int M
66 return double(2*ell1 + 1) * double(2*ell2 + 1) * double(2*ELL + 1)
78 "Specified three-point correlator multipole "
79 "vanishes identically owing to zero-valued Wigner 3-j symbol."
83 "Specified three-point correlator multipole "
84 "vanishes identically owing to zero-valued Wigner 3-j symbol.\n"
97 if (particles.
pdata ==
nullptr) {
107#if defined(__GNUC__) && !defined(__clang__)
108#pragma omp parallel for simd reduction(+:norm)
110#pragma omp parallel for reduction(+:norm)
113 for (
int pid = 0; pid < particles.
ntotal; pid++) {
114 norm += particles[pid].ws
115 * std::pow(particles[pid].nz, 2) * std::pow(particles[pid].wc, 3);
121 "Particle 'nz' values appear to be all zeros. "
122 "Check the input catalogue contains valid 'nz' field."
126 "Particle 'nz' values appear to be all zeros. "
127 "Check the input catalogue contains valid 'nz' field.\n"
131 double norm_factor = 1. / (alpha * norm);
139 MeshField catalogue_mesh(params,
false,
"`catalogue_mesh`");
144 norm_factor /= std::pow(alpha, 3);
157 double alpha,
int ell,
int m
159 double sn_data_real = 0., sn_data_imag = 0.;
162#pragma omp parallel for reduction(+:sn_data_real, sn_data_imag)
164 for (
int pid = 0; pid < particles_data.
ntotal; pid++) {
166 los_data[pid].
pos[0], los_data[pid].
pos[1], los_data[pid].
pos[2]
169 std::complex<double> ylm = trvm::SphericalHarmonicCalculator::
170 calc_reduced_spherical_harmonic(ell, m, los_);
172 std::complex<double> sn_part = ylm * std::pow(particles_data[pid].w, 3);
173 double sn_part_real = sn_part.real();
174 double sn_part_imag = sn_part.imag();
176 sn_data_real += sn_part_real;
177 sn_data_imag += sn_part_imag;
180 std::complex<double> sn_data(sn_data_real, sn_data_imag);
182 double sn_rand_real = 0., sn_rand_imag = 0.;
185#pragma omp parallel for reduction(+:sn_rand_real, sn_rand_imag)
187 for (
int pid = 0; pid < particles_rand.
ntotal; pid++) {
189 los_rand[pid].
pos[0], los_rand[pid].
pos[1], los_rand[pid].
pos[2]
192 std::complex<double> ylm = trvm::SphericalHarmonicCalculator::
193 calc_reduced_spherical_harmonic(ell, m, los_);
195 std::complex<double> sn_part = ylm * std::pow(particles_rand[pid].w, 3);
196 double sn_part_real = sn_part.real();
197 double sn_part_imag = sn_part.imag();
199 sn_rand_real += sn_part_real;
200 sn_rand_imag += sn_part_imag;
203 std::complex<double> sn_rand(sn_rand_real, sn_rand_imag);
205 return sn_data + std::pow(alpha, 3) * sn_rand;
210 double alpha,
int ell,
int m
212 double sn_real = 0., sn_imag = 0.;
215#pragma omp parallel for reduction(+:sn_real, sn_imag)
217 for (
int pid = 0; pid < particles.
ntotal; pid++) {
218 double los_[3] = {los[pid].
pos[0], los[pid].
pos[1], los[pid].
pos[2]};
220 std::complex<double> ylm = trvm::SphericalHarmonicCalculator::
221 calc_reduced_spherical_harmonic(ell, m, los_);
223 std::complex<double> sn_part = ylm * std::pow(particles[pid].w, 3);
224 double sn_part_real = sn_part.real();
225 double sn_part_imag = sn_part.imag();
227 sn_real += sn_part_real;
228 sn_imag += sn_part_imag;
231 std::complex<double> sn(sn_real, sn_imag);
233 return std::pow(alpha, 3) * sn;
256 "Computing bispectrum from paired survey-type catalogues..."
269 std::complex<double> factor_phase =
274 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
277 if (params.
shape ==
"off-diag") {
280 if (params.
shape ==
"full") {
283 if (params.
shape ==
"triu") {
288 "Three-point statistic form is not recognised: `form` = '%s'.",
293 "Three-point statistic form is not recognised: `form` = '%s'.\n",
298 int* nmodes1_dv =
new int[dv_dim];
299 int* nmodes2_dv =
new int[dv_dim];
300 double* k1bin_dv =
new double[dv_dim];
301 double* k2bin_dv =
new double[dv_dim];
302 double* k1eff_dv =
new double[dv_dim];
303 double* k2eff_dv =
new double[dv_dim];
304 std::complex<double>* bk_dv =
new std::complex<double>[dv_dim];
305 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
306 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
307 nmodes1_dv[idx_dv] = 0;
308 nmodes2_dv[idx_dv] = 0;
309 k1bin_dv[idx_dv] = 0.;
310 k2bin_dv[idx_dv] = 0.;
311 k1eff_dv[idx_dv] = 0.;
312 k2eff_dv[idx_dv] = 0.;
321#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
326 MeshField dn_00(params,
true,
"`dn_00`");
328 catalogue_data, catalogue_rand, los_data, los_rand, alpha, 0, 0
338 catalogue_data, catalogue_rand, los_data, los_rand, alpha, 0, 0
348 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
349 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
350 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
351 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
360 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
362 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
363 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
365 std::string flag_vanishing =
"true";
366 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
371 flag_vanishing =
"false";
375 if (flag_vanishing ==
"true") {
continue;}
377 trvm::SphericalHarmonicCalculator::
378 store_reduced_spherical_harmonic_in_fourier_space(
381 trvm::SphericalHarmonicCalculator::
382 store_reduced_spherical_harmonic_in_fourier_space(
385 trvm::SphericalHarmonicCalculator::
386 store_reduced_spherical_harmonic_in_config_space(
389 trvm::SphericalHarmonicCalculator::
390 store_reduced_spherical_harmonic_in_config_space(
394 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
398 std::string flag_redundant =
"false";
400 if (sph_order_current.
is_inverse(sph_order)) {
401 flag_redundant =
"true";
404 if (flag_redundant ==
"true") {
continue;}
422 double factor_mirror = sph_order_current.
is_zeros() ?
423 0. : std::pow(-1., params.
ELL);
424 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
434 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
441 MeshField F_lm_a(params,
true,
"`F_lm_a`");
442 MeshField F_lm_b(params,
true,
"`F_lm_b`");
444 if (params.
shape ==
"diag") {
445 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
448 double k_lower = kbinning.
bin_edges[ibin];
449 double k_upper = kbinning.
bin_edges[ibin + 1];
451 double k_eff_a_, k_eff_b_;
452 int nmodes_a_, nmodes_b_;
455 dn_00, ylm_k_a, k_lower, k_upper, k_eff_a_, nmodes_a_
458 dn_00, ylm_k_b, k_lower, k_upper, k_eff_b_, nmodes_b_
461 if (count_terms == 0) {
464 k1eff_dv[idx_dv] = k_eff_a_;
465 k2eff_dv[idx_dv] = k_eff_b_;
466 nmodes1_dv[idx_dv] = nmodes_a_;
467 nmodes2_dv[idx_dv] = nmodes_b_;
471 double bk_comp_real = 0., bk_comp_imag = 0.;
474#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
476 for (
long long gid = 0; gid < params.
nmesh; gid++) {
477 std::complex<double> F_lm_a_gridpt(
478 F_lm_a[gid][0], F_lm_a[gid][1]
480 std::complex<double> F_lm_b_gridpt(
481 F_lm_b[gid][0], F_lm_b[gid][1]
483 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
484 std::complex<double> bk_gridpt =
485 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
487 bk_comp_real += bk_gridpt.real();
488 bk_comp_imag += bk_gridpt.imag();
491 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
493 bk_dv[idx_dv] += coupling * vol_cell * (
494 bk_component + factor_mirror * std::conj(bk_component)
499 if (params.
shape ==
"off-diag") {
500 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
501 int ibin_row, ibin_col;
504 ibin_col = idx_dv + std::abs(params.
idx_bin);
506 ibin_row = idx_dv + std::abs(params.
idx_bin);
510 double k_lower_a = kbinning.
bin_edges[ibin_row];
511 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
512 double k_lower_b = kbinning.
bin_edges[ibin_col];
513 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
515 double k_eff_a_, k_eff_b_;
516 int nmodes_a_, nmodes_b_;
519 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
522 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
525 if (count_terms == 0) {
528 k1eff_dv[idx_dv] = k_eff_a_;
529 k2eff_dv[idx_dv] = k_eff_b_;
530 nmodes1_dv[idx_dv] = nmodes_a_;
531 nmodes2_dv[idx_dv] = nmodes_b_;
535 double bk_comp_real = 0., bk_comp_imag = 0.;
538#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
540 for (
long long gid = 0; gid < params.
nmesh; gid++) {
541 std::complex<double> F_lm_a_gridpt(
542 F_lm_a[gid][0], F_lm_a[gid][1]
544 std::complex<double> F_lm_b_gridpt(
545 F_lm_b[gid][0], F_lm_b[gid][1]
547 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
548 std::complex<double> bk_gridpt =
549 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
551 bk_comp_real += bk_gridpt.real();
552 bk_comp_imag += bk_gridpt.imag();
555 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
557 bk_dv[idx_dv] += coupling * vol_cell * (
558 bk_component + factor_mirror * std::conj(bk_component)
563 if (params.
shape ==
"row") {
566 double k_lower_a = kbinning.
bin_edges[ibin_row];
567 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
573 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
576 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
577 int ibin_col = idx_dv;
579 double k_lower_b = kbinning.
bin_edges[ibin_col];
580 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
586 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
589 if (count_terms == 0) {
592 k1eff_dv[idx_dv] = k_eff_a_;
593 k2eff_dv[idx_dv] = k_eff_b_;
594 nmodes1_dv[idx_dv] = nmodes_a_;
595 nmodes2_dv[idx_dv] = nmodes_b_;
599 double bk_comp_real = 0., bk_comp_imag = 0.;
602#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
604 for (
long long gid = 0; gid < params.
nmesh; gid++) {
605 std::complex<double> F_lm_a_gridpt(
606 F_lm_a[gid][0], F_lm_a[gid][1]
608 std::complex<double> F_lm_b_gridpt(
609 F_lm_b[gid][0], F_lm_b[gid][1]
611 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
612 std::complex<double> bk_gridpt =
613 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
615 bk_comp_real += bk_gridpt.real();
616 bk_comp_imag += bk_gridpt.imag();
619 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
621 bk_dv[idx_dv] += coupling * vol_cell * (
622 bk_component + factor_mirror * std::conj(bk_component)
627 if (params.
shape ==
"full") {
628 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
629 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
630 int idx_dv = idx_row * params.
num_bins + idx_col;
632 double k_lower_a = kbinning.
bin_edges[idx_row];
633 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
634 double k_lower_b = kbinning.
bin_edges[idx_col];
635 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
637 double k_eff_a_, k_eff_b_;
638 int nmodes_a_, nmodes_b_;
641 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
644 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
647 if (count_terms == 0) {
650 k1eff_dv[idx_dv] = k_eff_a_;
651 k2eff_dv[idx_dv] = k_eff_b_;
652 nmodes1_dv[idx_dv] = nmodes_a_;
653 nmodes2_dv[idx_dv] = nmodes_b_;
657 double bk_comp_real = 0., bk_comp_imag = 0.;
660#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
662 for (
long long gid = 0; gid < params.
nmesh; gid++) {
663 std::complex<double> F_lm_a_gridpt(
664 F_lm_a[gid][0], F_lm_a[gid][1]
666 std::complex<double> F_lm_b_gridpt(
667 F_lm_b[gid][0], F_lm_b[gid][1]
669 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
670 std::complex<double> bk_gridpt =
671 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
673 bk_comp_real += bk_gridpt.real();
674 bk_comp_imag += bk_gridpt.imag();
677 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
679 bk_dv[idx_dv] += coupling * vol_cell * (
680 bk_component + factor_mirror * std::conj(bk_component)
686 if (params.
shape ==
"triu") {
687 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
688 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
689 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
690 + (idx_col - idx_row);
692 double k_lower_a = kbinning.
bin_edges[idx_row];
693 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
694 double k_lower_b = kbinning.
bin_edges[idx_col];
695 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
697 double k_eff_a_, k_eff_b_;
698 int nmodes_a_, nmodes_b_;
701 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
704 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
707 if (count_terms == 0) {
710 k1eff_dv[idx_dv] = k_eff_a_;
711 k2eff_dv[idx_dv] = k_eff_b_;
712 nmodes1_dv[idx_dv] = nmodes_a_;
713 nmodes2_dv[idx_dv] = nmodes_b_;
717 double bk_comp_real = 0., bk_comp_imag = 0.;
720#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
722 for (
long long gid = 0; gid < params.
nmesh; gid++) {
723 std::complex<double> F_lm_a_gridpt(
724 F_lm_a[gid][0], F_lm_a[gid][1]
726 std::complex<double> F_lm_b_gridpt(
727 F_lm_b[gid][0], F_lm_b[gid][1]
729 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
730 std::complex<double> bk_gridpt =
731 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
733 bk_comp_real += bk_gridpt.real();
734 bk_comp_imag += bk_gridpt.imag();
737 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
739 bk_dv[idx_dv] += coupling * vol_cell * (
740 bk_component + factor_mirror * std::conj(bk_component)
751 MeshField dn_LM_for_sn(params,
true,
"`dn_LM_for_sn`");
755 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
762 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
768 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
772 if (params.
ell1 == 0 && params.
ell2 == 0) {
775 std::complex<double> S_ijk = coupling * Sbar_LM;
776 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
777 sn_dv[idx_dv] += S_ijk;
781 if (params.
ell2 == 0) {
784 dn_00_for_sn, N_LM, Sbar_LM, params.
ell1, m1_, kbinning
787 if (params.
shape ==
"diag") {
788 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
790 std::complex<double> S_i_jk = coupling * (
791 stats_sn.
pk[ibin] - stats_sn.
sn[ibin]
793 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
797 if (params.
shape ==
"off-diag") {
798 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
803 ibin_row = idx_dv + std::abs(params.
idx_bin);
805 std::complex<double> S_i_jk = coupling * (
806 stats_sn.
pk[ibin_row] - stats_sn.
sn[ibin_row]
808 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
812 if (params.
shape ==
"row") {
813 std::complex<double> S_i_jk_row_ = coupling * (
816 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
818 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
822 if (params.
shape ==
"full") {
823 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
824 std::complex<double> S_i_jk_row_ = coupling * (
825 stats_sn.
pk[idx_row] - stats_sn.
sn[idx_row]
827 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
828 int idx_dv = idx_row * params.
num_bins + idx_col;
830 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
835 if (params.
shape ==
"triu") {
836 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
837 std::complex<double> S_i_jk_row_ = coupling * (
838 stats_sn.
pk[idx_row] - stats_sn.
sn[idx_row]
840 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++)
842 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
843 + (idx_col - idx_row);
845 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
851 if (params.
ell1 == 0) {
854 dn_00_for_sn, N_LM, Sbar_LM, params.
ell2, m2_, kbinning
857 if (params.
shape ==
"diag") {
858 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
860 std::complex<double> S_ik_j_ki = coupling * (
861 stats_sn.
pk[ibin] - stats_sn.
sn[ibin]
864 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
868 if (params.
shape ==
"off-diag") {
869 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
872 ibin_col = idx_dv + params.
idx_bin;
876 std::complex<double> S_ik_j_ki = coupling * (
877 stats_sn.
pk[ibin_col] - stats_sn.
sn[ibin_col]
880 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
884 if (params.
shape ==
"row") {
885 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
886 int ibin_col = idx_dv;
887 std::complex<double> S_ik_j_ki = coupling * (
888 stats_sn.
pk[ibin_col] - stats_sn.
sn[ibin_col]
891 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
895 if (params.
shape ==
"full") {
896 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
897 std::complex<double> S_ik_j_ki_col_ = coupling * (
898 stats_sn.
pk[idx_col] - stats_sn.
sn[idx_col]
900 for (
int idx_row = 0; idx_row <= params.
num_bins; idx_row++) {
901 int idx_dv = idx_row * params.
num_bins + idx_col;
903 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
908 if (params.
shape ==
"triu") {
909 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
910 std::complex<double> S_ik_j_ki_col_ = coupling * (
911 stats_sn.
pk[idx_col] - stats_sn.
sn[idx_col]
913 for (
int idx_row = 0; idx_row <= idx_col; idx_row++) {
914 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
915 + (idx_col - idx_row);
917 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
923 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
924 double k_a = k1eff_dv[idx_dv];
925 double k_b = k2eff_dv[idx_dv];
927 std::complex<double> S_ij_k = coupling
929 dn_LM_for_sn, N_00, ylm_r_a, ylm_r_b, sj_a, sj_b,
933 sn_dv[idx_dv] += factor_phase * (
934 S_ij_k + factor_mirror_w3j * std::conj(S_ij_k)
938 sph_orders_computed.push_back(sph_order_current);
942 "Bispectrum term computed at orders (m₁, m₂, M) = ±(%d, %d, %d).",
955 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
956 bispec_out.
k1_bin.push_back(k1bin_dv[idx_dv]);
957 bispec_out.
k1_eff.push_back(k1eff_dv[idx_dv]);
958 bispec_out.
nmodes_1.push_back(nmodes1_dv[idx_dv]);
959 bispec_out.
k2_bin.push_back(k2bin_dv[idx_dv]);
960 bispec_out.
k2_eff.push_back(k2eff_dv[idx_dv]);
961 bispec_out.
nmodes_2.push_back(nmodes2_dv[idx_dv]);
962 bispec_out.
bk_raw.push_back(norm_factor * bk_dv[idx_dv]);
963 bispec_out.
bk_shot.push_back(norm_factor * sn_dv[idx_dv]);
965 bispec_out.
dim = dv_dim;
967 delete[] nmodes1_dv;
delete[] nmodes2_dv;
968 delete[] k1bin_dv;
delete[] k2bin_dv;
969 delete[] k1eff_dv;
delete[] k2eff_dv;
970 delete[] bk_dv;
delete[] sn_dv;
979 "... computed bispectrum from paired survey-type catalogues."
996 "Computing three-point correlation function "
997 "from paired survey-type catalogues..."
1010 std::complex<double> factor_phase =
1012 double factor_parity = std::pow(-1., params.
ell1 + params.
ell2);
1016 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
1019 if (params.
shape ==
"off-diag") {
1022 if (params.
shape ==
"full") {
1025 if (params.
shape ==
"triu") {
1030 "Three-point statistic form is not recognised: `form` = '%s'.",
1035 "Three-point statistic form is not recognised: `form` = '%s'.\n",
1040 int* npairs1_dv =
new int[dv_dim];
1041 int* npairs2_dv =
new int[dv_dim];
1042 double* r1bin_dv =
new double[dv_dim];
1043 double* r2bin_dv =
new double[dv_dim];
1044 double* r1eff_dv =
new double[dv_dim];
1045 double* r2eff_dv =
new double[dv_dim];
1046 std::complex<double>* zeta_dv =
new std::complex<double>[dv_dim];
1047 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
1048 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1049 npairs1_dv[idx_dv] = 0;
1050 npairs2_dv[idx_dv] = 0;
1051 r1bin_dv[idx_dv] = 0.;
1052 r2bin_dv[idx_dv] = 0.;
1053 r1eff_dv[idx_dv] = 0.;
1054 r2eff_dv[idx_dv] = 0.;
1055 zeta_dv[idx_dv] = 0.;
1063#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
1064 fftw_init_threads();
1068 MeshField dn_00(params,
true,
"`dn_00`");
1070 catalogue_data, catalogue_rand, los_data, los_rand, alpha, 0, 0
1078 catalogue_data, catalogue_rand, los_data, los_rand, alpha, 0, 0
1088 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
1089 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
1090 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
1091 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
1100 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
1101 int count_terms = 0;
1102 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
1103 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
1105 std::string flag_vanishing =
"true";
1106 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
1108 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
1111 flag_vanishing =
"false";
1115 if (flag_vanishing ==
"true") {
continue;}
1117 trvm::SphericalHarmonicCalculator::
1118 store_reduced_spherical_harmonic_in_config_space(
1121 trvm::SphericalHarmonicCalculator::
1122 store_reduced_spherical_harmonic_in_config_space(
1125 trvm::SphericalHarmonicCalculator::
1126 store_reduced_spherical_harmonic_in_fourier_space(
1129 trvm::SphericalHarmonicCalculator::
1130 store_reduced_spherical_harmonic_in_fourier_space(
1134 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
1138 std::string flag_redundant =
"false";
1140 if (sph_order_current.
is_inverse(sph_order)) {
1141 flag_redundant =
"true";
1144 if (flag_redundant ==
"true") {
continue;}
1148 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
1160 double factor_mirror = sph_order_current.
is_zeros() ?
1161 0. : std::pow(-1., params.
ELL);
1162 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
1170 MeshField dn_LM_for_sn(params,
true,
"`dn_LM_for_sn`");
1174 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
1180 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
1185 dn_LM_for_sn, N_00, ylm_r_a, ylm_r_b, Sbar_LM, rbinning
1189 if (params.
shape ==
"diag") {
1190 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1192 sn_dv[idx_dv] += coupling * factor_parity * (
1194 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
1199 if (params.
shape ==
"off-diag" && params.
idx_bin == 0) {
1201 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1203 sn_dv[idx_dv] += coupling * factor_parity * (
1205 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
1210 if (params.
shape ==
"row") {
1211 sn_dv[params.
idx_bin] += coupling * factor_parity * (
1213 + factor_mirror_w3j * std::conj(stats_sn.
xi[params.
idx_bin])
1217 if (params.
shape ==
"full") {
1218 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1220 int idx_dv = idx_row * params.
num_bins + idx_row;
1221 sn_dv[idx_dv] += coupling * factor_parity * (
1222 stats_sn.
xi[idx_row]
1223 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
1228 if (params.
shape ==
"triu") {
1229 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1231 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2;
1232 sn_dv[idx_dv] += coupling * factor_parity * (
1233 stats_sn.
xi[idx_row]
1234 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
1240 if (count_terms == 0) {
1241 if (params.
shape ==
"diag") {
1242 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1247 r1eff_dv[idx_dv] = stats_sn.
r[ibin];
1248 r2eff_dv[idx_dv] = stats_sn.
r[ibin];
1249 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin];
1250 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin];
1254 if (params.
shape ==
"off-diag") {
1255 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1256 int ibin_row, ibin_col;
1259 ibin_col = idx_dv + std::abs(params.
idx_bin);
1261 ibin_row = idx_dv + std::abs(params.
idx_bin);
1265 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
1266 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
1267 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
1268 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
1269 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
1270 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
1274 if (params.
shape ==
"row") {
1275 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1276 int ibin_row = params.
idx_bin;
1277 int ibin_col = idx_dv;
1279 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
1280 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
1281 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
1282 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
1283 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
1284 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
1288 if (params.
shape ==
"full") {
1289 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1290 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
1291 int idx_dv = idx_row * params.
num_bins + idx_col;
1295 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
1296 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
1297 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
1298 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
1303 if (params.
shape ==
"triu") {
1304 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1305 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++)
1307 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
1308 + (idx_col - idx_row);
1312 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
1313 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
1314 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
1315 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
1328 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
1335 MeshField F_lm_a(params,
true,
"`F_lm_a`");
1336 MeshField F_lm_b(params,
true,
"`F_lm_b`");
1338 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1339 double r_a = r1eff_dv[idx_dv];
1341 dn_00, ylm_k_a, sj_a, r_a
1344 double r_b = r2eff_dv[idx_dv];
1346 dn_00, ylm_k_b, sj_b, r_b
1350 double zeta_comp_real = 0., zeta_comp_imag = 0.;
1353#pragma omp parallel for reduction(+:zeta_comp_real, zeta_comp_imag)
1355 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1356 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
1357 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
1358 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
1359 std::complex<double> zeta_gridpt =
1360 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
1362 zeta_comp_real += zeta_gridpt.real();
1363 zeta_comp_imag += zeta_gridpt.imag();
1366 std::complex<double> zeta_component(zeta_comp_real, zeta_comp_imag);
1368 zeta_dv[idx_dv] += coupling * vol_cell * factor_phase * (
1369 zeta_component + factor_mirror * std::conj(zeta_component)
1373 sph_orders_computed.push_back(sph_order_current);
1377 "Three-point correlation function term computed at orders "
1378 "(m₁, m₂, M) = ±(%d, %d, %d).",
1391 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1392 threepcf_out.
r1_bin.push_back(r1bin_dv[idx_dv]);
1393 threepcf_out.
r1_eff.push_back(r1eff_dv[idx_dv]);
1394 threepcf_out.
npairs_1.push_back(npairs1_dv[idx_dv]);
1395 threepcf_out.
r2_bin.push_back(r2bin_dv[idx_dv]);
1396 threepcf_out.
r2_eff.push_back(r2eff_dv[idx_dv]);
1397 threepcf_out.
npairs_2.push_back(npairs2_dv[idx_dv]);
1398 threepcf_out.
zeta_raw.push_back(norm_factor * zeta_dv[idx_dv]);
1399 threepcf_out.
zeta_shot.push_back(norm_factor * sn_dv[idx_dv]);
1401 threepcf_out.
dim = dv_dim;
1403 delete[] npairs1_dv;
delete[] npairs2_dv;
1404 delete[] r1bin_dv;
delete[] r2bin_dv;
1405 delete[] r1eff_dv;
delete[] r2eff_dv;
1406 delete[] zeta_dv;
delete[] sn_dv;
1415 "... computed three-point correlation function "
1416 "from paired survey-type catalogues."
1420 return threepcf_out;
1432 "Computing bispectrum from a periodic-box simulation-type catalogue "
1433 "in the global plane-parallel approximation..."
1444 std::complex<double> factor_phase =
1449 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
1452 if (params.
shape ==
"off-diag") {
1455 if (params.
shape ==
"full") {
1458 if (params.
shape ==
"triu") {
1463 "Three-point statistic form is not recognised: `form` = '%s'.",
1468 "Three-point statistic form is not recognised: `form` = '%s'.\n",
1473 int* nmodes1_dv =
new int[dv_dim];
1474 int* nmodes2_dv =
new int[dv_dim];
1475 double* k1bin_dv =
new double[dv_dim];
1476 double* k2bin_dv =
new double[dv_dim];
1477 double* k1eff_dv =
new double[dv_dim];
1478 double* k2eff_dv =
new double[dv_dim];
1479 std::complex<double>* bk_dv =
new std::complex<double>[dv_dim];
1480 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
1481 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1482 nmodes1_dv[idx_dv] = 0;
1483 nmodes2_dv[idx_dv] = 0;
1484 k1bin_dv[idx_dv] = 0.;
1485 k2bin_dv[idx_dv] = 0.;
1486 k1eff_dv[idx_dv] = 0.;
1487 k2eff_dv[idx_dv] = 0.;
1496#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
1497 fftw_init_threads();
1501 MeshField dn_00(params,
true,
"`dn_00`");
1524 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
1525 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
1526 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
1527 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
1536 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
1537 int count_terms = 0;
1538 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
1539 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
1547 std::string flag_redundant =
"false";
1549 if (sph_order_current.
is_inverse(sph_order)) {
1550 flag_redundant =
"true";
1553 if (flag_redundant ==
"true") {
continue;}
1557 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
1571 double factor_mirror = sph_order_current.
is_zeros() ?
1572 0. : std::pow(-1., params.
ELL);
1573 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
1576 trvm::SphericalHarmonicCalculator::
1577 store_reduced_spherical_harmonic_in_fourier_space(
1580 trvm::SphericalHarmonicCalculator
1581 ::store_reduced_spherical_harmonic_in_fourier_space(
1584 trvm::SphericalHarmonicCalculator::
1585 store_reduced_spherical_harmonic_in_config_space(
1588 trvm::SphericalHarmonicCalculator::
1589 store_reduced_spherical_harmonic_in_config_space(
1603 MeshField F_lm_a(params,
true,
"`F_lm_a`");
1604 MeshField F_lm_b(params,
true,
"`F_lm_b`");
1606 if (params.
shape ==
"diag") {
1607 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1610 double k_lower = kbinning.
bin_edges[ibin];
1611 double k_upper = kbinning.
bin_edges[ibin + 1];
1613 double k_eff_a_, k_eff_b_;
1614 int nmodes_a_, nmodes_b_;
1617 dn_00, ylm_k_a, k_lower, k_upper, k_eff_a_, nmodes_a_
1620 dn_00, ylm_k_b, k_lower, k_upper, k_eff_b_, nmodes_b_
1623 if (count_terms == 0) {
1626 k1eff_dv[idx_dv] = k_eff_a_;
1627 k2eff_dv[idx_dv] = k_eff_b_;
1628 nmodes1_dv[idx_dv] = nmodes_a_;
1629 nmodes2_dv[idx_dv] = nmodes_b_;
1633 double bk_comp_real = 0., bk_comp_imag = 0.;
1636#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1638 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1639 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
1640 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
1641 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1642 std::complex<double> bk_gridpt =
1643 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1645 bk_comp_real += bk_gridpt.real();
1646 bk_comp_imag += bk_gridpt.imag();
1649 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1651 bk_dv[idx_dv] += coupling * vol_cell * (
1652 bk_component + factor_mirror * std::conj(bk_component)
1657 if (params.
shape ==
"off-diag") {
1658 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1659 int ibin_row, ibin_col;
1662 ibin_col = idx_dv + std::abs(params.
idx_bin);
1664 ibin_row = idx_dv + std::abs(params.
idx_bin);
1668 double k_lower_a = kbinning.
bin_edges[ibin_row];
1669 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
1670 double k_lower_b = kbinning.
bin_edges[ibin_col];
1671 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
1673 double k_eff_a_, k_eff_b_;
1674 int nmodes_a_, nmodes_b_;
1677 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
1680 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
1683 if (count_terms == 0) {
1684 k1bin_dv[idx_dv] = kbinning.
bin_centres[ibin_row];
1685 k2bin_dv[idx_dv] = kbinning.
bin_centres[ibin_col];
1686 k1eff_dv[idx_dv] = k_eff_a_;
1687 k2eff_dv[idx_dv] = k_eff_b_;
1688 nmodes1_dv[idx_dv] = nmodes_a_;
1689 nmodes2_dv[idx_dv] = nmodes_b_;
1693 double bk_comp_real = 0., bk_comp_imag = 0.;
1696#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1698 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1699 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
1700 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
1701 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1702 std::complex<double> bk_gridpt =
1703 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1705 bk_comp_real += bk_gridpt.real();
1706 bk_comp_imag += bk_gridpt.imag();
1709 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1711 bk_dv[idx_dv] += coupling * vol_cell * (
1712 bk_component + factor_mirror * std::conj(bk_component)
1717 if (params.
shape ==
"row") {
1718 int ibin_row = params.
idx_bin;
1720 double k_lower_a = kbinning.
bin_edges[ibin_row];
1721 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
1727 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
1730 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1731 int ibin_col = idx_dv;
1733 double k_lower_b = kbinning.
bin_edges[ibin_col];
1734 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
1740 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
1743 if (count_terms == 0) {
1744 k1bin_dv[idx_dv] = kbinning.
bin_centres[ibin_row];
1745 k2bin_dv[idx_dv] = kbinning.
bin_centres[ibin_col];
1746 k1eff_dv[idx_dv] = k_eff_a_;
1747 k2eff_dv[idx_dv] = k_eff_b_;
1748 nmodes1_dv[idx_dv] = nmodes_a_;
1749 nmodes2_dv[idx_dv] = nmodes_b_;
1753 double bk_comp_real = 0., bk_comp_imag = 0.;
1756#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1758 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1759 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
1760 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
1761 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1762 std::complex<double> bk_gridpt =
1763 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1765 bk_comp_real += bk_gridpt.real();
1766 bk_comp_imag += bk_gridpt.imag();
1769 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1771 bk_dv[idx_dv] += coupling * vol_cell * (
1772 bk_component + factor_mirror * std::conj(bk_component)
1777 if (params.
shape ==
"full") {
1778 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1779 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
1780 int idx_dv = idx_row * params.
num_bins + idx_col;
1782 double k_lower_a = kbinning.
bin_edges[idx_row];
1783 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
1784 double k_lower_b = kbinning.
bin_edges[idx_col];
1785 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
1787 double k_eff_a_, k_eff_b_;
1788 int nmodes_a_, nmodes_b_;
1791 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
1794 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
1797 if (count_terms == 0) {
1800 k1eff_dv[idx_dv] = k_eff_a_;
1801 k2eff_dv[idx_dv] = k_eff_b_;
1802 nmodes1_dv[idx_dv] = nmodes_a_;
1803 nmodes2_dv[idx_dv] = nmodes_b_;
1807 double bk_comp_real = 0., bk_comp_imag = 0.;
1810#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1812 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1813 std::complex<double> F_lm_a_gridpt(
1814 F_lm_a[gid][0], F_lm_a[gid][1]
1816 std::complex<double> F_lm_b_gridpt(
1817 F_lm_b[gid][0], F_lm_b[gid][1]
1819 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1820 std::complex<double> bk_gridpt =
1821 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1823 bk_comp_real += bk_gridpt.real();
1824 bk_comp_imag += bk_gridpt.imag();
1827 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1829 bk_dv[idx_dv] += coupling * vol_cell * (
1830 bk_component + factor_mirror * std::conj(bk_component)
1836 if (params.
shape ==
"triu") {
1837 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1838 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
1839 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
1840 + (idx_col - idx_row);
1842 double k_lower_a = kbinning.
bin_edges[idx_row];
1843 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
1844 double k_lower_b = kbinning.
bin_edges[idx_col];
1845 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
1847 double k_eff_a_, k_eff_b_;
1848 int nmodes_a_, nmodes_b_;
1851 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
1854 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
1857 if (count_terms == 0) {
1860 k1eff_dv[idx_dv] = k_eff_a_;
1861 k2eff_dv[idx_dv] = k_eff_b_;
1862 nmodes1_dv[idx_dv] = nmodes_a_;
1863 nmodes2_dv[idx_dv] = nmodes_b_;
1867 double bk_comp_real = 0., bk_comp_imag = 0.;
1870#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1872 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1873 std::complex<double> F_lm_a_gridpt(
1874 F_lm_a[gid][0], F_lm_a[gid][1]
1876 std::complex<double> F_lm_b_gridpt(
1877 F_lm_b[gid][0], F_lm_b[gid][1]
1879 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1880 std::complex<double> bk_gridpt =
1881 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1883 bk_comp_real += bk_gridpt.real();
1884 bk_comp_imag += bk_gridpt.imag();
1887 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1889 bk_dv[idx_dv] += coupling * vol_cell * (
1890 bk_component + factor_mirror * std::conj(bk_component)
1903 std::complex<double> Sbar_LM =
1904 double(catalogue_data.
ntotal);
1905 std::complex<double> Sbar_L0 = Sbar_LM;
1907 if (params.
ell1 == 0 && params.
ell2 == 0) {
1908 std::complex<double> S_ijk = coupling * Sbar_LM;
1909 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1910 sn_dv[idx_dv] += S_ijk;
1914 if (params.
ell2 == 0) {
1917 dn_00_for_sn, N_L0, Sbar_LM, params.
ell1, m1_, kbinning
1920 if (params.
shape ==
"diag") {
1921 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1923 std::complex<double> S_i_jk = coupling * (
1924 stats_sn.
pk[ibin] - stats_sn.
sn[ibin]
1926 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
1930 if (params.
shape ==
"off-diag") {
1931 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1936 ibin_row = idx_dv + std::abs(params.
idx_bin);
1938 std::complex<double> S_i_jk = coupling * (
1939 stats_sn.
pk[ibin_row] - stats_sn.
sn[ibin_row]
1941 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
1945 if (params.
shape ==
"row") {
1946 std::complex<double> S_i_jk_row_ = coupling * (
1949 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1951 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
1955 if (params.
shape ==
"full") {
1956 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1957 std::complex<double> S_i_jk_row_ = coupling * (
1958 stats_sn.
pk[idx_row] - stats_sn.
sn[idx_row]
1960 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
1961 int idx_dv = idx_row * params.
num_bins + idx_col;
1963 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
1968 if (params.
shape ==
"triu") {
1969 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1970 std::complex<double> S_i_jk_row_ = coupling * (
1971 stats_sn.
pk[idx_row] - stats_sn.
sn[idx_row]
1973 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
1974 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
1975 + (idx_col - idx_row);
1977 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
1983 if (params.
ell1 == 0) {
1986 dn_00_for_sn, N_L0, Sbar_LM, params.
ell2, m2_, kbinning
1989 if (params.
shape ==
"diag") {
1990 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1992 std::complex<double> S_ik_j_ki = coupling * (
1993 stats_sn.
pk[ibin] - stats_sn.
sn[ibin]
1995 sn_dv[idx_dv] += S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
1999 if (params.
shape ==
"off-diag") {
2000 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2003 ibin_col = idx_dv + params.
idx_bin;
2007 std::complex<double> S_ik_j_ki = coupling * (
2008 stats_sn.
pk[ibin_col] - stats_sn.
sn[ibin_col]
2010 sn_dv[idx_dv] += S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
2014 if (params.
shape ==
"row") {
2015 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2016 int ibin_col = idx_dv;
2017 std::complex<double> S_ik_j_ki = coupling * (
2018 stats_sn.
pk[ibin_col] - stats_sn.
sn[ibin_col]
2020 sn_dv[idx_dv] += S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
2024 if (params.
shape ==
"full") {
2025 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2026 std::complex<double> S_ik_j_ki_col_ = coupling * (
2027 stats_sn.
pk[idx_col] - stats_sn.
sn[idx_col]
2029 for (
int idx_row = 0; idx_row <= params.
num_bins; idx_row++) {
2030 int idx_dv = idx_row * params.
num_bins + idx_col;
2032 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
2037 if (params.
shape ==
"triu") {
2038 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2039 std::complex<double> S_ik_j_ki_col_ = coupling * (
2040 stats_sn.
pk[idx_col] - stats_sn.
sn[idx_col]
2042 for (
int idx_row = 0; idx_row <= idx_col; idx_row++) {
2043 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
2044 + (idx_col - idx_row);
2046 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
2052 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2053 double k_a = k1eff_dv[idx_dv];
2054 double k_b = k2eff_dv[idx_dv];
2056 std::complex<double> S_ij_k = coupling
2058 dn_L0_for_sn, N_00, ylm_r_a, ylm_r_b, sj_a, sj_b,
2062 sn_dv[idx_dv] += factor_phase * (
2063 S_ij_k + factor_mirror_w3j * std::conj(S_ij_k)
2067 sph_orders_computed.push_back(sph_order_current);
2071 "Bispectrum term computed at orders (m₁, m₂, M) = ±(%d, %d, 0).",
2083 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2084 bispec_out.
k1_bin.push_back(k1bin_dv[idx_dv]);
2085 bispec_out.
k1_eff.push_back(k1eff_dv[idx_dv]);
2086 bispec_out.
nmodes_1.push_back(nmodes1_dv[idx_dv]);
2087 bispec_out.
k2_bin.push_back(k2bin_dv[idx_dv]);
2088 bispec_out.
k2_eff.push_back(k2eff_dv[idx_dv]);
2089 bispec_out.
nmodes_2.push_back(nmodes2_dv[idx_dv]);
2090 bispec_out.
bk_raw.push_back(norm_factor * bk_dv[idx_dv]);
2091 bispec_out.
bk_shot.push_back(norm_factor * sn_dv[idx_dv]);
2093 bispec_out.
dim = dv_dim;
2095 delete[] nmodes1_dv;
delete[] nmodes2_dv;
2096 delete[] k1bin_dv;
delete[] k2bin_dv;
2097 delete[] k1eff_dv;
delete[] k2eff_dv;
2098 delete[] bk_dv;
delete[] sn_dv;
2107 "... computed bispectrum from a periodic-box simulation-type catalogue "
2108 "in the global plane-parallel approximation."
2124 "Computing three-point correlation function "
2125 "from a periodic-box simulation-type catalogue "
2126 "in the global plane-parallel approximation..."
2137 std::complex<double> factor_phase =
2139 double factor_parity = std::pow(-1., params.
ell1 + params.
ell2);
2143 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
2146 if (params.
shape ==
"off-diag") {
2149 if (params.
shape ==
"full") {
2152 if (params.
shape ==
"triu") {
2157 "Three-point statistic form is not recognised: `form` = '%s'.",
2162 "Three-point statistic form is not recognised: `form` = '%s'.\n",
2167 int* npairs1_dv =
new int[dv_dim];
2168 int* npairs2_dv =
new int[dv_dim];
2169 double* r1bin_dv =
new double[dv_dim];
2170 double* r2bin_dv =
new double[dv_dim];
2171 double* r1eff_dv =
new double[dv_dim];
2172 double* r2eff_dv =
new double[dv_dim];
2173 std::complex<double>* zeta_dv =
new std::complex<double>[dv_dim];
2174 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
2175 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2176 npairs1_dv[idx_dv] = 0;
2177 npairs2_dv[idx_dv] = 0;
2178 r1bin_dv[idx_dv] = 0.;
2179 r2bin_dv[idx_dv] = 0.;
2180 r1eff_dv[idx_dv] = 0.;
2181 r2eff_dv[idx_dv] = 0.;
2182 zeta_dv[idx_dv] = 0.;
2190#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
2191 fftw_init_threads();
2195 MeshField dn_00(params,
true,
"`dn_00`");
2213 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
2214 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
2215 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
2216 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
2225 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
2226 int count_terms = 0;
2227 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
2228 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
2236 std::string flag_redundant =
"false";
2238 if (sph_order_current.
is_inverse(sph_order)) {
2239 flag_redundant =
"true";
2242 if (flag_redundant ==
"true") {
continue;}
2246 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
2258 double factor_mirror = sph_order_current.
is_zeros() ?
2259 0. : std::pow(-1., params.
ELL);
2260 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
2263 trvm::SphericalHarmonicCalculator::
2264 store_reduced_spherical_harmonic_in_config_space(
2267 trvm::SphericalHarmonicCalculator::
2268 store_reduced_spherical_harmonic_in_config_space(
2271 trvm::SphericalHarmonicCalculator::
2272 store_reduced_spherical_harmonic_in_fourier_space(
2275 trvm::SphericalHarmonicCalculator::
2276 store_reduced_spherical_harmonic_in_fourier_space(
2287 std::complex<double> Sbar_L0 =
2288 double(catalogue_data.
ntotal);
2291 dn_L0_for_sn, N_00, ylm_r_a, ylm_r_b, Sbar_L0, rbinning
2295 if (params.
shape ==
"diag") {
2296 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2298 sn_dv[idx_dv] += coupling * factor_parity * (
2300 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
2305 if (params.
shape ==
"off-diag" && params.
idx_bin == 0) {
2307 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2309 sn_dv[idx_dv] += coupling * factor_parity * (
2311 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
2316 if (params.
shape ==
"row") {
2317 sn_dv[params.
idx_bin] += coupling * factor_parity * (
2319 + factor_mirror_w3j * std::conj(stats_sn.
xi[params.
idx_bin])
2323 if (params.
shape ==
"full") {
2324 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2326 int idx_dv = idx_row * params.
num_bins + idx_row;
2327 sn_dv[idx_dv] += coupling * factor_parity * (
2328 stats_sn.
xi[idx_row]
2329 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
2334 if (params.
shape ==
"triu") {
2335 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2337 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2;
2338 sn_dv[idx_dv] += coupling * factor_parity * (
2339 stats_sn.
xi[idx_row]
2340 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
2346 if (count_terms == 0) {
2347 if (params.
shape ==
"diag") {
2348 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2353 r1eff_dv[idx_dv] = stats_sn.
r[ibin];
2354 r2eff_dv[idx_dv] = stats_sn.
r[ibin];
2355 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin];
2356 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin];
2360 if (params.
shape ==
"off-diag") {
2361 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2362 int ibin_row, ibin_col;
2365 ibin_col = idx_dv + std::abs(params.
idx_bin);
2367 ibin_row = idx_dv + std::abs(params.
idx_bin);
2371 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
2372 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
2373 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
2374 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
2375 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
2376 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
2380 if (params.
shape ==
"row") {
2381 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2382 int ibin_row = params.
idx_bin;
2383 int ibin_col = idx_dv;
2385 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
2386 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
2387 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
2388 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
2389 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
2390 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
2394 if (params.
shape ==
"full") {
2395 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2396 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2397 int idx_dv = idx_row * params.
num_bins + idx_col;
2401 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
2402 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
2403 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
2404 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
2409 if (params.
shape ==
"triu") {
2410 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2411 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
2412 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
2413 + (idx_col - idx_row);
2417 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
2418 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
2419 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
2420 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
2437 MeshField F_lm_a(params,
true,
"`F_lm_a`");
2438 MeshField F_lm_b(params,
true,
"`F_lm_b`");
2440 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2441 double r_a = r1eff_dv[idx_dv];
2443 dn_00, ylm_k_a, sj_a, r_a
2446 double r_b = r2eff_dv[idx_dv];
2448 dn_00, ylm_k_b, sj_b, r_b
2452 double zeta_comp_real = 0., zeta_comp_imag = 0.;
2455#pragma omp parallel for reduction(+:zeta_comp_real, zeta_comp_imag)
2457 for (
long long gid = 0; gid < params.
nmesh; gid++) {
2458 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
2459 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
2460 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
2461 std::complex<double> zeta_gridpt =
2462 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
2464 zeta_comp_real += zeta_gridpt.real();
2465 zeta_comp_imag += zeta_gridpt.imag();
2468 std::complex<double> zeta_component(zeta_comp_real, zeta_comp_imag);
2470 zeta_dv[idx_dv] += coupling * vol_cell * factor_phase * (
2471 zeta_component + factor_mirror * std::conj(zeta_component)
2475 sph_orders_computed.push_back(sph_order_current);
2479 "Three-point correlation function term computed at orders "
2480 "(m₁, m₂, M) = ±(%d, %d, 0).",
2492 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2493 threepcf_out.
r1_bin.push_back(r1bin_dv[idx_dv]);
2494 threepcf_out.
r1_eff.push_back(r1eff_dv[idx_dv]);
2495 threepcf_out.
npairs_1.push_back(npairs1_dv[idx_dv]);
2496 threepcf_out.
r2_bin.push_back(r2bin_dv[idx_dv]);
2497 threepcf_out.
r2_eff.push_back(r2eff_dv[idx_dv]);
2498 threepcf_out.
npairs_2.push_back(npairs2_dv[idx_dv]);
2499 threepcf_out.
zeta_raw.push_back(norm_factor * zeta_dv[idx_dv]);
2500 threepcf_out.
zeta_shot.push_back(norm_factor * sn_dv[idx_dv]);
2502 threepcf_out.
dim = dv_dim;
2504 delete[] npairs1_dv;
delete[] npairs2_dv;
2505 delete[] r1bin_dv;
delete[] r2bin_dv;
2506 delete[] r1eff_dv;
delete[] r2eff_dv;
2507 delete[] zeta_dv;
delete[] sn_dv;
2516 "... computed three-point correlation function "
2517 "from a periodic-box simulation-type catalogue "
2518 "in the global plane-parallel approximation."
2522 return threepcf_out;
2528 double alpha,
double norm_factor,
bool wide_angle
2530 std::string msg_tag = wide_angle ?
"wide-angle corrections " :
"";
2536 "Computing three-point correlation function window %s"
2537 "from random catalogue...",
2549 std::complex<double> factor_phase =
2551 double factor_parity = std::pow(-1., params.
ell1 + params.
ell2);
2555 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
2558 if (params.
shape ==
"off-diag") {
2561 if (params.
shape ==
"full") {
2564 if (params.
shape ==
"triu") {
2569 "Three-point statistic form is not recognised: `form` = '%s'.",
2574 "Three-point statistic form is not recognised: `form` = '%s'.\n",
2579 int* npairs1_dv =
new int[dv_dim];
2580 int* npairs2_dv =
new int[dv_dim];
2581 double* r1bin_dv =
new double[dv_dim];
2582 double* r2bin_dv =
new double[dv_dim];
2583 double* r1eff_dv =
new double[dv_dim];
2584 double* r2eff_dv =
new double[dv_dim];
2585 std::complex<double>* zeta_dv =
new std::complex<double>[dv_dim];
2586 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
2587 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2588 npairs1_dv[idx_dv] = 0;
2589 npairs2_dv[idx_dv] = 0;
2590 r1bin_dv[idx_dv] = 0.;
2591 r2bin_dv[idx_dv] = 0.;
2592 r1eff_dv[idx_dv] = 0.;
2593 r2eff_dv[idx_dv] = 0.;
2594 zeta_dv[idx_dv] = 0.;
2602#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
2603 fftw_init_threads();
2623 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
2624 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
2625 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
2626 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
2635 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
2636 int count_terms = 0;
2637 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
2638 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
2640 std::string flag_vanishing =
"true";
2641 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
2643 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
2646 flag_vanishing =
"false";
2650 if (flag_vanishing ==
"true") {
continue;}
2652 trvm::SphericalHarmonicCalculator::
2653 store_reduced_spherical_harmonic_in_config_space(
2656 trvm::SphericalHarmonicCalculator::
2657 store_reduced_spherical_harmonic_in_config_space(
2660 trvm::SphericalHarmonicCalculator::
2661 store_reduced_spherical_harmonic_in_fourier_space(
2664 trvm::SphericalHarmonicCalculator::
2665 store_reduced_spherical_harmonic_in_fourier_space(
2669 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
2673 std::string flag_redundant =
"false";
2675 if (sph_order_current.
is_inverse(sph_order)) {
2676 flag_redundant =
"true";
2679 if (flag_redundant ==
"true") {
continue;}
2683 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
2695 double factor_mirror = sph_order_current.
is_zeros() ?
2696 0. : std::pow(-1., params.
ELL);
2697 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
2705 MeshField n_LM_for_sn(params,
true,
"`n_LM_for_sn`");
2709 catalogue_rand, los_rand, alpha, params.
ELL, M_
2714 catalogue_rand, los_rand, alpha, params.
ELL, M_
2718 n_LM_for_sn, N_00, ylm_r_a, ylm_r_b, Sbar_LM, rbinning
2722 if (params.
shape ==
"diag") {
2723 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2725 sn_dv[idx_dv] += coupling * factor_parity * (
2727 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
2732 if (params.
shape ==
"off-diag" && params.
idx_bin == 0) {
2734 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2736 sn_dv[idx_dv] += coupling * factor_parity * (
2738 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
2743 if (params.
shape ==
"row") {
2744 sn_dv[params.
idx_bin] += coupling * factor_parity * (
2746 + factor_mirror_w3j * std::conj(stats_sn.
xi[params.
idx_bin])
2750 if (params.
shape ==
"full") {
2751 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2753 int idx_dv = idx_row * params.
num_bins + idx_row;
2754 sn_dv[idx_dv] += coupling * factor_parity * (
2755 stats_sn.
xi[idx_row]
2756 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
2761 if (params.
shape ==
"triu") {
2762 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2764 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2;
2765 sn_dv[idx_dv] += coupling * factor_parity * (
2766 stats_sn.
xi[idx_row]
2767 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
2772 if (count_terms == 0) {
2773 if (params.
shape ==
"diag") {
2774 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2779 r1eff_dv[idx_dv] = stats_sn.
r[ibin];
2780 r2eff_dv[idx_dv] = stats_sn.
r[ibin];
2781 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin];
2782 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin];
2786 if (params.
shape ==
"off-diag") {
2787 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2788 int ibin_row, ibin_col;
2791 ibin_col = idx_dv + std::abs(params.
idx_bin);
2793 ibin_row = idx_dv + std::abs(params.
idx_bin);
2797 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
2798 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
2799 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
2800 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
2801 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
2802 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
2806 if (params.
shape ==
"row") {
2807 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2808 int ibin_row = params.
idx_bin;
2809 int ibin_col = idx_dv;
2811 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
2812 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
2813 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
2814 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
2815 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
2816 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
2820 if (params.
shape ==
"full") {
2821 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2822 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2823 int idx_dv = idx_row * params.
num_bins + idx_col;
2827 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
2828 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
2829 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
2830 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
2835 if (params.
shape ==
"triu") {
2836 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2837 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++)
2839 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
2840 + (idx_col - idx_row);
2844 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
2845 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
2846 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
2847 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
2860 catalogue_rand, los_rand, alpha, params.
ELL, M_
2871 MeshField F_lm_a(params,
true,
"`F_lm_a`");
2872 MeshField F_lm_b(params,
true,
"`F_lm_b`");
2874 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2875 double r_a = r1eff_dv[idx_dv];
2877 n_00, ylm_k_a, sj_a, r_a
2880 double r_b = r2eff_dv[idx_dv];
2882 n_00, ylm_k_b, sj_b, r_b
2886 double zeta_comp_real = 0., zeta_comp_imag = 0.;
2889#pragma omp parallel for reduction(+:zeta_comp_real, zeta_comp_imag)
2891 for (
long long gid = 0; gid < params.
nmesh; gid++) {
2892 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
2893 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
2894 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
2895 std::complex<double> zeta_gridpt =
2896 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
2898 zeta_comp_real += zeta_gridpt.real();
2899 zeta_comp_imag += zeta_gridpt.imag();
2902 std::complex<double> zeta_component(zeta_comp_real, zeta_comp_imag);
2904 zeta_dv[idx_dv] += coupling * vol_cell * factor_phase * (
2905 zeta_component + factor_mirror * std::conj(zeta_component)
2909 sph_orders_computed.push_back(sph_order_current);
2913 "Three-point correlation function window term computed at orders "
2914 "(m₁, m₂, M) = ±(%d, %d, %d).",
2927 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2928 threepcfwin_out.
r1_bin.push_back(r1bin_dv[idx_dv]);
2929 threepcfwin_out.
r1_eff.push_back(r1eff_dv[idx_dv]);
2930 threepcfwin_out.
npairs_1.push_back(npairs1_dv[idx_dv]);
2931 threepcfwin_out.
r2_bin.push_back(r2bin_dv[idx_dv]);
2932 threepcfwin_out.
r2_eff.push_back(r2eff_dv[idx_dv]);
2933 threepcfwin_out.
npairs_2.push_back(npairs2_dv[idx_dv]);
2934 threepcfwin_out.
zeta_raw.push_back(norm_factor * zeta_dv[idx_dv]);
2935 threepcfwin_out.
zeta_shot.push_back(norm_factor * sn_dv[idx_dv]);
2937 threepcfwin_out.
dim = dv_dim;
2939 delete[] npairs1_dv;
delete[] npairs2_dv;
2940 delete[] r1bin_dv;
delete[] r2bin_dv;
2941 delete[] r1eff_dv;
delete[] r2eff_dv;
2942 delete[] zeta_dv;
delete[] sn_dv;
2951 "... computed three-point correlation function window %s"
2952 "from random catalogue.",
2957 return threepcfwin_out;
2960#ifdef TRV_USE_LEGACY_CODE
2962 ParticleCatalogue& catalogue_data, ParticleCatalogue& catalogue_rand,
2963 LineOfSight* los_data, LineOfSight* los_rand,
2972 "Computing bispectrum from paired survey-type catalogues "
2973 "for line-of-sight choice %d...",
2985 double alpha = catalogue_data.wstotal / catalogue_rand.wstotal;
2987 std::complex<double> factor_phase =
2992 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
2995 if (params.
shape ==
"off-diag") {
2998 if (params.
shape ==
"full") {
3001 if (params.
shape ==
"triu") {
3006 "Three-point statistic form is not recognised: `form` = '%s'.",
3011 "Three-point statistic form is not recognised: `form` = '%s'.\n",
3016 int* nmodes1_dv =
new int[dv_dim];
3017 int* nmodes2_dv =
new int[dv_dim];
3018 double* k1bin_dv =
new double[dv_dim];
3019 double* k2bin_dv =
new double[dv_dim];
3020 double* k1eff_dv =
new double[dv_dim];
3021 double* k2eff_dv =
new double[dv_dim];
3022 std::complex<double>* bk_dv =
new std::complex<double>[dv_dim];
3023 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
3024 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3025 nmodes1_dv[idx_dv] = 0;
3026 nmodes2_dv[idx_dv] = 0;
3027 k1bin_dv[idx_dv] = 0.;
3028 k2bin_dv[idx_dv] = 0.;
3029 k1eff_dv[idx_dv] = 0.;
3030 k2eff_dv[idx_dv] = 0.;
3054#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
3055 fftw_init_threads();
3077 FieldStats stats_sn(params);
3080 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
3081 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
3082 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
3083 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
3092 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
3093 int count_terms = 0;
3094 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
3095 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
3097 std::string flag_vanishing =
"true";
3098 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
3100 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
3103 flag_vanishing =
"false";
3107 if (flag_vanishing ==
"true") {
continue;}
3109 trvm::SphericalHarmonicCalculator::
3110 store_reduced_spherical_harmonic_in_fourier_space(
3113 trvm::SphericalHarmonicCalculator::
3114 store_reduced_spherical_harmonic_in_fourier_space(
3117 trvm::SphericalHarmonicCalculator::
3118 store_reduced_spherical_harmonic_in_config_space(
3121 trvm::SphericalHarmonicCalculator::
3122 store_reduced_spherical_harmonic_in_config_space(
3126 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
3128 SphericalOrderTriplet sph_order_current = {m1_, m2_, M_};
3130 std::string flag_redundant =
"false";
3131 for (SphericalOrderTriplet sph_order : sph_orders_computed) {
3132 if (sph_order_current.is_inverse(sph_order)) {
3133 flag_redundant =
"true";
3136 if (flag_redundant ==
"true") {
continue;}
3140 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
3154 double factor_mirror = sph_order_current.is_zeros() ?
3155 0. : std::pow(-1., params.
ELL);
3156 double factor_mirror_w3j = sph_order_current.is_zeros() ?
3164 MeshField dn_LM_a(params,
true,
"`dn_LM_a`");
3165 if (los_choice == 0) {
3166 dn_LM_a.compute_ylm_wgtd_field(
3167 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3171 dn_LM_a.compute_ylm_wgtd_field(
3172 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3176 dn_LM_a.fourier_transform();
3178 MeshField dn_LM_b(params,
true,
"`dn_LM_b`");
3179 if (los_choice == 1) {
3180 dn_LM_b.compute_ylm_wgtd_field(
3181 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3185 dn_LM_b.compute_ylm_wgtd_field(
3186 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3190 dn_LM_b.fourier_transform();
3192 MeshField G_LM(params,
true,
"`G_LM`");
3193 if (los_choice == 2) {
3194 G_LM.compute_ylm_wgtd_field(
3195 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3199 G_LM.compute_ylm_wgtd_field(
3200 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3204 G_LM.fourier_transform();
3205 G_LM.apply_assignment_compensation();
3206 G_LM.inv_fourier_transform();
3208 double vol_cell = G_LM.vol_cell;
3210 MeshField F_lm_a(params,
true,
"`F_lm_a`");
3211 MeshField F_lm_b(params,
true,
"`F_lm_b`");
3213 if (params.
shape ==
"diag") {
3214 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3217 double k_lower = kbinning.
bin_edges[ibin];
3218 double k_upper = kbinning.
bin_edges[ibin + 1];
3220 double k_eff_a_, k_eff_b_;
3221 int nmodes_a_, nmodes_b_;
3223 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3224 dn_LM_a, ylm_k_a, k_lower, k_upper, k_eff_a_, nmodes_a_
3226 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3227 dn_LM_b, ylm_k_b, k_lower, k_upper, k_eff_b_, nmodes_b_
3230 if (count_terms == 0) {
3233 k1eff_dv[idx_dv] = k_eff_a_;
3234 k2eff_dv[idx_dv] = k_eff_b_;
3235 nmodes1_dv[idx_dv] = nmodes_a_;
3236 nmodes2_dv[idx_dv] = nmodes_b_;
3240 double bk_comp_real = 0., bk_comp_imag = 0.;
3243#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3245 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3246 std::complex<double> F_lm_a_gridpt(
3247 F_lm_a[gid][0], F_lm_a[gid][1]
3249 std::complex<double> F_lm_b_gridpt(
3250 F_lm_b[gid][0], F_lm_b[gid][1]
3252 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3253 std::complex<double> bk_gridpt =
3254 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3256 bk_comp_real += bk_gridpt.real();
3257 bk_comp_imag += bk_gridpt.imag();
3260 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3262 bk_dv[idx_dv] += coupling * vol_cell * (
3263 bk_component + factor_mirror * std::conj(bk_component)
3268 if (params.
shape ==
"off-diag") {
3269 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3270 int ibin_row, ibin_col;
3273 ibin_col = idx_dv + std::abs(params.
idx_bin);
3275 ibin_row = idx_dv + std::abs(params.
idx_bin);
3279 double k_lower_a = kbinning.
bin_edges[ibin_row];
3280 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
3281 double k_lower_b = kbinning.
bin_edges[ibin_col];
3282 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
3284 double k_eff_a_, k_eff_b_;
3285 int nmodes_a_, nmodes_b_;
3287 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3288 dn_LM_a, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
3290 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3291 dn_LM_b, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
3294 if (count_terms == 0) {
3295 k1bin_dv[idx_dv] = kbinning.
bin_centres[ibin_row];
3296 k2bin_dv[idx_dv] = kbinning.
bin_centres[ibin_col];
3297 k1eff_dv[idx_dv] = k_eff_a_;
3298 k2eff_dv[idx_dv] = k_eff_b_;
3299 nmodes1_dv[idx_dv] = nmodes_a_;
3300 nmodes2_dv[idx_dv] = nmodes_b_;
3304 double bk_comp_real = 0., bk_comp_imag = 0.;
3307#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3309 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3310 std::complex<double> F_lm_a_gridpt(
3311 F_lm_a[gid][0], F_lm_a[gid][1]
3313 std::complex<double> F_lm_b_gridpt(
3314 F_lm_b[gid][0], F_lm_b[gid][1]
3316 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3317 std::complex<double> bk_gridpt =
3318 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3320 bk_comp_real += bk_gridpt.real();
3321 bk_comp_imag += bk_gridpt.imag();
3324 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3326 bk_dv[idx_dv] += coupling * vol_cell * (
3327 bk_component + factor_mirror * std::conj(bk_component)
3332 if (params.
shape ==
"row") {
3333 int ibin_row = params.
idx_bin;
3341 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3342 dn_LM_a, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
3345 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3346 int ibin_col = idx_dv;
3348 double k_lower_b = kbinning.
bin_edges[ibin_col];
3349 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
3354 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3355 dn_LM_b, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
3358 if (count_terms == 0) {
3359 k1bin_dv[idx_dv] = kbinning.
bin_centres[ibin_row];
3360 k2bin_dv[idx_dv] = kbinning.
bin_centres[ibin_col];
3361 k1eff_dv[idx_dv] = k_eff_a_;
3362 k2eff_dv[idx_dv] = k_eff_b_;
3363 nmodes1_dv[idx_dv] = nmodes_a_;
3364 nmodes2_dv[idx_dv] = nmodes_b_;
3368 double bk_comp_real = 0., bk_comp_imag = 0.;
3371#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3373 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3374 std::complex<double> F_lm_a_gridpt(
3375 F_lm_a[gid][0], F_lm_a[gid][1]
3377 std::complex<double> F_lm_b_gridpt(
3378 F_lm_b[gid][0], F_lm_b[gid][1]
3380 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3381 std::complex<double> bk_gridpt =
3382 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3384 bk_comp_real += bk_gridpt.real();
3385 bk_comp_imag += bk_gridpt.imag();
3388 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3390 bk_dv[idx_dv] += coupling * vol_cell * (
3391 bk_component + factor_mirror * std::conj(bk_component)
3396 if (params.
shape ==
"full") {
3397 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
3398 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
3399 int idx_dv = idx_row * params.
num_bins + idx_col;
3401 double k_lower_a = kbinning.
bin_edges[idx_row];
3402 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
3403 double k_lower_b = kbinning.
bin_edges[idx_col];
3404 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
3406 double k_eff_a_, k_eff_b_;
3407 int nmodes_a_, nmodes_b_;
3409 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3410 dn_LM_a, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
3412 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3413 dn_LM_b, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
3416 if (count_terms == 0) {
3419 k1eff_dv[idx_dv] = k_eff_a_;
3420 k2eff_dv[idx_dv] = k_eff_b_;
3421 nmodes1_dv[idx_dv] = nmodes_a_;
3422 nmodes2_dv[idx_dv] = nmodes_b_;
3426 double bk_comp_real = 0., bk_comp_imag = 0.;
3429#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3431 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3432 std::complex<double> F_lm_a_gridpt(
3433 F_lm_a[gid][0], F_lm_a[gid][1]
3435 std::complex<double> F_lm_b_gridpt(
3436 F_lm_b[gid][0], F_lm_b[gid][1]
3438 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3439 std::complex<double> bk_gridpt =
3440 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3442 bk_comp_real += bk_gridpt.real();
3443 bk_comp_imag += bk_gridpt.imag();
3446 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3448 bk_dv[idx_dv] += coupling * vol_cell * (
3449 bk_component + factor_mirror * std::conj(bk_component)
3455 if (params.
shape ==
"triu") {
3456 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
3457 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
3458 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
3459 + (idx_col - idx_row);
3461 double k_lower_a = kbinning.
bin_edges[idx_row];
3462 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
3463 double k_lower_b = kbinning.
bin_edges[idx_col];
3464 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
3466 double k_eff_a_, k_eff_b_;
3467 int nmodes_a_, nmodes_b_;
3469 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3470 dn_LM_a, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
3472 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3473 dn_LM_b, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
3476 if (count_terms == 0) {
3479 k1eff_dv[idx_dv] = k_eff_a_;
3480 k2eff_dv[idx_dv] = k_eff_b_;
3481 nmodes1_dv[idx_dv] = nmodes_a_;
3482 nmodes2_dv[idx_dv] = nmodes_b_;
3486 double bk_comp_real = 0., bk_comp_imag = 0.;
3489#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3491 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3492 std::complex<double> F_lm_a_gridpt(
3493 F_lm_a[gid][0], F_lm_a[gid][1]
3495 std::complex<double> F_lm_b_gridpt(
3496 F_lm_b[gid][0], F_lm_b[gid][1]
3498 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3499 std::complex<double> bk_gridpt =
3500 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3502 bk_comp_real += bk_gridpt.real();
3503 bk_comp_imag += bk_gridpt.imag();
3506 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3508 bk_dv[idx_dv] += coupling * vol_cell * (
3509 bk_component + factor_mirror * std::conj(bk_component)
3520 MeshField dn_LM_a_for_sn(params,
true,
"`dn_LM_a_for_sn`");
3523 if (los_choice == 0) {
3524 dn_LM_a_for_sn.compute_ylm_wgtd_field(
3525 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3529 dn_LM_a_for_sn.compute_ylm_wgtd_field(
3530 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3534 dn_LM_a_for_sn.fourier_transform();
3536 MeshField dn_LM_b_for_sn(params,
true,
"`dn_LM_b_for_sn`");
3539 if (los_choice == 1) {
3540 dn_LM_b_for_sn.compute_ylm_wgtd_field(
3541 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3545 dn_LM_b_for_sn.compute_ylm_wgtd_field(
3546 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3550 dn_LM_b_for_sn.fourier_transform();
3553 MeshField dn_LM_c_for_sn(params,
true,
"`dn_LM_c_for_sn`");
3554 if (los_choice == 2) {
3555 dn_LM_c_for_sn.compute_ylm_wgtd_field(
3556 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3560 dn_LM_c_for_sn.compute_ylm_wgtd_field(
3561 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3565 dn_LM_c_for_sn.fourier_transform();
3567 MeshField N_LM_a(params,
true,
"`N_LM_a`");
3568 if (los_choice == 0) {
3569 N_LM_a.compute_ylm_wgtd_quad_field(
3570 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3574 N_LM_a.compute_ylm_wgtd_quad_field(
3575 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3579 N_LM_a.fourier_transform();
3581 MeshField N_LM_b(params,
true,
"`N_LM_b`");
3582 if (los_choice == 1) {
3583 N_LM_b.compute_ylm_wgtd_quad_field(
3584 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3588 N_LM_b.compute_ylm_wgtd_quad_field(
3589 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3593 N_LM_b.fourier_transform();
3595 MeshField N_LM_c(params,
true,
"`N_LM_c`");
3596 if (los_choice == 2) {
3597 N_LM_c.compute_ylm_wgtd_quad_field(
3598 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3602 N_LM_c.compute_ylm_wgtd_quad_field(
3603 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3607 N_LM_c.fourier_transform();
3610 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3614 if (params.
ell1 == 0 && params.
ell2 == 0) {
3617 std::complex<double> S_ijk = coupling * Sbar_LM;
3618 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3619 sn_dv[idx_dv] += S_ijk;
3623 if (params.
ell2 == 0) {
3625 stats_sn.compute_ylm_wgtd_2pt_stats_in_fourier(
3626 dn_LM_a_for_sn, N_LM_a, Sbar_LM, params.
ell1, m1_, kbinning
3629 if (params.
shape ==
"diag") {
3630 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3632 std::complex<double> S_i_jk = coupling * (
3633 stats_sn.pk[ibin] - stats_sn.sn[ibin]
3635 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
3639 if (params.
shape ==
"off-diag") {
3640 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3645 ibin_row = idx_dv + std::abs(params.
idx_bin);
3647 std::complex<double> S_i_jk = coupling * (
3648 stats_sn.pk[ibin_row] - stats_sn.sn[ibin_row]
3650 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
3654 if (params.
shape ==
"row") {
3655 std::complex<double> S_i_jk_row_ = coupling * (
3658 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3660 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
3664 if (params.
shape ==
"full") {
3665 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
3666 std::complex<double> S_i_jk_row_ = coupling * (
3667 stats_sn.pk[idx_row] - stats_sn.sn[idx_row]
3669 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
3670 int idx_dv = idx_row * params.
num_bins + idx_col;
3672 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
3677 if (params.
shape ==
"triu") {
3678 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
3679 std::complex<double> S_i_jk_row_ = coupling * (
3680 stats_sn.pk[idx_row] - stats_sn.sn[idx_row]
3682 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++)
3684 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
3685 + (idx_col - idx_row);
3687 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
3693 if (params.
ell1 == 0) {
3695 stats_sn.compute_ylm_wgtd_2pt_stats_in_fourier(
3696 dn_LM_b_for_sn, N_LM_b, Sbar_LM,
3697 params.
ell2, m2_, kbinning
3700 if (params.
shape ==
"diag") {
3701 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3703 std::complex<double> S_ik_j_ki = coupling * (
3704 stats_sn.pk[ibin] - stats_sn.sn[ibin]
3707 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
3711 if (params.
shape ==
"off-diag") {
3712 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3715 ibin_col = idx_dv + params.
idx_bin;
3719 std::complex<double> S_ik_j_ki = coupling * (
3720 stats_sn.pk[ibin_col] - stats_sn.sn[ibin_col]
3723 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
3727 if (params.
shape ==
"row") {
3728 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3729 int ibin_col = idx_dv;
3730 std::complex<double> S_ik_j_ki = coupling * (
3731 stats_sn.pk[ibin_col] - stats_sn.sn[ibin_col]
3734 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
3738 if (params.
shape ==
"full") {
3739 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
3740 std::complex<double> S_ik_j_ki_col_ = coupling * (
3741 stats_sn.pk[idx_col] - stats_sn.sn[idx_col]
3743 for (
int idx_row = 0; idx_row <= params.
num_bins; idx_row++) {
3744 int idx_dv = idx_row * params.
num_bins + idx_col;
3746 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
3751 if (params.
shape ==
"triu") {
3752 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
3753 std::complex<double> S_ik_j_ki_col_ = coupling * (
3754 stats_sn.pk[idx_col] - stats_sn.sn[idx_col]
3756 for (
int idx_row = 0; idx_row <= idx_col; idx_row++) {
3757 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
3758 + (idx_col - idx_row);
3760 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
3766 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3767 double k_a = k1eff_dv[idx_dv];
3768 double k_b = k2eff_dv[idx_dv];
3770 std::complex<double> S_ij_k = coupling
3771 * stats_sn.compute_uncoupled_shotnoise_for_bispec_per_bin(
3772 dn_LM_c_for_sn, N_LM_c, ylm_r_a, ylm_r_b, sj_a, sj_b,
3776 sn_dv[idx_dv] += factor_phase * (
3777 S_ij_k + factor_mirror_w3j * std::conj(S_ij_k)
3781 sph_orders_computed.push_back(sph_order_current);
3785 "Bispectrum term computed at orders (m₁, m₂, M) = ±(%d, %d, %d).",
3805 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3806 bispec_out.
k1_bin.push_back(k1bin_dv[idx_dv]);
3807 bispec_out.
k1_eff.push_back(k1eff_dv[idx_dv]);
3808 bispec_out.
nmodes_1.push_back(nmodes1_dv[idx_dv]);
3809 bispec_out.
k2_bin.push_back(k2bin_dv[idx_dv]);
3810 bispec_out.
k2_eff.push_back(k2eff_dv[idx_dv]);
3811 bispec_out.
nmodes_2.push_back(nmodes2_dv[idx_dv]);
3812 bispec_out.
bk_raw.push_back(norm_factor * bk_dv[idx_dv]);
3813 bispec_out.
bk_shot.push_back(norm_factor * sn_dv[idx_dv]);
3815 bispec_out.
dim = dv_dim;
3817 delete[] nmodes1_dv;
delete[] nmodes2_dv;
3818 delete[] k1bin_dv;
delete[] k2bin_dv;
3819 delete[] k1eff_dv;
delete[] k2eff_dv;
3820 delete[] bk_dv;
delete[] sn_dv;
3829 "... computed bispectrum from paired survey-type catalogues "
3830 "for line-of-sight choice %d.",
Isotropic coordinate binning.
std::vector< double > bin_edges
bin edges
std::vector< double > bin_centres
bin centres
int num_bins
number of bins
Field (pseudo-two-point) statistics.
std::vector< std::complex< double > > sn
shot-noise power in bins
std::vector< std::complex< double > > pk
pseudo power spectrum in bins
void compute_uncoupled_shotnoise_for_3pcf(MeshField &field_a, MeshField &field_b, std::vector< std::complex< double > > &ylm_a, std::vector< std::complex< double > > &ylm_b, std::complex< double > shotnoise_amp, trv::Binning &rbinning)
Compute binned uncoupled three-point correlation function shot noise.
std::complex< double > compute_uncoupled_shotnoise_for_bispec_per_bin(MeshField &field_a, MeshField &field_b, std::vector< std::complex< double > > &ylm_a, std::vector< std::complex< double > > &ylm_b, trvm::SphericalBesselCalculator &sj_a, trvm::SphericalBesselCalculator &sj_b, std::complex< double > shotnoise_amp, double k_a, double k_b)
Compute unbinned uncoupled bispectrum shot noise on the FFT mesh grid.
std::vector< std::complex< double > > xi
pseudo two-point correlation function in bins
std::vector< int > npairs
number of separation pairs in bins
void compute_ylm_wgtd_2pt_stats_in_fourier(MeshField &field_a, MeshField &field_b, std::complex< double > shotnoise_amp, int ell, int m, trv::Binning &kbinning)
Compute binned two-point statistics in Fourier space.
Discretely sampled field on a mesh grid from particle catalogues.
void inv_fourier_transform()
Inverse Fourier transform the (FFT-transformed) field.
void inv_fourier_transform_sjl_ylm_wgtd_field(MeshField &field_fourier, std::vector< std::complex< double > > &ylm, trvm::SphericalBesselCalculator &sjl, double r)
Inverse Fourier transform a field weighted by the spherical Bessel function and reduced spherical ha...
double calc_grid_based_powlaw_norm(ParticleCatalogue &particles, int order)
void inv_fourier_transform_ylm_wgtd_field_band_limited(MeshField &field_fourier, std::vector< std::complex< double > > &ylm, double k_band, double dk_band, double &k_eff, int &nmodes)
Inverse Fourier transform a field weighted by the reduced spherical harmonics restricted to a wavenu...
void fourier_transform()
Fourier transform the field.
void compute_ylm_wgtd_field(ParticleCatalogue &particles_data, ParticleCatalogue &particles_rand, LineOfSight *los_data, LineOfSight *los_rand, double alpha, int ell, int m)
Compute the weighted field (fluctuations) further weighted by the reduced spherical harmonics.
void compute_unweighted_field(ParticleCatalogue &particles)
Compute the unweighted field.
void apply_wide_angle_pow_law_kernel()
Apply wide-angle correction kernel in configuration space.
void compute_ylm_wgtd_quad_field(ParticleCatalogue &particles_data, ParticleCatalogue &particles_rand, LineOfSight *los_data, LineOfSight *los_rand, double alpha, int ell, int m)
Compute the quadratic weighted field (fluctuations) further weighted by the reduced spherical harmoni...
void compute_unweighted_field_fluctuations_insitu(ParticleCatalogue &particles)
Compute the unweighted field fluctuations.
double vol_cell
mesh grid cell volume
void apply_assignment_compensation()
Apply compensation needed after Fourier transform for assignment schemes.
long long nmesh
number of mesh grid cells
int ELL
spherical degree associated with the line of sight
int ell1
spherical degree associated with the first wavevector
int num_bins
number of measurement bins
int ell2
spherical degree associated with the second wavevector
int ngrid[3]
grid number in each dimension
int idx_bin
fixed bin index in "off-fiag"/"row" form three-point measurements
double boxsize[3]
box size (in Mpc/h) in each dimension
ParticleData * pdata
particle data
int ntotal
total number of particles
double wstotal
total sample weight of particles
Interpolated spherical Bessel function of the first kind.
Exception raised when the data to be operated on are invalid.
Exception raised when parameters are invalid.
void error(const char *fmt_string,...)
Emit a warning-level message.
void stat(const char *fmt_string,...)
Emit a status-level message.
void reset_level(LogLevel level)
Reset the logger threshold level.
const std::complex< double > M_I
imaginary unit
const double eps_coupling
zero-tolerance for Wigner 3-j coupling coefficients
double wigner_3j(int j1, int j2, int j3, int m1, int m2, int m3)
Calculate Wigner 3-j symbol.
double gbytesMem
current memory usage in gibibytes
double size_in_gb(long long num)
Return size in gibibytes.
void update_maxmem()
Update the maximum memory usage estimate.
Logger logger
default logger (at NSET logging level)
float count_grid
number of grids
int count_cgrid
number of 3-d complex grids
void update_maxcntgrid()
Update the maximum 3-d grid counts.
double calc_coupling_coeff_3pt(int ell1, int ell2, int ELL, int m1, int m2, int M)
Calculate the coupling coefficient for spherical-harmonic components of full three-point statistics.
double calc_bispec_normalisation_from_particles(ParticleCatalogue &particles, double alpha=1.)
Calculate particle-based bispectrum normalisation.
std::complex< double > calc_ylm_wgtd_shotnoise_amp_for_bispec(ParticleCatalogue &particles_data, ParticleCatalogue &particles_rand, LineOfSight *los_data, LineOfSight *los_rand, double alpha, int ell, int m)
Calculate bispectrum shot noise amplitude weighted by reduced spherical harmonics.
trv::ThreePCFMeasurements compute_3pcf_in_gpp_box(ParticleCatalogue &catalogue_data, trv::ParameterSet ¶ms, trv::Binning &rbinning, double norm_factor)
Compute three-point correlation function in a periodic box in the global plane-parallel approximation...
trv::BispecMeasurements compute_bispec_in_gpp_box(ParticleCatalogue &catalogue_data, trv::ParameterSet ¶ms, trv::Binning kbinning, double norm_factor)
Compute bispectrum in a periodic box in the global plane-parallel approximation.
trv::ThreePCFWindowMeasurements compute_3pcf_window(ParticleCatalogue &catalogue_rand, LineOfSight *los_rand, trv::ParameterSet ¶ms, trv::Binning &rbinning, double alpha, double norm_factor, bool wide_angle=false)
Compute three-point correlation function window from a random catalogue.
double calc_bispec_normalisation_from_mesh(ParticleCatalogue &particles, trv::ParameterSet ¶ms, double alpha=1.)
Calculate mesh-based bispectrum normalisation.
trv::BispecMeasurements compute_bispec(ParticleCatalogue &catalogue_data, ParticleCatalogue &catalogue_rand, LineOfSight *los_data, LineOfSight *los_rand, trv::ParameterSet ¶ms, trv::Binning &kbinning, double norm_factor)
Compute bispectrum from paired survey-type catalogues.
void validate_multipole_coupling(trv::ParameterSet ¶ms)
Validate three-point correlator multipoles are non-vanishing.
trv::ThreePCFMeasurements compute_3pcf(ParticleCatalogue &catalogue_data, ParticleCatalogue &catalogue_rand, LineOfSight *los_data, LineOfSight *los_rand, trv::ParameterSet ¶ms, trv::Binning &rbinning, double norm_factor)
Compute three-point correlation function from paired survey-type catalogues.
std::vector< std::complex< double > > bk_raw
bispectrum raw measurements (with normalisation and shot noise)
std::vector< double > k2_eff
second effective wavenumber in bins
std::vector< int > nmodes_2
std::vector< std::complex< double > > bk_shot
bispectrum shot noise
std::vector< double > k1_bin
first central wavenumber in bins
std::vector< double > k1_eff
first effective wavenumber in bins
std::vector< double > k2_bin
second central wavenumber in bins
int dim
dimension of data vector
std::vector< int > nmodes_1
number of first wavevectors in bins
double pos[3]
3-d position vector
Spherical order triplet .
bool is_zeros()
Check if the spherical orders are all zeros.
SphericalOrderTriplet operator+(const SphericalOrderTriplet &other)
Return the sum with another spherical order triplet.
bool is_inverse(const SphericalOrderTriplet &other)
Check if another triplet is the additive inverse.
Three-point correlation function measurements.
std::vector< double > r2_bin
second central separation in bins
std::vector< int > npairs_1
number of first separation vectors in bins
std::vector< double > r1_bin
first central separation in bins
std::vector< std::complex< double > > zeta_shot
three-point correlation function shot noise
std::vector< double > r2_eff
std::vector< std::complex< double > > zeta_raw
std::vector< double > r1_eff
first effective separation in bins
std::vector< int > npairs_2
number of second separation vectors in bins
int dim
dimension of data vector
Three-point correlation function window measurements.
std::vector< std::complex< double > > zeta_shot
three-point correlation function window shot noise
std::vector< int > npairs_2
number of second separation vectors in bins
std::vector< int > npairs_1
number of first separation vectors in bins
std::vector< double > r1_eff
first effective separation in bins
std::vector< double > r2_eff
int dim
dimension of data vector
std::vector< double > r2_bin
second central separation in bins
std::vector< double > r1_bin
first central separation in bins
std::vector< std::complex< double > > zeta_raw
Three-point statistic computations.