From 26a63100750be80e33173f5b456b2c5fe5e33152 Mon Sep 17 00:00:00 2001 From: Nicolo Valle Date: Fri, 10 Apr 2026 15:51:32 +0200 Subject: [PATCH 1/5] ITS Beam background studies - first workflow --- .../ITS/postprocessing/studies/CMakeLists.txt | 1 + .../ITSStudies/ITSBeamBackgroundStudy.h | 26 + .../studies/src/ITSBeamBackgroundStudy.cxx | 730 ++++++++++++++++++ .../standalone-postprocessing-workflow.cxx | 15 +- 4 files changed, 771 insertions(+), 1 deletion(-) create mode 100644 Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h create mode 100644 Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/CMakeLists.txt b/Detectors/ITSMFT/ITS/postprocessing/studies/CMakeLists.txt index 9794b69631d57..08ced25d0f5dc 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/CMakeLists.txt @@ -15,6 +15,7 @@ SOURCES src/ImpactParameter.cxx src/PIDStudy.cxx src/ITSStudiesConfigParam.cxx src/AnomalyStudy.cxx + src/ITSBeamBackgroundStudy.cxx src/TrackCheck.cxx src/TrackExtension.cxx src/Efficiency.cxx diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h new file mode 100644 index 0000000000000..cd96a9df8dee6 --- /dev/null +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/include/ITSStudies/ITSBeamBackgroundStudy.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ITS_BEAMBKG_STUDY_H +#define O2_ITS_BEAMBKG_STUDY_H + +#include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +namespace o2::its::study +{ + +using mask_t = o2::dataformats::GlobalTrackID::mask_t; + +o2::framework::DataProcessorSpec getITSBeamBackgroundStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC); + +} // namespace o2::its::study +#endif diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx new file mode 100644 index 0000000000000..5a445d278b76c --- /dev/null +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx @@ -0,0 +1,730 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITSStudies/ITSBeamBackgroundStudy.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "DataFormatsParameters/GRPObject.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" + +#include +#include +#include + +#include +#include + +#include "Framework/Task.h" +#include "Framework/Logger.h" + +// ZDC +#include "DataFormatsZDC/RecEventFlat.h" + +using namespace o2::framework; +using namespace o2::globaltracking; +using GTrackID = o2::dataformats::GlobalTrackID; + +namespace o2::its::study +{ +class ITSBeamBackgroundStudy : public Task +{ + public: + ITSBeamBackgroundStudy(std::shared_ptr dr, + std::shared_ptr gr, + bool isMC) : mDataRequest{dr}, mGGCCDBRequest(gr), mUseMC(isMC) {} + + void init(InitContext& ic) final; + void run(ProcessingContext&) final; + void endOfStream(EndOfStreamContext&) final; + void finaliseCCDB(ConcreteDataMatcher&, void*) final; + void save_and_reset(); + + // Custom + void process(o2::globaltracking::RecoContainer& recoData); + void updateTimeDependentParams(ProcessingContext& pc); + + private: + void getClusterPatterns(gsl::span&, gsl::span&, const o2::itsmft::TopologyDictionary&); + std::vector mPatterns; + + // ITS layout + int NStaves[7] = {12, 16, 20, 24, 30, 42, 48}; + int N_STAVES_IB = 48; + int N_CHIP_IB = 432; + + // Utilities + int ChipToLayer(int chip); + double ChipToPhi(int chip); + bool searchBCfromMap(std::map> &BCperorbit, long target_orbit, int target_bc); + + std::shared_ptr mGGCCDBRequest; + std::shared_ptr mDataRequest; + bool mUseMC; + const o2::itsmft::TopologyDictionary* mDict = nullptr; + + int mTFn = 0; + int mTF_first_after_dump = 1; + + int mStrobeFallBack = 594; + int mStrobe = mStrobeFallBack; + + // TODO: the following should be make configurable + + std::pair TimeWindowZDC = std::make_pair(5., 11.); + std::pair TimeWindowZNAr = std::make_pair(5.64507, 9.64507); + std::pair TimeWindowZNCr = std::make_pair(4.21299, 8.21299); + std::pair TimeWindowZNAl = std::make_pair(-11.3549, -8.35493); + std::pair TimeWindowZNCl = std::make_pair(-12.787, -9.78701); + + int targetClusterMinCol = 128; // definition of anomalous cluster + int targetClusterMaxRow = 29; // definition of anomalous cluster + + int mDumpEveryTF = 10; // use -1 to save only at the end + int mSkimmedOnlyAfterTF = 15000; + std::string mOutputChip = "chipevents"; + std::string mOutoutChipSkim = "chipeventstarget"; + + TH1F* TimeWindowCut; + TH1F* ZNACall; + TH1F* ZNCCall; + TH1F* ZDCAtagBC; + TH1F* ZDCCtagBC; + TH1I* Counters; + TTree* ITSChipEvtTree; + TTree* ITSChipEvtTargetTree; + + // Tree variables + int Tbc; + long Torbit; + int Tchip; + double Tphi; + int TZDCtag; + int Tnhit, Tnclus, Tnhit_no1pix, Tnclus_no1pix; + int Tnclus_s20, Tnclus_s100, Tnclus_s150; + int Tnclus_c20, Tnclus_c100, Tnclus_c128; + int Tnclus_target; + double Tnhit1, Tnhit10; + int Tmissingafter, Tmissingafter2; + int Tmincol, Tmaxcol; +}; + +void ITSBeamBackgroundStudy::updateTimeDependentParams(ProcessingContext& pc) +{ + // o2::base::GRPGeomHelper::instance().checkUpdates(pc); + // static bool initOnceDone = false; + // if (!initOnceDone) { // this param need to be queried only once + // initOnceDone = true; + // // mGeom = o2::its::GeometryTGeo::Instance(); + // // mGeom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::T2G)); + // } +} + +void ITSBeamBackgroundStudy::init(InitContext& ic) +{ + LOGP(info, "Initializing ITSBeamBackgroundStudy"); + LOGP(info, "Fetching ClusterDictionary"); + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL("http://alice-ccdb.cern.ch"); + mgr.setTimestamp(o2::ccdb::getCurrentTimestamp()); + mDict = mgr.get("ITS/Calib/ClusterDictionary"); + + LOGP(info, "Setting up trees and histograms. They will be dumped on file every {} TFs", mDumpEveryTF); + + TimeWindowCut = new TH1F("ZDC bkg region", "ZNAr, ZNCr, -ZNAl, -ZNCl", 8, 0, 8); + TimeWindowCut->SetBinContent(1, TimeWindowZNAr.first); + TimeWindowCut->SetBinContent(2, TimeWindowZNAr.second); + TimeWindowCut->SetBinContent(3, TimeWindowZNCr.first); + TimeWindowCut->SetBinContent(4, TimeWindowZNCr.second); + TimeWindowCut->SetBinContent(5, -TimeWindowZNAl.first); + TimeWindowCut->SetBinContent(6, -TimeWindowZNAl.second); + TimeWindowCut->SetBinContent(7, -TimeWindowZNCl.first); + TimeWindowCut->SetBinContent(8, -TimeWindowZNCl.second); + ZNACall = new TH1F("ZNACall", "ZNACall", 40, -20, 20); + ZNCCall = new TH1F("ZNCCall", "ZNCCall", 40, -20, 20); + ZDCAtagBC = new TH1F("ZDCA tagged BC", "ZDCA tagged bc", 3564, 0, 3564); + ZDCCtagBC = new TH1F("ZDCC tagged BC", "ZDCC tagged bc", 3564, 0, 3564); + + Counters = new TH1I("Counters", "Counters", 20, 1, 21); + Counters->GetXaxis()->SetBinLabel(1, "TF"); + Counters->GetXaxis()->SetBinLabel(2, "ROF"); + Counters->GetXaxis()->SetBinLabel(3, "ZDCA evt"); + Counters->GetXaxis()->SetBinLabel(4, "ROF-ZDCA tagged"); + Counters->GetXaxis()->SetBinLabel(5, "ITStag any"); + Counters->GetXaxis()->SetBinLabel(6, "ITStag TO"); + Counters->GetXaxis()->SetBinLabel(7, "ITStag any + ZDC"); + Counters->GetXaxis()->SetBinLabel(8, "ITStag TO + ZDC"); + Counters->GetXaxis()->SetBinLabel(9, "ZDCC evt"); + Counters->GetXaxis()->SetBinLabel(10, "ROF-ZDCC tagged"); + + ITSChipEvtTree = new TTree("chipevt", "chipevt"); + + // Chip event branches + ITSChipEvtTree->Branch("TFprogress", &mTFn, "TFprogress/I"); + ITSChipEvtTree->Branch("orbit", &Torbit, "orbit/L"); + ITSChipEvtTree->Branch("bc", &Tbc, "bc/I"); + ITSChipEvtTree->Branch("chip", &Tchip, "chip/I"); + ITSChipEvtTree->Branch("phi", &Tphi, "phi/D"); + ITSChipEvtTree->Branch("zdctag", &TZDCtag, "zdctag/I"); + ITSChipEvtTree->Branch("nhit", &Tnhit, "nhit/I"); + ITSChipEvtTree->Branch("nhit_no1pix", &Tnhit_no1pix, "nhit_no1pix/I"); + ITSChipEvtTree->Branch("size1", &Tnhit1, "size1/D"); + ITSChipEvtTree->Branch("size10", &Tnhit10, "size10/D"); + ITSChipEvtTree->Branch("nclus", &Tnclus, "nclus/I"); + ITSChipEvtTree->Branch("nclus_no1pix", &Tnclus_no1pix, "nclus_no1pix/I"); + ITSChipEvtTree->Branch("nclus_target", &Tnclus_target, "nclus_target/I"); + ITSChipEvtTree->Branch("missingafter", &Tmissingafter, "missingafter/I"); + ITSChipEvtTree->Branch("missingafter2", &Tmissingafter2, "missingafter2/I"); + ITSChipEvtTree->Branch("mincol", &Tmincol, "mincol/I"); + ITSChipEvtTree->Branch("maxcol", &Tmaxcol, "maxcol/I"); + + ITSChipEvtTargetTree = ITSChipEvtTree->CloneTree(0); + ITSChipEvtTargetTree->SetName("chipevttarget"); + ITSChipEvtTargetTree->SetTitle("chipevttarget"); +} + +void ITSBeamBackgroundStudy::save_and_reset() +{ + + std::string outfile11 = mOutoutChipSkim + "_" + std::to_string(mTF_first_after_dump) + "_" + std::to_string(mTFn) + ".root"; + LOGP(info, "Writing ROOT file {}", outfile11); + TFile* F11 = TFile::Open(outfile11.c_str(), "recreate"); + TimeWindowCut->Write(); + ZNACall->Write(); + ZNCCall->Write(); + ZDCAtagBC->Write(); + ZDCCtagBC->Write(); + Counters->Write(); + ITSChipEvtTargetTree->Write(); + F11->Close(); + delete F11; + + if (mTFn <= mSkimmedOnlyAfterTF) { + std::string outfile1 = mOutputChip + "_" + std::to_string(mTF_first_after_dump) + "_" + std::to_string(mTFn) + ".root"; + LOGP(info, "Writing ROOT file {}", outfile1); + TFile* F1 = TFile::Open(outfile1.c_str(), "recreate"); + TimeWindowCut->Write(); + ZNACall->Write(); + ZNCCall->Write(); + ZDCAtagBC->Write(); + ZDCCtagBC->Write(); + Counters->Write(); + ITSChipEvtTree->Write(); // chip events and the skimmed one + ITSChipEvtTargetTree->Write(); + F1->Close(); + delete F1; + } + + LOGP(info, "Resetting historgrams and trees"); + // Delete clears data but keep the branch setup intact + ITSChipEvtTree->Reset(); // Delete(""); + ITSChipEvtTargetTree->Reset(); // Delete(""); + ZNACall->Reset(); + ZNCCall->Reset(); + ZDCAtagBC->Reset(); + ZDCCtagBC->Reset(); + Counters->Reset(); + + mTF_first_after_dump = mTFn + 1; +} + +void ITSBeamBackgroundStudy::endOfStream(EndOfStreamContext&) +{ + LOGP(info, "End of stream for ITSBeamBackgroundStudy"); + + save_and_reset(); + + delete TimeWindowCut; + delete ZNACall; + delete ZNCCall; + delete ZDCAtagBC; + delete ZDCCtagBC; + delete Counters; + delete ITSChipEvtTree; + delete ITSChipEvtTargetTree; +} + +void ITSBeamBackgroundStudy::run(ProcessingContext& pc) +{ + + if (mTFn == std::numeric_limits::max()) { + LOGP(error, "Max {} TFs exceeded. Skipping all next events", mTFn); + return; + } + + mTFn++; + + if (mDumpEveryTF > 0 && mTFn > 0 && (mTFn % mDumpEveryTF) == 0) { + LOGP(info, "Reached TF #{}. Exporting new root files", mTFn); + save_and_reset(); + } + + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + // updateTimeDependentParams(pc); + LOGP(info, "Calling process() for TF: {}", mTFn); + process(recoData); +} + +void ITSBeamBackgroundStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + return; +} + +// Custom area +void ITSBeamBackgroundStudy::process(o2::globaltracking::RecoContainer& recoData) +{ + + LOGP(info, "Processing RecoContainer"); + Counters->Fill(1); + + LOGP(info, "Retrieving ZDC data"); + auto RecBC = recoData.getZDCBCRecData(); + auto Energy = recoData.getZDCEnergy(); + auto TDCData = recoData.getZDCTDCData(); + auto Info2 = recoData.getZDCInfo(); + LOGP(info, "sizeof ZDC RC: {}, {}, {}, {}", RecBC.size(), Energy.size(), TDCData.size(), Info2.size()); + + LOGP(info, "Retrieving ITS clusters"); + auto rofRecVec = recoData.getITSClustersROFRecords(); + auto clusArr = recoData.getITSClusters(); + auto clusPatt = recoData.getITSClustersPatterns(); + LOGP(info, "sizeof ITS RC: {}, {}, {}", clusArr.size(), clusPatt.size(), rofRecVec.size()); + + // TODO: improve this + if (rofRecVec.size() == 576 || rofRecVec.size() == 192) { + mStrobe = 3564 / (rofRecVec.size() / 32); + LOGP(info, "Assuimg TF length = 32 orbits and setting strobe length to {} bc", mStrobe); + } else { + mStrobe = mStrobeFallBack; + LOGP(warning, "Unforeseen number of ROFs in the loop. Using the strobe length fall back value {}", mStrobe); + } + + std::map> ZNArtag{}; // ZDCAtag[orbit] = + std::map> ZNCrtag{}; + std::map> ZNAltag{}; + std::map> ZNCltag{}; + + // ________________________________________________________________ + // FILLING ZDC ARRAY + o2::zdc::RecEventFlat ev; + + ev.init(RecBC, Energy, TDCData, Info2); + + int bkgcounterAr = 0, bkgcounterCr = 0; + int bkgcounterAl = 0, bkgcounterCl = 0; + while (ev.next()) { + + int32_t itdcA = o2::zdc::TDCZNAC; // should be == 0 + int32_t itdcC = o2::zdc::TDCZNCC; + long zdcorbit = (long)ev.ir.orbit; + + // ZDC - A side + int nhitA = ev.NtdcV(itdcA); + for (int32_t ipos = 0; ipos < nhitA; ipos++) { + + double mytdc = o2::zdc::FTDCVal * ev.TDCVal[itdcA][ipos]; + + ZNACall->Fill(mytdc); + + if (mytdc >= TimeWindowZNAr.first && mytdc <= TimeWindowZNAr.second) { + + // Backgroud event found here! + bkgcounterAr++; + Counters->Fill(3); + ZDCAtagBC->Fill(ev.ir.bc); + + if (ZNArtag.find(zdcorbit) != ZNArtag.end()) { + bool double_count_bkg = ZNArtag[zdcorbit].insert((int)ev.ir.bc).second; + if (double_count_bkg) { + LOGP(warning, "Multiple ZDCAr counts in the same orbit/bc {}/{}", zdcorbit, ev.ir.bc); + } + } else { + std::set zdcbcs{(int)ev.ir.bc}; + ZNArtag[zdcorbit] = zdcbcs; + } + + } // and of ZNAr time window + + if (mytdc >= TimeWindowZNAl.first && mytdc <= TimeWindowZNAl.second) { + + // Backgroud event found here! + bkgcounterAl++; + Counters->Fill(3); + ZDCAtagBC->Fill(ev.ir.bc); + + if (ZNAltag.find(zdcorbit) != ZNAltag.end()) { + bool double_count_bkg = ZNAltag[zdcorbit].insert((int)ev.ir.bc).second; + if (double_count_bkg) { + LOGP(warning, "Multiple ZDCAl counts in the same orbit/bc {}/{}", zdcorbit, ev.ir.bc); + } + } else { + std::set zdcbcs{(int)ev.ir.bc}; + ZNAltag[zdcorbit] = zdcbcs; + } + + } // and of ZNAl time window + } + + // ZDC - C side + int nhitC = ev.NtdcV(itdcC); + for (int32_t ipos = 0; ipos < nhitC; ipos++) { + + double mytdc = o2::zdc::FTDCVal * ev.TDCVal[itdcC][ipos]; + + ZNCCall->Fill(mytdc); + + if (mytdc >= TimeWindowZNCr.first && mytdc <= TimeWindowZNCr.second) { + + // Backgroud event found here! + bkgcounterCr++; + Counters->Fill(9); + ZDCCtagBC->Fill(ev.ir.bc); + + if (ZNCrtag.find(zdcorbit) != ZNCrtag.end()) { + bool double_count_bkg = ZNCrtag[zdcorbit].insert((int)ev.ir.bc).second; + if (double_count_bkg) { + LOGP(warning, "Multiple ZNCr counts in the same orbit/bc {}/{}", zdcorbit, ev.ir.bc); + } + } else { + std::set zdcbcs{(int)ev.ir.bc}; + ZNCrtag[zdcorbit] = zdcbcs; + } + + } // end of ZNCr time window + + if (mytdc >= TimeWindowZNCl.first && mytdc <= TimeWindowZNCl.second) { + + // Backgroud event found here! + bkgcounterCl++; + Counters->Fill(9); + ZDCCtagBC->Fill(ev.ir.bc); + + if (ZNCltag.find(zdcorbit) != ZNCltag.end()) { + bool double_count_bkg = ZNCltag[zdcorbit].insert((int)ev.ir.bc).second; + if (double_count_bkg) { + LOGP(warning, "Multiple ZNCl counts in the same orbit/bc {}/{}", zdcorbit, ev.ir.bc); + } + } else { + std::set zdcbcs{(int)ev.ir.bc}; + ZNCltag[zdcorbit] = zdcbcs; + } + + } // end of ZNCl time window + } + } // end of while ev.next() + + LOGP(info, "Found background envents from ZNAright/left {}/{} -- from ZNCright/left {}/{}", bkgcounterAr, bkgcounterAl, bkgcounterCr, bkgcounterCl); + //__________________________________________________________________ + + getClusterPatterns(clusArr, clusPatt, *mDict); + + int inTFROFcounter = -1; + + std::vector ChipSeenInThisROF(N_CHIP_IB, false); // ChipSeenInThisROF[chipid] = true/false + std::vector ChipSeenInLastROF(N_CHIP_IB, false); // ChipSeenInLastROF[chipid] = true/false + std::vector ChipSeenInLast2ROF(N_CHIP_IB, false); // ChipSeenInLast2ROF[chipid] = true/false + + // Begin loop over ROFs + for (auto it = rofRecVec.rbegin(); it != rofRecVec.rend(); ++it) { + + auto& rofRec = *it; + + inTFROFcounter++; + + Counters->Fill(2); + + ChipSeenInLast2ROF = ChipSeenInLastROF; + ChipSeenInLastROF = ChipSeenInThisROF; + std::fill(ChipSeenInThisROF.begin(), ChipSeenInThisROF.end(), false); + + auto clustersInRof = rofRec.getROFData(clusArr); + auto patternsInRof = rofRec.getROFData(mPatterns); + + Tbc = (int)rofRec.getBCData().bc; + Torbit = (long)rofRec.getBCData().orbit; + + if (inTFROFcounter < 1) { + LOGP(info, "First of TF: ITS orbit/bc {}/{}", Torbit, Tbc); + } + + // shifting by 60 bc + int eff_bc = Tbc + 60; + long eff_orbit = Torbit; + if (eff_bc > 3564) { + eff_bc -= 3564; + eff_orbit += 1; + } + + // Making a bitmask with ZDC tags for this bc + bool isZNArtagged = searchBCfromMap(ZNArtag, (long)eff_orbit, eff_bc); + if (isZNArtagged) { + Counters->Fill(4); + } + + bool isZNAltagged = searchBCfromMap(ZNAltag, (long)eff_orbit, eff_bc); + if (isZNAltagged) { + Counters->Fill(4); + } + + bool isZNCrtagged = searchBCfromMap(ZNCrtag, (long)eff_orbit, eff_bc); + if (isZNCrtagged) { + Counters->Fill(10); + } + + bool isZNCltagged = searchBCfromMap(ZNCltag, (long)eff_orbit, eff_bc); + if (isZNCltagged) { + Counters->Fill(10); + } + + TZDCtag = 0; + TZDCtag |= (isZNArtagged << 0); + TZDCtag |= (isZNAltagged << 1); + TZDCtag |= (isZNCrtagged << 2); + TZDCtag |= (isZNCltagged << 3); + + if (TZDCtag > 0) { + LOGP(info, "ZDC tag with mask {}: ZNAright = {} - ZNAleft = {} - ZNCright = {} - ZNCleft = {}", + TZDCtag, (TZDCtag >> 0) & 1, (TZDCtag >> 1) & 1, (TZDCtag >> 2) & 1, (TZDCtag >> 3) & 1); + } + + // preparing arrays for clusters analysis + std::set AvailableChips{}; + std::map> MAPsize{}; // MAP[chip] = {list if sizes} + std::map> MAPcols{}; // MAP[chip] = {list of column span} + std::map MAPntarget{}; // MAP[chip] = number of bad clusters in chip + std::map MAPcoo_mincol{}; // MAP[chip] = minimum of column coordinate + std::map MAPcoo_maxcol{}; // MAP[chip] = maximum of (column coordinate + colspan) + + // Finally loop over clusters + int ntarget_in_rof = 0; + for (int iclus = 0; iclus < clustersInRof.size(); iclus++) { + + const auto& compClus = clustersInRof[iclus]; + + auto chipid = compClus.getSensorID(); + + // Analyze only IB + if (ChipToLayer(chipid) > 2) { + continue; + } + + ChipSeenInThisROF[chipid] = true; + + int coo_col = (int)compClus.getCol(); + int coo_row = (int)compClus.getRow(); + + auto patti = patternsInRof[iclus]; + int npix = patti.getNPixels(); + int colspan = patti.getColumnSpan(); + int rowspan = patti.getRowSpan(); + + bool newchip = AvailableChips.insert(chipid).second; + if (newchip) { + MAPsize[chipid] = std::vector{}; + MAPcols[chipid] = std::vector{}; + MAPntarget[chipid] = 0; + MAPcoo_mincol[chipid] = coo_col; + MAPcoo_maxcol[chipid] = coo_col + colspan; + } + + MAPsize[chipid].push_back(npix); + MAPcols[chipid].push_back(colspan); + if (colspan >= targetClusterMinCol && rowspan <= targetClusterMaxRow) { + // Anomalous cluster found + MAPntarget[chipid] += 1; + ntarget_in_rof++; + } + MAPcoo_mincol[chipid] = TMath::Min(MAPcoo_mincol[chipid], coo_col); + MAPcoo_maxcol[chipid] = TMath::Max(MAPcoo_maxcol[chipid], coo_col + colspan); + + } // end of loop over clusters in rof + + if (ntarget_in_rof == 0 && mTFn > mSkimmedOnlyAfterTF + 2) { // extra 2 to avoid edge effects? + // do not need extra computations for this rof since it will not be saved in any case + continue; + } + + for (int ic : AvailableChips) { + + Tchip = ic; + + if (inTFROFcounter < 1) + Tmissingafter = -1; + else if (ChipSeenInLastROF[ic]) + Tmissingafter = 0; + else + Tmissingafter = 1; + + if (inTFROFcounter < 2) + Tmissingafter2 = -1; + else if (ChipSeenInLast2ROF[ic]) + Tmissingafter2 = 0; + else + Tmissingafter2 = 1; + + Tphi = ChipToPhi(ic); + + Tnclus = MAPsize[ic].size(); + Tmincol = MAPcoo_mincol[ic]; + Tmaxcol = MAPcoo_maxcol[ic]; + + std::sort(MAPsize[ic].begin(), MAPsize[ic].end(), std::greater()); + + Tnhit = Tnclus_s20 = Tnclus_s100 = Tnclus_s150 = 0; + Tnhit1 = Tnhit10 = 0.; + Tnclus_c20 = Tnclus_c100 = Tnclus_c128 = 0; + Tnclus_target = MAPntarget[ic]; + Tnhit_no1pix = 0; + Tnclus_no1pix = 0; + + int nhit_no1pix = 0; + int nclus10 = 0, nclus1 = 0; + + for (int nh : MAPsize[ic]) { + + Tnhit += nh; + + if (nh > 1) { + Tnhit_no1pix += nh; + Tnclus_no1pix += 1; + } + + if (nclus10 < 10) { + nclus10++; + Tnhit10 += 1. * nh; + } + + if (nclus1 < 1) { + nclus1++; + Tnhit1 += 1. * nh; + } + + Tnclus_s20 += (nh >= 20); + Tnclus_s100 += (nh >= 100); + Tnclus_s150 += (nh >= 150); + } + + Tnhit10 = (nclus10 == 0) ? 0. : 1. * Tnhit10 / nclus10; + + for (int nc : MAPcols[ic]) { + Tnclus_c20 += (nc >= 20); + Tnclus_c100 += (nc >= 100); + Tnclus_c128 += (nc >= 128); + } + + ITSChipEvtTree->Fill(); + if (Tnclus_target > 0) { + ITSChipEvtTargetTree->Fill(); + } + + } // end of loop over available chips + } // end of loop over ROFs +} + +// TODO: To be improved using geometry tools +int ITSBeamBackgroundStudy::ChipToLayer(int chip) +{ + if (chip < 108) + return 0; + if (chip < 252) + return 1; + if (chip < 432) + return 2; + if (chip < 3120) + return 3; + if (chip < 6480) + return 4; + if (chip < 14712) + return 5; + return 6; +} + +// TODO: To be improved using geometry tools +double ITSBeamBackgroundStudy::ChipToPhi(int chip) +{ + int staveinlayer = (int)(chip / 9); + for (int il = 0; il < ChipToLayer(chip); il++) { + staveinlayer -= NStaves[il]; + } + return 2. * TMath::Pi() * (0.5 + staveinlayer) / NStaves[ChipToLayer(chip)]; +} + +bool ITSBeamBackgroundStudy::searchBCfromMap(std::map>& BCperorbit, long its_orbit, int its_bc) +{ + auto it = BCperorbit.find(its_orbit); + if (it == BCperorbit.end()) { + return false; + } + + for (auto bc : it->second) { + if ((bc / mStrobe) == (its_bc / mStrobe)) { + return true; + } + } +} + +void ITSBeamBackgroundStudy::getClusterPatterns(gsl::span& ITSclus, gsl::span& ITSpatt, const o2::itsmft::TopologyDictionary& mdict) +{ + mPatterns.clear(); + mPatterns.reserve(ITSclus.size()); + auto pattIt = ITSpatt.begin(); + + for (unsigned int iClus{0}; iClus < ITSclus.size(); ++iClus) { + auto& clus = ITSclus[iClus]; + + auto pattID = clus.getPatternID(); + o2::itsmft::ClusterPattern patt; + + if (pattID == o2::itsmft::CompCluster::InvalidPatternID || mdict.isGroup(pattID)) { + patt.acquirePattern(pattIt); + } else { + patt = mdict.getPattern(pattID); + } + + mPatterns.push_back(patt); + } +} + +// getter +DataProcessorSpec getITSBeamBackgroundStudy(mask_t srcTracksMask, mask_t srcClustersMask, bool useMC) +{ + + // std::cout<<"DEBBUG track and clus masks "< outputs; + auto dataRequest = std::make_shared(); + dataRequest->requestClusters(srcClustersMask, useMC); + // dataRequest->requestTracks(GTrackID::getSourcesMask("ZDC"), useMC); + + dataRequest->requestTracks(srcTracksMask, useMC); + + auto ggRequest = std::make_shared(false, // orbitResetTime + true, // GRPECS=true + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::Aligned, // geometry + dataRequest->inputs, + true); + return DataProcessorSpec{ + "its-zdc-anomaly-study", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, useMC)}, + Options{}}; +} + +} // namespace o2::its::study diff --git a/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx b/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx index 30fb39c77f235..ffb9c311c305e 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/workflow/standalone-postprocessing-workflow.cxx @@ -22,6 +22,7 @@ #include "ITSStudies/AvgClusSize.h" #include "ITSStudies/PIDStudy.h" #include "ITSStudies/AnomalyStudy.h" +#include "ITSStudies/ITSBeamBackgroundStudy.h" #include "ITSStudies/Efficiency.h" #include "ITSStudies/TrackCheck.h" #include "ITSStudies/TrackExtension.h" @@ -42,7 +43,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ {"input-from-upstream", VariantType::Bool, false, {"read clusters from the clusterer"}}, - {"track-sources", VariantType::String, std::string{"ITS,ITS-TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC,ITS-TPC-TRD"}, {"comma-separated list of track sources to use"}}, + {"track-sources", VariantType::String, std::string{"ITS,ITS-TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC,ITS-TPC-TRD,ZDC"}, {"comma-separated list of track sources to use"}}, {"cluster-sources", VariantType::String, std::string{"ITS"}, {"comma-separated list of cluster sources to use"}}, {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, {"disable-mc", VariantType::Bool, false, {"disable MC propagation even if available"}}, @@ -51,6 +52,7 @@ void customize(std::vector& workflowOptions) {"track-study", VariantType::Bool, false, {"Perform the track study"}}, {"impact-parameter-study", VariantType::Bool, false, {"Perform the impact parameter study"}}, {"anomaly-study", VariantType::Bool, false, {"Perform the anomaly study"}}, + {"its-beambkg-study", VariantType::Bool, false, {"Perform the ITS beam background study"}}, {"track-extension-study", VariantType::Bool, false, {"Perform the track extension study"}}, {"efficiency-study", VariantType::Bool, false, {"Perform the efficiency study"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; @@ -112,6 +114,17 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } specs.emplace_back(o2::its::study::getAnomalyStudy(srcCls, useMC)); } + if (configcontext.options().get("its-beambkg-study")) { + anyStudy = true; + + srcCls = GID::getSourcesMask(configcontext.options().get("cluster-sources")); + srcTrc = GID::getSourcesMask(configcontext.options().get("track-sources")); + + if (!configcontext.options().get("input-from-upstream")) { + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC, srcCls, srcTrc); + } + specs.emplace_back(o2::its::study::getITSBeamBackgroundStudy(srcTrc, srcCls, useMC)); + } if (configcontext.options().get("track-extension-study")) { if (!useMC) { LOGP(fatal, "Track Extension Study needs MC!"); From 856bf0de9f11d7a2592b8ebbd15217d47b12603f Mon Sep 17 00:00:00 2001 From: Nicolo Valle Date: Fri, 10 Apr 2026 16:01:26 +0200 Subject: [PATCH 2/5] fix clang --- .../ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx index 5a445d278b76c..6438c626d89c2 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx @@ -68,7 +68,7 @@ class ITSBeamBackgroundStudy : public Task // Utilities int ChipToLayer(int chip); double ChipToPhi(int chip); - bool searchBCfromMap(std::map> &BCperorbit, long target_orbit, int target_bc); + bool searchBCfromMap(std::map>& BCperorbit, long target_orbit, int target_bc); std::shared_ptr mGGCCDBRequest; std::shared_ptr mDataRequest; From 96314ef31b7ea44f499c06200f657df19b5d212d Mon Sep 17 00:00:00 2001 From: Nicolo Valle Date: Fri, 10 Apr 2026 17:35:31 +0200 Subject: [PATCH 3/5] fix CI error --- .../ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx index 6438c626d89c2..bc32d16631cb7 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx @@ -674,6 +674,7 @@ bool ITSBeamBackgroundStudy::searchBCfromMap(std::map>& BCpe return true; } } + return false; } void ITSBeamBackgroundStudy::getClusterPatterns(gsl::span& ITSclus, gsl::span& ITSpatt, const o2::itsmft::TopologyDictionary& mdict) From ca29c9ff52c02c03f0d09b55c04bc46977d010dd Mon Sep 17 00:00:00 2001 From: Nicolo Valle Date: Sat, 11 Apr 2026 09:42:33 +0200 Subject: [PATCH 4/5] Fix statements in braces --- .../studies/src/ITSBeamBackgroundStudy.cxx | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx index bc32d16631cb7..f323c022afcf8 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx @@ -561,19 +561,21 @@ void ITSBeamBackgroundStudy::process(o2::globaltracking::RecoContainer& recoData Tchip = ic; - if (inTFROFcounter < 1) + if (inTFROFcounter < 1) { Tmissingafter = -1; - else if (ChipSeenInLastROF[ic]) + } else if (ChipSeenInLastROF[ic]) { Tmissingafter = 0; - else + } else { Tmissingafter = 1; + } - if (inTFROFcounter < 2) + if (inTFROFcounter < 2) { Tmissingafter2 = -1; - else if (ChipSeenInLast2ROF[ic]) + } else if (ChipSeenInLast2ROF[ic]) { Tmissingafter2 = 0; - else + } else { Tmissingafter2 = 1; + } Tphi = ChipToPhi(ic); @@ -581,7 +583,7 @@ void ITSBeamBackgroundStudy::process(o2::globaltracking::RecoContainer& recoData Tmincol = MAPcoo_mincol[ic]; Tmaxcol = MAPcoo_maxcol[ic]; - std::sort(MAPsize[ic].begin(), MAPsize[ic].end(), std::greater()); + std::sort(MAPsize[ic].begin(), MAPsize[ic].end(), std::greater<>()); Tnhit = Tnclus_s20 = Tnclus_s100 = Tnclus_s150 = 0; Tnhit1 = Tnhit10 = 0.; @@ -637,18 +639,24 @@ void ITSBeamBackgroundStudy::process(o2::globaltracking::RecoContainer& recoData // TODO: To be improved using geometry tools int ITSBeamBackgroundStudy::ChipToLayer(int chip) { - if (chip < 108) + if (chip < 108) { return 0; - if (chip < 252) + } + if (chip < 252) { return 1; - if (chip < 432) + } + if (chip < 432) { return 2; - if (chip < 3120) + } + if (chip < 3120) { return 3; - if (chip < 6480) + } + if (chip < 6480) { return 4; - if (chip < 14712) + } + if (chip < 14712) { return 5; + } return 6; } From 6b1be6a300a235218c5127c6963b678ca5a5ab7a Mon Sep 17 00:00:00 2001 From: Nicolo Valle Date: Sat, 11 Apr 2026 20:33:33 +0200 Subject: [PATCH 5/5] leftover... --- .../ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx index f323c022afcf8..02f61140a82b6 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ITSBeamBackgroundStudy.cxx @@ -729,7 +729,7 @@ DataProcessorSpec getITSBeamBackgroundStudy(mask_t srcTracksMask, mask_t srcClus dataRequest->inputs, true); return DataProcessorSpec{ - "its-zdc-anomaly-study", + "its-beambkg-study", dataRequest->inputs, outputs, AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, useMC)},