Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
GroupDef_BScalar.cpp
Go to the documentation of this file.
1#include "GroupDefinition.h"
3#include "Math.h"
4#include "ParameterProvider.h"
5
6#include <array>
7#include <cmath>
8#include <exception>
9#include <limits>
10#include <string_view>
11
13
14namespace {
15constexpr double kDefaultBsMassGeV = 5.36688;
16constexpr double kDefaultAWidthGeV = 1.0e-6;
17
18static double get_optional(const BlockSrc& src, std::string_view block, const LhaID& code, double fallback = 0.0) {
19 try {
20 return src.get_val(block, code);
21 } catch (const std::exception&) {
22 return fallback;
23 }
24}
25
26static double get_optional(const BlockSrc& src, std::string_view block, int code, double fallback = 0.0) {
27 return get_optional(src, block, LhaID(code), fallback);
28}
29
30static double get_optional(const BlockSrc& src, std::string_view block, std::initializer_list<int> code, double fallback = 0.0) {
31 try {
32 return src.get_val(block, code);
33 } catch (const std::exception&) {
34 return fallback;
35 }
36}
37
38static bool almost_zero(double x) {
39 return std::abs(x) < 1.0e-14;
40}
41
42static double chargino_mass(const BlockSrc& src, int i) {
43 return src.get_val("WPARAM_SI_BSM", {13, i});
44}
45
46static double stop_mass(const BlockSrc& src, int a) {
47 // WPARAM_SI_BSM {14,*} follows the helper ordering of the up-squark SLHA masses:
48 // {1000002,1000004,1000006,2000002,2000004,2000006}. The two stop entries
49 // are therefore indices 2 and 5.
50 return src.get_val("WPARAM_SI_BSM", {14, a == 0 ? 2 : 5});
51}
52
53static double stopmix(const BlockSrc& src, int mass_index, int gauge_index) {
54 // SLHA STOPMIX is 1-based: STOPMIX(i,j), i,j = 1,2.
55 return src.get_val("STOPMIX", {mass_index + 1, gauge_index + 1});
56}
57
58static double umix(const BlockSrc& src, int row, int col) {
59 // SLHA UMIX is 1-based: UMIX(i,j), i,j = 1,2.
60 return src.get_val("UMIX", {row + 1, col + 1});
61}
62
63static double vmix(const BlockSrc& src, int row, int col) {
64 // SLHA VMIX is 1-based: VMIX(i,j), i,j = 1,2.
65 return src.get_val("VMIX", {row + 1, col + 1});
66}
67
68static double nmamix(const BlockSrc& src, int a, int component) {
69 // SLHA2 NMAMIX is 1-based: rows A_1,A_2 and columns Im(H_d), Im(H_u), Im(S).
70 return src.get_val("NMAMIX", {a + 1, component + 1});
71}
72
73static double get_nmssm_optional(int nmssmrun_id, int extpar_id, double fallback = 0.0) {
75 if (bsm.exists("NMSSMRUN", LhaID(nmssmrun_id))) {
76 return static_cast<complex_t>(bsm("NMSSMRUN", LhaID(nmssmrun_id))).real();
77 }
78
80 if (passthrough.exists("EXTPAR", LhaID(extpar_id))) {
81 return static_cast<complex_t>(passthrough("EXTPAR", LhaID(extpar_id))).real();
82 }
83
84 return fallback;
85}
86
87static complex_t nmssm_pseudoscalar_threshold(const BlockSrc& src, double pseudoscalar_mass, int lepton_mass_slot) {
88 const double lambda = get_nmssm_optional(1, 61, 0.0);
89 const double kappa = get_nmssm_optional(2, 62, 0.0);
90 const double a_lambda = get_nmssm_optional(3, 63, 0.0);
91 const double mu_eff = get_nmssm_optional(5, 65, get_optional(src, "HMIX", 1, 0.0));
92
93 if (almost_zero(lambda) || almost_zero(mu_eff)) {
94 return 0.0;
95 }
96
97 const double singlet_vev = mu_eff / lambda;
98 const double denom = std::sqrt(2.0) * a_lambda + kappa * singlet_vev;
99 if (almost_zero(denom)) {
100 return 0.0;
101 }
102
103 const double tanb = src.get_val("HMIX", 2);
104 const double mW = src.get_val("MASS", 24);
105 const double mHpm = src.get_val("MASS", 37);
106 const double mt_muW = src.get_val("WPARAM_MATCH_SM", 6);
107 const double g2 = src.get_val("GAUGE", 2);
108 const double gf = src.get_val("SMINPUTS", 2);
109 const double v = std::sqrt(1.0 / (std::sqrt(2.0) * gf));
110
111 const double v_delta_m_s = v / singlet_vev
112 * (std::sqrt(2.0) * a_lambda - 2.0 * kappa * singlet_vev)
113 / denom;
114
115 complex_t cAH{0.0, -lambda * a_lambda / g2 / mW * tanb
116 * f30(mHpm * mHpm / mt_muW / mt_muW,
117 mW * mW / mt_muW / mt_muW)};
118
119 complex_t cAc{0.0, 0.0};
120
121 for (int i_chi = 0; i_chi < 2; ++i_chi) {
122 for (int j_chi = 0; j_chi < 2; ++j_chi) {
123 const double mi = chargino_mass(src, i_chi);
124 const double mj = chargino_mass(src, j_chi);
125 if (almost_zero(mi) || almost_zero(mj)) {
126 continue;
127 }
128
129 const complex_t rA =
130 -g2 / std::sqrt(2.0)
131 * (nmamix(src, 0, 0) * umix(src, 1, i_chi) * vmix(src, 0, j_chi)
132 + nmamix(src, 0, 1) * umix(src, 0, i_chi) * vmix(src, 1, j_chi))
133 -lambda / std::sqrt(2.0)
134 * nmamix(src, 0, 2) * umix(src, 1, i_chi) * vmix(src, 1, j_chi);
135
136 for (int a_stop = 0; a_stop < 2; ++a_stop) {
137 const double mstop = stop_mass(src, a_stop);
138 if (almost_zero(mstop)) {
139 continue;
140 }
141
142 const double tR = stopmix(src, a_stop, 1);
143 const double tL = stopmix(src, a_stop, 0);
144 const double g1_diag = (tR * tR - kron(a_stop + 1, 1))
145 * vmix(src, 1, j_chi) * umix(src, 1, i_chi)
146 - mt_muW / std::sqrt(2.0) / std::sin(std::atan(tanb)) / mW
147 * tL * tR * vmix(src, 1, j_chi) * umix(src, 1, i_chi);
148
149 const double x_stop_i = std::pow(mstop / mi, 2.0);
150 const double x_stop_j = std::pow(mstop / mj, 2.0);
151 const double x_chi = std::pow(mi / mj, 2.0);
152
153 const double loop_term =
154 v_delta_m_s * kron(i_chi, j_chi) * std::abs(mi / mW) * f80(x_stop_i)
155 - (rA * std::abs(mi / mj) * f30(x_stop_j, x_chi)
156 + rA * f40(x_stop_j, x_chi)).real();
157
158 cAc = complex_t(cAc.real(), cAc.imag() + tanb / std::sqrt(2.0) * g1_diag * loop_term);
159 }
160 }
161 }
162
163 const complex_t cA = cAH + cAc;
164
165 const double mBs = get_optional(src, "MASS", 531, kDefaultBsMassGeV);
166 const double widthA = get_optional(src, "DECAY", LhaID(36), kDefaultAWidthGeV);
167 const auto pole = complex_t{mBs * mBs - pseudoscalar_mass * pseudoscalar_mass,
168 pseudoscalar_mass * widthA};
169
170 if (std::abs(pole) == 0.0) {
171 return 0.0;
172 }
173
174 const double mb_muW_pole = src.get_val("WPARAM_MATCH_SM", {5, 2});
175 const double sw2 = src.get_val("WPARAM_SI_SM", 4);
176 const double ml_running = src.get_val("WPARAM_SI_SM", lepton_mass_slot);
177
178 return (v_delta_m_s / 2.0) * mb_muW_pole / sw2 * ml_running * cA / pole;
179}
180} // namespace
181
182static std::unordered_map<WCoefId, scalar_t>
183BScalar_SUSY_Base1_LO_calculation(
184 const std::unordered_map<QCDOrder, std::unordered_map<WCoefId, scalar_t>>& coef_matching,
185 const BlockSrc& src)
186{
187 auto out = BScalarCoefficientGroup::base_1_LO_calculation(coef_matching, src);
188
189 const double mA1 = get_optional(src, "MASS", 36, 0.0);
190 const double mA2 = get_optional(src, "MASS", 46, 0.0);
191 const double h3 = get_optional(src, "MASS", 45, 0.0);
192
193 // SLHA2/NMSSM: CP-even neutral Higgs masses are 25,35,45 and CP-odd
194 // masses are 36,46. If the NMSSM extension is absent, keep the generic
195 // BScalar running result.
196 if (almost_zero(h3) && almost_zero(mA2)) {
197 return out;
198 }
199
200 const double mb_muW_pole = src.get_val("WPARAM_MATCH_SM", {5, 2});
201 if (!almost_zero(mA1) && mA1 < mb_muW_pole) {
202 for (int i = 0; i < 3; ++i) {
204 nmssm_pseudoscalar_threshold(src, mA1, WCoefMapper::lepton_mass_slot_from_index(i));
205 }
206 }
207
208 return out;
209}
210
211static void Setup_BScalar_SUSY_Base1_LO(const BuildContext& ctx, CoefficientGroup& grp) {
212 std::map<QCDOrder, CGS> m;
213
214 CGS lo;
215 lo.sources = {
217 "WPARAM_RUN_SM", "WPARAM_SI_SM", "WPARAM_MATCH_SM", "WPARAM_SI_BSM" } },
218 { ParameterType::SM, { "SMINPUTS" } },
219 { ParameterType::BSM, { "GAUGE", "HMIX", "STOPMIX", "UMIX", "VMIX", "NMAMIX", "MASS" } }
220 };
221
222 // NMSSMRUN and EXTPAR are optional alternatives. Do not inspect the
223 // process-wide Parameters singleton from this build hook: group-definition
224 // integration tests deliberately construct groups without a MemoryManager.
225 // The low-mass NMSSM threshold reads whichever optional block is available
226 // at evaluation time through ParameterProvider.
227
228 lo.func = &BScalar_SUSY_Base1_LO_calculation;
229 m[QCDOrder::LO] = lo;
230
231 CGS nlo;
232 nlo.sources = {
234 "WPARAM_RUN_SM", "WPARAM_SI_SM" } }
235 };
237 m[QCDOrder::NLO] = nlo;
238
239 grp.add_sources(WilsonBasis::B_STANDARD, std::move(m));
240
241
242}
243
244namespace GroupDefinitions {
246 static const GroupDefinition def = []{
250
251 std::map<QCDOrder, CGS> m;
252 CGS lo;
253 lo.sources = {
254 { ParameterType::WILSON, { MATCHING_BLOCK_PLACEHOLDER, "WPARAM_RUN_SM", "WPARAM_SI_SM" } }
255 };
257 m[QCDOrder::LO] = lo;
258
260 m[QCDOrder::NLO] = nlo;
261
262 d.sources.emplace(WilsonBasis::B_STANDARD, std::move(m));
263
264 d.setup[Model::SUSY].push_back(&Setup_BScalar_SUSY_Base1_LO);
265 return d;
266 }();
267 return def;
268 }
269}
QCDOrder
Declarative registry describing Wilson coefficient groups, their sources, and setup hooks.
constexpr const char * MATCHING_BLOCK_PLACEHOLDER
Placeholder string used in GroupDefinition sources to refer to the matching block.
High-level access to parameter values and uncertainties.
std::complex< double > complex_t
Convenience alias for std::complex<double>.
Definition Utils.h:35
static std::unordered_map< WCoefId, scalar_t > base_1_NLO_calculation(const std::unordered_map< QCDOrder, std::unordered_map< WCoefId, scalar_t > > &coef_matching, const BlockSrc &src)
static std::unordered_map< WCoefId, scalar_t > base_1_LO_calculation(const std::unordered_map< QCDOrder, std::unordered_map< WCoefId, scalar_t > > &coef_matching, const BlockSrc &src)
Lightweight view over a set of source blocks.
Definition SourcesView.h:71
scalar_t get_val(std::string_view blk, std::initializer_list< long > code) const
Retrieves the value of a parameter given as an initializer_list.
Polymorphic container of WilsonCoefficient objects representing a coefficient group.
void add_sources(WilsonBasis basis, const std::map< QCDOrder, CoefficientGroupSources > &m)
Adds running-block sources for a given basis.
static IdOf< WCoefTag > to_id(WCoef e)
Converts an enum value to an IdOf<Tag>.
static std::string str(const WGroupId &gid, ScaleType s, WilsonBasis b=WilsonBasis::B_STANDARD)
Builds a composite block name using a WGroupId, scale and basis.
Provides access to parameter values, errors, and existence checks.
bool exists(const ParamId &pid) const
Checks if a parameter identified by ParamId exists.
static constexpr int lepton_mass_slot_from_index(int lepton_index)
static WCoef cq2_for_lepton_index(int lepton_index)
static std::vector< WCoef > get_group(WGroup g)
Returns the list of Wilson coefficients belonging to a WGroup.
Registry/factory of built-in and custom GroupDefinition objects.
Definition GroupDef_B.cpp:6
const GroupDefinition & BScalar()
double real(const scalar_t &z)
Definition scalar.cpp:83
double f40(double x, double y)
double f30(double x, double y)
double h3(double x)
Wilson special function h3 depending on x.
double f80(double x)
double kron(int x, int y)
Kronecker delta function.
Build-time context passed to group setup hooks.
WGroupId group_id
Identifier of the group being built.
Source specification and aggregation function for a coefficient group block.
Definition WilsonGroup.h:68
std::unordered_map< ParameterType, std::vector< std::string > > sources
Map of required source blocks for each ParameterType scope.
Definition WilsonGroup.h:70
std::function< std::unordered_map< WCoefId, scalar_t >(const std::unordered_map< QCDOrder, std::unordered_map< WCoefId, scalar_t > > &, const BlockSrc &)> func
Computes a set of coefficients from existing values and source blocks.
Definition WilsonGroup.h:82
Declarative description of a Wilson coefficient group.
Represents an identifier of a LHA element, possibly containing several sub-ids.
Definition LhaID.h:56