1919#include " IOTOFSimulation/Digitizer.h"
2020#include " IOTOFSimulation/DPLDigitizerParam.h"
2121#include " DetectorsRaw/HBFUtils.h"
22+ #include " CCDB/BasicCCDBManager.h"
2223
2324#include < TCollection.h>
2425#include < TFile.h>
2526#include < TKey.h>
2627#include < TRandom.h>
2728
2829#include < set>
30+ #include < string_view>
2931#include < vector>
3032#include < iostream>
3133#include < numeric>
@@ -66,15 +68,28 @@ void Digitizer::init()
6668 }
6769 }
6870
69- if (!digitizerParams.efficiencyFilePath .empty ()) {
70- loadEfficiencyMap (digitizerParams.efficiencyFilePath );
71- }
71+ const auto & digitizerParams = o2::iotof::DPLDigitizerParam::Instance ();
7272
7373 LOG (info) << " Initializing IOTOF digitizer" ;
7474 LOG (info) << " Time resolution: " << digitizerParams.timeResolution * 1e3 << " ps" ;
7575 LOG (info) << " Charge threshold: " << digitizerParams.chargeThreshold << " electrons" ;
76- LOG (info) << " Detection efficiency: " << digitizerParams.efficiency * 100 << " %" ;
7776 LOG (info) << " Continuous mode: " << (mContinuous ? " ON" : " OFF" );
77+
78+ loadMap (mEfficiencyMap , digitizerParams.efficiencyMapPath , " hEfficiencyMap" );
79+ if (!mEfficiencyMap ) {
80+ LOG (info) << " No efficiency map loaded, using uniform efficiency: " << digitizerParams.efficiency * 100 << " %" ;
81+ }
82+
83+ loadMap (mResolutionMap , digitizerParams.resolutionMapPath , " hResolutionMap" );
84+ if (!mResolutionMap ) {
85+ LOG (info) << " No resolution map loaded, using uniform time resolution: " << digitizerParams.timeResolution * 1e3 << " ps" ;
86+ }
87+
88+ loadMap (mTimeOfArrivalMap , digitizerParams.timeOfArrivalMapPath , " hTimeOfArrivalMap" );
89+ if (!mTimeOfArrivalMap ) {
90+ LOG (info) << " No time of arrival map loaded" ;
91+ }
92+
7893 sSegmentation = o2::iotof::Segmentation::Instance ();
7994}
8095
@@ -173,12 +188,11 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID)
173188 LOG (debug) << " Hit rejected by efficiency cut at pixel (row,col) = (" << rowIS << " , " << colIS << " )" ;
174189 continue ;
175190 }
191+ double smearedTime = smearTime (hitTimeWrtBC, avgHitLocalX[irow][icol], avgHitLocalZ[irow][icol]);
176192
177193 const int nElectronsSampled = gRandom ->Poisson (electronsPerStep * nEleResp);
178194 // Noise can be added here if needed
179195
180- double smearedTime = smearTime (hitTimeWrtBC);
181-
182196 registerDigits (chip, roFrameAbs, smearedTime, nROF,
183197 static_cast <uint16_t >(rowIS), static_cast <uint16_t >(colIS), nElectronsSampled, label);
184198 }
@@ -326,12 +340,22 @@ void Digitizer::stepping(const o2::itsmft::Hit& hit, float**& respMatrix, float*
326340}
327341
328342// _______________________________________________________________________
329- double Digitizer::smearTime (double time) const
343+ double Digitizer::smearTime (double time, const float x, const float y ) const
330344{
331345 // Apply Gaussian smearing to simulate detector time resolution
332346 const auto & digitizerParams = o2::iotof::DPLDigitizerParam::Instance ();
347+
348+ float resolutionScaling = 1 .;
349+ if (mResolutionMap ) {
350+ const float minimumResolution = mResolutionMap ->GetMinimum ();
351+ int bin = mResolutionMap ->FindBin (x * o2::iotof::Digitizer::cm2um, y * o2::iotof::Digitizer::cm2um);
352+ resolutionScaling = minimumResolution > 0 . ? mResolutionMap ->GetBinContent (bin) / minimumResolution : 1 .;
353+ LOG (debug) << " Time resolution map check: x=" << x * o2::iotof::Digitizer::cm2um << " , y=" << y * o2::iotof::Digitizer::cm2um << " , bin=" << bin << " , resolution=" << minimumResolution;
354+ LOG (debug) << " Time resolution scaling: " << resolutionScaling;
355+ }
356+
333357 if (digitizerParams.timeResolution > 0 ) {
334- return time + gRandom ->Gaus (0 , digitizerParams.timeResolution );
358+ return time + gRandom ->Gaus (0 , digitizerParams.timeResolution * resolutionScaling );
335359 }
336360 return time;
337361}
@@ -347,31 +371,59 @@ int Digitizer::energyToCharge(float energyLoss) const
347371}
348372
349373// _______________________________________________________________________
350- void Digitizer::loadEfficiencyMap (const std::string& filePath)
374+
375+ void Digitizer::loadMap (TH2D *& map, const std::string& path, const char * mapName)
351376{
352- // Load the efficiency map from a file
353- TFile* file = TFile::Open (filePath.c_str ());
354- if (!file || !file->IsOpen ()) {
355- LOG (error) << " Failed to open efficiency map file: " << filePath;
377+ // Load a map either from CCDB (path prefixed with "ccdb://") or from a ROOT file
378+ // (anything TFile::Open understands: local path, alien://, root://, http://, ...)
379+ static constexpr std::string_view ccdbPrefix = " ccdb://" ;
380+
381+ if (path.empty ()) {
356382 return ;
357383 }
358384
359- auto * rawMap = dynamic_cast <TH2D *>(file->Get (" hEfficiencyMap" ));
360- if (!rawMap) {
361- LOG (error) << " Failed to retrieve efficiency map from file: " << filePath;
362- LOG (error) << " Available keys in the file:" ;
363- TIter next (file->GetListOfKeys ());
364- TKey* key;
365- while ((key = dynamic_cast <TKey*>(next ()))) {
366- LOG (error) << " " << key->GetName () << " (" << key->GetClassName () << " )" ;
385+ TH2D * rawMap = nullptr ;
386+ TFile* file = nullptr ;
387+
388+ if (path.rfind (ccdbPrefix, 0 ) == 0 ) {
389+ const std::string ccdbPath = path.substr (ccdbPrefix.size ());
390+ LOG (info) << " Loading " << mapName << " from CCDB: " << ccdbPath;
391+ rawMap = o2::ccdb::BasicCCDBManager::instance ().get <TH2D >(ccdbPath); // owned by the CCDB manager
392+ if (!rawMap) {
393+ LOG (error) << " Failed to retrieve " << mapName << " from CCDB path: " << ccdbPath;
394+ return ;
395+ }
396+ } else {
397+ LOG (info) << " Loading " << mapName << " from file: " << path;
398+ file = TFile::Open (path.c_str ());
399+ if (!file || !file->IsOpen ()) {
400+ LOG (error) << " Failed to open file: " << path;
401+ delete file;
402+ return ;
403+ }
404+ rawMap = dynamic_cast <TH2D *>(file->Get (mapName));
405+ if (!rawMap) {
406+ LOG (error) << " Failed to retrieve " << mapName << " from file: " << path;
407+ LOG (error) << " Available keys in the file:" ;
408+ TIter next (file->GetListOfKeys ());
409+ TKey* key;
410+ while ((key = dynamic_cast <TKey*>(next ()))) {
411+ LOG (error) << " " << key->GetName () << " (" << key->GetClassName () << " )" ;
412+ }
413+ file->Close ();
414+ delete file;
415+ return ;
367416 }
368- file->Close ();
369- return ;
370417 }
371- mEfficiencyMap = dynamic_cast <TH2D *>(rawMap->Clone (" mEfficiencyMap" ));
372- mEfficiencyMap ->SetDirectory (nullptr ); // Detach from file to avoid deletion when file is closed
373418
374- file->Close ();
419+ map = dynamic_cast <TH2D *>(rawMap->Clone ());
420+ map->SetDirectory (nullptr ); // Detach from file to avoid deletion when file is closed
421+ LOG (info) << " Loaded " << mapName << " (" << map->GetNbinsX () << " x " << map->GetNbinsY () << " bins)" ;
422+
423+ if (file) {
424+ file->Close ();
425+ delete file;
426+ }
375427}
376428
377429// _______________________________________________________________________
@@ -469,7 +521,7 @@ void Digitizer::registerDigits(Chip& chip, uint32_t roFrame, double time, int nR
469521 int tdc = int ((time - nbc * o2::constants::lhc::LHCBunchSpacingNS) / digitizerParams.tdcBin );
470522 nbc += mEventTime .toLong ();
471523
472- double absoluteTime = tdc * digitizerParams.tdcBin + nbc * o2::constants::lhc::LHCBunchSpacingNS;
524+ double absoluteTime = tdc * digitizerParams.tdcBin * 1 . e - 9 + nbc * o2::constants::lhc::LHCBunchSpacingNS;
473525
474526 auto key = o2::iotof::Digit::getOrderingKey (nbc, tdc, row, col);
475527 o2::iotof::LabeledDigit* existingDigit = chip.findDigit (key);
0 commit comments