From d781f24e4f7955ac80259adc2103b7e44d58a6be Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Fri, 11 Sep 2026 09:40:22 +0200 Subject: [PATCH 1/5] add pixel efficiency map to iotof digitization --- .../IOTOFSimulation/DPLDigitizerParam.h | 1 + .../include/IOTOFSimulation/Digitizer.h | 14 +++- .../ALICE3/IOTOF/simulation/src/Digitizer.cxx | 76 ++++++++++++++++--- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h index c1cb7d2db6133..7d6fe8ab3f6c1 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h @@ -30,6 +30,7 @@ struct DPLDigitizerParam : public o2::conf::ConfigurableParamHelper #include -#include "Rtypes.h" // for Digitizer::Class -#include "TObject.h" // for TObject +#include +#include // for Digitizer::Class +#include // for TObject #include "ITSMFTSimulation/Hit.h" #include "DataFormatsIOTOF/Digit.h" @@ -90,8 +91,13 @@ class Digitizer : public TObject /// Convert energy loss to charge int energyToCharge(float energyLoss) const; + /// Load the efficiency map from a file + void loadEfficiencyMap(const std::string& filePath); + /// Check if the hit passes efficiency cut - bool isEfficient() const; + /// \param x Detector local coordinate x in cm with respect to the center of the sensitive volume. + /// \param z Detector local coordinate z in cm with respect to the center of the sensitive volume. + bool isEfficient(const float x, const float z) const; std::vector* getExtraLabelBuffer(uint32_t roFrame) { @@ -108,8 +114,10 @@ class Digitizer : public TObject } static constexpr float sec2ns = 1e9f; ///< seconds to nanoseconds conversion + static constexpr float cm2um = 1e4f; ///< centimeters to micrometers conversion const o2::iotof::GeometryTGeo* mGeometry = nullptr; ///< IOTOF geometry + TH2D* mEfficiencyMap = nullptr; ///< Efficiency map for the detector std::vector mChips; //! Chips in the detector, indexed by chip ID std::deque>> mExtraLabelBuffer; //! buffer for multiple mc labels to the same pixel diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx index 685ca22638344..60bc28da450b0 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx @@ -20,7 +20,11 @@ #include "IOTOFSimulation/DPLDigitizerParam.h" #include "DetectorsRaw/HBFUtils.h" +#include +#include +#include #include + #include #include #include @@ -51,6 +55,9 @@ void Digitizer::init() } const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance(); + if (!digitizerParams.efficiencyFilePath.empty()) { + loadEfficiencyMap(digitizerParams.efficiencyFilePath); + } LOG(info) << "Initializing IOTOF digitizer"; LOG(info) << " Time resolution: " << digitizerParams.timeResolution * 1e3 << " ps"; @@ -94,13 +101,7 @@ void Digitizer::process(const std::vector* hits, int evID, int void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) { // Process a single hit and create a digit if it passes all cuts - - // Apply efficiency cut - if (!isEfficient()) { - LOG(debug) << "Hit rejected by efficiency cut"; - return; - } - + // Get detector element ID const int chipID = hit.GetDetectorID(); auto& chip = mChips[chipID]; @@ -108,6 +109,26 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) LOG(debug) << "Hit rejected because chip " << chipID << " is disabled"; return; } + + // middle position of the hit in the sensor frame + const auto& matrix = mGeometry->getMatrixL2G(chipID); + auto xyzPositionStart = matrix ^ hit.GetPosStart(); + auto xyzPositionEnd = matrix ^ hit.GetPos(); + const auto xMid = 0.5f * (xyzPositionStart.X() + xyzPositionEnd.X()); + const auto zMid = 0.5f * (xyzPositionStart.Z() + xyzPositionEnd.Z()); + // move this to the local pixel coordinates for the efficiency map + int row, col; + float xPixelCenter, zPixelCenter; + if (!sSegmentation->localToDetector(xMid, zMid, row, col, mGeometry->getIOTOFLayer(chipID))) { + LOG(debug) << "Hit rejected because position (" << xMid << ", " << zMid << ") is outside the active area of chip " << chipID; + return; // hit is outside the active area + } + sSegmentation->detectorToLocalUnchecked(row, col, xPixelCenter, zPixelCenter, mGeometry->getIOTOFLayer(chipID)); + + if (!isEfficient(xMid - xPixelCenter, zMid - zPixelCenter)) { + LOG(debug) << "Hit rejected by efficiency cut"; + return; + } // Convert energy loss to charge (number of electrons) float energyLoss = hit.GetEnergyLoss(); // in GeV @@ -126,7 +147,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) double hitTime = hit.GetTime() * sec2ns; // convert to ns double eventTimeInBC = mEventTime.getTimeOffsetWrtBC(); // event time wrt bc double hitTimeWrtBC = hitTime + eventTimeInBC; // hit time wrt bc - double smearedTime = smearTime(hitTimeWrtBC); // apply detector resolution + double smearedTime = smearTime(hitTimeWrtBC); if (chipID < 0 || chipID >= mGeometry->getSize() || mGeometry->getSize() < 1) { LOG(debug) << "Invalid detector ID: " << chipID << ", geometry size: " << mGeometry->getSize(); @@ -166,8 +187,8 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) void Digitizer::stepping(const o2::itsmft::Hit& hit, float**& respMatrix, int& rowStart, int& colStart, int& rowSpan, int& colSpan) { - const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID()); const int chipID = hit.GetDetectorID(); + const auto& matrix = mGeometry->getMatrixL2G(chipID); const int subdetectorID = mGeometry->getIOTOFLayer(chipID); auto xyzPositionStart(matrix ^ (hit.GetPosStart())); // start position in sensor frame @@ -277,10 +298,45 @@ int Digitizer::energyToCharge(float energyLoss) const } //_______________________________________________________________________ -bool Digitizer::isEfficient() const +void Digitizer::loadEfficiencyMap(const std::string& filePath) +{ + // Load the efficiency map from a file + TFile* file = TFile::Open(filePath.c_str()); + if (!file || !file->IsOpen()) { + LOG(error) << "Failed to open efficiency map file: " << filePath; + return; + } + + auto* rawMap = dynamic_cast(file->Get("hEfficiencyMap")); + if (!rawMap) { + LOG(error) << "Failed to retrieve efficiency map from file: " << filePath; + LOG(error) << "Available keys in the file:"; + TIter next(file->GetListOfKeys()); + TKey* key; + while ((key = dynamic_cast(next()))) { + LOG(error) << " " << key->GetName() << " (" << key->GetClassName() << ")"; + } + file->Close(); + return; + } + mEfficiencyMap = dynamic_cast(rawMap->Clone("mEfficiencyMap")); + mEfficiencyMap->SetDirectory(nullptr); // Detach from file to avoid deletion when file is closed + + file->Close(); +} + +//_______________________________________________________________________ +bool Digitizer::isEfficient(const float x, const float z) const { // Apply efficiency cut using random number const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance(); + if (mEfficiencyMap) { + //int bin = mEfficiencyMap->FindBin(x * o2::iotof::Digitizer::cm2um, z * o2::iotof::Digitizer::cm2um); + int bin = mEfficiencyMap->FindBin(x * o2::iotof::Digitizer::cm2um, z * o2::iotof::Digitizer::cm2um); + float efficiency = mEfficiencyMap->GetBinContent(bin); + LOG(debug) << "Efficiency map check: x=" << x * o2::iotof::Digitizer::cm2um << ", z=" << z * o2::iotof::Digitizer::cm2um << ", bin=" << bin << ", efficiency=" << efficiency; + return gRandom->Uniform() < efficiency; + } return gRandom->Uniform() < digitizerParams.efficiency; } From 66ac2aed558a9d46626e80d4329837bd176f8c1e Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Fri, 11 Sep 2026 10:16:12 +0200 Subject: [PATCH 2/5] add path to the available file in a comment --- .../simulation/include/IOTOFSimulation/DPLDigitizerParam.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h index 7d6fe8ab3f6c1..8f7a27ce3fa11 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h @@ -30,7 +30,8 @@ struct DPLDigitizerParam : public o2::conf::ConfigurableParamHelper Date: Fri, 11 Sep 2026 10:17:00 +0200 Subject: [PATCH 3/5] change binning of the histograms --- Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C b/Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C index d83db9f0f03d2..699f8620e9841 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C +++ b/Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C @@ -250,13 +250,13 @@ void CheckDigitsIOTOF(std::string digifile = "tf3digits.root", std::string hitfi auto canvdXdZ = new TCanvas("canvdXdZ", "", 1600, 800); canvdXdZ->Divide(2, 1); canvdXdZ->cd(1); - nt->Draw("dx:dz>>h_dx_vs_dz_ITOF(600, -0.03, 0.03, 600, -0.03, 0.03)", "id >= 0 && id < 1920", "colz"); + nt->Draw("dx:dz>>h_dx_vs_dz_ITOF(150, -0.03, 0.03, 150, -0.03, 0.03)", "id >= 0 && id < 1920", "colz"); addTLines(0.01); auto h = (TH2F*)gPad->GetPrimitive("h_dx_vs_dz_ITOF"); Info("ITOF", "RMS(dx)=%.1f mu", h->GetRMS(2) * 1e4); Info("ITOF", "RMS(dz)=%.1f mu", h->GetRMS(1) * 1e4); canvdXdZ->cd(2); - nt->Draw("dx:dz>>h_dx_vs_dz_OTOF(600, -0.03, 0.03, 600, -0.03, 0.03)", "id >= 1920 && id < 55488", "colz"); + nt->Draw("dx:dz>>h_dx_vs_dz_OTOF(150, -0.03, 0.03, 150, -0.03, 0.03)", "id >= 1920 && id < 55488", "colz"); addTLines(0.01); h = (TH2F*)gPad->GetPrimitive("h_dx_vs_dz_OTOF"); Info("OTOF", "RMS(dx)=%.1f mu", h->GetRMS(2) * 1e4); From b8b8f4595368c1d9740492b6588c80a7a3a26ddc Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Fri, 11 Sep 2026 10:24:40 +0200 Subject: [PATCH 4/5] clang-format --- .../simulation/include/IOTOFSimulation/DPLDigitizerParam.h | 2 +- .../IOTOF/simulation/include/IOTOFSimulation/Digitizer.h | 2 +- .../Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h index 8f7a27ce3fa11..2f9b0c3c2e090 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/DPLDigitizerParam.h @@ -30,7 +30,7 @@ struct DPLDigitizerParam : public o2::conf::ConfigurableParamHelper mChips; //! Chips in the detector, indexed by chip ID std::deque>> mExtraLabelBuffer; //! buffer for multiple mc labels to the same pixel diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx index 60bc28da450b0..67f651af919c6 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx @@ -101,7 +101,7 @@ void Digitizer::process(const std::vector* hits, int evID, int void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) { // Process a single hit and create a digit if it passes all cuts - + // Get detector element ID const int chipID = hit.GetDetectorID(); auto& chip = mChips[chipID]; @@ -109,7 +109,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) LOG(debug) << "Hit rejected because chip " << chipID << " is disabled"; return; } - + // middle position of the hit in the sensor frame const auto& matrix = mGeometry->getMatrixL2G(chipID); auto xyzPositionStart = matrix ^ hit.GetPosStart(); @@ -331,7 +331,7 @@ bool Digitizer::isEfficient(const float x, const float z) const // Apply efficiency cut using random number const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance(); if (mEfficiencyMap) { - //int bin = mEfficiencyMap->FindBin(x * o2::iotof::Digitizer::cm2um, z * o2::iotof::Digitizer::cm2um); + // int bin = mEfficiencyMap->FindBin(x * o2::iotof::Digitizer::cm2um, z * o2::iotof::Digitizer::cm2um); int bin = mEfficiencyMap->FindBin(x * o2::iotof::Digitizer::cm2um, z * o2::iotof::Digitizer::cm2um); float efficiency = mEfficiencyMap->GetBinContent(bin); LOG(debug) << "Efficiency map check: x=" << x * o2::iotof::Digitizer::cm2um << ", z=" << z * o2::iotof::Digitizer::cm2um << ", bin=" << bin << ", efficiency=" << efficiency; From 22aea56b41a144547cb2a810f24c55f7191c4340 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Fri, 11 Sep 2026 11:15:32 +0200 Subject: [PATCH 5/5] revert size of the histograms --- Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C b/Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C index 699f8620e9841..d83db9f0f03d2 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C +++ b/Detectors/Upgrades/ALICE3/IOTOF/macros/CheckDigitsIOTOF.C @@ -250,13 +250,13 @@ void CheckDigitsIOTOF(std::string digifile = "tf3digits.root", std::string hitfi auto canvdXdZ = new TCanvas("canvdXdZ", "", 1600, 800); canvdXdZ->Divide(2, 1); canvdXdZ->cd(1); - nt->Draw("dx:dz>>h_dx_vs_dz_ITOF(150, -0.03, 0.03, 150, -0.03, 0.03)", "id >= 0 && id < 1920", "colz"); + nt->Draw("dx:dz>>h_dx_vs_dz_ITOF(600, -0.03, 0.03, 600, -0.03, 0.03)", "id >= 0 && id < 1920", "colz"); addTLines(0.01); auto h = (TH2F*)gPad->GetPrimitive("h_dx_vs_dz_ITOF"); Info("ITOF", "RMS(dx)=%.1f mu", h->GetRMS(2) * 1e4); Info("ITOF", "RMS(dz)=%.1f mu", h->GetRMS(1) * 1e4); canvdXdZ->cd(2); - nt->Draw("dx:dz>>h_dx_vs_dz_OTOF(150, -0.03, 0.03, 150, -0.03, 0.03)", "id >= 1920 && id < 55488", "colz"); + nt->Draw("dx:dz>>h_dx_vs_dz_OTOF(600, -0.03, 0.03, 600, -0.03, 0.03)", "id >= 1920 && id < 55488", "colz"); addTLines(0.01); h = (TH2F*)gPad->GetPrimitive("h_dx_vs_dz_OTOF"); Info("OTOF", "RMS(dx)=%.1f mu", h->GetRMS(2) * 1e4);