711 static constexpr std::array<double, 24> GL24_X {{
712 -0.99518721999702131, -0.97472855597130947, -0.93827455200273280, -0.88641552700440107,
713 -0.82000198597390295, -0.74012419157855436, -0.64809365193697555, -0.54542147138883956,
714 -0.43379350762604513, -0.31504267969616340, -0.19111886747361631, -0.06405689286260563,
715 0.06405689286260563, 0.19111886747361631, 0.31504267969616340, 0.43379350762604513,
716 0.54542147138883956, 0.64809365193697555, 0.74012419157855436, 0.82000198597390295,
717 0.88641552700440107, 0.93827455200273280, 0.97472855597130947, 0.99518721999702131
719 static constexpr std::array<double, 24> GL24_W {{
720 0.01234122979998869, 0.02853138862893356, 0.04427743881741941, 0.05929858491543636,
721 0.07334648141108016, 0.08619016153195321, 0.09761865210411393, 0.10744427011596556,
722 0.11550566805372552, 0.12167047292780329, 0.12583745634682825, 0.12793819534675202,
723 0.12793819534675202, 0.12583745634682825, 0.12167047292780329, 0.11550566805372552,
724 0.10744427011596556, 0.09761865210411393, 0.08619016153195321, 0.07334648141108016,
725 0.05929858491543636, 0.04427743881741941, 0.02853138862893356, 0.01234122979998869
757 auto zero_if_close = [] (
double x,
double tol) {
758 return std::abs(x) < tol ? 0.0 : x;
761 auto clear_and_reserve = [&] (std::array<std::vector<double>, 15>& dest,
size_t nbins) {
762 for (
auto& v : dest) {
768 auto eval_amplitudes = [&] (
double q2,
bool bar) -> AmpSet {
769 const double beta =
beta_l(q2);
785 auto eval_J = [&] (
const AmpSet& a,
double q2) -> JSet {
786 const double sqrt2 = std::sqrt(2.0);
787 const double ml = cache.
m_l;
788 const double ml_over_sqrt_q2 = ml / a.sqrt_q2;
789 const double four_ml2_over_q2 = 4.0 * ml * ml / q2;
791 const double norm_Aperp_L = std::norm(a.A_perp_L);
792 const double norm_Aperp_R = std::norm(a.A_perp_R);
793 const double norm_Apar_L = std::norm(a.A_par_L);
794 const double norm_Apar_R = std::norm(a.A_par_R);
795 const double norm_A0_L = std::norm(a.A_0_L);
796 const double norm_A0_R = std::norm(a.A_0_R);
797 const double norm_At = std::norm(a.A_t);
798 const double norm_AS = std::norm(a.A_S);
800 const complex_t Apar_sum = a.A_par_L + a.A_par_R;
801 const complex_t A0_sum = a.A_0_L + a.A_0_R;
802 const complex_t Aperp_sum = a.A_perp_L + a.A_perp_R;
806 (2.0 + a.beta2) / 4.0 * (norm_Aperp_L + norm_Aperp_R + norm_Apar_L + norm_Apar_R)
807 + four_ml2_over_q2 * std::real(a.A_perp_L * std::conj(a.A_perp_R)
808 + a.A_par_L * std::conj(a.A_par_R));
811 norm_A0_L + norm_A0_R
812 + four_ml2_over_q2 * (norm_At + 2.0 * std::real(a.A_0_L * std::conj(a.A_0_R)))
815 j.j2s = a.beta2 / 4.0 * (norm_Aperp_L + norm_Aperp_R + norm_Apar_L + norm_Apar_R);
816 j.j2c = -a.beta2 * (norm_A0_L + norm_A0_R);
818 j.j3 = a.beta2 / 2.0 * (norm_Aperp_L + norm_Aperp_R - norm_Apar_L - norm_Apar_R);
820 j.j4 = a.beta2 / sqrt2 * (
821 std::real(a.A_0_L * std::conj(a.A_par_L))
822 + std::real(a.A_0_R * std::conj(a.A_par_R))
825 j.j5 = a.beta * sqrt2 * (
826 std::real(a.A_0_L * std::conj(a.A_perp_L))
827 - std::real(a.A_0_R * std::conj(a.A_perp_R))
828 - ml_over_sqrt_q2 * std::real(Apar_sum * std::conj(a.A_S))
831 j.j6s = 2.0 * a.beta * (
832 std::real(a.A_par_L * std::conj(a.A_perp_L))
833 - std::real(a.A_par_R * std::conj(a.A_perp_R))
836 j.j6c = 4.0 * a.beta * ml_over_sqrt_q2 * std::real(A0_sum * std::conj(a.A_S));
838 j.j7 = a.beta * sqrt2 * (
839 std::imag(a.A_0_L * std::conj(a.A_par_L))
840 - std::imag(a.A_0_R * std::conj(a.A_par_R))
841 + ml_over_sqrt_q2 * std::imag(Aperp_sum * std::conj(a.A_S))
844 j.j8 = a.beta2 / sqrt2 * (
845 std::imag(a.A_0_L * std::conj(a.A_perp_L))
846 + std::imag(a.A_0_R * std::conj(a.A_perp_R))
850 std::imag(a.A_perp_L * std::conj(a.A_par_L))
851 + std::imag(a.A_perp_R * std::conj(a.A_par_R))
857 auto eval_integrands = [&] (
double q2) -> std::array<double, 15> {
858 const AmpSet a = eval_amplitudes(q2,
false);
859 const AmpSet b = eval_amplitudes(q2,
true);
860 const JSet jf = eval_J(a, q2);
861 const JSet jt = eval_J(b, q2);
863 const double ml = cache.
m_l;
864 const double x = ml * ml / q2;
865 const double beta = a.beta;
866 const double beta2 = a.beta2;
867 const double sqrt_q2 = a.sqrt_q2;
869 const complex_t ALperp_tilde = -b.A_perp_L;
870 const complex_t ARperp_tilde = -b.A_perp_R;
878 const complex_t sh1s_A = cache.
up * (ALperp_tilde * std::conj(a.A_perp_L) + ALpar_tilde * std::conj(a.A_par_L)
879 + ARperp_tilde * std::conj(a.A_perp_R) + ARpar_tilde * std::conj(a.A_par_R));
880 const complex_t sh1s_B = cache.
up * (ALperp_tilde * std::conj(a.A_perp_R) + ALpar_tilde * std::conj(a.A_par_R));
881 const complex_t sh1s_C = cache.
um * (a.A_perp_L * std::conj(ARperp_tilde) + a.A_par_L * std::conj(ARpar_tilde));
882 const double h1s = (2.0 + beta2) / 2.0 * std::real(sh1s_A) + 4.0 * x * std::real(sh1s_B + sh1s_C);
884 const complex_t sh1c_A = cache.
up * (AL0_tilde * std::conj(a.A_0_L) + AR0_tilde * std::conj(a.A_0_R));
885 const complex_t sh1c_B = cache.
up * At_tilde * std::conj(a.A_t);
886 const complex_t sh1c_C = cache.
up * AL0_tilde * std::conj(a.A_0_R);
887 const complex_t sh1c_D = cache.
um * a.A_0_L * std::conj(AR0_tilde);
888 const complex_t sh1c_E = cache.
up * AS_tilde * std::conj(a.A_S);
889 const double h1c = 2.0 * std::real(sh1c_A)
890 + 8.0 * x * (std::real(sh1c_B) + std::real(sh1c_C + sh1c_D))
891 + 2.0 * beta2 * std::real(sh1c_E);
893 const complex_t sh2s_A = cache.
up * (ALperp_tilde * std::conj(a.A_perp_L) + ALpar_tilde * std::conj(a.A_par_L)
894 + ARperp_tilde * std::conj(a.A_perp_R) + ARpar_tilde * std::conj(a.A_par_R));
895 const double h2s = beta2 / 2.0 * std::real(sh2s_A);
897 const complex_t sh2c_A = cache.
up * (AL0_tilde * std::conj(a.A_0_L) + AR0_tilde * std::conj(a.A_0_R));
898 const double h2c = -2.0 * beta2 * std::real(sh2c_A);
900 const complex_t sh3_A = -cache.
up * (b.A_perp_L * std::conj(a.A_perp_L) + b.A_par_L * std::conj(a.A_par_L)
901 + b.A_perp_R * std::conj(a.A_perp_R) + b.A_par_R * std::conj(a.A_par_R));
902 const double h3 = beta2 * std::real(sh3_A);
904 const complex_t sh4_A = cache.
up * (b.A_0_L * std::conj(a.A_par_L) + b.A_0_R * std::conj(a.A_par_R));
905 const complex_t sh4_B = cache.
um * (a.A_0_L * std::conj(b.A_par_L) + a.A_0_R * std::conj(b.A_par_R));
906 const double h4 =
INV_RT2 * beta2 * std::real(sh4_A + sh4_B);
908 const complex_t sh5_A = cache.
up * (b.A_0_L * std::conj(a.A_perp_L) - b.A_0_R * std::conj(a.A_perp_R));
909 const complex_t sh5_B = cache.
um * (a.A_0_L * std::conj(-b.A_perp_L) - a.A_0_R * std::conj(b.A_par_R));
910 const complex_t sh5_C = cache.
up * ((b.A_par_L + b.A_par_R) * std::conj(a.A_S));
911 const complex_t sh5_D = cache.
um * ((a.A_par_L + a.A_par_R) * std::conj(-b.A_S));
912 const double h5 =
RT2 * beta * (std::real(sh5_A + sh5_B) - ml / sqrt_q2 * std::real(sh5_C + sh5_D));
914 const complex_t sh6s_A = cache.
up * (b.A_par_L * std::conj(a.A_perp_L) - b.A_par_R * std::conj(a.A_perp_R));
915 const complex_t sh6s_B = cache.
um * (a.A_par_L * std::conj(-b.A_perp_L) - a.A_par_R * std::conj(-b.A_perp_R));
916 const double h6s = 2.0 * beta * std::real(sh6s_A + sh6s_B);
918 const complex_t sh6c_A = cache.
up * ((b.A_0_L + b.A_0_R) * std::conj(a.A_S));
919 const complex_t sh6c_B = cache.
um * ((a.A_0_L + a.A_0_R) * std::conj(-b.A_S));
920 const double h6c = 4.0 * beta * ml / sqrt_q2 * std::real(sh6c_A + sh6c_B);
922 const complex_t sh7_A = cache.
up * (b.A_0_L * std::conj(a.A_par_L) - b.A_0_R * std::conj(a.A_par_R));
923 const complex_t sh7_B = cache.
um * (a.A_0_L * std::conj(b.A_par_L) - a.A_0_R * std::conj(b.A_par_R));
924 const complex_t sh7_C = cache.
up * (-(b.A_perp_L + b.A_perp_R) * std::conj(a.A_S));
925 const complex_t sh7_D = cache.
um * ((a.A_perp_L + a.A_perp_R) * std::conj(-b.A_S));
926 const double h7 =
RT2 * beta * (std::imag(sh7_A + sh7_B) + ml / sqrt_q2 * std::imag(sh7_C + sh7_D));
928 const complex_t sh8_A = cache.
up * (b.A_0_L * std::conj(a.A_perp_L) + b.A_0_R * std::conj(a.A_perp_R));
929 const complex_t sh8_B = cache.
um * (a.A_0_L * std::conj(-b.A_perp_L) + a.A_0_R * std::conj(-b.A_perp_R));
930 const double h8 =
INV_RT2 * beta2 * std::imag(sh8_A + sh8_B);
932 const complex_t sh9_A = cache.
up * (b.A_par_L * std::conj(a.A_perp_L) + b.A_par_R * std::conj(a.A_perp_R));
933 const complex_t sh9_B = cache.
um * (a.A_par_L * std::conj(-b.A_perp_L) + a.A_par_R * std::conj(-b.A_perp_R));
934 const double h9 = -beta2 * std::imag(sh9_A + sh9_B);
936 const double s8v = -beta2 / sqrt_q2 * std::real(sh8_A - sh8_B);
937 const double s9v = beta2 * std::real(sh9_A - sh9_B);
939 const double val6 = zero_if_close(jf.j5 - jt.j5 - cache.
ys *
h5, 1e-30);
940 const double val7 = zero_if_close(jf.j6s - jt.j6s - cache.
ys *
h6s, 1e-30);
941 const double val9 = zero_if_close(jf.j6c - jt.j6c - cache.
ys *
h6c, 1e-30);
942 const double val11 = zero_if_close(jf.j8 - jt.j8 - cache.
ys *
h8, 1e-30);
943 const double val12 = zero_if_close(jf.j9 - jt.j9 - cache.
ys *
h9, 1e-30);
946 2.0 * (jf.j1s - cache.
ys *
h1s / 2.0) + jf.j1c - cache.
ys *
h1c / 2.0
947 - (2.0 * (jf.j2s - cache.
ys *
h2s / 2.0) + jf.j2c - cache.
ys *
h2c / 2.0) / 3.0,
948 2.0 * (jt.j1s - cache.
ys *
h1s / 2.0) + jt.j1c - cache.
ys *
h1c / 2.0
949 - (2.0 * (jt.j2s - cache.
ys *
h2s / 2.0) + jt.j2c - cache.
ys *
h2c / 2.0) / 3.0,
950 jt.j2s + jf.j2s - cache.
ys *
h2s,
951 jt.j2c + jf.j2c - cache.
ys *
h2c,
952 jt.j3 + jf.j3 - cache.
ys *
h3,
953 jt.j4 + jf.j4 - cache.
ys *
h4,
958 jt.j7 + jf.j7 - cache.
ys *
h7,
966 auto integrate_bin = [&] (
double q2_l,
double q2_u) -> std::array<double, 15> {
967 std::array<double, 15> acc {};
968 const double center = 0.5 * (q2_l + q2_u);
969 const double half_width = 0.5 * (q2_u - q2_l);
971 for (
size_t i = 0; i < GL24_X.size(); ++i) {
972 const double q2 = center + half_width * GL24_X[i];
973 const auto vals = eval_integrands(q2);
974 for (
size_t k = 0; k < acc.size(); ++k) {
975 acc[k] += GL24_W[i] * vals[k];
979 for (
double& v : acc) {
986 const double endpoint_eps = 1e-5;
987 const double low_q2_eps = 1e-7;
989 const auto&
bins = this->
bins.value();
990 const size_t nbins =
bins.size();
995 for (
const auto& [q2_l_raw, q2_u_raw] :
bins) {
996 const double q2_l = std::max(q2_l_raw, cache.
q2_min + low_q2_eps);
997 const double q2_u = std::min(q2_u_raw, cache.
q2_max - endpoint_eps);
999 if (!(q2_l < q2_u)) {
1001 "Skipping invalid BsPhi bin [",
1013 v.emplace_back(std::numeric_limits<double>::quiet_NaN());
1015 cache.
bin_widths.emplace_back(std::numeric_limits<double>::quiet_NaN());
1019 const double width = q2_u - q2_l;
1020 const auto integ = integrate_bin(q2_l, q2_u);
1024 for (
size_t k = 0; k < cache.
f_J_i_binned.size(); ++k) {