23#ifndef TRIGCONF_STANDALONE
33 std::ostringstream oss;
36 for (
const auto& val :
vec) {
50 os <<
"Bin(score=" <<
bin.score <<
", nVar=" <<
bin.nVar
59 int scale(
float val,
float min,
float max,
int bits=7) {
60 float arrRange =
max -
min;
61 int nPoints = (1 << bits) - 1;
62 float resolution = arrRange / nPoints;
63 int out =
static_cast<int>((val -
min) / resolution);
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;
341 for (
auto &[name, val] : obj[
"ranges"][
"min"].items()) {
345 for (
auto &[name, val] : obj[
"ranges"][
"max"].items()) {
352 for (
size_t i = 0; i < inputEvent.size(); ++i) {
353 if (inputEvent[i] <=
minVals[i]) {
356 else if (inputEvent[i] >
maxVals[i]) {
365 for (
auto &[binName,
bin] : obj[
"bins"].items()) {
373 if(
bin.isInside(inputEvent)) {
409 const std::string bdtfn =
"TrigAnomalyDetectionBDT/2025-06-18/fwX-config_nomAD_Jun3_2pi200t20d.json";
411 std::string fileLocation;
413 #ifndef TRIGCONF_STANDALONE
419 std::ifstream configFile(fileLocation);
421 if (!configFile.is_open()) {
422 TRG_MSG_ERROR(
"Unable to open BDT configuration file." << fileLocation);
426 nlohmann::json bdt_config;
427 configFile >> bdt_config;
428 m_nVar = bdt_config[
"nDim"];
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"];
442 for (
auto& [treeName,
tree] : bdt_config[
"trees"].items()) {
446 TRG_MSG_DEBUG(
"In initialize. There are " <<
m_trees.size() <<
" trees for AnomalyDetectionBDT.");
456 std::string hname_accept =
"hAnomalyDetecionBDT_accept_bit"+std::to_string((
int)i);
457 std::string hname_reject =
"hAnomalyDetecionBDT_reject_bit"+std::to_string((
int)i);
467 const std::vector<TCS::TOBArray *> & output,
470 if (input.size() != 1){
471 TCS_EXCEPTION(
"ADBDT algorithm expects only one TOBArray input (muons), but got " << input.size());
479 if (muons->
size() < 2) {
480 TRG_MSG_DEBUG(
"There are less than 2 muons. Skipping event.");
487 int64_t maxScore = 0;
491 std::vector<std::pair<int, int>> muonPairs;
492 for (
size_t i = 0; i < nMuons; ++i) {
493 for (
size_t j = i+1; j < nMuons; ++j) {
494 muonPairs.emplace_back(i, j);
498 for (
const auto& [i,j] : muonPairs) {
500 std::vector<int64_t> eventValues;
502 const auto& mu1 = (*muons)[i];
503 const auto& mu2 = (*muons)[j];
516 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");
520 if (mapval(mu1.Et(),
"pt") ==
int(mu1.Et()) || mapval(mu2.Et(),
"pt") ==
int(mu2.Et())) {
526 if (mapval(mu1.eta(),
"eta") == mu1.eta() || mapval(mu2.eta(),
"eta") == mu2.eta()) {
532 if (mapval(mu1.phi(),
"phi") == mu1.phi() || mapval(mu2.phi(),
"phi") == mu2.phi()) {
535 TRG_MSG_DEBUG(
"No input transformation done by LUT for muon Phi");
550 eventValues.push_back(mapval(mu1.Et(),
"pt"));
551 eventValues.push_back(mapval(mu1.eta(),
"eta"));
552 eventValues.push_back(mapval(mu1.phi(),
"phi"));
554 eventValues.push_back(mapval(mu2.Et(),
"pt"));
555 eventValues.push_back(mapval(mu2.eta(),
"eta"));
556 eventValues.push_back(mapval(mu2.phi(),
"phi"));
572 score +=
tree.getTreeScore(eventValues);
576 if (score > maxScore) {
594 for (
size_t k = 0; k < 3 && k < muons->
size(); ++k){
595 output[i]->push_back((*muons)[k]);
599 output[i]->setAmbiguityFlag(hasAmbiguousInputs);
610 TRG_MSG_DEBUG(
"Decision for bit " << i <<
": " <<(accept?
"pass":
"fail") <<
"with an anomaly score = " <<
m_totalScore << std::endl);
616 const std::vector<TCS::TOBArray *> & output,
618#ifdef TRIGCONF_STANDALONE
622 if (!status.isSuccess()){
628 TRG_MSG_WARNING(
"ADBDT:The calculated anomaly score exceeds the allowed number of bits.");
#define REGISTER_ALG_TCS(CLASS)
std::string vectorToString(const std::vector< T > &vec)
std::vector< size_t > vec
#define TRG_MSG_WARNING(x)
#define TCS_EXCEPTION(MSG)
static std::string find_calib_file(const std::string &logical_file_name)
virtual StatusCode process(const std::vector< TCS::TOBArray const * > &input, const std::vector< TCS::TOBArray * > &output, Decision &decision)
virtual StatusCode processBitCorrect(const std::vector< TCS::TOBArray const * > &input, const std::vector< TCS::TOBArray * > &output, Decision &decision)
AnomalyDetectionBDT(const std::string &name)
virtual ~AnomalyDetectionBDT()
std::vector< Tree > m_trees
parType_t p_ScoreThreshold[2]
virtual StatusCode initialize()
std::vector< int64_t > minVals
std::vector< int64_t > maxVals
bool isInside(const std::vector< int64_t > &inputEvent) const
Bin(const nlohmann::json &obj, int nVars)
const Parameter & parameter(const std::string ¶meterName) const
const std::string & name() const
void bookHist(std::vector< std::string > ®Name, const std::string &name, const std::string &title, const int binx, const int xmin, const int xmax)
void fillHist1D(const std::string &histName, double x)
void defineParameter(const std::string &name, TCS::parType_t value)
void setNumberOutputBits(unsigned int numberOutputBits)
DecisionAlg(const std::string &name)
bool fillHistosBasedOnHardware() const
! getter
bool fillHistos() const
whether the monitoring histograms should be filled
std::vector< std::string > m_histAccept
std::vector< std::string > m_histReject
unsigned int numberOutputBits() const
bool getDecisionHardwareBit(const unsigned int &bitNumber) const
! get one hardware decision bit from this algo
void setBit(unsigned int index, bool value)
Tree(const nlohmann::json &obj, int nVars)
int64_t getTreeScore(const std::vector< int64_t > &inputEvent) const
std::ostream & operator<<(std::ostream &os, const TCS::Bin &bin)
bool isAmbiguousAnywhere(TCS::TOBArray const *tobs, size_t pos, unsigned minEt=0)