Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
BKllDecay.cpp
Go to the documentation of this file.
1#include "BKllDecay.h"
2#include "wcoef_ids.hpp"
3
4#include <algorithm>
5#include <exception>
6#include <mutex>
7#include <thread>
8#include <vector>
9
11
12const std::unordered_set<ObservableId> BKllDecay::dBR_dq2_ids = {
19};
20
21const std::unordered_set<ObservableId> BKllDecay::dG_dq2_ids = {
28};
29
30const std::unordered_set<ObservableId> BKllDecay::A_FB_ids = {
37};
38
39const std::unordered_set<ObservableId> BKllDecay::F_H_ids = {
46};
47
48
49const std::map<Observables, std::pair<BKllConfig::Lepton, BKllConfig::B_Charge>> BKllDecay::cfg_map {
54
59
64
69
74
79};
80
83
84 cache.alpha_em = (*p)(ParamId{ParameterType::SM, "EW", {1, 2}}, DataType::VALUE);
85 cache.G_F = (*p)(ParamId{ParameterType::SM, "SMINPUTS", 2}, DataType::VALUE);
86 cache.m_s = (*p)(ParamId{ParameterType::SM, "MASS", 3}, DataType::VALUE);
87 cache.mu_b = (*p)(ParamId{ParameterType::WILSON, "B_SCALE", 1}, DataType::VALUE);
88 cache.alpha_s_mu_b = (*iobs_qcdp)(AlphasConfig(cache.mu_b, MassType::POLE, MassType::POLE));
89 // cache.m_c_mu_b = (*iobs_qcdp)(MassConfig(4, cache.mu_b, MassType::MSBAR, MassType::POLE));
90 cache.m_c_mu_b = (*p)(ParamId{ParameterType::SM, "MASS", 4}, DataType::VALUE); // ASK: To match Superiso
91 cache.m_b_mu_b = (*iobs_qcdp)(MassConfig(5, cache.mu_b, MassType::MSBAR, MassType::POLE));
92 cache.m_b_m_b = (*p)(ParamId{ParameterType::SM, "QCD", {5, 1}}, DataType::VALUE); // ASK: To match SI at high q² : why not m_b(mu_b) ?
93 double mu_f = sqrt(cache.mu_b * (*p)(ParamId{ParameterType::DECAY, "B_K", 14}, DataType::VALUE));
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);
95 cache.L_b = std::log(cache.mu_b / cache.m_b_PS);
96 cache.Delta_M = -6. * cache.L_b - 4. * (1 - mu_f / cache.m_b_PS);
97 cache.lambda_hat_u = std::conj((*p)(ParamId{ParameterType::SM, "VCKM", {0, 1}}, DataType::VALUE)) * (*p)(ParamId{ParameterType::SM, "VCKM", {0, 2}}, DataType::VALUE)
98 / (std::conj((*p)(ParamId{ParameterType::SM, "VCKM", {2, 1}}, DataType::VALUE)) * (*p)(ParamId{ParameterType::SM, "VCKM", {2, 2}}, DataType::VALUE));
99 cache.q2_low = (*p)(ParamId{ParameterType::DECAY, "B_K", {15, 1}}, DataType::VALUE);
100 cache.q2_high = (*p)(ParamId{ParameterType::DECAY, "B_K", {15, 2}}, DataType::VALUE);
101
102 for (size_t i = 0; i < 4; i++) {
103 cache.A_had_err_low_0[i] = (*p)(ParamId{ParameterType::DECAY, "B_K", {18, 1, i + 1}}, DataType::VALUE);
104 cache.A_had_err_low_1[i] = (*p)(ParamId{ParameterType::DECAY, "B_K", {18, 2, i + 1}}, DataType::VALUE);
105 cache.A_had_err_high[i] = (*p)(ParamId{ParameterType::DECAY, "B_K", {18, 3, i + 1}}, DataType::VALUE);
106 }
107
109}
110
112 cache.C.clear();
113
114 auto b_wilsons = w_proxy->getAFR(WGroup::B, this->w_config.order);
115 auto bp_wilsons = w_proxy->getAFR(WGroup::BPrime, this->w_config.order);
116 auto bq_wilsons = w_proxy->getAFR(WGroup::BScalar, this->w_config.order);
117
118 for (const auto& [id, val] : b_wilsons) {
119 cache.C[id] = val;
120 }
121 for (const auto& [id, val] : bq_wilsons) {
122 cache.C[id] = val;
123 }
124 for (const auto& [id, val] : bp_wilsons) {
125 cache.C[id] = val;
126 }
127}
128
130 const int B_id = cfg.charge == Charge::B_0 ? 511 : 521;
131 const int P_id = cfg.charge == Charge::B_0 ? 311 : 321;
132
134 B_id,
135 P_id,
136 p,
137 cfg.ff_src
138 );
139
141 B_id,
142 P_id,
143 cache.mu_b,
144 cache.C,
145 std::make_shared<BPFFCalculator>(cache.ff_calculator),
146 cfg.ff_type,
147 p,
149 );
150
151 cache.m_l = (*p)(ParamId{ParameterType::SM, "MASS", 11 + 2 * (int)cfg.gen}, DataType::VALUE);
152 cache.m_B = (*p)(ParamId{ParameterType::FLAVOR, "FMASS", B_id}, DataType::VALUE);
153 cache.m_K = (*p)(ParamId{ParameterType::FLAVOR, "FMASS", P_id}, DataType::VALUE);
154 cache.life_B = (*p)(ParamId{ParameterType::FLAVOR, "FLIFE", B_id}, DataType::VALUE) / HBAR;
155 cache.q2_min = 4 * std::pow(cache.m_l, 2);
156 cache.q2_max = std::pow(cache.m_B - cache.m_K, 2);
157 cache.q2_lookup_min = std::max(cache.q2_min, 1e-4);
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));
159
160 auto requested_threads = cfg.n_threads;
161 if (requested_threads == 0u) {
162 requested_threads = std::thread::hardware_concurrency();
163 }
164 if (requested_threads == 0u) {
165 requested_threads = 1u;
166 }
167
168 const size_t npts = BKllCache::LOOKUP_SIZE;
169 const size_t nworkers = std::min<size_t>(requested_threads, npts);
170
171 if (nworkers <= 1u) {
172 auto lam_T_P = [this] (double q2, bool bar) {
173 return cache.qcdf_calculator.T_P(q2, bar);
174 };
175
176 fill_cache(lam_T_P, cache.q2_lookup_min, cache.q2_high, cache.T_P_lookup, false);
177 } else {
178 const double x_min = cache.q2_lookup_min;
179 const double x_max = cache.q2_high;
180 const double step = (x_max - x_min) / static_cast<double>(npts - 1);
181
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>(
187 B_id,
188 P_id,
189 cache.mu_b,
190 cache.C,
191 ff_local,
192 cfg.ff_type,
193 p,
195 ));
196 }
197
198 std::vector<std::thread> workers;
199 workers.reserve(nworkers);
200
201 std::exception_ptr first_exception = nullptr;
202 std::mutex exception_mutex;
203
204 auto worker = [&] (size_t worker_id, size_t begin, size_t end) {
205 try {
206 BPQCDfCalculator& qcdf = *qcdf_locals[worker_id];
207 for (size_t i = begin; i < end; ++i) {
208 const double q2 = x_min + step * static_cast<double>(i);
209 cache.T_P_lookup[i] = qcdf.T_P(q2, false);
210 }
211 } catch (...) {
212 std::lock_guard<std::mutex> lock(exception_mutex);
213 if (!first_exception) {
214 first_exception = std::current_exception();
215 }
216 }
217 };
218
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);
223 if (begin >= end) {
224 break;
225 }
226 workers.emplace_back(worker, w, begin, end);
227 }
228
229 for (auto& th : workers) {
230 th.join();
231 }
232
233 if (first_exception) {
234 std::rethrow_exception(first_exception);
235 }
236 }
237
238 // printf("alpha_em = %.4e\n", cache.alpha_em);
239 // printf("m_l = %.4e\n", cache.m_l);
240 // printf("m_s = %.4e\n", cache.m_s);
241 // printf("mu_b = %.4e\n", cache.mu_b);
242 // printf("alpha_s(mu_b) = %.4e\n", cache.alpha_s_mu_b);
243 // printf("m_b(mu_b) = %.4e\n", cache.m_b_mu_b);
244 // printf("m_b_PS = %.4e\n", cache.m_b_PS);
245 // printf("L_b = %.4e\n", cache.L_b);
246 // printf("m_B = %.4e\n", cache.m_B);
247 // printf("m_K = %.4e\n", cache.m_K);
248 // printf("Delta_M = %.4e\n", cache.Delta_M);
249 // printf("lambda_hat_u = %.4e + %.4e i\n", cache.lambda_hat_u.real(), cache.lambda_hat_u.imag());
250 // printf("N_0 = %.4e\n", cache.N_0);
251
252 // double q2 = 15.0;
253
254 // printf("f_0(s = q2 GeV²) = %.4e\n", cache.ff_calculator.get(BP_FF::F_0, q2));
255 // printf("f_+(s = q2 GeV²) = %.4e\n", cache.ff_calculator.get(BP_FF::F_PLUS, q2));
256 // printf("f_T(s = q2 GeV²) = %.4e\n", cache.ff_calculator.get(BP_FF::F_T, q2));
257
258 // printf("T_P = %.4e + %.4e i\n", real(cache.qcdf_calculator.T_P(q2, false)), imag(cache.qcdf_calculator.T_P(q2, false)));
259
260 // printf("F_A(s = q2 GeV²) = %.4e + %.4e i\n", real(F_A(q2)), imag(F_A(q2)));
261 // printf("F_V(s = q2 GeV²) = %.4e + %.4e i\n", real(F_V(q2)), imag(F_V(q2)));
262 // printf("F_S(s = q2 GeV²) = %.4e + %.4e i\n", real(F_S(q2)), imag(F_S(q2)));
263 // printf("F_P(s = q2 GeV²) = %.4e + %.4e i\n", real(F_P(q2)), imag(F_P(q2)));
264
265
266 // printf("a(s = q2 GeV²) = %.4e + %.4e i\n", real(a(q2)), imag(a(q2)));
267 // printf("b(s = q2 GeV²) = %.4e + %.4e i\n", real(b(q2)), imag(b(q2)));
268 // printf("c(s = q2 GeV²) = %.4e + %.4e i\n", real(c(q2)), imag(c(q2)));
269
271}
272
274 bool changed = cfg.gen != gen || cfg.charge != charge;
275 if (changed) {
276 cfg.gen = gen;
277 cfg.charge = charge;
279 }
280}
281
283 const double x = std::max(q2, cache.q2_lookup_min);
284 return lerp(x, cache.T_P_lookup, cache.q2_lookup_min, cache.q2_high);
285}
286
287double BKllDecay::beta_l(double q2) {
288 const double x = 1.0 - std::pow(2.0 * cache.m_l, 2) / q2;
289 return std::sqrt(std::max(0.0, x));
290}
291
292double BKllDecay::lambda(double q2) {
293 const double mB2 = cache.m_B * cache.m_B;
294 const double mK2 = cache.m_K * cache.m_K;
295
296 const double lam =
297 mB2 * mB2
298 + mK2 * mK2
299 + q2 * q2
300 - 2.0 * (mB2 * mK2 + (mB2 + mK2) * q2);
301
302 return std::max(0.0, lam);
303}
304
305double BKllDecay::N(double q2) {
306 return cache.N_0 * std::sqrt(lambda(q2)) * beta_l(q2);
307}
308
310 complex_t F, F_T;
311 double m_b_local;
312 complex_t had_err_factor {1.0};
313
314 if (cfg.ff_type == B_FF_Type::SOFT) {
315 had_err_factor = 1.0 + cache.A_had_err_low_0[0] + cache.A_had_err_low_1[0] * q2 / 6.0;
316 F_T = T_P_cached(q2);
317 F = (cache.C[WCoef::C9] + cache.C[WCoef::CP9]) * cache.ff_calculator.get(BP_FF::XI_P, q2);
318 m_b_local = cache.m_b_PS;
319 } else {
320 complex_t T_p_err_factor = 1.0 + cache.A_had_err_low_0[0] + cache.A_had_err_low_1[0] * q2 / 6.0;
321 F_T = (cache.C[WCoef::C7] + cache.C[WCoef::CP7]) * cache.ff_calculator.get(BP_FF::F_T, q2) + T_P_cached(q2) * T_p_err_factor;
322 F = (cache.C[WCoef::C9] + cache.C[WCoef::CP9] + cache.qcdf_calculator.Y(q2)) * cache.ff_calculator.get(BP_FF::F_PLUS, q2);
323 m_b_local = cache.m_b_PS + cache.alpha_s_mu_b * cache.Delta_M / (3 * PI);
324 }
325
326 // printf("C7 = %.4e\n", real(cache.C[WCoef::C7]));
327 // printf("C9 = %.4e\n", real(cache.C[WCoef::C9]));
328 // printf("C'7 = %.4e\n", real(cache.C[WCoef::CP7]));
329 // printf("C'9 = %.4e\n", real(cache.C[WCoef::CP9]));
330 // printf("m_b_local = %.4e\n", m_b_local);
331 // printf("F = %.4e + %.4e i\n", real(F), imag(F));
332 // printf("F_T = %.4e + %.4e i\n", real(F_T), imag(F_T));
333
334 return (F + 2. * m_b_local / (cache.m_B + cache.m_K) * F_T) * had_err_factor;
335}
336
338 double ff;
339
340 if (cfg.ff_type == B_FF_Type::SOFT) {
341 ff = cache.ff_calculator.get(BP_FF::XI_P, q2);
342 } else {
343 ff = cache.ff_calculator.get(BP_FF::F_PLUS, q2);
344 }
345
346 return (cache.C[WCoef::C10] + cache.C[WCoef::CP10]) * ff;
347}
348
350 double f_p, f0_fp;
351
352 if (cfg.ff_type == B_FF_Type::SOFT) {
353 f_p = cache.ff_calculator.get(BP_FF::XI_P, q2);
354 f0_fp = (std::pow(cache.m_B, 2) + std::pow(cache.m_K, 2) - q2) / std::pow(cache.m_B, 2) * cache.qcdf_calculator.Delta_P_0(q2);
355 } else {
356 f_p = cache.ff_calculator.get(BP_FF::F_PLUS, q2);
357 f0_fp = cache.ff_calculator.get(BP_FF::F_0, q2) / f_p;
358 }
359
360 // printf("Delta_P_0(s = %.5f GeV²) = %.4e\n", q2, cache.qcdf_calculator.Delta_P_0(q2));
361 // printf("f0_fp(s = %.5f GeV²) = %.4e\n", q2, f0_fp);
362
363 return f_p * ((std::pow(cache.m_B, 2) - std::pow(cache.m_K, 2)) / (2 * (cache.m_b_mu_b - cache.m_s)) * f0_fp * (cache.C[WCoefMapper::cq2_for_lepton_index(static_cast<int>(cfg.gen))] + cache.C[WCoefMapper::cpq2_for_lepton_index(static_cast<int>(cfg.gen))])
364 - cache.m_l * (cache.C[WCoef::C10] + cache.C[WCoef::CP10]) * (1. - (std::pow(cache.m_B, 2) - std::pow(cache.m_K, 2)) / q2 * (f0_fp - 1.)));
365}
366
368 double ff;
369
370 if (cfg.ff_type == B_FF_Type::SOFT) {
371 double f0_fp = 2. * (std::pow(cache.m_B, 2) + std::pow(cache.m_K, 2) - q2) / (2 * std::pow(cache.m_B, 2)) * cache.qcdf_calculator.Delta_P_0(q2);
372 ff = cache.ff_calculator.get(BP_FF::XI_P, q2) * f0_fp;
373 } else {
374 ff = cache.ff_calculator.get(BP_FF::F_0, q2);
375 }
376
377 return (std::pow(cache.m_B, 2) - std::pow(cache.m_K, 2)) / (2 * (cache.m_b_mu_b - cache.m_s)) * (cache.C[WCoefMapper::cq1_for_lepton_index(static_cast<int>(cfg.gen))] + cache.C[WCoefMapper::cpq1_for_lepton_index(static_cast<int>(cfg.gen))]) * ff;
378}
379
381 double s_hat = q2 / std::pow(cache.m_b_PS, 2);
382 complex_t A = BV::A_Seidel(s_hat, cache.L_b);
383 return cache.C[WCoef::C7] + cache.alpha_s_mu_b / (4. * PI) * ((cache.C[WCoef::C1]-6.*cache.C[WCoef::C2])*A-cache.C[WCoef::C8]*BV::f_87(s_hat, cache.L_b));
384}
385
387 complex_t C_h0 = 4./3.*cache.C[WCoef::C1]+cache.C[WCoef::C2]+11./2.*cache.C[WCoef::C3]-2./3.*cache.C[WCoef::C4]+52.*cache.C[WCoef::C5]-32./3.*cache.C[WCoef::C6];
388 complex_t C_hb = -0.5 * (7.*cache.C[WCoef::C3]+4./3.*cache.C[WCoef::C4]+76.*cache.C[WCoef::C5]+64./3.*cache.C[WCoef::C6]);
389 complex_t C_0 = 4./3.*(cache.C[WCoef::C3]+16./3.*cache.C[WCoef::C5]+16./9.*cache.C[WCoef::C6]);
390 complex_t C_mc = 8. * ((4./9.*cache.C[WCoef::C1]+1./3.*cache.C[WCoef::C2])*(1.+cache.lambda_hat_u)+2.*cache.C[WCoef::C3]+20.*cache.C[WCoef::C5]);
391
392 double s_hat = q2 / std::pow(cache.m_b_PS, 2);
393 complex_t B = BV::B_Seidel(s_hat, cache.L_b);
394 complex_t C = BV::C_Seidel(q2, cache.mu_b);
395
396 return cache.C[WCoef::C9]
397 + BV::h(q2, 0., cache.mu_b) * C_h0
398 + BV::h(q2, cache.m_b_PS, cache.mu_b) * C_hb
399 + C_0
400 + cache.alpha_s_mu_b / (4. * PI) * (cache.C[WCoef::C1]*(B + 4. * C) - 3. * cache.C[WCoef::C2] * (2. * B - C) - cache.C[WCoef::C8] * BV::f_89(s_hat))
401 + std::pow(cache.m_c_mu_b, 2) / q2 * C_mc;
402}
403
405 return (C9_eff(q2) + cache.C[WCoef::CP9]) * cache.ff_calculator.get(BP_FF::F_PLUS, q2)
406 + 2. * cache.m_b_m_b / (cache.m_B + cache.m_K) * (C7_eff(q2) + cache.C[WCoef::CP7]) * cache.ff_calculator.get(BP_FF::F_T, q2);
407}
408
410 return (cache.C[WCoef::C10] + cache.C[WCoef::CP10]) * cache.ff_calculator.get(BP_FF::F_PLUS, q2);
411}
412
414 double f_p = cache.ff_calculator.get(BP_FF::F_PLUS, q2);
415 double f0_fp = cache.ff_calculator.get(BP_FF::F_0, q2) / f_p;
416 return f_p * ((std::pow(cache.m_B, 2) - std::pow(cache.m_K, 2)) / (2 * (cache.m_b_m_b - cache.m_s)) * f0_fp * (cache.C[WCoefMapper::cq2_for_lepton_index(static_cast<int>(cfg.gen))] + cache.C[WCoefMapper::cpq2_for_lepton_index(static_cast<int>(cfg.gen))])
417 - cache.m_l * (cache.C[WCoef::C10] + cache.C[WCoef::CP10]) * (1. - (std::pow(cache.m_B, 2) - std::pow(cache.m_K, 2)) / q2 * (f0_fp - 1.)));
418}
419
421 double ff = cache.ff_calculator.get(BP_FF::F_0, q2);
422 return (std::pow(cache.m_B, 2) - std::pow(cache.m_K, 2)) / (2 * (cache.m_b_m_b - cache.m_s)) * (cache.C[WCoefMapper::cq1_for_lepton_index(static_cast<int>(cfg.gen))] + cache.C[WCoefMapper::cpq1_for_lepton_index(static_cast<int>(cfg.gen))]) * ff;
423}
424
426 if (q2 < cache.q2_low)
427 return val_low;
428
429 if (q2 > cache.q2_high)
430 return val_high;
431
432 double t = (cache.q2_high - q2) / (cache.q2_high - cache.q2_low);
433 return t * val_low + (1 - t) * val_high;
434}
435
437 return interpolate(q2, F_V_low(q2), F_V_high(q2));
438}
439
441 return interpolate(q2, F_A_low(q2), F_A_high(q2));
442}
443
445 return interpolate(q2, F_P_low(q2), F_P_high(q2));
446}
447
449 return interpolate(q2, F_S_low(q2), F_S_high(q2));
450}
451
452double BKllDecay::a(double q2) {
453 return N(q2) * (
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)
458 );
459}
460
461double BKllDecay::b(double q2) {
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)));
463}
464
465double BKllDecay::c(double 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));
467}
468
470 for (auto& v : cache.abc_binned) {
471 v.clear();
472 }
473 cache.bin_widths.clear();
474
475 if (!this->bins.has_value()) {
476 LOG_WARN("BKllDecay::compute_binned_abc called without bins.");
477 return;
478 }
479
480 constexpr double q2_min_eps = 1e-8;
481 constexpr double endpoint_eps = 1e-2;
482 constexpr double shat_eps = 1e-3;
483
484 const double q2_qcdf_max = cache.m_b_PS * cache.m_b_PS * (1.0 - shat_eps);
485
486 for (auto [q2_l, q2_u] : this->bins.value()) {
487 const double low = std::max(q2_l, cache.q2_min + q2_min_eps);
488
489 const double high = std::min({
490 q2_u,
491 cache.q2_max - endpoint_eps,
492 q2_qcdf_max
493 });
494
495 if (q2_u > high) {
496 // LOG_WARN(
497 // "BKll bin [", q2_l, ",", q2_u,
498 // "] clipped to [", low, ",", high,
499 // "] because q2_max = ", cache.q2_max,
500 // " and m_b_PS^2 safe max = ", q2_qcdf_max
501 // );
502 }
503
504 if (!(low < high)) {
505 LOG_WARN(
506 "Skipping invalid BKll bin [",
507 q2_l,
508 ",",
509 q2_u,
510 "] after clipping to [",
511 low,
512 ",",
513 high,
514 "]"
515 );
516
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());
521 continue;
522 }
523
524 const double width = high - low;
525
526 try {
527 cache.abc_binned[0].emplace_back(
528 integrate([&](double q2) { return a(q2); }, low, high, 1e-3)
529 );
530 cache.abc_binned[1].emplace_back(
531 integrate([&](double q2) { return b(q2); }, low, high, 1e-3)
532 );
533 cache.abc_binned[2].emplace_back(
534 integrate([&](double q2) { return c(q2); }, low, high, 1e-3)
535 );
536
537 cache.bin_widths.emplace_back(width);
538 } catch (const std::exception& e) {
539 LOG_WARN(
540 "BKll integration failed for bin [",
541 q2_l,
542 ",",
543 q2_u,
544 "] clipped to [",
545 low,
546 ",",
547 high,
548 "]: ",
549 e.what()
550 );
551
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());
556 }
557 }
558}
559
560std::vector<ObservableValue> BKllDecay::dBR_dq2(Observables oid, bool br) {
561 std::vector<ObservableValue> out;
562 double br_factor = br ? cache.life_B : 1.0;
563
564 for (size_t i = 0; i < this->bins.value().size(); i++) {
565 const double integrated_rate = 2.0 * (cache.abc_binned[0][i] + cache.abc_binned[2][i] / 3.0);
566 const double requested_width = this->bins.value()[i].second - this->bins.value()[i].first;
567 const double width =
568 (i < cache.bin_widths.size() && std::isfinite(cache.bin_widths[i]) && cache.bin_widths[i] > 0.0)
569 ? cache.bin_widths[i]
570 : requested_width;
571
572 const double res =
573 (std::isfinite(width) && width > 0.0)
574 ? integrated_rate * br_factor / width
575 : std::numeric_limits<double>::quiet_NaN();
576
577 out.emplace_back(ObservableMapper::to_id(oid), res, this->bins.value()[i]);
578 }
579
580 return out;
581}
582
583std::vector<ObservableValue> BKllDecay::A_FB(Observables oid) {
584 std::vector<ObservableValue> out;
585 for (size_t i = 0; i < this->bins.value().size(); i++) {
586 double res = cache.abc_binned[1][i] / (2 * (cache.abc_binned[0][i] + cache.abc_binned[2][i] / 3.));
587 out.emplace_back(ObservableMapper::to_id(oid), res, this->bins.value()[i]);
588 }
589 return out;
590}
591
592std::vector<ObservableValue> BKllDecay::F_H(Observables oid) {
593 std::vector<ObservableValue> out;
594 for (size_t i = 0; i < this->bins.value().size(); i++) {
595 double res = (cache.abc_binned[0][i] + cache.abc_binned[2][i]) / (cache.abc_binned[0][i] + cache.abc_binned[2][i] / 3.);
596 out.emplace_back(ObservableMapper::to_id(oid), res, this->bins.value()[i]);
597 }
598 return out;
599}
600
601std::vector<ObservableValue> BKllDecay::Rm1_BK(Observables id, BKllConfig::B_Charge charge) {
602 std::vector<ObservableValue> out;
603 std::vector<double> Gamma_mu;
604 std::vector<double> Gamma_e;
605
607
608 for (size_t i = 0; i < this->bins.value().size(); i++)
609 Gamma_mu.emplace_back(2 * (cache.abc_binned[0][i] + cache.abc_binned[2][i] / 3.));
610
612
613 for (size_t i = 0; i < this->bins.value().size(); i++)
614 Gamma_e.emplace_back(2 * (cache.abc_binned[0][i] + cache.abc_binned[2][i] / 3.));
615
616 for (size_t i = 0; i < this->bins.value().size(); i++)
617 out.emplace_back(ObservableMapper::to_id(id), Gamma_mu[i] / Gamma_e[i] - 1, this->bins.value()[i]);
618
619 return out;
620}
621
622std::vector<ObservableValue> BKllDecay::compute_observable(Observables obs) {
623 if (obs == Observables::R_1_B__K_L_L) {
625 }
626
627 if (obs == Observables::R_1_B0__K0_L_L) {
629 }
630
631 auto it = BKllDecay::cfg_map.find(obs);
632 if (it == BKllDecay::cfg_map.end()) {
633 LOG_ERROR(
634 "IndexError",
635 "Observable",
637 "is not configured in BKllDecay::cfg_map"
638 );
639 return {};
640 }
641
642 auto flags = it->second;
643 set_lepton_gen_and_charge(flags.first, flags.second);
644
645 if (BKllDecay::dBR_dq2_ids.contains(ObservableMapper::to_id(obs))) return dBR_dq2(obs, true);
646 if (BKllDecay::dG_dq2_ids.contains(ObservableMapper::to_id(obs))) return dBR_dq2(obs, false);
647 if (BKllDecay::A_FB_ids.contains(ObservableMapper::to_id(obs))) return A_FB(obs);
648 if (BKllDecay::F_H_ids.contains(ObservableMapper::to_id(obs))) return F_H(obs);
649
650 LOG_ERROR(
651 "IndexError",
652 "Observable",
654 "doesn't belong to the decay",
655 DecayMapper::str(this->id)
656 );
657
658 return {};
659}
660
661std::vector<ObservableValue> BKllDecay::compute_observable(ObservableId obs) {
663}
664
665void BKllDecay::set_n_threads(size_t n_threads) {
666 unsigned int available_threads = std::thread::hardware_concurrency();
667
668 if (available_threads == 0) {
669 available_threads = 1;
670 }
671
672 if (n_threads == 0) {
673 this->cfg.n_threads = available_threads;
674 return;
675 }
676
677 if (n_threads > available_threads) {
678 LOG_WARN(
679 "Requested", n_threads,
680 "threads, but only", available_threads,
681 "are available. Using", available_threads,
682 "threads instead."
683 );
684
685 this->cfg.n_threads = available_threads;
686 return;
687 }
688
689 this->cfg.n_threads = std::max<size_t>(1, n_threads);
690}
Observables
Definition GeneralEnum.h:4
@ DBR_DQ2_B__K_TAU_TAU
@ DGAMMA_DQ2_B__K_TAU_TAU
@ DBR_DQ2_B0__K0_MU_MU
@ DBR_DQ2_B0__K0_TAU_TAU
@ DGAMMA_DQ2_B0__K0_MU_MU
@ DGAMMA_DQ2_B__K_MU_MU
@ DGAMMA_DQ2_B0__K0_TAU_TAU
@ DGAMMA_DQ2_B0__K0_E_E
#define LOG_ERROR(type,...)
Macro for logging error messages and terminating the application.
Definition Logger.h:41
#define LOG_WARN(...)
Macro for logging warning messages.
Definition Logger.h:40
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].
Definition Utils.h:241
std::complex< double > complex_t
Convenience alias for std::complex<double>.
Definition Utils.h:35
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].
Definition Utils.h:276
double a(double q2)
complex_t F_A_low(double q2)
void fill_wilson_cache()
double beta_l(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.
Definition BKllDecay.cpp:81
complex_t F_S_low(double q2)
double b(double q2)
complex_t F_P_high(double q2)
double c(double q2)
complex_t C7_eff(double q2)
complex_t F_P_low(double q2)
complex_t F_A(double q2)
complex_t F_S_high(double q2)
complex_t F_V_low(double q2)
void load_cfg_dependent_params()
complex_t F_S(double q2)
std::vector< ObservableValue > compute_observable(Observables obs) override
Compute an observable given a public observable enum.
complex_t F_P(double q2)
double lambda(double q2)
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 F_V(double q2)
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 N(double q2)
double get(BP_FF a, double q2) override
complex_t T_P(double q2, bool bar)
double Delta_P_0(double q2)
complex_t Y(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).
Definition DecayParent.h:99
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)
constexpr double PI
Definition constants.h:7
constexpr double HBAR
Definition constants.h:23
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 .
Definition Configs.h:206
double alpha_s_mu_b
Definition BKllDecay.h:158
double m_b_PS
Definition BKllDecay.h:157
std::array< std::vector< double >, 3 > abc_binned
Definition BKllDecay.h:176
double q2_high
Definition BKllDecay.h:165
double q2_max
Definition BKllDecay.h:164
std::array< complex_t, 4 > A_had_err_low_1
Definition BKllDecay.h:170
double m_K
Definition BKllDecay.h:159
static constexpr size_t LOOKUP_SIZE
Definition BKllDecay.h:174
double q2_lookup_min
Definition BKllDecay.h:166
std::vector< double > bin_widths
Definition BKllDecay.h:177
BPFFCalculator ff_calculator
Definition BKllDecay.h:152
double m_b_mu_b
Definition BKllDecay.h:157
double L_b
Definition BKllDecay.h:156
double q2_low
Definition BKllDecay.h:165
double alpha_em
Definition BKllDecay.h:155
double life_B
Definition BKllDecay.h:160
BPQCDfCalculator qcdf_calculator
Definition BKllDecay.h:153
double m_s
Definition BKllDecay.h:157
double m_B
Definition BKllDecay.h:159
std::array< complex_t, 4 > A_had_err_low_0
Definition BKllDecay.h:169
double N_0
Definition BKllDecay.h:163
double m_b_m_b
Definition BKllDecay.h:157
double q2_min
Definition BKllDecay.h:164
double m_c_mu_b
Definition BKllDecay.h:157
complex_t lambda_hat_u
Definition BKllDecay.h:162
double Delta_M
Definition BKllDecay.h:161
double m_l
Definition BKllDecay.h:157
std::array< complex_t, 4 > A_had_err_high
Definition BKllDecay.h:171
double mu_b
Definition BKllDecay.h:156
std::map< WCoef, complex_t > C
Definition BKllDecay.h:151
std::array< scalar_t, LOOKUP_SIZE > T_P_lookup
Definition BKllDecay.h:175
double G_F
Definition BKllDecay.h:155
Lepton gen
Definition BKllDecay.h:145
BP_FF_Src ff_src
Definition BKllDecay.h:142
size_t n_threads
Definition BKllDecay.h:147
B_FF_Type ff_type
Definition BKllDecay.h:143
B_Charge charge
Definition BKllDecay.h:144
Configuration for computing a particle mass at a given scale.
Definition Configs.h:242
Composite identifier for a single parameter.
Definition ParamID.h:57
QCDOrder order
Perturbative QCD order used for the evolution and matching of Wilson coefficients....
Definition Configs.h:54