12const std::unordered_set<ObservableId> BKllDecay::dBR_dq2_ids = {
21const std::unordered_set<ObservableId> BKllDecay::dG_dq2_ids = {
30const std::unordered_set<ObservableId> BKllDecay::A_FB_ids = {
39const std::unordered_set<ObservableId> BKllDecay::F_H_ids = {
49const std::map<Observables, std::pair<BKllConfig::Lepton, BKllConfig::B_Charge>> BKllDecay::cfg_map {
94 cache.
m_b_PS = (*p)(
ParamId{
ParameterType::SM,
"QCD", {5, 2}},
DataType::VALUE) - 4 * (*
iobs_qcdp)(
AlphasConfig((*
p)(
ParamId{
ParameterType::SM,
"QCD", {5, 2}},
DataType::VALUE),
MassType::POLE,
MassType::POLE)) * mu_f / (3 *
PI);
102 for (
size_t i = 0; i < 4; i++) {
118 for (
const auto& [
id, val] : b_wilsons) {
121 for (
const auto& [
id, val] : bq_wilsons) {
124 for (
const auto& [
id, val] : bp_wilsons) {
130 const int B_id = cfg.
charge == Charge::B_0 ? 511 : 521;
131 const int P_id = cfg.
charge == Charge::B_0 ? 311 : 321;
155 cache.
q2_min = 4 * std::pow(cache.
m_l, 2);
158 cache.
N_0 = std::pow(std::abs(std::conj((*
p)(
ParamId{
ParameterType::SM,
"VCKM", {2, 1}},
DataType::VALUE)) * (*
p)(
ParamId{
ParameterType::SM,
"VCKM", {2, 2}},
DataType::VALUE)) * cache.
G_F * cache.
alpha_em, 2) / (512. * std::pow(
PI, 5) * std::pow(cache.
m_B, 3));
161 if (requested_threads == 0u) {
162 requested_threads = std::thread::hardware_concurrency();
164 if (requested_threads == 0u) {
165 requested_threads = 1u;
169 const size_t nworkers = std::min<size_t>(requested_threads, npts);
171 if (nworkers <= 1u) {
172 auto lam_T_P = [
this] (
double q2,
bool bar) {
179 const double x_max = cache.
q2_high;
180 const double step = (x_max - x_min) /
static_cast<double>(npts - 1);
182 std::vector<std::shared_ptr<BPQCDfCalculator>> qcdf_locals;
183 qcdf_locals.reserve(nworkers);
184 for (
size_t w = 0; w < nworkers; ++w) {
185 auto ff_local = std::make_shared<BPFFCalculator>(cache.
ff_calculator);
186 qcdf_locals.emplace_back(std::make_shared<BPQCDfCalculator>(
198 std::vector<std::thread> workers;
199 workers.reserve(nworkers);
201 std::exception_ptr first_exception =
nullptr;
202 std::mutex exception_mutex;
204 auto worker = [&] (
size_t worker_id,
size_t begin,
size_t end) {
207 for (
size_t i = begin; i < end; ++i) {
208 const double q2 = x_min + step *
static_cast<double>(i);
212 std::lock_guard<std::mutex> lock(exception_mutex);
213 if (!first_exception) {
214 first_exception = std::current_exception();
219 const size_t chunk = (npts + nworkers - 1) / nworkers;
220 for (
size_t w = 0; w < nworkers; ++w) {
221 const size_t begin = w * chunk;
222 const size_t end = std::min(npts, begin + chunk);
226 workers.emplace_back(worker, w, begin, end);
229 for (
auto& th : workers) {
233 if (first_exception) {
234 std::rethrow_exception(first_exception);
274 bool changed = cfg.
gen != gen || cfg.
charge != charge;
288 const double x = 1.0 - std::pow(2.0 * cache.
m_l, 2) / q2;
289 return std::sqrt(std::max(0.0, x));
293 const double mB2 = cache.
m_B * cache.
m_B;
294 const double mK2 = cache.
m_K * cache.
m_K;
300 - 2.0 * (mB2 * mK2 + (mB2 + mK2) * q2);
302 return std::max(0.0, lam);
334 return (F + 2. * m_b_local / (cache.
m_B + cache.
m_K) *
F_T) * had_err_factor;
381 double s_hat = q2 / std::pow(cache.
m_b_PS, 2);
392 double s_hat = q2 / std::pow(cache.
m_b_PS, 2);
401 + std::pow(cache.
m_c_mu_b, 2) / q2 * C_mc;
433 return t * val_low + (1 - t) * val_high;
454 q2 * (std::pow(
beta_l(q2) * std::abs(
F_S(q2)), 2) + std::pow(std::abs(
F_P(q2)), 2))
455 + 0.25 *
lambda(q2) * (std::pow(std::abs(
F_A(q2)), 2) + std::pow(std::abs(
F_V(q2)), 2))
456 + 2 * cache.
m_l * (std::pow(cache.
m_B, 2) - std::pow(cache.
m_K, 2) + q2) * std::real(
F_P(q2) * std::conj(
F_A(q2)))
457 + std::pow(2 * cache.
m_l * cache.
m_B, 2) * std::pow(std::abs(
F_A(q2)), 2)
462 return 2 *
N(q2) * cache.
m_l *
beta_l(q2) * std::sqrt(
lambda(q2)) * std::real(
F_S(q2) * std::conj(
F_V(q2)));
466 return -0.25 *
N(q2) *
lambda(q2) * std::pow(
beta_l(q2), 2) * (std::pow(std::abs(
F_A(q2)), 2) + std::pow(std::abs(
F_V(q2)), 2));
475 if (!this->
bins.has_value()) {
476 LOG_WARN(
"BKllDecay::compute_binned_abc called without bins.");
480 constexpr double q2_min_eps = 1e-8;
481 constexpr double endpoint_eps = 1e-2;
482 constexpr double shat_eps = 1e-3;
484 const double q2_qcdf_max = cache.
m_b_PS * cache.
m_b_PS * (1.0 - shat_eps);
486 for (
auto [q2_l, q2_u] : this->
bins.value()) {
487 const double low = std::max(q2_l, cache.
q2_min + q2_min_eps);
489 const double high = std::min({
491 cache.
q2_max - endpoint_eps,
506 "Skipping invalid BKll bin [",
510 "] after clipping to [",
517 cache.
abc_binned[0].emplace_back(std::numeric_limits<double>::quiet_NaN());
518 cache.
abc_binned[1].emplace_back(std::numeric_limits<double>::quiet_NaN());
519 cache.
abc_binned[2].emplace_back(std::numeric_limits<double>::quiet_NaN());
520 cache.
bin_widths.emplace_back(std::numeric_limits<double>::quiet_NaN());
524 const double width = high - low;
528 integrate([&](
double q2) {
return a(q2); }, low, high, 1e-3)
531 integrate([&](
double q2) {
return b(q2); }, low, high, 1e-3)
534 integrate([&](
double q2) {
return c(q2); }, low, high, 1e-3)
538 }
catch (
const std::exception& e) {
540 "BKll integration failed for bin [",
552 cache.
abc_binned[0].emplace_back(std::numeric_limits<double>::quiet_NaN());
553 cache.
abc_binned[1].emplace_back(std::numeric_limits<double>::quiet_NaN());
554 cache.
abc_binned[2].emplace_back(std::numeric_limits<double>::quiet_NaN());
555 cache.
bin_widths.emplace_back(std::numeric_limits<double>::quiet_NaN());
561 std::vector<ObservableValue> out;
562 double br_factor = br ? cache.
life_B : 1.0;
564 for (
size_t i = 0; i < this->
bins.value().size(); i++) {
566 const double requested_width = this->
bins.value()[i].second - this->
bins.value()[i].first;
573 (std::isfinite(width) && width > 0.0)
574 ? integrated_rate * br_factor / width
575 : std::numeric_limits<double>::quiet_NaN();
584 std::vector<ObservableValue> out;
585 for (
size_t i = 0; i < this->
bins.value().size(); i++) {
593 std::vector<ObservableValue> out;
594 for (
size_t i = 0; i < this->
bins.value().size(); i++) {
602 std::vector<ObservableValue> out;
603 std::vector<double> Gamma_mu;
604 std::vector<double> Gamma_e;
608 for (
size_t i = 0; i < this->
bins.value().size(); i++)
613 for (
size_t i = 0; i < this->
bins.value().size(); i++)
616 for (
size_t i = 0; i < this->
bins.value().size(); i++)
631 auto it = BKllDecay::cfg_map.find(obs);
632 if (it == BKllDecay::cfg_map.end()) {
637 "is not configured in BKllDecay::cfg_map"
642 auto flags = it->second;
654 "doesn't belong to the decay",
666 unsigned int available_threads = std::thread::hardware_concurrency();
668 if (available_threads == 0) {
669 available_threads = 1;
672 if (n_threads == 0) {
677 if (n_threads > available_threads) {
679 "Requested", n_threads,
680 "threads, but only", available_threads,
681 "are available. Using", available_threads,
689 this->cfg.
n_threads = std::max<size_t>(1, n_threads);
@ DGAMMA_DQ2_B__K_TAU_TAU
@ DGAMMA_DQ2_B0__K0_MU_MU
@ DGAMMA_DQ2_B0__K0_TAU_TAU
#define LOG_ERROR(type,...)
Macro for logging error messages and terminating the application.
#define LOG_WARN(...)
Macro for logging warning messages.
void fill_cache(Func &&f, double a, double b, std::array< T, cache_size > &cache, Args &&... args)
Fills a lookup cache for a function on a finite interval [a, b].
std::complex< double > complex_t
Convenience alias for std::complex<double>.
T lerp(U x, const std::array< T, cache_size > &lookup, double a=0.0, double b=1.0)
Linearly interpolates a cached function on [a, b].
complex_t F_A_low(double q2)
void set_n_threads(size_t n_threads) override
Set the number of worker threads used by decays that support parallel cache filling.
void load_params() override
Load and cache parameters needed by this decay.
complex_t F_S_low(double q2)
complex_t F_P_high(double q2)
complex_t C7_eff(double q2)
complex_t F_P_low(double q2)
complex_t F_S_high(double q2)
complex_t F_V_low(double q2)
void load_cfg_dependent_params()
std::vector< ObservableValue > compute_observable(Observables obs) override
Compute an observable given a public observable enum.
std::vector< ObservableValue > dBR_dq2(Observables oid, bool br)
void set_lepton_gen_and_charge(BKllConfig::Lepton gen, BKllConfig::B_Charge charge)
std::vector< ObservableValue > Rm1_BK(Observables id, BKllConfig::B_Charge charge)
complex_t interpolate(double q2, complex_t val_low, complex_t val_high)
complex_t C9_eff(double q2)
complex_t T_P_cached(double q2)
complex_t F_A_high(double q2)
std::vector< ObservableValue > F_H(Observables oid)
void compute_binned_abc()
complex_t F_V_high(double q2)
std::vector< ObservableValue > A_FB(Observables oid)
double get(BP_FF a, double q2) override
complex_t T_P(double q2, bool bar)
double Delta_P_0(double q2)
DecayId id
Unique decay identifier.
WilsonBuildConfig w_config
Wilson build configuration used when enabling this decay (scales, order, groups).
std::optional< std::vector< std::pair< double, double > > > bins
Optional q^2 bins.
std::shared_ptr< IObsParameterProxy< ParamId, DataType, std::string, LhaID > > p
Parameter proxy for SM-like quantities used by the decay (may be SM/BSM depending on wiring).
std::shared_ptr< IObsWilsonProxy > w_proxy
Wilson proxy used at compute-time to query coefficients (matching/run).
std::shared_ptr< IObsQCDProxy > iobs_qcdp
QCD proxy (alpha_s, running masses, constants...).
static std::optional< Observables > enum_of(const IdOf< ObservableTag > &id)
Attempts to recover the enum value associated with an identifier.
static IdOf< ObservableTag > to_id(Observables e)
Converts an enum value to an IdOf<Tag>.
static std::string str(const IdOf< ObservableTag > &id)
Returns the string representation of an identifier.
static WCoef cpq1_for_lepton_index(int lepton_index)
static WCoef cq1_for_lepton_index(int lepton_index)
static WCoef cq2_for_lepton_index(int lepton_index)
static WCoef cpq2_for_lepton_index(int lepton_index)
double integrate(RealValuedFunction f, double l, double u, double prec)
Performs numerical integration of a real-valued function of a real variable.
complex_t h(double s, double m_q, double mu_b)
complex_t B_Seidel(double s_hat, double L_b)
complex_t C_Seidel(double s, double mu_b)
complex_t f_87(double s_hat, double L_b)
complex_t A_Seidel(double s_hat, double L_b)
complex_t f_89(double s_hat)
Configuration for evaluating the strong coupling constant .
std::array< std::vector< double >, 3 > abc_binned
std::array< complex_t, 4 > A_had_err_low_1
static constexpr size_t LOOKUP_SIZE
std::vector< double > bin_widths
BPFFCalculator ff_calculator
BPQCDfCalculator qcdf_calculator
std::array< complex_t, 4 > A_had_err_low_0
std::array< complex_t, 4 > A_had_err_high
std::map< WCoef, complex_t > C
std::array< scalar_t, LOOKUP_SIZE > T_P_lookup
Configuration for computing a particle mass at a given scale.
Composite identifier for a single parameter.
QCDOrder order
Perturbative QCD order used for the evolution and matching of Wilson coefficients....