44 this->
m1 + other.
m1, this->
m2 + other.
m2, this->
M + other.
M
46 return sph_order_triplet;
50 return (this->
m1 == 0) && (this->
m2 == 0) && (this->
M == 0);
55 (this->
m1 + other.
m1 == 0) &&
56 (this->
m2 + other.
m2 == 0) &&
57 (this->
M + other.
M == 0);
66 int ell1,
int ell2,
int ELL,
int m1,
int m2,
int M
68 return double(2*ell1 + 1) * double(2*ell2 + 1) * double(2*ELL + 1)
80 "Specified three-point correlator multipole "
81 "vanishes identically owing to zero-valued Wigner 3-j symbol."
85 "Specified three-point correlator multipole "
86 "vanishes identically owing to zero-valued Wigner 3-j symbol."
99 if (particles.
pdata ==
nullptr) {
109#if defined(__GNUC__) && !defined(__clang__)
110#pragma omp parallel for simd reduction(+:norm)
112#pragma omp parallel for reduction(+:norm)
115 for (
int pid = 0; pid < particles.
ntotal; pid++) {
116 norm += particles[pid].ws
117 * std::pow(particles[pid].nz, 2) * std::pow(particles[pid].wc, 3);
123 "Particle 'nz' values appear to be all zeros. "
124 "Check the input catalogue contains valid 'nz' field."
128 "Particle 'nz' values appear to be all zeros. "
129 "Check the input catalogue contains valid 'nz' field."
133 double norm_factor = 1. / (alpha * norm);
141 MeshField catalogue_mesh(params,
false,
"`catalogue_mesh`");
146 norm_factor /= std::pow(alpha, 3);
159 double alpha,
int ell,
int m
161 double sn_data_real = 0., sn_data_imag = 0.;
164#pragma omp parallel for reduction(+:sn_data_real, sn_data_imag)
166 for (
int pid = 0; pid < particles_data.
ntotal; pid++) {
168 los_data[pid].
pos[0], los_data[pid].
pos[1], los_data[pid].
pos[2]
174 std::complex<double> sn_part = ylm * std::pow(particles_data[pid].w, 3);
175 double sn_part_real = sn_part.real();
176 double sn_part_imag = sn_part.imag();
178 sn_data_real += sn_part_real;
179 sn_data_imag += sn_part_imag;
182 std::complex<double> sn_data(sn_data_real, sn_data_imag);
184 double sn_rand_real = 0., sn_rand_imag = 0.;
187#pragma omp parallel for reduction(+:sn_rand_real, sn_rand_imag)
189 for (
int pid = 0; pid < particles_rand.
ntotal; pid++) {
191 los_rand[pid].
pos[0], los_rand[pid].
pos[1], los_rand[pid].
pos[2]
197 std::complex<double> sn_part = ylm * std::pow(particles_rand[pid].w, 3);
198 double sn_part_real = sn_part.real();
199 double sn_part_imag = sn_part.imag();
201 sn_rand_real += sn_part_real;
202 sn_rand_imag += sn_part_imag;
205 std::complex<double> sn_rand(sn_rand_real, sn_rand_imag);
207 return sn_data + std::pow(alpha, 3) * sn_rand;
212 double alpha,
int ell,
int m
214 double sn_real = 0., sn_imag = 0.;
217#pragma omp parallel for reduction(+:sn_real, sn_imag)
219 for (
int pid = 0; pid < particles.
ntotal; pid++) {
220 double los_[3] = {los[pid].
pos[0], los[pid].
pos[1], los[pid].
pos[2]};
225 std::complex<double> sn_part = ylm * std::pow(particles[pid].w, 3);
226 double sn_part_real = sn_part.real();
227 double sn_part_imag = sn_part.imag();
229 sn_real += sn_part_real;
230 sn_imag += sn_part_imag;
233 std::complex<double> sn(sn_real, sn_imag);
235 return std::pow(alpha, 3) * sn;
258 "Computing bispectrum from paired survey-type catalogues..."
271 std::complex<double> factor_phase =
276 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
279 if (params.
shape ==
"off-diag") {
282 if (params.
shape ==
"full") {
285 if (params.
shape ==
"triu") {
290 "Three-point statistic form is not recognised: `form` = '%s'.",
295 "Three-point statistic form is not recognised: `form` = '%s'.",
300 int* nmodes1_dv =
new int[dv_dim]();
301 int* nmodes2_dv =
new int[dv_dim]();
302 double* k1bin_dv =
new double[dv_dim]();
303 double* k2bin_dv =
new double[dv_dim]();
304 double* k1eff_dv =
new double[dv_dim]();
305 double* k2eff_dv =
new double[dv_dim]();
306 std::complex<double>* bk_dv =
new std::complex<double>[dv_dim];
307 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
313#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
320 MeshField dn_00(params,
true,
"`dn_00`");
322 catalogue_data, catalogue_rand, los_data, los_rand, alpha, 0, 0
332 catalogue_data, catalogue_rand, los_data, los_rand, alpha, 0, 0
342 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
343 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
344 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
345 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
354 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
356 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
357 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
359 std::string flag_vanishing =
"true";
360 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
365 flag_vanishing =
"false";
369 if (flag_vanishing ==
"true") {
continue;}
388 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
392 std::string flag_redundant =
"false";
394 if (sph_order_current.
is_inverse(sph_order)) {
395 flag_redundant =
"true";
398 if (flag_redundant ==
"true") {
continue;}
416 double factor_mirror = sph_order_current.
is_zeros() ?
417 0. : std::pow(-1., params.
ELL);
418 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
422 int progbar_task_count = 4 + 3 * dv_dim;
423 std::stringstream progbar_name_ss;
425 <<
"component orders (" << m1_ <<
", " << m2_ <<
", " << M_ <<
")";
428 std::vector<float> progbar_nodes;
431 if (progbar_nodes.size() > 0) {
437 auto update_progbar = [&]() {
438 if (params.
progbar !=
"false") {
454 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
462 MeshField F_lm_a(params,
true,
"`F_lm_a`");
463 MeshField F_lm_b(params,
true,
"`F_lm_b`");
465 if (params.
shape ==
"diag") {
466 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
469 double k_lower = kbinning.
bin_edges[ibin];
470 double k_upper = kbinning.
bin_edges[ibin + 1];
472 double k_eff_a_, k_eff_b_;
473 int nmodes_a_, nmodes_b_;
476 dn_00, ylm_k_a, k_lower, k_upper, k_eff_a_, nmodes_a_
479 dn_00, ylm_k_b, k_lower, k_upper, k_eff_b_, nmodes_b_
483 if (count_terms == 0) {
486 k1eff_dv[idx_dv] = k_eff_a_;
487 k2eff_dv[idx_dv] = k_eff_b_;
488 nmodes1_dv[idx_dv] = nmodes_a_;
489 nmodes2_dv[idx_dv] = nmodes_b_;
493 double bk_comp_real = 0., bk_comp_imag = 0.;
496#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
498 for (
long long gid = 0; gid < params.
nmesh; gid++) {
499 std::complex<double> F_lm_a_gridpt(
500 F_lm_a[gid][0], F_lm_a[gid][1]
502 std::complex<double> F_lm_b_gridpt(
503 F_lm_b[gid][0], F_lm_b[gid][1]
505 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
506 std::complex<double> bk_gridpt =
507 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
509 bk_comp_real += bk_gridpt.real();
510 bk_comp_imag += bk_gridpt.imag();
513 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
515 bk_dv[idx_dv] += coupling * vol_cell * (
516 bk_component + factor_mirror * std::conj(bk_component)
521 if (params.
shape ==
"off-diag") {
522 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
523 int ibin_row, ibin_col;
526 ibin_col = idx_dv + std::abs(params.
idx_bin);
528 ibin_row = idx_dv + std::abs(params.
idx_bin);
532 double k_lower_a = kbinning.
bin_edges[ibin_row];
533 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
534 double k_lower_b = kbinning.
bin_edges[ibin_col];
535 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
537 double k_eff_a_, k_eff_b_;
538 int nmodes_a_, nmodes_b_;
541 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
544 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
548 if (count_terms == 0) {
551 k1eff_dv[idx_dv] = k_eff_a_;
552 k2eff_dv[idx_dv] = k_eff_b_;
553 nmodes1_dv[idx_dv] = nmodes_a_;
554 nmodes2_dv[idx_dv] = nmodes_b_;
558 double bk_comp_real = 0., bk_comp_imag = 0.;
561#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
563 for (
long long gid = 0; gid < params.
nmesh; gid++) {
564 std::complex<double> F_lm_a_gridpt(
565 F_lm_a[gid][0], F_lm_a[gid][1]
567 std::complex<double> F_lm_b_gridpt(
568 F_lm_b[gid][0], F_lm_b[gid][1]
570 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
571 std::complex<double> bk_gridpt =
572 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
574 bk_comp_real += bk_gridpt.real();
575 bk_comp_imag += bk_gridpt.imag();
578 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
580 bk_dv[idx_dv] += coupling * vol_cell * (
581 bk_component + factor_mirror * std::conj(bk_component)
586 if (params.
shape ==
"row") {
589 double k_lower_a = kbinning.
bin_edges[ibin_row];
590 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
596 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
599 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
600 int ibin_col = idx_dv;
602 double k_lower_b = kbinning.
bin_edges[ibin_col];
603 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
609 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
613 if (count_terms == 0) {
616 k1eff_dv[idx_dv] = k_eff_a_;
617 k2eff_dv[idx_dv] = k_eff_b_;
618 nmodes1_dv[idx_dv] = nmodes_a_;
619 nmodes2_dv[idx_dv] = nmodes_b_;
623 double bk_comp_real = 0., bk_comp_imag = 0.;
626#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
628 for (
long long gid = 0; gid < params.
nmesh; gid++) {
629 std::complex<double> F_lm_a_gridpt(
630 F_lm_a[gid][0], F_lm_a[gid][1]
632 std::complex<double> F_lm_b_gridpt(
633 F_lm_b[gid][0], F_lm_b[gid][1]
635 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
636 std::complex<double> bk_gridpt =
637 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
639 bk_comp_real += bk_gridpt.real();
640 bk_comp_imag += bk_gridpt.imag();
643 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
645 bk_dv[idx_dv] += coupling * vol_cell * (
646 bk_component + factor_mirror * std::conj(bk_component)
651 if (params.
shape ==
"full") {
652 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
653 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
654 int idx_dv = idx_row * params.
num_bins + idx_col;
656 double k_lower_a = kbinning.
bin_edges[idx_row];
657 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
658 double k_lower_b = kbinning.
bin_edges[idx_col];
659 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
661 double k_eff_a_, k_eff_b_;
662 int nmodes_a_, nmodes_b_;
665 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
668 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
672 if (count_terms == 0) {
675 k1eff_dv[idx_dv] = k_eff_a_;
676 k2eff_dv[idx_dv] = k_eff_b_;
677 nmodes1_dv[idx_dv] = nmodes_a_;
678 nmodes2_dv[idx_dv] = nmodes_b_;
682 double bk_comp_real = 0., bk_comp_imag = 0.;
685#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
687 for (
long long gid = 0; gid < params.
nmesh; gid++) {
688 std::complex<double> F_lm_a_gridpt(
689 F_lm_a[gid][0], F_lm_a[gid][1]
691 std::complex<double> F_lm_b_gridpt(
692 F_lm_b[gid][0], F_lm_b[gid][1]
694 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
695 std::complex<double> bk_gridpt =
696 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
698 bk_comp_real += bk_gridpt.real();
699 bk_comp_imag += bk_gridpt.imag();
702 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
704 bk_dv[idx_dv] += coupling * vol_cell * (
705 bk_component + factor_mirror * std::conj(bk_component)
711 if (params.
shape ==
"triu") {
712 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
713 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
714 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
715 + (idx_col - idx_row);
717 double k_lower_a = kbinning.
bin_edges[idx_row];
718 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
719 double k_lower_b = kbinning.
bin_edges[idx_col];
720 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
722 double k_eff_a_, k_eff_b_;
723 int nmodes_a_, nmodes_b_;
726 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
729 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
733 if (count_terms == 0) {
736 k1eff_dv[idx_dv] = k_eff_a_;
737 k2eff_dv[idx_dv] = k_eff_b_;
738 nmodes1_dv[idx_dv] = nmodes_a_;
739 nmodes2_dv[idx_dv] = nmodes_b_;
743 double bk_comp_real = 0., bk_comp_imag = 0.;
746#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
748 for (
long long gid = 0; gid < params.
nmesh; gid++) {
749 std::complex<double> F_lm_a_gridpt(
750 F_lm_a[gid][0], F_lm_a[gid][1]
752 std::complex<double> F_lm_b_gridpt(
753 F_lm_b[gid][0], F_lm_b[gid][1]
755 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
756 std::complex<double> bk_gridpt =
757 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
759 bk_comp_real += bk_gridpt.real();
760 bk_comp_imag += bk_gridpt.imag();
763 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
765 bk_dv[idx_dv] += coupling * vol_cell * (
766 bk_component + factor_mirror * std::conj(bk_component)
777 MeshField dn_LM_for_sn(params,
true,
"`dn_LM_for_sn`");
781 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
788 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
795 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
799 if (params.
ell1 == 0 && params.
ell2 == 0) {
802 std::complex<double> S_ijk = coupling * Sbar_LM;
803 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
804 sn_dv[idx_dv] += S_ijk;
808 if (params.
ell2 == 0) {
811 dn_00_for_sn, N_LM, Sbar_LM, params.
ell1, m1_, kbinning
814 if (params.
shape ==
"diag") {
815 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
817 std::complex<double> S_i_jk = coupling * (
818 stats_sn.
pk[ibin] - stats_sn.
sn[ibin]
820 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
824 if (params.
shape ==
"off-diag") {
825 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
830 ibin_row = idx_dv + std::abs(params.
idx_bin);
832 std::complex<double> S_i_jk = coupling * (
833 stats_sn.
pk[ibin_row] - stats_sn.
sn[ibin_row]
835 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
839 if (params.
shape ==
"row") {
840 std::complex<double> S_i_jk_row_ = coupling * (
843 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
845 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
849 if (params.
shape ==
"full") {
850 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
851 std::complex<double> S_i_jk_row_ = coupling * (
852 stats_sn.
pk[idx_row] - stats_sn.
sn[idx_row]
854 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
855 int idx_dv = idx_row * params.
num_bins + idx_col;
857 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
862 if (params.
shape ==
"triu") {
863 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
864 std::complex<double> S_i_jk_row_ = coupling * (
865 stats_sn.
pk[idx_row] - stats_sn.
sn[idx_row]
867 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++)
869 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
870 + (idx_col - idx_row);
872 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
878 if (params.
ell1 == 0) {
881 dn_00_for_sn, N_LM, Sbar_LM, params.
ell2, m2_, kbinning
884 if (params.
shape ==
"diag") {
885 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
887 std::complex<double> S_ik_j_ki = coupling * (
888 stats_sn.
pk[ibin] - stats_sn.
sn[ibin]
891 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
895 if (params.
shape ==
"off-diag") {
896 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
899 ibin_col = idx_dv + params.
idx_bin;
903 std::complex<double> S_ik_j_ki = coupling * (
904 stats_sn.
pk[ibin_col] - stats_sn.
sn[ibin_col]
907 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
911 if (params.
shape ==
"row") {
912 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
913 int ibin_col = idx_dv;
914 std::complex<double> S_ik_j_ki = coupling * (
915 stats_sn.
pk[ibin_col] - stats_sn.
sn[ibin_col]
918 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
922 if (params.
shape ==
"full") {
923 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
924 std::complex<double> S_ik_j_ki_col_ = coupling * (
925 stats_sn.
pk[idx_col] - stats_sn.
sn[idx_col]
927 for (
int idx_row = 0; idx_row <= params.
num_bins; idx_row++) {
928 int idx_dv = idx_row * params.
num_bins + idx_col;
930 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
935 if (params.
shape ==
"triu") {
936 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
937 std::complex<double> S_ik_j_ki_col_ = coupling * (
938 stats_sn.
pk[idx_col] - stats_sn.
sn[idx_col]
940 for (
int idx_row = 0; idx_row <= idx_col; idx_row++) {
941 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
942 + (idx_col - idx_row);
944 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
950 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
951 double k_a = k1eff_dv[idx_dv];
952 double k_b = k2eff_dv[idx_dv];
954 std::complex<double> S_ij_k = coupling
956 dn_LM_for_sn, N_00, ylm_r_a, ylm_r_b, sj_a, sj_b,
961 sn_dv[idx_dv] += factor_phase * (
962 S_ij_k + factor_mirror_w3j * std::conj(S_ij_k)
966 sph_orders_computed.push_back(sph_order_current);
970 "Bispectrum term computed at orders (m₁, m₂, M) = ±(%d, %d, %d).",
983 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
984 bispec_out.
k1_bin.push_back(k1bin_dv[idx_dv]);
985 bispec_out.
k1_eff.push_back(k1eff_dv[idx_dv]);
986 bispec_out.
nmodes_1.push_back(nmodes1_dv[idx_dv]);
987 bispec_out.
k2_bin.push_back(k2bin_dv[idx_dv]);
988 bispec_out.
k2_eff.push_back(k2eff_dv[idx_dv]);
989 bispec_out.
nmodes_2.push_back(nmodes2_dv[idx_dv]);
990 bispec_out.
bk_raw.push_back(norm_factor * bk_dv[idx_dv]);
991 bispec_out.
bk_shot.push_back(norm_factor * sn_dv[idx_dv]);
993 bispec_out.
dim = dv_dim;
995 delete[] nmodes1_dv;
delete[] nmodes2_dv;
996 delete[] k1bin_dv;
delete[] k2bin_dv;
997 delete[] k1eff_dv;
delete[] k2eff_dv;
998 delete[] bk_dv;
delete[] sn_dv;
1007 "... computed bispectrum from paired survey-type catalogues."
1024 "Computing three-point correlation function "
1025 "from paired survey-type catalogues..."
1038 std::complex<double> factor_phase =
1040 double factor_parity = std::pow(-1., params.
ell1 + params.
ell2);
1044 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
1047 if (params.
shape ==
"off-diag") {
1050 if (params.
shape ==
"full") {
1053 if (params.
shape ==
"triu") {
1058 "Three-point statistic form is not recognised: `form` = '%s'.",
1063 "Three-point statistic form is not recognised: `form` = '%s'.",
1068 int* npairs1_dv =
new int[dv_dim]();
1069 int* npairs2_dv =
new int[dv_dim]();
1070 double* r1bin_dv =
new double[dv_dim]();
1071 double* r2bin_dv =
new double[dv_dim]();
1072 double* r1eff_dv =
new double[dv_dim]();
1073 double* r2eff_dv =
new double[dv_dim]();
1074 std::complex<double>* zeta_dv =
new std::complex<double>[dv_dim];
1075 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
1081#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
1083 fftw_init_threads();
1088 MeshField dn_00(params,
true,
"`dn_00`");
1090 catalogue_data, catalogue_rand, los_data, los_rand, alpha, 0, 0
1098 catalogue_data, catalogue_rand, los_data, los_rand, alpha, 0, 0
1108 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
1109 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
1110 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
1111 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
1120 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
1121 int count_terms = 0;
1122 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
1123 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
1125 std::string flag_vanishing =
"true";
1126 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
1128 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
1131 flag_vanishing =
"false";
1135 if (flag_vanishing ==
"true") {
continue;}
1154 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
1158 std::string flag_redundant =
"false";
1160 if (sph_order_current.
is_inverse(sph_order)) {
1161 flag_redundant =
"true";
1164 if (flag_redundant ==
"true") {
continue;}
1168 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
1180 double factor_mirror = sph_order_current.
is_zeros() ?
1181 0. : std::pow(-1., params.
ELL);
1182 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
1186 int progbar_task_count = 4 + 2 * dv_dim;
1187 std::stringstream progbar_name_ss;
1189 <<
"component orders (" << m1_ <<
", " << m2_ <<
", " << M_ <<
")";
1192 std::vector<float> progbar_nodes;
1195 if (progbar_nodes.size() > 0) {
1201 auto update_progbar = [&]() {
1202 if (params.
progbar !=
"false") {
1216 MeshField dn_LM_for_sn(params,
true,
"`dn_LM_for_sn`");
1220 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
1227 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
1232 dn_LM_for_sn, N_00, ylm_r_a, ylm_r_b, Sbar_LM, rbinning
1237 if (params.
shape ==
"diag") {
1238 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1240 sn_dv[idx_dv] += coupling * factor_parity * (
1242 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
1247 if (params.
shape ==
"off-diag" && params.
idx_bin == 0) {
1249 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1251 sn_dv[idx_dv] += coupling * factor_parity * (
1253 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
1258 if (params.
shape ==
"row") {
1259 sn_dv[params.
idx_bin] += coupling * factor_parity * (
1261 + factor_mirror_w3j * std::conj(stats_sn.
xi[params.
idx_bin])
1265 if (params.
shape ==
"full") {
1266 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1268 int idx_dv = idx_row * params.
num_bins + idx_row;
1269 sn_dv[idx_dv] += coupling * factor_parity * (
1270 stats_sn.
xi[idx_row]
1271 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
1276 if (params.
shape ==
"triu") {
1277 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1279 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2;
1280 sn_dv[idx_dv] += coupling * factor_parity * (
1281 stats_sn.
xi[idx_row]
1282 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
1288 if (count_terms == 0) {
1289 if (params.
shape ==
"diag") {
1290 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1295 r1eff_dv[idx_dv] = stats_sn.
r[ibin];
1296 r2eff_dv[idx_dv] = stats_sn.
r[ibin];
1297 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin];
1298 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin];
1302 if (params.
shape ==
"off-diag") {
1303 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1304 int ibin_row, ibin_col;
1307 ibin_col = idx_dv + std::abs(params.
idx_bin);
1309 ibin_row = idx_dv + std::abs(params.
idx_bin);
1313 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
1314 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
1315 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
1316 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
1317 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
1318 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
1322 if (params.
shape ==
"row") {
1323 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1324 int ibin_row = params.
idx_bin;
1325 int ibin_col = idx_dv;
1327 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
1328 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
1329 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
1330 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
1331 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
1332 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
1336 if (params.
shape ==
"full") {
1337 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1338 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
1339 int idx_dv = idx_row * params.
num_bins + idx_col;
1343 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
1344 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
1345 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
1346 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
1351 if (params.
shape ==
"triu") {
1352 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1353 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++)
1355 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
1356 + (idx_col - idx_row);
1360 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
1361 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
1362 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
1363 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
1376 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
1384 MeshField F_lm_a(params,
true,
"`F_lm_a`");
1385 MeshField F_lm_b(params,
true,
"`F_lm_b`");
1387 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1388 double r_a = r1eff_dv[idx_dv];
1390 dn_00, ylm_k_a, sj_a, r_a
1393 double r_b = r2eff_dv[idx_dv];
1395 dn_00, ylm_k_b, sj_b, r_b
1400 double zeta_comp_real = 0., zeta_comp_imag = 0.;
1403#pragma omp parallel for reduction(+:zeta_comp_real, zeta_comp_imag)
1405 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1406 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
1407 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
1408 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
1409 std::complex<double> zeta_gridpt =
1410 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
1412 zeta_comp_real += zeta_gridpt.real();
1413 zeta_comp_imag += zeta_gridpt.imag();
1416 std::complex<double> zeta_component(zeta_comp_real, zeta_comp_imag);
1418 zeta_dv[idx_dv] += coupling * vol_cell * factor_phase * (
1419 zeta_component + factor_mirror * std::conj(zeta_component)
1423 sph_orders_computed.push_back(sph_order_current);
1427 "Three-point correlation function term computed at orders "
1428 "(m₁, m₂, M) = ±(%d, %d, %d).",
1441 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1442 threepcf_out.
r1_bin.push_back(r1bin_dv[idx_dv]);
1443 threepcf_out.
r1_eff.push_back(r1eff_dv[idx_dv]);
1444 threepcf_out.
npairs_1.push_back(npairs1_dv[idx_dv]);
1445 threepcf_out.
r2_bin.push_back(r2bin_dv[idx_dv]);
1446 threepcf_out.
r2_eff.push_back(r2eff_dv[idx_dv]);
1447 threepcf_out.
npairs_2.push_back(npairs2_dv[idx_dv]);
1448 threepcf_out.
zeta_raw.push_back(norm_factor * zeta_dv[idx_dv]);
1449 threepcf_out.
zeta_shot.push_back(norm_factor * sn_dv[idx_dv]);
1451 threepcf_out.
dim = dv_dim;
1453 delete[] npairs1_dv;
delete[] npairs2_dv;
1454 delete[] r1bin_dv;
delete[] r2bin_dv;
1455 delete[] r1eff_dv;
delete[] r2eff_dv;
1456 delete[] zeta_dv;
delete[] sn_dv;
1465 "... computed three-point correlation function "
1466 "from paired survey-type catalogues."
1470 return threepcf_out;
1482 "Computing bispectrum from a periodic-box simulation-type catalogue "
1483 "in the global plane-parallel approximation..."
1494 std::complex<double> factor_phase =
1499 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
1502 if (params.
shape ==
"off-diag") {
1505 if (params.
shape ==
"full") {
1508 if (params.
shape ==
"triu") {
1513 "Three-point statistic form is not recognised: `form` = '%s'.",
1518 "Three-point statistic form is not recognised: `form` = '%s'.",
1523 int* nmodes1_dv =
new int[dv_dim]();
1524 int* nmodes2_dv =
new int[dv_dim]();
1525 double* k1bin_dv =
new double[dv_dim]();
1526 double* k2bin_dv =
new double[dv_dim]();
1527 double* k1eff_dv =
new double[dv_dim]();
1528 double* k2eff_dv =
new double[dv_dim]();
1529 std::complex<double>* bk_dv =
new std::complex<double>[dv_dim];
1530 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
1536#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
1538 fftw_init_threads();
1543 MeshField dn_00(params,
true,
"`dn_00`");
1566 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
1567 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
1568 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
1569 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
1578 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
1579 int count_terms = 0;
1580 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
1581 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
1589 std::string flag_redundant =
"false";
1591 if (sph_order_current.
is_inverse(sph_order)) {
1592 flag_redundant =
"true";
1595 if (flag_redundant ==
"true") {
continue;}
1599 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
1613 double factor_mirror = sph_order_current.
is_zeros() ?
1614 0. : std::pow(-1., params.
ELL);
1615 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
1622 trvm::SphericalHarmonicCalculator
1623 ::store_reduced_spherical_harmonic_in_fourier_space(
1636 int progbar_task_count = 2 + 3 * dv_dim;
1637 std::stringstream progbar_name_ss;
1639 <<
"component orders (" << m1_ <<
", " << m2_ <<
", " << M_ <<
")";
1642 std::vector<float> progbar_nodes;
1645 if (progbar_nodes.size() > 0) {
1651 auto update_progbar = [&]() {
1652 if (params.
progbar !=
"false") {
1672 MeshField F_lm_a(params,
true,
"`F_lm_a`");
1673 MeshField F_lm_b(params,
true,
"`F_lm_b`");
1675 if (params.
shape ==
"diag") {
1676 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1679 double k_lower = kbinning.
bin_edges[ibin];
1680 double k_upper = kbinning.
bin_edges[ibin + 1];
1682 double k_eff_a_, k_eff_b_;
1683 int nmodes_a_, nmodes_b_;
1686 dn_00, ylm_k_a, k_lower, k_upper, k_eff_a_, nmodes_a_
1689 dn_00, ylm_k_b, k_lower, k_upper, k_eff_b_, nmodes_b_
1693 if (count_terms == 0) {
1696 k1eff_dv[idx_dv] = k_eff_a_;
1697 k2eff_dv[idx_dv] = k_eff_b_;
1698 nmodes1_dv[idx_dv] = nmodes_a_;
1699 nmodes2_dv[idx_dv] = nmodes_b_;
1703 double bk_comp_real = 0., bk_comp_imag = 0.;
1706#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1708 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1709 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
1710 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
1711 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1712 std::complex<double> bk_gridpt =
1713 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1715 bk_comp_real += bk_gridpt.real();
1716 bk_comp_imag += bk_gridpt.imag();
1719 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1721 bk_dv[idx_dv] += coupling * vol_cell * (
1722 bk_component + factor_mirror * std::conj(bk_component)
1727 if (params.
shape ==
"off-diag") {
1728 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1729 int ibin_row, ibin_col;
1732 ibin_col = idx_dv + std::abs(params.
idx_bin);
1734 ibin_row = idx_dv + std::abs(params.
idx_bin);
1738 double k_lower_a = kbinning.
bin_edges[ibin_row];
1739 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
1740 double k_lower_b = kbinning.
bin_edges[ibin_col];
1741 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
1743 double k_eff_a_, k_eff_b_;
1744 int nmodes_a_, nmodes_b_;
1747 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
1750 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
1754 if (count_terms == 0) {
1755 k1bin_dv[idx_dv] = kbinning.
bin_centres[ibin_row];
1756 k2bin_dv[idx_dv] = kbinning.
bin_centres[ibin_col];
1757 k1eff_dv[idx_dv] = k_eff_a_;
1758 k2eff_dv[idx_dv] = k_eff_b_;
1759 nmodes1_dv[idx_dv] = nmodes_a_;
1760 nmodes2_dv[idx_dv] = nmodes_b_;
1764 double bk_comp_real = 0., bk_comp_imag = 0.;
1767#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1769 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1770 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
1771 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
1772 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1773 std::complex<double> bk_gridpt =
1774 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1776 bk_comp_real += bk_gridpt.real();
1777 bk_comp_imag += bk_gridpt.imag();
1780 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1782 bk_dv[idx_dv] += coupling * vol_cell * (
1783 bk_component + factor_mirror * std::conj(bk_component)
1788 if (params.
shape ==
"row") {
1789 int ibin_row = params.
idx_bin;
1791 double k_lower_a = kbinning.
bin_edges[ibin_row];
1792 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
1798 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
1801 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1802 int ibin_col = idx_dv;
1804 double k_lower_b = kbinning.
bin_edges[ibin_col];
1805 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
1811 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
1815 if (count_terms == 0) {
1816 k1bin_dv[idx_dv] = kbinning.
bin_centres[ibin_row];
1817 k2bin_dv[idx_dv] = kbinning.
bin_centres[ibin_col];
1818 k1eff_dv[idx_dv] = k_eff_a_;
1819 k2eff_dv[idx_dv] = k_eff_b_;
1820 nmodes1_dv[idx_dv] = nmodes_a_;
1821 nmodes2_dv[idx_dv] = nmodes_b_;
1825 double bk_comp_real = 0., bk_comp_imag = 0.;
1828#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1830 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1831 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
1832 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
1833 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1834 std::complex<double> bk_gridpt =
1835 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1837 bk_comp_real += bk_gridpt.real();
1838 bk_comp_imag += bk_gridpt.imag();
1841 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1843 bk_dv[idx_dv] += coupling * vol_cell * (
1844 bk_component + factor_mirror * std::conj(bk_component)
1849 if (params.
shape ==
"full") {
1850 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1851 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
1852 int idx_dv = idx_row * params.
num_bins + idx_col;
1854 double k_lower_a = kbinning.
bin_edges[idx_row];
1855 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
1856 double k_lower_b = kbinning.
bin_edges[idx_col];
1857 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
1859 double k_eff_a_, k_eff_b_;
1860 int nmodes_a_, nmodes_b_;
1863 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
1866 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
1870 if (count_terms == 0) {
1873 k1eff_dv[idx_dv] = k_eff_a_;
1874 k2eff_dv[idx_dv] = k_eff_b_;
1875 nmodes1_dv[idx_dv] = nmodes_a_;
1876 nmodes2_dv[idx_dv] = nmodes_b_;
1880 double bk_comp_real = 0., bk_comp_imag = 0.;
1883#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1885 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1886 std::complex<double> F_lm_a_gridpt(
1887 F_lm_a[gid][0], F_lm_a[gid][1]
1889 std::complex<double> F_lm_b_gridpt(
1890 F_lm_b[gid][0], F_lm_b[gid][1]
1892 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1893 std::complex<double> bk_gridpt =
1894 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1896 bk_comp_real += bk_gridpt.real();
1897 bk_comp_imag += bk_gridpt.imag();
1900 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1902 bk_dv[idx_dv] += coupling * vol_cell * (
1903 bk_component + factor_mirror * std::conj(bk_component)
1909 if (params.
shape ==
"triu") {
1910 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
1911 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
1912 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
1913 + (idx_col - idx_row);
1915 double k_lower_a = kbinning.
bin_edges[idx_row];
1916 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
1917 double k_lower_b = kbinning.
bin_edges[idx_col];
1918 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
1920 double k_eff_a_, k_eff_b_;
1921 int nmodes_a_, nmodes_b_;
1924 dn_00, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
1927 dn_00, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
1931 if (count_terms == 0) {
1934 k1eff_dv[idx_dv] = k_eff_a_;
1935 k2eff_dv[idx_dv] = k_eff_b_;
1936 nmodes1_dv[idx_dv] = nmodes_a_;
1937 nmodes2_dv[idx_dv] = nmodes_b_;
1941 double bk_comp_real = 0., bk_comp_imag = 0.;
1944#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
1946 for (
long long gid = 0; gid < params.
nmesh; gid++) {
1947 std::complex<double> F_lm_a_gridpt(
1948 F_lm_a[gid][0], F_lm_a[gid][1]
1950 std::complex<double> F_lm_b_gridpt(
1951 F_lm_b[gid][0], F_lm_b[gid][1]
1953 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
1954 std::complex<double> bk_gridpt =
1955 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
1957 bk_comp_real += bk_gridpt.real();
1958 bk_comp_imag += bk_gridpt.imag();
1961 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
1963 bk_dv[idx_dv] += coupling * vol_cell * (
1964 bk_component + factor_mirror * std::conj(bk_component)
1977 std::complex<double> Sbar_LM =
1978 double(catalogue_data.
ntotal);
1979 std::complex<double> Sbar_L0 = Sbar_LM;
1981 if (params.
ell1 == 0 && params.
ell2 == 0) {
1982 std::complex<double> S_ijk = coupling * Sbar_LM;
1983 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1984 sn_dv[idx_dv] += S_ijk;
1988 if (params.
ell2 == 0) {
1991 dn_00_for_sn, N_L0, Sbar_LM, params.
ell1, m1_, kbinning
1994 if (params.
shape ==
"diag") {
1995 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
1997 std::complex<double> S_i_jk = coupling * (
1998 stats_sn.
pk[ibin] - stats_sn.
sn[ibin]
2000 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
2004 if (params.
shape ==
"off-diag") {
2005 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2010 ibin_row = idx_dv + std::abs(params.
idx_bin);
2012 std::complex<double> S_i_jk = coupling * (
2013 stats_sn.
pk[ibin_row] - stats_sn.
sn[ibin_row]
2015 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
2019 if (params.
shape ==
"row") {
2020 std::complex<double> S_i_jk_row_ = coupling * (
2023 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2025 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
2029 if (params.
shape ==
"full") {
2030 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2031 std::complex<double> S_i_jk_row_ = coupling * (
2032 stats_sn.
pk[idx_row] - stats_sn.
sn[idx_row]
2034 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2035 int idx_dv = idx_row * params.
num_bins + idx_col;
2037 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
2042 if (params.
shape ==
"triu") {
2043 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2044 std::complex<double> S_i_jk_row_ = coupling * (
2045 stats_sn.
pk[idx_row] - stats_sn.
sn[idx_row]
2047 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
2048 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
2049 + (idx_col - idx_row);
2051 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
2057 if (params.
ell1 == 0) {
2060 dn_00_for_sn, N_L0, Sbar_LM, params.
ell2, m2_, kbinning
2063 if (params.
shape ==
"diag") {
2064 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2066 std::complex<double> S_ik_j_ki = coupling * (
2067 stats_sn.
pk[ibin] - stats_sn.
sn[ibin]
2069 sn_dv[idx_dv] += S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
2073 if (params.
shape ==
"off-diag") {
2074 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2077 ibin_col = idx_dv + params.
idx_bin;
2081 std::complex<double> S_ik_j_ki = coupling * (
2082 stats_sn.
pk[ibin_col] - stats_sn.
sn[ibin_col]
2084 sn_dv[idx_dv] += S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
2088 if (params.
shape ==
"row") {
2089 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2090 int ibin_col = idx_dv;
2091 std::complex<double> S_ik_j_ki = coupling * (
2092 stats_sn.
pk[ibin_col] - stats_sn.
sn[ibin_col]
2094 sn_dv[idx_dv] += S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
2098 if (params.
shape ==
"full") {
2099 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2100 std::complex<double> S_ik_j_ki_col_ = coupling * (
2101 stats_sn.
pk[idx_col] - stats_sn.
sn[idx_col]
2103 for (
int idx_row = 0; idx_row <= params.
num_bins; idx_row++) {
2104 int idx_dv = idx_row * params.
num_bins + idx_col;
2106 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
2111 if (params.
shape ==
"triu") {
2112 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2113 std::complex<double> S_ik_j_ki_col_ = coupling * (
2114 stats_sn.
pk[idx_col] - stats_sn.
sn[idx_col]
2116 for (
int idx_row = 0; idx_row <= idx_col; idx_row++) {
2117 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
2118 + (idx_col - idx_row);
2120 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
2126 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2127 double k_a = k1eff_dv[idx_dv];
2128 double k_b = k2eff_dv[idx_dv];
2130 std::complex<double> S_ij_k = coupling
2132 dn_L0_for_sn, N_00, ylm_r_a, ylm_r_b, sj_a, sj_b,
2137 sn_dv[idx_dv] += factor_phase * (
2138 S_ij_k + factor_mirror_w3j * std::conj(S_ij_k)
2142 sph_orders_computed.push_back(sph_order_current);
2146 "Bispectrum term computed at orders (m₁, m₂, M) = ±(%d, %d, 0).",
2158 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2159 bispec_out.
k1_bin.push_back(k1bin_dv[idx_dv]);
2160 bispec_out.
k1_eff.push_back(k1eff_dv[idx_dv]);
2161 bispec_out.
nmodes_1.push_back(nmodes1_dv[idx_dv]);
2162 bispec_out.
k2_bin.push_back(k2bin_dv[idx_dv]);
2163 bispec_out.
k2_eff.push_back(k2eff_dv[idx_dv]);
2164 bispec_out.
nmodes_2.push_back(nmodes2_dv[idx_dv]);
2165 bispec_out.
bk_raw.push_back(norm_factor * bk_dv[idx_dv]);
2166 bispec_out.
bk_shot.push_back(norm_factor * sn_dv[idx_dv]);
2168 bispec_out.
dim = dv_dim;
2170 delete[] nmodes1_dv;
delete[] nmodes2_dv;
2171 delete[] k1bin_dv;
delete[] k2bin_dv;
2172 delete[] k1eff_dv;
delete[] k2eff_dv;
2173 delete[] bk_dv;
delete[] sn_dv;
2182 "... computed bispectrum from a periodic-box simulation-type catalogue "
2183 "in the global plane-parallel approximation."
2199 "Computing three-point correlation function "
2200 "from a periodic-box simulation-type catalogue "
2201 "in the global plane-parallel approximation..."
2212 std::complex<double> factor_phase =
2214 double factor_parity = std::pow(-1., params.
ell1 + params.
ell2);
2218 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
2221 if (params.
shape ==
"off-diag") {
2224 if (params.
shape ==
"full") {
2227 if (params.
shape ==
"triu") {
2232 "Three-point statistic form is not recognised: `form` = '%s'.",
2237 "Three-point statistic form is not recognised: `form` = '%s'.",
2242 int* npairs1_dv =
new int[dv_dim]();
2243 int* npairs2_dv =
new int[dv_dim]();
2244 double* r1bin_dv =
new double[dv_dim]();
2245 double* r2bin_dv =
new double[dv_dim]();
2246 double* r1eff_dv =
new double[dv_dim]();
2247 double* r2eff_dv =
new double[dv_dim]();
2248 std::complex<double>* zeta_dv =
new std::complex<double>[dv_dim];
2249 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
2255#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
2257 fftw_init_threads();
2262 MeshField dn_00(params,
true,
"`dn_00`");
2280 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
2281 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
2282 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
2283 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
2292 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
2293 int count_terms = 0;
2294 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
2295 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
2303 std::string flag_redundant =
"false";
2305 if (sph_order_current.
is_inverse(sph_order)) {
2306 flag_redundant =
"true";
2309 if (flag_redundant ==
"true") {
continue;}
2313 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
2325 double factor_mirror = sph_order_current.
is_zeros() ?
2326 0. : std::pow(-1., params.
ELL);
2327 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
2348 int progbar_task_count = 3 + 2 * dv_dim;
2349 std::stringstream progbar_name_ss;
2351 <<
"component orders (" << m1_ <<
", " << m2_ <<
", " << M_ <<
")";
2354 std::vector<float> progbar_nodes;
2357 if (progbar_nodes.size() > 0) {
2363 auto update_progbar = [&]() {
2364 if (params.
progbar !=
"false") {
2380 std::complex<double> Sbar_L0 =
2381 double(catalogue_data.
ntotal);
2384 dn_L0_for_sn, N_00, ylm_r_a, ylm_r_b, Sbar_L0, rbinning
2389 if (params.
shape ==
"diag") {
2390 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2392 sn_dv[idx_dv] += coupling * factor_parity * (
2394 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
2399 if (params.
shape ==
"off-diag" && params.
idx_bin == 0) {
2401 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2403 sn_dv[idx_dv] += coupling * factor_parity * (
2405 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
2410 if (params.
shape ==
"row") {
2411 sn_dv[params.
idx_bin] += coupling * factor_parity * (
2413 + factor_mirror_w3j * std::conj(stats_sn.
xi[params.
idx_bin])
2417 if (params.
shape ==
"full") {
2418 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2420 int idx_dv = idx_row * params.
num_bins + idx_row;
2421 sn_dv[idx_dv] += coupling * factor_parity * (
2422 stats_sn.
xi[idx_row]
2423 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
2428 if (params.
shape ==
"triu") {
2429 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2431 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2;
2432 sn_dv[idx_dv] += coupling * factor_parity * (
2433 stats_sn.
xi[idx_row]
2434 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
2440 if (count_terms == 0) {
2441 if (params.
shape ==
"diag") {
2442 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2447 r1eff_dv[idx_dv] = stats_sn.
r[ibin];
2448 r2eff_dv[idx_dv] = stats_sn.
r[ibin];
2449 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin];
2450 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin];
2454 if (params.
shape ==
"off-diag") {
2455 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2456 int ibin_row, ibin_col;
2459 ibin_col = idx_dv + std::abs(params.
idx_bin);
2461 ibin_row = idx_dv + std::abs(params.
idx_bin);
2465 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
2466 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
2467 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
2468 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
2469 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
2470 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
2474 if (params.
shape ==
"row") {
2475 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2476 int ibin_row = params.
idx_bin;
2477 int ibin_col = idx_dv;
2479 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
2480 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
2481 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
2482 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
2483 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
2484 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
2488 if (params.
shape ==
"full") {
2489 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2490 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2491 int idx_dv = idx_row * params.
num_bins + idx_col;
2495 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
2496 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
2497 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
2498 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
2503 if (params.
shape ==
"triu") {
2504 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2505 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
2506 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
2507 + (idx_col - idx_row);
2511 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
2512 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
2513 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
2514 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
2532 MeshField F_lm_a(params,
true,
"`F_lm_a`");
2533 MeshField F_lm_b(params,
true,
"`F_lm_b`");
2535 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2536 double r_a = r1eff_dv[idx_dv];
2538 dn_00, ylm_k_a, sj_a, r_a
2541 double r_b = r2eff_dv[idx_dv];
2543 dn_00, ylm_k_b, sj_b, r_b
2548 double zeta_comp_real = 0., zeta_comp_imag = 0.;
2551#pragma omp parallel for reduction(+:zeta_comp_real, zeta_comp_imag)
2553 for (
long long gid = 0; gid < params.
nmesh; gid++) {
2554 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
2555 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
2556 std::complex<double> G_00_gridpt(G_00[gid][0], G_00[gid][1]);
2557 std::complex<double> zeta_gridpt =
2558 F_lm_a_gridpt * F_lm_b_gridpt * G_00_gridpt;
2560 zeta_comp_real += zeta_gridpt.real();
2561 zeta_comp_imag += zeta_gridpt.imag();
2564 std::complex<double> zeta_component(zeta_comp_real, zeta_comp_imag);
2566 zeta_dv[idx_dv] += coupling * vol_cell * factor_phase * (
2567 zeta_component + factor_mirror * std::conj(zeta_component)
2571 sph_orders_computed.push_back(sph_order_current);
2575 "Three-point correlation function term computed at orders "
2576 "(m₁, m₂, M) = ±(%d, %d, 0).",
2588 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2589 threepcf_out.
r1_bin.push_back(r1bin_dv[idx_dv]);
2590 threepcf_out.
r1_eff.push_back(r1eff_dv[idx_dv]);
2591 threepcf_out.
npairs_1.push_back(npairs1_dv[idx_dv]);
2592 threepcf_out.
r2_bin.push_back(r2bin_dv[idx_dv]);
2593 threepcf_out.
r2_eff.push_back(r2eff_dv[idx_dv]);
2594 threepcf_out.
npairs_2.push_back(npairs2_dv[idx_dv]);
2595 threepcf_out.
zeta_raw.push_back(norm_factor * zeta_dv[idx_dv]);
2596 threepcf_out.
zeta_shot.push_back(norm_factor * sn_dv[idx_dv]);
2598 threepcf_out.
dim = dv_dim;
2600 delete[] npairs1_dv;
delete[] npairs2_dv;
2601 delete[] r1bin_dv;
delete[] r2bin_dv;
2602 delete[] r1eff_dv;
delete[] r2eff_dv;
2603 delete[] zeta_dv;
delete[] sn_dv;
2612 "... computed three-point correlation function "
2613 "from a periodic-box simulation-type catalogue "
2614 "in the global plane-parallel approximation."
2618 return threepcf_out;
2624 double alpha,
double norm_factor,
bool wide_angle
2626 std::string msg_tag = wide_angle ?
"wide-angle corrections " :
"";
2632 "Computing three-point correlation function window %s"
2633 "from random catalogue...",
2645 std::complex<double> factor_phase =
2647 double factor_parity = std::pow(-1., params.
ell1 + params.
ell2);
2651 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
2654 if (params.
shape ==
"off-diag") {
2657 if (params.
shape ==
"full") {
2660 if (params.
shape ==
"triu") {
2665 "Three-point statistic form is not recognised: `form` = '%s'.",
2670 "Three-point statistic form is not recognised: `form` = '%s'.",
2675 int* npairs1_dv =
new int[dv_dim]();
2676 int* npairs2_dv =
new int[dv_dim]();
2677 double* r1bin_dv =
new double[dv_dim]();
2678 double* r2bin_dv =
new double[dv_dim]();
2679 double* r1eff_dv =
new double[dv_dim]();
2680 double* r2eff_dv =
new double[dv_dim]();
2681 std::complex<double>* zeta_dv =
new std::complex<double>[dv_dim];
2682 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
2688#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
2690 fftw_init_threads();
2711 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
2712 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
2713 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
2714 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
2723 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
2724 int count_terms = 0;
2725 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
2726 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
2728 std::string flag_vanishing =
"true";
2729 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
2731 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
2734 flag_vanishing =
"false";
2738 if (flag_vanishing ==
"true") {
continue;}
2757 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
2761 std::string flag_redundant =
"false";
2763 if (sph_order_current.
is_inverse(sph_order)) {
2764 flag_redundant =
"true";
2767 if (flag_redundant ==
"true") {
continue;}
2771 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
2783 double factor_mirror = sph_order_current.
is_zeros() ?
2784 0. : std::pow(-1., params.
ELL);
2785 double factor_mirror_w3j = sph_order_current.
is_zeros() ?
2789 int progbar_task_count = 4 + 2 * dv_dim;
2790 std::stringstream progbar_name_ss;
2792 <<
"component orders (" << m1_ <<
", " << m2_ <<
", " << M_ <<
")";
2795 std::vector<float> progbar_nodes;
2798 if (progbar_nodes.size() > 0) {
2804 auto update_progbar = [&]() {
2805 if (params.
progbar !=
"false") {
2819 MeshField n_LM_for_sn(params,
true,
"`n_LM_for_sn`");
2823 catalogue_rand, los_rand, alpha, params.
ELL, M_
2829 catalogue_rand, los_rand, alpha, params.
ELL, M_
2833 n_LM_for_sn, N_00, ylm_r_a, ylm_r_b, Sbar_LM, rbinning
2838 if (params.
shape ==
"diag") {
2839 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2841 sn_dv[idx_dv] += coupling * factor_parity * (
2843 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
2848 if (params.
shape ==
"off-diag" && params.
idx_bin == 0) {
2850 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2852 sn_dv[idx_dv] += coupling * factor_parity * (
2854 + factor_mirror_w3j * std::conj(stats_sn.
xi[ibin])
2859 if (params.
shape ==
"row") {
2860 sn_dv[params.
idx_bin] += coupling * factor_parity * (
2862 + factor_mirror_w3j * std::conj(stats_sn.
xi[params.
idx_bin])
2866 if (params.
shape ==
"full") {
2867 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2869 int idx_dv = idx_row * params.
num_bins + idx_row;
2870 sn_dv[idx_dv] += coupling * factor_parity * (
2871 stats_sn.
xi[idx_row]
2872 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
2877 if (params.
shape ==
"triu") {
2878 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2880 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2;
2881 sn_dv[idx_dv] += coupling * factor_parity * (
2882 stats_sn.
xi[idx_row]
2883 + factor_mirror_w3j * std::conj(stats_sn.
xi[idx_row])
2888 if (count_terms == 0) {
2889 if (params.
shape ==
"diag") {
2890 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2895 r1eff_dv[idx_dv] = stats_sn.
r[ibin];
2896 r2eff_dv[idx_dv] = stats_sn.
r[ibin];
2897 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin];
2898 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin];
2902 if (params.
shape ==
"off-diag") {
2903 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2904 int ibin_row, ibin_col;
2907 ibin_col = idx_dv + std::abs(params.
idx_bin);
2909 ibin_row = idx_dv + std::abs(params.
idx_bin);
2913 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
2914 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
2915 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
2916 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
2917 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
2918 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
2922 if (params.
shape ==
"row") {
2923 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2924 int ibin_row = params.
idx_bin;
2925 int ibin_col = idx_dv;
2927 r1bin_dv[idx_dv] = rbinning.
bin_centres[ibin_row];
2928 r2bin_dv[idx_dv] = rbinning.
bin_centres[ibin_col];
2929 r1eff_dv[idx_dv] = stats_sn.
r[ibin_row];
2930 r2eff_dv[idx_dv] = stats_sn.
r[ibin_col];
2931 npairs1_dv[idx_dv] = stats_sn.
npairs[ibin_row];
2932 npairs2_dv[idx_dv] = stats_sn.
npairs[ibin_col];
2936 if (params.
shape ==
"full") {
2937 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2938 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
2939 int idx_dv = idx_row * params.
num_bins + idx_col;
2943 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
2944 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
2945 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
2946 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
2951 if (params.
shape ==
"triu") {
2952 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
2953 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++)
2955 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
2956 + (idx_col - idx_row);
2960 r1eff_dv[idx_dv] = stats_sn.
r[idx_row];
2961 r2eff_dv[idx_dv] = stats_sn.
r[idx_col];
2962 npairs1_dv[idx_dv] = stats_sn.
npairs[idx_row];
2963 npairs2_dv[idx_dv] = stats_sn.
npairs[idx_col];
2976 catalogue_rand, los_rand, alpha, params.
ELL, M_
2988 MeshField F_lm_a(params,
true,
"`F_lm_a`");
2989 MeshField F_lm_b(params,
true,
"`F_lm_b`");
2991 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
2992 double r_a = r1eff_dv[idx_dv];
2994 n_00, ylm_k_a, sj_a, r_a
2997 double r_b = r2eff_dv[idx_dv];
2999 n_00, ylm_k_b, sj_b, r_b
3005 double zeta_comp_real = 0., zeta_comp_imag = 0.;
3008#pragma omp parallel for reduction(+:zeta_comp_real, zeta_comp_imag)
3010 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3011 std::complex<double> F_lm_a_gridpt(F_lm_a[gid][0], F_lm_a[gid][1]);
3012 std::complex<double> F_lm_b_gridpt(F_lm_b[gid][0], F_lm_b[gid][1]);
3013 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3014 std::complex<double> zeta_gridpt =
3015 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3017 zeta_comp_real += zeta_gridpt.real();
3018 zeta_comp_imag += zeta_gridpt.imag();
3021 std::complex<double> zeta_component(zeta_comp_real, zeta_comp_imag);
3023 zeta_dv[idx_dv] += coupling * vol_cell * factor_phase * (
3024 zeta_component + factor_mirror * std::conj(zeta_component)
3028 sph_orders_computed.push_back(sph_order_current);
3032 "Three-point correlation function window term computed at orders "
3033 "(m₁, m₂, M) = ±(%d, %d, %d).",
3046 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3047 threepcfwin_out.
r1_bin.push_back(r1bin_dv[idx_dv]);
3048 threepcfwin_out.
r1_eff.push_back(r1eff_dv[idx_dv]);
3049 threepcfwin_out.
npairs_1.push_back(npairs1_dv[idx_dv]);
3050 threepcfwin_out.
r2_bin.push_back(r2bin_dv[idx_dv]);
3051 threepcfwin_out.
r2_eff.push_back(r2eff_dv[idx_dv]);
3052 threepcfwin_out.
npairs_2.push_back(npairs2_dv[idx_dv]);
3053 threepcfwin_out.
zeta_raw.push_back(norm_factor * zeta_dv[idx_dv]);
3054 threepcfwin_out.
zeta_shot.push_back(norm_factor * sn_dv[idx_dv]);
3056 threepcfwin_out.
dim = dv_dim;
3058 delete[] npairs1_dv;
delete[] npairs2_dv;
3059 delete[] r1bin_dv;
delete[] r2bin_dv;
3060 delete[] r1eff_dv;
delete[] r2eff_dv;
3061 delete[] zeta_dv;
delete[] sn_dv;
3070 "... computed three-point correlation function window %s"
3071 "from random catalogue.",
3076 return threepcfwin_out;
3079#ifdef TRV_USE_LEGACY_CODE
3081 ParticleCatalogue& catalogue_data, ParticleCatalogue& catalogue_rand,
3082 LineOfSight* los_data, LineOfSight* los_rand,
3091 "Computing bispectrum from paired survey-type catalogues "
3092 "for line-of-sight choice %d...",
3104 double alpha = catalogue_data.wstotal / catalogue_rand.wstotal;
3106 std::complex<double> factor_phase =
3111 if (params.
shape ==
"diag" || params.
shape ==
"row" ) {
3114 if (params.
shape ==
"off-diag") {
3117 if (params.
shape ==
"full") {
3120 if (params.
shape ==
"triu") {
3125 "Three-point statistic form is not recognised: `form` = '%s'.",
3129 throw trvs::InvalidParameterError(
3130 "Three-point statistic form is not recognised: `form` = '%s'.",
3135 int* nmodes1_dv =
new int[dv_dim]();
3136 int* nmodes2_dv =
new int[dv_dim]();
3137 double* k1bin_dv =
new double[dv_dim]();
3138 double* k2bin_dv =
new double[dv_dim]();
3139 double* k1eff_dv =
new double[dv_dim]();
3140 double* k2eff_dv =
new double[dv_dim]();
3141 std::complex<double>* bk_dv =
new std::complex<double>[dv_dim];
3142 std::complex<double>* sn_dv =
new std::complex<double>[dv_dim];
3148#if defined(TRV_USE_OMP) && defined(TRV_USE_FFTWOMP)
3150 fftw_init_threads();
3170 trvm::SphericalBesselCalculator sj_a(params.
ell1);
3171 trvm::SphericalBesselCalculator sj_b(params.
ell2);
3176 std::vector< std::complex<double> > ylm_k_a(params.
nmesh);
3177 std::vector< std::complex<double> > ylm_k_b(params.
nmesh);
3178 std::vector< std::complex<double> > ylm_r_a(params.
nmesh);
3179 std::vector< std::complex<double> > ylm_r_b(params.
nmesh);
3188 std::vector<trv::SphericalOrderTriplet> sph_orders_computed;
3189 int count_terms = 0;
3190 for (
int m1_ = - params.
ell1; m1_ <= params.
ell1; m1_++) {
3191 for (
int m2_ = - params.
ell2; m2_ <= params.
ell2; m2_++) {
3193 std::string flag_vanishing =
"true";
3194 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
3196 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
3199 flag_vanishing =
"false";
3203 if (flag_vanishing ==
"true") {
continue;}
3222 for (
int M_ = - params.
ELL; M_ <= params.
ELL; M_++) {
3226 std::string flag_redundant =
"false";
3228 if (sph_order_current.is_inverse(sph_order)) {
3229 flag_redundant =
"true";
3232 if (flag_redundant ==
"true") {
continue;}
3236 params.
ell1, params.
ell2, params.
ELL, m1_, m2_, M_
3250 double factor_mirror = sph_order_current.is_zeros() ?
3251 0. : std::pow(-1., params.
ELL);
3252 double factor_mirror_w3j = sph_order_current.is_zeros() ?
3256 int progbar_task_count = 10 + 3 * dv_dim;
3257 std::stringstream progbar_name_ss;
3259 <<
"component orders (" << m1_ <<
", " << m2_ <<
", " << M_ <<
")";
3260 trvs::ProgressBar progbar(progbar_task_count, progbar_name_ss.str());
3262 std::vector<float> progbar_nodes;
3265 if (progbar_nodes.size() > 0) {
3266 progbar.set_nodes(progbar_nodes);
3271 auto update_progbar = [&]() {
3272 if (params.
progbar !=
"false") {
3286 MeshField dn_LM_a(params,
true,
"`dn_LM_a`");
3287 if (los_choice == 0) {
3288 dn_LM_a.compute_ylm_wgtd_field(
3289 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3293 dn_LM_a.compute_ylm_wgtd_field(
3294 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3298 dn_LM_a.fourier_transform();
3301 MeshField dn_LM_b(params,
true,
"`dn_LM_b`");
3302 if (los_choice == 1) {
3303 dn_LM_b.compute_ylm_wgtd_field(
3304 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3308 dn_LM_b.compute_ylm_wgtd_field(
3309 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3313 dn_LM_b.fourier_transform();
3317 if (los_choice == 2) {
3318 G_LM.compute_ylm_wgtd_field(
3319 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3323 G_LM.compute_ylm_wgtd_field(
3324 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3328 G_LM.fourier_transform();
3329 G_LM.apply_assignment_compensation();
3330 G_LM.inv_fourier_transform();
3333 double vol_cell = G_LM.vol_cell;
3335 MeshField F_lm_a(params,
true,
"`F_lm_a`");
3336 MeshField F_lm_b(params,
true,
"`F_lm_b`");
3338 if (params.
shape ==
"diag") {
3339 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3342 double k_lower = kbinning.
bin_edges[ibin];
3343 double k_upper = kbinning.
bin_edges[ibin + 1];
3345 double k_eff_a_, k_eff_b_;
3346 int nmodes_a_, nmodes_b_;
3348 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3349 dn_LM_a, ylm_k_a, k_lower, k_upper, k_eff_a_, nmodes_a_
3351 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3352 dn_LM_b, ylm_k_b, k_lower, k_upper, k_eff_b_, nmodes_b_
3356 if (count_terms == 0) {
3359 k1eff_dv[idx_dv] = k_eff_a_;
3360 k2eff_dv[idx_dv] = k_eff_b_;
3361 nmodes1_dv[idx_dv] = nmodes_a_;
3362 nmodes2_dv[idx_dv] = nmodes_b_;
3366 double bk_comp_real = 0., bk_comp_imag = 0.;
3369#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3371 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3372 std::complex<double> F_lm_a_gridpt(
3373 F_lm_a[gid][0], F_lm_a[gid][1]
3375 std::complex<double> F_lm_b_gridpt(
3376 F_lm_b[gid][0], F_lm_b[gid][1]
3378 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3379 std::complex<double> bk_gridpt =
3380 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3382 bk_comp_real += bk_gridpt.real();
3383 bk_comp_imag += bk_gridpt.imag();
3386 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3388 bk_dv[idx_dv] += coupling * vol_cell * (
3389 bk_component + factor_mirror * std::conj(bk_component)
3394 if (params.
shape ==
"off-diag") {
3395 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3396 int ibin_row, ibin_col;
3399 ibin_col = idx_dv + std::abs(params.
idx_bin);
3401 ibin_row = idx_dv + std::abs(params.
idx_bin);
3405 double k_lower_a = kbinning.
bin_edges[ibin_row];
3406 double k_upper_a = kbinning.
bin_edges[ibin_row + 1];
3407 double k_lower_b = kbinning.
bin_edges[ibin_col];
3408 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
3410 double k_eff_a_, k_eff_b_;
3411 int nmodes_a_, nmodes_b_;
3413 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3414 dn_LM_a, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
3416 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3417 dn_LM_b, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
3421 if (count_terms == 0) {
3422 k1bin_dv[idx_dv] = kbinning.
bin_centres[ibin_row];
3423 k2bin_dv[idx_dv] = kbinning.
bin_centres[ibin_col];
3424 k1eff_dv[idx_dv] = k_eff_a_;
3425 k2eff_dv[idx_dv] = k_eff_b_;
3426 nmodes1_dv[idx_dv] = nmodes_a_;
3427 nmodes2_dv[idx_dv] = nmodes_b_;
3431 double bk_comp_real = 0., bk_comp_imag = 0.;
3434#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3436 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3437 std::complex<double> F_lm_a_gridpt(
3438 F_lm_a[gid][0], F_lm_a[gid][1]
3440 std::complex<double> F_lm_b_gridpt(
3441 F_lm_b[gid][0], F_lm_b[gid][1]
3443 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3444 std::complex<double> bk_gridpt =
3445 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3447 bk_comp_real += bk_gridpt.real();
3448 bk_comp_imag += bk_gridpt.imag();
3451 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3453 bk_dv[idx_dv] += coupling * vol_cell * (
3454 bk_component + factor_mirror * std::conj(bk_component)
3459 if (params.
shape ==
"row") {
3460 int ibin_row = params.
idx_bin;
3468 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3469 dn_LM_a, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
3472 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3473 int ibin_col = idx_dv;
3475 double k_lower_b = kbinning.
bin_edges[ibin_col];
3476 double k_upper_b = kbinning.
bin_edges[ibin_col + 1];
3481 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3482 dn_LM_b, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
3486 if (count_terms == 0) {
3487 k1bin_dv[idx_dv] = kbinning.
bin_centres[ibin_row];
3488 k2bin_dv[idx_dv] = kbinning.
bin_centres[ibin_col];
3489 k1eff_dv[idx_dv] = k_eff_a_;
3490 k2eff_dv[idx_dv] = k_eff_b_;
3491 nmodes1_dv[idx_dv] = nmodes_a_;
3492 nmodes2_dv[idx_dv] = nmodes_b_;
3496 double bk_comp_real = 0., bk_comp_imag = 0.;
3499#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3501 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3502 std::complex<double> F_lm_a_gridpt(
3503 F_lm_a[gid][0], F_lm_a[gid][1]
3505 std::complex<double> F_lm_b_gridpt(
3506 F_lm_b[gid][0], F_lm_b[gid][1]
3508 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3509 std::complex<double> bk_gridpt =
3510 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3512 bk_comp_real += bk_gridpt.real();
3513 bk_comp_imag += bk_gridpt.imag();
3516 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3518 bk_dv[idx_dv] += coupling * vol_cell * (
3519 bk_component + factor_mirror * std::conj(bk_component)
3524 if (params.
shape ==
"full") {
3525 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
3526 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
3527 int idx_dv = idx_row * params.
num_bins + idx_col;
3529 double k_lower_a = kbinning.
bin_edges[idx_row];
3530 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
3531 double k_lower_b = kbinning.
bin_edges[idx_col];
3532 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
3534 double k_eff_a_, k_eff_b_;
3535 int nmodes_a_, nmodes_b_;
3537 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3538 dn_LM_a, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
3540 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3541 dn_LM_b, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
3545 if (count_terms == 0) {
3548 k1eff_dv[idx_dv] = k_eff_a_;
3549 k2eff_dv[idx_dv] = k_eff_b_;
3550 nmodes1_dv[idx_dv] = nmodes_a_;
3551 nmodes2_dv[idx_dv] = nmodes_b_;
3555 double bk_comp_real = 0., bk_comp_imag = 0.;
3558#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3560 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3561 std::complex<double> F_lm_a_gridpt(
3562 F_lm_a[gid][0], F_lm_a[gid][1]
3564 std::complex<double> F_lm_b_gridpt(
3565 F_lm_b[gid][0], F_lm_b[gid][1]
3567 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3568 std::complex<double> bk_gridpt =
3569 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3571 bk_comp_real += bk_gridpt.real();
3572 bk_comp_imag += bk_gridpt.imag();
3575 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3577 bk_dv[idx_dv] += coupling * vol_cell * (
3578 bk_component + factor_mirror * std::conj(bk_component)
3584 if (params.
shape ==
"triu") {
3585 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
3586 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++) {
3587 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
3588 + (idx_col - idx_row);
3590 double k_lower_a = kbinning.
bin_edges[idx_row];
3591 double k_upper_a = kbinning.
bin_edges[idx_row + 1];
3592 double k_lower_b = kbinning.
bin_edges[idx_col];
3593 double k_upper_b = kbinning.
bin_edges[idx_col + 1];
3595 double k_eff_a_, k_eff_b_;
3596 int nmodes_a_, nmodes_b_;
3598 F_lm_a.inv_fourier_transform_ylm_wgtd_field_band_limited(
3599 dn_LM_a, ylm_k_a, k_lower_a, k_upper_a, k_eff_a_, nmodes_a_
3601 F_lm_b.inv_fourier_transform_ylm_wgtd_field_band_limited(
3602 dn_LM_b, ylm_k_b, k_lower_b, k_upper_b, k_eff_b_, nmodes_b_
3606 if (count_terms == 0) {
3609 k1eff_dv[idx_dv] = k_eff_a_;
3610 k2eff_dv[idx_dv] = k_eff_b_;
3611 nmodes1_dv[idx_dv] = nmodes_a_;
3612 nmodes2_dv[idx_dv] = nmodes_b_;
3616 double bk_comp_real = 0., bk_comp_imag = 0.;
3619#pragma omp parallel for reduction(+:bk_comp_real, bk_comp_imag)
3621 for (
long long gid = 0; gid < params.
nmesh; gid++) {
3622 std::complex<double> F_lm_a_gridpt(
3623 F_lm_a[gid][0], F_lm_a[gid][1]
3625 std::complex<double> F_lm_b_gridpt(
3626 F_lm_b[gid][0], F_lm_b[gid][1]
3628 std::complex<double> G_LM_gridpt(G_LM[gid][0], G_LM[gid][1]);
3629 std::complex<double> bk_gridpt =
3630 F_lm_a_gridpt * F_lm_b_gridpt * G_LM_gridpt;
3632 bk_comp_real += bk_gridpt.real();
3633 bk_comp_imag += bk_gridpt.imag();
3636 std::complex<double> bk_component(bk_comp_real, bk_comp_imag);
3638 bk_dv[idx_dv] += coupling * vol_cell * (
3639 bk_component + factor_mirror * std::conj(bk_component)
3650 MeshField dn_LM_a_for_sn(params,
true,
"`dn_LM_a_for_sn`");
3653 if (los_choice == 0) {
3654 dn_LM_a_for_sn.compute_ylm_wgtd_field(
3655 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3659 dn_LM_a_for_sn.compute_ylm_wgtd_field(
3660 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3664 dn_LM_a_for_sn.fourier_transform();
3667 MeshField dn_LM_b_for_sn(params,
true,
"`dn_LM_b_for_sn`");
3670 if (los_choice == 1) {
3671 dn_LM_b_for_sn.compute_ylm_wgtd_field(
3672 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3676 dn_LM_b_for_sn.compute_ylm_wgtd_field(
3677 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3681 dn_LM_b_for_sn.fourier_transform();
3685 MeshField dn_LM_c_for_sn(params,
true,
"`dn_LM_c_for_sn`");
3686 if (los_choice == 2) {
3687 dn_LM_c_for_sn.compute_ylm_wgtd_field(
3688 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3692 dn_LM_c_for_sn.compute_ylm_wgtd_field(
3693 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3697 dn_LM_c_for_sn.fourier_transform();
3700 MeshField N_LM_a(params,
true,
"`N_LM_a`");
3701 if (los_choice == 0) {
3702 N_LM_a.compute_ylm_wgtd_quad_field(
3703 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3707 N_LM_a.compute_ylm_wgtd_quad_field(
3708 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3712 N_LM_a.fourier_transform();
3715 MeshField N_LM_b(params,
true,
"`N_LM_b`");
3716 if (los_choice == 1) {
3717 N_LM_b.compute_ylm_wgtd_quad_field(
3718 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3722 N_LM_b.compute_ylm_wgtd_quad_field(
3723 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3727 N_LM_b.fourier_transform();
3730 MeshField N_LM_c(params,
true,
"`N_LM_c`");
3731 if (los_choice == 2) {
3732 N_LM_c.compute_ylm_wgtd_quad_field(
3733 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3737 N_LM_c.compute_ylm_wgtd_quad_field(
3738 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3742 N_LM_c.fourier_transform();
3746 catalogue_data, catalogue_rand, los_data, los_rand, alpha,
3750 if (params.
ell1 == 0 && params.
ell2 == 0) {
3753 std::complex<double> S_ijk = coupling * Sbar_LM;
3754 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3755 sn_dv[idx_dv] += S_ijk;
3759 if (params.
ell2 == 0) {
3761 stats_sn.compute_ylm_wgtd_2pt_stats_in_fourier(
3762 dn_LM_a_for_sn, N_LM_a, Sbar_LM, params.
ell1, m1_, kbinning
3765 if (params.
shape ==
"diag") {
3766 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3768 std::complex<double> S_i_jk = coupling * (
3769 stats_sn.pk[ibin] - stats_sn.sn[ibin]
3771 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
3775 if (params.
shape ==
"off-diag") {
3776 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3781 ibin_row = idx_dv + std::abs(params.
idx_bin);
3783 std::complex<double> S_i_jk = coupling * (
3784 stats_sn.pk[ibin_row] - stats_sn.sn[ibin_row]
3786 sn_dv[idx_dv] += S_i_jk + factor_mirror * std::conj(S_i_jk);
3790 if (params.
shape ==
"row") {
3791 std::complex<double> S_i_jk_row_ = coupling * (
3794 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3796 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
3800 if (params.
shape ==
"full") {
3801 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
3802 std::complex<double> S_i_jk_row_ = coupling * (
3803 stats_sn.pk[idx_row] - stats_sn.sn[idx_row]
3805 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
3806 int idx_dv = idx_row * params.
num_bins + idx_col;
3808 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
3813 if (params.
shape ==
"triu") {
3814 for (
int idx_row = 0; idx_row < params.
num_bins; idx_row++) {
3815 std::complex<double> S_i_jk_row_ = coupling * (
3816 stats_sn.pk[idx_row] - stats_sn.sn[idx_row]
3818 for (
int idx_col = idx_row; idx_col < params.
num_bins; idx_col++)
3820 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
3821 + (idx_col - idx_row);
3823 S_i_jk_row_ + factor_mirror * std::conj(S_i_jk_row_);
3829 if (params.
ell1 == 0) {
3831 stats_sn.compute_ylm_wgtd_2pt_stats_in_fourier(
3832 dn_LM_b_for_sn, N_LM_b, Sbar_LM,
3833 params.
ell2, m2_, kbinning
3836 if (params.
shape ==
"diag") {
3837 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3839 std::complex<double> S_ik_j_ki = coupling * (
3840 stats_sn.pk[ibin] - stats_sn.sn[ibin]
3843 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
3847 if (params.
shape ==
"off-diag") {
3848 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3851 ibin_col = idx_dv + params.
idx_bin;
3855 std::complex<double> S_ik_j_ki = coupling * (
3856 stats_sn.pk[ibin_col] - stats_sn.sn[ibin_col]
3859 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
3863 if (params.
shape ==
"row") {
3864 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3865 int ibin_col = idx_dv;
3866 std::complex<double> S_ik_j_ki = coupling * (
3867 stats_sn.pk[ibin_col] - stats_sn.sn[ibin_col]
3870 S_ik_j_ki + factor_mirror * std::conj(S_ik_j_ki);
3874 if (params.
shape ==
"full") {
3875 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
3876 std::complex<double> S_ik_j_ki_col_ = coupling * (
3877 stats_sn.pk[idx_col] - stats_sn.sn[idx_col]
3879 for (
int idx_row = 0; idx_row <= params.
num_bins; idx_row++) {
3880 int idx_dv = idx_row * params.
num_bins + idx_col;
3882 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
3887 if (params.
shape ==
"triu") {
3888 for (
int idx_col = 0; idx_col < params.
num_bins; idx_col++) {
3889 std::complex<double> S_ik_j_ki_col_ = coupling * (
3890 stats_sn.pk[idx_col] - stats_sn.sn[idx_col]
3892 for (
int idx_row = 0; idx_row <= idx_col; idx_row++) {
3893 int idx_dv = (2*params.
num_bins - idx_row + 1) * idx_row / 2
3894 + (idx_col - idx_row);
3896 S_ik_j_ki_col_ + factor_mirror * std::conj(S_ik_j_ki_col_);
3902 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3903 double k_a = k1eff_dv[idx_dv];
3904 double k_b = k2eff_dv[idx_dv];
3906 std::complex<double> S_ij_k = coupling
3907 * stats_sn.compute_uncoupled_shotnoise_for_bispec_per_bin(
3908 dn_LM_c_for_sn, N_LM_c, ylm_r_a, ylm_r_b, sj_a, sj_b,
3913 sn_dv[idx_dv] += factor_phase * (
3914 S_ij_k + factor_mirror_w3j * std::conj(S_ij_k)
3918 sph_orders_computed.push_back(sph_order_current);
3922 "Bispectrum term computed at orders (m₁, m₂, M) = ±(%d, %d, %d).",
3934 trv::BispecMeasurements bispec_out;
3935 for (
int idx_dv = 0; idx_dv < dv_dim; idx_dv++) {
3936 bispec_out.
k1_bin.push_back(k1bin_dv[idx_dv]);
3937 bispec_out.
k1_eff.push_back(k1eff_dv[idx_dv]);
3938 bispec_out.
nmodes_1.push_back(nmodes1_dv[idx_dv]);
3939 bispec_out.
k2_bin.push_back(k2bin_dv[idx_dv]);
3940 bispec_out.
k2_eff.push_back(k2eff_dv[idx_dv]);
3941 bispec_out.
nmodes_2.push_back(nmodes2_dv[idx_dv]);
3942 bispec_out.
bk_raw.push_back(norm_factor * bk_dv[idx_dv]);
3943 bispec_out.
bk_shot.push_back(norm_factor * sn_dv[idx_dv]);
3945 bispec_out.
dim = dv_dim;
3947 delete[] nmodes1_dv;
delete[] nmodes2_dv;
3948 delete[] k1bin_dv;
delete[] k2bin_dv;
3949 delete[] k1eff_dv;
delete[] k2eff_dv;
3950 delete[] bk_dv;
delete[] sn_dv;
3959 "... computed bispectrum from paired survey-type catalogues "
3960 "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 cell number in each dimension
std::string progbar
display a progress bar: {"true", "false" (default), <int-%-point>}
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.
static void store_reduced_spherical_harmonic_in_config_space(const int ell, const int m, const double boxsize[3], const int ngrid[3], std::vector< std::complex< double > > &ylm_out)
Store reduced spherical harmonics computed in configuration space.
static void store_reduced_spherical_harmonic_in_fourier_space(const int ell, const int m, const double boxsize[3], const int ngrid[3], std::vector< std::complex< double > > &ylm_out)
Store reduced spherical harmonics computed in Fourier space.
static std::complex< double > calc_reduced_spherical_harmonic(const int ell, const int m, double pos[3])
Calculate the reduced spherical harmonic.
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.
Progress bar for tracking tasks.
void set_nodes(std::vector< float > nodes)
Set progress bar width.
void update(int task_idx_now)
Update the progress bar.
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
void update_maxmem(bool gpu=false)
Update the maximum memory usage estimate.
double size_in_gb(long long num)
Return size in gibibytes.
bool is_gpu_enabled()
Check if GPU mode is enabled.
Logger logger
default logger (at NSET logging level)
float count_grid
number of grids
std::vector< float > set_nodes_by_str(std::string interval_str)
Set a node list possibly from a string.
int count_fft
number of FFTs
int count_cgrid
number of 3-d complex grids
int count_ifft
number of IFFTs
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.