23#ifndef TRIGCONF_STANDALONE
34 std::ostringstream oss;
37 for (
const auto& val :
vec) {
51 os <<
"Bin(score=" <<
bin.score <<
", nVar=" <<
bin.nVar
60 int scale(
float val,
float min,
float max,
int bits=7) {
61 float arrRange =
max -
min;
62 int nPoints = (1 << bits) - 1;
63 float resolution = arrRange / nPoints;
64 int out =
static_cast<int>((val -
min) / resolution);
68 if (out > nPoints) out = nPoints;
76 int mapval(
int value,
const std::string & vartype){
78 static const std::map<int,int> eta_LUT = {
285 static const std::map<int,int> phi_LUT = []{
287 for (
int i = 0;
i <= 125; ++
i)
m.emplace(i,i);
293 static const std::map<int,int> pt_LUT = {
320 auto it_eta = eta_LUT.find(value);
321 return it_eta != eta_LUT.end() ? it_eta->second :
value;
324 else if (vartype==
"phi"){
325 auto it_phi = phi_LUT.find(value);
326 return it_phi != phi_LUT.end() ? it_phi->second :
value;
329 else if(vartype ==
"pt"){
330 auto it_pt = pt_LUT.find(value);
331 return it_pt != pt_LUT.end() ? it_pt->second :
value;
342 for (
auto &[name, val] : obj[
"ranges"][
"min"].items()) {
346 for (
auto &[name, val] : obj[
"ranges"][
"max"].items()) {
353 for (
size_t i = 0; i < inputEvent.size(); ++i) {
354 if (inputEvent[i] <=
minVals[i]) {
357 else if (inputEvent[i] >
maxVals[i]) {
366 for (
auto &[binName,
bin] : obj[
"bins"].items()) {
374 if(
bin.isInside(inputEvent)) {
410 const std::string bdtfn =
"TrigAnomalyDetectionBDT/2025-06-18/fwX-config_nomAD_Jun3_2pi200t20d.json";
412 std::string fileLocation;
414 #ifndef TRIGCONF_STANDALONE
420 std::ifstream configFile(fileLocation);
422 if (!configFile.is_open()) {
423 TRG_MSG_ERROR(
"Unable to open BDT configuration file." << fileLocation);
427 nlohmann::json bdt_config;
428 configFile >> bdt_config;
429 m_nVar = bdt_config[
"nDim"];
430 m_mu1_ptmin = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_pt_100MeV"][
"min"];
431 m_mu1_ptmax = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_pt_100MeV"][
"max"];
432 m_mu1_etamin = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_eta"][
"min"];
433 m_mu1_etamax = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_eta"][
"max"];
434 m_mu1_phimin = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_phi_2pi"][
"min"];
435 m_mu1_phimax = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu1_phi_2pi"][
"max"];
436 m_mu2_ptmin = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_pt_100MeV"][
"min"];
437 m_mu2_ptmax = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_pt_100MeV"][
"max"];
438 m_mu2_etamin = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_eta"][
"min"];
439 m_mu2_etamax = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_eta"][
"max"];
440 m_mu2_phimin = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_phi_2pi"][
"min"];
441 m_mu2_phimax = bdt_config[
"variable_float_ranges"][
"flat_dimu_mu2_phi_2pi"][
"max"];
443 for (
auto& [treeName,
tree] : bdt_config[
"trees"].items()) {
447 TRG_MSG_DEBUG(
"In initialize. There are " <<
m_trees.size() <<
" trees for AnomalyDetectionBDT.");
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);
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;
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];
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");
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"));
573 score +=
tree.getTreeScore(eventValues);
577 if (score > maxScore) {
595 for (
size_t k = 0; k < 3 && k < muons->
size(); ++k){
596 output[i]->push_back((*muons)[k]);
600 output[i]->setAmbiguityFlag(hasAmbiguousInputs);
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
623 if (!status.isSuccess()){
629 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)