From 12fcd79d5beb4e74672facf32a3f802a663dd748 Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Tue, 8 Jul 2025 16:50:12 +0200 Subject: [PATCH 1/8] ALICE3-TRK: correctly setting the path to retrieve matrices from the geometry --- .../TRK/base/include/TRKBase/GeometryTGeo.h | 2 +- .../ALICE3/TRK/base/src/GeometryTGeo.cxx | 78 +++++++------------ 2 files changed, 28 insertions(+), 52 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h index cfd991728d09b..a1e4b9321130f 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h @@ -73,7 +73,7 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache void setOwner(bool v) { mOwner = v; } void Print(Option_t* opt = "") const; - void PrintChipID(int index, int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int indexRetrieved) const; + void PrintChipID(int index, int subDetID, int petalcase, int disk, int lay, int stave, int halfstave) const; int getLayer(int index) const; int getStave(int index) const; diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index 69bae0fad9cee..ee473509877e1 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -263,58 +263,35 @@ bool GeometryTGeo::getChipID(int index, int& subDetID, int& petalcase, int& disk TString GeometryTGeo::getMatrixPath(int index) const { - int subDetID, petalcase, disk, lay, stave, halfstave; //// TODO: add chips in a second step - getChipID(index, subDetID, petalcase, disk, lay, stave, halfstave); + int subDetID, petalcase, disk, layer, stave, halfstave; //// TODO: add chips in a second step + getChipID(index, subDetID, petalcase, disk, layer, stave, halfstave); - int indexRetrieved = getChipIndex(subDetID, petalcase, disk, lay, stave, halfstave); + PrintChipID(index, subDetID, petalcase, disk, layer, stave, halfstave); - PrintChipID(index, subDetID, petalcase, disk, lay, stave, halfstave, indexRetrieved); + // TString path = "/cave_1/barrel_1/TRKV_2/TRKLayer0_1/TRKStave0_1/TRKChip0_1/TRKSensor0_1/"; /// dummy path, to be used for tests + TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getTRKVolPattern()); - // TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getTRKVolPattern()); - TString path = "/cave_1/barrel_1/TRKV_2/TRKLayer0_1/TRKStave0_1/TRKChip0_1/TRKSensor0_1/"; /// dummy path, to be replaced - - // if (wrID >= 0) { - // path += Form("%s%d_1/", getITSWrapVolPattern(), wrID); - // } - - // if (isVD) { - // path += Form("%s%d_1/", getTRKPetalPattern(), index); - - // } else { - // path += Form("%s%d_1/", getTRKLayerPattern(), index); - // } - - // if (!mIsLayerITS3[lay]) { - // path += - // Form("%s%d_1/", getITSLayerPattern(), lay); - // if (mNumberOfHalfBarrels > 0) { - // path += Form("%s%d_%d/", getITSHalfBarrelPattern(), lay, hba); - // } - // path += - // Form("%s%d_%d/", getITSStavePattern(), lay, stav); - - // if (mNumberOfHalfStaves[lay] > 0) { - // path += Form("%s%d_%d/", getITSHalfStavePattern(), lay, sstav); - // } - // if (mNumberOfModules[lay] > 0) { - // path += Form("%s%d_%d/", getITSModulePattern(), lay, mod); - // } - // path += Form("%s%d_%d/%s%d_1", getITSChipPattern(), lay, chipInMod, getITSSensorPattern(), lay); - // } else { - // // hba = carbonform - // // stav = 0 - // // sstav = segment - // // mod = rsu - // // chipInMod = tile - // // sensor = pixelarray - // path += Form("%s_0/", getITS3LayerPattern(lay)); - // path += Form("%s_%d/", getITS3CarbonFormPattern(lay), hba); - // path += Form("%s_0/", getITS3ChipPattern(lay)); - // path += Form("%s_%d/", getITS3SegmentPattern(lay), sstav); - // path += Form("%s_%d/", getITS3RSUPattern(lay), mod); - // path += Form("%s_%d/", getITS3TilePattern(lay), chipInMod); - // path += Form("%s_0", getITS3PixelArrayPattern(lay)); - // } + if (subDetID == 0) { // VD + if (disk >= 0) { + path += Form("%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalDiskPattern(), disk); // PETALCASEx_DISKy_1 + path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalDiskPattern(), disk, getTRKChipPattern(), disk); // PETALCASEx_DISKy_TRKChipy_1 + path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalDiskPattern(), disk, getTRKSensorPattern(), disk); // PETALCASEx_DISKy_TRKSensory_1 + } else if (layer >= 0) { + path += Form("%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer); // PETALCASEx_LAYERy_1 + path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer, getTRKStavePattern(), layer); // PETALCASEx_LAYERy_TRKStavey_1 + path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer, getTRKChipPattern(), layer); // PETALCASEx_LAYERy_TRKChipy_1 + path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer, getTRKSensorPattern(), layer); // PETALCASEx_LAYERy_TRKSensory_1 + } + } else if (subDetID == 1) { // MLOT + path += Form("%s%d_1/", getTRKLayerPattern(), layer); // TRKLayerx_1 + path += Form("%s%d_%d/", getTRKStavePattern(), layer, stave); // TRKStavex_y + if (mNumberOfHalfStaves[layer] == 2) { // staggered geometry + path += Form("%s%d_%d/", getTRKChipPattern(), layer, halfstave); // TRKChipx_0/1 + } else if (mNumberOfHalfStaves[layer] == 1) { // turbo geometry + path += Form("%s%d_1/", getTRKChipPattern(), layer); // TRKChipx_1 + } + path += Form("%s%d_1/", getTRKSensorPattern(), layer); // TRKSensorx_1 + } return path; } @@ -672,7 +649,7 @@ int GeometryTGeo::extractNumberOfHalfStavesMLOT(int lay) const } //__________________________________________________________________________ -void GeometryTGeo::PrintChipID(int index, int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int indexRetrieved) const +void GeometryTGeo::PrintChipID(int index, int subDetID, int petalcase, int disk, int lay, int stave, int halfstave) const { std::cout << "\nindex = " << index << std::endl; std::cout << "subDetID = " << subDetID << std::endl; @@ -682,7 +659,6 @@ void GeometryTGeo::PrintChipID(int index, int subDetID, int petalcase, int disk, std::cout << "first chip index = " << getFirstChipIndex(lay, petalcase, subDetID) << std::endl; std::cout << "stave = " << stave << std::endl; std::cout << "halfstave = " << halfstave << std::endl; - std::cout << "check index Retrieved = " << indexRetrieved << std::endl; } //__________________________________________________________________________ From 40a43e23d2f97f7476e7b19339d412cef023845d Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Fri, 1 Aug 2025 15:50:13 +0200 Subject: [PATCH 2/8] ALICE3-TRK: setting basis for digitization code - definition of a simple segmentation, adding methods to deal with the curved VD layers, adding chip response based on ITS2 and ITS3 codes, adding useful codes for parameters, digit containers, etc. --- .../Upgrades/ALICE3/TRK/base/CMakeLists.txt | 4 +- .../base/include/TRKBase/SegmentationChip.h | 266 ++++++++++++++ .../ALICE3/TRK/base/include/TRKBase/Specs.h | 114 ++++++ .../ALICE3/TRK/base/src/GeometryTGeo.cxx | 40 ++- .../ALICE3/TRK/base/src/SegmentationChip.cxx | 27 ++ .../ALICE3/TRK/simulation/CMakeLists.txt | 8 +- .../TRKSimulation/ChipDigitsContainer.h | 97 +++++ .../include/TRKSimulation/ChipSimResponse.h | 185 ++++++++++ .../include/TRKSimulation/DigiParams.h | 134 +++++++ .../simulation/src/ChipDigitsContainer.cxx | 87 +++++ .../TRK/simulation/src/ChipSimResponse.cxx | 337 ++++++++++++++++++ .../ALICE3/TRK/simulation/src/DigiParams.cxx | 74 ++++ 12 files changed, 1352 insertions(+), 21 deletions(-) create mode 100644 Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/base/src/SegmentationChip.cxx create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipSimResponse.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DigiParams.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipDigitsContainer.cxx create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipSimResponse.cxx create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx diff --git a/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt index a237a2d12211d..96ebf4ead4b7b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt @@ -12,8 +12,10 @@ o2_add_library(TRKBase SOURCES src/GeometryTGeo.cxx src/TRKBaseParam.cxx + src/SegmentationChip.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsBase) o2_target_root_dictionary(TRKBase HEADERS include/TRKBase/GeometryTGeo.h - include/TRKBase/TRKBaseParam.h) \ No newline at end of file + include/TRKBase/TRKBaseParam.h + include/TRKBase/SegmentationChip.h) \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h new file mode 100644 index 0000000000000..4c129fedc0468 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h @@ -0,0 +1,266 @@ +// 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 SegmentationChip.h +/// \brief Definition of the SegmentationChipclass + +#ifndef ALICEO2_TRK_SEGMENTATIONCHIP_H_ +#define ALICEO2_TRK_SEGMENTATIONCHIP_H_ + +#include +#include + +#include "MathUtils/Cartesian.h" +#include "TRKBase/Specs.h" + +namespace o2::trk +{ + +/// Segmentation and response for TRK chips in ALICE3 upgrade +/// This is a work-in-progress code derived from the ITS2 and ITS3 segmentations. +class SegmentationChip +{ + // This class defines the segmenation of the TRK chips in the ALICE3 upgrade. We define + // two coordinate systems, one width x,z detector local coordianates (cm) and + // the more natural row,col layout: Also all the transformation between these + // two. The class provides the transformation from the stave/layer/disk to TGeo + // coordinates. + // For the curved VD layers there exist three coordinate systems and one is transient. + // 1. The global (curved) coordinate system. The chip's center of coordinate system is + // defined at the the mid-point of the detector. + // 2. The flat coordinate system. This is the tube segment projected onto a flat + // surface. In the projection we implicitly assume that the inner and outer + // stretch does not depend on the radius. + // 3. The detector coordinate system. Defined by the row and column segmentation + // defined at the upper edge in the flat coord. + // For the flat ML and OT layers, there exist two coordinate systems: + // 1. The global (flat) coordinate system. The chip's center of coordinate system is + // defined at the the mid-point of the detector. + // 2. The detector coordinate system. Defined by the row and column segmentation + // TODO: add segmentation for VD disks + + public: + constexpr SegmentationChip() = default; + ~SegmentationChip() = default; + constexpr SegmentationChip(const SegmentationChip&) = default; + constexpr SegmentationChip(SegmentationChip&&) = delete; + constexpr SegmentationChip& operator=(const SegmentationChip&) = default; + constexpr SegmentationChip& operator=(SegmentationChip&&) = delete; + + static constexpr float PitchColVD{constants::VD::petal::layer::pitchZ}; + static constexpr float PitchRowVD{constants::VD::petal::layer::pitchX}; + + static constexpr float PitchColML{constants::moduleMLOT::chip::pitchZ}; + static constexpr float PitchRowML{constants::moduleMLOT::chip::pitchX}; + + static constexpr float PitchColOT{constants::moduleMLOT::chip::pitchZ}; + static constexpr float PitchRowOT{constants::moduleMLOT::chip::pitchX}; + + static constexpr float SensorLayerThicknessVD = {constants::VD::petal::layer::totalThickness}; // physical thickness of sensitive part = 30 um + static constexpr float SensorLayerThicknessML = {constants::moduleMLOT::chip::totalThickness}; // physical thickness of sensitive part = 100 um + static constexpr float SensorLayerThicknessOT = {constants::moduleMLOT::chip::totalThickness}; // physical thickness of sensitive part = 100 um + + static constexpr float SiliconTickness = constants::silicon::thickness; // effective thickness of sensitive part + + static constexpr std::array radiiVD = constants::VD::petal::layer::radii; + + /// 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 + /// \param int subDetID Sub-detector ID (0 for VD, 1 for ML/OT) + /// \param int layer Layer number (0 to 2 for VD, 0 to 7 for ML/OT) + /// \param int disk Disk number (0 to 5 for VD) + static bool globalToDetector(float xRow, float zCol, int& iRow, int& iCol, int subDetID, int layer, int disk) noexcept + { + if (!isValidGlob(xRow, zCol, subDetID, layer)) { + LOGP(info, "Global coordinates not valid: row = {} cm, col = {} cm", xRow, zCol); + return false; + } + + globalToDetectorUnchecked(xRow, zCol, iRow, iCol, subDetID, layer, disk); + + if (!isValidDet(iRow, iCol, subDetID, layer)) { + iRow = iCol = -1; + LOGP(info, "Detector coordinates not valid: iRow = {}, iCol = {}", iRow, iCol); + return false; + } + return true; + }; + /// same but w/o check for row/column range + static void globalToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol, int subDetID, int layer, int disk) noexcept + { + // convert to row/col w/o over/underflow check + float pitchRow(0), pitchCol(0); + float maxWidth(0), maxLength(0); + + if (subDetID == 0) { + pitchRow = PitchRowVD; + pitchCol = PitchColVD; + maxWidth = constants::VD::petal::layer::width[layer]; + maxLength = constants::VD::petal::layer::length; + // TODO: change this to use the layer and disk + } else if (subDetID == 1 && layer <= 3) { // ML + pitchRow = PitchRowML; + pitchCol = PitchColML; + maxWidth = constants::ML::width; + maxLength = constants::ML::length; + } else if (subDetID == 1 && layer >= 4) { // OT + pitchRow = PitchRowOT; + pitchCol = PitchColOT; + maxWidth = constants::OT::width; + maxLength = constants::OT::length; + } + // convert to row/col + iRow = static_cast(std::floor((maxWidth / 2 - xRow) / pitchRow)); + iCol = static_cast(std::floor((zCol + maxLength / 2) / pitchCol)); + }; + + // Check global coordinates (cm) validity. + static constexpr bool isValidGlob(float x, float z, int subDetID, int layer) noexcept + { + float maxWidth(0), maxLength(0); + if (subDetID == 0) { + maxWidth = constants::VD::petal::layer::width[layer]; + maxLength = constants::VD::petal::layer::length; + // TODO: change this to use the layer and disk + } else if (subDetID == 1 && layer <= 3) { // ML + maxWidth = constants::ML::width; + maxLength = constants::ML::length; + } else if (subDetID == 1 && layer >= 4) { // OT + maxWidth = constants::OT::width; + maxLength = constants::OT::length; + } + return (-maxWidth / 2 < x && x < maxWidth / 2 && -maxLength / 2 < z && z < maxLength / 2); + } + + // Check detector coordinates validity. + static constexpr bool isValidDet(float row, float col, int subDetID, int layer) noexcept + { + // Check if the row and column are within the valid range + int nRows(0), nCols(0); + if (subDetID == 0) { + nRows = constants::VD::petal::layer::nRows[layer]; + nCols = constants::VD::petal::layer::nCols; + // TODO: change this to use the layer and disk + } else if (subDetID == 1 && layer <= 3) { // ML + nRows = constants::ML::nRows; + nCols = constants::ML::nCols; + } else if (subDetID == 1 && layer >= 4) { // OT + nRows = constants::OT::nRows; + nCols = constants::OT::nCols; + } + return (row >= 0 && row < static_cast(nRows) && + col >= 0 && col < static_cast(nCols)); + } + + /// Transformation from Detector cell coordinates to Geant detector centered + /// local coordinates (cm) + /// \param int iRow Detector x cell coordinate. + /// \param int iCol Detector z cell coordinate. + /// \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 volume. + /// If iRow and or iCol is outside of the segmentation range a value of -0.5*Dx() + /// or -0.5*Dz() is returned. + /// \param int subDetID Sub-detector ID (0 for VD, 1 for ML/OT) + /// \param int layer Layer number (0 to 2 for VD, 0 to 7 for ML/OT) + /// \param int disk Disk number (0 to 5 for VD) + static constexpr bool detectorToGlobal(int iRow, int iCol, float& xRow, float& zCol, int subDetID, int layer, int disk) noexcept + { + if (!isValidDet(xRow, zCol, subDetID, layer)) { + LOGP(debug, "Detector coordinates not valid: iRow = {}, iCol = {}", iRow, iCol); + return false; + } + detectorToGlobalUnchecked(iRow, iCol, xRow, zCol, subDetID, layer, disk); + + if (!isValidGlob(xRow, zCol, subDetID, layer)) { + LOGP(debug, "Global coordinates not valid: row = {} cm, col = {} cm", xRow, zCol); + return false; + } + return true; + }; + + // Same as detectorToGlobal w.o. checks. + // We position ourself in the middle of the pixel. + static void detectorToGlobalUnchecked(int& row, int& col, float xRow, float zCol, int subDetID, int layer, int disk) noexcept + { + if (subDetID == 0) { + xRow = -(row + 0.5f) * PitchRowVD + constants::VD::petal::layer::width[layer] / 2; + zCol = (col + 0.5f) * PitchColVD - constants::VD::petal::layer::length / 2; + } else if (subDetID == 1 && layer <= 3) { // ML + xRow = -(row + 0.5f) * PitchRowML + constants::ML::width / 2; + zCol = (col + 0.5f) * PitchColML - constants::ML::length / 2; + } else if (subDetID == 1 && layer >= 4) { // OT + xRow = -(row + 0.5f) * PitchRowOT + constants::OT::width / 2; + zCol = (col + 0.5f) * PitchColOT - constants::OT::length / 2; + } + } + + /// Transformation from the curved surface to a flat surface. + /// Additionally a shift in the flat coordinates must be applied because + /// the center of the TGeoShap when projected will be higher than the + /// physical thickness of the chip. Thus we shift the projected center + /// down by this difference to align the coordinate systems. + /// \param layer VD layer number + /// \param xCurved Detector local curved coordinate x in cm with respect to + /// the center of the sensitive volume. + /// \param yCurved Detector local curved coordinate y in cm with respect to + /// the center of the sensitive volume. + /// \return math_utils::Vector2D: x and y represent the detector local flat coordinates x and y + // in cm with respect to the center of the sensitive volume. + + static math_utils::Vector2D curvedToFlat(const int layer, const float xCurved, const float yCurved) noexcept + { + // Align the flat surface with the curved survace of the original chip (and account for metal stack, TODO) + float dist = std::hypot(xCurved, yCurved); + float phi = std::atan2(yCurved, xCurved); + + // the y position is in the silicon volume however we need the chip volume (silicon+metalstack) + // this is accounted by a y shift + float xFlat = -constants::VD::petal::layer::radii[layer] * phi; /// this is equal to the circumference segment covered between y=0 and the phi angle + float yFlat = dist - constants::VD::petal::layer::radii[layer]; + return math_utils::Vector2D(xFlat, yFlat); + } + + /// Transformation from the flat surface to a curved surface + /// It works only if the detector is not rototraslated. + /// \param layer VD layer number + /// \param xFlat Detector local flat coordinate x in cm with respect to + /// the center of the sensitive volume. + /// \param yFlat Detector local flat coordinate y in cm with respect to + /// the center of the sensitive volume. + /// \return math_utils::Vector2D: x and y represent the detector local curved coordinates x and y + // in cm with respect to the center of the sensitive volume. + static constexpr math_utils::Vector2D flatToCurved(int layer, float xFlat, float yFlat) noexcept + { + // Revert the curvedToFlat transformation + float dist = yFlat + constants::VD::petal::layer::radii[layer]; + float phi = -xFlat / constants::VD::petal::layer::radii[layer]; + // the y position is in the chip volume however we need the silicon volume + // this is accounted by a -y shift + float xCurved = dist * std::cos(phi); + float yCurved = dist * std::sin(phi); + return math_utils::Vector2D(xCurved, yCurved); + } +}; + +} // namespace o2::trk + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h new file mode 100644 index 0000000000000..e80c965ffe4d0 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h @@ -0,0 +1,114 @@ +// 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 Specs.h +/// \brief specs of the ALICE3 TRK + +#ifndef O2_ALICE_TRK_SPECS +#define O2_ALICE_TRK_SPECS + +#include +#include +// This is a temporary version with the specs for the ALICE3 TRK +// This files defines the design specifications of the chips for VD, ML, OT. +// Each TGeoShape has the following properties +// length: dimension in z-axis +// width: dimension in xy-axes +// color: for visulisation +namespace o2::trk::constants +{ +// Default unit of TGeo = cm +constexpr double cm{1}; +constexpr double mu{1e-4}; +constexpr double mm{1e-1}; + +// namespace metalstack /// still to be defined +// { +// constexpr double thickness{5 * mu}; // physical thickness of the copper metal stack +// } + +namespace VD // TODO: add a primitive segmentation with more granularity wrt 1/4 layer = 1 chip +{ +namespace petal +{ +constexpr int nLayers{3}; // number of layers in each VD petal +constexpr int nDisks{6}; // number of disks in each VD petal +namespace layer +{ +constexpr double pitchX{10 * mu}; // pitch of the row +constexpr double pitchZ{10 * mu}; // pitch of the column +constexpr double totalThickness{30 * mu}; // total thickness of the chip +constexpr std::array radii{0.5 * cm, 1.2 * cm, 2.5 * cm}; // width of the quarter of layer in cm +constexpr std::array width{radii[0] * 2 * M_PI / 4, radii[1] * 2 * M_PI / 4, radii[2] * 2 * M_PI / 4}; // width of the quarter of layer in cm +constexpr double length{50 * cm}; // length of the layer +constexpr int nCols{static_cast(length / pitchZ)}; // number of columns in the chip +constexpr std::array nRows{static_cast(width[0] / pitchX), static_cast(width[1] / pitchX), static_cast(width[2] / pitchX)}; // number of rows in the chip + +} // namespace layer +namespace disk +{ //// TODO: to be filled +constexpr double radiusIn{0.5 * cm}; +constexpr double radiusOut{2.5 * cm}; +} // namespace disk +} // namespace petal +} // namespace VD + +namespace moduleMLOT /// same for ML and OT for the moment +{ /// TODO: account for different modules in case of change +namespace chip +{ +constexpr double width{25 * mm}; // width of the chip +constexpr double length{32 * mm}; // length of the chip +constexpr double pitchX{50 * mu}; // pitch of the row +constexpr double pitchZ{50 * mu}; // pitch of the column +constexpr int nRows{static_cast(width / pitchX)}; // number of columns in the chip +constexpr int nCold{static_cast(length / pitchZ)}; // number of rows in the chipù +constexpr double totalThickness{100 * mu}; // total thickness of the chip +/// Set to 0 for the moment, to be adjusted with the actual design of the chip if needed +static constexpr float PassiveEdgeReadOut = 0.f; // width of the readout edge (Passive bottom) +static constexpr float PassiveEdgeTop = 0.f; // Passive area on top +static constexpr float PassiveEdgeSide = 0.f; // width of Passive area on left/right of the sensor +} // namespace chip +namespace gaps +{ +constexpr double interChips{0.2 * mm}; // gap between the chips +constexpr double outerEdgeLongSide{1 * mm}; // gap between the chips and the outer edges (long side) +constexpr double outerEdgeShortSide{0.1 * mm}; // gap between the chips and the outer edges (short side) +} // namespace gaps +constexpr double width{chip::width * 2 + gaps::interChips + 2 * gaps::outerEdgeLongSide}; // width of the module +constexpr double length{chip::length * 4 + 3 * gaps::interChips + 2 * gaps::outerEdgeShortSide}; // length of the module +constexpr int nRows{static_cast(width / chip::pitchX)}; // number of columns in the module +constexpr int nCold{static_cast(length / chip::pitchZ)}; // number of rows in the module +} // namespace moduleMLOT + +namespace ML +{ +constexpr double width{constants::moduleMLOT::width * 1}; // width of the stave +constexpr double length{constants::moduleMLOT::length * 10}; // length of the stave +constexpr int nRows{static_cast(width / constants::moduleMLOT::chip::pitchX)}; // number of rows in the stave +constexpr int nCols{static_cast(length / constants::moduleMLOT::chip::pitchZ)}; // number of columns in the stave +} // namespace ML + +namespace OT +{ +constexpr double width{moduleMLOT::width * 2}; // width of the stave +constexpr double length{moduleMLOT::length * 20}; // length of the stave +constexpr int nRows{static_cast(width / moduleMLOT::chip::pitchX)}; // number of rows in the stave +constexpr int nCols{static_cast(length / moduleMLOT::chip::pitchZ)}; // number of columns in the stave +} // namespace OT + +namespace silicon +{ +constexpr double thickness{10 * mu}; // thickness of active material +} // namespace silicon +} // namespace o2::trk::constants + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index ee473509877e1..0052c95cbd92c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -11,9 +11,9 @@ #include #include -// #include "TRKBase/SegmentationChip.h" +#include "TRKBase/SegmentationChip.h" -// using Segmentation = o2::trk::SegmentationChip; +using Segmentation = o2::trk::SegmentationChip; namespace o2 { @@ -302,40 +302,40 @@ TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const // Note, the if the effective sensitive layer thickness is smaller than the // total physical sensor tickness, this matrix is biased and connot be used // directly for transformation from sensor frame to global one. - // // Therefore we need to add a shift + auto path = getMatrixPath(index); static TGeoHMatrix matTmp; - // gGeoManager->PushPath(); // Preserve the modeler state. + gGeoManager->PushPath(); // Preserve the modeler state. - // if (!gGeoManager->cd(path.Data())) { - // gGeoManager->PopPath(); - // LOG(error) << "Error in cd-ing to " << path.Data(); - // return nullptr; - // } // end if !gGeoManager + if (!gGeoManager->cd(path.Data())) { + gGeoManager->PopPath(); + LOG(error) << "Error in cd-ing to " << path.Data(); + return nullptr; + } // end if !gGeoManager matTmp = *gGeoManager->GetCurrentMatrix(); // matrix may change after cd // RSS - // printf("%d/%d/%d %s\n", lay, stav, detInSta, path.Data()); // matTmp.Print(); // Restore the modeler state. gGeoManager->PopPath(); static int chipInGlo{0}; + /// TODO: // account for the difference between physical sensitive layer (where charge collection is simulated) and effective sensor thicknesses - // in the ITS3 case this accounted by specialized functions - // double delta = Segmentation::SensorLayerThickness; - // static TGeoTranslation tra(0., 0.5 * delta, 0.); - // #ifdef ENABLE_UPGRADES // only apply for non ITS3 OB layers - // if (!mIsLayerITS3[getLayer(index)]) { - // matTmp *= tra; - // } - // #else + // in the VD case this will be accounted by specialized functions during the clusterization (following what it is done for ITS3) + // this can be done once the right sensor thickness is in place in the geometry + // double delta = 0.; + // if (getSubDetID(index) == 1){ /// ML/OT + // delta = Segmentation::SensorLayerThicknessVD - Segmentation::SiliconTickness; + // static TGeoTranslation tra(0., 0.5 * delta, 0.); // matTmp *= tra; - // #endif + // } + // std::cout<<"-----"< + +using namespace o2::trk; + +// void SegmentationChip::print() +// { +// printf("++++++++++ VD ++++++++++"); +// printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", PitchRowVD * 1e4, -999, PitchColVD * 1e4, NColsVD); +// printf("++++++++++ ML ++++++++++"); +// printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", PitchRowML * 1e4, -999, PitchColML * 1e4, NColsML); + +// } \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt index a1cb0279efef8..dad0c9b8a970b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt @@ -11,7 +11,10 @@ o2_add_library(TRKSimulation SOURCES src/TRKLayer.cxx + src/ChipDigitsContainer.cxx + src/ChipSimResponse.cxx src/Detector.cxx + src/DigiParams.cxx src/Digitizer.cxx src/TRKServices.cxx src/DPLDigitizerParam.cxx @@ -24,7 +27,10 @@ o2_add_library(TRKSimulation O2::SimulationDataFormat) o2_target_root_dictionary(TRKSimulation - HEADERS include/TRKSimulation/Digitizer.h + HEADERS include/TRKSimulation/ChipDigitsContainer.h + include/TRKSimulation/ChipSimResponse.h + include/TRKSimulation/DigiParams.h + include/TRKSimulation/Digitizer.h include/TRKSimulation/Detector.h include/TRKSimulation/TRKLayer.h include/TRKSimulation/TRKServices.h diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h new file mode 100644 index 0000000000000..760da766be701 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h @@ -0,0 +1,97 @@ +// 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 ChipDigitsContainer.h +/// \brief transient container for single chip digits accumulation. Using ITSMFT digits definition. +// + +#ifndef ALICEO2_ITSMFT_CHIPDIGITSCONTAINER_ +#define ALICEO2_ITSMFT_CHIPDIGITSCONTAINER_ + +#include "SimulationDataFormat/MCCompLabel.h" +#include "TRKBase/SegmentationChip.h" +#include "ITSMFTSimulation/PreDigit.h" +#include "DataFormatsITSMFT/NoiseMap.h" +#include +#include + +namespace o2 +{ +namespace trk +{ +class DigiParams; + +/// @class ChipDigitsContainer +/// @brief Container for simulated points connected to a given chip. Using ITSMFT digits definition + +class ChipDigitsContainer +{ + public: + /// Default constructor + ChipDigitsContainer(UShort_t idx = 0) : mChipIndex(idx) {}; + + /// Destructor + ~ChipDigitsContainer() = default; + + std::map& getPreDigits() { return mDigits; } + bool isEmpty() const { return mDigits.empty(); } + void setNoiseMap(const o2::itsmft::NoiseMap* mp) { mNoiseMap = mp; } + void setDeadChanMap(const o2::itsmft::NoiseMap* mp) { mDeadChanMap = mp; } + void setChipIndex(UShort_t ind) { mChipIndex = ind; } + UShort_t getChipIndex() const { return mChipIndex; } + + o2::itsmft::PreDigit* findDigit(ULong64_t key); + void addDigit(ULong64_t key, UInt_t roframe, UShort_t row, UShort_t col, int charge, o2::MCCompLabel lbl); + // void addNoiseVD(UInt_t rofMin, UInt_t rofMax, const o2::trk::DigiParams* params, int maxRows = o2::trk::SegmentationChip::NColsVD, int maxCols = o2::trk::SegmentationChip::NColsVD); + // void addNoiseML(UInt_t rofMin, UInt_t rofMax, const o2::trk::DigiParams* params, int maxRows = o2::trk::SegmentationChip::NColsML, int maxCols = o2::trk::SegmentationChip::NColsML); + + /// Get global ordering key made of readout frame, column and row + static ULong64_t getOrderingKey(UInt_t roframe, UShort_t row, UShort_t col) + { + return (static_cast(roframe) << (8 * sizeof(UInt_t))) + (col << (8 * sizeof(Short_t))) + row; + } + + /// Get ROFrame from the ordering key + static UInt_t key2ROFrame(ULong64_t key) + { + return static_cast(key >> (8 * sizeof(UInt_t))); + } + + bool isDisabled() const { return mDisabled; } + void disable(bool v) { mDisabled = v; } + + protected: + UShort_t mChipIndex = 0; ///< chip index + bool mDisabled = false; + const o2::itsmft::NoiseMap* mNoiseMap = nullptr; + const o2::itsmft::NoiseMap* mDeadChanMap = nullptr; + std::map mDigits; ///< Map of fired pixels, possibly in multiple frames +}; + +//_______________________________________________________________________ +inline o2::itsmft::PreDigit* ChipDigitsContainer::findDigit(ULong64_t key) +{ + // finds the digit corresponding to global key + auto digitentry = mDigits.find(key); + return digitentry != mDigits.end() ? &(digitentry->second) : nullptr; +} + +//_______________________________________________________________________ +inline void ChipDigitsContainer::addDigit(ULong64_t key, UInt_t roframe, UShort_t row, UShort_t col, + int charge, o2::MCCompLabel lbl) +{ + mDigits.emplace(std::make_pair(key, o2::itsmft::PreDigit(roframe, row, col, charge, lbl))); +} +} // namespace trk +} // namespace o2 + +#endif /* defined(ALICEO2_ITSMFT_CHIPCONTAINER_) */ \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipSimResponse.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipSimResponse.h new file mode 100644 index 0000000000000..2cf3b3f310775 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipSimResponse.h @@ -0,0 +1,185 @@ +// 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 ChipSimResponse.h +/// \brief Definition of the TRK chip simulated response parametrization + +#ifndef ALICEO2_TRK_CHIPSIMRESPONSE_H +#define ALICEO2_TRK_CHIPSIMRESPONSE_H + +#include +#include +#include +#include + +#include "TRKBase/SegmentationChip.h" + +namespace o2 +{ +namespace trk +{ +/* + * ChipRespSimMat : class to access the response: probability to collect electron + * in MNPix*MNPix cells. + */ +class ChipRespSimMat +{ + public: + static int constexpr NPix = 5; /// side of quadrant (pixels) with non-0 response + static int constexpr MatSize = NPix * NPix; /// number of pixels in the quadrant + static int constexpr getNPix() { return NPix; } + + ChipRespSimMat() = default; + ~ChipRespSimMat() = default; + + void adopt(const ChipRespSimMat& src, bool flipRow = false, bool flipCol = false) + { + // copy constructor with option of channels flipping + for (int iRow = NPix; iRow--;) { + int rw = flipRow ? NPix - 1 - iRow : iRow; + for (int iCol = NPix; iCol--;) { + int bDest = rw * NPix + (flipCol ? NPix - 1 - iCol : iCol); + data[bDest] = src.data[iRow * NPix + iCol]; + } + } + } + + /// probability to find an electron in pixel ix,iy,iz + float getValue(int iRow, int iCol) const { return data[iRow * NPix + iCol]; } + float getValue(int iRow, int iCol, bool flipRow, bool flipCol) const + { + int bin = (flipRow ? NPix - 1 - iRow : iRow) * NPix + (flipCol ? NPix - 1 - iCol : iCol); + return data[bin]; + } + + /// pointer on underlying array + std::array* getArray() { return &data; } + + /// print values + void print(bool flipRow = false, bool flipCol = false) const; + + private: + std::array data; + + // ClassDefNV(ChipRespSimMat, 1); +}; + +/* + * ChipSimResponse: container for Chip simulates parameterized response matrices + * Based on the ITS2 and ITS3 sim response code. + * Provides for the electron injected to point X(columns direction),Y (rows direction) + * (with respect to pixel center) and Z (depth, with respect to epitaxial layer inner + * serface!!! i.e. touching the substrate) the probability to be collected in every + * of NPix*NPix pixels with reference pixel in the center. + */ + +class ChipSimResponse +{ + + private: + int getColBin(float pos) const; + int getRowBin(float pos) const; + int getDepthBin(float pos) const; + std::string composeDataName(int colBin, int rowBin); + + int mNBinCol = 0; /// number of bins in X(col direction) + int mNBinRow = 0; /// number of bins in Y(row direction) + int mNBinDpt = 0; /// number of bins in Z(sensor dept) + int mMaxBinCol = 0; /// max allowed Xb (to avoid subtraction) + int mMaxBinRow = 0; /// max allowed Yb (to avoid subtraction) + float mColMaxVD = SegmentationChip::PitchColVD / 2.f; /// upper boundary of Col in the VD + float mRowMaxVD = SegmentationChip::PitchRowVD / 2.f; /// upper boundary of Row in the VD + float mColMaxML = SegmentationChip::PitchColML / 2.f; /// upper boundary of Col in the ML + float mRowMaxML = SegmentationChip::PitchRowML / 2.f; /// upper boundary of Row in the ML + float mColMaxOT = SegmentationChip::PitchColOT / 2.f; /// upper boundary of Col in the OT + float mRowMaxOT = SegmentationChip::PitchRowOT / 2.f; /// upper boundary of Row in the OT + float mDptMin = 0.f; /// lower boundary of Dpt + float mDptMax = 0.f; /// upper boundary of Dpt + float mDptShift = 0.f; /// shift of the depth center wrt 0 + float mStepInvCol = 0; /// inverse step of the Col grid + float mStepInvRow = 0; /// inverse step of the Row grid + float mStepInvDpt = 0; /// inverse step of the Dpt grid + std::vector mData; /// response data + /// path to look for data file + std::string mDataPath; + std::string mGridColName = "grid_list_x.txt"; /// name of the file with grid in Col + std::string mGridRowName = "grid_list_y.txt"; /// name of the file with grid in Row + std::string mColRowDataFmt = "data_pixels_%.2f_%.2f.txt"; /// format to read the data for given Col,Row + + public: + ChipSimResponse() = default; + virtual ~ChipSimResponse() = default; + + void initData(int tableNumber, std::string dataPath, const bool quiet = true); + + bool getResponse(float vRow, float vCol, float cDepth, ChipRespSimMat& dest, const int nLayer) const; + const ChipRespSimMat* getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, const int subDetID, const int nLayer) const; + const ChipRespSimMat* getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, float rowMax, float colMax) const; + static int constexpr getNPix() { return ChipRespSimMat::getNPix(); } + int getNBinCol() const { return mNBinCol; } + int getNBinRow() const { return mNBinRow; } + int getNBinDepth() const { return mNBinDpt; } + float getColMaxVD() const { return mColMaxVD; } + float getRowMaxVD() const { return mRowMaxVD; } + float getColMaxML() const { return mColMaxML; } + float getRowMaxML() const { return mRowMaxML; } + float getDepthMin() const { return mDptMin; } + float getDepthMax() const { return mDptMax; } + float getDepthShift() const { return mDptShift; } + float getStepCol() const { return mStepInvCol ? 1. / mStepInvCol : 0.f; } + float getStepRow() const { return mStepInvRow ? 1. / mStepInvRow : 0.f; } + float getStepDepth() const { return mStepInvDpt ? 1. / mStepInvDpt : 0.f; } + void setColMaxVD(float v) noexcept { mColMaxVD = v; } + void setRowMaxVD(float v) noexcept { mRowMaxVD = v; } + void setColMaxML(float v) noexcept { mColMaxML = v; } + void setRowMaxML(float v) noexcept { mRowMaxML = v; } + void setDataPath(const std::string pth) { mDataPath = pth; } + void setGridColName(const std::string nm) { mGridColName = nm; } + void setGridRowName(const std::string nm) { mGridRowName = nm; } + void setColRowDataFmt(const std::string nm) { mColRowDataFmt = nm; } + const std::string& getDataPath() const { return mDataPath; } + const std::string& getGridColName() const { return mGridColName; } + const std::string& getGridRowName() const { return mGridRowName; } + const std::string& getColRowDataFmt() const { return mColRowDataFmt; } + void print() const; + + // ClassDefNV(ChipSimResponse, 2); +}; + +//----------------------------------------------------- +inline int ChipSimResponse::getColBin(float pos) const +{ + /// get column bin w/o checking for over/under flow. pos MUST be >=0 + int i = pos * mStepInvCol + 0.5f; + return i < mNBinCol ? i : mMaxBinCol; +} + +//----------------------------------------------------- +inline int ChipSimResponse::getRowBin(float pos) const +{ + // get row bin w/o checking for over/under flow. pos MUST be >=0 + int i = pos * mStepInvRow + 0.5f; + return i < mNBinRow ? i : mMaxBinRow; +} + +//----------------------------------------------------- +inline int ChipSimResponse::getDepthBin(float pos) const +{ + // get depth bin w/o checking for over/under flow. pos is with respect of the beginning + // of epitaxial layer + int i = (mDptMax - pos) * mStepInvDpt; + return i < 0 ? 0 : i; // depth bin +} + +} // namespace trk +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DigiParams.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DigiParams.h new file mode 100644 index 0000000000000..fbe5cb9d9359c --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DigiParams.h @@ -0,0 +1,134 @@ +// 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 DigiParams.h +/// \brief Simulation parameters for the TRK digitizer. Based on the ITS2 and ITS3 digitizer parameters + +#ifndef ALICEO2_TRK_DIGIPARAMS_H +#define ALICEO2_TRK_DIGIPARAMS_H + +#include +#include +#include "TRKBase/TRKBaseParam.h" +#include "TRKBase/GeometryTGeo.h" + +//////////////////////////////////////////////////////////// +// // +// Simulation params for the TRK digitizer // +// // +// This is a provisionary implementation, until proper // +// microscopic simulation and its configuration will // +// be implemented // +// // +//////////////////////////////////////////////////////////// + +namespace o2 +{ +namespace trk +{ + +class ChipSimResponse; + +class DigiParams +{ + + using SignalShape = o2::itsmft::AlpideSignalTrapezoid; + + public: + DigiParams(); + ~DigiParams() = default; + + void setNoisePerPixel(float v) { mNoisePerPixel = v; } + float getNoisePerPixel() const { return mNoisePerPixel; } + + void setContinuous(bool v) { mIsContinuous = v; } + bool isContinuous() const { return mIsContinuous; } + + int getROFrameLengthInBC() const { return mROFrameLengthInBC; } + void setROFrameLengthInBC(int n) { mROFrameLengthInBC = n; } + + void setROFrameLength(float ns); + float getROFrameLength() const { return mROFrameLength; } + float getROFrameLengthInv() const { return mROFrameLengthInv; } + + void setStrobeDelay(float ns) { mStrobeDelay = ns; } + float getStrobeDelay() const { return mStrobeDelay; } + + void setStrobeLength(float ns) { mStrobeLength = ns; } + float getStrobeLength() const { return mStrobeLength; } + + void setTimeOffset(double sec) { mTimeOffset = sec; } + double getTimeOffset() const { return mTimeOffset; } + + void setROFrameBiasInBC(int n) { mROFrameBiasInBC = n; } + int getROFrameBiasInBC() const { return mROFrameBiasInBC; } + + void setChargeThreshold(int v, float frac2Account = 0.1); + void setNSimSteps(int v); + void setEnergyToNElectrons(float v) { mEnergyToNElectrons = v; } + + void setVbb(float v) { mVbb = v; } + void setIBVbb(float v) { mIBVbb = v; } + void setOBVbb(float v) { mOBVbb = v; } + + int getChargeThreshold() const { return mChargeThreshold; } + int getMinChargeToAccount() const { return mMinChargeToAccount; } + int getNSimSteps() const { return mNSimSteps; } + float getNSimStepsInv() const { return mNSimStepsInv; } + float getEnergyToNElectrons() const { return mEnergyToNElectrons; } + + float getVbb() const { return mVbb; } + float getIBVbb() const { return mIBVbb; } + float getOBVbb() const { return mOBVbb; } + + bool isTimeOffsetSet() const { return mTimeOffset > -infTime; } + + const o2::trk::ChipSimResponse* getAlpSimResponse() const { return mAlpSimResponse; } + void setAlpSimResponse(const o2::trk::ChipSimResponse* par) { mAlpSimResponse = par; } + + const SignalShape& getSignalShape() const { return mSignalShape; } + SignalShape& getSignalShape() { return (SignalShape&)mSignalShape; } + + virtual void print() const; + + private: + static constexpr double infTime = 1e99; + bool mIsContinuous = false; ///< flag for continuous simulation + float mNoisePerPixel = 1.e-8; ///< ALPIDE Noise per chip + int mROFrameLengthInBC = 0; ///< ROF length in BC for continuos mode + float mROFrameLength = 0; ///< length of RO frame in ns + float mStrobeDelay = 0.; ///< strobe start (in ns) wrt ROF start + float mStrobeLength = 0; ///< length of the strobe in ns (sig. over threshold checked in this window only) + double mTimeOffset = -2 * infTime; ///< time offset (in seconds!) to calculate ROFrame from hit time + int mROFrameBiasInBC = 0; ///< misalignment of the ROF start in BC + int mChargeThreshold = 150; ///< charge threshold in Nelectrons + int mMinChargeToAccount = 15; ///< minimum charge contribution to account + int mNSimSteps = 7; ///< number of steps in response simulation + float mEnergyToNElectrons = 1. / 3.6e-9; // conversion of eloss to Nelectrons + + float mVbb = 0.0; ///< back bias absolute value for MFT (in Volt) + float mIBVbb = 0.0; ///< back bias absolute value for ITS Inner Barrel (in Volt) + float mOBVbb = 0.0; ///< back bias absolute value for ITS Outter Barrel (in Volt) + + o2::itsmft::AlpideSignalTrapezoid mSignalShape; ///< signal timeshape parameterization + + const o2::trk::ChipSimResponse* mAlpSimResponse = nullptr; //!< pointer on external response + + // auxiliary precalculated parameters + float mROFrameLengthInv = 0; ///< inverse length of RO frame in ns + float mNSimStepsInv = 0; ///< its inverse + + // ClassDef(DigiParams, 2); +}; +} // namespace trk +} // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipDigitsContainer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipDigitsContainer.cxx new file mode 100644 index 0000000000000..b24b61da2b503 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipDigitsContainer.cxx @@ -0,0 +1,87 @@ +// 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. + +// +// ChipDigitsContainer.cpp +// ALICEO2 +// + +#include "TRKSimulation/ChipDigitsContainer.h" +#include "TRKSimulation/DigiParams.h" +#include + +using namespace o2::trk; +using Segmentation = o2::trk::SegmentationChip; + +//// TODO: add noise + +//______________________________________________________________________ +// void ChipDigitsContainer::addNoiseVD(UInt_t rofMin, UInt_t rofMax, const o2::trk::DigiParams* params, int maxRows, int maxCols) +// { +// UInt_t row = 0; +// UInt_t col = 0; +// Int_t nhits = 0; +// constexpr float ns2sec = 1e-9; + + +// float mean = params->getNoisePerPixel() * Segmentation::NPixels; +// int nel = params->getChargeThreshold() * 1.1; // RS: TODO: need realistic spectrum of noise above the threshold + +// for (UInt_t rof = rofMin; rof <= rofMax; rof++) { +// nhits = gRandom->Poisson(mean); +// for (Int_t i = 0; i < nhits; ++i) { +// row = gRandom->Integer(maxRows); +// col = gRandom->Integer(maxCols); +// if (mNoiseMap && mNoiseMap->isNoisy(mChipIndex, row, col)) { +// continue; +// } +// if (mDeadChanMap && mDeadChanMap->isNoisy(mChipIndex, row, col)) { +// continue; +// } +// // RS TODO: why the noise was added with 0 charge? It should be above the threshold! +// auto key = getOrderingKey(rof, row, col); +// if (!findDigit(key)) { +// addDigit(key, rof, row, col, nel, o2::MCCompLabel(true)); +// } +// } +// } +// } + +// void ChipDigitsContainer::addNoiseML(UInt_t rofMin, UInt_t rofMax, const o2::trk::DigiParams* params, int maxRows, int maxCols) +// { +// UInt_t row = 0; +// UInt_t col = 0; +// Int_t nhits = 0; +// constexpr float ns2sec = 1e-9; + + //// TODO: add noise +// float mean = params->getNoisePerPixel() * Segmentation::NPixels; +// int nel = params->getChargeThreshold() * 1.1; // RS: TODO: need realistic spectrum of noise above the threshold + +// for (UInt_t rof = rofMin; rof <= rofMax; rof++) { +// nhits = gRandom->Poisson(mean); +// for (Int_t i = 0; i < nhits; ++i) { +// row = gRandom->Integer(maxRows); +// col = gRandom->Integer(maxCols); +// if (mNoiseMap && mNoiseMap->isNoisy(mChipIndex, row, col)) { +// continue; +// } +// if (mDeadChanMap && mDeadChanMap->isNoisy(mChipIndex, row, col)) { +// continue; +// } +// // RS TODO: why the noise was added with 0 charge? It should be above the threshold! +// auto key = getOrderingKey(rof, row, col); +// if (!findDigit(key)) { +// addDigit(key, rof, row, col, nel, o2::MCCompLabel(true)); +// } +// } +// } +// } diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipSimResponse.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipSimResponse.cxx new file mode 100644 index 0000000000000..177d26088bda4 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipSimResponse.cxx @@ -0,0 +1,337 @@ +// 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 ChipSimResponse.cxx +/// \brief Definition of the TRK chip simulated response parametrization. Based on ITS2 and ITS3 codes. + +#include "TRKSimulation/ChipSimResponse.h" +#include "TRKSimulation/DPLDigitizerParam.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace o2::trk; +using namespace std; + +constexpr float micron2cm = 1e-4; + +void ChipSimResponse::initData(int tableNumber, std::string dataPath, const bool quiet) +{ + /* + * read grid parameters and load data + */ + if (tableNumber == 0) // 0V back bias + { + const std::string newDataPath = dataPath + "Vbb-0.0V"; + setDataPath(newDataPath); // setting the new data path + } else if (tableNumber == 1) // -3V back bias + { + const std::string newDataPath = dataPath + "Vbb-3.0V"; + setDataPath(newDataPath); // setting the new data path + } + + if (mData.size()) { + cout << "Object already initialized" << endl; + print(); + return; + } + + const float kTiny = 1e-6; // to check 0 values + + // if needed, append path with slash + if (mDataPath.length() && mDataPath.back() != '/') { + mDataPath.push_back('/'); + } + mDataPath = gSystem->ExpandPathName(mDataPath.data()); + string inpfname = mDataPath + mGridColName; + std::ifstream inpGrid; + + // read X grid + inpGrid.open(inpfname, std::ifstream::in); + if (inpGrid.fail()) { + LOG(fatal) << "Failed to open file " << inpfname; + } + + while (inpGrid >> mStepInvCol && inpGrid.good()) { + mNBinCol++; + } + + if (!mNBinCol || mStepInvCol < kTiny) { + LOG(fatal) << "Failed to read X(col) binning from " << inpfname; + } + mMaxBinCol = mNBinCol - 1; + mStepInvCol = mMaxBinCol / mStepInvCol; // inverse of the X bin width + inpGrid.close(); + + // read Y grid + inpfname = mDataPath + mGridRowName; + inpGrid.open(inpfname, std::ifstream::in); + if (inpGrid.fail()) { + LOG(fatal) << "Failed to open file " << inpfname; + } + + while (inpGrid >> mStepInvRow && inpGrid.good()) { + mNBinRow++; + } + if (!mNBinRow || mStepInvRow < kTiny) { + LOG(fatal) << "Failed to read Y(row) binning from " << inpfname; + } + mMaxBinRow = mNBinRow - 1; + mStepInvRow = mMaxBinRow / mStepInvRow; // inverse of the Row bin width + inpGrid.close(); + + // load response data + int nz = 0; + size_t cnt = 0; + float val, gx, gy, gz; + int lost, untrck, dead, nele; + size_t dataSize = 0; + mDptMax = -2.e9; + mDptMin = 2.e9; + const int npix = ChipRespSimMat::getNPix(); + + for (int ix = 0; ix < mNBinCol; ix++) { + for (int iy = 0; iy < mNBinRow; iy++) { + inpfname = composeDataName(ix, iy); + inpGrid.open(inpfname, std::ifstream::in); + if (inpGrid.fail()) { + LOG(fatal) << "Failed to open file " << inpfname; + } + inpGrid >> nz; + if (cnt == 0) { + mNBinDpt = nz; + dataSize = mNBinCol * mNBinRow * mNBinDpt; + mData.reserve(dataSize); // reserve space for data + } else if (nz != mNBinDpt) { + LOG(fatal) << "Mismatch in Nz slices of bin X(col): " << ix << " Y(row): " << iy + << " wrt bin 0,0. File " << inpfname; + } + + // load data + for (int iz = 0; iz < nz; iz++) { + ChipRespSimMat mat; + + std::array* arr = mat.getArray(); + for (int ip = 0; ip < npix * npix; ip++) { + inpGrid >> val; + (*arr)[ip] = val; + cnt++; + } + inpGrid >> lost >> dead >> untrck >> nele >> gx >> gy >> gz; + + if (inpGrid.bad()) { + LOG(fatal) << "Failed reading data for depth(Z) slice " << iz << " from " + << inpfname; + } + if (!nele) { + LOG(fatal) << "Wrong normalization Nele=" << nele << "for depth(Z) slice " + << iz << " from " << inpfname; + } + + if (mDptMax < -1e9) { + mDptMax = gz; + } + if (mDptMin > gz) { + mDptMin = gz; + } + + // normalize + float norm = 1.f / nele; + for (int ip = npix * npix; ip--;) { + (*arr)[ip] *= norm; + } + mData.push_back(mat); // store in the final container + } // loop over z + + inpGrid.close(); + + } // loop over y + } // loop over x + + // final check + if (dataSize != mData.size()) { + LOG(fatal) << "Mismatch between expected " << dataSize << " and loaded " << mData.size() + << " number of bins"; + } + + // normalize Dpt boundaries + + mStepInvCol /= micron2cm; + mStepInvRow /= micron2cm; + + mDptMin *= micron2cm; + mDptMax *= micron2cm; + mStepInvDpt = (mNBinDpt - 1) / (mDptMax - mDptMin); + mDptMin -= 0.5 / mStepInvDpt; + mDptMax += 0.5 / mStepInvDpt; + mDptShift = 0.5 * (mDptMax + mDptMin); + if (!quiet) { + print(); + } +} + +//----------------------------------------------------- +void ChipSimResponse::print() const +{ + /* + * print itself + */ + printf("Chip response object of %zu matrices to map chagre in xyz to %dx%d pixels\n", + mData.size(), getNPix(), getNPix()); + printf("VD X(col) range: %+e : %+e | step: %e | Nbins: %d\n", 0.f, mColMaxVD, 1.f / mStepInvCol, mNBinCol); + printf("ML X(col) range: %+e : %+e | step: %e | Nbins: %d\n", 0.f, mColMaxML, 1.f / mStepInvCol, mNBinCol); + printf("VD Y(row) range: %+e : %+e | step: %e | Nbins: %d\n", 0.f, mRowMaxVD, 1.f / mStepInvRow, mNBinRow); + printf("ML Y(row) range: %+e : %+e | step: %e | Nbins: %d\n", 0.f, mRowMaxML, 1.f / mStepInvRow, mNBinRow); + printf("Z(dpt) range: %+e : %+e | step: %e | Nbins: %d\n", mDptMin, mDptMax, 1.f / mStepInvDpt, mNBinDpt); +} + +//----------------------------------------------------- +string ChipSimResponse::composeDataName(int colBin, int rowBin) +{ + /* + * compose the file-name to read data for bin colBin,rowBin + */ + + // ugly but safe way to compose the file name + float vcol = colBin / mStepInvCol, vrow = rowBin / mStepInvRow; + size_t size = snprintf(nullptr, 0, mColRowDataFmt.data(), vcol, vrow) + 1; + unique_ptr tmp(new char[size]); + snprintf(tmp.get(), size, mColRowDataFmt.data(), vcol, vrow); + return mDataPath + string(tmp.get(), tmp.get() + size - 1); +} + +//____________________________________________________________ +bool ChipSimResponse::getResponse(float vRow, float vCol, float vDepth, ChipRespSimMat& dest, const int layer) const +{ + /* + * get linearized NPix*NPix matrix for response at point vRow(sensor local X, along row) + * vCol(sensor local Z, along columns) and vDepth (sensor local Y, i.e. depth) + */ + if (!mNBinDpt) { + LOG(fatal) << "response object is not initialized"; + } + bool flipCol = false, flipRow = true; + if (vDepth < mDptMin || vDepth > mDptMax) { + return false; + } + if (vCol < 0) { + vCol = -vCol; + flipCol = true; + } + if (vRow < 0) { + vRow = -vRow; + flipRow = false; + } + if (layer < 3) { + if (vCol > mColMaxVD) { + return false; + } + if (vRow > mRowMaxVD) { + return false; + } + } else { + if (vCol > mColMaxML) { + return false; + } + if (vRow > mRowMaxML) { + return false; + } + } + + size_t bin = getDepthBin(vDepth) + mNBinDpt * (getRowBin(vRow) + mNBinRow * getColBin(vCol)); + if (bin >= mData.size()) { + // this should not happen + LOG(fatal) << "requested bin " << bin << "row/col/depth: " << getRowBin(vRow) << ":" << getColBin(vCol) + << ":" << getDepthBin(vDepth) << ")" + << ">= maxBin " << mData.size() + << " for X(row)=" << vRow << " Z(col)=" << vCol << " Y(depth)=" << vDepth; + } + // printf("bin %d %d %d\n",getColBin(vCol),getRowBin(vRow),getDepthBin(vDepth)); + // return &mData[bin]; + dest.adopt(mData[bin], flipRow, flipCol); + return true; +} + +//____________________________________________________________ +const ChipRespSimMat* ChipSimResponse::getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, const int subDetID, const int nLayer) const +{ + if (subDetID == 0) { + return getResponse(vRow, vCol, vDepth, flipRow, flipCol, mRowMaxVD, mColMaxVD); + } else if (subDetID == 1 && nLayer <= 3) { // ML + return getResponse(vRow, vCol, vDepth, flipRow, flipCol, mRowMaxML, mColMaxML); + } else if (subDetID == 1 && nLayer >= 4) { // OT + return getResponse(vRow, vCol, vDepth, flipRow, flipCol, mRowMaxOT, mColMaxOT); + } else { + LOG(fatal) << "Unknown subdetector ID " << subDetID << " or layer " << nLayer; + return nullptr; + } +} + +//____________________________________________________________ +const ChipRespSimMat* ChipSimResponse::getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, float rowMax, float colMax) const +{ + /* + * get linearized NPix*NPix matrix for response at point vRow(sensor local X, along row) + * vCol(sensor local Z, along columns) and vDepth (sensor local Y, i.e. depth) + */ + if (!mNBinDpt) { + LOG(fatal) << "response object is not initialized"; + } + if (vDepth < mDptMin || vDepth > mDptMax) { + return nullptr; + } + if (vCol < 0) { + vCol = -vCol; + flipCol = true; + } else { + flipCol = false; + } + if (vCol > colMax) { + return nullptr; + } + if (vRow < 0) { + vRow = -vRow; + flipRow = false; + } else { + flipRow = true; + } + if (vRow > rowMax) { + return nullptr; + } + + size_t bin = getDepthBin(vDepth) + mNBinDpt * (getRowBin(vRow) + mNBinRow * getColBin(vCol)); + if (bin >= mData.size()) { + // this should not happen + LOG(fatal) << "requested bin " << bin << "row/col/depth: " << getRowBin(vRow) << ":" << getColBin(vCol) + << ":" << getDepthBin(vDepth) << ")" + << ">= maxBin " << mData.size() + << " for X(row)=" << vRow << " Z(col)=" << vCol << " Y(depth)=" << vDepth; + } + return &mData[bin]; +} + +//__________________________________________________ +void ChipRespSimMat::print(bool flipRow, bool flipCol) const +{ + /* + * print the response matrix + */ + for (int iRow = 0; iRow < NPix; iRow++) { + for (int iCol = 0; iCol < NPix; iCol++) { + printf("%+e ", getValue(iRow, iCol, flipRow, flipCol)); + } + printf("\n"); + } +} \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx new file mode 100644 index 0000000000000..7cc4e8109f6dd --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx @@ -0,0 +1,74 @@ + +// 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 DigiParams.cxx +/// \brief Implementation of the TRK digitization steering params. Based on the ITS2 code. + +#include // for LOG +#include "TRKSimulation/DigiParams.h" +#include + + +using namespace o2::trk; + +DigiParams::DigiParams() +{ + // make sure the defaults are consistent + setNSimSteps(mNSimSteps); +} + +void DigiParams::setROFrameLength(float lNS) +{ + // set ROFrame length in nanosecongs + mROFrameLength = lNS; + assert(mROFrameLength > 1.); + mROFrameLengthInv = 1. / mROFrameLength; +} + +void DigiParams::setNSimSteps(int v) +{ + // set number of sampling steps in silicon + mNSimSteps = v > 0 ? v : 1; + mNSimStepsInv = 1.f / mNSimSteps; +} + +void DigiParams::setChargeThreshold(int v, float frac2Account) +{ + // set charge threshold for digits creation and its fraction to account + // contribution from single hit + mChargeThreshold = v; + mMinChargeToAccount = v * frac2Account; + if (mMinChargeToAccount < 0 || mMinChargeToAccount > mChargeThreshold) { + mMinChargeToAccount = mChargeThreshold; + } + LOG(info) << "Set charge threshold to " << mChargeThreshold + << ", single hit will be accounted from " << mMinChargeToAccount + << " electrons"; +} + +//______________________________________________ +void DigiParams::print() const +{ + // print settings + printf("TRK digitization params:\n"); + printf("Continuous readout : %s\n", mIsContinuous ? "ON" : "OFF"); + printf("Readout Frame Length(ns) : %f\n", mROFrameLength); + printf("Strobe delay (ns) : %f\n", mStrobeDelay); + printf("Strobe length (ns) : %f\n", mStrobeLength); + printf("Threshold (N electrons) : %d\n", mChargeThreshold); + printf("Min N electrons to account : %d\n", mMinChargeToAccount); + printf("Number of charge sharing steps : %d\n", mNSimSteps); + printf("ELoss to N electrons factor : %e\n", mEnergyToNElectrons); + printf("Noise level per pixel : %e\n", mNoisePerPixel); + printf("Charge time-response:\n"); + mSignalShape.print(); +} From 5e060aa5ef64a9f8a61ed8873641e682586d32f7 Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Thu, 14 Aug 2025 16:37:12 +0200 Subject: [PATCH 3/8] ALICE3-TRK: improving segmentation, dealing with different silicon depth and pixel size wrt the APTS response --- .../base/include/TRKBase/SegmentationChip.h | 92 ++- .../ALICE3/TRK/base/include/TRKBase/Specs.h | 59 +- .../ALICE3/TRK/base/src/GeometryTGeo.cxx | 4 +- .../ALICE3/TRK/simulation/CMakeLists.txt | 1 + .../TRKSimulation/ChipDigitsContainer.h | 88 +- .../include/TRKSimulation/ChipSimResponse.h | 164 +--- .../include/TRKSimulation/Digitizer.h | 82 +- .../simulation/src/ChipDigitsContainer.cxx | 74 +- .../TRK/simulation/src/ChipSimResponse.cxx | 322 +------- .../ALICE3/TRK/simulation/src/Digitizer.cxx | 773 ++++++++++-------- 10 files changed, 618 insertions(+), 1041 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h index 4c129fedc0468..d00fb68925c4c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h @@ -28,15 +28,17 @@ namespace o2::trk /// This is a work-in-progress code derived from the ITS2 and ITS3 segmentations. class SegmentationChip { - // This class defines the segmenation of the TRK chips in the ALICE3 upgrade. We define - // two coordinate systems, one width x,z detector local coordianates (cm) and - // the more natural row,col layout: Also all the transformation between these - // two. The class provides the transformation from the stave/layer/disk to TGeo - // coordinates. + // This class defines the segmenation of the TRK chips in the ALICE3 upgrade. + // The "global coordinate system" refers to the hit position in cm in the global coordinate system centered in 0,0,0 + // The "local coordinate system" refers to the hit position in cm in the coordinate system of the sensor, which + // is centered in 0,0,0 in the case of curved layers, and in the middle of the chip in the case of flat layers + // The "detector coordinate system" refers to the hit position in row,col inside the sensor + // This class provides the transformations from the local and detector coordinate systems + // The conversion between global and local coordinate systems is operated by the transformation matrices // For the curved VD layers there exist three coordinate systems and one is transient. // 1. The global (curved) coordinate system. The chip's center of coordinate system is // defined at the the mid-point of the detector. - // 2. The flat coordinate system. This is the tube segment projected onto a flat + // 2. The local (flat) coordinate system. This is the tube segment projected onto a flat // surface. In the projection we implicitly assume that the inner and outer // stretch does not depend on the radius. // 3. The detector coordinate system. Defined by the row and column segmentation @@ -58,17 +60,15 @@ class SegmentationChip static constexpr float PitchColVD{constants::VD::petal::layer::pitchZ}; static constexpr float PitchRowVD{constants::VD::petal::layer::pitchX}; - static constexpr float PitchColML{constants::moduleMLOT::chip::pitchZ}; - static constexpr float PitchRowML{constants::moduleMLOT::chip::pitchX}; - - static constexpr float PitchColOT{constants::moduleMLOT::chip::pitchZ}; - static constexpr float PitchRowOT{constants::moduleMLOT::chip::pitchX}; + static constexpr float PitchColMLOT{constants::moduleMLOT::chip::pitchZ}; + static constexpr float PitchRowMLOT{constants::moduleMLOT::chip::pitchX}; static constexpr float SensorLayerThicknessVD = {constants::VD::petal::layer::totalThickness}; // physical thickness of sensitive part = 30 um static constexpr float SensorLayerThicknessML = {constants::moduleMLOT::chip::totalThickness}; // physical thickness of sensitive part = 100 um static constexpr float SensorLayerThicknessOT = {constants::moduleMLOT::chip::totalThickness}; // physical thickness of sensitive part = 100 um - static constexpr float SiliconTickness = constants::silicon::thickness; // effective thickness of sensitive part + static constexpr float SiliconThicknessVD = constants::VD::silicon::thickness; // effective thickness of sensitive part + static constexpr float SiliconThicknessMLOT = constants::moduleMLOT::silicon::thickness; // effective thickness of sensitive part static constexpr std::array radiiVD = constants::VD::petal::layer::radii; @@ -86,24 +86,25 @@ class SegmentationChip /// \param int subDetID Sub-detector ID (0 for VD, 1 for ML/OT) /// \param int layer Layer number (0 to 2 for VD, 0 to 7 for ML/OT) /// \param int disk Disk number (0 to 5 for VD) - static bool globalToDetector(float xRow, float zCol, int& iRow, int& iCol, int subDetID, int layer, int disk) noexcept + static bool localToDetector(float xRow, float zCol, int& iRow, int& iCol, int subDetID, int layer, int disk) noexcept { if (!isValidGlob(xRow, zCol, subDetID, layer)) { - LOGP(info, "Global coordinates not valid: row = {} cm, col = {} cm", xRow, zCol); + LOGP(debug, "Local coordinates not valid: row = {} cm, col = {} cm", xRow, zCol); return false; } + localToDetectorUnchecked(xRow, zCol, iRow, iCol, subDetID, layer, disk); - globalToDetectorUnchecked(xRow, zCol, iRow, iCol, subDetID, layer, disk); + LOG(debug) << "Result from localToDetectorUnchecked: xRow " << xRow << " -> iRow " << iRow << ", zCol " << zCol << " -> iCol " << iCol << " on subDetID, layer, disk: " << subDetID << " " << layer << " " << disk; if (!isValidDet(iRow, iCol, subDetID, layer)) { iRow = iCol = -1; - LOGP(info, "Detector coordinates not valid: iRow = {}, iCol = {}", iRow, iCol); + LOGP(debug, "Detector coordinates not valid: iRow = {}, iCol = {}", iRow, iCol); return false; } return true; }; /// same but w/o check for row/column range - static void globalToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol, int subDetID, int layer, int disk) noexcept + static void localToDetectorUnchecked(float xRow, float zCol, int& iRow, int& iCol, int subDetID, int layer, int disk) noexcept { // convert to row/col w/o over/underflow check float pitchRow(0), pitchCol(0); @@ -116,13 +117,13 @@ class SegmentationChip maxLength = constants::VD::petal::layer::length; // TODO: change this to use the layer and disk } else if (subDetID == 1 && layer <= 3) { // ML - pitchRow = PitchRowML; - pitchCol = PitchColML; + pitchRow = PitchRowMLOT; + pitchCol = PitchColMLOT; maxWidth = constants::ML::width; maxLength = constants::ML::length; } else if (subDetID == 1 && layer >= 4) { // OT - pitchRow = PitchRowOT; - pitchCol = PitchColOT; + pitchRow = PitchRowMLOT; + pitchCol = PitchColMLOT; maxWidth = constants::OT::width; maxLength = constants::OT::length; } @@ -131,7 +132,7 @@ class SegmentationChip iCol = static_cast(std::floor((zCol + maxLength / 2) / pitchCol)); }; - // Check global coordinates (cm) validity. + // Check local coordinates (cm) validity. static constexpr bool isValidGlob(float x, float z, int subDetID, int layer) noexcept { float maxWidth(0), maxLength(0); @@ -165,8 +166,7 @@ class SegmentationChip nRows = constants::OT::nRows; nCols = constants::OT::nCols; } - return (row >= 0 && row < static_cast(nRows) && - col >= 0 && col < static_cast(nCols)); + return (row >= 0 && row < static_cast(nRows) && col >= 0 && col < static_cast(nCols)); } /// Transformation from Detector cell coordinates to Geant detector centered @@ -182,34 +182,37 @@ class SegmentationChip /// \param int subDetID Sub-detector ID (0 for VD, 1 for ML/OT) /// \param int layer Layer number (0 to 2 for VD, 0 to 7 for ML/OT) /// \param int disk Disk number (0 to 5 for VD) - static constexpr bool detectorToGlobal(int iRow, int iCol, float& xRow, float& zCol, int subDetID, int layer, int disk) noexcept + static constexpr bool detectorToLocal(int iRow, int iCol, float& xRow, float& zCol, int subDetID, int layer, int disk) noexcept { - if (!isValidDet(xRow, zCol, subDetID, layer)) { + if (!isValidDet(iRow, iCol, subDetID, layer)) { LOGP(debug, "Detector coordinates not valid: iRow = {}, iCol = {}", iRow, iCol); return false; } - detectorToGlobalUnchecked(iRow, iCol, xRow, zCol, subDetID, layer, disk); + detectorToLocalUnchecked(iRow, iCol, xRow, zCol, subDetID, layer, disk); + LOG(debug) << "Result from detectorToLocalUnchecked: iRow " << iRow << " -> xRow " << xRow << ", iCol " << iCol << " -> zCol " << zCol << " on subDetID, layer, disk: " << subDetID << " " << layer << " " << disk; if (!isValidGlob(xRow, zCol, subDetID, layer)) { - LOGP(debug, "Global coordinates not valid: row = {} cm, col = {} cm", xRow, zCol); + LOGP(debug, "Local coordinates not valid: row = {} cm, col = {} cm", xRow, zCol); return false; } return true; }; - // Same as detectorToGlobal w.o. checks. + // Same as detectorToLocal w.o. checks. // We position ourself in the middle of the pixel. - static void detectorToGlobalUnchecked(int& row, int& col, float xRow, float zCol, int subDetID, int layer, int disk) noexcept + static void detectorToLocalUnchecked(int row, int col, float& xRow, float& zCol, int subDetID, int layer, int disk) noexcept { + /// xRow = half chip width - iRow(center) * pitch + /// zCol = iCol * pitch - half chip lenght if (subDetID == 0) { - xRow = -(row + 0.5f) * PitchRowVD + constants::VD::petal::layer::width[layer] / 2; - zCol = (col + 0.5f) * PitchColVD - constants::VD::petal::layer::length / 2; + xRow = 0.5 * (constants::VD::petal::layer::width[layer] - PitchRowVD) - (row * PitchRowVD); + zCol = col * PitchColVD + 0.5 * (PitchColVD - constants::VD::petal::layer::length); } else if (subDetID == 1 && layer <= 3) { // ML - xRow = -(row + 0.5f) * PitchRowML + constants::ML::width / 2; - zCol = (col + 0.5f) * PitchColML - constants::ML::length / 2; + xRow = 0.5 * (constants::ML::width - PitchRowMLOT) - (row * PitchRowMLOT); + zCol = col * PitchRowMLOT + 0.5 * (PitchRowMLOT - constants::ML::length); } else if (subDetID == 1 && layer >= 4) { // OT - xRow = -(row + 0.5f) * PitchRowOT + constants::OT::width / 2; - zCol = (col + 0.5f) * PitchColOT - constants::OT::length / 2; + xRow = 0.5 * (constants::OT::width - PitchRowMLOT) - (row * PitchRowMLOT); + zCol = col * PitchColMLOT + 0.5 * (PitchColMLOT - constants::OT::length); } } @@ -225,7 +228,6 @@ class SegmentationChip /// the center of the sensitive volume. /// \return math_utils::Vector2D: x and y represent the detector local flat coordinates x and y // in cm with respect to the center of the sensitive volume. - static math_utils::Vector2D curvedToFlat(const int layer, const float xCurved, const float yCurved) noexcept { // Align the flat surface with the curved survace of the original chip (and account for metal stack, TODO) @@ -259,8 +261,22 @@ class SegmentationChip float yCurved = dist * std::sin(phi); return math_utils::Vector2D(xCurved, yCurved); } + + /// Print segmentation info + static const void Print() noexcept + { + LOG(info) << "Number of rows:\nVD L0: " << constants::VD::petal::layer::nRows[0] + << "\nVD L1: " << constants::VD::petal::layer::nRows[1] + << "\nVD L2: " << constants::VD::petal::layer::nRows[2] + << "\nML stave: " << constants::ML::nRows + << "\nOT stave: " << constants::OT::nRows; + + LOG(info) << "Number of cols:\nVD: " << constants::VD::petal::layer::nCols + << "\nML stave: " << constants::ML::nCols + << "\nOT stave: " << constants::OT::nCols; + } }; } // namespace o2::trk -#endif \ No newline at end of file +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h index e80c965ffe4d0..373e9d972656b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h @@ -30,13 +30,16 @@ constexpr double cm{1}; constexpr double mu{1e-4}; constexpr double mm{1e-1}; -// namespace metalstack /// still to be defined -// { -// constexpr double thickness{5 * mu}; // physical thickness of the copper metal stack -// } - namespace VD // TODO: add a primitive segmentation with more granularity wrt 1/4 layer = 1 chip { +namespace silicon +{ +constexpr double thickness{30 * mu}; // thickness of the silicon (should be 10 um epitaxial layer + 20 um substrate)? +} // namespace silicon +namespace metalstack +{ +constexpr double thickness{0 * mu}; // thickness of the copper metal stack - for the moment it is not implemented +} // namespace metalstack namespace petal { constexpr int nLayers{3}; // number of layers in each VD petal @@ -45,12 +48,12 @@ namespace layer { constexpr double pitchX{10 * mu}; // pitch of the row constexpr double pitchZ{10 * mu}; // pitch of the column -constexpr double totalThickness{30 * mu}; // total thickness of the chip -constexpr std::array radii{0.5 * cm, 1.2 * cm, 2.5 * cm}; // width of the quarter of layer in cm +constexpr double totalThickness{silicon::thickness + metalstack::thickness}; // total thickness of the chip +constexpr std::array radii{0.5 * cm, 1.2 * cm, 2.5 * cm}; // radius of layer in cm constexpr std::array width{radii[0] * 2 * M_PI / 4, radii[1] * 2 * M_PI / 4, radii[2] * 2 * M_PI / 4}; // width of the quarter of layer in cm constexpr double length{50 * cm}; // length of the layer constexpr int nCols{static_cast(length / pitchZ)}; // number of columns in the chip -constexpr std::array nRows{static_cast(width[0] / pitchX), static_cast(width[1] / pitchX), static_cast(width[2] / pitchX)}; // number of rows in the chip +constexpr std::array nRows{static_cast(width[0] / pitchX), static_cast(width[1] / pitchX), static_cast(width[2] / pitchX)}; // number of rows in the chip. For the moment is different for each layer since a siner segmentation in repetitive units is stil to be implemented } // namespace layer namespace disk @@ -62,16 +65,24 @@ constexpr double radiusOut{2.5 * cm}; } // namespace VD namespace moduleMLOT /// same for ML and OT for the moment -{ /// TODO: account for different modules in case of change +{ /// TODO: account for different modules in case of changes +namespace silicon +{ +constexpr double thickness{100 * mu}; // thickness of the silicon (should be 10 um epitaxial layer + 90 um substrate)? +} // namespace silicon +namespace metalstack +{ +constexpr double thickness{0 * mu}; // thickness of the copper metal stack - for the moment it is not implemented +} // namespace metalstack namespace chip { -constexpr double width{25 * mm}; // width of the chip -constexpr double length{32 * mm}; // length of the chip -constexpr double pitchX{50 * mu}; // pitch of the row -constexpr double pitchZ{50 * mu}; // pitch of the column -constexpr int nRows{static_cast(width / pitchX)}; // number of columns in the chip -constexpr int nCold{static_cast(length / pitchZ)}; // number of rows in the chipù -constexpr double totalThickness{100 * mu}; // total thickness of the chip +constexpr double width{25 * mm}; // width of the chip +constexpr double length{32 * mm}; // length of the chip +constexpr double pitchX{50 * mu}; // pitch of the row +constexpr double pitchZ{50 * mu}; // pitch of the column +constexpr int nRows{static_cast(width / pitchX)}; // number of columns in the chip +constexpr int nCols{static_cast(length / pitchZ)}; // number of rows in the chip +constexpr double totalThickness{silicon::thickness + metalstack::thickness}; // total thickness of the chip /// Set to 0 for the moment, to be adjusted with the actual design of the chip if needed static constexpr float PassiveEdgeReadOut = 0.f; // width of the readout edge (Passive bottom) static constexpr float PassiveEdgeTop = 0.f; // Passive area on top @@ -86,7 +97,7 @@ constexpr double outerEdgeShortSide{0.1 * mm}; // gap between the chips and the constexpr double width{chip::width * 2 + gaps::interChips + 2 * gaps::outerEdgeLongSide}; // width of the module constexpr double length{chip::length * 4 + 3 * gaps::interChips + 2 * gaps::outerEdgeShortSide}; // length of the module constexpr int nRows{static_cast(width / chip::pitchX)}; // number of columns in the module -constexpr int nCold{static_cast(length / chip::pitchZ)}; // number of rows in the module +constexpr int nCols{static_cast(length / chip::pitchZ)}; // number of rows in the module } // namespace moduleMLOT namespace ML @@ -98,17 +109,21 @@ constexpr int nCols{static_cast(length / constants::moduleMLOT::chip::pitch } // namespace ML namespace OT -{ +{ //// TODO: add shorter lenght of the stave of L4 constexpr double width{moduleMLOT::width * 2}; // width of the stave constexpr double length{moduleMLOT::length * 20}; // length of the stave constexpr int nRows{static_cast(width / moduleMLOT::chip::pitchX)}; // number of rows in the stave constexpr int nCols{static_cast(length / moduleMLOT::chip::pitchZ)}; // number of columns in the stave } // namespace OT -namespace silicon +namespace apts /// parameters for the APTS response { -constexpr double thickness{10 * mu}; // thickness of active material -} // namespace silicon +constexpr double pitchX{15.0 * mu}; +constexpr double pitchZ{15.0 * mu}; +constexpr double responseYShift{15.5 * mu}; +constexpr double thickness{45 * mu}; +} // namespace apts + } // namespace o2::trk::constants -#endif \ No newline at end of file +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index 0052c95cbd92c..20088179f4dcc 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -266,7 +266,7 @@ TString GeometryTGeo::getMatrixPath(int index) const int subDetID, petalcase, disk, layer, stave, halfstave; //// TODO: add chips in a second step getChipID(index, subDetID, petalcase, disk, layer, stave, halfstave); - PrintChipID(index, subDetID, petalcase, disk, layer, stave, halfstave); + // PrintChipID(index, subDetID, petalcase, disk, layer, stave, halfstave); // TString path = "/cave_1/barrel_1/TRKV_2/TRKLayer0_1/TRKStave0_1/TRKChip0_1/TRKSensor0_1/"; /// dummy path, to be used for tests TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getTRKVolPattern()); @@ -709,4 +709,4 @@ void GeometryTGeo::Print(Option_t*) const } } // namespace trk -} // namespace o2 \ No newline at end of file +} // namespace o2 diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt index dad0c9b8a970b..ab817a3fdaa0d 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/CMakeLists.txt @@ -24,6 +24,7 @@ o2_add_library(TRKSimulation PUBLIC_LINK_LIBRARIES O2::TRKBase O2::FT3Simulation O2::ITSMFTSimulation + O2::DetectorsRaw O2::SimulationDataFormat) o2_target_root_dictionary(TRKSimulation diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h index 760da766be701..658fb823bb596 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h @@ -9,89 +9,29 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// -/// \file ChipDigitsContainer.h -/// \brief transient container for single chip digits accumulation. Using ITSMFT digits definition. -// +#ifndef ALICEO2_TRK_CHIPDIGITSCONTAINER_ +#define ALICEO2_TRK_CHIPDIGITSCONTAINER_ -#ifndef ALICEO2_ITSMFT_CHIPDIGITSCONTAINER_ -#define ALICEO2_ITSMFT_CHIPDIGITSCONTAINER_ - -#include "SimulationDataFormat/MCCompLabel.h" +#include "ITSMFTBase/SegmentationAlpide.h" +#include "ITSMFTSimulation/ChipDigitsContainer.h" #include "TRKBase/SegmentationChip.h" -#include "ITSMFTSimulation/PreDigit.h" -#include "DataFormatsITSMFT/NoiseMap.h" -#include -#include +#include "TRKBase/Specs.h" +#include "TRKSimulation/DigiParams.h" +#include -namespace o2 -{ -namespace trk +namespace o2::trk { -class DigiParams; -/// @class ChipDigitsContainer -/// @brief Container for simulated points connected to a given chip. Using ITSMFT digits definition - -class ChipDigitsContainer +class ChipDigitsContainer : public o2::itsmft::ChipDigitsContainer { public: - /// Default constructor - ChipDigitsContainer(UShort_t idx = 0) : mChipIndex(idx) {}; - - /// Destructor - ~ChipDigitsContainer() = default; - - std::map& getPreDigits() { return mDigits; } - bool isEmpty() const { return mDigits.empty(); } - void setNoiseMap(const o2::itsmft::NoiseMap* mp) { mNoiseMap = mp; } - void setDeadChanMap(const o2::itsmft::NoiseMap* mp) { mDeadChanMap = mp; } - void setChipIndex(UShort_t ind) { mChipIndex = ind; } - UShort_t getChipIndex() const { return mChipIndex; } + explicit ChipDigitsContainer(UShort_t idx = 0); - o2::itsmft::PreDigit* findDigit(ULong64_t key); - void addDigit(ULong64_t key, UInt_t roframe, UShort_t row, UShort_t col, int charge, o2::MCCompLabel lbl); - // void addNoiseVD(UInt_t rofMin, UInt_t rofMax, const o2::trk::DigiParams* params, int maxRows = o2::trk::SegmentationChip::NColsVD, int maxCols = o2::trk::SegmentationChip::NColsVD); - // void addNoiseML(UInt_t rofMin, UInt_t rofMax, const o2::trk::DigiParams* params, int maxRows = o2::trk::SegmentationChip::NColsML, int maxCols = o2::trk::SegmentationChip::NColsML); + using Segmentation = SegmentationChip; - /// Get global ordering key made of readout frame, column and row - static ULong64_t getOrderingKey(UInt_t roframe, UShort_t row, UShort_t col) - { - return (static_cast(roframe) << (8 * sizeof(UInt_t))) + (col << (8 * sizeof(Short_t))) + row; - } - - /// Get ROFrame from the ordering key - static UInt_t key2ROFrame(ULong64_t key) - { - return static_cast(key >> (8 * sizeof(UInt_t))); - } - - bool isDisabled() const { return mDisabled; } - void disable(bool v) { mDisabled = v; } - - protected: - UShort_t mChipIndex = 0; ///< chip index - bool mDisabled = false; - const o2::itsmft::NoiseMap* mNoiseMap = nullptr; - const o2::itsmft::NoiseMap* mDeadChanMap = nullptr; - std::map mDigits; ///< Map of fired pixels, possibly in multiple frames + ClassDefNV(ChipDigitsContainer, 1); }; -//_______________________________________________________________________ -inline o2::itsmft::PreDigit* ChipDigitsContainer::findDigit(ULong64_t key) -{ - // finds the digit corresponding to global key - auto digitentry = mDigits.find(key); - return digitentry != mDigits.end() ? &(digitentry->second) : nullptr; -} - -//_______________________________________________________________________ -inline void ChipDigitsContainer::addDigit(ULong64_t key, UInt_t roframe, UShort_t row, UShort_t col, - int charge, o2::MCCompLabel lbl) -{ - mDigits.emplace(std::make_pair(key, o2::itsmft::PreDigit(roframe, row, col, charge, lbl))); -} -} // namespace trk -} // namespace o2 +} // namespace o2::trk -#endif /* defined(ALICEO2_ITSMFT_CHIPCONTAINER_) */ \ No newline at end of file +#endif // ALICEO2_TRK_CHIPDIGITSCONTAINER_ diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipSimResponse.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipSimResponse.h index 2cf3b3f310775..29147997f66bf 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipSimResponse.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipSimResponse.h @@ -9,177 +9,29 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file ChipSimResponse.h -/// \brief Definition of the TRK chip simulated response parametrization +#ifndef ALICEO2_TRKSIMULATION_CHIPSIMRESPONSE_H +#define ALICEO2_TRKSIMULATION_CHIPSIMRESPONSE_H -#ifndef ALICEO2_TRK_CHIPSIMRESPONSE_H -#define ALICEO2_TRK_CHIPSIMRESPONSE_H - -#include -#include -#include -#include - -#include "TRKBase/SegmentationChip.h" +#include "ITSMFTSimulation/AlpideSimResponse.h" namespace o2 { namespace trk { -/* - * ChipRespSimMat : class to access the response: probability to collect electron - * in MNPix*MNPix cells. - */ -class ChipRespSimMat -{ - public: - static int constexpr NPix = 5; /// side of quadrant (pixels) with non-0 response - static int constexpr MatSize = NPix * NPix; /// number of pixels in the quadrant - static int constexpr getNPix() { return NPix; } - - ChipRespSimMat() = default; - ~ChipRespSimMat() = default; - - void adopt(const ChipRespSimMat& src, bool flipRow = false, bool flipCol = false) - { - // copy constructor with option of channels flipping - for (int iRow = NPix; iRow--;) { - int rw = flipRow ? NPix - 1 - iRow : iRow; - for (int iCol = NPix; iCol--;) { - int bDest = rw * NPix + (flipCol ? NPix - 1 - iCol : iCol); - data[bDest] = src.data[iRow * NPix + iCol]; - } - } - } - - /// probability to find an electron in pixel ix,iy,iz - float getValue(int iRow, int iCol) const { return data[iRow * NPix + iCol]; } - float getValue(int iRow, int iCol, bool flipRow, bool flipCol) const - { - int bin = (flipRow ? NPix - 1 - iRow : iRow) * NPix + (flipCol ? NPix - 1 - iCol : iCol); - return data[bin]; - } - - /// pointer on underlying array - std::array* getArray() { return &data; } - - /// print values - void print(bool flipRow = false, bool flipCol = false) const; - - private: - std::array data; - - // ClassDefNV(ChipRespSimMat, 1); -}; -/* - * ChipSimResponse: container for Chip simulates parameterized response matrices - * Based on the ITS2 and ITS3 sim response code. - * Provides for the electron injected to point X(columns direction),Y (rows direction) - * (with respect to pixel center) and Z (depth, with respect to epitaxial layer inner - * serface!!! i.e. touching the substrate) the probability to be collected in every - * of NPix*NPix pixels with reference pixel in the center. - */ - -class ChipSimResponse +class ChipSimResponse : public o2::itsmft::AlpideSimResponse { - - private: - int getColBin(float pos) const; - int getRowBin(float pos) const; - int getDepthBin(float pos) const; - std::string composeDataName(int colBin, int rowBin); - - int mNBinCol = 0; /// number of bins in X(col direction) - int mNBinRow = 0; /// number of bins in Y(row direction) - int mNBinDpt = 0; /// number of bins in Z(sensor dept) - int mMaxBinCol = 0; /// max allowed Xb (to avoid subtraction) - int mMaxBinRow = 0; /// max allowed Yb (to avoid subtraction) - float mColMaxVD = SegmentationChip::PitchColVD / 2.f; /// upper boundary of Col in the VD - float mRowMaxVD = SegmentationChip::PitchRowVD / 2.f; /// upper boundary of Row in the VD - float mColMaxML = SegmentationChip::PitchColML / 2.f; /// upper boundary of Col in the ML - float mRowMaxML = SegmentationChip::PitchRowML / 2.f; /// upper boundary of Row in the ML - float mColMaxOT = SegmentationChip::PitchColOT / 2.f; /// upper boundary of Col in the OT - float mRowMaxOT = SegmentationChip::PitchRowOT / 2.f; /// upper boundary of Row in the OT - float mDptMin = 0.f; /// lower boundary of Dpt - float mDptMax = 0.f; /// upper boundary of Dpt - float mDptShift = 0.f; /// shift of the depth center wrt 0 - float mStepInvCol = 0; /// inverse step of the Col grid - float mStepInvRow = 0; /// inverse step of the Row grid - float mStepInvDpt = 0; /// inverse step of the Dpt grid - std::vector mData; /// response data - /// path to look for data file - std::string mDataPath; - std::string mGridColName = "grid_list_x.txt"; /// name of the file with grid in Col - std::string mGridRowName = "grid_list_y.txt"; /// name of the file with grid in Row - std::string mColRowDataFmt = "data_pixels_%.2f_%.2f.txt"; /// format to read the data for given Col,Row - public: ChipSimResponse() = default; - virtual ~ChipSimResponse() = default; + ChipSimResponse(const ChipSimResponse& other) = default; + ChipSimResponse(const o2::itsmft::AlpideSimResponse* base) : o2::itsmft::AlpideSimResponse(*base) {} void initData(int tableNumber, std::string dataPath, const bool quiet = true); - bool getResponse(float vRow, float vCol, float cDepth, ChipRespSimMat& dest, const int nLayer) const; - const ChipRespSimMat* getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, const int subDetID, const int nLayer) const; - const ChipRespSimMat* getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, float rowMax, float colMax) const; - static int constexpr getNPix() { return ChipRespSimMat::getNPix(); } - int getNBinCol() const { return mNBinCol; } - int getNBinRow() const { return mNBinRow; } - int getNBinDepth() const { return mNBinDpt; } - float getColMaxVD() const { return mColMaxVD; } - float getRowMaxVD() const { return mRowMaxVD; } - float getColMaxML() const { return mColMaxML; } - float getRowMaxML() const { return mRowMaxML; } - float getDepthMin() const { return mDptMin; } - float getDepthMax() const { return mDptMax; } - float getDepthShift() const { return mDptShift; } - float getStepCol() const { return mStepInvCol ? 1. / mStepInvCol : 0.f; } - float getStepRow() const { return mStepInvRow ? 1. / mStepInvRow : 0.f; } - float getStepDepth() const { return mStepInvDpt ? 1. / mStepInvDpt : 0.f; } - void setColMaxVD(float v) noexcept { mColMaxVD = v; } - void setRowMaxVD(float v) noexcept { mRowMaxVD = v; } - void setColMaxML(float v) noexcept { mColMaxML = v; } - void setRowMaxML(float v) noexcept { mRowMaxML = v; } - void setDataPath(const std::string pth) { mDataPath = pth; } - void setGridColName(const std::string nm) { mGridColName = nm; } - void setGridRowName(const std::string nm) { mGridRowName = nm; } - void setColRowDataFmt(const std::string nm) { mColRowDataFmt = nm; } - const std::string& getDataPath() const { return mDataPath; } - const std::string& getGridColName() const { return mGridColName; } - const std::string& getGridRowName() const { return mGridRowName; } - const std::string& getColRowDataFmt() const { return mColRowDataFmt; } - void print() const; - - // ClassDefNV(ChipSimResponse, 2); + ClassDef(ChipSimResponse, 1); }; -//----------------------------------------------------- -inline int ChipSimResponse::getColBin(float pos) const -{ - /// get column bin w/o checking for over/under flow. pos MUST be >=0 - int i = pos * mStepInvCol + 0.5f; - return i < mNBinCol ? i : mMaxBinCol; -} - -//----------------------------------------------------- -inline int ChipSimResponse::getRowBin(float pos) const -{ - // get row bin w/o checking for over/under flow. pos MUST be >=0 - int i = pos * mStepInvRow + 0.5f; - return i < mNBinRow ? i : mMaxBinRow; -} - -//----------------------------------------------------- -inline int ChipSimResponse::getDepthBin(float pos) const -{ - // get depth bin w/o checking for over/under flow. pos is with respect of the beginning - // of epitaxial layer - int i = (mDptMax - pos) * mStepInvDpt; - return i < 0 ? 0 : i; // depth bin -} - } // namespace trk } // namespace o2 -#endif \ No newline at end of file +#endif // ALICEO2_TRKSIMULATION_CHIPSIMRESPONSE_H diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h index 6863c5392cae3..85706d1bd25c1 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h @@ -21,12 +21,12 @@ #include "Rtypes.h" // for Digitizer::Class #include "TObject.h" // for TObject -#include "ITSMFTSimulation/ChipDigitsContainer.h" -// #include "ITSMFTSimulation/AlpideSimResponse.h" -#include "ITSMFTSimulation/DigiParams.h" +#include "TRKSimulation/ChipSimResponse.h" +#include "TRKSimulation/ChipDigitsContainer.h" + +#include "TRKSimulation/DigiParams.h" #include "ITSMFTSimulation/Hit.h" #include "TRKBase/GeometryTGeo.h" -// #include "ITS3Base/SegmentationSuperAlpide.h" #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "CommonDataFormat/InteractionRecord.h" @@ -46,11 +46,13 @@ class Digitizer : public TObject void setMCLabels(o2::dataformats::MCTruthContainer* mclb) { mMCLabels = mclb; } void setROFRecords(std::vector* rec) { mROFRecords = rec; } - o2::itsmft::DigiParams& getParams() { return (o2::itsmft::DigiParams&)mParams; } - const o2::itsmft::DigiParams& getParams() const { return mParams; } + o2::trk::DigiParams& getParams() { return (o2::trk::DigiParams&)mParams; } + const o2::trk::DigiParams& getParams() const { return mParams; } void init(); + o2::trk::ChipSimResponse* getChipResponse(int chipID); + /// Steer conversion of hits to digits void process(const std::vector* hits, int evID, int srcID); void setEventTime(const o2::InteractionTimeRecord& irt); @@ -64,10 +66,10 @@ class Digitizer : public TObject bool isContinuous() const { return mParams.isContinuous(); } void fillOutputContainer(uint32_t maxFrame = 0xffffffff); - void setDigiParams(const o2::itsmft::DigiParams& par) { mParams = par; } - const o2::itsmft::DigiParams& getDigitParams() const { return mParams; } + void setDigiParams(const o2::trk::DigiParams& par) { mParams = par; } + const o2::trk::DigiParams& getDigitParams() const { return mParams; } - // provide the common itsmft::GeometryTGeo to access matrices and segmentation + // provide the common trk::GeometryTGeo to access matrices and segmentation void setGeometry(const o2::trk::GeometryTGeo* gm) { mGeometry = gm; } uint32_t getEventROFrameMin() const { return mEventROFrameMin; } @@ -82,7 +84,7 @@ class Digitizer : public TObject private: void processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID); - void registerDigits(o2::itsmft::ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, + void registerDigits(o2::trk::ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl); ExtraDig* getExtraDigBuffer(uint32_t roFrame) @@ -97,9 +99,41 @@ class Digitizer : public TObject return mExtraBuff[ind].get(); } + /// Get the number of columns according to the subdetector + /// \param subDetID 0 for VD, 1 for ML/OT + /// \param layer 0 to 2 for VD, 0 to 7 for ML/OT + /// \return Number of columns (for the moment, in the entire layer(VD) or stave (ML/OT) + int getNCols(int subDetID, int layer) + { + if (subDetID == 0) { // VD + return constants::VD::petal::layer::nCols; + } else if (subDetID == 1 && layer <= 3) { // ML + return constants::ML::nCols; + } else if (subDetID == 1 && layer >= 4) { // OT + return constants::OT::nCols; + } + return 0; + } + + /// Get the number of rows according to the subdetector + /// \param subDetID 0 for VD, 1 for ML/OT + /// \param layer 0 to 2 for VD, 0 to 7 for ML/OT + /// \return Number of rows (for the moment, in the entire layer(VD) or stave (ML/OT) + int getNRows(int subDetID, int layer) + { + if (subDetID == 0) { // VD + return constants::VD::petal::layer::nRows[layer]; + } else if (subDetID == 1 && layer <= 3) { // ML + return constants::ML::nRows; + } else if (subDetID == 1 && layer >= 4) { // OT + return constants::OT::nRows; + } + return 0; + } + static constexpr float sec2ns = 1e9; - o2::itsmft::DigiParams mParams; ///< digitization parameters + o2::trk::DigiParams mParams; ///< digitization parameters o2::InteractionTimeRecord mEventTime; ///< global event time and interaction record o2::InteractionRecord mIRFirstSampledTF; ///< IR of the 1st sampled IR, noise-only ROFs will be inserted till this IR only double mCollisionTimeWrtROF{}; @@ -110,19 +144,37 @@ class Digitizer : public TObject uint32_t mEventROFrameMin = 0xffffffff; ///< lowest RO frame for processed events (w/o automatic noise ROFs) uint32_t mEventROFrameMax = 0; ///< highest RO frame forfor processed events (w/o automatic noise ROFs) - o2::itsmft::AlpideSimResponse* mAlpSimResp = nullptr; // simulated response + int mNumberOfChips = 0; + + o2::trk::ChipSimResponse* mChipSimResp = nullptr; // simulated response + o2::trk::ChipSimResponse* mChipSimRespVD = nullptr; // simulated response for VD chips + o2::trk::ChipSimResponse* mChipSimRespMLOT = nullptr; // simulated response for ML/OT chips + + // std::string mResponseFile = "$(O2_ROOT)/share/Detectors/ITSMFT/data/AlpideResponseData/AlpideResponseData.root"; + std::string mResponseFile = "$(O2_ROOT)/share/Detectors/Upgrades/ITS3/data/ITS3ChipResponseData/APTSResponseData.root"; /// using temporarly the APTS response + + bool mSimRespOrientation{false}; // wether the orientation in the response function is flipped + float mSimRespVDShift{0.f}; // adjusting the Y-shift in the APTS response function to match sensor local coord. + float mSimRespVDScaleX{1.f}; // scale x-local coordinate to response function x-coordinate + float mSimRespVDScaleZ{1.f}; // scale z-local coordinate to response function z-coordinate + float mSimRespMLOTShift{0.f}; // adjusting the Y-shift in the APTS response function to match sensor local coord. + float mSimRespMLOTScaleX{1.f}; // scale x-local coordinate to response function x-coordinate + float mSimRespMLOTScaleZ{1.f}; // scale z-local coordinate to response function z-coordinate + float mSimRespVDScaleDepth{1.f}; // scale depth-local coordinate to response function depth-coordinate + float mSimRespMLOTScaleDepth{1.f}; // scale depth-local coordinate to response function depth-coordinate const o2::trk::GeometryTGeo* mGeometry = nullptr; ///< TRK geometry - std::vector mChips; ///< Array of chips digits containers - std::deque> mExtraBuff; ///< burrer (per roFrame) for extra digits + std::vector mChips; ///< Array of chips digits containers + std::deque> mExtraBuff; ///< buffer (per roFrame) for extra digits std::vector* mDigits = nullptr; //! output digits std::vector* mROFRecords = nullptr; //! output ROF records o2::dataformats::MCTruthContainer* mMCLabels = nullptr; //! output labels const o2::itsmft::NoiseMap* mDeadChanMap = nullptr; + const o2::itsmft::NoiseMap* mNoiseMap = nullptr; ClassDef(Digitizer, 1); }; -} // namespace o2::trk \ No newline at end of file +} // namespace o2::trk diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipDigitsContainer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipDigitsContainer.cxx index b24b61da2b503..9ed4a4bedf5c5 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipDigitsContainer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipDigitsContainer.cxx @@ -9,79 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -// -// ChipDigitsContainer.cpp -// ALICEO2 -// - #include "TRKSimulation/ChipDigitsContainer.h" -#include "TRKSimulation/DigiParams.h" -#include using namespace o2::trk; -using Segmentation = o2::trk::SegmentationChip; - -//// TODO: add noise - -//______________________________________________________________________ -// void ChipDigitsContainer::addNoiseVD(UInt_t rofMin, UInt_t rofMax, const o2::trk::DigiParams* params, int maxRows, int maxCols) -// { -// UInt_t row = 0; -// UInt_t col = 0; -// Int_t nhits = 0; -// constexpr float ns2sec = 1e-9; - - -// float mean = params->getNoisePerPixel() * Segmentation::NPixels; -// int nel = params->getChargeThreshold() * 1.1; // RS: TODO: need realistic spectrum of noise above the threshold - -// for (UInt_t rof = rofMin; rof <= rofMax; rof++) { -// nhits = gRandom->Poisson(mean); -// for (Int_t i = 0; i < nhits; ++i) { -// row = gRandom->Integer(maxRows); -// col = gRandom->Integer(maxCols); -// if (mNoiseMap && mNoiseMap->isNoisy(mChipIndex, row, col)) { -// continue; -// } -// if (mDeadChanMap && mDeadChanMap->isNoisy(mChipIndex, row, col)) { -// continue; -// } -// // RS TODO: why the noise was added with 0 charge? It should be above the threshold! -// auto key = getOrderingKey(rof, row, col); -// if (!findDigit(key)) { -// addDigit(key, rof, row, col, nel, o2::MCCompLabel(true)); -// } -// } -// } -// } - -// void ChipDigitsContainer::addNoiseML(UInt_t rofMin, UInt_t rofMax, const o2::trk::DigiParams* params, int maxRows, int maxCols) -// { -// UInt_t row = 0; -// UInt_t col = 0; -// Int_t nhits = 0; -// constexpr float ns2sec = 1e-9; - - //// TODO: add noise -// float mean = params->getNoisePerPixel() * Segmentation::NPixels; -// int nel = params->getChargeThreshold() * 1.1; // RS: TODO: need realistic spectrum of noise above the threshold -// for (UInt_t rof = rofMin; rof <= rofMax; rof++) { -// nhits = gRandom->Poisson(mean); -// for (Int_t i = 0; i < nhits; ++i) { -// row = gRandom->Integer(maxRows); -// col = gRandom->Integer(maxCols); -// if (mNoiseMap && mNoiseMap->isNoisy(mChipIndex, row, col)) { -// continue; -// } -// if (mDeadChanMap && mDeadChanMap->isNoisy(mChipIndex, row, col)) { -// continue; -// } -// // RS TODO: why the noise was added with 0 charge? It should be above the threshold! -// auto key = getOrderingKey(rof, row, col); -// if (!findDigit(key)) { -// addDigit(key, rof, row, col, nel, o2::MCCompLabel(true)); -// } -// } -// } -// } +ChipDigitsContainer::ChipDigitsContainer(UShort_t idx) + : o2::itsmft::ChipDigitsContainer(idx) {} diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipSimResponse.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipSimResponse.cxx index 177d26088bda4..70c4f131b9724 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipSimResponse.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/ChipSimResponse.cxx @@ -9,329 +9,13 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file ChipSimResponse.cxx -/// \brief Definition of the TRK chip simulated response parametrization. Based on ITS2 and ITS3 codes. - #include "TRKSimulation/ChipSimResponse.h" -#include "TRKSimulation/DPLDigitizerParam.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include using namespace o2::trk; -using namespace std; - -constexpr float micron2cm = 1e-4; void ChipSimResponse::initData(int tableNumber, std::string dataPath, const bool quiet) { - /* - * read grid parameters and load data - */ - if (tableNumber == 0) // 0V back bias - { - const std::string newDataPath = dataPath + "Vbb-0.0V"; - setDataPath(newDataPath); // setting the new data path - } else if (tableNumber == 1) // -3V back bias - { - const std::string newDataPath = dataPath + "Vbb-3.0V"; - setDataPath(newDataPath); // setting the new data path - } - - if (mData.size()) { - cout << "Object already initialized" << endl; - print(); - return; - } - - const float kTiny = 1e-6; // to check 0 values - - // if needed, append path with slash - if (mDataPath.length() && mDataPath.back() != '/') { - mDataPath.push_back('/'); - } - mDataPath = gSystem->ExpandPathName(mDataPath.data()); - string inpfname = mDataPath + mGridColName; - std::ifstream inpGrid; - - // read X grid - inpGrid.open(inpfname, std::ifstream::in); - if (inpGrid.fail()) { - LOG(fatal) << "Failed to open file " << inpfname; - } - - while (inpGrid >> mStepInvCol && inpGrid.good()) { - mNBinCol++; - } - - if (!mNBinCol || mStepInvCol < kTiny) { - LOG(fatal) << "Failed to read X(col) binning from " << inpfname; - } - mMaxBinCol = mNBinCol - 1; - mStepInvCol = mMaxBinCol / mStepInvCol; // inverse of the X bin width - inpGrid.close(); - - // read Y grid - inpfname = mDataPath + mGridRowName; - inpGrid.open(inpfname, std::ifstream::in); - if (inpGrid.fail()) { - LOG(fatal) << "Failed to open file " << inpfname; - } - - while (inpGrid >> mStepInvRow && inpGrid.good()) { - mNBinRow++; - } - if (!mNBinRow || mStepInvRow < kTiny) { - LOG(fatal) << "Failed to read Y(row) binning from " << inpfname; - } - mMaxBinRow = mNBinRow - 1; - mStepInvRow = mMaxBinRow / mStepInvRow; // inverse of the Row bin width - inpGrid.close(); - - // load response data - int nz = 0; - size_t cnt = 0; - float val, gx, gy, gz; - int lost, untrck, dead, nele; - size_t dataSize = 0; - mDptMax = -2.e9; - mDptMin = 2.e9; - const int npix = ChipRespSimMat::getNPix(); - - for (int ix = 0; ix < mNBinCol; ix++) { - for (int iy = 0; iy < mNBinRow; iy++) { - inpfname = composeDataName(ix, iy); - inpGrid.open(inpfname, std::ifstream::in); - if (inpGrid.fail()) { - LOG(fatal) << "Failed to open file " << inpfname; - } - inpGrid >> nz; - if (cnt == 0) { - mNBinDpt = nz; - dataSize = mNBinCol * mNBinRow * mNBinDpt; - mData.reserve(dataSize); // reserve space for data - } else if (nz != mNBinDpt) { - LOG(fatal) << "Mismatch in Nz slices of bin X(col): " << ix << " Y(row): " << iy - << " wrt bin 0,0. File " << inpfname; - } - - // load data - for (int iz = 0; iz < nz; iz++) { - ChipRespSimMat mat; - - std::array* arr = mat.getArray(); - for (int ip = 0; ip < npix * npix; ip++) { - inpGrid >> val; - (*arr)[ip] = val; - cnt++; - } - inpGrid >> lost >> dead >> untrck >> nele >> gx >> gy >> gz; - - if (inpGrid.bad()) { - LOG(fatal) << "Failed reading data for depth(Z) slice " << iz << " from " - << inpfname; - } - if (!nele) { - LOG(fatal) << "Wrong normalization Nele=" << nele << "for depth(Z) slice " - << iz << " from " << inpfname; - } - - if (mDptMax < -1e9) { - mDptMax = gz; - } - if (mDptMin > gz) { - mDptMin = gz; - } - - // normalize - float norm = 1.f / nele; - for (int ip = npix * npix; ip--;) { - (*arr)[ip] *= norm; - } - mData.push_back(mat); // store in the final container - } // loop over z - - inpGrid.close(); - - } // loop over y - } // loop over x - - // final check - if (dataSize != mData.size()) { - LOG(fatal) << "Mismatch between expected " << dataSize << " and loaded " << mData.size() - << " number of bins"; - } - - // normalize Dpt boundaries - - mStepInvCol /= micron2cm; - mStepInvRow /= micron2cm; - - mDptMin *= micron2cm; - mDptMax *= micron2cm; - mStepInvDpt = (mNBinDpt - 1) / (mDptMax - mDptMin); - mDptMin -= 0.5 / mStepInvDpt; - mDptMax += 0.5 / mStepInvDpt; - mDptShift = 0.5 * (mDptMax + mDptMin); - if (!quiet) { - print(); - } -} - -//----------------------------------------------------- -void ChipSimResponse::print() const -{ - /* - * print itself - */ - printf("Chip response object of %zu matrices to map chagre in xyz to %dx%d pixels\n", - mData.size(), getNPix(), getNPix()); - printf("VD X(col) range: %+e : %+e | step: %e | Nbins: %d\n", 0.f, mColMaxVD, 1.f / mStepInvCol, mNBinCol); - printf("ML X(col) range: %+e : %+e | step: %e | Nbins: %d\n", 0.f, mColMaxML, 1.f / mStepInvCol, mNBinCol); - printf("VD Y(row) range: %+e : %+e | step: %e | Nbins: %d\n", 0.f, mRowMaxVD, 1.f / mStepInvRow, mNBinRow); - printf("ML Y(row) range: %+e : %+e | step: %e | Nbins: %d\n", 0.f, mRowMaxML, 1.f / mStepInvRow, mNBinRow); - printf("Z(dpt) range: %+e : %+e | step: %e | Nbins: %d\n", mDptMin, mDptMax, 1.f / mStepInvDpt, mNBinDpt); -} - -//----------------------------------------------------- -string ChipSimResponse::composeDataName(int colBin, int rowBin) -{ - /* - * compose the file-name to read data for bin colBin,rowBin - */ - - // ugly but safe way to compose the file name - float vcol = colBin / mStepInvCol, vrow = rowBin / mStepInvRow; - size_t size = snprintf(nullptr, 0, mColRowDataFmt.data(), vcol, vrow) + 1; - unique_ptr tmp(new char[size]); - snprintf(tmp.get(), size, mColRowDataFmt.data(), vcol, vrow); - return mDataPath + string(tmp.get(), tmp.get() + size - 1); -} - -//____________________________________________________________ -bool ChipSimResponse::getResponse(float vRow, float vCol, float vDepth, ChipRespSimMat& dest, const int layer) const -{ - /* - * get linearized NPix*NPix matrix for response at point vRow(sensor local X, along row) - * vCol(sensor local Z, along columns) and vDepth (sensor local Y, i.e. depth) - */ - if (!mNBinDpt) { - LOG(fatal) << "response object is not initialized"; - } - bool flipCol = false, flipRow = true; - if (vDepth < mDptMin || vDepth > mDptMax) { - return false; - } - if (vCol < 0) { - vCol = -vCol; - flipCol = true; - } - if (vRow < 0) { - vRow = -vRow; - flipRow = false; - } - if (layer < 3) { - if (vCol > mColMaxVD) { - return false; - } - if (vRow > mRowMaxVD) { - return false; - } - } else { - if (vCol > mColMaxML) { - return false; - } - if (vRow > mRowMaxML) { - return false; - } - } - - size_t bin = getDepthBin(vDepth) + mNBinDpt * (getRowBin(vRow) + mNBinRow * getColBin(vCol)); - if (bin >= mData.size()) { - // this should not happen - LOG(fatal) << "requested bin " << bin << "row/col/depth: " << getRowBin(vRow) << ":" << getColBin(vCol) - << ":" << getDepthBin(vDepth) << ")" - << ">= maxBin " << mData.size() - << " for X(row)=" << vRow << " Z(col)=" << vCol << " Y(depth)=" << vDepth; - } - // printf("bin %d %d %d\n",getColBin(vCol),getRowBin(vRow),getDepthBin(vDepth)); - // return &mData[bin]; - dest.adopt(mData[bin], flipRow, flipCol); - return true; -} - -//____________________________________________________________ -const ChipRespSimMat* ChipSimResponse::getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, const int subDetID, const int nLayer) const -{ - if (subDetID == 0) { - return getResponse(vRow, vCol, vDepth, flipRow, flipCol, mRowMaxVD, mColMaxVD); - } else if (subDetID == 1 && nLayer <= 3) { // ML - return getResponse(vRow, vCol, vDepth, flipRow, flipCol, mRowMaxML, mColMaxML); - } else if (subDetID == 1 && nLayer >= 4) { // OT - return getResponse(vRow, vCol, vDepth, flipRow, flipCol, mRowMaxOT, mColMaxOT); - } else { - LOG(fatal) << "Unknown subdetector ID " << subDetID << " or layer " << nLayer; - return nullptr; - } -} - -//____________________________________________________________ -const ChipRespSimMat* ChipSimResponse::getResponse(float vRow, float vCol, float vDepth, bool& flipRow, bool& flipCol, float rowMax, float colMax) const -{ - /* - * get linearized NPix*NPix matrix for response at point vRow(sensor local X, along row) - * vCol(sensor local Z, along columns) and vDepth (sensor local Y, i.e. depth) - */ - if (!mNBinDpt) { - LOG(fatal) << "response object is not initialized"; - } - if (vDepth < mDptMin || vDepth > mDptMax) { - return nullptr; - } - if (vCol < 0) { - vCol = -vCol; - flipCol = true; - } else { - flipCol = false; - } - if (vCol > colMax) { - return nullptr; - } - if (vRow < 0) { - vRow = -vRow; - flipRow = false; - } else { - flipRow = true; - } - if (vRow > rowMax) { - return nullptr; - } - - size_t bin = getDepthBin(vDepth) + mNBinDpt * (getRowBin(vRow) + mNBinRow * getColBin(vCol)); - if (bin >= mData.size()) { - // this should not happen - LOG(fatal) << "requested bin " << bin << "row/col/depth: " << getRowBin(vRow) << ":" << getColBin(vCol) - << ":" << getDepthBin(vDepth) << ")" - << ">= maxBin " << mData.size() - << " for X(row)=" << vRow << " Z(col)=" << vCol << " Y(depth)=" << vDepth; - } - return &mData[bin]; -} - -//__________________________________________________ -void ChipRespSimMat::print(bool flipRow, bool flipCol) const -{ - /* - * print the response matrix - */ - for (int iRow = 0; iRow < NPix; iRow++) { - for (int iCol = 0; iCol < NPix; iCol++) { - printf("%+e ", getValue(iRow, iCol, flipRow, flipCol)); - } - printf("\n"); - } + AlpideSimResponse::initData(tableNumber, dataPath, quiet); } \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index 21e6e629ec418..b3bf393e5ac93 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -12,184 +12,195 @@ /// \file Digitizer.cxx #include "DataFormatsITSMFT/Digit.h" -// #include "ITSMFTBase/SegmentationAlpide.h" +#include "TRKBase/SegmentationChip.h" #include "TRKSimulation/DPLDigitizerParam.h" +#include "TRKSimulation/TRKLayer.h" #include "TRKSimulation/Digitizer.h" -// #include "MathUtils/Cartesian.h" -// #include "SimulationDataFormat/MCTruthContainer.h" -// #include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/HBFUtils.h" -// #include +#include // #include -// #include -// #include +#include +#include +#include #include // for LOG using o2::itsmft::Digit; using o2::itsmft::Hit; -// using Segmentation = o2::itsmft::SegmentationAlpide; +using Segmentation = o2::trk::SegmentationChip; using namespace o2::trk; +using namespace o2::itsmft; // using namespace o2::base; - //_______________________________________________________________________ void Digitizer::init() { - // mNumberOfChips = mGeometry->getNumberOfChips(); - // mChips.resize(mNumberOfChips); - // for (int i = mNumberOfChips; i--;) { - // mChips[i].setChipIndex(i); - // if (mNoiseMap) { - // mChips[i].setNoiseMap(mNoiseMap); - // } - // if (mDeadChanMap) { - // mChips[i].disable(mDeadChanMap->isFullChipMasked(i)); - // mChips[i].setDeadChanMap(mDeadChanMap); - // } - // } - // initializing for both collection tables - /*for (int i = 0; i < 2; i++) { - mAlpSimResp[i].initData(i); - }*/ - + LOG(info) << "Initializing digitizer"; + mNumberOfChips = mGeometry->getNumberOfChips(); + mChips.resize(mNumberOfChips); /// temporary, to not make it crash + for (int i = mNumberOfChips; i--;) { + mChips[i].setChipIndex(i); + if (mNoiseMap) { + mChips[i].setNoiseMap(mNoiseMap); + } + if (mDeadChanMap) { + mChips[i].disable(mDeadChanMap->isFullChipMasked(i)); + mChips[i].setDeadChanMap(mDeadChanMap); + } + } // importing the charge collection tables // (initialized while building O2) - // auto file = TFile::Open(mResponseFile.data()); - // if (!file) { - // LOG(fatal) << "Cannot open response file " << mResponseFile; - // } - /*std::string response = "response"; - for (int i=0; i<2; i++) { - response.append(std::to_string(i)); - mAlpSimResp[i] = *(o2::itsmft::AlpideSimResponse*)file->Get(response.data()); - }*/ - // mAlpSimResp[0] = *(o2::itsmft::AlpideSimResponse*)file->Get("response0"); - // mAlpSimResp[1] = *(o2::itsmft::AlpideSimResponse*)file->Get("response1"); + auto file = TFile::Open(mResponseFile.data()); + if (!file) { + LOG(fatal) << "Cannot open response file " << mResponseFile; + } + + // setting the correct response function (for the moment, for both VD and MLOT the APTS response function is udes) + mChipSimResp = (o2::trk::ChipSimResponse*)file->Get("response1"); + mChipSimRespVD = mChipSimResp; /// for the moment considering the same response + mChipSimRespMLOT = mChipSimResp; /// for the moment considering the same response + + /// setting scale factors to adapt to the APTS response function (adjusting pitch and Y shift) + // TODO: adjust Y shift when the geometry is improved + mSimRespVDScaleX = o2::trk::constants::apts::pitchX / o2::trk::SegmentationChip::PitchRowVD; + mSimRespVDScaleZ = o2::trk::constants::apts::pitchZ / o2::trk::SegmentationChip::PitchColVD; + mSimRespVDScaleDepth = o2::trk::constants::apts::thickness / (0.1); /// introducing this scaling factor because the silicon thickness for the moment is 1 mm -> rescale to 45 um which is the depth of the APTS response + mSimRespVDShift = mChipSimRespVD->getDepthMax() - 0.1 * mSimRespVDScaleDepth / 2.f; // the shift should be done considering the rescaling done to adapt to the wrong silicon thickness. TODO: remove the scaling factor for the depth when the silicon thickness match the simulated response + mSimRespMLOTScaleX = o2::trk::constants::apts::pitchX / o2::trk::SegmentationChip::PitchRowMLOT; + mSimRespMLOTScaleZ = o2::trk::constants::apts::pitchZ / o2::trk::SegmentationChip::PitchColMLOT; + mSimRespMLOTScaleDepth = o2::trk::constants::apts::thickness / (0.1); /// introducing this scaling factor because the silicon thickness for the moment is 1 mm -> rescale to 45 um which is the depth of the APTS response + mSimRespMLOTShift = mChipSimRespMLOT->getDepthMax() - 0.1 * mSimRespMLOTScaleDepth / 2.f; // the shift should be done considering the rescaling done to adapt to the wrong silicon thickness. TODO: remove the scaling factor for the depth when the silicon thickness match the simulated response + mSimRespOrientation = true; // importing the parameters from DPLDigitizerParam.h auto& dOptTRK = DPLDigitizerParam::Instance(); - LOGP(info, "TRK Digitizer is initalised."); + LOGP(info, "TRK Digitizer is initialised."); + mParams.print(); + LOGP(info, "VD shift = {} = {} - {} ; ML/OT shift = {} = {} - {}", mSimRespVDShift, mChipSimRespVD->getDepthMax(), 0.1 * mSimRespVDScaleDepth / 2.f, mSimRespMLOTShift, mChipSimRespMLOT->getDepthMax(), 0.1 * mSimRespMLOTScaleDepth / 2.f); + LOGP(info, "VD pixel scale on x = {} ; z = {}", mSimRespVDScaleX, mSimRespVDScaleZ); + LOGP(info, "ML/OT pixel scale on x = {} ; z = {}", mSimRespMLOTScaleX, mSimRespMLOTScaleZ); + LOGP(info, "Response orientation: {}", mSimRespOrientation ? "flipped" : "normal"); + + mIRFirstSampledTF = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); } -// auto Digitizer::getChipResponse(int chipID) -// { -// if (mNumberOfChips < 10000) { // in MFT -// return mAlpSimRespMFT; -// } +o2::trk::ChipSimResponse* Digitizer::getChipResponse(int chipID) +{ + if (mGeometry->getSubDetID(chipID) == 0) { /// VD + return mChipSimRespVD; + } -// if (chipID < 432) { // in ITS Inner Barrel -// return mAlpSimRespIB; -// } else { // in ITS Outter Barrel -// return mAlpSimRespOB; -// } -// } + else if (mGeometry->getSubDetID(chipID) == 1) { /// ML/OT + return mChipSimRespMLOT; + } + return nullptr; +}; //_______________________________________________________________________ void Digitizer::process(const std::vector* hits, int evID, int srcID) { // digitize single event, the time must have been set beforehand - // LOG(info) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source " - // << srcID << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" - // << " cont.mode: " << isContinuous() - // << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; + LOG(info) << " Digitizing " << mGeometry->getName() << " (ID: " << mGeometry->getDetID() + << ") hits of entry " << evID << " from source " << srcID + << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" + << " cont.mode: " << isContinuous() + << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; - // // is there something to flush ? - // if (mNewROFrame > mROFrameMin) { - // fillOutputContainer(mNewROFrame - 1); // flush out all frame preceding the new one - // } + std::cout << "Printing segmentation info: " << std::endl; + SegmentationChip::Print(); - // int nHits = hits->size(); - // std::vector hitIdx(nHits); - // std::iota(std::begin(hitIdx), std::end(hitIdx), 0); - // // sort hits to improve memory access - // std::sort(hitIdx.begin(), hitIdx.end(), - // [hits](auto lhs, auto rhs) { - // return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); - // }); - // for (int i : hitIdx) { - // processHit((*hits)[i], mROFrameMax, evID, srcID); - // } - // // in the triggered mode store digits after every MC event - // // TODO: in the real triggered mode this will not be needed, this is actually for the - // // single event processing only - // if (!mParams.isContinuous()) { - // fillOutputContainer(mROFrameMax); - // } + // // is there something to flush ? + if (mNewROFrame > mROFrameMin) { + fillOutputContainer(mNewROFrame - 1); // flush out all frames preceding the new one + } + + int nHits = hits->size(); + std::vector hitIdx(nHits); + std::iota(std::begin(hitIdx), std::end(hitIdx), 0); + // sort hits to improve memory access + std::sort(hitIdx.begin(), hitIdx.end(), + [hits](auto lhs, auto rhs) { + return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); + }); + for (int i : hitIdx) { + // (*hits)[i].Print(""); + processHit((*hits)[i], mROFrameMax, evID, srcID); + } + + // in the triggered mode store digits after every MC event + // TODO: in the real triggered mode this will not be needed, this is actually for the + // single event processing only + if (!mParams.isContinuous()) { + fillOutputContainer(mROFrameMax); + } } //_______________________________________________________________________ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) { - // // assign event time in ns - // mEventTime = irt; - // if (!mParams.isContinuous()) { - // mROFrameMin = 0; // in triggered mode reset the frame counters - // mROFrameMax = 0; - // } - // // RO frame corresponding to provided time - // mCollisionTimeWrtROF = mEventTime.timeInBCNS; // in triggered mode the ROF starts at BC (is there a delay?) - // if (mParams.isContinuous()) { - // auto nbc = mEventTime.differenceInBC(mIRFirstSampledTF); - // if (mCollisionTimeWrtROF < 0 && nbc > 0) { - // nbc--; - // } - - // // we might get interactions to digitize from before - // // the first sampled IR - // if (nbc < 0) { - // mNewROFrame = 0; - // // this event is before the first RO - // mIsBeforeFirstRO = true; - // } else { - // mNewROFrame = nbc / mParams.getROFrameLengthInBC(); - // mIsBeforeFirstRO = false; - // } - // LOG(info) << " NewROFrame " << mNewROFrame << " nbc " << nbc; - - // // in continuous mode depends on starts of periodic readout frame - // mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS; - // } else { - // mNewROFrame = 0; - // } - - // if (mNewROFrame < mROFrameMin) { - // LOG(error) << "New ROFrame " << mNewROFrame << " (" << irt << ") precedes currently cashed " << mROFrameMin; - // throw std::runtime_error("deduced ROFrame precedes already processed one"); - // } - - // if (mParams.isContinuous() && mROFrameMax < mNewROFrame) { - // mROFrameMax = mNewROFrame - 1; // all frames up to this are finished - // } + LOG(info) << "Setting event time "; + // assign event time in ns + mEventTime = irt; + if (!mParams.isContinuous()) { + mROFrameMin = 0; // in triggered mode reset the frame counters + mROFrameMax = 0; + } + // RO frame corresponding to provided time + mCollisionTimeWrtROF = mEventTime.timeInBCNS; // in triggered mode the ROF starts at BC (is there a delay?) + if (mParams.isContinuous()) { + auto nbc = mEventTime.differenceInBC(mIRFirstSampledTF); + + if (mCollisionTimeWrtROF < 0 && nbc > 0) { + nbc--; + } + + mNewROFrame = nbc / mParams.getROFrameLengthInBC(); + + LOG(info) << " NewROFrame " << mNewROFrame << " = " << nbc << "/" << mParams.getROFrameLengthInBC() << " (nbc/mParams.getROFrameLengthInBC()"; + + // in continuous mode depends on starts of periodic readout frame + mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS; + } else { + mNewROFrame = 0; + } + + if (mNewROFrame < mROFrameMin) { + LOG(error) << "New ROFrame " << mNewROFrame << " (" << irt << ") precedes currently cashed " << mROFrameMin; + throw std::runtime_error("deduced ROFrame precedes already processed one"); + } + + if (mParams.isContinuous() && mROFrameMax < mNewROFrame) { + mROFrameMax = mNewROFrame - 1; // all frames up to this are finished + } } //_______________________________________________________________________ void Digitizer::fillOutputContainer(uint32_t frameLast) { - // // fill output with digits from min.cached up to requested frame, generating the noise beforehand + // std::cout << "Entering fillOutputContainer " << std::endl; + // // // fill output with digits from min.cached up to requested frame, generating the noise beforehand // if (frameLast > mROFrameMax) { // frameLast = mROFrameMax; // } - // // make sure all buffers for extra digits are created up to the maxFrame + // // // make sure all buffers for extra digits are created up to the maxFrame // getExtraDigBuffer(mROFrameMax); - // LOG(info) << "Filling " << mGeometry->getName() << " digits output for RO frames " << mROFrameMin << ":" // << frameLast; - // o2::itsmft::ROFRecord rcROF; + // o2::itsmft::ROFRecord rcROF; /// using temporarly itsmft::ROFRecord // // we have to write chips in RO increasing order, therefore have to loop over the frames here // for (; mROFrameMin <= frameLast; mROFrameMin++) { // rcROF.setROFrame(mROFrameMin); // rcROF.setFirstEntry(mDigits->size()); // start of current ROF in digits - // auto& extra = *(mExtraBuff.front().get()); - // for (auto& chip : mChips) { + // for (auto& chip : mChips) { /// TODO: do also for ML? // if (chip.isDisabled()) { // continue; // } - // chip.addNoise(mROFrameMin, mROFrameMin, &mParams); + // // chip.addNoiseVD(mROFrameMin, mROFrameMin, &mParams); // auto& buffer = chip.getPreDigits(); // if (buffer.empty()) { // continue; @@ -226,7 +237,7 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) // mROFRecords->push_back(rcROF); // } // extra.clear(); // clear container for extra digits of the mROFrameMin ROFrame - // // and move it as a new slot in the end + // // and move it as a new slot in the end // mExtraBuff.emplace_back(mExtraBuff.front().release()); // mExtraBuff.pop_front(); // } @@ -235,233 +246,309 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) //_______________________________________________________________________ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID) { - // // convert single hit to digits - // int chipID = hit.GetDetectorID(); - // auto& chip = mChips[chipID]; - // if (chip.isDisabled()) { - // LOG(debug) << "skip disabled chip " << chipID; - // return; - // } - // float timeInROF = hit.GetTime() * sec2ns; - // if (timeInROF > 20e3) { - // const int maxWarn = 10; - // static int warnNo = 0; - // if (warnNo < maxWarn) { - // LOG(warning) << "Ignoring hit with time_in_event = " << timeInROF << " ns" - // << ((++warnNo < maxWarn) ? "" : " (suppressing further warnings)"); - // } - // return; - // } - // if (isContinuous()) { - // timeInROF += mCollisionTimeWrtROF; - // } - // if (mIsBeforeFirstRO && timeInROF < 0) { - // // disregard this hit because it comes from an event before readout starts and it does not effect this RO - // return; - // } - - // // calculate RO Frame for this hit - // if (timeInROF < 0) { - // timeInROF = 0.; - // } - // float tTot = mParams.getSignalShape().getMaxDuration(); - // // frame of the hit signal start wrt event ROFrame - // int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv()); - // // frame of the hit signal end wrt event ROFrame: in the triggered mode we read just 1 frame - // uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel; - // int nFrames = roFrameRelMax + 1 - roFrameRel; - // uint32_t roFrameMax = mNewROFrame + roFrameRelMax; - // if (roFrameMax > maxFr) { - // maxFr = roFrameMax; // if signal extends beyond current maxFrame, increase the latter - // } - - // // here we start stepping in the depth of the sensor to generate charge diffusion - // float nStepsInv = mParams.getNSimStepsInv(); - // int nSteps = mParams.getNSimSteps(); - // const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID()); - // math_utils::Vector3D xyzLocS(matrix ^ (hit.GetPosStart())); // start position in sensor frame - // math_utils::Vector3D xyzLocE(matrix ^ (hit.GetPos())); // end position in sensor frame - - // math_utils::Vector3D step(xyzLocE); - // step -= xyzLocS; - // step *= nStepsInv; // position increment at each step - // // the electrons will injected in the middle of each step - // math_utils::Vector3D stepH(step * 0.5); - // xyzLocS += stepH; - // xyzLocE -= stepH; - - // int rowS = -1, colS = -1, rowE = -1, colE = -1, nSkip = 0; - // // get entrance pixel row and col - // while (!Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), rowS, colS)) { // guard-ring ? - // if (++nSkip >= nSteps) { - // return; // did not enter to sensitive matrix - // } - // xyzLocS += step; - // } - // // get exit pixel row and col - // while (!Segmentation::localToDetector(xyzLocE.X(), xyzLocE.Z(), rowE, colE)) { // guard-ring ? - // if (++nSkip >= nSteps) { - // return; // did not enter to sensitive matrix - // } - // xyzLocE -= step; - // } - // // estimate the limiting min/max row and col where the non-0 response is possible - // if (rowS > rowE) { - // std::swap(rowS, rowE); - // } - // if (colS > colE) { - // std::swap(colS, colE); - // } - // rowS -= AlpideRespSimMat::NPix / 2; - // rowE += AlpideRespSimMat::NPix / 2; - // if (rowS < 0) { - // rowS = 0; - // } - // if (rowE >= Segmentation::NRows) { - // rowE = Segmentation::NRows - 1; - // } - // colS -= AlpideRespSimMat::NPix / 2; - // colE += AlpideRespSimMat::NPix / 2; - // if (colS < 0) { - // colS = 0; - // } - // if (colE >= Segmentation::NCols) { - // colE = Segmentation::NCols - 1; - // } - // int rowSpan = rowE - rowS + 1, colSpan = colE - colS + 1; // size of plaquet where some response is expected - - // float respMatrix[rowSpan][colSpan]; // response accumulated here - // std::fill(&respMatrix[0][0], &respMatrix[0][0] + rowSpan * colSpan, 0.f); - - // float nElectrons = hit.GetEnergyLoss() * mParams.getEnergyToNElectrons(); // total number of deposited electrons - // nElectrons *= nStepsInv; // N electrons injected per step - // if (nSkip) { - // nSteps -= nSkip; - // } - // // - // int rowPrev = -1, colPrev = -1, row, col; - // float cRowPix = 0.f, cColPix = 0.f; // local coordinated of the current pixel center - - // const o2::itsmft::AlpideSimResponse* resp = getChipResponse(chipID); - - // // take into account that the AlpideSimResponse depth defintion has different min/max boundaries - // // although the max should coincide with the surface of the epitaxial layer, which in the chip - // // local coordinates has Y = +SensorLayerThickness/2 - - // xyzLocS.SetY(xyzLocS.Y() + resp->getDepthMax() - Segmentation::SensorLayerThickness / 2.); - - // // collect charge in every pixel which might be affected by the hit - // for (int iStep = nSteps; iStep--;) { - // // Get the pixel ID - // Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), row, col); - // if (row != rowPrev || col != colPrev) { // update pixel and coordinates of its center - // if (!Segmentation::detectorToLocal(row, col, cRowPix, cColPix)) { - // continue; // should not happen - // } - // rowPrev = row; - // colPrev = col; - // } - // bool flipCol, flipRow; - // // note that response needs coordinates along column row (locX) (locZ) then depth (locY) - // auto rspmat = resp->getResponse(xyzLocS.X() - cRowPix, xyzLocS.Z() - cColPix, xyzLocS.Y(), flipRow, flipCol); - - // xyzLocS += step; - // if (!rspmat) { - // continue; - // } - - // for (int irow = AlpideRespSimMat::NPix; irow--;) { - // int rowDest = row + irow - AlpideRespSimMat::NPix / 2 - rowS; // destination row in the respMatrix - // if (rowDest < 0 || rowDest >= rowSpan) { - // continue; - // } - // for (int icol = AlpideRespSimMat::NPix; icol--;) { - // int colDest = col + icol - AlpideRespSimMat::NPix / 2 - colS; // destination column in the respMatrix - // if (colDest < 0 || colDest >= colSpan) { - // continue; - // } - // respMatrix[rowDest][colDest] += rspmat->getValue(irow, icol, flipRow, flipCol); - // } - // } - // } - - // // fire the pixels assuming Poisson(n_response_electrons) - // o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false); - // auto roFrameAbs = mNewROFrame + roFrameRel; - // for (int irow = rowSpan; irow--;) { - // uint16_t rowIS = irow + rowS; - // for (int icol = colSpan; icol--;) { - // float nEleResp = respMatrix[irow][icol]; - // if (!nEleResp) { - // continue; - // } - // int nEle = gRandom->Poisson(nElectrons * nEleResp); // total charge in given pixel - // // ignore charge which have no chance to fire the pixel - // if (nEle < mParams.getMinChargeToAccount()) { - // continue; - // } - // uint16_t colIS = icol + colS; - // if (mNoiseMap && mNoiseMap->isNoisy(chipID, rowIS, colIS)) { - // continue; - // } - // if (mDeadChanMap && mDeadChanMap->isNoisy(chipID, rowIS, colIS)) { - // continue; - // } - // // - // registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl); - // } - // } + int chipID = hit.GetDetectorID(); //// the chip ID at the moment is not referred to the chip but to a wider detector element (e.g. quarter of layer or disk in VD, stave in ML, half stave in OT) + LOG(debug) << "Processing hit for chip " << chipID << " in event " << evID << " from source " << srcID; + int subDetID = mGeometry->getSubDetID(chipID); + + int layer = mGeometry->getLayer(chipID); + int disk = mGeometry->getDisk(chipID); + + if (disk != -1) { + LOG(debug) << "Skipping disk " << disk; + return; // skipping hits on disks for the moment + } + auto& chip = mChips[chipID]; + if (chip.isDisabled()) { + LOG(debug) << "Skipping disabled chip " << chipID; + return; + } + float timeInROF = hit.GetTime() * sec2ns; + LOG(debug) << "timeInROF: " << timeInROF; + if (timeInROF > 20e3) { + const int maxWarn = 10; + static int warnNo = 0; + if (warnNo < maxWarn) { + LOG(info) << "Ignoring hit with time_in_event = " << timeInROF << " ns" + << ((++warnNo < maxWarn) ? "" : " (suppressing further warnings)"); + } + return; + } + if (isContinuous()) { + timeInROF += mCollisionTimeWrtROF; + } + if (timeInROF < 0) { + // disregard this hit because it comes from an event byefore readout starts and it does not effect this RO + LOG(debug) << "Ignoring hit with timeInROF = " << timeInROF; + return; + } + + // calculate RO Frame for this hit + if (timeInROF < 0) { + timeInROF = 0.; + } + float tTot = mParams.getSignalShape().getMaxDuration(); + // frame of the hit signal start wrt event ROFrame + int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv()); + // frame of the hit signal end wrt event ROFrame: in the triggered mode we read just 1 frame + uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel; + int nFrames = roFrameRelMax + 1 - roFrameRel; + uint32_t roFrameMax = mNewROFrame + roFrameRelMax; + if (roFrameMax > maxFr) { + maxFr = roFrameMax; // if signal extends beyond current maxFrame, increase the latter + } + + // here we start stepping in the depth of the sensor to generate charge diffusion + float nStepsInv = mParams.getNSimStepsInv(); + int nSteps = mParams.getNSimSteps(); + + const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID()); + // matrix.print(); + + /// transorm from the global detector coordinates to the local detector coordinates + math_utils::Vector3D xyzLocS(matrix ^ (hit.GetPosStart())); // start position in sensor frame + math_utils::Vector3D xyzLocE(matrix ^ (hit.GetPos())); // end position in sensor frame + + if (subDetID == 0) { // VD - need to take into account for the curved layers. TODO: consider the disks + // transform the point on the curved surface to a flat one + math_utils::Vector2D xyFlatS = Segmentation::curvedToFlat(layer, xyzLocS.x(), xyzLocS.y()); + math_utils::Vector2D xyFlatE = Segmentation::curvedToFlat(layer, xyzLocE.x(), xyzLocE.y()); + LOG(debug) << "Called curved to flat: " << xyzLocS.x() << " -> " << xyFlatS.x() << ", " << xyzLocS.y() << " -> " << xyFlatS.y(); + // update the local coordinates with the flattened ones + xyzLocS.SetXYZ(xyFlatS.x(), xyFlatS.y(), xyzLocS.Z()); + xyzLocE.SetXYZ(xyFlatE.x(), xyFlatE.y(), xyzLocE.Z()); + } + + // std::cout<<"Printing example of point in 0.35 0.35 0 in global frame: "< examplehitGlob(0.35, 0.35, 0); + // math_utils::Vector3D exampleLoc(matrix ^ (examplehitGlob)); // start position in sensor frame + // std::cout<< "Example hit in local frame: " << exampleLoc << std::endl; + // std::cout<<"Going back to glob coordinates: " << (matrix * exampleLoc) << std::endl; + + //// adapting the depth (Y) of the chip to the APTS response maximum depth + if (subDetID == 0) { + xyzLocS.SetY(xyzLocS.Y() * mSimRespVDScaleDepth); + xyzLocE.SetY(xyzLocE.Y() * mSimRespVDScaleDepth); + LOG(debug) << "rescaled: startPos Y = " << xyzLocS.Y() << ", endPos Y = " << xyzLocE.Y() << std::endl; + } else { + xyzLocS.SetY(xyzLocS.Y() * mSimRespMLOTScaleDepth); + xyzLocE.SetY(xyzLocE.Y() * mSimRespMLOTScaleDepth); + LOG(debug) << "rescaled: startPos Y = " << xyzLocS.Y() << ", endPos Y = " << xyzLocE.Y() << std::endl; + } + + math_utils::Vector3D step(xyzLocE); + step -= xyzLocS; + step *= nStepsInv; // position increment at each step + // the electrons will injected in the middle of each step + // starting from the middle of the first step + math_utils::Vector3D stepH(step * 0.5); + xyzLocS += stepH; + xyzLocE -= stepH; + + LOG(debug) << "Step into the sensitive volume: " << step; + int rowS = -1, colS = -1, rowE = -1, colE = -1, nSkip = 0; + + /// here it is the control whether the hit is in the sensitive matrix based on the segmentation + // get entrance pixel row and col + while (!Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), rowS, colS, subDetID, layer, disk)) { // guard-ring ? + if (++nSkip >= nSteps) { + LOG(debug) << "Did not enter to sensitive matrix, " << nSkip << " >= " << nSteps; + return; // did not enter to sensitive matrix + } + xyzLocS += step; + } + + // get exit pixel row and col + while (!Segmentation::localToDetector(xyzLocE.X(), xyzLocE.Z(), rowE, colE, subDetID, layer, disk)) { /// for the moment chipID = bigger element + if (++nSkip >= nSteps) { + LOG(debug) << "Did not enter to sensitive matrix, " << nSkip << " >= " << nSteps; + return; // did not enter to sensitive matrix + } + xyzLocE -= step; + } + + LOG(info) << "rowS: " << rowS << " colS: " << colS << " rowE: " << rowE << " colE: " << colE; + + int nCols = getNCols(subDetID, layer); + int nRows = getNRows(subDetID, layer); + + // estimate the limiting min/max row and col where the non-0 response is possible + if (rowS > rowE) { + std::swap(rowS, rowE); + } + if (colS > colE) { + std::swap(colS, colE); + } + rowS -= AlpideRespSimMat::NPix / 2; + rowE += AlpideRespSimMat::NPix / 2; + if (rowS < 0) { + rowS = 0; + } + if (rowE >= nRows) { + rowE = nRows - 1; + } + colS -= AlpideRespSimMat::NPix / 2; + colE += AlpideRespSimMat::NPix / 2; + if (colS < 0) { + colS = 0; + } + if (colE >= nCols) { + colE = nCols - 1; + } + int rowSpan = rowE - rowS + 1, colSpan = colE - colS + 1; // size of plaquet where some response is expected + + float respMatrix[rowSpan][colSpan]; // response accumulated here + std::fill(&respMatrix[0][0], &respMatrix[0][0] + rowSpan * colSpan, 0.f); + + float nElectrons = hit.GetEnergyLoss() * mParams.getEnergyToNElectrons(); // total number of deposited electrons + nElectrons *= nStepsInv; // N electrons injected per step + if (nSkip) { + nSteps -= nSkip; + } + + int rowPrev = -1, colPrev = -1, row, col; + float cRowPix = 0.f, cColPix = 0.f; // local coordinate of the current pixel center + + const o2::trk::ChipSimResponse* resp = getChipResponse(chipID); + // std::cout << "Printing chip response:" << std::endl; + // resp->print(); + + // take into account that the ChipSimResponse depth defintion has different min/max boundaries + // although the max should coincide with the surface of the epitaxial layer, which in the chip + // local coordinates has Y = +SensorLayerThickness/2 + xyzLocS.SetY(xyzLocS.Y() + ((subDetID == 0) ? mSimRespVDShift : mSimRespMLOTShift)); + + // collect charge in every pixel which might be affected by the hit + for (int iStep = nSteps; iStep--;) { + // Get the pixel ID + Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), row, col, subDetID, layer, disk); + if (row != rowPrev || col != colPrev) { // update pixel and coordinates of its center + if (!Segmentation::detectorToLocal(row, col, cRowPix, cColPix, subDetID, layer, disk)) { + continue; // should not happen + } + rowPrev = row; + colPrev = col; + } + bool flipCol = true, flipRow = true; + // note that response needs coordinates along column row (locX) (locZ) then depth (locY) + float rowMax{}, colMax{}; + const AlpideRespSimMat* rspmat{nullptr}; + if (subDetID == 0) { // VD + rowMax = 0.5f * Segmentation::PitchRowVD * mSimRespVDScaleX; + colMax = 0.5f * Segmentation::PitchColVD * mSimRespVDScaleZ; + rspmat = resp->getResponse(mSimRespVDScaleX * (xyzLocS.X() - cRowPix), mSimRespVDScaleZ * (xyzLocS.Z() - cColPix), xyzLocS.Y(), flipRow, flipCol, rowMax, colMax); + } else { // ML/OT + rowMax = 0.5f * Segmentation::PitchRowMLOT * mSimRespMLOTScaleX; + colMax = 0.5f * Segmentation::PitchColMLOT * mSimRespMLOTScaleZ; + rspmat = resp->getResponse(mSimRespMLOTScaleX * (xyzLocS.X() - cRowPix), mSimRespMLOTScaleZ * (xyzLocS.Z() - cColPix), xyzLocS.Y(), flipRow, flipCol, rowMax, colMax); + } + + xyzLocS += step; + + if (rspmat == nullptr) { + LOG(error) << "Error in rspmat for step " << iStep << " / " << nSteps; + continue; + } + LOG(debug) << "rspmat valid! for step " << iStep << " / " << nSteps; + // rspmat->print(); // print the response matrix for debugging + + for (int irow = AlpideRespSimMat::NPix; irow--;) { + int rowDest = row + irow - AlpideRespSimMat::NPix / 2 - rowS; // destination row in the respMatrix + if (rowDest < 0 || rowDest >= rowSpan) { + continue; + } + for (int icol = AlpideRespSimMat::NPix; icol--;) { + int colDest = col + icol - AlpideRespSimMat::NPix / 2 - colS; // destination column in the respMatrix + if (colDest < 0 || colDest >= colSpan) { + continue; + } + respMatrix[rowDest][colDest] += rspmat->getValue(irow, icol, mSimRespOrientation ? !flipRow : flipRow, flipCol); + } + } + } + + // fire the pixels assuming Poisson(n_response_electrons) + o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false); + auto roFrameAbs = mNewROFrame + roFrameRel; + for (int irow = rowSpan; irow--;) { + uint16_t rowIS = irow + rowS; + for (int icol = colSpan; icol--;) { + float nEleResp = respMatrix[irow][icol]; // value of the probability of the response in this pixel + if (nEleResp <= 1.e-36) { + continue; + } + LOG(debug) << "nEleResp: value " << nEleResp << " for pixel " << irow << " " << icol << std::endl; + int nEle = gRandom->Poisson(nElectrons * nEleResp); // total charge in given pixel = number of electrons generated in the hit multiplied by the probability of being detected in their position + LOG(debug) << "Charge detected in the pixel: " << nEle << " for pixel " << irow << " " << icol << std::endl; + // ignore charge which have no chance to fire the pixel + if (nEle < mParams.getMinChargeToAccount()) { /// TODO: substitute with the threshold? + LOG(debug) << "Ignoring pixel with nEle = " << nEle << " < min charge to account " + << mParams.getMinChargeToAccount() << " for pixel " << irow << " " << icol; + continue; + } + uint16_t colIS = icol + colS; + if (mNoiseMap && mNoiseMap->isNoisy(chipID, rowIS, colIS)) { + continue; + } + if (mDeadChanMap && mDeadChanMap->isNoisy(chipID, rowIS, colIS)) { + continue; + } + + registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl); + } + } } //________________________________________________________________________________ -void Digitizer::registerDigits(o2::itsmft::ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, +void Digitizer::registerDigits(o2::trk::ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl) { // Register digits for given pixel, accounting for the possible signal contribution to // multiple ROFrame. The signal starts at time tInROF wrt the start of provided roFrame // In every ROFrame we check the collected signal during strobe - - // float tStrobe = mParams.getStrobeDelay() - tInROF; // strobe start wrt signal start - // for (int i = 0; i < nROF; i++) { - // uint32_t roFr = roFrame + i; - // int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength()); - // tStrobe += mParams.getROFrameLength(); // for the next ROF - - // // discard too small contributions, they have no chance to produce a digit - // if (nEleROF < mParams.getMinChargeToAccount()) { - // continue; - // } - // if (roFr > mEventROFrameMax) { - // mEventROFrameMax = roFr; - // } - // if (roFr < mEventROFrameMin) { - // mEventROFrameMin = roFr; - // } - // auto key = chip.getOrderingKey(roFr, row, col); - // PreDigit* pd = chip.findDigit(key); - // if (!pd) { - // chip.addDigit(key, roFr, row, col, nEleROF, lbl); - // } else { // there is already a digit at this slot, account as PreDigitExtra contribution - // pd->charge += nEleROF; - // if (pd->labelRef.label == lbl) { // don't store the same label twice - // continue; - // } - // ExtraDig* extra = getExtraDigBuffer(roFr); - // int& nxt = pd->labelRef.next; - // bool skip = false; - // while (nxt >= 0) { - // if ((*extra)[nxt].label == lbl) { // don't store the same label twice - // skip = true; - // break; - // } - // nxt = (*extra)[nxt].next; - // } - // if (skip) { - // continue; - // } - // // new predigit will be added in the end of the chain - // nxt = extra->size(); - // extra->emplace_back(lbl); - // } - // } + LOG(debug) << "Registering digits for chip " << chip.getChipIndex() << " at ROFrame " << roFrame + << " row " << row << " col " << col << " nEle " << nEle << " label " << lbl; + float tStrobe = mParams.getStrobeDelay() - tInROF; // strobe start wrt signal start + for (int i = 0; i < nROF; i++) { + uint32_t roFr = roFrame + i; + int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength()); + tStrobe += mParams.getROFrameLength(); // for the next ROF + + // discard too small contributions, they have no chance to produce a digit + if (nEleROF < mParams.getMinChargeToAccount()) { /// use threshold instead? + continue; + } + if (roFr > mEventROFrameMax) { + mEventROFrameMax = roFr; + } + if (roFr < mEventROFrameMin) { + mEventROFrameMin = roFr; + } + auto key = chip.getOrderingKey(roFr, row, col); + o2::itsmft::PreDigit* pd = chip.findDigit(key); + if (!pd) { + chip.addDigit(key, roFr, row, col, nEleROF, lbl); + LOG(debug) << "Added digit " << key << " " << roFr << " " << row << " " << col << " " << nEleROF; + } else { // there is already a digit at this slot, account as PreDigitExtra contribution + pd->charge += nEleROF; + if (pd->labelRef.label == lbl) { // don't store the same label twice + continue; + } + ExtraDig* extra = getExtraDigBuffer(roFr); + int& nxt = pd->labelRef.next; + bool skip = false; + while (nxt >= 0) { + if ((*extra)[nxt].label == lbl) { // don't store the same label twice + skip = true; + break; + } + nxt = (*extra)[nxt].next; + } + if (skip) { + continue; + } + // new predigit will be added in the end of the chain + nxt = extra->size(); + extra->emplace_back(lbl); + } + } } From 271a51963a3692f5cf9b83951153f2bae9c8b523 Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Thu, 21 Aug 2025 14:03:55 +0200 Subject: [PATCH 4/8] ALICE3-TRK: adjusted curvedToFlat coordinate orientation --- .../ALICE3/TRK/base/include/TRKBase/SegmentationChip.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h index d00fb68925c4c..3d99dc6f3fae6 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h @@ -236,8 +236,8 @@ class SegmentationChip // the y position is in the silicon volume however we need the chip volume (silicon+metalstack) // this is accounted by a y shift - float xFlat = -constants::VD::petal::layer::radii[layer] * phi; /// this is equal to the circumference segment covered between y=0 and the phi angle - float yFlat = dist - constants::VD::petal::layer::radii[layer]; + float xFlat = constants::VD::petal::layer::radii[layer] * phi; /// this is equal to the circumference segment covered between y=0 and the phi angle + float yFlat = constants::VD::petal::layer::radii[layer] - dist; return math_utils::Vector2D(xFlat, yFlat); } @@ -253,8 +253,8 @@ class SegmentationChip static constexpr math_utils::Vector2D flatToCurved(int layer, float xFlat, float yFlat) noexcept { // Revert the curvedToFlat transformation - float dist = yFlat + constants::VD::petal::layer::radii[layer]; - float phi = -xFlat / constants::VD::petal::layer::radii[layer]; + float dist = constants::VD::petal::layer::radii[layer] - yFlat; + float phi = xFlat / constants::VD::petal::layer::radii[layer]; // the y position is in the chip volume however we need the silicon volume // this is accounted by a -y shift float xCurved = dist * std::cos(phi); From 167c823030305fb939c7cb0ff21034274027920c Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Fri, 22 Aug 2025 18:14:53 +0200 Subject: [PATCH 5/8] ALICE3-TRK: first version of complete digitizer. Now the digits are stored in the trkdigits.root file --- .../include/TRKSimulation/DPLDigitizerParam.h | 2 +- .../include/TRKSimulation/DigiParams.h | 25 +-- .../include/TRKSimulation/Digitizer.h | 4 +- .../ALICE3/TRK/simulation/src/Digitizer.cxx | 186 ++++++++++-------- .../src/TRKDigitizerSpec.cxx | 7 +- 5 files changed, 124 insertions(+), 100 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DPLDigitizerParam.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DPLDigitizerParam.h index 59b3551ecbd32..584ffaa3aff75 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DPLDigitizerParam.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DPLDigitizerParam.h @@ -39,7 +39,7 @@ struct DPLDigitizerParam : public o2::conf::ConfigurableParamHelper; ///< container for extra contributions to PreDigits @@ -174,7 +174,5 @@ class Digitizer : public TObject const o2::itsmft::NoiseMap* mDeadChanMap = nullptr; const o2::itsmft::NoiseMap* mNoiseMap = nullptr; - - ClassDef(Digitizer, 1); }; } // namespace o2::trk diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index b3bf393e5ac93..1f50954217b04 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -62,22 +62,29 @@ void Digitizer::init() /// setting scale factors to adapt to the APTS response function (adjusting pitch and Y shift) // TODO: adjust Y shift when the geometry is improved + LOG(debug) << " Depth max: " << mChipSimRespVD->getDepthMax(); + LOG(debug) << " Depth min: " << mChipSimRespVD->getDepthMin(); + + float thicknessVD = 0.0095; // cm --- hardcoded based on geometry currently present + float thicknessMLOT = 0.1; // cm --- hardcoded based on geometry currently present + mSimRespVDScaleX = o2::trk::constants::apts::pitchX / o2::trk::SegmentationChip::PitchRowVD; mSimRespVDScaleZ = o2::trk::constants::apts::pitchZ / o2::trk::SegmentationChip::PitchColVD; - mSimRespVDScaleDepth = o2::trk::constants::apts::thickness / (0.1); /// introducing this scaling factor because the silicon thickness for the moment is 1 mm -> rescale to 45 um which is the depth of the APTS response - mSimRespVDShift = mChipSimRespVD->getDepthMax() - 0.1 * mSimRespVDScaleDepth / 2.f; // the shift should be done considering the rescaling done to adapt to the wrong silicon thickness. TODO: remove the scaling factor for the depth when the silicon thickness match the simulated response + mSimRespVDScaleDepth = o2::trk::constants::apts::thickness / (thicknessVD); /// introducing this scaling factor because the silicon thickness for the moment is 1 mm -> rescale to 45 um which is the depth of the APTS response + // mSimRespVDShift = mChipSimRespVD->getDepthMax() - thicknessVD * mSimRespVDScaleDepth / 2.f; // the shift should be done considering the rescaling done to adapt to the wrong silicon thickness. TODO: remove the scaling factor for the depth when the silicon thickness match the simulated response + mSimRespVDShift = mChipSimRespVD->getDepthMax(); // the curved, rescaled, sensors have a width from 0 to -45. Must add 10 um (= max depth) to match the APTS response. mSimRespMLOTScaleX = o2::trk::constants::apts::pitchX / o2::trk::SegmentationChip::PitchRowMLOT; mSimRespMLOTScaleZ = o2::trk::constants::apts::pitchZ / o2::trk::SegmentationChip::PitchColMLOT; - mSimRespMLOTScaleDepth = o2::trk::constants::apts::thickness / (0.1); /// introducing this scaling factor because the silicon thickness for the moment is 1 mm -> rescale to 45 um which is the depth of the APTS response - mSimRespMLOTShift = mChipSimRespMLOT->getDepthMax() - 0.1 * mSimRespMLOTScaleDepth / 2.f; // the shift should be done considering the rescaling done to adapt to the wrong silicon thickness. TODO: remove the scaling factor for the depth when the silicon thickness match the simulated response - mSimRespOrientation = true; + mSimRespMLOTScaleDepth = o2::trk::constants::apts::thickness / (thicknessMLOT); /// introducing this scaling factor because the silicon thickness for the moment is 1 mm -> rescale to 45 um which is the depth of the APTS response + mSimRespMLOTShift = mChipSimRespMLOT->getDepthMax() - thicknessMLOT * mSimRespMLOTScaleDepth / 2.f; // the shift should be done considering the rescaling done to adapt to the wrong silicon thickness. TODO: remove the scaling factor for the depth when the silicon thickness match the simulated response + mSimRespOrientation = false; // importing the parameters from DPLDigitizerParam.h auto& dOptTRK = DPLDigitizerParam::Instance(); LOGP(info, "TRK Digitizer is initialised."); mParams.print(); - LOGP(info, "VD shift = {} = {} - {} ; ML/OT shift = {} = {} - {}", mSimRespVDShift, mChipSimRespVD->getDepthMax(), 0.1 * mSimRespVDScaleDepth / 2.f, mSimRespMLOTShift, mChipSimRespMLOT->getDepthMax(), 0.1 * mSimRespMLOTScaleDepth / 2.f); + LOGP(info, "VD shift = {} ; ML/OT shift = {} = {} - {}", mSimRespVDShift, mSimRespMLOTShift, mChipSimRespMLOT->getDepthMax(), thicknessMLOT * mSimRespMLOTScaleDepth / 2.f); LOGP(info, "VD pixel scale on x = {} ; z = {}", mSimRespVDScaleX, mSimRespVDScaleZ); LOGP(info, "ML/OT pixel scale on x = {} ; z = {}", mSimRespMLOTScaleX, mSimRespMLOTScaleZ); LOGP(info, "Response orientation: {}", mSimRespOrientation ? "flipped" : "normal"); @@ -125,7 +132,6 @@ void Digitizer::process(const std::vector* hits, int evID, int srcID) return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); }); for (int i : hitIdx) { - // (*hits)[i].Print(""); processHit((*hits)[i], mROFrameMax, evID, srcID); } @@ -179,75 +185,78 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) //_______________________________________________________________________ void Digitizer::fillOutputContainer(uint32_t frameLast) { - // std::cout << "Entering fillOutputContainer " << std::endl; - // // // fill output with digits from min.cached up to requested frame, generating the noise beforehand - // if (frameLast > mROFrameMax) { - // frameLast = mROFrameMax; - // } - // // // make sure all buffers for extra digits are created up to the maxFrame - // getExtraDigBuffer(mROFrameMax); - // LOG(info) << "Filling " << mGeometry->getName() << " digits output for RO frames " << mROFrameMin << ":" - // << frameLast; - - // o2::itsmft::ROFRecord rcROF; /// using temporarly itsmft::ROFRecord - - // // we have to write chips in RO increasing order, therefore have to loop over the frames here - // for (; mROFrameMin <= frameLast; mROFrameMin++) { - // rcROF.setROFrame(mROFrameMin); - // rcROF.setFirstEntry(mDigits->size()); // start of current ROF in digits - // auto& extra = *(mExtraBuff.front().get()); - // for (auto& chip : mChips) { /// TODO: do also for ML? - // if (chip.isDisabled()) { - // continue; - // } - // // chip.addNoiseVD(mROFrameMin, mROFrameMin, &mParams); - // auto& buffer = chip.getPreDigits(); - // if (buffer.empty()) { - // continue; - // } - // auto itBeg = buffer.begin(); - // auto iter = itBeg; - // ULong64_t maxKey = chip.getOrderingKey(mROFrameMin + 1, 0, 0) - 1; // fetch digits with key below that - // for (; iter != buffer.end(); ++iter) { - // if (iter->first > maxKey) { - // break; // is the digit ROFrame from the key > the max requested frame - // } - // auto& preDig = iter->second; // preDigit - // if (preDig.charge >= mParams.getChargeThreshold()) { - // int digID = mDigits->size(); - // mDigits->emplace_back(chip.getChipIndex(), preDig.row, preDig.col, preDig.charge); - // mMCLabels->addElement(digID, preDig.labelRef.label); - // auto& nextRef = preDig.labelRef; // extra contributors are in extra array - // while (nextRef.next >= 0) { - // nextRef = extra[nextRef.next]; - // mMCLabels->addElement(digID, nextRef.label); - // } - // } - // } - // buffer.erase(itBeg, iter); - // } - // // finalize ROF record - // rcROF.setNEntries(mDigits->size() - rcROF.getFirstEntry()); // number of digits - // if (isContinuous()) { - // rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC()); - // } else { - // rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay? - // } - // if (mROFRecords) { - // mROFRecords->push_back(rcROF); - // } - // extra.clear(); // clear container for extra digits of the mROFrameMin ROFrame - // // and move it as a new slot in the end - // mExtraBuff.emplace_back(mExtraBuff.front().release()); - // mExtraBuff.pop_front(); - // } + std::cout << "Entering fillOutputContainer " << std::endl; + std::cout << "Digit size before fill: " << mDigits->size() << std::endl; + // // fill output with digits from min.cached up to requested frame, generating the noise beforehand + if (frameLast > mROFrameMax) { + frameLast = mROFrameMax; + } + // // make sure all buffers for extra digits are created up to the maxFrame + getExtraDigBuffer(mROFrameMax); + LOG(info) << "Filling " << mGeometry->getName() << " digits output for RO frames " << mROFrameMin << ":" + << frameLast; + + o2::itsmft::ROFRecord rcROF; /// using temporarly itsmft::ROFRecord + + // we have to write chips in RO increasing order, therefore have to loop over the frames here + for (; mROFrameMin <= frameLast; mROFrameMin++) { + std::cout << "Entering ROFrame " << mROFrameMin << std::endl; + rcROF.setROFrame(mROFrameMin); + rcROF.setFirstEntry(mDigits->size()); // start of current ROF in digits + + auto& extra = *(mExtraBuff.front().get()); + for (auto& chip : mChips) { + if (chip.isDisabled()) { + continue; + } + // chip.addNoise(mROFrameMin, mROFrameMin, &mParams); /// TODO: add noise + auto& buffer = chip.getPreDigits(); + if (buffer.empty()) { + continue; + } + auto itBeg = buffer.begin(); + auto iter = itBeg; + ULong64_t maxKey = chip.getOrderingKey(mROFrameMin + 1, 0, 0) - 1; // fetch digits with key below that + for (; iter != buffer.end(); ++iter) { + if (iter->first > maxKey) { + break; // is the digit ROFrame from the key > the max requested frame + } + auto& preDig = iter->second; // preDigit + if (preDig.charge >= mParams.getChargeThreshold()) { + int digID = mDigits->size(); + mDigits->emplace_back(chip.getChipIndex(), preDig.row, preDig.col, preDig.charge); + LOG(debug) << "Adding digit ID: " << digID << " with chipID: " << chip.getChipIndex() << ", row: " << preDig.row << ", col: " << preDig.col << ", charge: " << preDig.charge; + mMCLabels->addElement(digID, preDig.labelRef.label); + auto& nextRef = preDig.labelRef; // extra contributors are in extra array + while (nextRef.next >= 0) { + nextRef = extra[nextRef.next]; + mMCLabels->addElement(digID, nextRef.label); + } + } + } + buffer.erase(itBeg, iter); + } + // finalize ROF record + rcROF.setNEntries(mDigits->size() - rcROF.getFirstEntry()); // number of digits + if (isContinuous()) { + rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC()); + } else { + rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay? + } + if (mROFRecords->size()) { + mROFRecords->push_back(rcROF); + } + extra.clear(); // clear container for extra digits of the mROFrameMin ROFrame + // and move it as a new slot in the end + mExtraBuff.emplace_back(mExtraBuff.front().release()); + mExtraBuff.pop_front(); + } } //_______________________________________________________________________ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID) { int chipID = hit.GetDetectorID(); //// the chip ID at the moment is not referred to the chip but to a wider detector element (e.g. quarter of layer or disk in VD, stave in ML, half stave in OT) - LOG(debug) << "Processing hit for chip " << chipID << " in event " << evID << " from source " << srcID; int subDetID = mGeometry->getSubDetID(chipID); int layer = mGeometry->getLayer(chipID); @@ -257,6 +266,8 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID LOG(debug) << "Skipping disk " << disk; return; // skipping hits on disks for the moment } + + LOG(debug) << "Processing hit for chip " << chipID; auto& chip = mChips[chipID]; if (chip.isDisabled()) { LOG(debug) << "Skipping disabled chip " << chipID; @@ -325,15 +336,15 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID // std::cout<<"Going back to glob coordinates: " << (matrix * exampleLoc) << std::endl; //// adapting the depth (Y) of the chip to the APTS response maximum depth + LOG(debug) << "local original: startPos = " << xyzLocS << ", endPos = " << xyzLocE << std::endl; if (subDetID == 0) { xyzLocS.SetY(xyzLocS.Y() * mSimRespVDScaleDepth); xyzLocE.SetY(xyzLocE.Y() * mSimRespVDScaleDepth); - LOG(debug) << "rescaled: startPos Y = " << xyzLocS.Y() << ", endPos Y = " << xyzLocE.Y() << std::endl; } else { xyzLocS.SetY(xyzLocS.Y() * mSimRespMLOTScaleDepth); xyzLocE.SetY(xyzLocE.Y() * mSimRespMLOTScaleDepth); - LOG(debug) << "rescaled: startPos Y = " << xyzLocS.Y() << ", endPos Y = " << xyzLocE.Y() << std::endl; } + LOG(debug) << "rescaled Y: startPos = " << xyzLocS << ", endPos = " << xyzLocE << std::endl; math_utils::Vector3D step(xyzLocE); step -= xyzLocS; @@ -344,7 +355,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID xyzLocS += stepH; xyzLocE -= stepH; - LOG(debug) << "Step into the sensitive volume: " << step; + LOG(debug) << "Step into the sensitive volume: " << step << ". Number of steps: " << nSteps; int rowS = -1, colS = -1, rowE = -1, colE = -1, nSkip = 0; /// here it is the control whether the hit is in the sensitive matrix based on the segmentation @@ -366,8 +377,6 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID xyzLocE -= step; } - LOG(info) << "rowS: " << rowS << " colS: " << colS << " rowE: " << rowE << " colE: " << colE; - int nCols = getNCols(subDetID, layer); int nRows = getNRows(subDetID, layer); @@ -428,7 +437,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID rowPrev = row; colPrev = col; } - bool flipCol = true, flipRow = true; + bool flipCol = false, flipRow = false; // note that response needs coordinates along column row (locX) (locZ) then depth (locY) float rowMax{}, colMax{}; const AlpideRespSimMat* rspmat{nullptr}; @@ -442,13 +451,24 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID rspmat = resp->getResponse(mSimRespMLOTScaleX * (xyzLocS.X() - cRowPix), mSimRespMLOTScaleZ * (xyzLocS.Z() - cColPix), xyzLocS.Y(), flipRow, flipCol, rowMax, colMax); } + float tempPitchX = 0, tempPitchZ = 0; + if (subDetID == 0) { + tempPitchX = Segmentation::PitchRowVD; + tempPitchZ = Segmentation::PitchColVD; + } else { + tempPitchX = Segmentation::PitchRowMLOT; + tempPitchZ = Segmentation::PitchColMLOT; + } + LOG(debug) << "X and Z inside pixel at start = " << (xyzLocS.X() - cRowPix) << " , " << (xyzLocS.Z() - cColPix) << ", rescaled: " << mSimRespMLOTScaleX * (xyzLocS.X() - cRowPix) << " , " << mSimRespMLOTScaleZ * (xyzLocS.Z() - cColPix); + LOG(debug) << "Hit inside pitch? X: " << ((xyzLocS.X() - cRowPix) < tempPitchX) << " Z: " << ((xyzLocS.Z() - cColPix) < tempPitchZ); + xyzLocS += step; if (rspmat == nullptr) { - LOG(error) << "Error in rspmat for step " << iStep << " / " << nSteps; + LOG(debug) << "Error in rspmat for step " << iStep << " / " << nSteps; continue; } - LOG(debug) << "rspmat valid! for step " << iStep << " / " << nSteps; + LOG(debug) << "rspmat valid! for step " << iStep << " / " << nSteps << ", (row,col) = (" << row << "," << col << ")"; // rspmat->print(); // print the response matrix for debugging for (int irow = AlpideRespSimMat::NPix; irow--;) { @@ -469,9 +489,10 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID // fire the pixels assuming Poisson(n_response_electrons) o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false); auto roFrameAbs = mNewROFrame + roFrameRel; - for (int irow = rowSpan; irow--;) { - uint16_t rowIS = irow + rowS; - for (int icol = colSpan; icol--;) { + LOG(debug) << "Spanning through rows and columns; rowspan = " << rowSpan << " colspan = " << colSpan << " = " << colE << " - " << colS << " +1 " << std::endl; + for (int irow = rowSpan; irow--;) { // irow ranging from 4 to 0 + uint16_t rowIS = irow + rowS; // row distant irow from the row of the hit start + for (int icol = colSpan; icol--;) { // icol ranging from 4 to 0 float nEleResp = respMatrix[irow][icol]; // value of the probability of the response in this pixel if (nEleResp <= 1.e-36) { continue; @@ -485,7 +506,8 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID << mParams.getMinChargeToAccount() << " for pixel " << irow << " " << icol; continue; } - uint16_t colIS = icol + colS; + + uint16_t colIS = icol + colS; // col distant icol from the col of the hit start if (mNoiseMap && mNoiseMap->isNoisy(chipID, rowIS, colIS)) { continue; } diff --git a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx index cb375936744d5..0ed276237bd86 100644 --- a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx @@ -93,7 +93,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer timer.Start(); LOG(info) << " CALLING TRK DIGITIZATION "; - // mDigitizer.setDigits(&mDigits); + mDigitizer.setDigits(&mDigits); mDigitizer.setROFRecords(&mROFRecords); mDigitizer.setMCLabels(&mLabels); @@ -104,8 +104,10 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer // accumulate result of single event processing, called after processing every event supplied // AND after the final flushing via digitizer::fillOutputContainer if (mDigits.empty()) { + LOG(debug) << "No digits to accumulate"; return; // no digits were flushed, nothing to accumulate } + LOG(debug) << "Accumulating " << mDigits.size() << " digits "; auto ndigAcc = digitsAccum.size(); std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(digitsAccum)); @@ -139,7 +141,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer mLabels.clear(); mDigits.clear(); mROFRecords.clear(); - }; // and accumulate lambda + }; // end accumulate lambda auto& eventParts = context->getEventParts(withQED); // loop over all composite collisions given from context (aka loop over all the interaction records) @@ -172,6 +174,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer accumulate(); } mDigitizer.fillOutputContainer(); + LOG(debug) << "mDigits size after fill: " << mDigits.size(); accumulate(); // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output) From f0a812003f46694c47f4b9584e9cd544e0cac225 Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Mon, 25 Aug 2025 13:54:52 +0200 Subject: [PATCH 6/8] ALICE3-TRK: fixing DigitROF setting --- .../Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index 1f50954217b04..5518cd0366d9b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -131,6 +131,7 @@ void Digitizer::process(const std::vector* hits, int evID, int srcID) [hits](auto lhs, auto rhs) { return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); }); + LOG(info) << "Processing " << nHits << " hits"; for (int i : hitIdx) { processHit((*hits)[i], mROFrameMax, evID, srcID); } @@ -185,8 +186,6 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) //_______________________________________________________________________ void Digitizer::fillOutputContainer(uint32_t frameLast) { - std::cout << "Entering fillOutputContainer " << std::endl; - std::cout << "Digit size before fill: " << mDigits->size() << std::endl; // // fill output with digits from min.cached up to requested frame, generating the noise beforehand if (frameLast > mROFrameMax) { frameLast = mROFrameMax; @@ -200,7 +199,6 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) // we have to write chips in RO increasing order, therefore have to loop over the frames here for (; mROFrameMin <= frameLast; mROFrameMin++) { - std::cout << "Entering ROFrame " << mROFrameMin << std::endl; rcROF.setROFrame(mROFrameMin); rcROF.setFirstEntry(mDigits->size()); // start of current ROF in digits @@ -243,7 +241,7 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) } else { rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay? } - if (mROFRecords->size()) { + if (mROFRecords) { mROFRecords->push_back(rcROF); } extra.clear(); // clear container for extra digits of the mROFrameMin ROFrame @@ -279,7 +277,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID const int maxWarn = 10; static int warnNo = 0; if (warnNo < maxWarn) { - LOG(info) << "Ignoring hit with time_in_event = " << timeInROF << " ns" + LOG(warning) << "Ignoring hit with time_in_event = " << timeInROF << " ns" << ((++warnNo < maxWarn) ? "" : " (suppressing further warnings)"); } return; From 58f735c1286bdc31098d8e47777e461af74d592a Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Mon, 25 Aug 2025 12:14:20 +0000 Subject: [PATCH 7/8] Please consider the following formatting changes --- .../Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h | 2 +- Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx | 1 - Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h index 3d99dc6f3fae6..100af5be1b4d0 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/SegmentationChip.h @@ -253,7 +253,7 @@ class SegmentationChip static constexpr math_utils::Vector2D flatToCurved(int layer, float xFlat, float yFlat) noexcept { // Revert the curvedToFlat transformation - float dist = constants::VD::petal::layer::radii[layer] - yFlat; + float dist = constants::VD::petal::layer::radii[layer] - yFlat; float phi = xFlat / constants::VD::petal::layer::radii[layer]; // the y position is in the chip volume however we need the silicon volume // this is accounted by a -y shift diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx index 7cc4e8109f6dd..98460adf8224c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx @@ -17,7 +17,6 @@ #include "TRKSimulation/DigiParams.h" #include - using namespace o2::trk; DigiParams::DigiParams() diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index 5518cd0366d9b..cc89f0eff1a54 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -278,7 +278,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID static int warnNo = 0; if (warnNo < maxWarn) { LOG(warning) << "Ignoring hit with time_in_event = " << timeInROF << " ns" - << ((++warnNo < maxWarn) ? "" : " (suppressing further warnings)"); + << ((++warnNo < maxWarn) ? "" : " (suppressing further warnings)"); } return; } From 726823867593fcfbc95034fd17d8ea6bb66e9a87 Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Mon, 25 Aug 2025 14:19:53 +0200 Subject: [PATCH 8/8] ALICE3-TRK: fixing copyright headers --- Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx index 98460adf8224c..df6f46ac0ecb0 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx @@ -1,4 +1,3 @@ - // 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.