Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
WilsonManager.cpp
Go to the documentation of this file.
1#include "WilsonManager.h"
2#include "WilsonBlockNames.h"
4#include "MartyWilson.h"
5
6
7
8static int qcd_index(QCDOrder o) {
9 switch (o) {
10 case QCDOrder::LO: return 0;
11 case QCDOrder::NLO: return 1;
12 case QCDOrder::NNLO: return 2;
13 case QCDOrder::NONE: LOG_ERROR("ValueError", "Cannot handle QCDOrder::None as qcd index");
14 }
15 return 0;
16}
17
18static constexpr std::array<QCDOrder, 3> ALL_ORDERS = {
20};
21
22static std::string hadronic_final_block_name(const std::string& groupName, WilsonBasis basis) {
24}
25
26static std::string hadronic_sm_intermediate_block_name(const std::string& groupName, WilsonBasis basis) {
27 return hadronic_final_block_name(groupName, basis) + "__SM_INTERMEDIATE";
28}
29
30static std::string hadronic_bsm_intermediate_block_name(const std::string& groupName, WilsonBasis basis) {
31 return hadronic_final_block_name(groupName, basis) + "__BSM_INTERMEDIATE";
32}
33
34static scalar_t get_block_value_or_zero(
35 const std::map<LhaID, std::shared_ptr<Parameter>>& items,
36 const LhaID& id
37) {
38 auto it = items.find(id);
39 if (it == items.end() || !it->second) {
40 return 0.0;
41 }
42 return it->second->get_val();
43}
44
45static bool hard_coded_lo_enabled(const WilsonPortsConfig& pc) {
46 return pc.hard_coded_lo && pc.hard_coded_lo->get();
47}
48
49static void compose_sm_only_triplet_for_order(
50 const std::string& groupName,
51 const std::vector<WCoefId>& members,
52 QCDOrder order,
53 WilsonPortsConfig& ports_config
54) {
55 WGroupId gid = GroupMapper::enum_elt(groupName);
56 const std::string final_block = WilsonBlockNames::matching(gid);
57
58 for (const auto& wcoef_id : members) {
59 auto base = WCoefMapper::flha_base(wcoef_id);
60
61 LhaID id_sm (base.first, base.second, qcd_index(order), 0);
62 LhaID id_bsm(base.first, base.second, qcd_index(order), 1);
63 LhaID id_tot(base.first, base.second, qcd_index(order), 2);
64
65 ParamId pid_sm { ParameterType::WILSON, final_block, id_sm };
66 ParamId pid_bsm { ParameterType::WILSON, final_block, id_bsm };
67 ParamId pid_tot { ParameterType::WILSON, final_block, id_tot };
68
69 ports_config.iblock_c->compose_parameter(
70 pid_bsm,
71 std::unordered_set<ParamId>{},
72 [](const ParamSrc&, std::shared_ptr<DependentParameter> dep) {
73 dep->set_expected(0.);
74 }
75 );
76
77 ports_config.iblock_c->compose_parameter(
78 pid_tot,
79 std::unordered_set<ParamId>{ pid_sm },
80 [pid_sm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
81 dep->set_expected(src.get_val(pid_sm));
82 }
83 );
84 }
85}
86
87static std::vector<QCDOrder> orders_up_to(QCDOrder max) {
88 std::vector<QCDOrder> out{QCDOrder::LO};
89 if (max >= QCDOrder::NLO) out.push_back(QCDOrder::NLO);
90 if (max >= QCDOrder::NNLO) out.push_back(QCDOrder::NNLO);
91 return out;
92}
93
94
95bool CoefficientManager::apply_matching_patch_to_group(
96 const std::string& groupName,
97 const WilsonMatchingPatch& patch,
98 std::size_t patch_index,
99 QCDOrder max_order
100) {
101 if (!patch.enabled) {
102 return false;
103 }
104 if (patch.order == QCDOrder::NONE || qcd_index(patch.order) > qcd_index(max_order)) {
105 return false;
106 }
107 if (!this->coefficientGroups.contains(groupName)) {
108 return false;
109 }
110
111 auto group = this->coefficientGroups.at(groupName);
112 if (!group) {
113 return false;
114 }
115 if (!(group->get_group_id() == patch.group)) {
116 return false;
117 }
118 const ContributionType group_type = group->get_type();
119 const bool contribution_compatible =
120 group_type == patch.contribution
121 || (group_type == ContributionType::TOTAL
123 if (!contribution_compatible) {
124 return false;
125 }
126
127 const std::string coeff_name = WCoefMapper::str(patch.coefficient);
128 auto coeff_it = group->find(coeff_name);
129 if (coeff_it == group->end() || !coeff_it->second) {
130 return false;
131 }
132
133 if (patch.marty_only && !std::dynamic_pointer_cast<MartyWilson>(coeff_it->second)) {
134 return false;
135 }
136
137 if (!patch.compute) {
138 LOG_ERROR("ValueError", "Wilson matching patch", patch.label, "has no compute function.");
139 }
140
141 const std::string key = groupName + "|" + std::to_string(patch_index);
142 if (this->applied_matching_patches.contains(key)) {
143 return false;
144 }
145
146 coeff_it->second->add_matching_patch(patch.order, patch.sources, patch.compute);
147 this->applied_matching_patches.insert(key);
148
150 "Applied Wilson matching patch",
151 patch.label.empty() ? std::string("<anonymous>") : patch.label,
152 "to", groupName, coeff_name, OrderMapper::str(patch.order)
153 );
154 return true;
155}
156
157void CoefficientManager::apply_matching_patches(const std::string& groupName, QCDOrder max_order) {
158 for (std::size_t i = 0; i < ports_config.matching_patches.size(); ++i) {
159 apply_matching_patch_to_group(groupName, ports_config.matching_patches[i], i, max_order);
160 }
161}
162
164 ports_config.matching_patches.push_back(patch);
165 const std::size_t patch_index = ports_config.matching_patches.size() - 1;
166
167 for (auto& [groupName, group] : this->coefficientGroups) {
168 if (!group) {
169 continue;
170 }
171 const QCDOrder reinit_order = qcd_index(group->get_order()) > qcd_index(patch.order)
172 ? group->get_order()
173 : patch.order;
174 const bool applied = apply_matching_patch_to_group(
175 groupName,
176 ports_config.matching_patches[patch_index],
177 patch_index,
178 reinit_order
179 );
180 if (applied) {
181 group->init(reinit_order);
182 }
183 }
184}
185
186void CoefficientManager::add_matching_patches(const std::vector<WilsonMatchingPatch>& patches) {
187 for (const auto& patch : patches) {
188 add_matching_patch(patch);
189 }
190}
191
192void CoefficientManager::throw_no_group_error(const std::string &groupName) const {
193 std::stringstream ss;
194 ss << "Coefficient group " << groupName << " not found in manager. Existing groups are:\n";
195 for (const auto& group : this->coefficientGroups) {
196 ss << "\t- " << group.first << "\n";
197 }
198 LOG_ERROR("KeyError", ss.str());
199}
200
202 const std::string& groupName,
203 QCDOrder max_order
204) {
205 WGroupId gid = GroupMapper::enum_elt(groupName);
206 const std::string final_block = WilsonBlockNames::matching(gid);
207
208 const auto& members = this->coefficientGroups.at(groupName)->get_member_ids();
209
210 auto wp = ports_config.wilson_proxy;
211
212 for (auto o : orders_up_to(max_order)) {
213 for (const auto& wcoef_id : members) {
214 auto base = WCoefMapper::flha_base(wcoef_id);
215
216 LhaID id_sm (base.first, base.second, qcd_index(o), 0);
217 LhaID id_bsm(base.first, base.second, qcd_index(o), 1);
218 LhaID id_tot(base.first, base.second, qcd_index(o), 2);
219
220 ParamId pid_sm { ParameterType::WILSON, final_block, id_sm };
221 ParamId pid_bsm { ParameterType::WILSON, final_block, id_bsm };
222 ParamId pid_tot { ParameterType::WILSON, final_block, id_tot };
223
224 auto zero = [](const ParamSrc&, std::shared_ptr<DependentParameter> dep) {
225 dep->set_expected(0.);
226 };
227
228 if (!wp->exist(final_block, id_sm)) ports_config.iblock_c->compose_parameter(pid_sm, {}, zero);
229 if (!wp->exist(final_block, id_bsm)) ports_config.iblock_c->compose_parameter(pid_bsm, {}, zero);
230 if (!wp->exist(final_block, id_tot)) ports_config.iblock_c->compose_parameter(pid_tot, {}, zero);
231 }
232 }
233}
234
235
237 const std::string& groupName,
238 QCDOrder max_order,
239 WilsonPortsConfig& ports_config
240) {
241 WGroupId gid = GroupMapper::enum_elt(groupName);
242 const std::string sm_block = WilsonBlockNames::sm_matching(gid);
243 const std::string final_block = WilsonBlockNames::matching(gid);
244
245 std::shared_ptr<CoefficientGroup> sm_group_ptr;
246
247 const bool marty_backend = ports_config.use_marty->get();
248 const bool hard_lo = hard_coded_lo_enabled(ports_config);
249
250 bool allow_hardcoded_sm = (marty_backend && hard_lo);
251 if (allow_hardcoded_sm && !ports_config.build_group) {
252 LOG_WARN(
253 "(CoefficientManager) HYP_AS_SM_MARTY=true but no ports_config.build_group provided; "
254 "cannot build a built-in SM group. Falling back to MARTY SM at LO."
255 );
256 allow_hardcoded_sm = false;
257 }
258
259 const bool sm_use_marty = allow_hardcoded_sm ? false : marty_backend;
260
261 const Model sm_generation_model = Model::SM;
262
263 const QCDOrder sm_max_order = (marty_backend && (max_order > QCDOrder::LO) && !allow_hardcoded_sm)
265 : max_order;
266
267 if (ports_config.build_group) {
268 sm_group_ptr = ports_config.build_group(
269 gid,
270 sm_generation_model,
271 sm_use_marty,
273 sm_block
274 );
275 } else {
276 sm_group_ptr = this->coefficientGroups.at(groupName)->get_sm_group();
277 sm_group_ptr->set_matching_storage_block(sm_block);
278 }
279
280 if (!sm_group_ptr) {
281 LOG_ERROR("LogicError", "No SM group found for " + groupName);
282 }
283
284 if (!this->coefficientGroups.contains(sm_block)) {
285 this->registerCoefficientGroup(sm_block, sm_group_ptr);
286 }
287
288 apply_matching_patches(sm_block, sm_max_order);
289 sm_group_ptr->init(sm_max_order);
290
291 const auto& members = this->coefficientGroups.at(groupName)->get_member_ids();
292
293 for (auto o : ALL_ORDERS) {
294 if (qcd_index(o) > qcd_index(sm_max_order)) continue;
295
296 for (const auto& wcoef_id : members) {
297 auto base = WCoefMapper::flha_base(wcoef_id);
298
299 LhaID id_sm(base.first, base.second, qcd_index(o), 0);
300
301 ParamId pid_src { ParameterType::WILSON, sm_block, id_sm };
302 ParamId pid_dst { ParameterType::WILSON, final_block, id_sm };
303
304 ports_config.iblock_c->compose_parameter(
305 pid_dst,
306 std::unordered_set<ParamId>{ pid_src },
307 [pid_src](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
308 dep->set_expected(src.get_val(pid_src));
309 }
310 );
311 }
312 }
313}
314
316 return ModelMapper::str(ports_config.model_api->get());
317}
318
319void CoefficientManager::init_group_matching(const std::string& groupName, const std::string& order) {
320 init_specific_order_group_matching(groupName, order, /*only_total=*/false);
321
322}
324 const std::string& groupName,
325 QCDOrder o
326) {
327 std::string storage_block = this->coefficientGroups.at(groupName)->get_matching_storage_block();
328
329 for (auto& coeff : *this->coefficientGroups.at(groupName)) {
330 auto base = WCoefMapper::enum_elt(coeff.second->get_base_name());
331
332 ParamId pid_SM { storage_block, WCoefMapper::flha_full(base, o, ContributionType::SM) };
333 ParamId pid_BSM { storage_block, WCoefMapper::flha_full(base, o, ContributionType::BSM) };
334 ParamId pid_TOT { storage_block, WCoefMapper::flha_full(base, o, ContributionType::TOTAL) };
335
336 auto zero = [] (const ParamSrc&, std::shared_ptr<DependentParameter> dep) {
337 dep->set_expected(0.);
338 };
339
340 ports_config.iblock_c->compose_parameter(pid_SM, {}, zero);
341 ports_config.iblock_c->compose_parameter(pid_BSM, {}, zero);
342 ports_config.iblock_c->compose_parameter(pid_TOT, {}, zero);
343 }
344}
345
346void CoefficientManager::fill_matching_groups(const std::string& groupName, const std::string& orderStr) {
347 QCDOrder max = OrderMapper::enum_elt(orderStr);
348
349 if (max == QCDOrder::LO) {
352 } else if (max == QCDOrder::NLO) {
354 } else {
355 }
356}
357
358
360 const std::string& groupName,
361 QCDOrder max_order,
362 WilsonPortsConfig& ports_config
363) {
364 WGroupId gid = GroupMapper::enum_elt(groupName);
365 const std::string sm_block = WilsonBlockNames::sm_matching(gid);
366 const std::string final_block = WilsonBlockNames::matching(gid);
367 const std::string fw_block = WilsonBlockNames::fwcoef();
368
369 auto wp = ports_config.wilson_proxy;
370
371 const auto& members = this->coefficientGroups.at(groupName)->get_member_ids();
372
373 for (auto o : ALL_ORDERS) {
374 if (qcd_index(o) > qcd_index(max_order)) continue;
375
376 for (const auto& wcoef_id : members) {
377 auto base = WCoefMapper::flha_base(wcoef_id);
378
379 LhaID id_sm (base.first, base.second, qcd_index(o), 0);
380 LhaID id_bsm(base.first, base.second, qcd_index(o), 1);
381 LhaID id_tot(base.first, base.second, qcd_index(o), 2);
382
383 ParamId fw_sm { ParameterType::WILSON, fw_block, id_sm };
384 ParamId fw_bsm { ParameterType::WILSON, fw_block, id_bsm };
385 ParamId fw_tot { ParameterType::WILSON, fw_block, id_tot };
386
387 const bool fw_has_sm = wp->exist(fw_block, id_sm);
388 const bool fw_has_bsm = wp->exist(fw_block, id_bsm);
389 const bool fw_has_tot = wp->exist(fw_block, id_tot);
390
391 ParamId sm_inter { ParameterType::WILSON, sm_block, id_sm };
392
393 if (fw_has_sm) {
394 ports_config.iblock_c->compose_parameter(
395 sm_inter,
396 std::unordered_set<ParamId>{ fw_sm },
397 [fw_sm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
398 dep->set_expected(src.get_val(fw_sm));
399 }
400 );
401 } else if (fw_has_tot && fw_has_bsm) {
402 ports_config.iblock_c->compose_parameter(
403 sm_inter,
404 std::unordered_set<ParamId>{ fw_tot, fw_bsm },
405 [fw_tot, fw_bsm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
406 dep->set_expected(src.get_val(fw_tot) - src.get_val(fw_bsm));
407 }
408 );
409 }
410
411 ParamId final_sm { ParameterType::WILSON, final_block, id_sm };
412 ParamId final_bsm { ParameterType::WILSON, final_block, id_bsm };
413 ParamId final_tot { ParameterType::WILSON, final_block, id_tot };
414
415 if (fw_has_bsm) {
416 ports_config.iblock_c->compose_parameter(
417 final_bsm,
418 std::unordered_set<ParamId>{ fw_bsm },
419 [fw_bsm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
420 dep->set_expected(src.get_val(fw_bsm));
421 }
422 );
423 } else if (fw_has_tot) {
424 ports_config.iblock_c->compose_parameter(
425 final_bsm,
426 std::unordered_set<ParamId>{ fw_tot, final_sm },
427 [fw_tot, final_sm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
428 dep->set_expected(src.get_val(fw_tot) - src.get_val(final_sm));
429 }
430 );
431 } else {
432 ports_config.iblock_c->compose_parameter(
433 final_bsm,
434 std::unordered_set<ParamId>{},
435 [](const ParamSrc&, std::shared_ptr<DependentParameter> dep) {
436 dep->set_expected(0.0);
437 }
438 );
439 }
440
441 if (fw_has_tot) {
442 ports_config.iblock_c->compose_parameter(
443 final_tot,
444 std::unordered_set<ParamId>{ fw_tot },
445 [fw_tot](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
446 dep->set_expected(src.get_val(fw_tot));
447 }
448 );
449 } else if (fw_has_bsm) {
450 ports_config.iblock_c->compose_parameter(
451 final_tot,
452 std::unordered_set<ParamId>{ final_sm, final_bsm },
453 [final_sm, final_bsm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
454 dep->set_expected(src.get_val(final_sm) + src.get_val(final_bsm));
455 }
456 );
457 } else {
458 ports_config.iblock_c->compose_parameter(
459 final_tot,
460 std::unordered_set<ParamId>{ final_sm },
461 [final_sm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
462 dep->set_expected(src.get_val(final_sm));
463 }
464 );
465 }
466 }
467 }
468}
469
471 const std::string& groupName,
472 QCDOrder order,
473 WilsonPortsConfig& ports_config
474) {
475 WGroupId gid = GroupMapper::enum_elt(groupName);
476 const std::string final_block = WilsonBlockNames::matching(gid);
477
478 const auto group = this->coefficientGroups.at(groupName);
479 const auto& members = group->get_member_ids();
480 const bool calculation_is_total = group->get_type() == ContributionType::TOTAL;
481
482 for (const auto& wcoef_id : members) {
483 auto base = WCoefMapper::flha_base(wcoef_id);
484
485 LhaID id_sm (base.first, base.second, qcd_index(order), 0);
486 LhaID id_bsm(base.first, base.second, qcd_index(order), 1);
487 LhaID id_tot(base.first, base.second, qcd_index(order), 2);
488
489 ParamId pid_sm { ParameterType::WILSON, final_block, id_sm };
490 ParamId pid_bsm { ParameterType::WILSON, final_block, id_bsm };
491 ParamId pid_tot { ParameterType::WILSON, final_block, id_tot };
492
493 if (calculation_is_total) {
494 // MARTY generated the complete target model directly into TOTAL.
495 // Preserve that value and derive the genuine new-physics piece.
496 ports_config.iblock_c->compose_parameter(
497 pid_bsm,
498 std::unordered_set<ParamId>{ pid_tot, pid_sm },
499 [pid_tot, pid_sm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
500 dep->set_expected(src.get_val(pid_tot) - src.get_val(pid_sm));
501 }
502 );
503 } else {
504 // Builtin BSM backends calculate the pure BSM contribution.
505 ports_config.iblock_c->compose_parameter(
506 pid_tot,
507 std::unordered_set<ParamId>{ pid_sm, pid_bsm },
508 [pid_sm, pid_bsm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
509 dep->set_expected(src.get_val(pid_sm) + src.get_val(pid_bsm));
510 }
511 );
512 }
513 }
514}
515
517 const std::string& groupName,
518 QCDOrder max_order
519) {
520 WGroupId gid = GroupMapper::enum_elt(groupName);
521 const std::string final_block = WilsonBlockNames::matching(gid);
522
523 const auto& members = this->coefficientGroups.at(groupName)->get_member_ids();
524
525 for (auto o : orders_up_to(max_order)) {
526 for (const auto& wcoef_id : members) {
527 auto base = WCoefMapper::flha_base(wcoef_id);
528
529 LhaID id_sm (base.first, base.second, qcd_index(o), 0);
530 LhaID id_bsm(base.first, base.second, qcd_index(o), 1);
531 LhaID id_tot(base.first, base.second, qcd_index(o), 2);
532
533 ParamId pid_sm { ParameterType::WILSON, final_block, id_sm };
534 ParamId pid_bsm { ParameterType::WILSON, final_block, id_bsm };
535 ParamId pid_tot { ParameterType::WILSON, final_block, id_tot };
536
537 ports_config.iblock_c->compose_parameter(
538 pid_bsm,
539 std::unordered_set<ParamId>{},
540 [](const ParamSrc&, std::shared_ptr<DependentParameter> dep) {
541 dep->set_expected(0.0);
542 }
543 );
544
545 ports_config.iblock_c->compose_parameter(
546 pid_tot,
547 std::unordered_set<ParamId>{ pid_sm, pid_bsm },
548 [pid_sm, pid_bsm](const ParamSrc& src, std::shared_ptr<DependentParameter> dep) {
549 dep->set_expected(src.get_val(pid_sm) + src.get_val(pid_bsm));
550 }
551 );
552 }
553 }
554}
555
556
558 const std::string& orderStr,
559 bool only_total)
560{
561 if (!this->coefficientGroups.contains(groupName)) {
562 throw_no_group_error(groupName);
563 }
564
565 const bool has_input = ports_config.has_wilson->get();
566 const bool marty_backend = ports_config.use_marty->get();
567 const bool hard_lo = hard_coded_lo_enabled(ports_config);
568 const bool SM_model = (ports_config.model_api->get() == Model::SM);
569
570 const QCDOrder requested = OrderMapper::enum_elt(orderStr);
571
572 const bool mixed_orders = marty_backend
573 && hard_lo
574 && (requested > QCDOrder::LO)
575 && static_cast<bool>(ports_config.build_group);
576
577 const QCDOrder marty_calc_order = (marty_backend && (requested > QCDOrder::LO))
579 : requested;
580
581 if (!has_input) {
582 if (!only_total) {
583 apply_matching_patches(groupName, marty_calc_order);
584 this->coefficientGroups.at(groupName)->init(marty_calc_order);
585 }
586
587 if (SM_model) {
588 ensure_sm_model_triplet_in_matching(groupName, marty_calc_order);
589
590 for (auto o : ALL_ORDERS) {
591 if (qcd_index(o) > qcd_index(requested)) continue;
592 if (qcd_index(o) <= qcd_index(marty_calc_order)) continue;
593 ensure_matching_triplet_zeroed(groupName, o);
594 }
595 return;
596 }
597
598 ensure_sm_intermediate_and_copy_to_final(groupName, requested, ports_config);
599
600 if (!only_total) {
601 if (marty_backend && (requested > QCDOrder::LO)) {
602 compose_missing_from_calculation(groupName, QCDOrder::LO, ports_config);
603
604 if (mixed_orders) {
605 // >LO : BSM=0 ; TOTAL=SM
606 for (auto o : ALL_ORDERS) {
607 if (o == QCDOrder::LO) continue;
608 if (qcd_index(o) > qcd_index(requested)) continue;
609 compose_sm_only_triplet_for_order(groupName, this->coefficientGroups.at(groupName)->get_member_ids(), o, ports_config);
610 }
611 } else {
612 for (auto o : ALL_ORDERS) {
613 if (o == QCDOrder::LO) continue;
614 if (qcd_index(o) > qcd_index(requested)) continue;
615 ensure_matching_triplet_zeroed(groupName, o);
616 }
617
618 if (hard_lo && !ports_config.build_group) {
619 LOG_WARN(
620 "(CoefficientManager) hard_coded_lo=true requested but ports_config.build_group is not set; "
621 "cannot compute SM beyond LO. Higher orders are zero-filled."
622 );
623 } else if (!hard_lo) {
624 LOG_WARN(
625 "(CoefficientManager) Marty backend does not support QCD orders beyond LO; "
626 "higher orders are zero-filled. Set hard_coded_lo=true (with build_group hook) to keep SM up to the requested order."
627 );
628 }
629 }
630 } else {
631 compose_missing_from_calculation(groupName, requested, ports_config);
632 }
633 }
634
635 } else {
636 ensure_sm_intermediate_and_copy_to_final(groupName, requested, ports_config);
637 compose_from_fwcoef(groupName, requested, ports_config);
638 }
639}
640
641void CoefficientManager::fill_sources_for_group(const std::string & groupName, const std::string& order, std::unordered_map<ParameterType, std::vector<std::string>>& src, WilsonBasis id) {
642 switch (OrderMapper::enum_elt(order))
643 {
644 case QCDOrder::NNLO:
645 for (const auto& [key, vec] : this->coefficientGroups[groupName]->get_sources(QCDOrder::NNLO, id)) {
646 auto& targetVec = src[key];
647 targetVec.insert(targetVec.end(), vec.begin(), vec.end());
648 }
649 [[fallthrough]];
650
651 case QCDOrder::NLO:
652 for (const auto& [key, vec] : this->coefficientGroups[groupName]->get_sources(QCDOrder::NLO, id)) {
653 auto& targetVec = src[key];
654 targetVec.insert(targetVec.end(), vec.begin(), vec.end());
655 }
656 [[fallthrough]];
657
658 case QCDOrder::LO:
659 for (const auto& [key, vec] : this->coefficientGroups[groupName]->get_sources(QCDOrder::LO, id)) {
660 auto& targetVec = src[key];
661 targetVec.insert(targetVec.end(), vec.begin(), vec.end());
662 }
663 break;
664
665 default:
666 break;
667 }
668}
669
670std::pair<WCoefId, std::pair<QCDOrder, ContributionType>> lha_wilson_deserialize(LhaID id) {
671 auto parts = id.get_parts();
672 auto w_id = std::make_pair<int, int>(parts[0], parts[1]);
673
674 auto maybe = WCoefMapper::from_flha_key(w_id.first, w_id.second);
675 if (!maybe) {
676 LOG_ERROR("ValueError", "bad lha id for wilson conversion (unknown custom/base key)");
677 }
678 WCoefId coef = *maybe;
679 QCDOrder order = parts[2] ? ((parts[2] -1) ? QCDOrder::NNLO : QCDOrder::NLO) : QCDOrder::LO;
681
682 std::pair<WCoefId, std::pair<QCDOrder, ContributionType>> ret;
683 ret = {coef, {order, part}};
684
685 return ret;
686}
687
688void CoefficientManager::init_group_hadronic(const std::string& groupName,
689 const std::string& order,
690 WilsonBasis basis) {
691 if (!this->coefficientGroups.contains(groupName)) {
692 throw_no_group_error(groupName);
693 }
694
695 std::unordered_map<ParameterType, std::vector<std::string>> running_src = {};
696 fill_sources_for_group(groupName, order, running_src, basis);
697
698 const QCDOrder ord = OrderMapper::enum_elt(order);
699
700 const std::map<QCDOrder,
701 std::function<std::unordered_map<WCoefId, scalar_t>(
702 const std::unordered_map<QCDOrder, std::unordered_map<WCoefId, scalar_t>>&,
703 const BlockSrc&)>> funcs = {
704 {QCDOrder::LO, this->coefficientGroups[groupName]->get_func(QCDOrder::LO, basis)},
705 {QCDOrder::NLO, this->coefficientGroups[groupName]->get_func(QCDOrder::NLO, basis)},
706 {QCDOrder::NNLO, this->coefficientGroups[groupName]->get_func(QCDOrder::NNLO, basis)}
707 };
708
709 const std::string matching_block_name = this->coefficientGroups[groupName]->get_matching_storage_block();
710 const auto& members = this->coefficientGroups.at(groupName)->get_member_ids();
711
712 const std::string final_block_name = hadronic_final_block_name(groupName, basis);
713 const std::string sm_run_block_name = hadronic_sm_intermediate_block_name(groupName, basis);
714 const std::string bsm_run_block_name = hadronic_bsm_intermediate_block_name(groupName, basis);
715
716 auto make_partial_running_func =
717 [matching_block_name, ord, funcs, members, groupName, basis]
718 (ContributionType kept_contrib, const std::string& target_block_name) {
719
720 return [matching_block_name, ord, funcs, kept_contrib, target_block_name, members, groupName, basis]
721 (const BlockSrc& src, std::shared_ptr<DependentBlock> dep_block) {
722 auto raw = src.raw();
723 auto it = raw.find(matching_block_name);
724 if (it == raw.end() || !it->second) {
725 return;
726 }
727
728 const auto& matching_coeff = it->second->getItems();
729
730 std::unordered_map<QCDOrder, std::unordered_map<WCoefId, scalar_t>> matching_one;
731
732 // Defensive defaulting: built-in running functions often use .at(order).at(coef).
733 // Missing BSM coefficients, missing higher orders, or custom sparse groups should
734 // therefore be represented explicitly by zero instead of leaving the key absent.
735 for (auto qcd_order : ALL_ORDERS) {
736 if (qcd_index(qcd_order) > qcd_index(ord)) {
737 continue;
738 }
739 for (const auto& wcoef_id : members) {
740 matching_one[qcd_order][wcoef_id] = 0.0;
741 }
742 }
743
744 for (const auto& [lha_id, param] : matching_coeff) {
745 auto dec = lha_wilson_deserialize(lha_id);
746 const WCoefId& wcoef = dec.first;
747 const QCDOrder& qcd_order = dec.second.first;
748 const ContributionType& contrib = dec.second.second;
749
750 if (qcd_index(qcd_order) > qcd_index(ord) || contrib != kept_contrib || !param) {
751 continue;
752 }
753
754 matching_one[qcd_order][wcoef] = param->get_val();
755 }
756
757 std::unordered_map<QCDOrder, std::unordered_map<WCoefId, scalar_t>> res_one;
758
759 auto run_order = [&](QCDOrder qcd_order) {
760 WilsonRunningValidation::require_running_function(funcs, qcd_order, groupName, basis);
761 WilsonRunningValidation::require_matching_input_complete(matching_one, members, qcd_order, groupName, basis);
762
763 auto result = funcs.at(qcd_order)(matching_one, src);
764 WilsonRunningValidation::require_running_result_known_members(result, members, qcd_order, groupName, basis);
765 res_one[qcd_order] = std::move(result);
766 };
767
768 switch (ord) {
769 case QCDOrder::NNLO:
770 run_order(QCDOrder::NNLO);
771 [[fallthrough]];
772 case QCDOrder::NLO:
773 run_order(QCDOrder::NLO);
774 [[fallthrough]];
775 case QCDOrder::LO:
776 run_order(QCDOrder::LO);
777 break;
778 default:
779 break;
780 }
781
782 for (const auto& [qcd_order, coef_map] : res_one) {
783 for (const auto& [coef_id, coef_val] : coef_map) {
784 const LhaID coef_lha = WCoefMapper::flha_full(coef_id, qcd_order, kept_contrib);
785 const ParamId pid{
787 target_block_name,
788 coef_lha
789 };
790 dep_block->store_or_assign(
791 pid.code,
792 std::make_shared<Parameter>(pid, coef_val, 0.0, static_cast<int>(kept_contrib))
793 );
794 }
795 }
796 };
797 };
798
799 auto sm_func = make_partial_running_func(ContributionType::SM, sm_run_block_name);
800 auto bsm_func = make_partial_running_func(ContributionType::BSM, bsm_run_block_name);
801
802 ports_config.iblock_c->compose_block(sm_run_block_name, running_src, sm_func);
803 ports_config.iblock_c->compose_block(bsm_run_block_name, running_src, bsm_func);
804
805 std::unordered_map<ParameterType, std::vector<std::string>> combine_src = {
806 { ParameterType::WILSON, { sm_run_block_name, bsm_run_block_name } }
807 };
808
809
810 auto combine_func =
811 [groupName, basis, ord, final_block_name, sm_run_block_name, bsm_run_block_name, members]
812 (const BlockSrc& src, std::shared_ptr<DependentBlock> dep_block) {
813 auto raw = src.raw();
814
815 auto it_sm = raw.find(sm_run_block_name);
816 auto it_bsm = raw.find(bsm_run_block_name);
817
818 if (it_sm == raw.end() || !it_sm->second) {
819 return;
820 }
821 if (it_bsm == raw.end() || !it_bsm->second) {
822 return;
823 }
824
825 const auto& sm_items = it_sm->second->getItems();
826 const auto& bsm_items = it_bsm->second->getItems();
827
828 for (auto qcd_order : ALL_ORDERS) {
829 if (qcd_index(qcd_order) > qcd_index(ord)) {
830 continue;
831 }
832
833 for (const auto& wcoef_id : members) {
834 auto base = WCoefMapper::flha_base(wcoef_id);
835
836 const LhaID id_sm (base.first, base.second, qcd_index(qcd_order), 0);
837 const LhaID id_bsm(base.first, base.second, qcd_index(qcd_order), 1);
838 const LhaID id_tot(base.first, base.second, qcd_index(qcd_order), 2);
839
840 const scalar_t sm_val = get_block_value_or_zero(sm_items, id_sm);
841 const scalar_t bsm_val = get_block_value_or_zero(bsm_items, id_bsm);
842 const scalar_t tot_val = sm_val + bsm_val;
843
844 {
845 const ParamId pid{ParameterType::WILSON, final_block_name, id_sm};
846 dep_block->store_or_assign(
847 pid.code,
848 std::make_shared<Parameter>(pid, sm_val, 0.0, static_cast<int>(ContributionType::SM))
849 );
850 }
851 {
852 const ParamId pid{ParameterType::WILSON, final_block_name, id_bsm};
853 dep_block->store_or_assign(
854 pid.code,
855 std::make_shared<Parameter>(pid, bsm_val, 0.0, static_cast<int>(ContributionType::BSM))
856 );
857 }
858 {
859 const ParamId pid{ParameterType::WILSON, final_block_name, id_tot};
860 dep_block->store_or_assign(
861 pid.code,
862 std::make_shared<Parameter>(pid, tot_val, 0.0, static_cast<int>(ContributionType::TOTAL))
863 );
864 }
865 }
866 }
867 };
868
869 ports_config.iblock_c->compose_block(final_block_name, combine_src, combine_func);
870}
871
872
873void CoefficientManager::init_group_hadronic_all_bases(const std::string &groupName, const std::string &order) {
875 fill_matching_groups(groupName, order);
876 }
877
878 for (auto basis : this->coefficientGroups.at(groupName)->get_bases()) {
879 this->init_group_hadronic(groupName, order, basis);
880 }
881}
882
883complex_t CoefficientManager::getMatchingCoefficient(const std::string& groupName, const std::string& coeffName, const std::string& order, ContributionType cont_type) {
884 complex_t c = this->coefficientGroups.at(groupName)->get_matching_coefficient(coeffName, order, cont_type);
885
886 return c;
887}
888
889complex_t CoefficientManager::getFullMatchingCoefficient(const std::string& groupName, const std::string& coeffName, const std::string& order, ContributionType cont_type) {
890 double fact = (*ports_config.wilson_proxy)("WPARAM_MATCH_SM", 1) / (4 * PI);
891 size_t max_order = static_cast<size_t>(OrderMapper::enum_elt(order));
892 complex_t c {0};
893 for (size_t o = 1; o <= max_order; o++) {
894 c += this->getMatchingCoefficient(groupName, coeffName, OrderMapper::str(static_cast<QCDOrder>(o)), cont_type) * std::pow(fact, o - 1);
895 }
896 return c;
897}
898
899complex_t CoefficientManager::getRunCoefficient(const std::string& groupName, const std::string& coeffName, const std::string& order, ContributionType cont_type, WilsonBasis basis) {
900
901 complex_t c = this->coefficientGroups.at(groupName)->get_running_coefficient(coeffName, order, cont_type, basis);
902 return c;
903}
904
905complex_t CoefficientManager::getFullRunCoefficient(const std::string& groupName, const std::string& coeffName, const std::string& order, ContributionType cont_type, WilsonBasis basis) {
906 double fact = (*ports_config.wilson_proxy)("WPARAM_RUN_SM", 1) / (4 * PI);
907 size_t max_order = static_cast<size_t>(OrderMapper::enum_elt(order));
908 complex_t c {0};
909 for (size_t o = 1; o <= max_order; o++) {
910 c += this->getRunCoefficient(groupName, coeffName, OrderMapper::str(static_cast<QCDOrder>(o)), cont_type, basis) * std::pow(fact, o - 1);
911 }
912 return c;
913}
914
915void CoefficientManager::registerCoefficientGroup(const std::string& groupName, std::shared_ptr<CoefficientGroup> group) {
916 coefficientGroups[groupName] = group;
917}
918
919std::shared_ptr<CoefficientGroup> CoefficientManager::getCoefficientGroup(const std::string& groupName) const {
920 if (!this->coefficientGroups.contains(groupName)) {
921 throw_no_group_error(groupName);
922 }
923
924 return this->coefficientGroups.at(groupName);
925}
926
927std::map<std::string, std::shared_ptr<CoefficientGroup>> CoefficientManager::getGroups() {
928 return this->coefficientGroups;
929}
930
931std::unordered_set<WilsonBasis> CoefficientManager::getGroupBases(WGroupId group) {
932 return this->coefficientGroups.at(GroupMapper::str(group))->get_bases();
933}
934
935void CoefficientManager::printGroupCoefficients(const std::string& groupName) const {
936 std::shared_ptr<CoefficientGroup> group = getCoefficientGroup(groupName);
937}
938
940 LOG_TRACE("Call to CoefficientManager destructor");
941 if (ports_config.iblock_c) {
942 ports_config.iblock_c->remove_all_composed_blocks();
943 }
944
945}
946
947void CoefficientManager::update(double mu_W, double mu_h) {
948 this->set_matching_scale(mu_W);
949 this->set_hadronic_scale(mu_h);
950}
951
952std::shared_ptr<CoefficientManager> CoefficientManager::Builder( std::map<std::string, std::shared_ptr<CoefficientGroup>> groups, double mu_W, double mu_h, std::string order, WilsonPortsConfig portconfig, std::map<Model, std::shared_ptr<IWilsonParameterHelper>> wilson_param_helpers) {
953
954 for (auto& helper : wilson_param_helpers) {
955 for (const auto& elem : groups) {
956 helper.second->init(2, GroupMapper::enum_elt(elem.first));
957 }
958 }
959
960 if (groups.empty()) {
961 return std::make_shared<CoefficientManager>(portconfig);
962 }
963
964 auto manager = std::make_shared<CoefficientManager>(portconfig);
965 for (auto& group : groups) {
966 LOG_DEBUG("(CoefficientManager) Registering coefficient group", group.first);
967 manager->registerCoefficientGroup(group.first, group.second);
968 }
969 LOG_DEBUG("(CoefficientManager) Setting matching scale");
970 manager->set_matching_scale(mu_W);
971 LOG_DEBUG("(CoefficientManager) Setting hadronic scale");
972 manager->set_hadronic_scale(mu_h);
973 for (auto& group: groups) {
974 LOG_DEBUG("(CoefficientManager) Initializing group matching", group.first, "at", order);
975 manager->init_group_matching(group.first, order);
976 LOG_DEBUG("(CoefficientManager) Initializing group hadronic", group.first, "at", order);
977 manager->init_group_hadronic_all_bases(group.first, order);
978 }
979 LOG_DEBUG("(CoefficientManager) Manager successfully initialized");
980 return manager;
981}
982
984 ports_config.scale_setter_api->switch_param(ScaleType::HADRONIC);
985 ports_config.scale_setter_api->set(mu_h);
986}
987
989 ports_config.scale_setter_api->switch_param(ScaleType::MATCHING);
990 ports_config.scale_setter_api->set(mu_W);
991}
Model
QCDOrder
WilsonBasis
ParameterType
ContributionType
#define LOG_ERROR(type,...)
Macro for logging error messages and terminating the application.
Definition Logger.h:41
#define LOG_TRACE(...)
Macro for logging trace messages.
Definition Logger.h:46
#define LOG_DEBUG(...)
Macro for logging debug messages.
Definition Logger.h:45
#define LOG_VERBOSE(...)
Macro for logging verbose messages.
Definition Logger.h:47
#define LOG_WARN(...)
Macro for logging warning messages.
Definition Logger.h:40
WilsonCoefficient implementation whose matching is produced by a MARTY backend.
std::complex< double > complex_t
Convenience alias for std::complex<double>.
Definition Utils.h:35
Centralizes canonical SLHA/LHA block naming conventions for Wilson blocks.
std::pair< WCoefId, std::pair< QCDOrder, ContributionType > > lha_wilson_deserialize(LhaID id)
High-level orchestration of Wilson coefficient groups (matching + running/hadronic).
Lightweight view over a set of source blocks.
Definition SourcesView.h:71
void compose_from_fwcoef(const std::string &groupName, QCDOrder order, WilsonPortsConfig &ports_config)
Composes matching triplets from an input FWCOEF-like block into final storage block.
void init_group_hadronic_all_bases(const std::string &groupName, const std::string &order)
Initializes hadronic blocks for all bases supported by the group.
void set_hadronic_scale(double mu_h)
Switches to hadronic scale context and sets mu_h via scale_setter_api.
void init_specific_order_group_matching(const std::string &groupName, const std::string &order, bool only_total)
Initializes matching parameters for a specific QCD order.
void ensure_sm_intermediate_and_copy_to_final(const std::string &groupName, QCDOrder order, WilsonPortsConfig &ports_config)
Ensures an SM intermediate matching block exists and copies SM entries into the final block.
std::map< std::string, std::shared_ptr< CoefficientGroup > > getGroups()
Returns all registered groups.
void add_matching_patches(const std::vector< WilsonMatchingPatch > &patches)
Add several additive matching patches.
void set_matching_scale(double mu_W)
Switches to matching scale context and sets mu_W via scale_setter_api.
void ensure_final_triplet_defaults_zero(const std::string &groupName, QCDOrder max_order)
Ensures final matching block has triplet parameters defined (SM/BSM/TOTAL) defaulting to zero if abse...
complex_t getRunCoefficient(const std::string &groupName, const std::string &coeffName, const std::string &order, ContributionType cont_type, WilsonBasis basis=WilsonBasis::B_STANDARD)
Returns running/hadronic coefficient (raw, order slot) for given basis and contribution type.
std::shared_ptr< CoefficientGroup > getCoefficientGroup(const std::string &groupName) const
Retrieves a registered coefficient group by name (throws/logs on missing).
static std::shared_ptr< CoefficientManager > Builder(std::map< std::string, std::shared_ptr< CoefficientGroup > > groups, double mu_W, double mu_h, std::string order, WilsonPortsConfig portconfig, std::map< Model, std::shared_ptr< IWilsonParameterHelper > > wilson_param_helpers={})
Factory that builds and initializes a manager from pre-created groups.
std::unordered_set< WilsonBasis > getGroupBases(WGroupId group)
Returns bases supported by the group (delegates to CoefficientGroup::get_bases()).
void add_matching_patch(const WilsonMatchingPatch &patch)
Add one additive matching patch and apply it to already-registered groups when relevant.
void printGroupCoefficients(const std::string &groupName) const
Debug helper (currently stubby in implementation).
void update(double mu_W, double mu_h)
Updates the manager by changing scales (delegates to set_matching_scale / set_hadronic_scale).
void compose_missing_from_calculation(const std::string &groupName, QCDOrder order, WilsonPortsConfig &ports_config)
For a given group/order, composes the “missing piece” of the triplet using algebraic relations.
void fill_matching_groups(const std::string &groupName, const std::string &order)
Ensures missing higher-order matching triplets are present/zeroed when only lower order is requested.
std::string getModel()
Returns current model as a string (via model_api).
void ensure_matching_triplet_zeroed(const std::string &groupName, QCDOrder o)
Ensures that, for a given order, SM/BSM/TOTAL slots exist and are set to 0 in the group matching bloc...
void fill_sources_for_group(const std::string &groupName, const std::string &order, std::unordered_map< ParameterType, std::vector< std::string > > &src, WilsonBasis id)
Gathers source block names needed to build hadronic/running block dependencies.
complex_t getFullMatchingCoefficient(const std::string &groupName, const std::string &coeffName, const std::string &order, ContributionType cont_type)
Returns “full” matching coefficient including perturbative prefactor powers.
void init_group_matching(const std::string &groupName, const std::string &order)
Initializes matching-side parameters for a group up to order.
void ensure_sm_model_triplet_in_matching(const std::string &groupName, QCDOrder max_order)
Ensures SM-model semantics: BSM=0 and TOTAL=SM for all coefficients up to max_order in final matching...
~CoefficientManager()
Destructor.
void init_group_hadronic(const std::string &groupName, const std::string &order, WilsonBasis id)
Initializes hadronic (running) block for one basis.
complex_t getFullRunCoefficient(const std::string &groupName, const std::string &coeffName, const std::string &order, ContributionType cont_type, WilsonBasis basis=WilsonBasis::B_STANDARD)
Returns “full” running coefficient including perturbative prefactor powers.
complex_t getMatchingCoefficient(const std::string &groupName, const std::string &coeffName, const std::string &order, ContributionType cont_type)
Returns matching coefficient (raw, order slot) for a given contribution type.
void registerCoefficientGroup(const std::string &groupName, std::shared_ptr< CoefficientGroup > group)
Registers a coefficient group under a given name.
static std::string str(const IdOf< ModelTag > &id)
Returns the string representation associated with an identifier.
static IdOf< WGroupTag > enum_elt(std::string_view s)
Alias for id_of(), kept for compatibility.
static std::string str(const IdOf< WCoefTag > &id)
Returns the string representation of an identifier.
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.
static QCDOrder enum_elt(std::string_view s)
Legacy lookup: converts a string into a QCDOrder enum. Performs a case-insensitive search over the bu...
Lightweight view over a set of source parameters keyed by ParamId.
scalar_t get_val(const ParamId &id) const
Retrieves the current value of a parameter.
Returns an uppercase copy of the input string.
static std::pair< int, int > flha_base(WCoef e)
Returns the base FLHA pair (a,b) for a given WCoef.
static LhaID flha_full(WCoef e, QCDOrder q, ContributionType c)
static std::optional< WCoefId > from_flha_key(int a, int b)
Registry-based lookup of WCoefId from a FLHA base key (a,b).
Definition wcoef_ids.hpp:94
constexpr double PI
Definition constants.h:7
void require_matching_input_complete(const std::unordered_map< QCDOrder, std::unordered_map< WCoefId, scalar_t > > &matching, const std::vector< WCoefId > &members, QCDOrder order, const std::string &group_name, WilsonBasis basis)
void require_running_function(const std::map< QCDOrder, std::function< std::unordered_map< WCoefId, scalar_t >(const std::unordered_map< QCDOrder, std::unordered_map< WCoefId, scalar_t > > &, const BlockSrc &)> > &funcs, QCDOrder order, const std::string &group_name, WilsonBasis basis)
void require_running_result_known_members(const std::unordered_map< WCoefId, scalar_t > &result, const std::vector< WCoefId > &members, QCDOrder order, const std::string &group_name, WilsonBasis basis)
Represents an identifier of a LHA element, possibly containing several sub-ids.
Definition LhaID.h:56
Composite identifier for a single parameter.
Definition ParamID.h:57
static std::string matching(WGroupId gid)
Returns the canonical matching block name for a Wilson group.
static constexpr const char * fwcoef()
Returns the fixed FWCOEF block name.
static std::string sm_matching(WGroupId gid)
Returns the SM-only matching block name for a Wilson group.
ContributionType contribution
WilsonMatchingPatchFunction compute
std::unordered_set< ParamId > sources
Aggregates “ports” / APIs that connect the manager to the rest of the framework.
std::vector< WilsonMatchingPatch > matching_patches
Additive matching patches applied before group initialization.
std::shared_ptr< ICoreAPI< bool > > hard_coded_lo
std::shared_ptr< IParameterProxy< std::string, LhaID > > wilson_proxy
Read-only access to existing blocks/parameters (FWCOEF, matching blocks, etc.).
std::shared_ptr< IParamSetter< ScaleType > > scale_setter_api
Scale setter used to switch and set mu_W / mu_h.
std::shared_ptr< ICoreAPI< Model > > model_api
Current model selector (SM/SUSY/THDM...).
std::shared_ptr< IBlockComposer > iblock_c
Dependency engine used to compose derived blocks/parameters.
std::shared_ptr< ICoreAPI< bool > > use_marty
Backend selector: true => Marty, false => builtin.
std::function< std::shared_ptr< CoefficientGroup >(WGroupId, Model, bool, ContributionType, std::string)> build_group
Optional group builder hook.
std::shared_ptr< ICoreAPI< bool > > has_wilson
Whether an input Wilson block exists (FWCOEF-style input present).