diff --git a/Detectors/Upgrades/ALICE3/IOTOF/CMakeLists.txt b/Detectors/Upgrades/ALICE3/IOTOF/CMakeLists.txt index 808320bf66404..04288f205d8f4 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/IOTOF/CMakeLists.txt @@ -11,4 +11,5 @@ add_subdirectory(base) add_subdirectory(simulation) +add_subdirectory(DataFormatsIOTOF) add_subdirectory(macros) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/CMakeLists.txt b/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/CMakeLists.txt new file mode 100644 index 0000000000000..534e6217807c5 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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. + +o2_add_library(DataFormatsIOTOF + SOURCES src/Digit.cxx + # SOURCES src/MCLabel.cxx + # SOURCES src/Cluster.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsITSMFT) + +o2_target_root_dictionary(DataFormatsIOTOF + HEADERS include/DataFormatsIOTOF/Digit.h + # HEADERS include/DataFormatsIOTOF/MCLabel.h + # HEADERS include/DataFormatsIOTOF/Cluster.h + ) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/include/DataFormatsIOTOF/Digit.h b/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/include/DataFormatsIOTOF/Digit.h new file mode 100644 index 0000000000000..19b5dc3bcd72b --- /dev/null +++ b/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/include/DataFormatsIOTOF/Digit.h @@ -0,0 +1,46 @@ +// 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. + +/// +/// \file Digit.h +/// \brief Definition of IOTOF digit class +/// \author Nicolò Jacazio, Università del Piemonte Orientale (IT) +/// \since 2026-03-17 +/// + +#ifndef ALICEO2_IOTOF_DIGIT_H +#define ALICEO2_IOTOF_DIGIT_H + +#include "DataFormatsITSMFT/Digit.h" + +namespace o2::iotof +{ +class Digit : public o2::itsmft::Digit +{ + public: + Digit() = default; + ~Digit() = default; + Digit(UShort_t chipindex = 0, UShort_t row = 0, UShort_t col = 0, Int_t charge = 0, double time = 0.) + : o2::itsmft::Digit(chipindex, row, col, charge), mTime(time) {}; + + // Setters + void setTime(double time) { mTime = time; } + + // Getters + double getTime() const { return mTime; } + + private: + double mTime = 0.; ///< Measured time (ns) + ClassDefNV(Digit, 1); +}; + +} // namespace o2::iotof +#endif // ALICEO2_IOTOF_DIGIT_H diff --git a/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/src/DataFormatsIOTOFLinkDef.h b/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/src/DataFormatsIOTOFLinkDef.h new file mode 100644 index 0000000000000..8a167df4d6c7b --- /dev/null +++ b/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/src/DataFormatsIOTOFLinkDef.h @@ -0,0 +1,20 @@ +// 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. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::iotof::Digit + ; +// #pragma link C++ class std::vector < o2::iotof::Digit> + ; +#endif diff --git a/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/src/Digit.cxx b/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/src/Digit.cxx new file mode 100644 index 0000000000000..b15ecd94cd9af --- /dev/null +++ b/Detectors/Upgrades/ALICE3/IOTOF/DataFormatsIOTOF/src/Digit.cxx @@ -0,0 +1,21 @@ +// 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. + +/// +/// \file Digit.cxx +/// \brief Implementation of IOTOF digit class +/// \author Nicolò Jacazio, Università del Piemonte Orientale (IT) +/// \since 2026-03-17 +/// + +#include "DataFormatsIOTOF/Digit.h" + +using namespace o2::iotof; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt index 5e7cbd87bfd35..f3418d9065fcb 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt @@ -12,11 +12,14 @@ o2_add_library(IOTOFSimulation SOURCES src/Layer.cxx src/Detector.cxx + src/Digitizer.cxx # src/IOTOFServices.cxx PUBLIC_LINK_LIBRARIES O2::IOTOFBase + O2::DataFormatsIOTOF O2::ITSMFTSimulation) o2_target_root_dictionary(IOTOFSimulation HEADERS include/IOTOFSimulation/Detector.h - include/IOTOFSimulation/Layer.h) + include/IOTOFSimulation/Layer.h + include/IOTOFSimulation/Digitizer.h) # include/IOTOFSimulation/IOTOFServices.h) \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h new file mode 100644 index 0000000000000..8964e33f8a1b6 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h @@ -0,0 +1,111 @@ +// 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. + +/// +/// \file Digitizer.h +/// \brief Definition of the ALICE3 TOF digitizer +/// \author Nicolò Jacazio, Università del Piemonte Orientale (IT) +/// \since 2026-03-17 +/// + +#ifndef ALICEO2_IOTOF_DIGITIZER_H +#define ALICEO2_IOTOF_DIGITIZER_H + +#include "ITSMFTSimulation/Hit.h" +#include "DataFormatsITSMFT/Digit.h" +#include "DataFormatsIOTOF/Digit.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" +#include "IOTOFBase/GeometryTGeo.h" + +namespace o2::iotof +{ + +/// \class Digitizer +/// \brief Digitizer for the ALICE3 Inner/Outer TOF detector +/// +/// Converts MC hits into detector digits by: +/// - Applying time smearing according to detector resolution +/// - Converting energy loss to charge +/// - Applying charge threshold +/// - Managing readout frames (ROF) +class Digitizer +{ + public: + void setDigits(std::vector* dig) { mDigits = dig; } + void setMCLabels(o2::dataformats::MCTruthContainer* mclb) { mMCLabels = mclb; } + void setROFRecords(std::vector* rec) { mROFRecords = rec; } + + /// Initialize the digitizer + void init(); + + /// Steer conversion of hits to digits + void process(const std::vector* hits, int evID, int srcID); + + /// Set the event time + void setEventTime(const o2::InteractionTimeRecord& irt) { mEventTime = irt; } + + /// Set continuous readout mode + void setContinuous(bool v) { mContinuous = v; } + bool isContinuous() const { return mContinuous; } + + /// Flush the output container + void fillOutputContainer(); + + // Provide the common iotof::GeometryTGeo to access matrices and segmentation + void setGeometry(const o2::iotof::GeometryTGeo* gm) { mGeometry = gm; } + + // Setters for digitization parameters + void setChargeThreshold(float thr) { mChargeThreshold = thr; } + void setTimeResolution(float res) { mTimeResolution = res; } + void setEfficiency(float eff) { mEfficiency = eff; } + void setEnergyToCharge(float e2c) { mEnergyToCharge = e2c; } + + // Getters + float getChargeThreshold() const { return mChargeThreshold; } + float getTimeResolution() const { return mTimeResolution; } + float getEfficiency() const { return mEfficiency; } + + private: + /// Process a single hit + void processHit(const o2::itsmft::Hit& hit, int evID, int srcID); + + /// Apply time smearing to simulate detector resolution + double smearTime(double time) const; + + /// Convert energy loss to charge + int energyToCharge(float energyLoss) const; + + /// Check if the hit passes efficiency cut + bool isEfficient() const; + + static constexpr float sec2ns = 1e9f; ///< seconds to nanoseconds conversion + + const o2::iotof::GeometryTGeo* mGeometry = nullptr; ///< IOTOF geometry + + std::vector* mDigits = nullptr; //! output digits + std::vector* mROFRecords = nullptr; //! output ROF records + o2::dataformats::MCTruthContainer* mMCLabels = nullptr; //! output labels + + o2::InteractionTimeRecord mEventTime; ///< global event time and interaction record + bool mContinuous = true; ///< continuous readout mode + + // Digitization parameters + float mChargeThreshold = 100.f; ///< charge threshold for digit creation (electrons) + float mTimeResolution = 0.020f; ///< time resolution sigma in ns (20 ps default) + float mEfficiency = 0.98f; ///< detection efficiency + float mEnergyToCharge = 3.6e-9f; ///< energy loss to electrons conversion (3.6 eV per e-h pair in Si) +}; +} // namespace o2::iotof + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx new file mode 100644 index 0000000000000..b865d6958ecfd --- /dev/null +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx @@ -0,0 +1,162 @@ +// 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. + +/// +/// \file Digitizer.cxx +/// \brief Implementation of the ALICE3 TOF digitizer +/// \author Nicolò Jacazio, Università del Piemonte Orientale (IT) +/// \since 2026-03-17 +/// + +#include "IOTOFSimulation/Digitizer.h" +#include "DetectorsRaw/HBFUtils.h" + +#include +#include +#include +#include +#include +#include + +namespace o2::iotof +{ + +//_______________________________________________________________________ +void Digitizer::init() +{ + LOG(info) << "Initializing IOTOF digitizer"; + LOG(info) << " Time resolution: " << mTimeResolution * 1e3 << " ps"; + LOG(info) << " Charge threshold: " << mChargeThreshold << " electrons"; + LOG(info) << " Detection efficiency: " << mEfficiency * 100 << " %"; + LOG(info) << " Continuous mode: " << (mContinuous ? "ON" : "OFF"); +} + +//_______________________________________________________________________ +void Digitizer::process(const std::vector* hits, int evID, int srcID) +{ + // Digitize hits from a single event + LOG(debug) << "Digitizing IOTOF hits: " << hits->size() << " hits from event " << evID << " source " << srcID; + + if (!hits || hits->empty()) { + return; + } + + // Sort hits by detector ID for better cache locality + std::vector hitIdx(hits->size()); + std::iota(hitIdx.begin(), hitIdx.end(), 0); + std::sort(hitIdx.begin(), hitIdx.end(), + [hits](int lhs, int rhs) { + return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); + }); + + // Process each hit + for (int i : hitIdx) { + processHit((*hits)[i], evID, srcID); + } + + // In triggered mode, flush output after each event + if (!mContinuous) { + fillOutputContainer(); + } +} + +//_______________________________________________________________________ +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 + int detID = hit.GetDetectorID(); + + // Convert energy loss to charge (number of electrons) + float energyLoss = hit.GetEnergyLoss(); // in GeV + int charge = energyToCharge(energyLoss); + + // Apply charge threshold + if (charge < mChargeThreshold) { + LOG(debug) << "Hit rejected by charge threshold: " << charge << " < " << mChargeThreshold; + return; + } + + // Get hit time and apply smearing + // Hit time is in seconds, convert to ns and add event time + double hitTime = hit.GetTime() * sec2ns; // convert to ns + double eventTimeNS = mEventTime.getTimeNS(); // event time since orbit 0 + double absoluteTime = hitTime + eventTimeNS; // absolute time + double smearedTime = smearTime(absoluteTime); // apply detector resolution + + // For now, use simple row/col mapping from detector ID + // TODO: Implement proper segmentation when geometry is finalized + uint16_t chipIndex = static_cast(detID); + uint16_t row = 0; // Will be determined from hit position + uint16_t col = 0; // Will be determined from hit position + + // Create the digit with time information + int digID = mDigits->size(); + mDigits->emplace_back(chipIndex, row, col, charge, smearedTime); + + LOG(debug) << "Created digit #" << digID << " chip=" << chipIndex + << " charge=" << charge << " time=" << smearedTime << " ns"; + + // Add MC truth label + if (mMCLabels) { + o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false); + mMCLabels->addElement(digID, lbl); + } +} + +//_______________________________________________________________________ +double Digitizer::smearTime(double time) const +{ + // Apply Gaussian smearing to simulate detector time resolution + if (mTimeResolution > 0) { + return time + gRandom->Gaus(0, mTimeResolution); + } + return time; +} + +//_______________________________________________________________________ +int Digitizer::energyToCharge(float energyLoss) const +{ + // Convert energy loss (GeV) to number of electrons + // Typical value: 3.6 eV per electron-hole pair in silicon + // energyLoss is in GeV, mEnergyToCharge is GeV per electron + return static_cast(energyLoss / mEnergyToCharge); +} + +//_______________________________________________________________________ +bool Digitizer::isEfficient() const +{ + // Apply efficiency cut using random number + return gRandom->Uniform() < mEfficiency; +} + +//_______________________________________________________________________ +void Digitizer::fillOutputContainer() +{ + // Create ROF record for the current event + if (mROFRecords && mDigits && !mDigits->empty()) { + o2::itsmft::ROFRecord rof; + rof.setFirstEntry(0); + rof.setNEntries(mDigits->size()); + rof.setBCData(mEventTime); + mROFRecords->push_back(rof); + LOG(debug) << "Created ROF record with " << mDigits->size() << " digits"; + } +} + +} // namespace o2::iotof