From 2b1798166e7fcad9ce7c760ffe04eb7e64687e76 Mon Sep 17 00:00:00 2001 From: maciacco Date: Thu, 30 Apr 2026 12:02:07 +0200 Subject: [PATCH 01/19] one sensor per chip --- Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx index b603d2a4a423b..d09bcd49a7ba1 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx @@ -197,8 +197,8 @@ void ITOFLayer::createLayer(TGeoVolume* motherVolume) setChipStyle(chipVol); // Finally we create the volume of the sensor, which is the same for all chips - const int sensorsPerChipX = 2; // we assume that each chip is divided in 2 sensors along the x direction - const int sensorsPerChipZ = 2; // we assume that each chip is divided in 2 sensors along the z direction + const int sensorsPerChipX = 1; // we assume that each chip is divided in 2 sensors along the x direction + const int sensorsPerChipZ = 1; // we assume that each chip is divided in 2 sensors along the z direction const double sensorSizeX = chipSizeX / sensorsPerChipX; // cm const double sensorSizeY = mSensorThickness; // cm const double sensorSizeZ = chipSizeZ / sensorsPerChipZ; // cm From 3b726415512d0aabe4abb7eff5b56112044ba823 Mon Sep 17 00:00:00 2001 From: maciacco Date: Thu, 30 Apr 2026 12:16:16 +0200 Subject: [PATCH 02/19] one sensor per chip also in second layer --- Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx index d09bcd49a7ba1..4f76d71b63aa3 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx @@ -331,8 +331,8 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume) setChipStyle(chipVol); // Finally we create the volume of the sensor, which is the same for all chips - const int sensorsPerChipX = 2; // we assume that each chip is divided in 2 sensors along the x direction - const int sensorsPerChipZ = 2; // we assume that each chip is divided in 2 sensors along the z direction + const int sensorsPerChipX = 1; // we assume that each chip is divided in 2 sensors along the x direction + const int sensorsPerChipZ = 1; // we assume that each chip is divided in 2 sensors along the z direction const double sensorSizeX = chipSizeX / sensorsPerChipX; // cm const double sensorSizeY = mSensorThickness; // cm const double sensorSizeZ = chipSizeZ / sensorsPerChipZ; // cm From e0f57a709d8116f07029221b2ccf828769cb4460 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Thu, 30 Apr 2026 16:17:01 +0200 Subject: [PATCH 03/19] iotof segmentation and parameters. Segmentation parameters are stolen from ALPIDE and probably nonsensical --- .../base/include/IOTOFBase/IOTOFBaseParam.h | 14 ++ .../ALICE3/IOTOF/simulation/CMakeLists.txt | 9 +- .../include/IOTOFSimulation/Segmentation.h | 178 ++++++++++++++++++ .../IOTOF/simulation/src/Segmentation.cxx | 79 ++++++++ 4 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h create mode 100644 Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h index c1a9578484c17..952b6a8b3a28d 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h @@ -31,6 +31,20 @@ struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper float x2x0 = 0.02f; // thickness expressed in radiation length, for all layers for the moment float sensorThickness = 0.0050f; // thickness of the sensor in cm, for all layers for the moment, the default is set to 50 microns + struct chipSpecifics { + int NCols = 1024; + int NRows = 512; + float PitchCol = 29.24e-4; + float PitchRow = 26.88e-4; + float PassiveEdgeReadOut = 0.12f; // width of the readout edge (Passive bottom) + float PassiveEdgeTop = 37.44e-4; // Passive area on top + float PassiveEdgeSide = 29.12e-4; // width of Passive area on left/right of the sensor + + // effective thickness of sensitive layer, accounting for charge collection non-unifoemity, https://alice.its.cern.ch/jira/browse/AOC-46 + float SensorLayerThicknessEff = 28.e-4; + float SensorLayerThickness = 30.e-4; // physical thickness of sensitive part + } chipSpecifics; + O2ParamDef(IOTOFBaseParam, "IOTOFBase"); }; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt index f3418d9065fcb..ae9b0ed29e63d 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt @@ -13,7 +13,9 @@ o2_add_library(IOTOFSimulation SOURCES src/Layer.cxx src/Detector.cxx src/Digitizer.cxx + src/DPLDigitizerParam.cxx # src/IOTOFServices.cxx + src/Segmentation.cxx PUBLIC_LINK_LIBRARIES O2::IOTOFBase O2::DataFormatsIOTOF O2::ITSMFTSimulation) @@ -21,5 +23,8 @@ o2_add_library(IOTOFSimulation o2_target_root_dictionary(IOTOFSimulation HEADERS include/IOTOFSimulation/Detector.h include/IOTOFSimulation/Layer.h - include/IOTOFSimulation/Digitizer.h) - # include/IOTOFSimulation/IOTOFServices.h) \ No newline at end of file + include/IOTOFSimulation/Digitizer.h + include/IOTOFSimulation/DPLDigitizerParam.h + # include/IOTOFSimulation/IOTOFServices.h + include/IOTOFSimulation/Segmentation.h + ) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h new file mode 100644 index 0000000000000..f65e0451d3f14 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h @@ -0,0 +1,178 @@ +// 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 Segmentation.h +/// \brief Definition of the Segmentation class +/// \author Giorgio Alberto Lucia: giorgio.alberto.lucia@cern.ch + +#ifndef ALICEO2_IOTOF_SEGMENTATION_H +#define ALICEO2_IOTOF_SEGMENTATION_H + +#include +#include "MathUtils/Cartesian.h" + +namespace o2 +{ +namespace iotof +{ + +/// Segmentation and response for pixels in inner and outer TOF of the ALICE 3 apparatus +/// Questions to solve: +class Segmentation +{ + public: + + static int NCols; + static int NRows; + static int NPixels; + static float PitchCol; + static float PitchRow; + static float PassiveEdgeReadOut; + static float PassiveEdgeTop; + static float PassiveEdgeSide; + static float ActiveMatrixSizeCols; + static float ActiveMatrixSizeRows; + + // effective thickness of sensitive layer, accounting for charge collection non-unifoemity, https://alice.its.cern.ch/jira/browse/AOC-46 + static float SensorLayerThicknessEff; + static float SensorLayerThickness; + static float SensorSizeCols; + static float SensorSizeRows; + + Segmentation(); + ~Segmentation() = default; + + static void configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, const float passiveEdgeTop, + const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness); + + /// Transformation from Geant detector centered local coordinates (cm) to + /// Pixel cell numbers iRow and iCol. + /// Returns kTRUE if point x,z is inside sensitive volume, kFALSE otherwise. + /// A value of -1 for iRow or iCol indicates that this point is outside of the + /// detector segmentation as defined. + /// \param float x Detector local coordinate x in cm with respect to + /// the center of the sensitive volume. + /// \param float z Detector local coordinate z in cm with respect to + /// the center of the sensitive volulme. + /// \param int iRow Detector x cell coordinate. Has the range 0 <= iRow < mNumberOfRows + /// \param int iCol Detector z cell coordinate. Has the range 0 <= iCol < mNumberOfColumns + static bool localToDetector(float x, float z, int& iRow, int& iCol); + /// same but w/o check for row/column range + static void localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol); + + /// Transformation from Detector cell coordiantes to Geant detector centered + /// local coordinates (cm) + /// \param int iRow Detector x cell coordinate. Has the range 0 <= iRow < mNumberOfRows + /// \param int iCol Detector z cell coordinate. Has the range 0 <= iCol < mNumberOfColumns + /// \param float x Detector local coordinate x in cm with respect to the + /// center of the sensitive volume. + /// \param float z Detector local coordinate z in cm with respect to the + /// center of the sensitive volulme. + /// If iRow and or iCol is outside of the segmentation range a value of -0.5*Dx() + /// or -0.5*Dz() is returned. + + // w/o check for row/col range + template + static void detectorToLocalUnchecked(L row, L col, T& xRow, T& zCol) + { + xRow = getFirstRowCoordinate() - row * PitchRow; + zCol = col * PitchCol + getFirstColCoordinate(); + } + template + static void detectorToLocalUnchecked(L row, L col, math_utils::Point3D& loc) + { + loc.SetCoordinates(getFirstRowCoordinate() - row * PitchRow, T(0.), col * PitchCol + getFirstColCoordinate()); + } + template + static void detectorToLocalUnchecked(L row, L col, std::array& loc) + { + loc[0] = getFirstRowCoordinate() - row * PitchRow; + loc[1] = T(0); + loc[2] = col * PitchCol + getFirstColCoordinate(); + } + + // same but with check for row/col range + + template + static bool detectorToLocal(L row, L col, T& xRow, T& zCol) + { + if (row < 0 || row >= NRows || col < 0 || col >= NCols) { + return false; + } + detectorToLocalUnchecked(row, col, xRow, zCol); + return true; + } + + template + static bool detectorToLocal(L row, L col, math_utils::Point3D& loc) + { + if (row < 0 || row >= NRows || col < 0 || col >= NCols) { + return false; + } + detectorToLocalUnchecked(row, col, loc); + return true; + } + template + static bool detectorToLocal(L row, L col, std::array& loc) + { + if (row < 0 || row >= NRows || col < 0 || col >= NCols) { + return false; + } + detectorToLocalUnchecked(row, col, loc); + return true; + } + + static float getFirstRowCoordinate() + { + return 0.5 * ((ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - PitchRow); + } + static float getFirstColCoordinate() { return 0.5 * (PitchCol - ActiveMatrixSizeCols); } + + static void print(); + + ClassDefNV(Segmentation, 1); // Segmentation class upgrade pixels +}; + +//_________________________________________________________________________________________________ +inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol) +{ + // convert to row/col w/o over/underflow check + xRow = 0.5 * (ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix + zCol += 0.5 * ActiveMatrixSizeCols; // coordinate wrt left edge of Active matrix + iRow = int(xRow / PitchRow); + iCol = int(zCol / PitchCol); + if (xRow < 0) { + iRow -= 1; + } + if (zCol < 0) { + iCol -= 1; + } +} + +//_________________________________________________________________________________________________ +inline bool Segmentation::localToDetector(float xRow, float zCol, int& iRow, int& iCol) +{ + // convert to row/col + xRow = 0.5 * (ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix + zCol += 0.5 * ActiveMatrixSizeCols; // coordinate wrt left edge of Active matrix + if (xRow < 0 || xRow >= ActiveMatrixSizeRows || zCol < 0 || zCol >= ActiveMatrixSizeCols) { + iRow = iCol = -1; + return false; + } + iRow = int(xRow / PitchRow); + iCol = int(zCol / PitchCol); + return true; +} + +} // namespace iotof +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx new file mode 100644 index 0000000000000..3c0cdea04af65 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx @@ -0,0 +1,79 @@ +// 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 Segmentation.cxx +/// \brief Implementation of the Segmentation class + +#include "IOTOFSimulation/Segmentation.h" +#include "IOTOFBase/IOTOFBaseParam.h" +#include + +namespace o2 +{ + +namespace iotof +{ + +int Segmentation::NCols = 0; +int Segmentation::NRows = 0; +int Segmentation::NPixels = 0; +float Segmentation::PitchCol = 0.f; +float Segmentation::PitchRow = 0.f; +float Segmentation::PassiveEdgeReadOut = 0.f; +float Segmentation::PassiveEdgeTop = 0.f; +float Segmentation::PassiveEdgeSide = 0.f; +float Segmentation::ActiveMatrixSizeCols = 0.f; +float Segmentation::ActiveMatrixSizeRows = 0.f; +float Segmentation::SensorLayerThicknessEff = 0.f; +float Segmentation::SensorLayerThickness = 0.f; +float Segmentation::SensorSizeCols = 0.f; +float Segmentation::SensorSizeRows = 0.f; + +Segmentation::Segmentation() +{ + auto& iotofPars = IOTOFBaseParam::Instance(); + auto& chipPars = iotofPars.chipSpecifics; + configChip(chipPars.NCols, chipPars.NRows, chipPars.PitchCol, chipPars.PitchRow, chipPars.PassiveEdgeReadOut, chipPars.PassiveEdgeTop, + chipPars.PassiveEdgeSide, chipPars.SensorLayerThicknessEff, chipPars.SensorLayerThickness); +} + +void Segmentation::configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, + const float passiveEdgeTop, const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness) +{ + NCols = nCols; + NRows = nRows; + NPixels = NCols * NRows; + PitchCol = pitchCol; + PitchRow = pitchRow; + PassiveEdgeReadOut = passiveEdgeReadOut; + PassiveEdgeTop = passiveEdgeTop; + PassiveEdgeSide = passiveEdgeSide; + ActiveMatrixSizeCols = PitchCol * NCols; + ActiveMatrixSizeRows = PitchRow * NRows; + SensorLayerThicknessEff = sensorLayerThicknessEff; + SensorLayerThickness = sensorLayerThickness; + SensorSizeCols = ActiveMatrixSizeCols + PassiveEdgeSide + PassiveEdgeSide; + SensorSizeRows = ActiveMatrixSizeRows + PassiveEdgeTop + PassiveEdgeReadOut; +} + +void Segmentation::print() +{ + printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", PitchRow * 1e4, NRows, PitchCol * 1e4, NCols); + printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", + PassiveEdgeReadOut * 1e4, PassiveEdgeTop * 1e4, PassiveEdgeSide * 1e4); + printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", ActiveMatrixSizeRows, SensorSizeRows, + ActiveMatrixSizeCols, SensorSizeCols); +} + +} // namespace iotof +} // namespace o2 + +ClassImp(o2::iotof::Segmentation); From c072ae20bd04c31b0f560c3dbf7f3b8efaca4155 Mon Sep 17 00:00:00 2001 From: maciacco Date: Thu, 30 Apr 2026 16:29:36 +0200 Subject: [PATCH 04/19] compute number of chips in IOTOF --- .../base/include/IOTOFBase/GeometryTGeo.h | 22 ++++- .../ALICE3/IOTOF/base/src/GeometryTGeo.cxx | 96 +++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h index 577bd1bcabaf1..eaa8b5b28fbdc 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h @@ -54,6 +54,13 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache static const char* getBTOFChipPattern() { return sBTOFChipName.c_str(); } static const char* getBTOFSensorPattern() { return sBTOFSensorName.c_str(); } + // Determine the number of active parts in the geometry + int extractNumberOfStavesIOTOF(int lay) const; + int extractNumberOfModulesIOTOF(int lay) const; + int extractNumberOfChipsPerModuleIOTOF(int lay) const; + int extractNumberOfChipsFTOF() const; + int extractNumberOfChipsBTOF() const; + static const char* composeSymNameIOTOF(int d) { return Form("%s_%d", o2::detectors::DetID(o2::detectors::DetID::TF3).getName(), d); @@ -107,10 +114,23 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache static std::string sBTOFChipName; static std::string sBTOFSensorName; + // Inner/outer TOF + int mNumberOfStavesIOTOF[2]; + int mNumberOfModulesIOTOF[2]; + int mNumberOfChipsPerModuleIOTOF[2]; + int mNumberOfChipsIOTOF[2]; + int mLastChipIndex[2]; + + // Forward TOF + int mNumberOfChipsFTOF; + + // Backward TOF + int mNumberOfChipsBTOF; + private: static std::unique_ptr sInstance; }; } // namespace iotof } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx index f7d0eb135a27a..467475b169c07 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx @@ -55,6 +55,75 @@ GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : DetMatrixCache() } } +int GeometryTGeo::extractNumberOfStavesIOTOF(int lay) const +{ + int numberOfStaves{0}; + + std::string layName = lay == 0 ? getITOFLayerPattern() : getOTOFLayerPattern(); + TGeoVolume* layV = gGeoManager->GetVolume(layName.c_str()); + + // LOG(info) << "lay name = " << layV->GetName(); + + TObjArray* nodes = layV->GetNodes(); + int nNodes = nodes->GetEntriesFast(); + + for (int j{0}; j < nNodes; ++j) { + if (strstr(nodes->At(j)->GetName(), lay == 0 ? getITOFStavePattern() : getOTOFStavePattern()) != nullptr) { + numberOfStaves++; + } + } + + return numberOfStaves; +} + +int GeometryTGeo::extractNumberOfModulesIOTOF(int lay) const +{ + int numberOfModules{0}; + + std::string staveName = lay == 0 ? getITOFStavePattern() : getOTOFStavePattern(); + TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str()); + + TObjArray* nodes = staveV->GetNodes(); + int nNodes = nodes->GetEntriesFast(); + + for (int j{0}; j < nNodes; ++j) { + if (strstr(nodes->At(j)->GetName(), lay == 0 ? getITOFModulePattern() : getOTOFModulePattern()) != nullptr) { + numberOfModules++; + } + } + + return numberOfModules; +} + +int GeometryTGeo::extractNumberOfChipsPerModuleIOTOF(int lay) const +{ + int numberOfChips{0}; + + std::string moduleName = lay == 0 ? getITOFModulePattern() : getOTOFModulePattern(); + TGeoVolume* moduleV = gGeoManager->GetVolume(moduleName.c_str()); + + TObjArray* nodes = moduleV->GetNodes(); + int nNodes = nodes->GetEntriesFast(); + + for (int j{0}; j < nNodes; ++j) { + if (strstr(nodes->At(j)->GetName(), lay == 0 ? getITOFChipPattern() : getOTOFChipPattern()) != nullptr) { + numberOfChips++; + } + } + + return numberOfChips; +} + +int GeometryTGeo::extractNumberOfChipsFTOF() const +{ + return 0; +} + +int GeometryTGeo::extractNumberOfChipsBTOF() const +{ + return 0; +} + void GeometryTGeo::Build(int loadTrans) { if (isBuilt()) { @@ -66,6 +135,33 @@ void GeometryTGeo::Build(int loadTrans) LOGP(fatal, "Geometry is not loaded"); } + // Inner/outer TOF + for (int j{0}; j < 2; ++j) { + mNumberOfStavesIOTOF[j] = extractNumberOfStavesIOTOF(j); + mNumberOfModulesIOTOF[j] = extractNumberOfModulesIOTOF(j); + mNumberOfChipsPerModuleIOTOF[j] = extractNumberOfChipsPerModuleIOTOF(j); + } + + // Forward TOF + mNumberOfChipsFTOF = extractNumberOfChipsFTOF(); + + // Backward TOF + mNumberOfChipsBTOF = extractNumberOfChipsBTOF(); + + // LOG(info) << "stavesITOF = " << mNumberOfStavesITOF << ", stavesOTOF = " << mNumberOfStavesOTOF; + // LOG(info) << "modulesITOF = " << mNumberOfModulesITOF << ", modulesOTOF = " << mNumberOfModulesOTOF; + // LOG(info) << "chipsITOF = " << mNumberOfChipsITOF << ", chipsOTOF = " << mNumberOfChipsOTOF; + + int numberOfChips{0}; + for (int j{0}; j < 2; ++j) { + mNumberOfChipsIOTOF[j] = mNumberOfStavesIOTOF[j] * mNumberOfModulesIOTOF[j] * mNumberOfChipsPerModuleIOTOF[j]; + numberOfChips += mNumberOfChipsIOTOF[j]; + mLastChipIndex[j] = numberOfChips - 1; + } + + // LOG(info) << "numberOfChipsITOF = " << mNumberOfChipsIOTOF[0] << ", numberOfChipsOTOF = " << mNumberOfChipsIOTOF[1] << ", numberOfChips = " << numberOfChips; + + setSize(numberOfChips); fillMatrixCache(loadTrans); } From 876f1719da138743b400d185b3df9d0a74be9eea Mon Sep 17 00:00:00 2001 From: maciacco Date: Thu, 30 Apr 2026 19:02:42 +0200 Subject: [PATCH 05/19] fill L2G transformation matrices --- .../base/include/IOTOFBase/GeometryTGeo.h | 29 +++- .../ALICE3/IOTOF/base/src/GeometryTGeo.cxx | 130 ++++++++++++++++-- 2 files changed, 138 insertions(+), 21 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h index eaa8b5b28fbdc..a818e3ca45b0f 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h @@ -22,6 +22,9 @@ namespace iotof class GeometryTGeo : public o2::detectors::DetMatrixCache { public: + using Mat3D = o2::math_utils::Transform3D; + using DetMatrixCache::getMatrixL2G; + GeometryTGeo(bool build = false, int loadTrans = 0); void Build(int loadTrans); void fillMatrixCache(int mask); @@ -54,13 +57,6 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache static const char* getBTOFChipPattern() { return sBTOFChipName.c_str(); } static const char* getBTOFSensorPattern() { return sBTOFSensorName.c_str(); } - // Determine the number of active parts in the geometry - int extractNumberOfStavesIOTOF(int lay) const; - int extractNumberOfModulesIOTOF(int lay) const; - int extractNumberOfChipsPerModuleIOTOF(int lay) const; - int extractNumberOfChipsFTOF() const; - int extractNumberOfChipsBTOF() const; - static const char* composeSymNameIOTOF(int d) { return Form("%s_%d", o2::detectors::DetID(o2::detectors::DetID::TF3).getName(), d); @@ -86,7 +82,25 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache static const char* composeBTOFSymNameChip(int d, int lr); static const char* composeBTOFSymNameSensor(int d, int layer); + int getIOTOFFirstChipIndex(int lay) const; + int getIOTOFLayer(int index) const; + bool getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& chip) const; + + /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) + /// for a given chip 'index' by querying the TGeoManager + TGeoHMatrix* extractMatrixSensor(int index) const; + + TString getMatrixPath(int index) const; + + protected: + // Determine the number of active parts in the geometry + int extractNumberOfStavesIOTOF(int lay) const; + int extractNumberOfModulesIOTOF(int lay) const; + int extractNumberOfChipsPerModuleIOTOF(int lay) const; + int extractNumberOfChipsFTOF() const; + int extractNumberOfChipsBTOF() const; + // i/oTOF mother volume static std::string sIOTOFVolumeName; @@ -118,6 +132,7 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache int mNumberOfStavesIOTOF[2]; int mNumberOfModulesIOTOF[2]; int mNumberOfChipsPerModuleIOTOF[2]; + int mNumberOfChipsPerStaveIOTOF[2]; int mNumberOfChipsIOTOF[2]; int mLastChipIndex[2]; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx index 467475b169c07..9201fc229a565 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx @@ -59,16 +59,18 @@ int GeometryTGeo::extractNumberOfStavesIOTOF(int lay) const { int numberOfStaves{0}; - std::string layName = lay == 0 ? getITOFLayerPattern() : getOTOFLayerPattern(); + std::string layName = lay == 0 ? GeometryTGeo::getITOFLayerPattern() : GeometryTGeo::getOTOFLayerPattern(); TGeoVolume* layV = gGeoManager->GetVolume(layName.c_str()); - - // LOG(info) << "lay name = " << layV->GetName(); + if (layV == nullptr) { + LOG(fatal) << "Can't find volume " << layName; + return -1; + } TObjArray* nodes = layV->GetNodes(); int nNodes = nodes->GetEntriesFast(); for (int j{0}; j < nNodes; ++j) { - if (strstr(nodes->At(j)->GetName(), lay == 0 ? getITOFStavePattern() : getOTOFStavePattern()) != nullptr) { + if (strstr(nodes->At(j)->GetName(), lay == 0 ? GeometryTGeo::getITOFStavePattern() : GeometryTGeo::getOTOFStavePattern()) != nullptr) { numberOfStaves++; } } @@ -80,14 +82,18 @@ int GeometryTGeo::extractNumberOfModulesIOTOF(int lay) const { int numberOfModules{0}; - std::string staveName = lay == 0 ? getITOFStavePattern() : getOTOFStavePattern(); + std::string staveName = lay == 0 ? GeometryTGeo::getITOFStavePattern() : GeometryTGeo::getOTOFStavePattern(); TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str()); + if (staveV == nullptr) { + LOG(fatal) << "Can't find volume " << staveName; + return -1; + } TObjArray* nodes = staveV->GetNodes(); int nNodes = nodes->GetEntriesFast(); for (int j{0}; j < nNodes; ++j) { - if (strstr(nodes->At(j)->GetName(), lay == 0 ? getITOFModulePattern() : getOTOFModulePattern()) != nullptr) { + if (strstr(nodes->At(j)->GetName(), lay == 0 ? GeometryTGeo::getITOFModulePattern() : GeometryTGeo::getOTOFModulePattern()) != nullptr) { numberOfModules++; } } @@ -99,14 +105,18 @@ int GeometryTGeo::extractNumberOfChipsPerModuleIOTOF(int lay) const { int numberOfChips{0}; - std::string moduleName = lay == 0 ? getITOFModulePattern() : getOTOFModulePattern(); + std::string moduleName = lay == 0 ? GeometryTGeo::getITOFModulePattern() : GeometryTGeo::getOTOFModulePattern(); TGeoVolume* moduleV = gGeoManager->GetVolume(moduleName.c_str()); + if (moduleV == nullptr) { + LOG(fatal) << "Can't find volume " << moduleName; + return -1; + } TObjArray* nodes = moduleV->GetNodes(); int nNodes = nodes->GetEntriesFast(); for (int j{0}; j < nNodes; ++j) { - if (strstr(nodes->At(j)->GetName(), lay == 0 ? getITOFChipPattern() : getOTOFChipPattern()) != nullptr) { + if (strstr(nodes->At(j)->GetName(), lay == 0 ? GeometryTGeo::getITOFChipPattern() : GeometryTGeo::getOTOFChipPattern()) != nullptr) { numberOfChips++; } } @@ -124,6 +134,83 @@ int GeometryTGeo::extractNumberOfChipsBTOF() const return 0; } +int GeometryTGeo::getIOTOFFirstChipIndex(int lay) const +{ + return lay == 0 ? 0 : mLastChipIndex[0] + 1; +} + +int GeometryTGeo::getIOTOFLayer(int index) const +{ + return index > mLastChipIndex[0] ? 1 : 0; +} + +bool GeometryTGeo::getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& chip) const +{ + lay = getIOTOFLayer(index); + index -= getIOTOFFirstChipIndex(lay); + sta = mNumberOfStavesIOTOF[lay] > 0 ? index / mNumberOfChipsPerStaveIOTOF[lay] : -1; + index %= mNumberOfChipsPerStaveIOTOF[lay]; + mod = mNumberOfModulesIOTOF[lay] > 0 ? index / mNumberOfChipsPerModuleIOTOF[lay] : -1; + chip = index % mNumberOfChipsPerModuleIOTOF[lay]; + return false; +} + +TString GeometryTGeo::getMatrixPath(int index) const +{ + int lay, sta, mod, chip; + getIOTOFChipId(index, lay, sta, mod, chip); + + TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getIOTOFVolPattern()); + sta += 1; + mod += 1; + chip += 1; + + if (lay == 0) { + path += Form("%s_1/", GeometryTGeo::getITOFLayerPattern()); + if (mNumberOfStavesIOTOF[lay] > 0) + path += Form("%s_%d/", GeometryTGeo::getITOFStavePattern(), sta); + if (mNumberOfModulesIOTOF[lay] > 0) + path += Form("%s_%d/", GeometryTGeo::getITOFModulePattern(), mod); + if (mNumberOfChipsPerModuleIOTOF[lay] > 0) + path += Form("%s_%d/%s_1", GeometryTGeo::getITOFChipPattern(), chip, GeometryTGeo::getITOFSensorPattern()); + } else { + path += Form("%s_1/", GeometryTGeo::getOTOFLayerPattern()); + if (mNumberOfStavesIOTOF[lay] > 0) + path += Form("%s_%d/", GeometryTGeo::getOTOFStavePattern(), sta); + if (mNumberOfModulesIOTOF[lay] > 0) + path += Form("%s_%d/", GeometryTGeo::getOTOFModulePattern(), mod); + if (mNumberOfChipsPerModuleIOTOF[lay] > 0) + path += Form("%s_%d/%s_1", GeometryTGeo::getOTOFChipPattern(), chip, GeometryTGeo::getOTOFSensorPattern()); + } + + return path; +} + +TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const +{ + auto path = getMatrixPath(index); + + static TGeoHMatrix matTmp; + gGeoManager->PushPath(); + + if (!gGeoManager->cd(path.Data())) { + gGeoManager->PopPath(); + LOG(error) << "Error in cd-ing to " << path.Data(); + return nullptr; + } + + matTmp = *gGeoManager->GetCurrentMatrix(); + LOG(info) << "Path = " << path.Data(); + + // Restore the modeler state + gGeoManager->PopPath(); + + // account for the difference between physical sensitive layer (where charge collection is simulated) and effective sensor thicknesses + // TODO: apply translation by the effective sensor thickness, not yet done (see ITS) + + return &matTmp; +} + void GeometryTGeo::Build(int loadTrans) { if (isBuilt()) { @@ -148,25 +235,40 @@ void GeometryTGeo::Build(int loadTrans) // Backward TOF mNumberOfChipsBTOF = extractNumberOfChipsBTOF(); - // LOG(info) << "stavesITOF = " << mNumberOfStavesITOF << ", stavesOTOF = " << mNumberOfStavesOTOF; - // LOG(info) << "modulesITOF = " << mNumberOfModulesITOF << ", modulesOTOF = " << mNumberOfModulesOTOF; - // LOG(info) << "chipsITOF = " << mNumberOfChipsITOF << ", chipsOTOF = " << mNumberOfChipsOTOF; - int numberOfChips{0}; for (int j{0}; j < 2; ++j) { - mNumberOfChipsIOTOF[j] = mNumberOfStavesIOTOF[j] * mNumberOfModulesIOTOF[j] * mNumberOfChipsPerModuleIOTOF[j]; + mNumberOfChipsPerStaveIOTOF[j] = mNumberOfModulesIOTOF[j] * mNumberOfChipsPerModuleIOTOF[j]; + mNumberOfChipsIOTOF[j] = mNumberOfStavesIOTOF[j] * mNumberOfChipsPerStaveIOTOF[j]; numberOfChips += mNumberOfChipsIOTOF[j]; mLastChipIndex[j] = numberOfChips - 1; } - // LOG(info) << "numberOfChipsITOF = " << mNumberOfChipsIOTOF[0] << ", numberOfChipsOTOF = " << mNumberOfChipsIOTOF[1] << ", numberOfChips = " << numberOfChips; + LOG(info) << "numberOfChipsITOF = " << mNumberOfChipsIOTOF[0] << ", numberOfChipsOTOF = " << mNumberOfChipsIOTOF[1] << ", numberOfChips = " << numberOfChips << ", mNumberOfChipesPerStaveITOF" << mNumberOfChipsPerStaveIOTOF[0]; setSize(numberOfChips); fillMatrixCache(loadTrans); + // fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); } void GeometryTGeo::fillMatrixCache(int mask) { + if (mSize < 1) { + LOG(warning) << "The method Build was not called yet"; + Build(mask); + return; + } + + if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)) && !getCacheL2G().isFilled()) { + // Matrices for Local (Sensor!!! rather than the full chip) to Global frame transformation + LOG(info) << "Loading " << getName() << " L2G matrices from TGeo; there are " << mSize << " matrices"; + auto& cacheL2G = getCacheL2G(); + cacheL2G.setSize(mSize); + + for (int i = 0; i < mSize; i++) { + TGeoHMatrix* hm = extractMatrixSensor(i); + cacheL2G.setMatrix(Mat3D(*hm), i); + } + } } GeometryTGeo* GeometryTGeo::Instance() From 684490f13d493273a80cfcb10036632ad5f69166 Mon Sep 17 00:00:00 2001 From: maciacco Date: Thu, 30 Apr 2026 19:26:18 +0200 Subject: [PATCH 06/19] fix cmakelist --- Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt index ae9b0ed29e63d..25d623c0047a9 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt @@ -13,7 +13,6 @@ o2_add_library(IOTOFSimulation SOURCES src/Layer.cxx src/Detector.cxx src/Digitizer.cxx - src/DPLDigitizerParam.cxx # src/IOTOFServices.cxx src/Segmentation.cxx PUBLIC_LINK_LIBRARIES O2::IOTOFBase @@ -24,7 +23,6 @@ o2_target_root_dictionary(IOTOFSimulation HEADERS include/IOTOFSimulation/Detector.h include/IOTOFSimulation/Layer.h include/IOTOFSimulation/Digitizer.h - include/IOTOFSimulation/DPLDigitizerParam.h # include/IOTOFSimulation/IOTOFServices.h include/IOTOFSimulation/Segmentation.h ) From abe83cb66f22054c91218a4619443b4bb37157b5 Mon Sep 17 00:00:00 2001 From: maciacco Date: Fri, 1 May 2026 13:01:55 +0200 Subject: [PATCH 07/19] only fill segmentation details if layout is segmented + add function to retrieve chip index --- .../IOTOF/base/include/IOTOFBase/GeometryTGeo.h | 1 + .../ALICE3/IOTOF/base/src/GeometryTGeo.cxx | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h index a818e3ca45b0f..810b816b51022 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h @@ -84,6 +84,7 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache int getIOTOFFirstChipIndex(int lay) const; int getIOTOFLayer(int index) const; + int getIOTOFChipIndex(int lay, int sta, int mod, int chip) const; bool getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& chip) const; /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx index 9201fc229a565..8669ef855b8e3 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. #include +#include #include namespace o2 @@ -144,6 +145,11 @@ int GeometryTGeo::getIOTOFLayer(int index) const return index > mLastChipIndex[0] ? 1 : 0; } +int GeometryTGeo::getIOTOFChipIndex(int lay, int sta, int mod, int chip) const +{ + return getIOTOFFirstChipIndex(lay) + (sta - 1) * mNumberOfChipsPerStaveIOTOF[lay] + (mod - 1) * mNumberOfChipsPerModuleIOTOF[lay] + (chip - 1); +} + bool GeometryTGeo::getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& chip) const { lay = getIOTOFLayer(index); @@ -152,7 +158,7 @@ bool GeometryTGeo::getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& index %= mNumberOfChipsPerStaveIOTOF[lay]; mod = mNumberOfModulesIOTOF[lay] > 0 ? index / mNumberOfChipsPerModuleIOTOF[lay] : -1; chip = index % mNumberOfChipsPerModuleIOTOF[lay]; - return false; + return true; } TString GeometryTGeo::getMatrixPath(int index) const @@ -200,7 +206,7 @@ TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const } matTmp = *gGeoManager->GetCurrentMatrix(); - LOG(info) << "Path = " << path.Data(); + // LOG(info) << "Path = " << path.Data(); // Restore the modeler state gGeoManager->PopPath(); @@ -222,6 +228,11 @@ void GeometryTGeo::Build(int loadTrans) LOGP(fatal, "Geometry is not loaded"); } + auto& iotofPars = IOTOFBaseParam::Instance(); + if (!iotofPars.segmentedInnerTOF && !iotofPars.segmentedOuterTOF) { + return; + } + // Inner/outer TOF for (int j{0}; j < 2; ++j) { mNumberOfStavesIOTOF[j] = extractNumberOfStavesIOTOF(j); From ce30af9f1d12559b178c8502ef71a49069b39049 Mon Sep 17 00:00:00 2001 From: maciacco Date: Fri, 1 May 2026 14:34:03 +0200 Subject: [PATCH 08/19] use proper chip id for segmented barrel --- .../ALICE3/IOTOF/simulation/src/Detector.cxx | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx index 59b914a3dd076..bed8cbfd6dfac 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx @@ -314,13 +314,29 @@ bool Detector::ProcessHits(FairVolume* vol) TLorentzVector positionStop; fMC->TrackPosition(positionStop); // Retrieve the indices with the volume path - int stave(0), halfstave(0), chipinmodule(0), module; + int stave(0), chipinmodule(0), module(0); fMC->CurrentVolOffID(1, chipinmodule); fMC->CurrentVolOffID(2, module); - fMC->CurrentVolOffID(3, halfstave); - fMC->CurrentVolOffID(4, stave); + fMC->CurrentVolOffID(3, stave); - o2::itsmft::Hit* p = addHit(stack->GetCurrentTrackNumber(), lay, mTrackData.mPositionStart.Vect(), positionStop.Vect(), + int sensorID = lay; + auto& iotofPars = IOTOFBaseParam::Instance(); + + int layN = -1; + if (strstr(vol->GetName(), GeometryTGeo::getITOFSensorPattern()) != nullptr) { + layN = 0; + } else if (strstr(vol->GetName(), GeometryTGeo::getOTOFSensorPattern())) { + layN = 1; + } + if (iotofPars.segmentedInnerTOF && iotofPars.segmentedOuterTOF) { + if (layN > -1) { + sensorID = mGeometryTGeo->getIOTOFChipIndex(layN, stave, module, chipinmodule); + } else { + sensorID += (mGeometryTGeo->getSize() - 1); // temporary as f/b tof is not yet segmented + } + } + + o2::itsmft::Hit* p = addHit(stack->GetCurrentTrackNumber(), sensorID, mTrackData.mPositionStart.Vect(), positionStop.Vect(), mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); From 0038f099007da40ca51b1555b7f8e74b75b47686 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Mon, 4 May 2026 19:26:27 +0200 Subject: [PATCH 09/19] refactoring of segmentation, idependent for inner and outer tof, nonstatic --- .../base/include/IOTOFBase/IOTOFBaseParam.h | 33 +++--- .../include/IOTOFSimulation/Segmentation.h | 107 +++++++++--------- .../IOTOF/simulation/src/Segmentation.cxx | 73 ++++++------ 3 files changed, 109 insertions(+), 104 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h index 952b6a8b3a28d..864bfcc2cef58 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h @@ -20,6 +20,24 @@ namespace o2 namespace iotof { +struct ChipSpecifics { + int NCols = 1024; + int NRows = 512; + float PitchCol = 29.24e-4; + float PitchRow = 26.88e-4; + float PassiveEdgeReadOut = 0.12f; + float PassiveEdgeTop = 37.44e-4; + float PassiveEdgeSide = 29.12e-4; + float SensorLayerThicknessEff = 28.e-4; + float SensorLayerThickness = 30.e-4; + + int NPixels() const { return NCols * NRows; } + float ActiveMatrixSizeCols() const { return PitchCol * NCols; } + float ActiveMatrixSizeRows() const { return PitchRow * NRows; } + float SensorSizeCols() const { return ActiveMatrixSizeCols() + 2 * PassiveEdgeSide; } + float SensorSizeRows() const { return ActiveMatrixSizeRows() + PassiveEdgeTop + PassiveEdgeReadOut; } +}; + struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper { bool enableInnerTOF = true; // Enable Inner TOF layer bool enableOuterTOF = true; // Enable Outer TOF layer @@ -31,19 +49,8 @@ struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper float x2x0 = 0.02f; // thickness expressed in radiation length, for all layers for the moment float sensorThickness = 0.0050f; // thickness of the sensor in cm, for all layers for the moment, the default is set to 50 microns - struct chipSpecifics { - int NCols = 1024; - int NRows = 512; - float PitchCol = 29.24e-4; - float PitchRow = 26.88e-4; - float PassiveEdgeReadOut = 0.12f; // width of the readout edge (Passive bottom) - float PassiveEdgeTop = 37.44e-4; // Passive area on top - float PassiveEdgeSide = 29.12e-4; // width of Passive area on left/right of the sensor - - // effective thickness of sensitive layer, accounting for charge collection non-unifoemity, https://alice.its.cern.ch/jira/browse/AOC-46 - float SensorLayerThicknessEff = 28.e-4; - float SensorLayerThickness = 30.e-4; // physical thickness of sensitive part - } chipSpecifics; + ChipSpecifics oTofChipSpecifics{1024, 512, 29.24e-4, 26.88e-4, 0.12f, 37.44e-4, 29.12e-4, 28.e-4, 30.e-4}; + ChipSpecifics iTofChipSpecifics{1024, 512, 29.24e-4, 26.88e-4, 0.12f, 37.44e-4, 29.12e-4, 28.e-4, 30.e-4}; O2ParamDef(IOTOFBaseParam, "IOTOFBase"); }; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h index f65e0451d3f14..bf86fac82f44c 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h @@ -18,6 +18,7 @@ #include #include "MathUtils/Cartesian.h" +#include "IOTOFBase/IOTOFBaseParam.h" namespace o2 { @@ -29,29 +30,16 @@ namespace iotof class Segmentation { public: - - static int NCols; - static int NRows; - static int NPixels; - static float PitchCol; - static float PitchRow; - static float PassiveEdgeReadOut; - static float PassiveEdgeTop; - static float PassiveEdgeSide; - static float ActiveMatrixSizeCols; - static float ActiveMatrixSizeRows; - - // effective thickness of sensitive layer, accounting for charge collection non-unifoemity, https://alice.its.cern.ch/jira/browse/AOC-46 - static float SensorLayerThicknessEff; - static float SensorLayerThickness; - static float SensorSizeCols; - static float SensorSizeRows; + + ChipSpecifics iTofSpecsConfig; + ChipSpecifics oTofSpecsConfig; Segmentation(); ~Segmentation() = default; - static void configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, const float passiveEdgeTop, - const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness); + void configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, const float passiveEdgeTop, + const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness, const int subDetectorID); + void configChip(const ChipSpecifics& specsConfig, const int subDetectorID); /// Transformation from Geant detector centered local coordinates (cm) to /// Pixel cell numbers iRow and iCol. @@ -64,9 +52,9 @@ class Segmentation /// the center of the sensitive volulme. /// \param int iRow Detector x cell coordinate. Has the range 0 <= iRow < mNumberOfRows /// \param int iCol Detector z cell coordinate. Has the range 0 <= iCol < mNumberOfColumns - static bool localToDetector(float x, float z, int& iRow, int& iCol); + bool localToDetector(float x, float z, int& iRow, int& iCol, const int subDetectorID); /// same but w/o check for row/column range - static void localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol); + void localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol, const int subDetectorID); /// Transformation from Detector cell coordiantes to Geant detector centered /// local coordinates (cm) @@ -81,74 +69,86 @@ class Segmentation // w/o check for row/col range template - static void detectorToLocalUnchecked(L row, L col, T& xRow, T& zCol) + void detectorToLocalUnchecked(L row, L col, T& xRow, T& zCol, const int subDetectorID) { - xRow = getFirstRowCoordinate() - row * PitchRow; - zCol = col * PitchCol + getFirstColCoordinate(); + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + xRow = getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow; + zCol = col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID); } template - static void detectorToLocalUnchecked(L row, L col, math_utils::Point3D& loc) + void detectorToLocalUnchecked(L row, L col, math_utils::Point3D& loc, const int subDetectorID) { - loc.SetCoordinates(getFirstRowCoordinate() - row * PitchRow, T(0.), col * PitchCol + getFirstColCoordinate()); + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + loc.SetCoordinates(getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow, T(0.), col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID)); } template - static void detectorToLocalUnchecked(L row, L col, std::array& loc) + void detectorToLocalUnchecked(L row, L col, std::array& loc, const int subDetectorID) { - loc[0] = getFirstRowCoordinate() - row * PitchRow; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + loc[0] = getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow; loc[1] = T(0); - loc[2] = col * PitchCol + getFirstColCoordinate(); + loc[2] = col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID); } // same but with check for row/col range template - static bool detectorToLocal(L row, L col, T& xRow, T& zCol) + bool detectorToLocal(L row, L col, T& xRow, T& zCol, const int subDetectorID) { - if (row < 0 || row >= NRows || col < 0 || col >= NCols) { + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } - detectorToLocalUnchecked(row, col, xRow, zCol); + detectorToLocalUnchecked(row, col, xRow, zCol, subDetectorID); return true; } template - static bool detectorToLocal(L row, L col, math_utils::Point3D& loc) + bool detectorToLocal(L row, L col, math_utils::Point3D& loc, const int subDetectorID) { - if (row < 0 || row >= NRows || col < 0 || col >= NCols) { + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } - detectorToLocalUnchecked(row, col, loc); + detectorToLocalUnchecked(row, col, loc, subDetectorID); return true; } template - static bool detectorToLocal(L row, L col, std::array& loc) + bool detectorToLocal(L row, L col, std::array& loc, const int subDetectorID) { - if (row < 0 || row >= NRows || col < 0 || col >= NCols) { + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } - detectorToLocalUnchecked(row, col, loc); + detectorToLocalUnchecked(row, col, loc, subDetectorID); return true; } - static float getFirstRowCoordinate() + float getFirstRowCoordinate(const int subDetectorID) { - return 0.5 * ((ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - PitchRow); + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + return 0.5 * ((specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - specsConfig.PitchRow); + } + float getFirstColCoordinate(const int subDetectorID) + { + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + return 0.5 * (specsConfig.PitchCol - specsConfig.ActiveMatrixSizeCols()); } - static float getFirstColCoordinate() { return 0.5 * (PitchCol - ActiveMatrixSizeCols); } - static void print(); + void print(); ClassDefNV(Segmentation, 1); // Segmentation class upgrade pixels }; //_________________________________________________________________________________________________ -inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol) +inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol, const int subDetectorID) { // convert to row/col w/o over/underflow check - xRow = 0.5 * (ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix - zCol += 0.5 * ActiveMatrixSizeCols; // coordinate wrt left edge of Active matrix - iRow = int(xRow / PitchRow); - iCol = int(zCol / PitchCol); + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix + zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix + iRow = int(xRow / specsConfig.PitchRow); + iCol = int(zCol / specsConfig.PitchCol); if (xRow < 0) { iRow -= 1; } @@ -158,17 +158,18 @@ inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& } //_________________________________________________________________________________________________ -inline bool Segmentation::localToDetector(float xRow, float zCol, int& iRow, int& iCol) +inline bool Segmentation::localToDetector(float xRow, float zCol, int& iRow, int& iCol, const int subDetectorID) { // convert to row/col - xRow = 0.5 * (ActiveMatrixSizeRows - PassiveEdgeTop + PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix - zCol += 0.5 * ActiveMatrixSizeCols; // coordinate wrt left edge of Active matrix - if (xRow < 0 || xRow >= ActiveMatrixSizeRows || zCol < 0 || zCol >= ActiveMatrixSizeCols) { + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix + zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix + if (xRow < 0 || xRow >= specsConfig.ActiveMatrixSizeRows() || zCol < 0 || zCol >= specsConfig.ActiveMatrixSizeCols()) { iRow = iCol = -1; return false; } - iRow = int(xRow / PitchRow); - iCol = int(zCol / PitchCol); + iRow = int(xRow / specsConfig.PitchRow); + iCol = int(zCol / specsConfig.PitchCol); return true; } diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx index 3c0cdea04af65..6d627a802714d 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx @@ -22,55 +22,52 @@ namespace o2 namespace iotof { -int Segmentation::NCols = 0; -int Segmentation::NRows = 0; -int Segmentation::NPixels = 0; -float Segmentation::PitchCol = 0.f; -float Segmentation::PitchRow = 0.f; -float Segmentation::PassiveEdgeReadOut = 0.f; -float Segmentation::PassiveEdgeTop = 0.f; -float Segmentation::PassiveEdgeSide = 0.f; -float Segmentation::ActiveMatrixSizeCols = 0.f; -float Segmentation::ActiveMatrixSizeRows = 0.f; -float Segmentation::SensorLayerThicknessEff = 0.f; -float Segmentation::SensorLayerThickness = 0.f; -float Segmentation::SensorSizeCols = 0.f; -float Segmentation::SensorSizeRows = 0.f; - Segmentation::Segmentation() { auto& iotofPars = IOTOFBaseParam::Instance(); - auto& chipPars = iotofPars.chipSpecifics; - configChip(chipPars.NCols, chipPars.NRows, chipPars.PitchCol, chipPars.PitchRow, chipPars.PassiveEdgeReadOut, chipPars.PassiveEdgeTop, - chipPars.PassiveEdgeSide, chipPars.SensorLayerThicknessEff, chipPars.SensorLayerThickness); + const ChipSpecifics& iTofChipPars = iotofPars.iTofChipSpecifics; + const ChipSpecifics& oTofChipPars = iotofPars.oTofChipSpecifics; + + configChip(iTofChipPars, 0 /* subDetectorID for iTOF */); + configChip(oTofChipPars, 1 /* subDetectorID for oTOF */); } void Segmentation::configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, - const float passiveEdgeTop, const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness) + const float passiveEdgeTop, const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness, const int subDetectorID) { - NCols = nCols; - NRows = nRows; - NPixels = NCols * NRows; - PitchCol = pitchCol; - PitchRow = pitchRow; - PassiveEdgeReadOut = passiveEdgeReadOut; - PassiveEdgeTop = passiveEdgeTop; - PassiveEdgeSide = passiveEdgeSide; - ActiveMatrixSizeCols = PitchCol * NCols; - ActiveMatrixSizeRows = PitchRow * NRows; - SensorLayerThicknessEff = sensorLayerThicknessEff; - SensorLayerThickness = sensorLayerThickness; - SensorSizeCols = ActiveMatrixSizeCols + PassiveEdgeSide + PassiveEdgeSide; - SensorSizeRows = ActiveMatrixSizeRows + PassiveEdgeTop + PassiveEdgeReadOut; + if (subDetectorID == 0) { + iTofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, sensorLayerThicknessEff, sensorLayerThickness); + } else if (subDetectorID == 1) { + oTofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, sensorLayerThicknessEff, sensorLayerThickness); + } else { + printf("Invalid subDetectorID %d. Must be 0 (iTOF) or 1 (oTOF). No configuration applied.\n", subDetectorID); + } +} + +void Segmentation::configChip(const ChipSpecifics& specsConfig, const int subDetectorID) +{ + if (subDetectorID == 0) { + iTofSpecsConfig = specsConfig; + } else if (subDetectorID == 1) { + oTofSpecsConfig = specsConfig; + } else { + printf("Invalid subDetectorID %d. Must be 0 (iTOF) or 1 (oTOF). No configuration applied.\n", subDetectorID); + } } void Segmentation::print() { - printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", PitchRow * 1e4, NRows, PitchCol * 1e4, NCols); - printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", - PassiveEdgeReadOut * 1e4, PassiveEdgeTop * 1e4, PassiveEdgeSide * 1e4); - printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", ActiveMatrixSizeRows, SensorSizeRows, - ActiveMatrixSizeCols, SensorSizeCols); + // iTOF specs + printf("iTOF specs:\n"); + printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", iTofSpecsConfig.PitchRow * 1e4, iTofSpecsConfig.NRows, iTofSpecsConfig.PitchCol * 1e4, iTofSpecsConfig.NCols); + printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", iTofSpecsConfig.PassiveEdgeReadOut * 1e4, iTofSpecsConfig.PassiveEdgeTop * 1e4, iTofSpecsConfig.PassiveEdgeSide * 1e4); + printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", iTofSpecsConfig.ActiveMatrixSizeRows(), iTofSpecsConfig.SensorSizeRows(), iTofSpecsConfig.ActiveMatrixSizeCols(), iTofSpecsConfig.SensorSizeCols()); + + // oTOF specs + printf("oTOF specs:\n"); + printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", oTofSpecsConfig.PitchRow * 1e4, oTofSpecsConfig.NRows, oTofSpecsConfig.PitchCol * 1e4, oTofSpecsConfig.NCols); + printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", oTofSpecsConfig.PassiveEdgeReadOut * 1e4, oTofSpecsConfig.PassiveEdgeTop * 1e4, oTofSpecsConfig.PassiveEdgeSide * 1e4); + printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", oTofSpecsConfig.ActiveMatrixSizeRows(), oTofSpecsConfig.SensorSizeRows(), oTofSpecsConfig.ActiveMatrixSizeCols(), oTofSpecsConfig.SensorSizeCols()); } } // namespace iotof From 728a5052da5730f6c112f4085be232b9110638e4 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 15:40:06 +0200 Subject: [PATCH 10/19] singleton implementation of the segmentation class --- .../include/IOTOFSimulation/Segmentation.h | 31 +++++++----- .../IOTOF/simulation/src/Segmentation.cxx | 47 ++++++++++++------- 2 files changed, 49 insertions(+), 29 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h index bf86fac82f44c..6446dd3565508 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h @@ -17,6 +17,7 @@ #define ALICEO2_IOTOF_SEGMENTATION_H #include +#include #include "MathUtils/Cartesian.h" #include "IOTOFBase/IOTOFBaseParam.h" @@ -29,12 +30,16 @@ namespace iotof /// Questions to solve: class Segmentation { + private: + Segmentation(); + static std::unique_ptr sInstance; + public: - ChipSpecifics iTofSpecsConfig; - ChipSpecifics oTofSpecsConfig; + ChipSpecifics mITofSpecsConfig; + ChipSpecifics mOTofSpecsConfig; + static Segmentation* Instance(); - Segmentation(); ~Segmentation() = default; void configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, const float passiveEdgeTop, @@ -71,20 +76,20 @@ class Segmentation template void detectorToLocalUnchecked(L row, L col, T& xRow, T& zCol, const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; xRow = getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow; zCol = col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID); } template void detectorToLocalUnchecked(L row, L col, math_utils::Point3D& loc, const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; loc.SetCoordinates(getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow, T(0.), col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID)); } template void detectorToLocalUnchecked(L row, L col, std::array& loc, const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; loc[0] = getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow; loc[1] = T(0); loc[2] = col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID); @@ -95,7 +100,7 @@ class Segmentation template bool detectorToLocal(L row, L col, T& xRow, T& zCol, const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } @@ -106,7 +111,7 @@ class Segmentation template bool detectorToLocal(L row, L col, math_utils::Point3D& loc, const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } @@ -116,7 +121,7 @@ class Segmentation template bool detectorToLocal(L row, L col, std::array& loc, const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } @@ -126,12 +131,12 @@ class Segmentation float getFirstRowCoordinate(const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; return 0.5 * ((specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - specsConfig.PitchRow); } float getFirstColCoordinate(const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; return 0.5 * (specsConfig.PitchCol - specsConfig.ActiveMatrixSizeCols()); } @@ -144,7 +149,7 @@ class Segmentation inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol, const int subDetectorID) { // convert to row/col w/o over/underflow check - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix iRow = int(xRow / specsConfig.PitchRow); @@ -161,7 +166,7 @@ inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& inline bool Segmentation::localToDetector(float xRow, float zCol, int& iRow, int& iCol, const int subDetectorID) { // convert to row/col - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? iTofSpecsConfig : oTofSpecsConfig; + const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix if (xRow < 0 || xRow >= specsConfig.ActiveMatrixSizeRows() || zCol < 0 || zCol >= specsConfig.ActiveMatrixSizeCols()) { diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx index 6d627a802714d..31f77478e4898 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx @@ -22,23 +22,38 @@ namespace o2 namespace iotof { +std::unique_ptr Segmentation::sInstance; + +Segmentation* Segmentation::Instance() +{ + if (!sInstance) { + sInstance = std::unique_ptr(new Segmentation()); + } + return sInstance.get(); +} + Segmentation::Segmentation() { - auto& iotofPars = IOTOFBaseParam::Instance(); - const ChipSpecifics& iTofChipPars = iotofPars.iTofChipSpecifics; - const ChipSpecifics& oTofChipPars = iotofPars.oTofChipSpecifics; - - configChip(iTofChipPars, 0 /* subDetectorID for iTOF */); - configChip(oTofChipPars, 1 /* subDetectorID for oTOF */); + if (sInstance) { + printf("Invalid use of public constructor: o2::iotof::Segmentation instance exists\n"); + } + else { + auto& iotofPars = IOTOFBaseParam::Instance(); + const ChipSpecifics& mITofChipPars = iotofPars.iTofChipSpecifics; + const ChipSpecifics& mOTofChipPars = iotofPars.oTofChipSpecifics; + + configChip(mITofChipPars, 0 /* subDetectorID for iTOF */); + configChip(mOTofChipPars, 1 /* subDetectorID for oTOF */); + } } void Segmentation::configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, const float passiveEdgeTop, const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness, const int subDetectorID) { if (subDetectorID == 0) { - iTofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, sensorLayerThicknessEff, sensorLayerThickness); + mITofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, sensorLayerThicknessEff, sensorLayerThickness); } else if (subDetectorID == 1) { - oTofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, sensorLayerThicknessEff, sensorLayerThickness); + mOTofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, sensorLayerThicknessEff, sensorLayerThickness); } else { printf("Invalid subDetectorID %d. Must be 0 (iTOF) or 1 (oTOF). No configuration applied.\n", subDetectorID); } @@ -47,9 +62,9 @@ void Segmentation::configChip(const int nCols, const int nRows, const float pitc void Segmentation::configChip(const ChipSpecifics& specsConfig, const int subDetectorID) { if (subDetectorID == 0) { - iTofSpecsConfig = specsConfig; + mITofSpecsConfig = specsConfig; } else if (subDetectorID == 1) { - oTofSpecsConfig = specsConfig; + mOTofSpecsConfig = specsConfig; } else { printf("Invalid subDetectorID %d. Must be 0 (iTOF) or 1 (oTOF). No configuration applied.\n", subDetectorID); } @@ -59,15 +74,15 @@ void Segmentation::print() { // iTOF specs printf("iTOF specs:\n"); - printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", iTofSpecsConfig.PitchRow * 1e4, iTofSpecsConfig.NRows, iTofSpecsConfig.PitchCol * 1e4, iTofSpecsConfig.NCols); - printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", iTofSpecsConfig.PassiveEdgeReadOut * 1e4, iTofSpecsConfig.PassiveEdgeTop * 1e4, iTofSpecsConfig.PassiveEdgeSide * 1e4); - printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", iTofSpecsConfig.ActiveMatrixSizeRows(), iTofSpecsConfig.SensorSizeRows(), iTofSpecsConfig.ActiveMatrixSizeCols(), iTofSpecsConfig.SensorSizeCols()); + printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", mITofSpecsConfig.PitchRow * 1e4, mITofSpecsConfig.NRows, mITofSpecsConfig.PitchCol * 1e4, mITofSpecsConfig.NCols); + printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", mITofSpecsConfig.PassiveEdgeReadOut * 1e4, mITofSpecsConfig.PassiveEdgeTop * 1e4, mITofSpecsConfig.PassiveEdgeSide * 1e4); + printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", mITofSpecsConfig.ActiveMatrixSizeRows(), mITofSpecsConfig.SensorSizeRows(), mITofSpecsConfig.ActiveMatrixSizeCols(), mITofSpecsConfig.SensorSizeCols()); // oTOF specs printf("oTOF specs:\n"); - printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", oTofSpecsConfig.PitchRow * 1e4, oTofSpecsConfig.NRows, oTofSpecsConfig.PitchCol * 1e4, oTofSpecsConfig.NCols); - printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", oTofSpecsConfig.PassiveEdgeReadOut * 1e4, oTofSpecsConfig.PassiveEdgeTop * 1e4, oTofSpecsConfig.PassiveEdgeSide * 1e4); - printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", oTofSpecsConfig.ActiveMatrixSizeRows(), oTofSpecsConfig.SensorSizeRows(), oTofSpecsConfig.ActiveMatrixSizeCols(), oTofSpecsConfig.SensorSizeCols()); + printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", mOTofSpecsConfig.PitchRow * 1e4, mOTofSpecsConfig.NRows, mOTofSpecsConfig.PitchCol * 1e4, mOTofSpecsConfig.NCols); + printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", mOTofSpecsConfig.PassiveEdgeReadOut * 1e4, mOTofSpecsConfig.PassiveEdgeTop * 1e4, mOTofSpecsConfig.PassiveEdgeSide * 1e4); + printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", mOTofSpecsConfig.ActiveMatrixSizeRows(), mOTofSpecsConfig.SensorSizeRows(), mOTofSpecsConfig.ActiveMatrixSizeCols(), mOTofSpecsConfig.SensorSizeCols()); } } // namespace iotof From 5924d188204e3b4a9625eff4d2c304c2b62f856e Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 15:40:26 +0200 Subject: [PATCH 11/19] realistic values fot the chip segmentation --- .../ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h index 864bfcc2cef58..f209da9ac8d56 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h @@ -49,8 +49,8 @@ struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper float x2x0 = 0.02f; // thickness expressed in radiation length, for all layers for the moment float sensorThickness = 0.0050f; // thickness of the sensor in cm, for all layers for the moment, the default is set to 50 microns - ChipSpecifics oTofChipSpecifics{1024, 512, 29.24e-4, 26.88e-4, 0.12f, 37.44e-4, 29.12e-4, 28.e-4, 30.e-4}; - ChipSpecifics iTofChipSpecifics{1024, 512, 29.24e-4, 26.88e-4, 0.12f, 37.44e-4, 29.12e-4, 28.e-4, 30.e-4}; + ChipSpecifics iTofChipSpecifics{258, 271, 250.00e-4, 100.00e-4, 0.00f, 0.00e-4, 0.00e-4, 28.e-4, 30.e-4}; + ChipSpecifics oTofChipSpecifics{251, 487, 250.00e-4, 100.00e-4, 0.00f, 0.00e-4, 106.48e-4, 28.e-4, 30.e-4}; O2ParamDef(IOTOFBaseParam, "IOTOFBase"); }; From bdbd1b8deb68dd57b98c21ec2697266204b13047 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 15:41:08 +0200 Subject: [PATCH 12/19] hit processing in place, tested on A3Studies/Digitization/testDigitization.cpp --- .../include/IOTOFSimulation/Digitizer.h | 3 +++ .../ALICE3/IOTOF/simulation/src/Digitizer.cxx | 21 +++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h index 8964e33f8a1b6..b5e4441df36c6 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h @@ -27,6 +27,7 @@ #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "IOTOFBase/GeometryTGeo.h" +#include "IOTOFSimulation/Segmentation.h" namespace o2::iotof { @@ -105,6 +106,8 @@ class Digitizer 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) + + static o2::iotof::Segmentation* sSegmentation; ///< IOTOF segmentation instance (singleton) }; } // namespace o2::iotof diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx index b865d6958ecfd..00f4578b2e392 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx @@ -29,6 +29,8 @@ namespace o2::iotof { +o2::iotof::Segmentation* Digitizer::sSegmentation = nullptr; + //_______________________________________________________________________ void Digitizer::init() { @@ -37,6 +39,7 @@ void Digitizer::init() LOG(info) << " Charge threshold: " << mChargeThreshold << " electrons"; LOG(info) << " Detection efficiency: " << mEfficiency * 100 << " %"; LOG(info) << " Continuous mode: " << (mContinuous ? "ON" : "OFF"); + sSegmentation = o2::iotof::Segmentation::Instance(); } //_______________________________________________________________________ @@ -44,7 +47,7 @@ void Digitizer::process(const std::vector* hits, int evID, int { // Digitize hits from a single event LOG(debug) << "Digitizing IOTOF hits: " << hits->size() << " hits from event " << evID << " source " << srcID; - + if (!hits || hits->empty()) { return; } @@ -102,12 +105,22 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) // 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 + + const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID()); + math_utils::Vector3D xyzPositionStart(matrix ^ (hit.GetPosStart())); // start position in sensor frame + //math_utils::Vector3D xyzPositionEnd(matrix ^ (hit.GetPos())); // end position in sensor frame + + int row = 0; // Will be determined from start hit position + int col = 0; // Will be determined from start hit position + + if (!sSegmentation->localToDetector(xyzPositionStart.X(), xyzPositionStart.Z(), row, col, mGeometry->getIOTOFLayer(detID))) { + LOG(debug) << "Hit position out of bounds for detector ID " << detID; + return; // hit is outside the active area + } // Create the digit with time information int digID = mDigits->size(); - mDigits->emplace_back(chipIndex, row, col, charge, smearedTime); + mDigits->emplace_back(chipIndex, static_cast(row), static_cast(col), charge, smearedTime); LOG(debug) << "Created digit #" << digID << " chip=" << chipIndex << " charge=" << charge << " time=" << smearedTime << " ns"; From 175f4db4d7037d8b3edc1c595c905cf48e1b126f Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 15:42:56 +0200 Subject: [PATCH 13/19] clang format --- .../simulation/include/IOTOFSimulation/Digitizer.h | 2 +- .../simulation/include/IOTOFSimulation/Segmentation.h | 11 +++++------ .../ALICE3/IOTOF/simulation/src/Digitizer.cxx | 6 +++--- .../ALICE3/IOTOF/simulation/src/Segmentation.cxx | 5 ++--- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h index b5e4441df36c6..aae989248f07e 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Digitizer.h @@ -106,7 +106,7 @@ class Digitizer 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) - + static o2::iotof::Segmentation* sSegmentation; ///< IOTOF segmentation instance (singleton) }; } // namespace o2::iotof diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h index 6446dd3565508..8b76fe413f9d5 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h @@ -35,7 +35,6 @@ class Segmentation static std::unique_ptr sInstance; public: - ChipSpecifics mITofSpecsConfig; ChipSpecifics mOTofSpecsConfig; static Segmentation* Instance(); @@ -134,10 +133,10 @@ class Segmentation const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; return 0.5 * ((specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - specsConfig.PitchRow); } - float getFirstColCoordinate(const int subDetectorID) - { + float getFirstColCoordinate(const int subDetectorID) + { const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; - return 0.5 * (specsConfig.PitchCol - specsConfig.ActiveMatrixSizeCols()); + return 0.5 * (specsConfig.PitchCol - specsConfig.ActiveMatrixSizeCols()); } void print(); @@ -151,7 +150,7 @@ inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& // convert to row/col w/o over/underflow check const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix - zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix + zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix iRow = int(xRow / specsConfig.PitchRow); iCol = int(zCol / specsConfig.PitchCol); if (xRow < 0) { @@ -168,7 +167,7 @@ inline bool Segmentation::localToDetector(float xRow, float zCol, int& iRow, int // convert to row/col const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix - zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix + zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix if (xRow < 0 || xRow >= specsConfig.ActiveMatrixSizeRows() || zCol < 0 || zCol >= specsConfig.ActiveMatrixSizeCols()) { iRow = iCol = -1; return false; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx index 00f4578b2e392..114a0d0ffe286 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx @@ -47,7 +47,7 @@ void Digitizer::process(const std::vector* hits, int evID, int { // Digitize hits from a single event LOG(debug) << "Digitizing IOTOF hits: " << hits->size() << " hits from event " << evID << " source " << srcID; - + if (!hits || hits->empty()) { return; } @@ -108,11 +108,11 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID()); math_utils::Vector3D xyzPositionStart(matrix ^ (hit.GetPosStart())); // start position in sensor frame - //math_utils::Vector3D xyzPositionEnd(matrix ^ (hit.GetPos())); // end position in sensor frame + // math_utils::Vector3D xyzPositionEnd(matrix ^ (hit.GetPos())); // end position in sensor frame int row = 0; // Will be determined from start hit position int col = 0; // Will be determined from start hit position - + if (!sSegmentation->localToDetector(xyzPositionStart.X(), xyzPositionStart.Z(), row, col, mGeometry->getIOTOFLayer(detID))) { LOG(debug) << "Hit position out of bounds for detector ID " << detID; return; // hit is outside the active area diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx index 31f77478e4898..bbfb60234210d 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx @@ -36,8 +36,7 @@ Segmentation::Segmentation() { if (sInstance) { printf("Invalid use of public constructor: o2::iotof::Segmentation instance exists\n"); - } - else { + } else { auto& iotofPars = IOTOFBaseParam::Instance(); const ChipSpecifics& mITofChipPars = iotofPars.iTofChipSpecifics; const ChipSpecifics& mOTofChipPars = iotofPars.oTofChipSpecifics; @@ -48,7 +47,7 @@ Segmentation::Segmentation() } void Segmentation::configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, - const float passiveEdgeTop, const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness, const int subDetectorID) + const float passiveEdgeTop, const float passiveEdgeSide, const float sensorLayerThicknessEff, const float sensorLayerThickness, const int subDetectorID) { if (subDetectorID == 0) { mITofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, sensorLayerThicknessEff, sensorLayerThickness); From ea0d6743925a325c27b786656d90d69061f5fe86 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 15:57:47 +0200 Subject: [PATCH 14/19] protect against disks for now --- .../include/IOTOFSimulation/Segmentation.h | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h index 8b76fe413f9d5..efa68dba6de1c 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h @@ -75,6 +75,10 @@ class Segmentation template void detectorToLocalUnchecked(L row, L col, T& xRow, T& zCol, const int subDetectorID) { + if (subDetectorID != 0 && subDetectorID != 1) { + iRow = iCol = -1; + return false; + } const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; xRow = getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow; zCol = col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID); @@ -82,12 +86,20 @@ class Segmentation template void detectorToLocalUnchecked(L row, L col, math_utils::Point3D& loc, const int subDetectorID) { + if (subDetectorID != 0 && subDetectorID != 1) { + iRow = iCol = -1; + return false; + } const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; loc.SetCoordinates(getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow, T(0.), col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID)); } template void detectorToLocalUnchecked(L row, L col, std::array& loc, const int subDetectorID) { + if (subDetectorID != 0 && subDetectorID != 1) { + iRow = iCol = -1; + return false; + } const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; loc[0] = getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow; loc[1] = T(0); @@ -99,6 +111,10 @@ class Segmentation template bool detectorToLocal(L row, L col, T& xRow, T& zCol, const int subDetectorID) { + if (subDetectorID != 0 && subDetectorID != 1) { + iRow = iCol = -1; + return false; + } const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; @@ -110,6 +126,10 @@ class Segmentation template bool detectorToLocal(L row, L col, math_utils::Point3D& loc, const int subDetectorID) { + if (subDetectorID != 0 && subDetectorID != 1) { + iRow = iCol = -1; + return false; + } const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; @@ -120,6 +140,10 @@ class Segmentation template bool detectorToLocal(L row, L col, std::array& loc, const int subDetectorID) { + if (subDetectorID != 0 && subDetectorID != 1) { + iRow = iCol = -1; + return false; + } const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; @@ -148,6 +172,10 @@ class Segmentation inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol, const int subDetectorID) { // convert to row/col w/o over/underflow check + if (subDetectorID != 0 && subDetectorID != 1) { + iRow = iCol = -1; + return false; + } const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix @@ -165,6 +193,10 @@ inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& inline bool Segmentation::localToDetector(float xRow, float zCol, int& iRow, int& iCol, const int subDetectorID) { // convert to row/col + if (subDetectorID != 0 && subDetectorID != 1) { + iRow = iCol = -1; + return false; + } const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix From e437ecfe55a87fa636ba5db450c8aba57798cd97 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 16:53:04 +0200 Subject: [PATCH 15/19] added sanity checks --- Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx | 4 ++++ Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx index 8669ef855b8e3..61ea960409e7c 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx @@ -142,6 +142,10 @@ int GeometryTGeo::getIOTOFFirstChipIndex(int lay) const int GeometryTGeo::getIOTOFLayer(int index) const { + if (index < 0 || index > mLastChipIndex[1]) { + LOG(fatal) << "Invalid chip index " << index; + return -1; + } return index > mLastChipIndex[0] ? 1 : 0; } diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx index 114a0d0ffe286..2752d7f16bb4a 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx @@ -106,7 +106,12 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) // TODO: Implement proper segmentation when geometry is finalized uint16_t chipIndex = static_cast(detID); + if (detID > mGeometry->getSize() || !mGeometry->getSize() < 0) { + LOG(debug) << "Invalid detector ID: " << detID; + return; // invalid detector ID + } const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID()); + math_utils::Vector3D xyzPositionStart(matrix ^ (hit.GetPosStart())); // start position in sensor frame // math_utils::Vector3D xyzPositionEnd(matrix ^ (hit.GetPos())); // end position in sensor frame From d4b2789c63235de574158bd550aa8c4697b41746 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 17:00:14 +0200 Subject: [PATCH 16/19] thickness that matches the values currently in O2 --- .../ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h index f209da9ac8d56..5b3eb3234fb1a 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h @@ -28,8 +28,8 @@ struct ChipSpecifics { float PassiveEdgeReadOut = 0.12f; float PassiveEdgeTop = 37.44e-4; float PassiveEdgeSide = 29.12e-4; - float SensorLayerThicknessEff = 28.e-4; - float SensorLayerThickness = 30.e-4; + float SensorLayerThicknessEff = 50.e-4; + float SensorLayerThickness = 50.e-4; int NPixels() const { return NCols * NRows; } float ActiveMatrixSizeCols() const { return PitchCol * NCols; } @@ -49,8 +49,8 @@ struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper float x2x0 = 0.02f; // thickness expressed in radiation length, for all layers for the moment float sensorThickness = 0.0050f; // thickness of the sensor in cm, for all layers for the moment, the default is set to 50 microns - ChipSpecifics iTofChipSpecifics{258, 271, 250.00e-4, 100.00e-4, 0.00f, 0.00e-4, 0.00e-4, 28.e-4, 30.e-4}; - ChipSpecifics oTofChipSpecifics{251, 487, 250.00e-4, 100.00e-4, 0.00f, 0.00e-4, 106.48e-4, 28.e-4, 30.e-4}; + ChipSpecifics iTofChipSpecifics{258, 271, 250.00e-4, 100.00e-4, 0.00f, 0.00e-4, 0.00e-4, 50.e-4, 50.e-4}; + ChipSpecifics oTofChipSpecifics{251, 487, 250.00e-4, 100.00e-4, 0.00f, 0.00e-4, 106.48e-4, 50.e-4, 50.e-4}; O2ParamDef(IOTOFBaseParam, "IOTOFBase"); }; From 6a4c6c2166561c6f8a31689928b8871dc67df5f2 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 17:01:49 +0200 Subject: [PATCH 17/19] default init of chipspecifics to zero --- .../base/include/IOTOFBase/IOTOFBaseParam.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h index 5b3eb3234fb1a..c4cf5fd8844a8 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h @@ -21,15 +21,15 @@ namespace iotof { struct ChipSpecifics { - int NCols = 1024; - int NRows = 512; - float PitchCol = 29.24e-4; - float PitchRow = 26.88e-4; - float PassiveEdgeReadOut = 0.12f; - float PassiveEdgeTop = 37.44e-4; - float PassiveEdgeSide = 29.12e-4; - float SensorLayerThicknessEff = 50.e-4; - float SensorLayerThickness = 50.e-4; + int NCols = 0; + int NRows = 0; + float PitchCol = 0.; + float PitchRow = 0.; + float PassiveEdgeReadOut = 0.; + float PassiveEdgeTop = 0.; + float PassiveEdgeSide = 0.; + float SensorLayerThicknessEff = 0.; + float SensorLayerThickness = 0.; int NPixels() const { return NCols * NRows; } float ActiveMatrixSizeCols() const { return PitchCol * NCols; } From 31daa6d33952dba4dc16d126271da078c0e74501 Mon Sep 17 00:00:00 2001 From: GiorgioAlbertoLucia Date: Wed, 6 May 2026 17:05:17 +0200 Subject: [PATCH 18/19] double typo (half the honor) --- Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx index 2752d7f16bb4a..8e5e74dd1f0ca 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx @@ -106,7 +106,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID) // TODO: Implement proper segmentation when geometry is finalized uint16_t chipIndex = static_cast(detID); - if (detID > mGeometry->getSize() || !mGeometry->getSize() < 0) { + if (detID > mGeometry->getSize() || mGeometry->getSize() < 1) { LOG(debug) << "Invalid detector ID: " << detID; return; // invalid detector ID } From 213c808551e86455e9df258140f33e67577648fb Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Wed, 6 May 2026 15:08:57 +0000 Subject: [PATCH 19/19] Please consider the following formatting changes --- .../Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h index 810b816b51022..4dbdb49d4822d 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h @@ -93,7 +93,6 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache TString getMatrixPath(int index) const; - protected: // Determine the number of active parts in the geometry int extractNumberOfStavesIOTOF(int lay) const;