23 #ifndef TRIGCONF_STANDALONE
33 std::ostringstream oss;
36 for (
const auto&
val :
vec) {
50 os <<
"Bin(score=" <<
bin.score <<
", nVar=" <<
bin.nVar
60 float arrRange =
max -
min;
61 int nPoints = (1 << bits) - 1;
67 if (
out > nPoints)
out = nPoints;
75 int mapval(
int value,
const std::string & vartype){
77 static const std::map<int,int> eta_LUT = {
284 static const std::map<int,int> phi_LUT = []{
286 for (
int i = 0;
i <= 125; ++
i)
m.emplace(
i,
i);
292 static const std::map<int,int> pt_LUT = {
319 auto it_eta = eta_LUT.find(
value);
320 return it_eta != eta_LUT.end() ? it_eta->second :
value;
323 else if (vartype==
"phi"){
324 auto it_phi = phi_LUT.find(
value);
325 return it_phi != phi_LUT.end() ? it_phi->second :
value;
328 else if(vartype ==
"pt"){
329 auto it_pt = pt_LUT.find(
value);
330 return it_pt != pt_LUT.end() ? it_pt->second :
value;
340 :
score(
obj[
"score"]), nVar(nVars) {
352 for (
size_t i = 0;
i < inputEvent.size(); ++
i) {
373 if(
bin.isInside(inputEvent)) {
402 p_MaxTob = parameter(
"MaxTob").value();
403 p_minEt1 = parameter(
"MinET1").value();
404 p_minEt2 = parameter(
"MinET2").value();
405 for (
size_t i=0;
i <numberOutputBits(); ++
i) {
406 p_ScoreThreshold[
i] = parameter(
"ScoreThreshold",
i).value();
408 TRG_MSG_INFO(
"ADBDT: Threshold set to " << p_ScoreThreshold);
409 const std::string bdtfn =
"TrigAnomalyDetectionBDT/2025-06-18/fwX-config_nomAD_Jun3_2pi200t20d.json";
411 std::string fileLocation;
413 #ifndef TRIGCONF_STANDALONE
422 TRG_MSG_ERROR(
"Unable to open BDT configuration file." << fileLocation);
429 m_mu1_ptmin =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_pt_100MeV"][
"min"];
430 m_mu1_ptmax =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_pt_100MeV"][
"max"];
431 m_mu1_etamin =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_eta"][
"min"];
432 m_mu1_etamax =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_eta"][
"max"];
433 m_mu1_phimin =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_phi_2pi"][
"min"];
434 m_mu1_phimax =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_phi_2pi"][
"max"];
435 m_mu2_ptmin =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_pt_100MeV"][
"min"];
436 m_mu2_ptmax =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_pt_100MeV"][
"max"];
437 m_mu2_etamin =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_eta"][
"min"];
438 m_mu2_etamax =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_eta"][
"max"];
439 m_mu2_phimin =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_phi_2pi"][
"min"];
440 m_mu2_phimax =
bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_phi_2pi"][
"max"];
444 m_trees.push_back(
t);
447 TRG_MSG_DEBUG(
"In initialize. There are " << m_trees.size() <<
" trees for AnomalyDetectionBDT.");
456 for (
size_t i=0;
i<numberOutputBits(); ++
i) {
457 std::string hname_accept =
"hAnomalyDetecionBDT_accept_bit"+
std::to_string((
int)
i);
458 std::string hname_reject =
"hAnomalyDetecionBDT_reject_bit"+
std::to_string((
int)
i);
460 bookHist(m_histAccept, hname_accept,
"AnomalyScore", 100, 0, 128);
461 bookHist(m_histReject, hname_reject,
"AnomalyScore", 100, 0, 128);
468 const std::vector<TCS::TOBArray *> & output,
471 if (input.size() != 1){
472 TCS_EXCEPTION(
"ADBDT algorithm expects only one TOBArray input (muons), but got " << input.size());
480 if (muons->
size() < 2) {
481 TRG_MSG_DEBUG(
"There are less than 2 muons. Skipping event.");
488 int64_t maxScore = 0;
490 size_t nMuons = p_MaxTob > 0 ?
std::min(muons->
size(), p_MaxTob) : muons->
size();
492 std::vector<std::pair<int, int>> muonPairs;
493 for (
size_t i = 0;
i < nMuons; ++
i) {
494 for (
size_t j =
i+1; j < nMuons; ++j) {
495 muonPairs.emplace_back(
i, j);
499 for (
const auto& [
i,j] : muonPairs) {
501 std::vector<int64_t> eventValues;
503 const auto& mu1 = (*muons)[
i];
504 const auto& mu2 = (*muons)[j];
507 if (
parType_t( mu1.Et() ) <= p_minEt1 )
continue;
508 if (
parType_t( mu2.Et() ) <= p_minEt2 )
continue;
510 if (
scale(mu1.Et(),m_mu1_ptmin, m_mu1_ptmax) != mapval(mu1.Et(),
"pt")
511 ||
scale(mu1.eta()/40.0, m_mu1_etamin, m_mu1_etamax) != mapval(mu1.eta(),
"eta")
512 ||
scale(mu1.phi()/20.0, m_mu1_phimin, m_mu1_phimax) != mapval(mu1.phi(),
"phi")
513 ||
scale(mu2.Et(),m_mu2_ptmin, m_mu2_ptmax) != mapval(mu2.Et(),
"pt")
514 ||
scale(mu2.eta()/40.0, m_mu2_etamin, m_mu2_etamax) != mapval(mu2.eta(),
"eta")
515 ||
scale(mu2.phi()/20.0, m_mu2_phimin, m_mu2_phimax) != mapval(mu2.phi(),
"phi")){
517 TRG_MSG_WARNING(
"The math function for the mapping of Muon pt,eta,or phi does not match the LUT mapping. Check LUT, 'scale' function, or if illegal vartype was given to 'mapval' function");
521 if (mapval(mu1.Et(),
"pt") ==
int(mu1.Et()) || mapval(mu2.Et(),
"pt") ==
int(mu2.Et())) {
527 if (mapval(mu1.eta(),
"eta") == mu1.eta() || mapval(mu2.eta(),
"eta") == mu2.eta()) {
533 if (mapval(mu1.phi(),
"phi") == mu1.phi() || mapval(mu2.phi(),
"phi") == mu2.phi()) {
536 TRG_MSG_DEBUG(
"No input transformation done by LUT for muon Phi");
540 if (m_sim_mode ==
"math"){
541 eventValues.push_back(
scale(mu1.Et(), m_mu1_ptmin, m_mu1_ptmax));
542 eventValues.push_back(
scale(mu1.eta()/40.0, m_mu1_etamin, m_mu1_etamax));
543 eventValues.push_back(
scale(mu1.phi()/20.0, m_mu1_phimin, m_mu1_phimax));
545 eventValues.push_back(
scale(mu2.Et(), m_mu2_ptmin, m_mu2_ptmax));
546 eventValues.push_back(
scale(mu2.eta()/40.0, m_mu2_etamin, m_mu2_etamax));
547 eventValues.push_back(
scale(mu2.phi()/20.0, m_mu2_phimin, m_mu2_phimax));
550 else if(m_sim_mode ==
"lut"){
551 eventValues.push_back(mapval(mu1.Et(),
"pt"));
552 eventValues.push_back(mapval(mu1.eta(),
"eta"));
553 eventValues.push_back(mapval(mu1.phi(),
"phi"));
555 eventValues.push_back(mapval(mu2.Et(),
"pt"));
556 eventValues.push_back(mapval(mu2.eta(),
"eta"));
557 eventValues.push_back(mapval(mu2.phi(),
"phi"));
561 eventValues.push_back(
scale(mu1.Et(), m_mu1_ptmin, m_mu1_ptmax));
562 eventValues.push_back(
scale(mu1.eta()/40.0, m_mu1_etamin, m_mu1_etamax));
563 eventValues.push_back(
scale(mu1.phi()/20.0, m_mu1_phimin, m_mu1_phimax));
565 eventValues.push_back(
scale(mu2.Et(), m_mu2_ptmin, m_mu2_ptmax));
566 eventValues.push_back(
scale(mu2.eta()/40.0, m_mu2_etamin, m_mu2_etamax));
567 eventValues.push_back(
scale(mu2.phi()/20.0, m_mu2_phimin, m_mu2_phimax));
577 if (
score > maxScore) {
582 m_totalScore = maxScore;
586 for (
size_t i=0;
i<numberOutputBits(); ++
i){
592 if (m_totalScore > p_ScoreThreshold[
i]) {
595 for (
size_t k = 0;
k < 3 &&
k < muons->
size(); ++
k){
596 output[
i]->push_back((*muons)[
k]);
600 output[
i]->setAmbiguityFlag(hasAmbiguousInputs);
603 const bool fillAccept = fillHistosBasedOnHardware() ? getDecisionHardwareBit(
i) :
accept;
605 fillHist1D(m_histAccept[
i], m_totalScore);
607 fillHist1D(m_histReject[
i], m_totalScore);
611 TRG_MSG_DEBUG(
"Decision for bit " <<
i <<
": " <<(
accept?
"pass":
"fail") <<
"with an anomaly score = " << m_totalScore << std::endl);
617 const std::vector<TCS::TOBArray *> & output,
619 #ifdef TRIGCONF_STANDALONE
628 if (m_totalScore >= (1
L << 8)) {
629 TRG_MSG_WARNING(
"ADBDT:The calculated anomaly score exceeds the allowed number of bits.");