From abe0a3d901ba269a2973544f39823e7626192054 Mon Sep 17 00:00:00 2001 From: scannito Date: Mon, 9 Mar 2026 15:58:36 +0100 Subject: [PATCH 1/7] TRKLayer refactoring --- .../base/include/TRKBase/GeometryTGeo_copy.h | 246 ++++ .../base/include/TRKBase/TRKBaseParam_copy.h | 52 + .../ALICE3/TRK/base/src/GeometryTGeo_copy.cxx | 1253 +++++++++++++++++ .../include/TRKSimulation/Detector_copy.h | 128 ++ .../include/TRKSimulation/TRKLayer_copy.h | 135 ++ .../TRK/simulation/src/Detector_copy.cxx | 542 +++++++ .../TRK/simulation/src/TRKLayer_copy.cxx | 358 +++++ 7 files changed, 2714 insertions(+) create mode 100644 Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo_copy.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam_copy.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo_copy.cxx create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector_copy.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer_copy.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector_copy.cxx create mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer_copy.cxx diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo_copy.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo_copy.h new file mode 100644 index 0000000000000..21d86378f59ec --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo_copy.h @@ -0,0 +1,246 @@ +// 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. + +#ifndef ALICEO2_TRK_GEOMETRYTGEO_H +#define ALICEO2_TRK_GEOMETRYTGEO_H + +#include +#include +#include "DetectorsCommonDataFormats/DetID.h" +#include "TRKBase/TRKBaseParam.h" + +namespace o2 +{ +namespace trk +{ +class GeometryTGeo : public o2::detectors::DetMatrixCache +{ + public: + using Mat3D = o2::math_utils::Transform3D; + using DetMatrixCache::getMatrixL2G; + using DetMatrixCache::getMatrixT2GRot; + using DetMatrixCache::getMatrixT2L; + // this method is not advised for ITS: for barrel detectors whose tracking frame is just a rotation + // it is cheaper to use T2GRot + using DetMatrixCache::getMatrixT2G; + GeometryTGeo(bool build = false, int loadTrans = 0); + ~GeometryTGeo(); + void Build(int loadTrans); + void fillMatrixCache(int mask); + static GeometryTGeo* Instance() + { + if (!sInstance) { + sInstance = std::make_unique(true, 0); + } + return sInstance.get(); + }; + static const char* getTRKVolPattern() { return sVolumeName.c_str(); } + static const char* getTRKLayerPattern() { return sLayerName.c_str(); } + static const char* getTRKPetalAssemblyPattern() { return sPetalAssemblyName.c_str(); } + static const char* getTRKPetalPattern() { return sPetalName.c_str(); } + static const char* getTRKPetalDiskPattern() { return sPetalDiskName.c_str(); } + static const char* getTRKPetalLayerPattern() { return sPetalLayerName.c_str(); } + static const char* getTRKStavePattern() { return sStaveName.c_str(); } + static const char* getTRKHalfStavePattern() { return sHalfStaveName.c_str(); } + static const char* getTRKModulePattern() { return sModuleName.c_str(); } + static const char* getTRKChipPattern() { return sChipName.c_str(); } + static const char* getTRKSensorPattern() { return sSensorName.c_str(); } + static const char* getTRKDeadzonePattern() { return sDeadzoneName.c_str(); } + static const char* getTRKMetalStackPattern() { return sMetalStackName.c_str(); } + + static const char* getTRKWrapVolPattern() { return sWrapperVolumeName.c_str(); } + + int getNumberOfChips() const { return mSize; } + + /// Determines the number of active parts in the Geometry + int extractNumberOfLayersMLOT(); + int extractNumberOfLayersVD() const; + int extractNumberOfPetalsVD() const; + int extractNumberOfActivePartsVD() const; + int extractNumberOfDisksVD() const; + int extractNumberOfChipsPerPetalVD() const; + int extractNumberOfStavesMLOT(int lay) const; + int extractNumberOfHalfStavesMLOT(int lay) const; + int extractNumberOfModulesMLOT(int lay) const; + int extractNumberOfChipsMLOT(int lay) const; + + /// Extract number following the prefix in the name string + int extractVolumeCopy(const char* name, const char* prefix) const; + + int getNumberOfLayersMLOT() const { return mNumberOfLayersMLOT; } + int getNumberOfActivePartsVD() const { return mNumberOfActivePartsVD; } + int getNumberOfHalfStaves(int lay) const { return mNumberOfHalfStaves[lay]; } + + bool isOwner() const { return mOwner; } + 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 mod, int chip) const; + + int getSubDetID(int index) const; + int getPetalCase(int index) const; + int getDisk(int index) const; + int getLayer(int index) const; + int getStave(int index) const; + int getHalfStave(int index) const; + int getModule(int index) const; + int getChip(int index) const; + + void defineMLOTSensors(); + int getBarrelLayer(int) const; + + // sensor ref X and alpha for ML & OT + void extractSensorXAlphaMLOT(int, float&, float&); + + // cache for tracking frames (ML & OT) + bool isTrackingFrameCachedMLOT() const { return !mCacheRefXMLOT.empty(); } + void fillTrackingFramesCacheMLOT(); + + float getSensorRefAlphaMLOT(int chipId) const + { + assert(getSubDetID(chipId) != 0 && "Called MLOT getter with VD chipId"); + const int local = chipId - getNumberOfActivePartsVD(); + assert(local >= 0 && local < (int)mCacheRefAlphaMLOT.size()); + return mCacheRefAlphaMLOT[local]; + } + + float getSensorXMLOT(int chipId) const + { + assert(getSubDetID(chipId) != 0 && "Called MLOT getter with VD chipId"); + const int local = chipId - getNumberOfActivePartsVD(); + assert(local >= 0 && local < (int)mCacheRefXMLOT.size()); + return mCacheRefXMLOT[local]; + } + + // create matrix for tracking to local frame for MLOT + TGeoHMatrix& createT2LMatrixMLOT(int); + + /// This routine computes the chip index number from the subDetID, petal, disk, layer, stave /// TODO: retrieve also from chip when chips will be available + /// This routine computes the chip index number from the subDetID, petal, disk, layer, stave, half stave, module, chip + /// \param int subDetID The subdetector ID, 0 for VD, 1 for MLOT + /// \param int petalcase The petal case number for VD, from 0 to 3 + /// \param int disk The disk number for VD, from 0 to 5 + /// \param int lay The layer number. Starting from 0 both for VD and MLOT + /// \param int stave The stave number for MLOT. Starting from 0 + /// \param int halfstave The half stave number for MLOT. Can be 0 or 1 + /// \param int module The module number for MLOT, from 0 to 10 (or 20) + /// \param int chip The chip number for MLOT, from 0 to 8 + unsigned short getChipIndex(int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int mod, int chip) const; + + /// This routine computes the chip index number from the subDetID, volume, layer, stave, half stave, module, chip + /// \param int subDetID The subdetector ID, 0 for VD, 1 for MLOT + /// \param int volume is needed only with the current configuration for VD where each single element is a volume. // TODO: when the geometry naming scheme will be changed, change this method + /// \param int lay The layer number for the MLOT. In the current configuration for VD this is not needed. // TODO: when the geometry naming scheme will be changed, change this method + /// \param int stave The stave number in each layer for MLOT. Starting from 0. + /// \param int halfstave The half stave number for MLOT. Can be 0 or 1 + /// \param int module The module number for MLOT, from 0 to 10 (or 20) + /// \param int chip The chip number for MLOT, from 0 to 8 + unsigned short getChipIndex(int subDetID, int volume, int lay, int stave, int halfstave, int mod, int chip) const; + + /// This routine computes subDetID, petal, disk, layer, stave, half stave, module, chip, given the chip index number + /// \param int index The chip index number, starting from 0 + /// \param int subDetID The subdetector ID, 0 for VD, 1 for MLOT + /// \param int petalcase The petal case number for VD, from 0 to 3 + /// \param int disk The disk number for VD, from 0 to 5 + /// \param int lay The layer number. Starting from 0 both for VD and MLOT + /// \param int stave The stave number for MLOT. Starting from 0 + /// \param int halfstave The half stave number for MLOT. Can be 0 or 1 + /// \param int module The module number for MLOT, from 0 to 10 (or 20) + /// \param int chip The chip number for MLOT, from 0 to 8 + bool getChipID(int index, int& subDetID, int& petalcase, int& disk, int& lay, int& stave, int& halfstave, int& mod, int& chip) const; + + unsigned short getLastChipIndex(int lay) const { return mLastChipIndex[lay]; } + unsigned short getFirstChipIndex(int lay, int petalcase, int subDetID) const + { + /// Get the first chip index of the active petal (VD) or layer (MLOT) + if (subDetID == 0) { // VD + return (petalcase == 0) ? 0 : mLastChipIndexVD[petalcase - 1] + 1; + } else if (subDetID == 1) { // MLOT + return mLastChipIndex[lay + mNumberOfPetalsVD - 1] + 1; + } + return -1; // not found + } + + /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) + /// for a given chip 'index' by quering the TGeoManager + TGeoHMatrix* extractMatrixSensor(int index) const; + + TString getMatrixPath(int index) const; + +#ifdef ENABLE_UPGRADES + static const char* composeSymNameTRK(int d) + { + return Form("%s_%d", o2::detectors::DetID(o2::detectors::DetID::TRK).getName(), d); + } +#endif + + static const char* composeSymNameLayer(int d, int layer); + static const char* composeSymNameStave(int d, int layer); + static const char* composeSymNameModule(int d, int layer); + static const char* composeSymNameChip(int d, int layer); + static const char* composeSymNameSensor(int d, int layer); + + protected: + static constexpr int MAXLAYERS = 20; ///< max number of active layers + + static std::string sVolumeName; + static std::string sLayerName; + static std::string sPetalAssemblyName; + static std::string sPetalName; + static std::string sPetalDiskName; + static std::string sPetalLayerName; + static std::string sStaveName; + static std::string sHalfStaveName; + static std::string sModuleName; + static std::string sChipName; + static std::string sSensorName; + static std::string sDeadzoneName; + static std::string sMetalStackName; + + static std::string sWrapperVolumeName; ///< Wrapper volume name, not implemented at the moment + + Int_t mNumberOfLayersMLOT; ///< number of layers + Int_t mNumberOfActivePartsVD; ///< number of layers + Int_t mNumberOfLayersVD; ///< number of layers + Int_t mNumberOfPetalsVD; ///< number of Petals = chip in each VD layer + Int_t mNumberOfDisksVD; ///< number of Disks = 6 + std::vector mNumberOfStaves; ///< Number Of Staves per layer in ML/OT + std::vector mNumberOfHalfStaves; ///< Number Of Half staves in each stave of the layer in ML/OT + std::vector mNumberOfModules; ///< Number Of Modules per stave (half stave) in ML/OT + std::vector mNumberOfChips; ///< number of chips per module in ML/OT + std::vector mNumberOfChipsPerLayerVD; ///< number of chips per layer VD ( = number of petals) + std::vector mNumberOfChipsPerLayerMLOT; ///< number of chips per layer MLOT + std::vector mNumbersOfChipPerDiskVD; ///< numbersOfChipPerDiskVD + std::vector mNumberOfChipsPerPetalVD; ///< numbersOfChipPerPetalVD + // std::vector mNumberOfChipsPerStave; ///< number of chips per stave in ML/OT + // std::vector mNumberOfChipsPerHalfStave; ///< number of chips per half stave in ML/OT + // std::vector mNumberOfChipsPerModule; ///< number of chips per module in ML/OT + std::vector mLastChipIndex; ///< max ID of the detctor in the petal(VD) or layer(MLOT) + std::vector mLastChipIndexVD; ///< max ID of the detctor in the layer for the VD + std::vector mLastChipIndexMLOT; ///< max ID of the detctor in the layer for the MLOT + + std::array mLayerToWrapper; ///< Layer to wrapper correspondence, not implemented yet + + bool mOwner = true; //! is it owned by the singleton? + + std::vector sensorsMLOT; + std::vector mCacheRefXMLOT; /// cache for X of ML and OT + std::vector mCacheRefAlphaMLOT; /// cache for sensor ref alpha ML and OT + + eMLOTLayout mLayoutMLOT; // ML and OT detector layout design + + private: + static std::unique_ptr sInstance; +}; + +} // namespace trk +} // namespace o2 +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam_copy.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam_copy.h new file mode 100644 index 0000000000000..e43c85e9dc070 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam_copy.h @@ -0,0 +1,52 @@ +// 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. + +#ifndef O2_TRK_BASEPARAM_H +#define O2_TRK_BASEPARAM_H + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +enum eVDLayout { + kIRIS4 = 0, + kIRISFullCyl, + kIRISFullCyl3InclinedWalls, + kIRIS5, + kIRIS4a, +}; + +namespace trk +{ +enum eMLOTLayout { + kCylindrical = 0, + kSegmented, +}; + +struct TRKBaseParam : public o2::conf::ConfigurableParamHelper { + std::string configFile = ""; + float serviceTubeX0 = 0.02f; // X0 Al2O3 + Bool_t irisOpen = false; + + eVDLayout layoutVD = kIRIS4; // VD detector layout design + eMLOTLayout layoutMLOT = kSegmented; // ML and OT detector layout design + + eVDLayout getLayoutVD() const { return layoutVD; } + eMLOTLayout getLayoutMLOT() const { return layoutMLOT; } + + O2ParamDef(TRKBaseParam, "TRKBase"); +}; + +} // end namespace trk +} // end namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo_copy.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo_copy.cxx new file mode 100644 index 0000000000000..93c0171543eca --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo_copy.cxx @@ -0,0 +1,1253 @@ +// 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. + +#include +#include +#include "TRKBase/SegmentationChip.h" +#include + +#include + +using Segmentation = o2::trk::SegmentationChip; + +namespace o2 +{ +namespace trk +{ +std::unique_ptr GeometryTGeo::sInstance; + +// Names +std::string GeometryTGeo::sVolumeName = "TRKV"; +std::string GeometryTGeo::sLayerName = "TRKLayer"; +std::string GeometryTGeo::sPetalAssemblyName = "PETAL"; +std::string GeometryTGeo::sPetalName = "PETALCASE"; +std::string GeometryTGeo::sPetalDiskName = "DISK"; +std::string GeometryTGeo::sPetalLayerName = "LAYER"; +std::string GeometryTGeo::sStaveName = "TRKStave"; +std::string GeometryTGeo::sHalfStaveName = "TRKHalfStave"; +std::string GeometryTGeo::sModuleName = "TRKModule"; +std::string GeometryTGeo::sChipName = "TRKChip"; +std::string GeometryTGeo::sSensorName = "TRKSensor"; +std::string GeometryTGeo::sDeadzoneName = "TRKDeadzone"; +std::string GeometryTGeo::sMetalStackName = "TRKMetalStack"; + +std::string GeometryTGeo::sWrapperVolumeName = "TRKUWrapVol"; ///< Wrapper volume name, not implemented at the moment + +o2::trk::GeometryTGeo::~GeometryTGeo() +{ + if (!mOwner) { + mOwner = true; + sInstance.release(); + } +} +GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : DetMatrixCache(detectors::DetID::TRK) +{ + if (sInstance) { + LOGP(fatal, "Invalid use of public constructor: o2::trk::GeometryTGeo instance exists"); + } + mLayerToWrapper.fill(-1); + if (build) { + Build(loadTrans); + } +} + +//__________________________________________________________________________ +void GeometryTGeo::Build(int loadTrans) +{ + ///// current geometry organization: + ///// total elements = x staves (*2 half staves if staggered geometry) * 8 layers ML+OT + 4 petal cases * (3 layers + 6 disks) + ///// indexing from 0 to 35: VD petals -> layers -> disks + ///// indexing from 36 to y: MLOT staves + + if (isBuilt()) { + LOGP(warning, "Already built"); + return; // already initialized + } + + if (gGeoManager == nullptr) { + LOGP(fatal, "Geometry is not loaded"); + } + + mLayoutMLOT = o2::trk::TRKBaseParam::Instance().getLayoutMLOT(); + + LOG(debug) << "Overall layout ML and OT: " << mLayoutMLOT; + + mNumberOfLayersMLOT = extractNumberOfLayersMLOT(); + mNumberOfPetalsVD = extractNumberOfPetalsVD(); + mNumberOfActivePartsVD = extractNumberOfActivePartsVD(); + mNumberOfLayersVD = extractNumberOfLayersVD(); + mNumberOfDisksVD = extractNumberOfDisksVD(); + + mNumberOfStaves.resize(mNumberOfLayersMLOT); + mNumberOfHalfStaves.resize(mNumberOfLayersMLOT); + mNumberOfModules.resize(mNumberOfLayersMLOT); + mNumberOfChips.resize(mNumberOfLayersMLOT); + + mNumberOfChipsPerLayerVD.resize(mNumberOfLayersVD); + mNumberOfChipsPerLayerMLOT.resize(mNumberOfLayersMLOT); + mNumbersOfChipPerDiskVD.resize(mNumberOfDisksVD); + mNumberOfChipsPerPetalVD.resize(mNumberOfPetalsVD); + + mLastChipIndex.resize(mNumberOfPetalsVD + mNumberOfLayersMLOT); + mLastChipIndexVD.resize(mNumberOfPetalsVD); + mLastChipIndexMLOT.resize(mNumberOfLayersMLOT); /// ML and OT are part of TRK as the same detector, without disks + + for (int i = 0; i < mNumberOfLayersMLOT; i++) { + mNumberOfStaves[i] = extractNumberOfStavesMLOT(i); + mNumberOfHalfStaves[i] = extractNumberOfHalfStavesMLOT(i); + mNumberOfModules[i] = extractNumberOfModulesMLOT(i); + mNumberOfChips[i] = extractNumberOfChipsMLOT(i); + } + + int numberOfChipsTotal = 0; + + /// filling the information for the VD + for (int i = 0; i < mNumberOfPetalsVD; i++) { + mNumberOfChipsPerPetalVD[i] = extractNumberOfChipsPerPetalVD(); + numberOfChipsTotal += mNumberOfChipsPerPetalVD[i]; + mLastChipIndex[i] = numberOfChipsTotal - 1; + mLastChipIndexVD[i] = numberOfChipsTotal - 1; + } + + /// filling the information for the MLOT + for (int i = 0; i < mNumberOfLayersMLOT; i++) { + mNumberOfChipsPerLayerMLOT[i] = mNumberOfStaves[i] * mNumberOfHalfStaves[i] * mNumberOfModules[i] * mNumberOfChips[i]; + numberOfChipsTotal += mNumberOfChipsPerLayerMLOT[i]; + mLastChipIndex[i + mNumberOfPetalsVD] = numberOfChipsTotal - 1; + mLastChipIndexMLOT[i] = numberOfChipsTotal - 1; + } + + setSize(numberOfChipsTotal); + defineMLOTSensors(); + fillTrackingFramesCacheMLOT(); + fillMatrixCache(loadTrans); +} + +//__________________________________________________________________________ +int GeometryTGeo::getSubDetID(int index) const +{ + if (index <= mLastChipIndexVD[mLastChipIndexVD.size() - 1]) { + return 0; + } else if (index > mLastChipIndexVD[mLastChipIndexVD.size() - 1]) { + return 1; + } + return -1; /// not found +} + +//__________________________________________________________________________ +int GeometryTGeo::getPetalCase(int index) const +{ + int petalcase = 0; + + int subDetID = getSubDetID(index); + if (subDetID == 1) { + return -1; + } else if (index <= mLastChipIndexVD[mNumberOfPetalsVD - 1]) { + while (index > mLastChipIndexVD[petalcase]) { + petalcase++; + } + } + return petalcase; +} + +//__________________________________________________________________________ +int GeometryTGeo::getDisk(int index) const +{ + int subDetID = getSubDetID(index); + int petalcase = getPetalCase(index); + + if (subDetID == 0) { /// VD + if (index % mNumberOfChipsPerPetalVD[petalcase] < mNumberOfLayersVD) { + return -1; /// layers + } + return (index % mNumberOfChipsPerPetalVD[petalcase]) - mNumberOfLayersVD; + } + + return -1; /// not found or ML/OT +} + +//__________________________________________________________________________ +int GeometryTGeo::getLayer(int index) const +{ + int subDetID = getSubDetID(index); + int petalcase = getPetalCase(index); + int lay = 0; + + if (subDetID == 0) { /// VD + if (index % mNumberOfChipsPerPetalVD[petalcase] >= mNumberOfLayersVD) { + return -1; /// disks + } + return index % mNumberOfChipsPerPetalVD[petalcase]; + } else if (subDetID == 1) { /// MLOT + while (index > mLastChipIndex[lay]) { + lay++; + } + return lay - mNumberOfPetalsVD; /// numeration of MLOT layers starting from 0 + } + return -1; /// -1 if not found +} +//__________________________________________________________________________ +int GeometryTGeo::getStave(int index) const +{ + int subDetID = getSubDetID(index); + int lay = getLayer(index); + int petalcase = getPetalCase(index); + + if (subDetID == 0) { /// VD + return -1; + } else if (subDetID == 1) { /// MLOT + int lay = getLayer(index); + index -= getFirstChipIndex(lay, petalcase, subDetID); // get the index of the sensing element in the layer + + const int Nhs = mNumberOfHalfStaves[lay]; + const int Nmod = mNumberOfModules[lay]; + const int Nchip = mNumberOfChips[lay]; + + if (Nhs == 2) { + int chipsPerModule = Nchip; + int chipsPerHalfStave = Nmod * chipsPerModule; + int chipsPerStave = Nhs * chipsPerHalfStave; + return index / chipsPerStave; + } else if (Nhs == 1) { + int chipsPerModule = Nchip; + int chipsPerStave = Nmod * chipsPerModule; + return index / chipsPerStave; + } + } + return -1; +} + +//__________________________________________________________________________ +int GeometryTGeo::getHalfStave(int index) const +{ + int subDetID = getSubDetID(index); + int lay = getLayer(index); + int petalcase = getPetalCase(index); + + if (subDetID == 0) { /// VD + return -1; + } else if (subDetID == 1) { /// MLOT + int lay = getLayer(index); + index -= getFirstChipIndex(lay, petalcase, subDetID); // get the index of the sensing element in the layer + + const int Nhs = mNumberOfHalfStaves[lay]; + const int Nmod = mNumberOfModules[lay]; + const int Nchip = mNumberOfChips[lay]; + + int chipsPerModule = Nchip; + int chipsPerHalfStave = Nmod * chipsPerModule; + int chipsPerStave = Nhs * chipsPerHalfStave; + + int rem = index % chipsPerStave; + return rem / chipsPerHalfStave; // 0 = left, 1 = right + } + return -1; +} + +//__________________________________________________________________________ +int GeometryTGeo::getModule(int index) const +{ + int subDetID = getSubDetID(index); + int lay = getLayer(index); + int petalcase = getPetalCase(index); + + if (subDetID == 0) { /// VD + return -1; + } else if (subDetID == 1) { /// MLOT + int lay = getLayer(index); + index -= getFirstChipIndex(lay, petalcase, subDetID); // get the index of the sensing element in the layer + + const int Nhs = mNumberOfHalfStaves[lay]; + const int Nmod = mNumberOfModules[lay]; + const int Nchip = mNumberOfChips[lay]; + + if (Nhs == 2) { + int chipsPerModule = Nchip; + int chipsPerHalfStave = Nmod * chipsPerModule; + int rem = index % (Nhs * chipsPerHalfStave); + rem = rem % chipsPerHalfStave; + return rem / chipsPerModule; + } else if (Nhs == 1) { + int chipsPerModule = Nchip; + int rem = index % (Nmod * chipsPerModule); + return rem / chipsPerModule; + } + } + return -1; +} + +//__________________________________________________________________________ +int GeometryTGeo::getChip(int index) const +{ + int subDetID = getSubDetID(index); + int lay = getLayer(index); + int petalcase = getPetalCase(index); + + if (subDetID == 0) { /// VD + return -1; + } else if (subDetID == 1) { /// MLOT + int lay = getLayer(index); + index -= getFirstChipIndex(lay, petalcase, subDetID); // get the index of the sensing element in the layer + + const int Nhs = mNumberOfHalfStaves[lay]; + const int Nmod = mNumberOfModules[lay]; + const int Nchip = mNumberOfChips[lay]; + + if (Nhs == 2) { + int chipsPerModule = Nchip; + return index % chipsPerModule; + } else if (Nhs == 1) { + int chipsPerModule = Nchip; + return index % chipsPerModule; + } + } + return -1; +} + +//__________________________________________________________________________ +unsigned short GeometryTGeo::getChipIndex(int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int mod, int chip) const +{ + if (subDetID == 0) { // VD + if (lay == -1) { // disk + return getFirstChipIndex(lay, petalcase, subDetID) + mNumberOfLayersVD + disk; + } else { // layer + return getFirstChipIndex(lay, petalcase, subDetID) + lay; + } + } else if (subDetID == 1) { // MLOT + const int Nhs = mNumberOfHalfStaves[lay]; // 1 or 2 + const int Nmod = mNumberOfModules[lay]; // module per half-stave (per stave if Nhs==1) + const int Nchip = mNumberOfChips[lay]; // chips per module + + if (Nhs == 2) { // staggered geometry: layer -> stave -> halfstave -> mod -> chip + int chipsPerModule = Nchip; + int chipsPerHalfStave = Nmod * chipsPerModule; + int chipsPerStave = Nhs * chipsPerHalfStave; + return getFirstChipIndex(lay, petalcase, subDetID) + stave * chipsPerStave + halfstave * chipsPerHalfStave + mod * chipsPerModule + chip; + } else if (Nhs == 1) { // turbo geometry: layer -> stave -> mod -> chip (no halfstave) + int chipsPerModule = Nchip; + int chipsPerStave = Nmod * chipsPerModule; + return getFirstChipIndex(lay, petalcase, subDetID) + stave * chipsPerStave + mod * chipsPerModule + chip; + } + } + + LOGP(warning, "Chip index not found for subDetID %d, petalcase %d, disk %d, layer %d, stave %d, halfstave %d, module %d, chip %d, returning numeric limit", subDetID, petalcase, disk, lay, stave, halfstave, mod, chip); + return std::numeric_limits::max(); // not found +} + +//__________________________________________________________________________ +unsigned short GeometryTGeo::getChipIndex(int subDetID, int volume, int lay, int stave, int halfstave, int mod, int chip) const +{ + if (subDetID == 0) { // VD + return volume; /// In the current configuration for VD, each volume is the sensor element = chip. // TODO: when the geometry naming scheme will be changed, change this method + + } else if (subDetID == 1) { // MLOT + const int Nhs = mNumberOfHalfStaves[lay]; // 1 or 2 + const int Nmod = mNumberOfModules[lay]; // module per half-stave (per stave if Nhs==1) + const int Nchip = mNumberOfChips[lay]; // chips per module + + if (Nhs == 2) { // staggered geometry: layer -> stave -> halfstave -> mod -> chip + int chipsPerModule = Nchip; + int chipsPerHalfStave = Nmod * chipsPerModule; + int chipsPerStave = Nhs * chipsPerHalfStave; + return getFirstChipIndex(lay, -1, subDetID) + stave * chipsPerStave + halfstave * chipsPerHalfStave + mod * chipsPerModule + chip; + } else if (Nhs == 1) { // turbo geometry: layer -> stave -> mod -> chip (no halfstave) + int chipsPerModule = Nchip; + int chipsPerStave = Nmod * chipsPerModule; + return getFirstChipIndex(lay, -1, subDetID) + stave * chipsPerStave + mod * chipsPerModule + chip; + } + } + + LOGP(warning, "Chip index not found for subDetID %d, volume %d, layer %d, stave %d, halfstave %d, module %d, chip %d, returning numeric limit", subDetID, volume, lay, stave, halfstave, mod, chip); + return std::numeric_limits::max(); // not found +} + +//__________________________________________________________________________ +bool GeometryTGeo::getChipID(int index, int& subDetID, int& petalcase, int& disk, int& lay, int& stave, int& halfstave, int& mod, int& chip) const +{ + subDetID = getSubDetID(index); + petalcase = getPetalCase(index); + disk = getDisk(index); + lay = getLayer(index); + stave = getStave(index); + if (mNumberOfHalfStaves[lay] == 2) { + halfstave = getHalfStave(index); + } else { + halfstave = 0; // if not staggered geometry, return 0 + } + halfstave = getHalfStave(index); + mod = getModule(index); + chip = getChip(index); + + return kTRUE; +} + +//__________________________________________________________________________ +TString GeometryTGeo::getMatrixPath(int index) const +{ + + int subDetID, petalcase, disk, layer, stave, halfstave, mod, chip; + getChipID(index, subDetID, petalcase, disk, layer, stave, halfstave, mod, chip); + + // PrintChipID(index, subDetID, petalcase, disk, layer, stave, halfstave, mod, chip); + + // 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()); + + // handling cylindrical configuration for ML and/or OT + // needed because of the different numbering scheme in the geometry for the cylindrical case wrt the staggered and turbo ones + if (subDetID == 1) { + if ((layer < 4 && mLayoutMLOT == eMLOTLayout::kCylindrical) || (layer > 3 && mLayoutMLOT == MLOTLayout::kCylindrical)) { + stave = 1; + mod = 1; + chip = 1; + } + } + + // build the path + if (subDetID == 0) { // VD + if (disk >= 0) { + path += Form("%s_%d_%d/", getTRKPetalAssemblyPattern(), petalcase, petalcase + 1); // PETAL_n + 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_%d/", getTRKPetalAssemblyPattern(), petalcase, petalcase + 1); // PETAL_n + 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/", getTRKHalfStavePattern(), layer, halfstave); // TRKHalfStavex_y + } + path += Form("%s%d_%d/", getTRKModulePattern(), layer, mod); // TRKModulx_y + path += Form("%s%d_%d/", getTRKChipPattern(), layer, chip); // TRKChipx_y + path += Form("%s%d_1/", getTRKSensorPattern(), layer); // TRKSensorx_1 + } + return path; +} + +//__________________________________________________________________________ +TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const +{ + // extract matrix transforming from the PHYSICAL sensor frame to global one + // 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. + + 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 + // 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 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; + // } + // std::cout<<"-----"<GetVolume(getTRKVolPattern()); + if (trkV == nullptr) { + LOG(fatal) << getName() << " volume " << getTRKVolPattern() << " is not in the geometry"; + } + + // Loop on all TRKV nodes, count Layer volumes by checking names + // Build on the fly layer - wrapper correspondence + TObjArray* nodes = trkV->GetNodes(); + // nodes->Print(); + int nNodes = nodes->GetEntriesFast(); + for (int j = 0; j < nNodes; j++) { + int lrID = -1; + auto nd = dynamic_cast(nodes->At(j)); + const char* name = nd->GetName(); + if (strstr(name, getTRKLayerPattern()) != nullptr) { + numberOfLayers++; + if ((lrID = extractVolumeCopy(name, GeometryTGeo::getTRKLayerPattern())) < 0) { + LOG(fatal) << "Failed to extract layer ID from the " << name; + } + mLayerToWrapper[lrID] = -1; // not wrapped + } else if (strstr(name, getTRKWrapVolPattern()) != nullptr) { // this is a wrapper volume, may cointain layers + int wrID = -1; + if ((wrID = extractVolumeCopy(name, GeometryTGeo::getTRKWrapVolPattern())) < 0) { + LOG(fatal) << "Failed to extract wrapper ID from the " << name; + } + TObjArray* nodesW = nd->GetNodes(); + int nNodesW = nodesW->GetEntriesFast(); + + for (int jw = 0; jw < nNodesW; jw++) { + auto ndW = dynamic_cast(nodesW->At(jw))->GetName(); + if (strstr(ndW, getTRKLayerPattern()) != nullptr) { + if ((lrID = extractVolumeCopy(ndW, GeometryTGeo::getTRKLayerPattern())) < 0) { + LOGP(fatal, "Failed to extract layer ID from wrapper volume '{}' from one of its nodes '{}'", name, ndW); + } + numberOfLayers++; + mLayerToWrapper[lrID] = wrID; + } + } + } + } + return numberOfLayers; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfPetalsVD() const +{ + int numberOfPetals = 0; + TGeoVolume* trkV = gGeoManager->GetVolume(getTRKVolPattern()); + if (!trkV) { + LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); + return 0; + } + + // Loop on all TRKV nodes, count PETAL assemblies and their contents + TObjArray* nodes = trkV->GetNodes(); + if (!nodes) { + LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); + return 0; + } + + LOGP(info, "Searching for petal assemblies in {} (pattern: {})", + getTRKVolPattern(), getTRKPetalAssemblyPattern()); + + for (int j = 0; j < nodes->GetEntriesFast(); j++) { + auto* nd = dynamic_cast(nodes->At(j)); + const char* name = nd->GetName(); + + if (strstr(name, getTRKPetalAssemblyPattern()) != nullptr) { + numberOfPetals++; + LOGP(info, "Found petal assembly: {}", name); + + // Get petal volume and its nodes for debugging + TGeoVolume* petalVol = nd->GetVolume(); + if (petalVol) { + TObjArray* petalNodes = petalVol->GetNodes(); + if (petalNodes) { + LOGP(debug, "Petal {} contains {} child nodes", name, petalNodes->GetEntriesFast()); + // Print all nodes in this petal + for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { + auto* petalNode = dynamic_cast(petalNodes->At(k)); + LOGP(debug, " Node {}: {}", k, petalNode->GetName()); + } + } else { + LOGP(warning, "Petal {} has no child nodes", name); + } + } else { + LOGP(warning, "Petal {} has no volume", name); + } + } + } + + if (numberOfPetals == 0) { + LOGP(warning, "No petal assemblies found in geometry"); + } else { + LOGP(info, "Found {} petal assemblies", numberOfPetals); + } + + return numberOfPetals; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfActivePartsVD() const +{ + // The number of active parts returned here is 36 = 4 petals * (3 layers + 6 disks) + int numberOfParts = 0; + TGeoVolume* vdV = gGeoManager->GetVolume(getTRKVolPattern()); + if (!vdV) { + LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); + return 0; + } + + // Find first petal to count its active parts + TObjArray* nodes = vdV->GetNodes(); + if (!nodes) { + LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); + return 0; + } + + bool petalFound = false; + + for (int j = 0; j < nodes->GetEntriesFast(); j++) { + auto* nd = dynamic_cast(nodes->At(j)); + const char* name = nd->GetName(); + if (strstr(name, getTRKPetalAssemblyPattern()) == nullptr) { + continue; + } + + petalFound = true; + LOGP(info, "Counting active parts in petal: {}", name); + + // Found a petal, count its layers and disks + TGeoVolume* petalVol = nd->GetVolume(); + if (!petalVol) { + LOGP(warning, "Petal {} has no volume", name); + break; + } + + TObjArray* petalNodes = petalVol->GetNodes(); + if (!petalNodes) { + LOGP(warning, "Petal {} has no child nodes", name); + break; + } + + for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { + auto* petalNode = dynamic_cast(petalNodes->At(k)); + const char* nodeName = petalNode->GetName(); + + if (strstr(nodeName, getTRKPetalLayerPattern()) != nullptr || + strstr(nodeName, getTRKPetalDiskPattern()) != nullptr) { + numberOfParts++; + LOGP(debug, "Found active part in {}: {}", name, nodeName); + } + } + // We only need to check one petal as they're identical + break; + } + + if (!petalFound) { + LOGP(warning, "No petal assembly found matching pattern '{}'", getTRKPetalAssemblyPattern()); + return 0; + } + + if (numberOfParts == 0) { + LOGP(warning, "No active parts (layers/disks) found in petal"); + return 0; + } + + // Multiply by number of petals since all petals are identical + int totalParts = numberOfParts * mNumberOfPetalsVD; + LOGP(info, "Total number of active parts: {} ({}*{})", + totalParts, numberOfParts, mNumberOfPetalsVD); + return totalParts; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfDisksVD() const +{ + // Count disks in the first petal (all petals are identical) + int numberOfDisks = 0; + TGeoVolume* vdV = gGeoManager->GetVolume(getTRKVolPattern()); + if (!vdV) { + LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); + return 0; + } + + // Find first petal + TObjArray* nodes = vdV->GetNodes(); + if (!nodes) { + LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); + return 0; + } + + bool petalFound = false; + + for (int j = 0; j < nodes->GetEntriesFast(); j++) { + auto* nd = dynamic_cast(nodes->At(j)); + if (strstr(nd->GetName(), getTRKPetalAssemblyPattern()) == nullptr) { + continue; + } + + petalFound = true; + LOGP(info, "Counting disks in petal: {}", nd->GetName()); + + // Count disks in this petal + TGeoVolume* petalVol = nd->GetVolume(); + if (!petalVol) { + LOGP(warning, "Petal {} has no volume", nd->GetName()); + break; + } + + TObjArray* petalNodes = petalVol->GetNodes(); + if (!petalNodes) { + LOGP(warning, "Petal {} has no child nodes", nd->GetName()); + break; + } + + for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { + auto* petalNode = dynamic_cast(petalNodes->At(k)); + if (strstr(petalNode->GetName(), getTRKPetalDiskPattern()) != nullptr) { + numberOfDisks++; + LOGP(info, "Found disk in {} : {}", nd->GetName(), petalNode->GetName()); + } + } + // One petal is enough + break; + } + + if (!petalFound) { + LOGP(warning, "No petal assembly found matching pattern '{}'", getTRKPetalAssemblyPattern()); + } + + if (numberOfDisks == 0) { + LOGP(warning, "No disks found in VD geometry"); + } + + return numberOfDisks; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfLayersVD() const +{ + // Count layers in the first petal (all petals are identical) + int numberOfLayers = 0; + TGeoVolume* vdV = gGeoManager->GetVolume(getTRKVolPattern()); + if (!vdV) { + LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); + return 0; + } + + // Find first petal + TObjArray* nodes = vdV->GetNodes(); + if (!nodes) { + LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); + return 0; + } + + bool petalFound = false; + + for (int j = 0; j < nodes->GetEntriesFast(); j++) { + auto* nd = dynamic_cast(nodes->At(j)); + if (strstr(nd->GetName(), getTRKPetalAssemblyPattern()) == nullptr) { + continue; + } + + petalFound = true; + LOGP(info, "Counting layers in petal: {}", nd->GetName()); + + // Count layers in this petal + TGeoVolume* petalVol = nd->GetVolume(); + if (!petalVol) { + LOGP(warning, "Petal {} has no volume", nd->GetName()); + break; + } + + TObjArray* petalNodes = petalVol->GetNodes(); + if (!petalNodes) { + LOGP(warning, "Petal {} has no child nodes", nd->GetName()); + break; + } + + for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { + auto* petalNode = dynamic_cast(petalNodes->At(k)); + if (strstr(petalNode->GetName(), getTRKPetalLayerPattern()) != nullptr) { + numberOfLayers++; + LOGP(info, "Found layer in {} : {}", nd->GetName(), petalNode->GetName()); + } + } + // One petal is enough + break; + } + + if (!petalFound) { + LOGP(warning, "No petal assembly found matching pattern '{}'", getTRKPetalAssemblyPattern()); + } + + if (numberOfLayers == 0) { + LOGP(warning, "No layers found in VD geometry"); + } + + return numberOfLayers; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfChipsPerPetalVD() const +{ + // The number of chips per petal returned here is 9 for each layer = number of layers + number of quarters of disks per petal + int numberOfChips = 0; + TGeoVolume* vdV = gGeoManager->GetVolume(getTRKVolPattern()); + if (!vdV) { + LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); + return 0; + } + + // Find first petal assembly + TObjArray* nodes = vdV->GetNodes(); + if (!nodes) { + LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); + return 0; + } + + bool petalFound = false; + + for (int j = 0; j < nodes->GetEntriesFast(); j++) { + auto* nd = dynamic_cast(nodes->At(j)); + const char* name = nd->GetName(); + if (strstr(name, getTRKPetalAssemblyPattern()) == nullptr) { + continue; + } + + petalFound = true; + LOGP(info, "Counting chips in petal: {}", name); + + // Found a petal, count sensors in its layers and disks + TGeoVolume* petalVol = nd->GetVolume(); + if (!petalVol) { + LOGP(warning, "Petal {} has no volume", name); + break; + } + + TObjArray* petalNodes = petalVol->GetNodes(); + if (!petalNodes) { + LOGP(warning, "Petal {} has no child nodes", name); + break; + } + + for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { + auto* petalNode = dynamic_cast(petalNodes->At(k)); + const char* nodeName = petalNode->GetName(); + TGeoVolume* vol = petalNode->GetVolume(); + + if (!vol) { + LOGP(debug, "Node {} has no volume", nodeName); + continue; + } + + // Look for sensors in this volume + TObjArray* subNodes = vol->GetNodes(); + if (!subNodes) { + LOGP(debug, "Node {} has no sub-nodes", nodeName); + continue; + } + + for (int i = 0; i < subNodes->GetEntriesFast(); i++) { + auto* subNode = dynamic_cast(subNodes->At(i)); + if (strstr(subNode->GetName(), getTRKChipPattern()) != nullptr) { + numberOfChips++; + LOGP(debug, "Found chip in {}: {}", nodeName, subNode->GetName()); + } + } + } + // We only need one petal + break; + } + + if (!petalFound) { + LOGP(warning, "No petal assembly found matching pattern '{}'", getTRKPetalAssemblyPattern()); + } + + if (numberOfChips == 0) { + LOGP(warning, "No chips/sensors found in VD petal"); + } + + LOGP(info, "Number of chips per petal: {}", numberOfChips); + return numberOfChips; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfStavesMLOT(int lay) const +{ + int numberOfStaves = 0; + + std::string layName = Form("%s%d", getTRKLayerPattern(), lay); + TGeoVolume* layV = gGeoManager->GetVolume(layName.c_str()); + + if (layV == nullptr) { + LOG(fatal) << getName() << " volume " << getTRKLayerPattern() << " is not in the geometry"; + } + + // Loop on all layV nodes, count Layer volumes by checking names + TObjArray* nodes = layV->GetNodes(); + // std::cout << "Printing nodes for layer " << lay << std::endl; + // nodes->Print(); + int nNodes = nodes->GetEntriesFast(); + + for (int j = 0; j < nNodes; j++) { + int lrID = -1; + auto nd = dynamic_cast(nodes->At(j)); /// layer node + const char* name = nd->GetName(); + if (strstr(name, getTRKStavePattern()) != nullptr) { + numberOfStaves++; + } + } + return numberOfStaves; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfHalfStavesMLOT(int lay) const +{ + int numberOfHalfStaves = 0; + + std::string staveName = Form("%s%d", getTRKStavePattern(), lay); + TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str()); + + if (staveV == nullptr) { + LOG(fatal) << getName() << " volume " << getTRKStavePattern() << " is not in the geometry"; + } + + // Loop on all layV nodes, count Layer volumes by checking names + TObjArray* nodes = staveV->GetNodes(); + // std::cout << "Printing nodes for layer " << lay << std::endl; + // nodes->Print(); + int nNodes = nodes->GetEntriesFast(); + + for (int j = 0; j < nNodes; j++) { + auto nd = dynamic_cast(nodes->At(j)); /// layer node + const char* name = nd->GetName(); + if (strstr(name, getTRKHalfStavePattern()) != nullptr) { + numberOfHalfStaves++; + } + } + + if (numberOfHalfStaves == 0) { + numberOfHalfStaves = 1; /// in case of turbo geometry, there is no half stave volume, but only stave volume + } + return numberOfHalfStaves; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfModulesMLOT(int lay) const +{ + int numberOfModules = 0; + + std::string staveName = Form("%s%d", (mNumberOfHalfStaves[lay] == 2 ? getTRKHalfStavePattern() : getTRKStavePattern()), lay); + TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str()); + + if (staveV == nullptr) { + LOG(fatal) << getName() << " volume " << (mNumberOfHalfStaves[lay] == 2 ? getTRKHalfStavePattern() : getTRKStavePattern()) << " is not in the geometry"; + } + + // Loop on all staveV nodes, count Module volumes by checking names + TObjArray* nodes = staveV->GetNodes(); + int nNodes = nodes->GetEntriesFast(); + + for (int j = 0; j < nNodes; j++) { + auto nd = dynamic_cast(nodes->At(j)); /// stave node + const char* name = nd->GetName(); + if (strstr(name, getTRKModulePattern()) != nullptr) { + numberOfModules++; + } + } + return numberOfModules; +} + +//__________________________________________________________________________ +int GeometryTGeo::extractNumberOfChipsMLOT(int lay) const +{ + int numberOfChips = 0; + + std::string moduleName = Form("%s%d", getTRKModulePattern(), lay); + TGeoVolume* moduleV = gGeoManager->GetVolume(moduleName.c_str()); + + if (moduleV == nullptr) { + LOG(fatal) << getName() << " volume " << getTRKModulePattern() << " is not in the geometry"; + } + + // Loop on all moduleV nodes, count Chip volumes by checking names + TObjArray* nodes = moduleV->GetNodes(); + int nNodes = nodes->GetEntriesFast(); + + for (int j = 0; j < nNodes; j++) { + auto nd = dynamic_cast(nodes->At(j)); /// module node + const char* name = nd->GetName(); + if (strstr(name, getTRKChipPattern()) != nullptr) { + numberOfChips++; + } + } + return numberOfChips; +} + +//__________________________________________________________________________ +void GeometryTGeo::PrintChipID(int index, int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int mod, int chip) const +{ + std::cout << "\nindex = " << index << std::endl; + std::cout << "subDetID = " << subDetID << std::endl; + std::cout << "petalcase = " << petalcase << std::endl; + std::cout << "layer = " << lay << std::endl; + std::cout << "disk = " << disk << std::endl; + 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 << "module = " << mod << std::endl; + std::cout << "chip = " << chip << std::endl; +} + +//__________________________________________________________________________ +void GeometryTGeo::Print(Option_t*) const +{ + if (!isBuilt()) { + LOGF(info, "Geometry not built yet!"); + return; + } + std::cout << "Detector ID: " << sInstance.get()->getDetID() << std::endl; + + LOGF(info, "Summary of GeometryTGeo: %s", getName()); + LOGF(info, "Number of layers ML + OL: %d", mNumberOfLayersMLOT); + LOGF(info, "Number of active parts VD: %d", mNumberOfActivePartsVD); + LOGF(info, "Number of layers VD: %d", mNumberOfLayersVD); + LOGF(info, "Number of petals VD: %d", mNumberOfPetalsVD); + LOGF(info, "Number of disks VD: %d", mNumberOfDisksVD); + LOGF(info, "Number of chips per petal VD: "); + for (int i = 0; i < mNumberOfPetalsVD; i++) { + LOGF(info, "%d", mNumberOfChipsPerPetalVD[i]); + } + LOGF(info, "Number of staves and half staves per layer MLOT: "); + for (int i = 0; i < mNumberOfLayersMLOT; i++) { + std::string mlot = ""; + mlot = (i < 4) ? "ML" : "OT"; + LOGF(info, "Layer: %d, %s, %d staves, %d half staves per stave", i, mlot.c_str(), mNumberOfStaves[i], mNumberOfHalfStaves[i]); + } + LOGF(info, "Number of modules per stave (half stave) in each ML(OT) layer: "); + for (int i = 0; i < mNumberOfLayersMLOT; i++) { + LOGF(info, "%d", mNumberOfModules[i]); + } + LOGF(info, "Number of chips per module MLOT: "); + for (int i = 0; i < mNumberOfLayersMLOT; i++) { + LOGF(info, "%d", mNumberOfChips[i]); + } + LOGF(info, "Number of chips per layer MLOT: "); + for (int i = 0; i < mNumberOfLayersMLOT; i++) { + LOGF(info, "%d", mNumberOfChipsPerLayerMLOT[i]); + } + LOGF(info, "Total number of chips: %d", getNumberOfChips()); + + std::cout << "mLastChipIndex = ["; + for (int i = 0; i < mLastChipIndex.size(); i++) { + std::cout << mLastChipIndex[i]; + if (i < mLastChipIndex.size() - 1) { + std::cout << ", "; + } + } + std::cout << "]" << std::endl; + std::cout << "mLastChipIndexVD = ["; + for (int i = 0; i < mLastChipIndexVD.size(); i++) { + std::cout << mLastChipIndexVD[i]; + if (i < mLastChipIndexVD.size() - 1) { + std::cout << ", "; + } + } + std::cout << "]" << std::endl; +} + +//__________________________________________________________________________ +int GeometryTGeo::getBarrelLayer(int chipID) const +{ + // for barrel layers only, + // so it would be consistent with number of layers i.e. from 0 to 10, + // starting from VD0 to OT10; + // skip the disks; + + int subDetID = getSubDetID(chipID); + int subLayerID = getLayer(chipID); + + if (subDetID < 0 || subDetID > 1) { + LOG(error) << "getBarrelLayer(): Invalid subDetID for barrel: " << subDetID + << ". Expected values are 0 or 1."; + return -1; + } + + if (subLayerID < 0 || subLayerID > 7) { + LOG(error) << "getBarrelLayer(): Invalid subLayerID for barrel: " << subDetID + << ". Expected values are between 0 and 7."; + return -1; + } + + const int baseOffsets[] = {0, 3}; + + return baseOffsets[subDetID] + subLayerID; +} + +//__________________________________________________________________________ +void GeometryTGeo::extractSensorXAlphaMLOT(int chipID, float& x, float& alp) +{ + // works for ML and OT only, a.k.a flat sensors !!! + double locA[3] = {-100., 0., 0.}, locB[3] = {100., 0., 0.}, gloA[3], gloB[3]; + double xp{0}, yp{0}; + + if (getSubDetID(chipID) == 0) { + + LOG(error) << "extractSensorXAlphaMLOT(): VD layers are not supported yet! chipID = " << chipID; + return; + + } else { // flat sensors, ML and OT + const TGeoHMatrix* matL2G = extractMatrixSensor(chipID); + matL2G->LocalToMaster(locA, gloA); + matL2G->LocalToMaster(locB, gloB); + double dx = gloB[0] - gloA[0], dy = gloB[1] - gloA[1]; + double t = (gloB[0] * dx + gloB[1] * dy) / (dx * dx + dy * dy); + xp = gloB[0] - dx * t; + yp = gloB[1] - dy * t; + } + + alp = std::atan2(yp, xp); + x = std::hypot(xp, yp); + o2::math_utils::bringTo02Pi(alp); + + /// TODO: + // once the VD segmentation is done, VD should be added +} + +//__________________________________________________________________________ +TGeoHMatrix& GeometryTGeo::createT2LMatrixMLOT(int chipID) +{ + // works only for ML & OT + // for VD is yet to be implemented once we have more refined geometry + if (getSubDetID(chipID) == 0) { + + LOG(error) << "createT2LMatrixMLOT(): VD layers are not supported yet! chipID = " << chipID + << "returning dummy values! "; + static TGeoHMatrix dummy; + return dummy; + + } else { + static TGeoHMatrix t2l; + t2l.Clear(); + float alpha = getSensorRefAlphaMLOT(chipID); + t2l.RotateZ(alpha * TMath::RadToDeg()); + const TGeoHMatrix* matL2G = extractMatrixSensor(chipID); + const TGeoHMatrix& matL2Gi = matL2G->Inverse(); + t2l.MultiplyLeft(&matL2Gi); + return t2l; + } +} + +} // namespace trk +} // namespace o2 diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector_copy.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector_copy.h new file mode 100644 index 0000000000000..ed2c7bfea6218 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector_copy.h @@ -0,0 +1,128 @@ +// 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. + +#ifndef ALICEO2_TRK_DETECTOR_H +#define ALICEO2_TRK_DETECTOR_H + +#include "DetectorsBase/Detector.h" +#include "TRKSimulation/Hit.h" + +#include "TRKSimulation/TRKLayer.h" +#include "TRKSimulation/TRKServices.h" +#include "TRKBase/GeometryTGeo.h" + +#include +#include + +namespace o2 +{ +namespace trk +{ + +class Detector : public o2::base::DetImpl +{ + public: + Detector(bool active); + Detector(); + ~Detector(); + + // Factory method + static o2::base::Detector* create(bool active) + { + return new Detector(active); + } + + void ConstructGeometry() override; + + o2::trk::Hit* addHit(int trackID, unsigned short detID, const TVector3& startPos, const TVector3& endPos, + const TVector3& startMom, double startE, double endTime, double eLoss, + unsigned char startStatus, unsigned char endStatus); + + // Mandatory overrides + void BeginPrimary() override { ; } + void FinishPrimary() override { ; } + void InitializeO2Detector() override; + void PostTrack() override { ; } + void PreTrack() override { ; } + bool ProcessHits(FairVolume* v = nullptr) override; + void EndOfEvent() override; + void Register() override; + void Reset() override; + + // Custom member functions + std::vector* getHits(int iColl) const + { + if (!iColl) { + return mHits; + } + return nullptr; + } + + void configMLOT(); + void configFromFile(std::string fileName = "alice3_TRK_layout.txt"); + void configToFile(std::string fileName = "alice3_TRK_layout.txt"); + + void configServices(); // To get special conf from CLI options + void createMaterials(); + void createGeometry(); + + private: + int mNumberOfVolumes; + int mNumberOfVolumesVD; + + // Transient data about track passing the sensor + struct TrackData { + bool mHitStarted; // hit creation started + unsigned char mTrkStatusStart; // track status flag + TLorentzVector mPositionStart; // position at entrance + TLorentzVector mMomentumStart; // momentum + double mEnergyLoss; // energy loss + } mTrackData; //! transient data + GeometryTGeo* mGeometryTGeo; //! + std::vector* mHits; // ITSMFT ones for the moment + std::vector> mLayers; + TRKServices mServices; // Houses the services of the TRK, but not the Iris tracker + + std::vector mFirstOrLastLayers; // Names of the first or last layers + bool InsideFirstOrLastLayer(std::string layerName); + + void defineSensitiveVolumes(); + + protected: + std::vector mSensorID; //! layer identifiers + std::vector mSensorName; //! layer names + + public: + static constexpr Int_t sNumberVDPetalCases = 4; //! Number of VD petals + int getNumberOfLayers() const { return mLayers.size(); } //! Number of TRK layers + + void Print(FairVolume* vol, int volume, int subDetID, int layer, int stave, int halfstave, int mod, int chip, int chipID) const; + + template + friend class o2::base::DetImpl; + ClassDefOverride(Detector, 2); +}; +} // namespace trk +} // namespace o2 + +#ifdef USESHM +namespace o2 +{ +namespace base +{ +template <> +struct UseShm { + static constexpr bool value = true; +}; +} // namespace base +} // namespace o2 +#endif +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer_copy.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer_copy.h new file mode 100644 index 0000000000000..c0e15d36929a4 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer_copy.h @@ -0,0 +1,135 @@ +// 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. + +#ifndef ALICEO2_TRK_LAYER_H +#define ALICEO2_TRK_LAYER_H + +#include +#include + +#include "TRKBase/TRKBaseParam.h" +#include "TRKBase/Specs.h" + +namespace o2 +{ +namespace trk +{ +class TRKCylindricalLayer +{ + public: + TRKCylindricalLayer() = default; + TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float layerX2X0); + TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thick); + virtual ~TRKCylindricalLayer() = default; + + auto getInnerRadius() const { return mInnerRadius; } + auto getOuterRadius() const { return mOuterRadius; } + auto getZ() const { return mLength; } + auto getx2X0() const { return mX2X0; } + auto getChipThickness() const { return mChipThickness; } + auto getNumber() const { return mLayerNumber; } + auto getName() const { return mLayerName; } + + virtual TGeoVolume* createSensor(); + virtual TGeoVolume* createMetalStack(); + virtual void createLayer(TGeoVolume* motherVolume); + + protected: + // User defined parameters for the layer, to be set in the constructor + int mLayerNumber; + std::string mLayerName; + float mInnerRadius; + float mOuterRadius; + float mLength; + float mX2X0; + float mChipThickness; + + // Fixed parameters for the layer, to be set based on the specifications of the chip and module + static constexpr double sSensorThickness = constants::moduleMLOT::silicon::thickness; + + static constexpr float Si_X0 = 9.5f; + + ClassDef(TRKCylindricalLayer, 0); +}; + +class TRKSegmentedLayer : public TRKCylindricalLayer +{ + public: + TRKSegmentedLayer() = default; + TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); + TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + ~TRKSegmentedLayer() override = default; + + TGeoVolume* createSensor() override; + TGeoVolume* createDeadzone(); + TGeoVolume* createMetalStack() override; + TGeoVolume* createChip(); + TGeoVolume* createModule(); + TGeoVolume* createStave() = 0; + void createLayer(TGeoVolume* motherVolume) override = 0; + + private: + int mNumberOfModules; + + // Fixed parameters for the layer, to be set based on the specifications of the chip and module + static constexpr double sChipWidth = constants::moduleMLOT::chip::width; + static constexpr double sChipLength = constants::moduleMLOT::chip::length; + static constexpr double sDeadzoneWidth = constants::moduleMLOT::chip::passiveEdgeReadOut; + static constexpr double sModuleLength = constants::moduleMLOT::length; + static constexpr double sModuleWidth = constants::moduleMLOT::width; + static constexpr int sHalfNumberOfChips = 4; + + // TGeo objects outside logical volumes can cause errors + static constexpr float sLogicalVolumeThickness = 1.3; + + ClassDef(TRKSegmentedLayer, 0); +}; + +class TRKMLLayer : public TRKSegmentedLayer +{ + public: + TRKMLLayer() = default; + TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); + TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + ~TRKMLLayer() override = default; + + TGeoVolume* createStave() override; + void createLayer(TGeoVolume* motherVolume) override; + + private: + static constexpr double sStaveWidth = constants::ML::width; + + ClassDef(TRKMLLayer, 0); +}; + +class TRKOTLayer : public TRKSegmentedLayer +{ + public: + TRKOTLayer() = default; + TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); + TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + ~TRKOTLayer() override = default; + + TGeoVolume* createStave() override; + TGeoVolume* createHalfStave(); + void createLayer(TGeoVolume* motherVolume) override; + + private: + static constexpr double sHalfStaveWidth = constants::OT::halfstave::width; + static constexpr double sInStaveOverlap = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true) overlap + static constexpr double sStaveWidth = constants::OT::width - sInStaveOverlap; + + ClassDef(TRKOTLayer, 0) +}; + +} // namespace trk +} // namespace o2 +#endif // ALICEO2_TRK_LAYER_H \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector_copy.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector_copy.cxx new file mode 100644 index 0000000000000..95dde592fc043 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector_copy.cxx @@ -0,0 +1,542 @@ +// 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. + +#include + +#include +#include +#include + +#include "DetectorsBase/Stack.h" +#include "TRKSimulation/Hit.h" +#include "TRKSimulation/Detector.h" +#include "TRKBase/TRKBaseParam.h" +#include "TRKSimulation/VDGeometryBuilder.h" +#include "TRKSimulation/VDSensorRegistry.h" + +#include +#include + +using o2::trk::Hit; + +namespace o2 +{ +namespace trk +{ + +float getDetLengthFromEta(const float eta, const float radius) +{ + return 2. * (10. + radius * std::cos(2 * std::atan(std::exp(-eta)))); +} + +Detector::Detector() + : o2::base::DetImpl("TRK", true), + mTrackData(), + mHits(o2::utils::createSimVector()) +{ +} + +Detector::Detector(bool active) + : o2::base::DetImpl("TRK", true), + mTrackData(), + mHits(o2::utils::createSimVector()) +{ + auto& trkPars = TRKBaseParam::Instance(); + + if (trkPars.configFile != "") { + configFromFile(trkPars.configFile); + } else { + configMLOT(); + configToFile(); + configServices(); + } + + LOGP(info, "Summary of TRK configuration:"); + for (auto& layer : mLayers) { + LOGP(info, "Layer: {} name: {} r: {} cm | z: {} cm | thickness: {} cm", layer.getNumber(), layer.getName(), layer.getInnerRadius(), layer.getZ(), layer.getChipThickness()); + } +} + +Detector::~Detector() +{ + if (mHits) { + o2::utils::freeSimVector(mHits); + } +} + +void Detector::ConstructGeometry() +{ + createMaterials(); + createGeometry(); +} + +void Detector::configMLOT() +{ + auto& trkPars = TRKBaseParam::Instance(); + + mLayers.clear(); + + const std::vector rInn{7.f, 9.f, 12.f, 20.f, 30.f, 45.f, 60.f, 80.f}; + const float thick = 100.e-3; + + switch (trkPars.layoutMLOT) { + case kCylindrical: + const std::vector length{128.35f, 128.35f, 128.35f, 128.35f, 128.35f, 256.7f, 256.7f, 256.7f}; + LOGP(warning, "Loading cylindrical configuration for ALICE3 TRK"); + for (int i{0}; i < 8; ++i) { + std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i); + mLayers.push_back(std::make_unique(i, name, rInn[i], length[i], thick)); + } + break; + case kSegmented: + const std::vector nMods{10, 10, 10, 10, 10, 20, 20, 20}; + LOGP(warning, "Loading segmented configuration for ALICE3 TRK"); + for (int i{0}; i < 8; ++i) { + std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i); + if (i < 4) { + mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick)); + } else { + mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick)); + } + } + break; + default: + LOGP(fatal, "Unknown option {} for configMLOT", static_cast(trkPars.layoutMLOT)); + break; + } +} + +void Detector::configFromFile(std::string fileName) +{ + // Override the default geometry if config file provided + std::ifstream confFile(fileName); + if (!confFile.good()) { + LOGP(fatal, "File {} not found, aborting.", fileName); + } + + auto& trkPars = TRKBaseParam::Instance(); + + mLayers.clear(); + + LOGP(info, "Overriding geometry of ALICE3 TRK using {} file.", fileName); + + std::string line; + std::vector tmpBuff; + int layerCount{0}; + while (std::getline(confFile, line)) { + if (line[0] == '/') { + continue; + } + tmpBuff.clear(); + std::stringstream ss(line); + float val; + std::string substr; + while (getline(ss, substr, '\t')) { + tmpBuff.push_back(std::stof(substr)); + } + + std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(layerCount); + switch (trkPars.layoutMLOT) { + case kCylindrical: + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], tmpBuff[1], tmpBuff[2])); + break; + case kSegmented: { + int nMods = static_cast(tmpBuff[1]); + if (layerCount < 4) { + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2])); + } else { + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2])); + } + break; + } + default: + LOGP(fatal, "Unknown option {} for configMLOT", static_cast(trkPars.layoutMLOT)); + break; + } + + ++layerCount; + } +} + +void Detector::configToFile(std::string fileName) +{ + LOGP(info, "Exporting TRK Detector layout to {}", fileName); + std::ofstream conFile(fileName.c_str(), std::ios::out); + conFile << "/// TRK configuration file: inn_radius z_length lay_thickness" << std::endl; + for (auto layer : mLayers) { + conFile << layer.getInnerRadius() << "\t" << layer.getZ() << "\t" << layer.getChipThickness() << std::endl; + } +} + +void Detector::configServices() +{ + mServices = TRKServices(); +} + +void Detector::createMaterials() +{ + int ifield = 2; // ? + float fieldm = 10.0; // ? + o2::base::Detector::initFieldTrackingParams(ifield, fieldm); + + float tmaxfdSi = 0.1; // .10000E+01; // Degree + float stemaxSi = 0.0075; // .10000E+01; // cm + float deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0GetVolume("barrel"); + if (!vALIC) { + LOGP(fatal, "Could not find barrel volume while constructing TRK geometry"); + } + new TGeoVolumeAssembly(GeometryTGeo::getTRKVolPattern()); + TGeoVolume* vTRK = geoManager->GetVolume(GeometryTGeo::getTRKVolPattern()); + vALIC->AddNode(vTRK, 2, new TGeoTranslation(0, 30., 0)); + + char vstrng[100] = "TRKVol"; + vTRK->SetTitle(vstrng); + + for (auto& layer : mLayers) { + layer.createLayer(vTRK); + } + + // Add service for inner tracker + mServices.createServices(vTRK); + + // Build the VD using the petal builder + // Choose the VD design based on TRKBaseParam.layoutVD + auto& trkPars = TRKBaseParam::Instance(); + + o2::trk::clearVDSensorRegistry(); + + switch (trkPars.layoutVD) { + case kIRIS4: + LOG(info) << "Building VD with IRIS4 layout"; + o2::trk::createIRIS4Geometry(vTRK); + break; + case kIRISFullCyl: + LOG(info) << "Building VD with IRIS fully cylindrical layout"; + o2::trk::createIRISGeometryFullCyl(vTRK); + break; + case kIRISFullCyl3InclinedWalls: + LOG(info) << "Building VD with IRIS fully cylindrical layout with 3 inclined walls"; + o2::trk::createIRISGeometry3InclinedWalls(vTRK); + break; + case kIRIS5: + LOG(info) << "Building VD with IRIS5 layout"; + o2::trk::createIRIS5Geometry(vTRK); + break; + case kIRIS4a: + LOG(info) << "Building VD with IRIS4a layout"; + o2::trk::createIRIS4aGeometry(vTRK); + break; + default: + LOG(fatal) << "Unknown VD layout option: " << static_cast(trkPars.layoutVD); + break; + } + + // Fill sensor names from registry right after geometry creation + const auto& regs = o2::trk::vdSensorRegistry(); + mNumberOfVolumesVD = static_cast(regs.size()); + mNumberOfVolumes = mNumberOfVolumesVD + mLayers.size(); + mSensorName.resize(mNumberOfVolumes); + + // Fill VD sensor names from registry + int VDvolume = 0; + for (const auto& sensor : regs) { + mSensorName[VDvolume] = sensor.name; + VDvolume++; + } + + // Add MLOT sensor names + for (int i = 0; i < mLayers.size(); i++) { + mSensorName[VDvolume++].Form("%s%d", GeometryTGeo::getTRKSensorPattern(), i); + } + + for (auto vd : mSensorName) { + std::cout << "Volume name: " << vd << std::endl; + } + + mServices.excavateFromVacuum("IRIS_CUTOUTsh"); + mServices.registerVacuum(vTRK); +} + +void Detector::InitializeO2Detector() +{ + LOG(info) << "Initialize TRK O2Detector"; + mGeometryTGeo = GeometryTGeo::Instance(); + defineSensitiveVolumes(); + + mSensorID.resize(mNumberOfVolumes); // hardcoded. TODO: change size when a different namingh scheme for VD is in place. Ideally could be 4 petals + 8 layers = 12 + for (int i = 0; i < mNumberOfVolumes; i++) { + mSensorID[i] = gMC ? TVirtualMC::GetMC()->VolId(mSensorName[i]) : 0; // Volume ID from the Geant geometry + LOGP(info, "{}: mSensorID={}, mSensorName={}", i, mSensorID[i], mSensorName[i].Data()); + } +} + +void Detector::defineSensitiveVolumes() +{ + TGeoManager* geoManager = gGeoManager; + TGeoVolume* v; + + TString volumeName; + LOGP(info, "Adding TRK Sensitive Volumes"); + + // Register VD sensors created by VDGeometryBuilder + for (const auto& s : o2::trk::vdSensorRegistry()) { + TGeoVolume* v = gGeoManager->GetVolume(s.name.c_str()); + if (!v) { + LOGP(warning, "VD sensor volume '{}' not found", s.name); + continue; + } + LOGP(info, "Adding VD Sensitive Volume {}", v->GetName()); + AddSensitiveVolume(v); + // Optionally track first/last layers for TR references: + if (s.region == o2::trk::VDSensorDesc::Region::Barrel && (s.idx == 0 /*innermost*/)) { + mFirstOrLastLayers.push_back(s.name); + } + } + + // The names of the TRK sensitive volumes have the format: TRKLayer(0...mLayers.size()-1) + for (int j{0}; j < mLayers.size(); j++) { + volumeName = GeometryTGeo::getTRKSensorPattern() + TString::Itoa(j, 10); + if (j == mLayers.size() - 1) { + mFirstOrLastLayers.push_back(volumeName.Data()); + } + LOGP(info, "Trying {}", volumeName.Data()); + v = geoManager->GetVolume(volumeName.Data()); + LOGP(info, "Adding TRK Sensitive Volume {}", v->GetName()); + AddSensitiveVolume(v); + } +} + +void Detector::EndOfEvent() { Reset(); } + +void Detector::Register() +{ + // This will create a branch in the output tree called Hit, setting the last + // parameter to kFALSE means that this collection will not be written to the file, + // it will exist only during the simulation + + if (FairRootManager::Instance()) { + FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, true); + } +} + +void Detector::Reset() +{ + if (!o2::utils::ShmManager::Instance().isOperational()) { + mHits->clear(); + } +} + +bool Detector::InsideFirstOrLastLayer(std::string layerName) +{ + bool inside = false; + for (auto& firstOrLastLayer : mFirstOrLastLayers) { + if (firstOrLastLayer == layerName) { + inside = true; + break; + } + } + return inside; +} + +bool Detector::ProcessHits(FairVolume* vol) +{ + // This method is called from the MC stepping + if (!(fMC->TrackCharge())) { + return false; + } + + int subDetID = -1; + int layer = -1; + int volume = 0; + int volID = vol->getMCid(); + + bool notSens = false; + while ((volume < mNumberOfVolumes) && (notSens = (volID != mSensorID[volume]))) { + ++volume; /// there are 44 volumes, 36 for the VD (1 for each sensing element) and 8 for the MLOT (1 for each layer) + } + + if (notSens) { + return kFALSE; // RS: can this happen? This method must be called for sensors only? + } + + if (volume < mNumberOfVolumesVD) { + subDetID = 0; // VD. For the moment each "chip" is a volume./// TODO: change this logic once the naming scheme is changed + } else { + subDetID = 1; // MLOT + layer = volume - mNumberOfVolumesVD; + } + + // Is it needed to keep a track reference when the outer ITS volume is encountered? + auto stack = (o2::data::Stack*)fMC->GetStack(); + // if (fMC->IsTrackExiting() && (lay == 0 || lay == mLayers.size() - 1)) { + if (fMC->IsTrackExiting() && InsideFirstOrLastLayer(vol->GetName())) { + // Keep the track refs for the innermost and outermost layers only + o2::TrackReference tr(*fMC, GetDetId()); + tr.setTrackID(stack->GetCurrentTrackNumber()); + tr.setUserId(volume); + stack->addTrackReference(tr); + } + bool startHit = false, stopHit = false; + unsigned char status = 0; + if (fMC->IsTrackEntering()) { + status |= Hit::kTrackEntering; + } + if (fMC->IsTrackInside()) { + status |= Hit::kTrackInside; + } + if (fMC->IsTrackExiting()) { + status |= Hit::kTrackExiting; + } + if (fMC->IsTrackOut()) { + status |= Hit::kTrackOut; + } + if (fMC->IsTrackStop()) { + status |= Hit::kTrackStopped; + } + if (fMC->IsTrackAlive()) { + status |= Hit::kTrackAlive; + } + + // track is entering or created in the volume + if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { + startHit = true; + } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { + stopHit = true; + } + + // increment energy loss at all steps except entrance + if (!startHit) { + mTrackData.mEnergyLoss += fMC->Edep(); + } + if (!(startHit | stopHit)) { + return false; // do noting + } + + if (startHit) { + mTrackData.mEnergyLoss = 0.; + fMC->TrackMomentum(mTrackData.mMomentumStart); + fMC->TrackPosition(mTrackData.mPositionStart); + mTrackData.mTrkStatusStart = status; + mTrackData.mHitStarted = true; + } + if (stopHit) { + TLorentzVector positionStop; + fMC->TrackPosition(positionStop); + // Retrieve the indices with the volume path + int stave(0), halfstave(0), mod(0), chip(0); + if (subDetID == 1) { + fMC->CurrentVolOffID(1, chip); + fMC->CurrentVolOffID(2, mod); + if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 2) { + fMC->CurrentVolOffID(3, halfstave); + fMC->CurrentVolOffID(4, stave); + } else if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 1) { + fMC->CurrentVolOffID(3, stave); + } else { + LOGP(fatal, "Wrong number of halfstaves for layer {}", layer); + } + } /// if VD, for the moment the volume is the "chipID" so no need to retrieve other elments + + unsigned short chipID = mGeometryTGeo->getChipIndex(subDetID, volume, layer, stave, halfstave, mod, chip); + + // Print(vol, volume, subDetID, layer, stave, halfstave, mod, chip, chipID); + + // mGeometryTGeo->Print(); + + Hit* p = addHit(stack->GetCurrentTrackNumber(), chipID, mTrackData.mPositionStart.Vect(), positionStop.Vect(), + mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), + mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); + // p->SetTotalEnergy(vmc->Etot()); + + // RS: not sure this is needed + // Increment number of Detector det points in TParticle + stack->addHit(GetDetId()); + } + + return true; +} + +o2::trk::Hit* Detector::addHit(int trackID, unsigned short detID, const TVector3& startPos, const TVector3& endPos, + const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus, + unsigned char endStatus) +{ + mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus); + return &(mHits->back()); +} + +void Detector::Print(FairVolume* vol, int volume, int subDetID, int layer, int stave, int halfstave, int mod, int chip, int chipID) const +{ + int currentVol(0); + LOG(info) << "Current volume name: " << fMC->CurrentVolName() << " and ID " << fMC->CurrentVolID(currentVol); + LOG(info) << "volume: " << volume << "/" << mNumberOfVolumes - 1; + LOG(info) << "off volume name 1 " << fMC->CurrentVolOffName(1) << " chip: " << chip; + LOG(info) << "off volume name 2 " << fMC->CurrentVolOffName(2) << " module: " << mod; + if (subDetID == 1 && mGeometryTGeo->getNumberOfHalfStaves(layer) == 2) { // staggered geometry + LOG(info) << "off volume name 3 " << fMC->CurrentVolOffName(3) << " halfstave: " << halfstave; + LOG(info) << "off volume name 4 " << fMC->CurrentVolOffName(4) << " stave: " << stave; + LOG(info) << "SubDetector ID: " << subDetID << " Layer: " << layer << " staveinLayer: " << stave << " Chip ID: " << chipID; + } else if (subDetID == 1 && mGeometryTGeo->getNumberOfHalfStaves(layer) == 1) { // turbo geometry + LOG(info) << "off volume name 3 " << fMC->CurrentVolOffName(3) << " stave: " << stave; + LOG(info) << "SubDetector ID: " << subDetID << " Layer: " << layer << " staveinLayer: " << stave << " Chip ID: " << chipID; + } else { + LOG(info) << "SubDetector ID: " << subDetID << " Chip ID: " << chipID; + } + LOG(info); +} + +} // namespace trk +} // namespace o2 + +ClassImp(o2::trk::Detector); + +// Define Factory method for calling from the outside +extern "C" { +o2::base::Detector* create_detector_trk(bool active) +{ + return o2::trk::Detector::create(active); +} +} diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer_copy.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer_copy.cxx new file mode 100644 index 0000000000000..c54cd91f2ba10 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer_copy.cxx @@ -0,0 +1,358 @@ +// 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. + +#include "TRKSimulation/TRKLayer.h" +#include "TRKBase/GeometryTGeo.h" +#include "TRKBase/Specs.h" + +#include "Framework/Logger.h" + +#include +#include +#include + +#include +#include "TRKLayer_copy.h" + +namespace o2 +{ +namespace trk +{ +TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float layerX2X0) + : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length), mX2X0(layerX2X0) +{ + sChipThickness = mX2X0 * Si_X0; + mOuterRadius = rInn + sChipThickness; + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thick) + : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length), sChipThickness(thick) +{ + mOuterRadius = rInn + thick; + mX2X0 = thick / Si_X0; + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TGeoVolume* TRKCylindricalLayer::createSensor() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string sensName = GeometryTGeo::getTRKSensorPattern() + std::to_string(mLayerNumber); + TGeoShape* sensor = new TGeoTube(mInnerRadius, mInnerRadius + sSensorThickness, mLength / 2); + TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); + sensVol->SetLineColor(kYellow); + + return sensVol; +}; + +TGeoVolume* TRKCylindricalLayer::createMetalStack() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string metalName = GeometryTGeo::getTRKMetalStackPattern() + std::to_string(mLayerNumber); + TGeoShape* metalStack metalStack = new TGeoTube(mInnerRadius + sSensorThickness, mInnerRadius + sChipThickness, mLength / 2); + TGeoVolume* metalVol = new TGeoVolume(metalName.c_str(), metalStack, medSi); + metalVol->SetLineColor(kGray); + + return metalVol; +}; + +void TRKCylindricalLayer::createLayer(TGeoVolume* motherVolume) +{ + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + TGeoTube* layer = new TGeoTube(mInnerRadius, mInnerRadius + sChipThickness, mLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kYellow); + + TGeoVolume* sensVol = createSensor(); + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + layerVol->AddNode(sensVol, 1, nullptr); + + TGeoVolume* metalVol = createMetalStack(); + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); + layerVol->AddNode(metalVol, 1, nullptr); + + LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); + motherVolume->AddNode(layerVol, 1, nullptr); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) + : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, layerX2X0), mNumberOfModules(numberOfModules) +{ + sChipThickness = mX2X0 * Si_X0; + mOuterRadius = rInn + sChipThickness; + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) + : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, thick), mNumberOfModules(numberOfModules) +{ + mOuterRadius = rInn + thick; + mX2X0 = thick / Si_X0; + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TGeoVolume* TRKSegmentedLayer::createSensor() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string sensName = GeometryTGeo::getTRKSensorPattern() + std::to_string(mLayerNumber); + TGeoShape* sensor = new TGeoBBox((sChipWidth - sDeadzoneWidth) / 2, sSensorThickness / 2, sChipLength / 2); + TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); + sensVol->SetLineColor(kYellow); + + return sensVol; +} + +TGeoVolume* TRKSegmentedLayer::createDeadzone() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string deadName = GeometryTGeo::getTRKDeadzonePattern() + std::to_string(mLayerNumber); + TGeoShape* deadzone = new TGeoBBox(sDeadzoneWidth / 2, sSensorThickness / 2, sChipLength / 2); + TGeoVolume* deadVol = new TGeoVolume(deadName.c_str(), deadzone, medSi); + deadVol->SetLineColor(kGray); + + return deadVol; +} + +TGeoVolume* TRKSegmentedLayer::createMetalStack() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string metalName = GeometryTGeo::getTRKMetalStackPattern() + std::to_string(mLayerNumber); + TGeoShape* metalStack = new TGeoBBox(sChipWidth / 2, (sChipThickness - sSensorThickness) / 2, sChipLength / 2); + TGeoVolume* metalVol = new TGeoVolume(metalName.c_str(), metalStack, medSi); + metalVol->SetLineColor(kGray); + + return metalVol; +} + +TGeoVolume* TRKSegmentedLayer::createChip() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string chipName = GeometryTGeo::getTRKChipPattern() + std::to_string(mLayerNumber); + TGeoShape* chip = new TGeoBBox(sChipWidth / 2, sChipThickness / 2, sChipLength / 2); + TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); + chipVol->SetLineColor(kYellow); + + TGeoVolume* sensVol = createSensor(); + TGeoCombiTrans* transSens = new TGeoCombiTrans(); + transSens->SetTranslation(-sDeadzoneWidth / 2, -(sChipThickness - sSensorThickness) / 2, 0); + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + chipVol->AddNode(sensVol, 1, transSens); + + TGeoVolume* deadVol = createDeadzone(); + TGeoCombiTrans* transDead = new TGeoCombiTrans(); + transDead->SetTranslation((sChipWidth - sDeadzoneWidth) / 2, -(sChipThickness - sSensorThickness) / 2, 0); + LOGP(debug, "Inserting {} in {} ", deadVol->GetName(), chipVol->GetName()); + chipVol->AddNode(deadVol, 1, transDead); + + TGeoVolume* metalVol = createMetalStack(); + TGeoCombiTrans* transMetal = new TGeoCombiTrans(); + transMetal->SetTranslation(0, sSensorThickness / 2, 0); + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); + chipVol->AddNode(metalVol, 1, transMetal); + + return chipVol; +} + +TGeoVolume* TRKSegmentedLayer::createModule() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string moduleName = GeometryTGeo::getTRKModulePattern() + std::to_string(mLayerNumber); + TGeoShape* module = new TGeoBBox(sModuleWidth / 2, sChipThickness / 2, sModuleLength / 2); + TGeoVolume* moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); + moduleVol->SetLineColor(kYellow); + + for (int iChip = 0; iChip < mHalfNumberOfChips; iChip++) { + TGeoVolume* chipVolLeft = createChip(); + double xLeft = -sModuleWidth / 2 + constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::width / 2; + double zLeft = -sModuleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; + TGeoCombiTrans* transLeft = new TGeoCombiTrans(); + transLeft->SetTranslation(xLeft, 0, zLeft); + TGeoRotation* rot = new TGeoRotation(); + rot->RotateY(180); + transLeft->SetRotation(rot); + LOGP(debug, "Inserting {} in {} ", chipVolLeft->GetName(), moduleVol->GetName()); + moduleVol->AddNode(chipVolLeft, iChip * 2, transLeft); + + TGeoVolume* chipVolRight = createChip(); + double xRight = +sModuleWidth / 2 - constants::moduleMLOT::gaps::outerEdgeLongSide - constants::moduleMLOT::chip::width / 2; + double zRight = -sModuleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; + TGeoCombiTrans* transRight = new TGeoCombiTrans(); + transRight->SetTranslation(xRight, 0, zRight); + LOGP(debug, "Inserting {} in {} ", chipVolRight->GetName(), moduleVol->GetName()); + moduleVol->AddNode(chipVolRight, iChip * 2 + 1, transRight); + } + + return moduleVol; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, layerX2X0) +{ + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thick) +{ + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TGeoVolume* TRKMLLayer::createStave() +{ + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + std::string staveName = GeometryTGeo::getTRKStavePattern() + std::to_string(mLayerNumber); + TGeoShape* stave = new TGeoBBox(sStaveWidth / 2, sChipThickness / 2, mLength / 2); + TGeoVolume* staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); + staveVol->SetLineColor(kYellow); + + for (int iModule = 0; iModule < mNumberOfModules; iModule++) { + TGeoVolume* moduleVol = createModule(); + double zPos = -0.5 * mNumberOfModules * sModuleLength + (iModule + 0.5) * sModuleLength; + TGeoCombiTrans* trans = new TGeoCombiTrans(); + trans->SetTranslation(0, 0, zPos); + LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), staveVol->GetName()); + staveVol->AddNode(moduleVol, iModule, trans); + } + + return staveVol; +} + +void TRKMLLayer::createLayer(TGeoVolume* motherVolume) +{ + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + TGeoTube* layer = new TGeoTube(mInnerRadius - 0.333 * sLogicalVolumeThickness, mInnerRadius + 0.667 * sLogicalVolumeThickness, mLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kYellow); + + // Compute the number of staves + int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / sStaveWidth); + nStaves += nStaves % 2; // Require an even number of staves + + // Compute the size of the overlap region + double theta = 2 * TMath::Pi() / nStaves; + double theta1 = std::atan(sStaveWidth / 2 / mInnerRadius); + double st = std::sin(theta); + double ct = std::cos(theta); + double theta2 = std::atan((mInnerRadius * st - sStaveWidth / 2 * ct) / (mInnerRadius * ct + sStaveWidth / 2 * st)); + double overlap = (theta1 - theta2) * mInnerRadius; + LOGP(info, "Creating a layer with {} staves and {} mm overlap", nStaves, overlap * 10); + + for (int iStave = 0; iStave < nStaves; iStave++) { + TGeoVolume* staveVol = createStave(); + TGeoCombiTrans* trans = new TGeoCombiTrans(); + double theta = 360. * iStave / nStaves; + TGeoRotation* rot = new TGeoRotation("rot", theta - 90 + 4, 0, 0); + trans->SetRotation(rot); + trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); + LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); + layerVol->AddNode(staveVol, iStave, trans); + } + + LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); + motherVolume->AddNode(layerVol, 1, nullptr); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, layerX2X0) +{ + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thick) +{ + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TGeoVolume* TRKOTLayer::createHalfStave() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string halfStaveName = GeometryTGeo::getTRKHalfStavePattern() + std::to_string(mLayerNumber); + TGeoShape* halfStave = new TGeoBBox(sHalfStaveWidth / 2, sChipThickness / 2, mLength / 2); + TGeoVolume* halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); + halfStaveVol->SetLineColor(kYellow); + + for (int iModule = 0; iModule < mNumberOfModules; iModule++) { + TGeoVolume* moduleVol = createModule("flat"); + double zPos = -0.5 * mNumberOfModules * sModuleLength + (iModule + 0.5) * sModuleLength; + TGeoCombiTrans* trans = new TGeoCombiTrans(); + trans->SetTranslation(0, 0, zPos); + LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), halfStaveVol->GetName()); + halfStaveVol->AddNode(moduleVol, iModule, trans); + } + + return halfStaveVol; +} + +TGeoVolume* TRKOTLayer::createStave() +{ + std::string staveName = GeometryTGeo::getTRKStavePattern() + std::to_string(mLayerNumber); + TGeoVolume* staveVol = new TGeoVolumeAssembly(staveName.c_str()); + + TGeoVolume* halfStaveVolLeft = createHalfStave(); + TGeoCombiTrans* transLeft = new TGeoCombiTrans(); + transLeft->SetTranslation(-(sHalfStaveWidth - sInStaveOverlap) / 2, 0, 0); + LOGP(debug, "Inserting {} in {} ", halfStaveVolLeft->GetName(), staveVol->GetName()); + staveVol->AddNode(halfStaveVolLeft, 0, transLeft); + + TGeoVolume* halfStaveVolRight = createHalfStave(); + TGeoCombiTrans* transRight = new TGeoCombiTrans(); + transRight->SetTranslation(sHalfStaveWidth / 2 - shift, 0.2, 0); + LOGP(debug, "Inserting {} in {} ", halfStaveVolRight->GetName(), staveVol->GetName()); + staveVol->AddNode(halfStaveVolRight, 1, transRight); + + return staveVol; +} + +void TRKOTLayer::createLayer(TGeoVolume* motherVolume) +{ + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + TGeoTube* layer = new TGeoTube(mInnerRadius - 0.333 * sLogicalVolumeThickness, mInnerRadius + 0.667 * sLogicalVolumeThickness, mLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kYellow); + + // Compute the number of staves + int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / sStaveWidth); + nStaves += nStaves % 2; // Require an even number of staves + + // Compute the size of the overlap region + double theta = 2 * TMath::Pi() / nStaves; + double theta1 = std::atan(sStaveWidth / 2 / mInnerRadius); + double st = std::sin(theta); + double ct = std::cos(theta); + double theta2 = std::atan((mInnerRadius * st - sStaveWidth / 2 * ct) / (mInnerRadius * ct + sStaveWidth / 2 * st)); + double overlap = (theta1 - theta2) * mInnerRadius; + LOGP(info, "Creating a layer with {} staves and {} mm overlap", nStaves, overlap * 10); + + for (int iStave = 0; iStave < nStaves; iStave++) { + TGeoVolume* staveVol = createStave(); + TGeoCombiTrans* trans = new TGeoCombiTrans(); + double theta = 360. * iStave / nStaves; + TGeoRotation* rot = new TGeoRotation("rot", theta - 90, 0, 0); + trans->SetRotation(rot); + trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); + LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); + layerVol->AddNode(staveVol, iStave, trans); + } + + LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); + motherVolume->AddNode(layerVol, 1, nullptr); +} +// ClassImp(TRKLayer); + +} // namespace trk +} // namespace o2 \ No newline at end of file From 8be3db1504b8753c6b39188dd742f3dee84b4e0a Mon Sep 17 00:00:00 2001 From: scannito Date: Mon, 9 Mar 2026 16:03:14 +0100 Subject: [PATCH 2/7] Naming --- .../TRK/base/include/TRKBase/GeometryTGeo.h | 3 +- .../base/include/TRKBase/GeometryTGeo_copy.h | 246 ---- .../TRK/base/include/TRKBase/TRKBaseParam.h | 29 +- .../base/include/TRKBase/TRKBaseParam_copy.h | 52 - .../ALICE3/TRK/base/src/GeometryTGeo.cxx | 9 +- .../ALICE3/TRK/base/src/GeometryTGeo_copy.cxx | 1253 ----------------- .../include/TRKSimulation/Detector.h | 5 +- .../include/TRKSimulation/Detector_copy.h | 128 -- .../include/TRKSimulation/TRKLayer.h | 111 +- .../include/TRKSimulation/TRKLayer_copy.h | 135 -- .../ALICE3/TRK/simulation/src/Detector.cxx | 111 +- .../TRK/simulation/src/Detector_copy.cxx | 542 ------- .../ALICE3/TRK/simulation/src/TRKLayer.cxx | 553 ++++---- .../TRK/simulation/src/TRKLayer_copy.cxx | 358 ----- 14 files changed, 387 insertions(+), 3148 deletions(-) delete mode 100644 Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo_copy.h delete mode 100644 Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam_copy.h delete mode 100644 Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo_copy.cxx delete mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector_copy.h delete mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer_copy.h delete mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector_copy.cxx delete mode 100644 Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer_copy.cxx diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h index d4402d66cff7e..21d86378f59ec 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h @@ -235,8 +235,7 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache std::vector mCacheRefXMLOT; /// cache for X of ML and OT std::vector mCacheRefAlphaMLOT; /// cache for sensor ref alpha ML and OT - eLayout mLayoutML; // Type of segmentation for the middle layers - eLayout mLayoutOT; // Type of segmentation for the outer layers + eMLOTLayout mLayoutMLOT; // ML and OT detector layout design private: static std::unique_ptr sInstance; diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo_copy.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo_copy.h deleted file mode 100644 index 21d86378f59ec..0000000000000 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo_copy.h +++ /dev/null @@ -1,246 +0,0 @@ -// 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. - -#ifndef ALICEO2_TRK_GEOMETRYTGEO_H -#define ALICEO2_TRK_GEOMETRYTGEO_H - -#include -#include -#include "DetectorsCommonDataFormats/DetID.h" -#include "TRKBase/TRKBaseParam.h" - -namespace o2 -{ -namespace trk -{ -class GeometryTGeo : public o2::detectors::DetMatrixCache -{ - public: - using Mat3D = o2::math_utils::Transform3D; - using DetMatrixCache::getMatrixL2G; - using DetMatrixCache::getMatrixT2GRot; - using DetMatrixCache::getMatrixT2L; - // this method is not advised for ITS: for barrel detectors whose tracking frame is just a rotation - // it is cheaper to use T2GRot - using DetMatrixCache::getMatrixT2G; - GeometryTGeo(bool build = false, int loadTrans = 0); - ~GeometryTGeo(); - void Build(int loadTrans); - void fillMatrixCache(int mask); - static GeometryTGeo* Instance() - { - if (!sInstance) { - sInstance = std::make_unique(true, 0); - } - return sInstance.get(); - }; - static const char* getTRKVolPattern() { return sVolumeName.c_str(); } - static const char* getTRKLayerPattern() { return sLayerName.c_str(); } - static const char* getTRKPetalAssemblyPattern() { return sPetalAssemblyName.c_str(); } - static const char* getTRKPetalPattern() { return sPetalName.c_str(); } - static const char* getTRKPetalDiskPattern() { return sPetalDiskName.c_str(); } - static const char* getTRKPetalLayerPattern() { return sPetalLayerName.c_str(); } - static const char* getTRKStavePattern() { return sStaveName.c_str(); } - static const char* getTRKHalfStavePattern() { return sHalfStaveName.c_str(); } - static const char* getTRKModulePattern() { return sModuleName.c_str(); } - static const char* getTRKChipPattern() { return sChipName.c_str(); } - static const char* getTRKSensorPattern() { return sSensorName.c_str(); } - static const char* getTRKDeadzonePattern() { return sDeadzoneName.c_str(); } - static const char* getTRKMetalStackPattern() { return sMetalStackName.c_str(); } - - static const char* getTRKWrapVolPattern() { return sWrapperVolumeName.c_str(); } - - int getNumberOfChips() const { return mSize; } - - /// Determines the number of active parts in the Geometry - int extractNumberOfLayersMLOT(); - int extractNumberOfLayersVD() const; - int extractNumberOfPetalsVD() const; - int extractNumberOfActivePartsVD() const; - int extractNumberOfDisksVD() const; - int extractNumberOfChipsPerPetalVD() const; - int extractNumberOfStavesMLOT(int lay) const; - int extractNumberOfHalfStavesMLOT(int lay) const; - int extractNumberOfModulesMLOT(int lay) const; - int extractNumberOfChipsMLOT(int lay) const; - - /// Extract number following the prefix in the name string - int extractVolumeCopy(const char* name, const char* prefix) const; - - int getNumberOfLayersMLOT() const { return mNumberOfLayersMLOT; } - int getNumberOfActivePartsVD() const { return mNumberOfActivePartsVD; } - int getNumberOfHalfStaves(int lay) const { return mNumberOfHalfStaves[lay]; } - - bool isOwner() const { return mOwner; } - 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 mod, int chip) const; - - int getSubDetID(int index) const; - int getPetalCase(int index) const; - int getDisk(int index) const; - int getLayer(int index) const; - int getStave(int index) const; - int getHalfStave(int index) const; - int getModule(int index) const; - int getChip(int index) const; - - void defineMLOTSensors(); - int getBarrelLayer(int) const; - - // sensor ref X and alpha for ML & OT - void extractSensorXAlphaMLOT(int, float&, float&); - - // cache for tracking frames (ML & OT) - bool isTrackingFrameCachedMLOT() const { return !mCacheRefXMLOT.empty(); } - void fillTrackingFramesCacheMLOT(); - - float getSensorRefAlphaMLOT(int chipId) const - { - assert(getSubDetID(chipId) != 0 && "Called MLOT getter with VD chipId"); - const int local = chipId - getNumberOfActivePartsVD(); - assert(local >= 0 && local < (int)mCacheRefAlphaMLOT.size()); - return mCacheRefAlphaMLOT[local]; - } - - float getSensorXMLOT(int chipId) const - { - assert(getSubDetID(chipId) != 0 && "Called MLOT getter with VD chipId"); - const int local = chipId - getNumberOfActivePartsVD(); - assert(local >= 0 && local < (int)mCacheRefXMLOT.size()); - return mCacheRefXMLOT[local]; - } - - // create matrix for tracking to local frame for MLOT - TGeoHMatrix& createT2LMatrixMLOT(int); - - /// This routine computes the chip index number from the subDetID, petal, disk, layer, stave /// TODO: retrieve also from chip when chips will be available - /// This routine computes the chip index number from the subDetID, petal, disk, layer, stave, half stave, module, chip - /// \param int subDetID The subdetector ID, 0 for VD, 1 for MLOT - /// \param int petalcase The petal case number for VD, from 0 to 3 - /// \param int disk The disk number for VD, from 0 to 5 - /// \param int lay The layer number. Starting from 0 both for VD and MLOT - /// \param int stave The stave number for MLOT. Starting from 0 - /// \param int halfstave The half stave number for MLOT. Can be 0 or 1 - /// \param int module The module number for MLOT, from 0 to 10 (or 20) - /// \param int chip The chip number for MLOT, from 0 to 8 - unsigned short getChipIndex(int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int mod, int chip) const; - - /// This routine computes the chip index number from the subDetID, volume, layer, stave, half stave, module, chip - /// \param int subDetID The subdetector ID, 0 for VD, 1 for MLOT - /// \param int volume is needed only with the current configuration for VD where each single element is a volume. // TODO: when the geometry naming scheme will be changed, change this method - /// \param int lay The layer number for the MLOT. In the current configuration for VD this is not needed. // TODO: when the geometry naming scheme will be changed, change this method - /// \param int stave The stave number in each layer for MLOT. Starting from 0. - /// \param int halfstave The half stave number for MLOT. Can be 0 or 1 - /// \param int module The module number for MLOT, from 0 to 10 (or 20) - /// \param int chip The chip number for MLOT, from 0 to 8 - unsigned short getChipIndex(int subDetID, int volume, int lay, int stave, int halfstave, int mod, int chip) const; - - /// This routine computes subDetID, petal, disk, layer, stave, half stave, module, chip, given the chip index number - /// \param int index The chip index number, starting from 0 - /// \param int subDetID The subdetector ID, 0 for VD, 1 for MLOT - /// \param int petalcase The petal case number for VD, from 0 to 3 - /// \param int disk The disk number for VD, from 0 to 5 - /// \param int lay The layer number. Starting from 0 both for VD and MLOT - /// \param int stave The stave number for MLOT. Starting from 0 - /// \param int halfstave The half stave number for MLOT. Can be 0 or 1 - /// \param int module The module number for MLOT, from 0 to 10 (or 20) - /// \param int chip The chip number for MLOT, from 0 to 8 - bool getChipID(int index, int& subDetID, int& petalcase, int& disk, int& lay, int& stave, int& halfstave, int& mod, int& chip) const; - - unsigned short getLastChipIndex(int lay) const { return mLastChipIndex[lay]; } - unsigned short getFirstChipIndex(int lay, int petalcase, int subDetID) const - { - /// Get the first chip index of the active petal (VD) or layer (MLOT) - if (subDetID == 0) { // VD - return (petalcase == 0) ? 0 : mLastChipIndexVD[petalcase - 1] + 1; - } else if (subDetID == 1) { // MLOT - return mLastChipIndex[lay + mNumberOfPetalsVD - 1] + 1; - } - return -1; // not found - } - - /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) - /// for a given chip 'index' by quering the TGeoManager - TGeoHMatrix* extractMatrixSensor(int index) const; - - TString getMatrixPath(int index) const; - -#ifdef ENABLE_UPGRADES - static const char* composeSymNameTRK(int d) - { - return Form("%s_%d", o2::detectors::DetID(o2::detectors::DetID::TRK).getName(), d); - } -#endif - - static const char* composeSymNameLayer(int d, int layer); - static const char* composeSymNameStave(int d, int layer); - static const char* composeSymNameModule(int d, int layer); - static const char* composeSymNameChip(int d, int layer); - static const char* composeSymNameSensor(int d, int layer); - - protected: - static constexpr int MAXLAYERS = 20; ///< max number of active layers - - static std::string sVolumeName; - static std::string sLayerName; - static std::string sPetalAssemblyName; - static std::string sPetalName; - static std::string sPetalDiskName; - static std::string sPetalLayerName; - static std::string sStaveName; - static std::string sHalfStaveName; - static std::string sModuleName; - static std::string sChipName; - static std::string sSensorName; - static std::string sDeadzoneName; - static std::string sMetalStackName; - - static std::string sWrapperVolumeName; ///< Wrapper volume name, not implemented at the moment - - Int_t mNumberOfLayersMLOT; ///< number of layers - Int_t mNumberOfActivePartsVD; ///< number of layers - Int_t mNumberOfLayersVD; ///< number of layers - Int_t mNumberOfPetalsVD; ///< number of Petals = chip in each VD layer - Int_t mNumberOfDisksVD; ///< number of Disks = 6 - std::vector mNumberOfStaves; ///< Number Of Staves per layer in ML/OT - std::vector mNumberOfHalfStaves; ///< Number Of Half staves in each stave of the layer in ML/OT - std::vector mNumberOfModules; ///< Number Of Modules per stave (half stave) in ML/OT - std::vector mNumberOfChips; ///< number of chips per module in ML/OT - std::vector mNumberOfChipsPerLayerVD; ///< number of chips per layer VD ( = number of petals) - std::vector mNumberOfChipsPerLayerMLOT; ///< number of chips per layer MLOT - std::vector mNumbersOfChipPerDiskVD; ///< numbersOfChipPerDiskVD - std::vector mNumberOfChipsPerPetalVD; ///< numbersOfChipPerPetalVD - // std::vector mNumberOfChipsPerStave; ///< number of chips per stave in ML/OT - // std::vector mNumberOfChipsPerHalfStave; ///< number of chips per half stave in ML/OT - // std::vector mNumberOfChipsPerModule; ///< number of chips per module in ML/OT - std::vector mLastChipIndex; ///< max ID of the detctor in the petal(VD) or layer(MLOT) - std::vector mLastChipIndexVD; ///< max ID of the detctor in the layer for the VD - std::vector mLastChipIndexMLOT; ///< max ID of the detctor in the layer for the MLOT - - std::array mLayerToWrapper; ///< Layer to wrapper correspondence, not implemented yet - - bool mOwner = true; //! is it owned by the singleton? - - std::vector sensorsMLOT; - std::vector mCacheRefXMLOT; /// cache for X of ML and OT - std::vector mCacheRefAlphaMLOT; /// cache for sensor ref alpha ML and OT - - eMLOTLayout mLayoutMLOT; // ML and OT detector layout design - - private: - static std::unique_ptr sInstance; -}; - -} // namespace trk -} // namespace o2 -#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h index fb67b90afa7ad..63e961db44505 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h @@ -19,18 +19,6 @@ namespace o2 { namespace trk { - -enum eOverallGeom { - kDefaultRadii = 0, // After Upgrade Days March 2024 - kModRadii, -}; - -enum eLayout { - kCylinder = 0, - kTurboStaves, - kStaggered, -}; - enum eVDLayout { kIRIS4 = 0, kIRISFullCyl, @@ -39,6 +27,11 @@ enum eVDLayout { kIRIS4a, }; +enum eMLOTLayout { + kCylindrical = 0, + kSegmented, +}; + enum eSrvLayout { kPeacockv1 = 0, kLOISymm, @@ -49,16 +42,12 @@ struct TRKBaseParam : public o2::conf::ConfigurableParamHelper { float serviceTubeX0 = 0.02f; // X0 Al2O3 Bool_t irisOpen = false; - eOverallGeom overallGeom = kDefaultRadii; // Overall geometry option, to be used in Detector::buildTRKMiddleOuterLayers - - eLayout layoutML = kTurboStaves; // Type of segmentation for the middle layers - eLayout layoutOT = kStaggered; // Type of segmentation for the outer layers - eVDLayout layoutVD = kIRIS4; // VD detector layout design - eSrvLayout layoutSRV = kPeacockv1; // Layout of services + eVDLayout layoutVD = kIRIS4; // VD detector layout design + eMLOTLayout layoutMLOT = kSegmented; // ML and OT detector layout design + eSrvLayout layoutSRV = kPeacockv1; // Layout of services - eLayout getLayoutML() const { return layoutML; } - eLayout getLayoutOT() const { return layoutOT; } eVDLayout getLayoutVD() const { return layoutVD; } + eMLOTLayout getLayoutMLOT() const { return layoutMLOT; } eSrvLayout getLayoutSRV() const { return layoutSRV; } O2ParamDef(TRKBaseParam, "TRKBase"); diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam_copy.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam_copy.h deleted file mode 100644 index e43c85e9dc070..0000000000000 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam_copy.h +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -#ifndef O2_TRK_BASEPARAM_H -#define O2_TRK_BASEPARAM_H - -#include "CommonUtils/ConfigurableParam.h" -#include "CommonUtils/ConfigurableParamHelper.h" - -namespace o2 -{ -enum eVDLayout { - kIRIS4 = 0, - kIRISFullCyl, - kIRISFullCyl3InclinedWalls, - kIRIS5, - kIRIS4a, -}; - -namespace trk -{ -enum eMLOTLayout { - kCylindrical = 0, - kSegmented, -}; - -struct TRKBaseParam : public o2::conf::ConfigurableParamHelper { - std::string configFile = ""; - float serviceTubeX0 = 0.02f; // X0 Al2O3 - Bool_t irisOpen = false; - - eVDLayout layoutVD = kIRIS4; // VD detector layout design - eMLOTLayout layoutMLOT = kSegmented; // ML and OT detector layout design - - eVDLayout getLayoutVD() const { return layoutVD; } - eMLOTLayout getLayoutMLOT() const { return layoutMLOT; } - - O2ParamDef(TRKBaseParam, "TRKBase"); -}; - -} // end namespace trk -} // end namespace o2 - -#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 7b3d33ca1a75c..93c0171543eca 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -76,10 +76,9 @@ void GeometryTGeo::Build(int loadTrans) LOGP(fatal, "Geometry is not loaded"); } - mLayoutML = o2::trk::TRKBaseParam::Instance().getLayoutML(); - mLayoutOT = o2::trk::TRKBaseParam::Instance().getLayoutOT(); + mLayoutMLOT = o2::trk::TRKBaseParam::Instance().getLayoutMLOT(); - LOG(debug) << "Layout ML: " << mLayoutML << ", Layout OL: " << mLayoutOT; + LOG(debug) << "Overall layout ML and OT: " << mLayoutMLOT; mNumberOfLayersMLOT = extractNumberOfLayersMLOT(); mNumberOfPetalsVD = extractNumberOfPetalsVD(); @@ -403,9 +402,9 @@ TString GeometryTGeo::getMatrixPath(int index) const TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getTRKVolPattern()); // handling cylindrical configuration for ML and/or OT - // needed bercause of the different numbering scheme in the geometry for the cylindrical case wrt the staggered and turbo ones + // needed because of the different numbering scheme in the geometry for the cylindrical case wrt the staggered and turbo ones if (subDetID == 1) { - if ((layer < 4 && mLayoutML == eLayout::kCylinder) || (layer > 3 && mLayoutOT == eLayout::kCylinder)) { + if ((layer < 4 && mLayoutMLOT == eMLOTLayout::kCylindrical) || (layer > 3 && mLayoutMLOT == MLOTLayout::kCylindrical)) { stave = 1; mod = 1; chip = 1; diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo_copy.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo_copy.cxx deleted file mode 100644 index 93c0171543eca..0000000000000 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo_copy.cxx +++ /dev/null @@ -1,1253 +0,0 @@ -// 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. - -#include -#include -#include "TRKBase/SegmentationChip.h" -#include - -#include - -using Segmentation = o2::trk::SegmentationChip; - -namespace o2 -{ -namespace trk -{ -std::unique_ptr GeometryTGeo::sInstance; - -// Names -std::string GeometryTGeo::sVolumeName = "TRKV"; -std::string GeometryTGeo::sLayerName = "TRKLayer"; -std::string GeometryTGeo::sPetalAssemblyName = "PETAL"; -std::string GeometryTGeo::sPetalName = "PETALCASE"; -std::string GeometryTGeo::sPetalDiskName = "DISK"; -std::string GeometryTGeo::sPetalLayerName = "LAYER"; -std::string GeometryTGeo::sStaveName = "TRKStave"; -std::string GeometryTGeo::sHalfStaveName = "TRKHalfStave"; -std::string GeometryTGeo::sModuleName = "TRKModule"; -std::string GeometryTGeo::sChipName = "TRKChip"; -std::string GeometryTGeo::sSensorName = "TRKSensor"; -std::string GeometryTGeo::sDeadzoneName = "TRKDeadzone"; -std::string GeometryTGeo::sMetalStackName = "TRKMetalStack"; - -std::string GeometryTGeo::sWrapperVolumeName = "TRKUWrapVol"; ///< Wrapper volume name, not implemented at the moment - -o2::trk::GeometryTGeo::~GeometryTGeo() -{ - if (!mOwner) { - mOwner = true; - sInstance.release(); - } -} -GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : DetMatrixCache(detectors::DetID::TRK) -{ - if (sInstance) { - LOGP(fatal, "Invalid use of public constructor: o2::trk::GeometryTGeo instance exists"); - } - mLayerToWrapper.fill(-1); - if (build) { - Build(loadTrans); - } -} - -//__________________________________________________________________________ -void GeometryTGeo::Build(int loadTrans) -{ - ///// current geometry organization: - ///// total elements = x staves (*2 half staves if staggered geometry) * 8 layers ML+OT + 4 petal cases * (3 layers + 6 disks) - ///// indexing from 0 to 35: VD petals -> layers -> disks - ///// indexing from 36 to y: MLOT staves - - if (isBuilt()) { - LOGP(warning, "Already built"); - return; // already initialized - } - - if (gGeoManager == nullptr) { - LOGP(fatal, "Geometry is not loaded"); - } - - mLayoutMLOT = o2::trk::TRKBaseParam::Instance().getLayoutMLOT(); - - LOG(debug) << "Overall layout ML and OT: " << mLayoutMLOT; - - mNumberOfLayersMLOT = extractNumberOfLayersMLOT(); - mNumberOfPetalsVD = extractNumberOfPetalsVD(); - mNumberOfActivePartsVD = extractNumberOfActivePartsVD(); - mNumberOfLayersVD = extractNumberOfLayersVD(); - mNumberOfDisksVD = extractNumberOfDisksVD(); - - mNumberOfStaves.resize(mNumberOfLayersMLOT); - mNumberOfHalfStaves.resize(mNumberOfLayersMLOT); - mNumberOfModules.resize(mNumberOfLayersMLOT); - mNumberOfChips.resize(mNumberOfLayersMLOT); - - mNumberOfChipsPerLayerVD.resize(mNumberOfLayersVD); - mNumberOfChipsPerLayerMLOT.resize(mNumberOfLayersMLOT); - mNumbersOfChipPerDiskVD.resize(mNumberOfDisksVD); - mNumberOfChipsPerPetalVD.resize(mNumberOfPetalsVD); - - mLastChipIndex.resize(mNumberOfPetalsVD + mNumberOfLayersMLOT); - mLastChipIndexVD.resize(mNumberOfPetalsVD); - mLastChipIndexMLOT.resize(mNumberOfLayersMLOT); /// ML and OT are part of TRK as the same detector, without disks - - for (int i = 0; i < mNumberOfLayersMLOT; i++) { - mNumberOfStaves[i] = extractNumberOfStavesMLOT(i); - mNumberOfHalfStaves[i] = extractNumberOfHalfStavesMLOT(i); - mNumberOfModules[i] = extractNumberOfModulesMLOT(i); - mNumberOfChips[i] = extractNumberOfChipsMLOT(i); - } - - int numberOfChipsTotal = 0; - - /// filling the information for the VD - for (int i = 0; i < mNumberOfPetalsVD; i++) { - mNumberOfChipsPerPetalVD[i] = extractNumberOfChipsPerPetalVD(); - numberOfChipsTotal += mNumberOfChipsPerPetalVD[i]; - mLastChipIndex[i] = numberOfChipsTotal - 1; - mLastChipIndexVD[i] = numberOfChipsTotal - 1; - } - - /// filling the information for the MLOT - for (int i = 0; i < mNumberOfLayersMLOT; i++) { - mNumberOfChipsPerLayerMLOT[i] = mNumberOfStaves[i] * mNumberOfHalfStaves[i] * mNumberOfModules[i] * mNumberOfChips[i]; - numberOfChipsTotal += mNumberOfChipsPerLayerMLOT[i]; - mLastChipIndex[i + mNumberOfPetalsVD] = numberOfChipsTotal - 1; - mLastChipIndexMLOT[i] = numberOfChipsTotal - 1; - } - - setSize(numberOfChipsTotal); - defineMLOTSensors(); - fillTrackingFramesCacheMLOT(); - fillMatrixCache(loadTrans); -} - -//__________________________________________________________________________ -int GeometryTGeo::getSubDetID(int index) const -{ - if (index <= mLastChipIndexVD[mLastChipIndexVD.size() - 1]) { - return 0; - } else if (index > mLastChipIndexVD[mLastChipIndexVD.size() - 1]) { - return 1; - } - return -1; /// not found -} - -//__________________________________________________________________________ -int GeometryTGeo::getPetalCase(int index) const -{ - int petalcase = 0; - - int subDetID = getSubDetID(index); - if (subDetID == 1) { - return -1; - } else if (index <= mLastChipIndexVD[mNumberOfPetalsVD - 1]) { - while (index > mLastChipIndexVD[petalcase]) { - petalcase++; - } - } - return petalcase; -} - -//__________________________________________________________________________ -int GeometryTGeo::getDisk(int index) const -{ - int subDetID = getSubDetID(index); - int petalcase = getPetalCase(index); - - if (subDetID == 0) { /// VD - if (index % mNumberOfChipsPerPetalVD[petalcase] < mNumberOfLayersVD) { - return -1; /// layers - } - return (index % mNumberOfChipsPerPetalVD[petalcase]) - mNumberOfLayersVD; - } - - return -1; /// not found or ML/OT -} - -//__________________________________________________________________________ -int GeometryTGeo::getLayer(int index) const -{ - int subDetID = getSubDetID(index); - int petalcase = getPetalCase(index); - int lay = 0; - - if (subDetID == 0) { /// VD - if (index % mNumberOfChipsPerPetalVD[petalcase] >= mNumberOfLayersVD) { - return -1; /// disks - } - return index % mNumberOfChipsPerPetalVD[petalcase]; - } else if (subDetID == 1) { /// MLOT - while (index > mLastChipIndex[lay]) { - lay++; - } - return lay - mNumberOfPetalsVD; /// numeration of MLOT layers starting from 0 - } - return -1; /// -1 if not found -} -//__________________________________________________________________________ -int GeometryTGeo::getStave(int index) const -{ - int subDetID = getSubDetID(index); - int lay = getLayer(index); - int petalcase = getPetalCase(index); - - if (subDetID == 0) { /// VD - return -1; - } else if (subDetID == 1) { /// MLOT - int lay = getLayer(index); - index -= getFirstChipIndex(lay, petalcase, subDetID); // get the index of the sensing element in the layer - - const int Nhs = mNumberOfHalfStaves[lay]; - const int Nmod = mNumberOfModules[lay]; - const int Nchip = mNumberOfChips[lay]; - - if (Nhs == 2) { - int chipsPerModule = Nchip; - int chipsPerHalfStave = Nmod * chipsPerModule; - int chipsPerStave = Nhs * chipsPerHalfStave; - return index / chipsPerStave; - } else if (Nhs == 1) { - int chipsPerModule = Nchip; - int chipsPerStave = Nmod * chipsPerModule; - return index / chipsPerStave; - } - } - return -1; -} - -//__________________________________________________________________________ -int GeometryTGeo::getHalfStave(int index) const -{ - int subDetID = getSubDetID(index); - int lay = getLayer(index); - int petalcase = getPetalCase(index); - - if (subDetID == 0) { /// VD - return -1; - } else if (subDetID == 1) { /// MLOT - int lay = getLayer(index); - index -= getFirstChipIndex(lay, petalcase, subDetID); // get the index of the sensing element in the layer - - const int Nhs = mNumberOfHalfStaves[lay]; - const int Nmod = mNumberOfModules[lay]; - const int Nchip = mNumberOfChips[lay]; - - int chipsPerModule = Nchip; - int chipsPerHalfStave = Nmod * chipsPerModule; - int chipsPerStave = Nhs * chipsPerHalfStave; - - int rem = index % chipsPerStave; - return rem / chipsPerHalfStave; // 0 = left, 1 = right - } - return -1; -} - -//__________________________________________________________________________ -int GeometryTGeo::getModule(int index) const -{ - int subDetID = getSubDetID(index); - int lay = getLayer(index); - int petalcase = getPetalCase(index); - - if (subDetID == 0) { /// VD - return -1; - } else if (subDetID == 1) { /// MLOT - int lay = getLayer(index); - index -= getFirstChipIndex(lay, petalcase, subDetID); // get the index of the sensing element in the layer - - const int Nhs = mNumberOfHalfStaves[lay]; - const int Nmod = mNumberOfModules[lay]; - const int Nchip = mNumberOfChips[lay]; - - if (Nhs == 2) { - int chipsPerModule = Nchip; - int chipsPerHalfStave = Nmod * chipsPerModule; - int rem = index % (Nhs * chipsPerHalfStave); - rem = rem % chipsPerHalfStave; - return rem / chipsPerModule; - } else if (Nhs == 1) { - int chipsPerModule = Nchip; - int rem = index % (Nmod * chipsPerModule); - return rem / chipsPerModule; - } - } - return -1; -} - -//__________________________________________________________________________ -int GeometryTGeo::getChip(int index) const -{ - int subDetID = getSubDetID(index); - int lay = getLayer(index); - int petalcase = getPetalCase(index); - - if (subDetID == 0) { /// VD - return -1; - } else if (subDetID == 1) { /// MLOT - int lay = getLayer(index); - index -= getFirstChipIndex(lay, petalcase, subDetID); // get the index of the sensing element in the layer - - const int Nhs = mNumberOfHalfStaves[lay]; - const int Nmod = mNumberOfModules[lay]; - const int Nchip = mNumberOfChips[lay]; - - if (Nhs == 2) { - int chipsPerModule = Nchip; - return index % chipsPerModule; - } else if (Nhs == 1) { - int chipsPerModule = Nchip; - return index % chipsPerModule; - } - } - return -1; -} - -//__________________________________________________________________________ -unsigned short GeometryTGeo::getChipIndex(int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int mod, int chip) const -{ - if (subDetID == 0) { // VD - if (lay == -1) { // disk - return getFirstChipIndex(lay, petalcase, subDetID) + mNumberOfLayersVD + disk; - } else { // layer - return getFirstChipIndex(lay, petalcase, subDetID) + lay; - } - } else if (subDetID == 1) { // MLOT - const int Nhs = mNumberOfHalfStaves[lay]; // 1 or 2 - const int Nmod = mNumberOfModules[lay]; // module per half-stave (per stave if Nhs==1) - const int Nchip = mNumberOfChips[lay]; // chips per module - - if (Nhs == 2) { // staggered geometry: layer -> stave -> halfstave -> mod -> chip - int chipsPerModule = Nchip; - int chipsPerHalfStave = Nmod * chipsPerModule; - int chipsPerStave = Nhs * chipsPerHalfStave; - return getFirstChipIndex(lay, petalcase, subDetID) + stave * chipsPerStave + halfstave * chipsPerHalfStave + mod * chipsPerModule + chip; - } else if (Nhs == 1) { // turbo geometry: layer -> stave -> mod -> chip (no halfstave) - int chipsPerModule = Nchip; - int chipsPerStave = Nmod * chipsPerModule; - return getFirstChipIndex(lay, petalcase, subDetID) + stave * chipsPerStave + mod * chipsPerModule + chip; - } - } - - LOGP(warning, "Chip index not found for subDetID %d, petalcase %d, disk %d, layer %d, stave %d, halfstave %d, module %d, chip %d, returning numeric limit", subDetID, petalcase, disk, lay, stave, halfstave, mod, chip); - return std::numeric_limits::max(); // not found -} - -//__________________________________________________________________________ -unsigned short GeometryTGeo::getChipIndex(int subDetID, int volume, int lay, int stave, int halfstave, int mod, int chip) const -{ - if (subDetID == 0) { // VD - return volume; /// In the current configuration for VD, each volume is the sensor element = chip. // TODO: when the geometry naming scheme will be changed, change this method - - } else if (subDetID == 1) { // MLOT - const int Nhs = mNumberOfHalfStaves[lay]; // 1 or 2 - const int Nmod = mNumberOfModules[lay]; // module per half-stave (per stave if Nhs==1) - const int Nchip = mNumberOfChips[lay]; // chips per module - - if (Nhs == 2) { // staggered geometry: layer -> stave -> halfstave -> mod -> chip - int chipsPerModule = Nchip; - int chipsPerHalfStave = Nmod * chipsPerModule; - int chipsPerStave = Nhs * chipsPerHalfStave; - return getFirstChipIndex(lay, -1, subDetID) + stave * chipsPerStave + halfstave * chipsPerHalfStave + mod * chipsPerModule + chip; - } else if (Nhs == 1) { // turbo geometry: layer -> stave -> mod -> chip (no halfstave) - int chipsPerModule = Nchip; - int chipsPerStave = Nmod * chipsPerModule; - return getFirstChipIndex(lay, -1, subDetID) + stave * chipsPerStave + mod * chipsPerModule + chip; - } - } - - LOGP(warning, "Chip index not found for subDetID %d, volume %d, layer %d, stave %d, halfstave %d, module %d, chip %d, returning numeric limit", subDetID, volume, lay, stave, halfstave, mod, chip); - return std::numeric_limits::max(); // not found -} - -//__________________________________________________________________________ -bool GeometryTGeo::getChipID(int index, int& subDetID, int& petalcase, int& disk, int& lay, int& stave, int& halfstave, int& mod, int& chip) const -{ - subDetID = getSubDetID(index); - petalcase = getPetalCase(index); - disk = getDisk(index); - lay = getLayer(index); - stave = getStave(index); - if (mNumberOfHalfStaves[lay] == 2) { - halfstave = getHalfStave(index); - } else { - halfstave = 0; // if not staggered geometry, return 0 - } - halfstave = getHalfStave(index); - mod = getModule(index); - chip = getChip(index); - - return kTRUE; -} - -//__________________________________________________________________________ -TString GeometryTGeo::getMatrixPath(int index) const -{ - - int subDetID, petalcase, disk, layer, stave, halfstave, mod, chip; - getChipID(index, subDetID, petalcase, disk, layer, stave, halfstave, mod, chip); - - // PrintChipID(index, subDetID, petalcase, disk, layer, stave, halfstave, mod, chip); - - // 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()); - - // handling cylindrical configuration for ML and/or OT - // needed because of the different numbering scheme in the geometry for the cylindrical case wrt the staggered and turbo ones - if (subDetID == 1) { - if ((layer < 4 && mLayoutMLOT == eMLOTLayout::kCylindrical) || (layer > 3 && mLayoutMLOT == MLOTLayout::kCylindrical)) { - stave = 1; - mod = 1; - chip = 1; - } - } - - // build the path - if (subDetID == 0) { // VD - if (disk >= 0) { - path += Form("%s_%d_%d/", getTRKPetalAssemblyPattern(), petalcase, petalcase + 1); // PETAL_n - 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_%d/", getTRKPetalAssemblyPattern(), petalcase, petalcase + 1); // PETAL_n - 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/", getTRKHalfStavePattern(), layer, halfstave); // TRKHalfStavex_y - } - path += Form("%s%d_%d/", getTRKModulePattern(), layer, mod); // TRKModulx_y - path += Form("%s%d_%d/", getTRKChipPattern(), layer, chip); // TRKChipx_y - path += Form("%s%d_1/", getTRKSensorPattern(), layer); // TRKSensorx_1 - } - return path; -} - -//__________________________________________________________________________ -TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const -{ - // extract matrix transforming from the PHYSICAL sensor frame to global one - // 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. - - 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 - // 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 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; - // } - // std::cout<<"-----"<GetVolume(getTRKVolPattern()); - if (trkV == nullptr) { - LOG(fatal) << getName() << " volume " << getTRKVolPattern() << " is not in the geometry"; - } - - // Loop on all TRKV nodes, count Layer volumes by checking names - // Build on the fly layer - wrapper correspondence - TObjArray* nodes = trkV->GetNodes(); - // nodes->Print(); - int nNodes = nodes->GetEntriesFast(); - for (int j = 0; j < nNodes; j++) { - int lrID = -1; - auto nd = dynamic_cast(nodes->At(j)); - const char* name = nd->GetName(); - if (strstr(name, getTRKLayerPattern()) != nullptr) { - numberOfLayers++; - if ((lrID = extractVolumeCopy(name, GeometryTGeo::getTRKLayerPattern())) < 0) { - LOG(fatal) << "Failed to extract layer ID from the " << name; - } - mLayerToWrapper[lrID] = -1; // not wrapped - } else if (strstr(name, getTRKWrapVolPattern()) != nullptr) { // this is a wrapper volume, may cointain layers - int wrID = -1; - if ((wrID = extractVolumeCopy(name, GeometryTGeo::getTRKWrapVolPattern())) < 0) { - LOG(fatal) << "Failed to extract wrapper ID from the " << name; - } - TObjArray* nodesW = nd->GetNodes(); - int nNodesW = nodesW->GetEntriesFast(); - - for (int jw = 0; jw < nNodesW; jw++) { - auto ndW = dynamic_cast(nodesW->At(jw))->GetName(); - if (strstr(ndW, getTRKLayerPattern()) != nullptr) { - if ((lrID = extractVolumeCopy(ndW, GeometryTGeo::getTRKLayerPattern())) < 0) { - LOGP(fatal, "Failed to extract layer ID from wrapper volume '{}' from one of its nodes '{}'", name, ndW); - } - numberOfLayers++; - mLayerToWrapper[lrID] = wrID; - } - } - } - } - return numberOfLayers; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfPetalsVD() const -{ - int numberOfPetals = 0; - TGeoVolume* trkV = gGeoManager->GetVolume(getTRKVolPattern()); - if (!trkV) { - LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); - return 0; - } - - // Loop on all TRKV nodes, count PETAL assemblies and their contents - TObjArray* nodes = trkV->GetNodes(); - if (!nodes) { - LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); - return 0; - } - - LOGP(info, "Searching for petal assemblies in {} (pattern: {})", - getTRKVolPattern(), getTRKPetalAssemblyPattern()); - - for (int j = 0; j < nodes->GetEntriesFast(); j++) { - auto* nd = dynamic_cast(nodes->At(j)); - const char* name = nd->GetName(); - - if (strstr(name, getTRKPetalAssemblyPattern()) != nullptr) { - numberOfPetals++; - LOGP(info, "Found petal assembly: {}", name); - - // Get petal volume and its nodes for debugging - TGeoVolume* petalVol = nd->GetVolume(); - if (petalVol) { - TObjArray* petalNodes = petalVol->GetNodes(); - if (petalNodes) { - LOGP(debug, "Petal {} contains {} child nodes", name, petalNodes->GetEntriesFast()); - // Print all nodes in this petal - for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { - auto* petalNode = dynamic_cast(petalNodes->At(k)); - LOGP(debug, " Node {}: {}", k, petalNode->GetName()); - } - } else { - LOGP(warning, "Petal {} has no child nodes", name); - } - } else { - LOGP(warning, "Petal {} has no volume", name); - } - } - } - - if (numberOfPetals == 0) { - LOGP(warning, "No petal assemblies found in geometry"); - } else { - LOGP(info, "Found {} petal assemblies", numberOfPetals); - } - - return numberOfPetals; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfActivePartsVD() const -{ - // The number of active parts returned here is 36 = 4 petals * (3 layers + 6 disks) - int numberOfParts = 0; - TGeoVolume* vdV = gGeoManager->GetVolume(getTRKVolPattern()); - if (!vdV) { - LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); - return 0; - } - - // Find first petal to count its active parts - TObjArray* nodes = vdV->GetNodes(); - if (!nodes) { - LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); - return 0; - } - - bool petalFound = false; - - for (int j = 0; j < nodes->GetEntriesFast(); j++) { - auto* nd = dynamic_cast(nodes->At(j)); - const char* name = nd->GetName(); - if (strstr(name, getTRKPetalAssemblyPattern()) == nullptr) { - continue; - } - - petalFound = true; - LOGP(info, "Counting active parts in petal: {}", name); - - // Found a petal, count its layers and disks - TGeoVolume* petalVol = nd->GetVolume(); - if (!petalVol) { - LOGP(warning, "Petal {} has no volume", name); - break; - } - - TObjArray* petalNodes = petalVol->GetNodes(); - if (!petalNodes) { - LOGP(warning, "Petal {} has no child nodes", name); - break; - } - - for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { - auto* petalNode = dynamic_cast(petalNodes->At(k)); - const char* nodeName = petalNode->GetName(); - - if (strstr(nodeName, getTRKPetalLayerPattern()) != nullptr || - strstr(nodeName, getTRKPetalDiskPattern()) != nullptr) { - numberOfParts++; - LOGP(debug, "Found active part in {}: {}", name, nodeName); - } - } - // We only need to check one petal as they're identical - break; - } - - if (!petalFound) { - LOGP(warning, "No petal assembly found matching pattern '{}'", getTRKPetalAssemblyPattern()); - return 0; - } - - if (numberOfParts == 0) { - LOGP(warning, "No active parts (layers/disks) found in petal"); - return 0; - } - - // Multiply by number of petals since all petals are identical - int totalParts = numberOfParts * mNumberOfPetalsVD; - LOGP(info, "Total number of active parts: {} ({}*{})", - totalParts, numberOfParts, mNumberOfPetalsVD); - return totalParts; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfDisksVD() const -{ - // Count disks in the first petal (all petals are identical) - int numberOfDisks = 0; - TGeoVolume* vdV = gGeoManager->GetVolume(getTRKVolPattern()); - if (!vdV) { - LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); - return 0; - } - - // Find first petal - TObjArray* nodes = vdV->GetNodes(); - if (!nodes) { - LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); - return 0; - } - - bool petalFound = false; - - for (int j = 0; j < nodes->GetEntriesFast(); j++) { - auto* nd = dynamic_cast(nodes->At(j)); - if (strstr(nd->GetName(), getTRKPetalAssemblyPattern()) == nullptr) { - continue; - } - - petalFound = true; - LOGP(info, "Counting disks in petal: {}", nd->GetName()); - - // Count disks in this petal - TGeoVolume* petalVol = nd->GetVolume(); - if (!petalVol) { - LOGP(warning, "Petal {} has no volume", nd->GetName()); - break; - } - - TObjArray* petalNodes = petalVol->GetNodes(); - if (!petalNodes) { - LOGP(warning, "Petal {} has no child nodes", nd->GetName()); - break; - } - - for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { - auto* petalNode = dynamic_cast(petalNodes->At(k)); - if (strstr(petalNode->GetName(), getTRKPetalDiskPattern()) != nullptr) { - numberOfDisks++; - LOGP(info, "Found disk in {} : {}", nd->GetName(), petalNode->GetName()); - } - } - // One petal is enough - break; - } - - if (!petalFound) { - LOGP(warning, "No petal assembly found matching pattern '{}'", getTRKPetalAssemblyPattern()); - } - - if (numberOfDisks == 0) { - LOGP(warning, "No disks found in VD geometry"); - } - - return numberOfDisks; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfLayersVD() const -{ - // Count layers in the first petal (all petals are identical) - int numberOfLayers = 0; - TGeoVolume* vdV = gGeoManager->GetVolume(getTRKVolPattern()); - if (!vdV) { - LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); - return 0; - } - - // Find first petal - TObjArray* nodes = vdV->GetNodes(); - if (!nodes) { - LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); - return 0; - } - - bool petalFound = false; - - for (int j = 0; j < nodes->GetEntriesFast(); j++) { - auto* nd = dynamic_cast(nodes->At(j)); - if (strstr(nd->GetName(), getTRKPetalAssemblyPattern()) == nullptr) { - continue; - } - - petalFound = true; - LOGP(info, "Counting layers in petal: {}", nd->GetName()); - - // Count layers in this petal - TGeoVolume* petalVol = nd->GetVolume(); - if (!petalVol) { - LOGP(warning, "Petal {} has no volume", nd->GetName()); - break; - } - - TObjArray* petalNodes = petalVol->GetNodes(); - if (!petalNodes) { - LOGP(warning, "Petal {} has no child nodes", nd->GetName()); - break; - } - - for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { - auto* petalNode = dynamic_cast(petalNodes->At(k)); - if (strstr(petalNode->GetName(), getTRKPetalLayerPattern()) != nullptr) { - numberOfLayers++; - LOGP(info, "Found layer in {} : {}", nd->GetName(), petalNode->GetName()); - } - } - // One petal is enough - break; - } - - if (!petalFound) { - LOGP(warning, "No petal assembly found matching pattern '{}'", getTRKPetalAssemblyPattern()); - } - - if (numberOfLayers == 0) { - LOGP(warning, "No layers found in VD geometry"); - } - - return numberOfLayers; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfChipsPerPetalVD() const -{ - // The number of chips per petal returned here is 9 for each layer = number of layers + number of quarters of disks per petal - int numberOfChips = 0; - TGeoVolume* vdV = gGeoManager->GetVolume(getTRKVolPattern()); - if (!vdV) { - LOGP(fatal, "{} volume {} is not in the geometry", getName(), getTRKVolPattern()); - return 0; - } - - // Find first petal assembly - TObjArray* nodes = vdV->GetNodes(); - if (!nodes) { - LOGP(warning, "{} volume has no child nodes", getTRKVolPattern()); - return 0; - } - - bool petalFound = false; - - for (int j = 0; j < nodes->GetEntriesFast(); j++) { - auto* nd = dynamic_cast(nodes->At(j)); - const char* name = nd->GetName(); - if (strstr(name, getTRKPetalAssemblyPattern()) == nullptr) { - continue; - } - - petalFound = true; - LOGP(info, "Counting chips in petal: {}", name); - - // Found a petal, count sensors in its layers and disks - TGeoVolume* petalVol = nd->GetVolume(); - if (!petalVol) { - LOGP(warning, "Petal {} has no volume", name); - break; - } - - TObjArray* petalNodes = petalVol->GetNodes(); - if (!petalNodes) { - LOGP(warning, "Petal {} has no child nodes", name); - break; - } - - for (int k = 0; k < petalNodes->GetEntriesFast(); k++) { - auto* petalNode = dynamic_cast(petalNodes->At(k)); - const char* nodeName = petalNode->GetName(); - TGeoVolume* vol = petalNode->GetVolume(); - - if (!vol) { - LOGP(debug, "Node {} has no volume", nodeName); - continue; - } - - // Look for sensors in this volume - TObjArray* subNodes = vol->GetNodes(); - if (!subNodes) { - LOGP(debug, "Node {} has no sub-nodes", nodeName); - continue; - } - - for (int i = 0; i < subNodes->GetEntriesFast(); i++) { - auto* subNode = dynamic_cast(subNodes->At(i)); - if (strstr(subNode->GetName(), getTRKChipPattern()) != nullptr) { - numberOfChips++; - LOGP(debug, "Found chip in {}: {}", nodeName, subNode->GetName()); - } - } - } - // We only need one petal - break; - } - - if (!petalFound) { - LOGP(warning, "No petal assembly found matching pattern '{}'", getTRKPetalAssemblyPattern()); - } - - if (numberOfChips == 0) { - LOGP(warning, "No chips/sensors found in VD petal"); - } - - LOGP(info, "Number of chips per petal: {}", numberOfChips); - return numberOfChips; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfStavesMLOT(int lay) const -{ - int numberOfStaves = 0; - - std::string layName = Form("%s%d", getTRKLayerPattern(), lay); - TGeoVolume* layV = gGeoManager->GetVolume(layName.c_str()); - - if (layV == nullptr) { - LOG(fatal) << getName() << " volume " << getTRKLayerPattern() << " is not in the geometry"; - } - - // Loop on all layV nodes, count Layer volumes by checking names - TObjArray* nodes = layV->GetNodes(); - // std::cout << "Printing nodes for layer " << lay << std::endl; - // nodes->Print(); - int nNodes = nodes->GetEntriesFast(); - - for (int j = 0; j < nNodes; j++) { - int lrID = -1; - auto nd = dynamic_cast(nodes->At(j)); /// layer node - const char* name = nd->GetName(); - if (strstr(name, getTRKStavePattern()) != nullptr) { - numberOfStaves++; - } - } - return numberOfStaves; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfHalfStavesMLOT(int lay) const -{ - int numberOfHalfStaves = 0; - - std::string staveName = Form("%s%d", getTRKStavePattern(), lay); - TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str()); - - if (staveV == nullptr) { - LOG(fatal) << getName() << " volume " << getTRKStavePattern() << " is not in the geometry"; - } - - // Loop on all layV nodes, count Layer volumes by checking names - TObjArray* nodes = staveV->GetNodes(); - // std::cout << "Printing nodes for layer " << lay << std::endl; - // nodes->Print(); - int nNodes = nodes->GetEntriesFast(); - - for (int j = 0; j < nNodes; j++) { - auto nd = dynamic_cast(nodes->At(j)); /// layer node - const char* name = nd->GetName(); - if (strstr(name, getTRKHalfStavePattern()) != nullptr) { - numberOfHalfStaves++; - } - } - - if (numberOfHalfStaves == 0) { - numberOfHalfStaves = 1; /// in case of turbo geometry, there is no half stave volume, but only stave volume - } - return numberOfHalfStaves; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfModulesMLOT(int lay) const -{ - int numberOfModules = 0; - - std::string staveName = Form("%s%d", (mNumberOfHalfStaves[lay] == 2 ? getTRKHalfStavePattern() : getTRKStavePattern()), lay); - TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str()); - - if (staveV == nullptr) { - LOG(fatal) << getName() << " volume " << (mNumberOfHalfStaves[lay] == 2 ? getTRKHalfStavePattern() : getTRKStavePattern()) << " is not in the geometry"; - } - - // Loop on all staveV nodes, count Module volumes by checking names - TObjArray* nodes = staveV->GetNodes(); - int nNodes = nodes->GetEntriesFast(); - - for (int j = 0; j < nNodes; j++) { - auto nd = dynamic_cast(nodes->At(j)); /// stave node - const char* name = nd->GetName(); - if (strstr(name, getTRKModulePattern()) != nullptr) { - numberOfModules++; - } - } - return numberOfModules; -} - -//__________________________________________________________________________ -int GeometryTGeo::extractNumberOfChipsMLOT(int lay) const -{ - int numberOfChips = 0; - - std::string moduleName = Form("%s%d", getTRKModulePattern(), lay); - TGeoVolume* moduleV = gGeoManager->GetVolume(moduleName.c_str()); - - if (moduleV == nullptr) { - LOG(fatal) << getName() << " volume " << getTRKModulePattern() << " is not in the geometry"; - } - - // Loop on all moduleV nodes, count Chip volumes by checking names - TObjArray* nodes = moduleV->GetNodes(); - int nNodes = nodes->GetEntriesFast(); - - for (int j = 0; j < nNodes; j++) { - auto nd = dynamic_cast(nodes->At(j)); /// module node - const char* name = nd->GetName(); - if (strstr(name, getTRKChipPattern()) != nullptr) { - numberOfChips++; - } - } - return numberOfChips; -} - -//__________________________________________________________________________ -void GeometryTGeo::PrintChipID(int index, int subDetID, int petalcase, int disk, int lay, int stave, int halfstave, int mod, int chip) const -{ - std::cout << "\nindex = " << index << std::endl; - std::cout << "subDetID = " << subDetID << std::endl; - std::cout << "petalcase = " << petalcase << std::endl; - std::cout << "layer = " << lay << std::endl; - std::cout << "disk = " << disk << std::endl; - 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 << "module = " << mod << std::endl; - std::cout << "chip = " << chip << std::endl; -} - -//__________________________________________________________________________ -void GeometryTGeo::Print(Option_t*) const -{ - if (!isBuilt()) { - LOGF(info, "Geometry not built yet!"); - return; - } - std::cout << "Detector ID: " << sInstance.get()->getDetID() << std::endl; - - LOGF(info, "Summary of GeometryTGeo: %s", getName()); - LOGF(info, "Number of layers ML + OL: %d", mNumberOfLayersMLOT); - LOGF(info, "Number of active parts VD: %d", mNumberOfActivePartsVD); - LOGF(info, "Number of layers VD: %d", mNumberOfLayersVD); - LOGF(info, "Number of petals VD: %d", mNumberOfPetalsVD); - LOGF(info, "Number of disks VD: %d", mNumberOfDisksVD); - LOGF(info, "Number of chips per petal VD: "); - for (int i = 0; i < mNumberOfPetalsVD; i++) { - LOGF(info, "%d", mNumberOfChipsPerPetalVD[i]); - } - LOGF(info, "Number of staves and half staves per layer MLOT: "); - for (int i = 0; i < mNumberOfLayersMLOT; i++) { - std::string mlot = ""; - mlot = (i < 4) ? "ML" : "OT"; - LOGF(info, "Layer: %d, %s, %d staves, %d half staves per stave", i, mlot.c_str(), mNumberOfStaves[i], mNumberOfHalfStaves[i]); - } - LOGF(info, "Number of modules per stave (half stave) in each ML(OT) layer: "); - for (int i = 0; i < mNumberOfLayersMLOT; i++) { - LOGF(info, "%d", mNumberOfModules[i]); - } - LOGF(info, "Number of chips per module MLOT: "); - for (int i = 0; i < mNumberOfLayersMLOT; i++) { - LOGF(info, "%d", mNumberOfChips[i]); - } - LOGF(info, "Number of chips per layer MLOT: "); - for (int i = 0; i < mNumberOfLayersMLOT; i++) { - LOGF(info, "%d", mNumberOfChipsPerLayerMLOT[i]); - } - LOGF(info, "Total number of chips: %d", getNumberOfChips()); - - std::cout << "mLastChipIndex = ["; - for (int i = 0; i < mLastChipIndex.size(); i++) { - std::cout << mLastChipIndex[i]; - if (i < mLastChipIndex.size() - 1) { - std::cout << ", "; - } - } - std::cout << "]" << std::endl; - std::cout << "mLastChipIndexVD = ["; - for (int i = 0; i < mLastChipIndexVD.size(); i++) { - std::cout << mLastChipIndexVD[i]; - if (i < mLastChipIndexVD.size() - 1) { - std::cout << ", "; - } - } - std::cout << "]" << std::endl; -} - -//__________________________________________________________________________ -int GeometryTGeo::getBarrelLayer(int chipID) const -{ - // for barrel layers only, - // so it would be consistent with number of layers i.e. from 0 to 10, - // starting from VD0 to OT10; - // skip the disks; - - int subDetID = getSubDetID(chipID); - int subLayerID = getLayer(chipID); - - if (subDetID < 0 || subDetID > 1) { - LOG(error) << "getBarrelLayer(): Invalid subDetID for barrel: " << subDetID - << ". Expected values are 0 or 1."; - return -1; - } - - if (subLayerID < 0 || subLayerID > 7) { - LOG(error) << "getBarrelLayer(): Invalid subLayerID for barrel: " << subDetID - << ". Expected values are between 0 and 7."; - return -1; - } - - const int baseOffsets[] = {0, 3}; - - return baseOffsets[subDetID] + subLayerID; -} - -//__________________________________________________________________________ -void GeometryTGeo::extractSensorXAlphaMLOT(int chipID, float& x, float& alp) -{ - // works for ML and OT only, a.k.a flat sensors !!! - double locA[3] = {-100., 0., 0.}, locB[3] = {100., 0., 0.}, gloA[3], gloB[3]; - double xp{0}, yp{0}; - - if (getSubDetID(chipID) == 0) { - - LOG(error) << "extractSensorXAlphaMLOT(): VD layers are not supported yet! chipID = " << chipID; - return; - - } else { // flat sensors, ML and OT - const TGeoHMatrix* matL2G = extractMatrixSensor(chipID); - matL2G->LocalToMaster(locA, gloA); - matL2G->LocalToMaster(locB, gloB); - double dx = gloB[0] - gloA[0], dy = gloB[1] - gloA[1]; - double t = (gloB[0] * dx + gloB[1] * dy) / (dx * dx + dy * dy); - xp = gloB[0] - dx * t; - yp = gloB[1] - dy * t; - } - - alp = std::atan2(yp, xp); - x = std::hypot(xp, yp); - o2::math_utils::bringTo02Pi(alp); - - /// TODO: - // once the VD segmentation is done, VD should be added -} - -//__________________________________________________________________________ -TGeoHMatrix& GeometryTGeo::createT2LMatrixMLOT(int chipID) -{ - // works only for ML & OT - // for VD is yet to be implemented once we have more refined geometry - if (getSubDetID(chipID) == 0) { - - LOG(error) << "createT2LMatrixMLOT(): VD layers are not supported yet! chipID = " << chipID - << "returning dummy values! "; - static TGeoHMatrix dummy; - return dummy; - - } else { - static TGeoHMatrix t2l; - t2l.Clear(); - float alpha = getSensorRefAlphaMLOT(chipID); - t2l.RotateZ(alpha * TMath::RadToDeg()); - const TGeoHMatrix* matL2G = extractMatrixSensor(chipID); - const TGeoHMatrix& matL2Gi = matL2G->Inverse(); - t2l.MultiplyLeft(&matL2Gi); - return t2l; - } -} - -} // namespace trk -} // namespace o2 diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h index 32bdc89109269..ed2c7bfea6218 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h @@ -66,8 +66,7 @@ class Detector : public o2::base::DetImpl return nullptr; } - void configDefault(); - void buildTRKMiddleOuterLayers(); + void configMLOT(); void configFromFile(std::string fileName = "alice3_TRK_layout.txt"); void configToFile(std::string fileName = "alice3_TRK_layout.txt"); @@ -89,7 +88,7 @@ class Detector : public o2::base::DetImpl } mTrackData; //! transient data GeometryTGeo* mGeometryTGeo; //! std::vector* mHits; // ITSMFT ones for the moment - std::vector mLayers; + std::vector> mLayers; TRKServices mServices; // Houses the services of the TRK, but not the Iris tracker std::vector mFirstOrLastLayers; // Names of the first or last layers diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector_copy.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector_copy.h deleted file mode 100644 index ed2c7bfea6218..0000000000000 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector_copy.h +++ /dev/null @@ -1,128 +0,0 @@ -// 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. - -#ifndef ALICEO2_TRK_DETECTOR_H -#define ALICEO2_TRK_DETECTOR_H - -#include "DetectorsBase/Detector.h" -#include "TRKSimulation/Hit.h" - -#include "TRKSimulation/TRKLayer.h" -#include "TRKSimulation/TRKServices.h" -#include "TRKBase/GeometryTGeo.h" - -#include -#include - -namespace o2 -{ -namespace trk -{ - -class Detector : public o2::base::DetImpl -{ - public: - Detector(bool active); - Detector(); - ~Detector(); - - // Factory method - static o2::base::Detector* create(bool active) - { - return new Detector(active); - } - - void ConstructGeometry() override; - - o2::trk::Hit* addHit(int trackID, unsigned short detID, const TVector3& startPos, const TVector3& endPos, - const TVector3& startMom, double startE, double endTime, double eLoss, - unsigned char startStatus, unsigned char endStatus); - - // Mandatory overrides - void BeginPrimary() override { ; } - void FinishPrimary() override { ; } - void InitializeO2Detector() override; - void PostTrack() override { ; } - void PreTrack() override { ; } - bool ProcessHits(FairVolume* v = nullptr) override; - void EndOfEvent() override; - void Register() override; - void Reset() override; - - // Custom member functions - std::vector* getHits(int iColl) const - { - if (!iColl) { - return mHits; - } - return nullptr; - } - - void configMLOT(); - void configFromFile(std::string fileName = "alice3_TRK_layout.txt"); - void configToFile(std::string fileName = "alice3_TRK_layout.txt"); - - void configServices(); // To get special conf from CLI options - void createMaterials(); - void createGeometry(); - - private: - int mNumberOfVolumes; - int mNumberOfVolumesVD; - - // Transient data about track passing the sensor - struct TrackData { - bool mHitStarted; // hit creation started - unsigned char mTrkStatusStart; // track status flag - TLorentzVector mPositionStart; // position at entrance - TLorentzVector mMomentumStart; // momentum - double mEnergyLoss; // energy loss - } mTrackData; //! transient data - GeometryTGeo* mGeometryTGeo; //! - std::vector* mHits; // ITSMFT ones for the moment - std::vector> mLayers; - TRKServices mServices; // Houses the services of the TRK, but not the Iris tracker - - std::vector mFirstOrLastLayers; // Names of the first or last layers - bool InsideFirstOrLastLayer(std::string layerName); - - void defineSensitiveVolumes(); - - protected: - std::vector mSensorID; //! layer identifiers - std::vector mSensorName; //! layer names - - public: - static constexpr Int_t sNumberVDPetalCases = 4; //! Number of VD petals - int getNumberOfLayers() const { return mLayers.size(); } //! Number of TRK layers - - void Print(FairVolume* vol, int volume, int subDetID, int layer, int stave, int halfstave, int mod, int chip, int chipID) const; - - template - friend class o2::base::DetImpl; - ClassDefOverride(Detector, 2); -}; -} // namespace trk -} // namespace o2 - -#ifdef USESHM -namespace o2 -{ -namespace base -{ -template <> -struct UseShm { - static constexpr bool value = true; -}; -} // namespace base -} // namespace o2 -#endif -#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h index 39dd7752cc010..c0e15d36929a4 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h @@ -22,57 +22,112 @@ namespace o2 { namespace trk { -class TRKLayer +class TRKCylindricalLayer { public: - TRKLayer() = default; - TRKLayer(int layerNumber, std::string layerName, float rInn, float rOut, int numberOfModules, float layerX2X0); - TRKLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); - ~TRKLayer() = default; - - void setLayout(eLayout layout) { mLayout = layout; }; + TRKCylindricalLayer() = default; + TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float layerX2X0); + TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thick); + virtual ~TRKCylindricalLayer() = default; auto getInnerRadius() const { return mInnerRadius; } auto getOuterRadius() const { return mOuterRadius; } - auto getZ() const { return constants::moduleMLOT::length * mNumberOfModules; } + auto getZ() const { return mLength; } auto getx2X0() const { return mX2X0; } auto getChipThickness() const { return mChipThickness; } auto getNumber() const { return mLayerNumber; } auto getName() const { return mLayerName; } - TGeoVolume* createSensor(std::string type); - TGeoVolume* createDeadzone(std::string type); - TGeoVolume* createMetalStack(std::string type); - TGeoVolume* createChip(std::string type); - TGeoVolume* createModule(std::string type); - TGeoVolume* createStave(std::string type); - TGeoVolume* createHalfStave(std::string type); - void createLayer(TGeoVolume* motherVolume); - - private: - // TGeo objects outside logical volumes can cause errors. Only used in case of kStaggered and kTurboStaves layouts - static constexpr float mLogicalVolumeThickness = 1.3; + virtual TGeoVolume* createSensor(); + virtual TGeoVolume* createMetalStack(); + virtual void createLayer(TGeoVolume* motherVolume); + protected: // User defined parameters for the layer, to be set in the constructor int mLayerNumber; std::string mLayerName; float mInnerRadius; float mOuterRadius; - int mNumberOfModules; + float mLength; float mX2X0; float mChipThickness; // Fixed parameters for the layer, to be set based on the specifications of the chip and module - eLayout mLayout = kCylinder; - float mChipWidth = constants::moduleMLOT::chip::width; - float mChipLength = constants::moduleMLOT::chip::length; - float mDeadzoneWidth = constants::moduleMLOT::chip::passiveEdgeReadOut; - float mSensorThickness = constants::moduleMLOT::silicon::thickness; - int mHalfNumberOfChips = 4; + static constexpr double sSensorThickness = constants::moduleMLOT::silicon::thickness; static constexpr float Si_X0 = 9.5f; - ClassDef(TRKLayer, 2); + ClassDef(TRKCylindricalLayer, 0); +}; + +class TRKSegmentedLayer : public TRKCylindricalLayer +{ + public: + TRKSegmentedLayer() = default; + TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); + TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + ~TRKSegmentedLayer() override = default; + + TGeoVolume* createSensor() override; + TGeoVolume* createDeadzone(); + TGeoVolume* createMetalStack() override; + TGeoVolume* createChip(); + TGeoVolume* createModule(); + TGeoVolume* createStave() = 0; + void createLayer(TGeoVolume* motherVolume) override = 0; + + private: + int mNumberOfModules; + + // Fixed parameters for the layer, to be set based on the specifications of the chip and module + static constexpr double sChipWidth = constants::moduleMLOT::chip::width; + static constexpr double sChipLength = constants::moduleMLOT::chip::length; + static constexpr double sDeadzoneWidth = constants::moduleMLOT::chip::passiveEdgeReadOut; + static constexpr double sModuleLength = constants::moduleMLOT::length; + static constexpr double sModuleWidth = constants::moduleMLOT::width; + static constexpr int sHalfNumberOfChips = 4; + + // TGeo objects outside logical volumes can cause errors + static constexpr float sLogicalVolumeThickness = 1.3; + + ClassDef(TRKSegmentedLayer, 0); +}; + +class TRKMLLayer : public TRKSegmentedLayer +{ + public: + TRKMLLayer() = default; + TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); + TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + ~TRKMLLayer() override = default; + + TGeoVolume* createStave() override; + void createLayer(TGeoVolume* motherVolume) override; + + private: + static constexpr double sStaveWidth = constants::ML::width; + + ClassDef(TRKMLLayer, 0); +}; + +class TRKOTLayer : public TRKSegmentedLayer +{ + public: + TRKOTLayer() = default; + TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); + TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + ~TRKOTLayer() override = default; + + TGeoVolume* createStave() override; + TGeoVolume* createHalfStave(); + void createLayer(TGeoVolume* motherVolume) override; + + private: + static constexpr double sHalfStaveWidth = constants::OT::halfstave::width; + static constexpr double sInStaveOverlap = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true) overlap + static constexpr double sStaveWidth = constants::OT::width - sInStaveOverlap; + + ClassDef(TRKOTLayer, 0) }; } // namespace trk diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer_copy.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer_copy.h deleted file mode 100644 index c0e15d36929a4..0000000000000 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer_copy.h +++ /dev/null @@ -1,135 +0,0 @@ -// 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. - -#ifndef ALICEO2_TRK_LAYER_H -#define ALICEO2_TRK_LAYER_H - -#include -#include - -#include "TRKBase/TRKBaseParam.h" -#include "TRKBase/Specs.h" - -namespace o2 -{ -namespace trk -{ -class TRKCylindricalLayer -{ - public: - TRKCylindricalLayer() = default; - TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float layerX2X0); - TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thick); - virtual ~TRKCylindricalLayer() = default; - - auto getInnerRadius() const { return mInnerRadius; } - auto getOuterRadius() const { return mOuterRadius; } - auto getZ() const { return mLength; } - auto getx2X0() const { return mX2X0; } - auto getChipThickness() const { return mChipThickness; } - auto getNumber() const { return mLayerNumber; } - auto getName() const { return mLayerName; } - - virtual TGeoVolume* createSensor(); - virtual TGeoVolume* createMetalStack(); - virtual void createLayer(TGeoVolume* motherVolume); - - protected: - // User defined parameters for the layer, to be set in the constructor - int mLayerNumber; - std::string mLayerName; - float mInnerRadius; - float mOuterRadius; - float mLength; - float mX2X0; - float mChipThickness; - - // Fixed parameters for the layer, to be set based on the specifications of the chip and module - static constexpr double sSensorThickness = constants::moduleMLOT::silicon::thickness; - - static constexpr float Si_X0 = 9.5f; - - ClassDef(TRKCylindricalLayer, 0); -}; - -class TRKSegmentedLayer : public TRKCylindricalLayer -{ - public: - TRKSegmentedLayer() = default; - TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); - TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); - ~TRKSegmentedLayer() override = default; - - TGeoVolume* createSensor() override; - TGeoVolume* createDeadzone(); - TGeoVolume* createMetalStack() override; - TGeoVolume* createChip(); - TGeoVolume* createModule(); - TGeoVolume* createStave() = 0; - void createLayer(TGeoVolume* motherVolume) override = 0; - - private: - int mNumberOfModules; - - // Fixed parameters for the layer, to be set based on the specifications of the chip and module - static constexpr double sChipWidth = constants::moduleMLOT::chip::width; - static constexpr double sChipLength = constants::moduleMLOT::chip::length; - static constexpr double sDeadzoneWidth = constants::moduleMLOT::chip::passiveEdgeReadOut; - static constexpr double sModuleLength = constants::moduleMLOT::length; - static constexpr double sModuleWidth = constants::moduleMLOT::width; - static constexpr int sHalfNumberOfChips = 4; - - // TGeo objects outside logical volumes can cause errors - static constexpr float sLogicalVolumeThickness = 1.3; - - ClassDef(TRKSegmentedLayer, 0); -}; - -class TRKMLLayer : public TRKSegmentedLayer -{ - public: - TRKMLLayer() = default; - TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); - TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); - ~TRKMLLayer() override = default; - - TGeoVolume* createStave() override; - void createLayer(TGeoVolume* motherVolume) override; - - private: - static constexpr double sStaveWidth = constants::ML::width; - - ClassDef(TRKMLLayer, 0); -}; - -class TRKOTLayer : public TRKSegmentedLayer -{ - public: - TRKOTLayer() = default; - TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); - TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); - ~TRKOTLayer() override = default; - - TGeoVolume* createStave() override; - TGeoVolume* createHalfStave(); - void createLayer(TGeoVolume* motherVolume) override; - - private: - static constexpr double sHalfStaveWidth = constants::OT::halfstave::width; - static constexpr double sInStaveOverlap = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true) overlap - static constexpr double sStaveWidth = constants::OT::width - sInStaveOverlap; - - ClassDef(TRKOTLayer, 0) -}; - -} // namespace trk -} // namespace o2 -#endif // ALICEO2_TRK_LAYER_H \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx index 2ad1d52ba73c4..95dde592fc043 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -54,7 +54,7 @@ Detector::Detector(bool active) if (trkPars.configFile != "") { configFromFile(trkPars.configFile); } else { - buildTRKMiddleOuterLayers(); + configMLOT(); configToFile(); configServices(); } @@ -78,78 +78,40 @@ void Detector::ConstructGeometry() createGeometry(); } -void Detector::configDefault() -{ - - // Build TRK detector according to the scoping document - - mLayers.clear(); - - LOGP(warning, "Loading Scoping Document configuration for ALICE3 TRK"); - mLayers.emplace_back(0, GeometryTGeo::getTRKLayerPattern() + std::to_string(0), 3.78f, 10, 100.e-3); - mLayers.emplace_back(1, GeometryTGeo::getTRKLayerPattern() + std::to_string(1), 7.f, 10, 100.e-3); - mLayers.emplace_back(2, GeometryTGeo::getTRKLayerPattern() + std::to_string(2), 12.f, 10, 100.e-3); - mLayers.emplace_back(3, GeometryTGeo::getTRKLayerPattern() + std::to_string(3), 20.f, 10, 100.e-3); - mLayers.emplace_back(4, GeometryTGeo::getTRKLayerPattern() + std::to_string(4), 30.f, 10, 100.e-3); - mLayers.emplace_back(5, GeometryTGeo::getTRKLayerPattern() + std::to_string(5), 45.f, 20, 100.e-3); - mLayers.emplace_back(6, GeometryTGeo::getTRKLayerPattern() + std::to_string(6), 60.f, 20, 100.e-3); - mLayers.emplace_back(7, GeometryTGeo::getTRKLayerPattern() + std::to_string(7), 80.f, 20, 100.e-3); -} - -void Detector::buildTRKMiddleOuterLayers() +void Detector::configMLOT() { auto& trkPars = TRKBaseParam::Instance(); mLayers.clear(); - switch (trkPars.overallGeom) { - case kDefaultRadii: - // Build the TRK detector according to changes proposed during - // https://indico.cern.ch/event/1407704/ - // to adhere to the changes that were presented at the ALICE 3 Upgrade days in March 2024 - // L3 -> 7 cm, L4 -> 9 cm, L5 -> 12 cm, L6 -> 20 cm - - LOGP(warning, "Loading \"After Upgrade Days March 2024\" configuration for ALICE3 TRK"); - LOGP(warning, "Building TRK with new vacuum vessel and L3 at 7 cm, L4 at 9 cm, L5 at 12 cm, L6 at 20 cm"); - mLayers.emplace_back(0, GeometryTGeo::getTRKLayerPattern() + std::to_string(0), 7.f, 10, 100.e-3); - LOGP(info, "TRKLayer created. Name: {}", GeometryTGeo::getTRKLayerPattern() + std::to_string(0)); - mLayers.emplace_back(1, GeometryTGeo::getTRKLayerPattern() + std::to_string(1), 9.f, 10, 100.e-3); - mLayers.emplace_back(2, GeometryTGeo::getTRKLayerPattern() + std::to_string(2), 12.f, 10, 100.e-3); - mLayers.emplace_back(3, GeometryTGeo::getTRKLayerPattern() + std::to_string(3), 20.f, 10, 100.e-3); - mLayers.emplace_back(4, GeometryTGeo::getTRKLayerPattern() + std::to_string(4), 30.f, 10, 100.e-3); - mLayers.emplace_back(5, GeometryTGeo::getTRKLayerPattern() + std::to_string(5), 45.f, 20, 100.e-3); - mLayers.emplace_back(6, GeometryTGeo::getTRKLayerPattern() + std::to_string(6), 60.f, 20, 100.e-3); - mLayers.emplace_back(7, GeometryTGeo::getTRKLayerPattern() + std::to_string(7), 80.f, 20, 100.e-3); + const std::vector rInn{7.f, 9.f, 12.f, 20.f, 30.f, 45.f, 60.f, 80.f}; + const float thick = 100.e-3; + + switch (trkPars.layoutMLOT) { + case kCylindrical: + const std::vector length{128.35f, 128.35f, 128.35f, 128.35f, 128.35f, 256.7f, 256.7f, 256.7f}; + LOGP(warning, "Loading cylindrical configuration for ALICE3 TRK"); + for (int i{0}; i < 8; ++i) { + std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i); + mLayers.push_back(std::make_unique(i, name, rInn[i], length[i], thick)); + } break; - case kModRadii: - LOGP(warning, "Loading \"Alternative\" configuration for ALICE3 TRK"); - LOGP(warning, "Building TRK with new vacuum vessel and L3 at 7 cm, L4 at 11 cm, L5 at 15 cm, L6 at 19 cm"); - mLayers.emplace_back(0, GeometryTGeo::getTRKLayerPattern() + std::to_string(0), 7.f, 10, 100.e-3); - LOGP(info, "TRKLayer created. Name: {}", GeometryTGeo::getTRKLayerPattern() + std::to_string(0)); - mLayers.emplace_back(1, GeometryTGeo::getTRKLayerPattern() + std::to_string(1), 11.f, 10, 100.e-3); - mLayers.emplace_back(2, GeometryTGeo::getTRKLayerPattern() + std::to_string(2), 15.f, 10, 100.e-3); - mLayers.emplace_back(3, GeometryTGeo::getTRKLayerPattern() + std::to_string(3), 20.f, 10, 100.e-3); - mLayers.emplace_back(4, GeometryTGeo::getTRKLayerPattern() + std::to_string(4), 30.f, 10, 100.e-3); - mLayers.emplace_back(5, GeometryTGeo::getTRKLayerPattern() + std::to_string(5), 45.f, 20, 100.e-3); - mLayers.emplace_back(6, GeometryTGeo::getTRKLayerPattern() + std::to_string(6), 60.f, 20, 100.e-3); - mLayers.emplace_back(7, GeometryTGeo::getTRKLayerPattern() + std::to_string(7), 80.f, 20, 100.e-3); + case kSegmented: + const std::vector nMods{10, 10, 10, 10, 10, 20, 20, 20}; + LOGP(warning, "Loading segmented configuration for ALICE3 TRK"); + for (int i{0}; i < 8; ++i) { + std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i); + if (i < 4) { + mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick)); + } else { + mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick)); + } + } break; default: - LOGP(fatal, "Unknown option {} for buildTRKMiddleOuterLayers", static_cast(trkPars.overallGeom)); + LOGP(fatal, "Unknown option {} for configMLOT", static_cast(trkPars.layoutMLOT)); break; } - - // Middle layers - mLayers[0].setLayout(trkPars.layoutML); - mLayers[1].setLayout(trkPars.layoutML); - mLayers[2].setLayout(trkPars.layoutML); - mLayers[3].setLayout(trkPars.layoutML); - - // Outer tracker - mLayers[4].setLayout(trkPars.layoutOT); - mLayers[5].setLayout(trkPars.layoutOT); - mLayers[6].setLayout(trkPars.layoutOT); - mLayers[7].setLayout(trkPars.layoutOT); } void Detector::configFromFile(std::string fileName) @@ -160,6 +122,8 @@ void Detector::configFromFile(std::string fileName) LOGP(fatal, "File {} not found, aborting.", fileName); } + auto& trkPars = TRKBaseParam::Instance(); + mLayers.clear(); LOGP(info, "Overriding geometry of ALICE3 TRK using {} file.", fileName); @@ -178,7 +142,26 @@ void Detector::configFromFile(std::string fileName) while (getline(ss, substr, '\t')) { tmpBuff.push_back(std::stof(substr)); } - mLayers.emplace_back(layerCount, GeometryTGeo::getTRKLayerPattern() + std::to_string(layerCount), tmpBuff[0], tmpBuff[1], tmpBuff[2]); + + std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(layerCount); + switch (trkPars.layoutMLOT) { + case kCylindrical: + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], tmpBuff[1], tmpBuff[2])); + break; + case kSegmented: { + int nMods = static_cast(tmpBuff[1]); + if (layerCount < 4) { + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2])); + } else { + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2])); + } + break; + } + default: + LOGP(fatal, "Unknown option {} for configMLOT", static_cast(trkPars.layoutMLOT)); + break; + } + ++layerCount; } } diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector_copy.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector_copy.cxx deleted file mode 100644 index 95dde592fc043..0000000000000 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector_copy.cxx +++ /dev/null @@ -1,542 +0,0 @@ -// 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. - -#include - -#include -#include -#include - -#include "DetectorsBase/Stack.h" -#include "TRKSimulation/Hit.h" -#include "TRKSimulation/Detector.h" -#include "TRKBase/TRKBaseParam.h" -#include "TRKSimulation/VDGeometryBuilder.h" -#include "TRKSimulation/VDSensorRegistry.h" - -#include -#include - -using o2::trk::Hit; - -namespace o2 -{ -namespace trk -{ - -float getDetLengthFromEta(const float eta, const float radius) -{ - return 2. * (10. + radius * std::cos(2 * std::atan(std::exp(-eta)))); -} - -Detector::Detector() - : o2::base::DetImpl("TRK", true), - mTrackData(), - mHits(o2::utils::createSimVector()) -{ -} - -Detector::Detector(bool active) - : o2::base::DetImpl("TRK", true), - mTrackData(), - mHits(o2::utils::createSimVector()) -{ - auto& trkPars = TRKBaseParam::Instance(); - - if (trkPars.configFile != "") { - configFromFile(trkPars.configFile); - } else { - configMLOT(); - configToFile(); - configServices(); - } - - LOGP(info, "Summary of TRK configuration:"); - for (auto& layer : mLayers) { - LOGP(info, "Layer: {} name: {} r: {} cm | z: {} cm | thickness: {} cm", layer.getNumber(), layer.getName(), layer.getInnerRadius(), layer.getZ(), layer.getChipThickness()); - } -} - -Detector::~Detector() -{ - if (mHits) { - o2::utils::freeSimVector(mHits); - } -} - -void Detector::ConstructGeometry() -{ - createMaterials(); - createGeometry(); -} - -void Detector::configMLOT() -{ - auto& trkPars = TRKBaseParam::Instance(); - - mLayers.clear(); - - const std::vector rInn{7.f, 9.f, 12.f, 20.f, 30.f, 45.f, 60.f, 80.f}; - const float thick = 100.e-3; - - switch (trkPars.layoutMLOT) { - case kCylindrical: - const std::vector length{128.35f, 128.35f, 128.35f, 128.35f, 128.35f, 256.7f, 256.7f, 256.7f}; - LOGP(warning, "Loading cylindrical configuration for ALICE3 TRK"); - for (int i{0}; i < 8; ++i) { - std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i); - mLayers.push_back(std::make_unique(i, name, rInn[i], length[i], thick)); - } - break; - case kSegmented: - const std::vector nMods{10, 10, 10, 10, 10, 20, 20, 20}; - LOGP(warning, "Loading segmented configuration for ALICE3 TRK"); - for (int i{0}; i < 8; ++i) { - std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i); - if (i < 4) { - mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick)); - } else { - mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick)); - } - } - break; - default: - LOGP(fatal, "Unknown option {} for configMLOT", static_cast(trkPars.layoutMLOT)); - break; - } -} - -void Detector::configFromFile(std::string fileName) -{ - // Override the default geometry if config file provided - std::ifstream confFile(fileName); - if (!confFile.good()) { - LOGP(fatal, "File {} not found, aborting.", fileName); - } - - auto& trkPars = TRKBaseParam::Instance(); - - mLayers.clear(); - - LOGP(info, "Overriding geometry of ALICE3 TRK using {} file.", fileName); - - std::string line; - std::vector tmpBuff; - int layerCount{0}; - while (std::getline(confFile, line)) { - if (line[0] == '/') { - continue; - } - tmpBuff.clear(); - std::stringstream ss(line); - float val; - std::string substr; - while (getline(ss, substr, '\t')) { - tmpBuff.push_back(std::stof(substr)); - } - - std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(layerCount); - switch (trkPars.layoutMLOT) { - case kCylindrical: - mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], tmpBuff[1], tmpBuff[2])); - break; - case kSegmented: { - int nMods = static_cast(tmpBuff[1]); - if (layerCount < 4) { - mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2])); - } else { - mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2])); - } - break; - } - default: - LOGP(fatal, "Unknown option {} for configMLOT", static_cast(trkPars.layoutMLOT)); - break; - } - - ++layerCount; - } -} - -void Detector::configToFile(std::string fileName) -{ - LOGP(info, "Exporting TRK Detector layout to {}", fileName); - std::ofstream conFile(fileName.c_str(), std::ios::out); - conFile << "/// TRK configuration file: inn_radius z_length lay_thickness" << std::endl; - for (auto layer : mLayers) { - conFile << layer.getInnerRadius() << "\t" << layer.getZ() << "\t" << layer.getChipThickness() << std::endl; - } -} - -void Detector::configServices() -{ - mServices = TRKServices(); -} - -void Detector::createMaterials() -{ - int ifield = 2; // ? - float fieldm = 10.0; // ? - o2::base::Detector::initFieldTrackingParams(ifield, fieldm); - - float tmaxfdSi = 0.1; // .10000E+01; // Degree - float stemaxSi = 0.0075; // .10000E+01; // cm - float deemaxSi = 0.1; // 0.30000E-02; // Fraction of particle's energy 0GetVolume("barrel"); - if (!vALIC) { - LOGP(fatal, "Could not find barrel volume while constructing TRK geometry"); - } - new TGeoVolumeAssembly(GeometryTGeo::getTRKVolPattern()); - TGeoVolume* vTRK = geoManager->GetVolume(GeometryTGeo::getTRKVolPattern()); - vALIC->AddNode(vTRK, 2, new TGeoTranslation(0, 30., 0)); - - char vstrng[100] = "TRKVol"; - vTRK->SetTitle(vstrng); - - for (auto& layer : mLayers) { - layer.createLayer(vTRK); - } - - // Add service for inner tracker - mServices.createServices(vTRK); - - // Build the VD using the petal builder - // Choose the VD design based on TRKBaseParam.layoutVD - auto& trkPars = TRKBaseParam::Instance(); - - o2::trk::clearVDSensorRegistry(); - - switch (trkPars.layoutVD) { - case kIRIS4: - LOG(info) << "Building VD with IRIS4 layout"; - o2::trk::createIRIS4Geometry(vTRK); - break; - case kIRISFullCyl: - LOG(info) << "Building VD with IRIS fully cylindrical layout"; - o2::trk::createIRISGeometryFullCyl(vTRK); - break; - case kIRISFullCyl3InclinedWalls: - LOG(info) << "Building VD with IRIS fully cylindrical layout with 3 inclined walls"; - o2::trk::createIRISGeometry3InclinedWalls(vTRK); - break; - case kIRIS5: - LOG(info) << "Building VD with IRIS5 layout"; - o2::trk::createIRIS5Geometry(vTRK); - break; - case kIRIS4a: - LOG(info) << "Building VD with IRIS4a layout"; - o2::trk::createIRIS4aGeometry(vTRK); - break; - default: - LOG(fatal) << "Unknown VD layout option: " << static_cast(trkPars.layoutVD); - break; - } - - // Fill sensor names from registry right after geometry creation - const auto& regs = o2::trk::vdSensorRegistry(); - mNumberOfVolumesVD = static_cast(regs.size()); - mNumberOfVolumes = mNumberOfVolumesVD + mLayers.size(); - mSensorName.resize(mNumberOfVolumes); - - // Fill VD sensor names from registry - int VDvolume = 0; - for (const auto& sensor : regs) { - mSensorName[VDvolume] = sensor.name; - VDvolume++; - } - - // Add MLOT sensor names - for (int i = 0; i < mLayers.size(); i++) { - mSensorName[VDvolume++].Form("%s%d", GeometryTGeo::getTRKSensorPattern(), i); - } - - for (auto vd : mSensorName) { - std::cout << "Volume name: " << vd << std::endl; - } - - mServices.excavateFromVacuum("IRIS_CUTOUTsh"); - mServices.registerVacuum(vTRK); -} - -void Detector::InitializeO2Detector() -{ - LOG(info) << "Initialize TRK O2Detector"; - mGeometryTGeo = GeometryTGeo::Instance(); - defineSensitiveVolumes(); - - mSensorID.resize(mNumberOfVolumes); // hardcoded. TODO: change size when a different namingh scheme for VD is in place. Ideally could be 4 petals + 8 layers = 12 - for (int i = 0; i < mNumberOfVolumes; i++) { - mSensorID[i] = gMC ? TVirtualMC::GetMC()->VolId(mSensorName[i]) : 0; // Volume ID from the Geant geometry - LOGP(info, "{}: mSensorID={}, mSensorName={}", i, mSensorID[i], mSensorName[i].Data()); - } -} - -void Detector::defineSensitiveVolumes() -{ - TGeoManager* geoManager = gGeoManager; - TGeoVolume* v; - - TString volumeName; - LOGP(info, "Adding TRK Sensitive Volumes"); - - // Register VD sensors created by VDGeometryBuilder - for (const auto& s : o2::trk::vdSensorRegistry()) { - TGeoVolume* v = gGeoManager->GetVolume(s.name.c_str()); - if (!v) { - LOGP(warning, "VD sensor volume '{}' not found", s.name); - continue; - } - LOGP(info, "Adding VD Sensitive Volume {}", v->GetName()); - AddSensitiveVolume(v); - // Optionally track first/last layers for TR references: - if (s.region == o2::trk::VDSensorDesc::Region::Barrel && (s.idx == 0 /*innermost*/)) { - mFirstOrLastLayers.push_back(s.name); - } - } - - // The names of the TRK sensitive volumes have the format: TRKLayer(0...mLayers.size()-1) - for (int j{0}; j < mLayers.size(); j++) { - volumeName = GeometryTGeo::getTRKSensorPattern() + TString::Itoa(j, 10); - if (j == mLayers.size() - 1) { - mFirstOrLastLayers.push_back(volumeName.Data()); - } - LOGP(info, "Trying {}", volumeName.Data()); - v = geoManager->GetVolume(volumeName.Data()); - LOGP(info, "Adding TRK Sensitive Volume {}", v->GetName()); - AddSensitiveVolume(v); - } -} - -void Detector::EndOfEvent() { Reset(); } - -void Detector::Register() -{ - // This will create a branch in the output tree called Hit, setting the last - // parameter to kFALSE means that this collection will not be written to the file, - // it will exist only during the simulation - - if (FairRootManager::Instance()) { - FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, true); - } -} - -void Detector::Reset() -{ - if (!o2::utils::ShmManager::Instance().isOperational()) { - mHits->clear(); - } -} - -bool Detector::InsideFirstOrLastLayer(std::string layerName) -{ - bool inside = false; - for (auto& firstOrLastLayer : mFirstOrLastLayers) { - if (firstOrLastLayer == layerName) { - inside = true; - break; - } - } - return inside; -} - -bool Detector::ProcessHits(FairVolume* vol) -{ - // This method is called from the MC stepping - if (!(fMC->TrackCharge())) { - return false; - } - - int subDetID = -1; - int layer = -1; - int volume = 0; - int volID = vol->getMCid(); - - bool notSens = false; - while ((volume < mNumberOfVolumes) && (notSens = (volID != mSensorID[volume]))) { - ++volume; /// there are 44 volumes, 36 for the VD (1 for each sensing element) and 8 for the MLOT (1 for each layer) - } - - if (notSens) { - return kFALSE; // RS: can this happen? This method must be called for sensors only? - } - - if (volume < mNumberOfVolumesVD) { - subDetID = 0; // VD. For the moment each "chip" is a volume./// TODO: change this logic once the naming scheme is changed - } else { - subDetID = 1; // MLOT - layer = volume - mNumberOfVolumesVD; - } - - // Is it needed to keep a track reference when the outer ITS volume is encountered? - auto stack = (o2::data::Stack*)fMC->GetStack(); - // if (fMC->IsTrackExiting() && (lay == 0 || lay == mLayers.size() - 1)) { - if (fMC->IsTrackExiting() && InsideFirstOrLastLayer(vol->GetName())) { - // Keep the track refs for the innermost and outermost layers only - o2::TrackReference tr(*fMC, GetDetId()); - tr.setTrackID(stack->GetCurrentTrackNumber()); - tr.setUserId(volume); - stack->addTrackReference(tr); - } - bool startHit = false, stopHit = false; - unsigned char status = 0; - if (fMC->IsTrackEntering()) { - status |= Hit::kTrackEntering; - } - if (fMC->IsTrackInside()) { - status |= Hit::kTrackInside; - } - if (fMC->IsTrackExiting()) { - status |= Hit::kTrackExiting; - } - if (fMC->IsTrackOut()) { - status |= Hit::kTrackOut; - } - if (fMC->IsTrackStop()) { - status |= Hit::kTrackStopped; - } - if (fMC->IsTrackAlive()) { - status |= Hit::kTrackAlive; - } - - // track is entering or created in the volume - if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { - startHit = true; - } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { - stopHit = true; - } - - // increment energy loss at all steps except entrance - if (!startHit) { - mTrackData.mEnergyLoss += fMC->Edep(); - } - if (!(startHit | stopHit)) { - return false; // do noting - } - - if (startHit) { - mTrackData.mEnergyLoss = 0.; - fMC->TrackMomentum(mTrackData.mMomentumStart); - fMC->TrackPosition(mTrackData.mPositionStart); - mTrackData.mTrkStatusStart = status; - mTrackData.mHitStarted = true; - } - if (stopHit) { - TLorentzVector positionStop; - fMC->TrackPosition(positionStop); - // Retrieve the indices with the volume path - int stave(0), halfstave(0), mod(0), chip(0); - if (subDetID == 1) { - fMC->CurrentVolOffID(1, chip); - fMC->CurrentVolOffID(2, mod); - if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 2) { - fMC->CurrentVolOffID(3, halfstave); - fMC->CurrentVolOffID(4, stave); - } else if (mGeometryTGeo->getNumberOfHalfStaves(layer) == 1) { - fMC->CurrentVolOffID(3, stave); - } else { - LOGP(fatal, "Wrong number of halfstaves for layer {}", layer); - } - } /// if VD, for the moment the volume is the "chipID" so no need to retrieve other elments - - unsigned short chipID = mGeometryTGeo->getChipIndex(subDetID, volume, layer, stave, halfstave, mod, chip); - - // Print(vol, volume, subDetID, layer, stave, halfstave, mod, chip, chipID); - - // mGeometryTGeo->Print(); - - Hit* p = addHit(stack->GetCurrentTrackNumber(), chipID, mTrackData.mPositionStart.Vect(), positionStop.Vect(), - mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), - mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); - // p->SetTotalEnergy(vmc->Etot()); - - // RS: not sure this is needed - // Increment number of Detector det points in TParticle - stack->addHit(GetDetId()); - } - - return true; -} - -o2::trk::Hit* Detector::addHit(int trackID, unsigned short detID, const TVector3& startPos, const TVector3& endPos, - const TVector3& startMom, double startE, double endTime, double eLoss, unsigned char startStatus, - unsigned char endStatus) -{ - mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus); - return &(mHits->back()); -} - -void Detector::Print(FairVolume* vol, int volume, int subDetID, int layer, int stave, int halfstave, int mod, int chip, int chipID) const -{ - int currentVol(0); - LOG(info) << "Current volume name: " << fMC->CurrentVolName() << " and ID " << fMC->CurrentVolID(currentVol); - LOG(info) << "volume: " << volume << "/" << mNumberOfVolumes - 1; - LOG(info) << "off volume name 1 " << fMC->CurrentVolOffName(1) << " chip: " << chip; - LOG(info) << "off volume name 2 " << fMC->CurrentVolOffName(2) << " module: " << mod; - if (subDetID == 1 && mGeometryTGeo->getNumberOfHalfStaves(layer) == 2) { // staggered geometry - LOG(info) << "off volume name 3 " << fMC->CurrentVolOffName(3) << " halfstave: " << halfstave; - LOG(info) << "off volume name 4 " << fMC->CurrentVolOffName(4) << " stave: " << stave; - LOG(info) << "SubDetector ID: " << subDetID << " Layer: " << layer << " staveinLayer: " << stave << " Chip ID: " << chipID; - } else if (subDetID == 1 && mGeometryTGeo->getNumberOfHalfStaves(layer) == 1) { // turbo geometry - LOG(info) << "off volume name 3 " << fMC->CurrentVolOffName(3) << " stave: " << stave; - LOG(info) << "SubDetector ID: " << subDetID << " Layer: " << layer << " staveinLayer: " << stave << " Chip ID: " << chipID; - } else { - LOG(info) << "SubDetector ID: " << subDetID << " Chip ID: " << chipID; - } - LOG(info); -} - -} // namespace trk -} // namespace o2 - -ClassImp(o2::trk::Detector); - -// Define Factory method for calling from the outside -extern "C" { -o2::base::Detector* create_detector_trk(bool active) -{ - return o2::trk::Detector::create(active); -} -} diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx index b5bde06d09484..c54cd91f2ba10 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -20,405 +20,334 @@ #include #include +#include "TRKLayer_copy.h" namespace o2 { namespace trk { -TRKLayer::TRKLayer(int layerNumber, std::string layerName, float rInn, float rOut, int numberOfModules, float layerX2X0) - : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mOuterRadius(rOut), mNumberOfModules(numberOfModules), mX2X0(layerX2X0) +TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float layerX2X0) + : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length), mX2X0(layerX2X0) { - mChipThickness = mX2X0 * Si_X0; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, getZ(), mX2X0); + sChipThickness = mX2X0 * Si_X0; + mOuterRadius = rInn + sChipThickness; + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); } -TRKLayer::TRKLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) - : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mNumberOfModules(numberOfModules), mChipThickness(thick) +TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thick) + : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length), sChipThickness(thick) { mOuterRadius = rInn + thick; - mX2X0 = mChipThickness / Si_X0; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, getZ(), mX2X0); + mX2X0 = thick / Si_X0; + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); } -TGeoVolume* TRKLayer::createSensor(std::string type) +TGeoVolume* TRKCylindricalLayer::createSensor() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string sensName = GeometryTGeo::getTRKSensorPattern() + std::to_string(mLayerNumber); - - TGeoShape* sensor; - - if (type == "cylinder") { - sensor = new TGeoTube(mInnerRadius, mInnerRadius + mSensorThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); // TO BE CHECKED !!! - } else if (type == "flat") { - sensor = new TGeoBBox((mChipWidth - mDeadzoneWidth) / 2, mSensorThickness / 2, mChipLength / 2); // TO BE CHECKED !!! - } else { - LOGP(fatal, "Sensor of type '{}' is not implemented", type); - } - + TGeoShape* sensor = new TGeoTube(mInnerRadius, mInnerRadius + sSensorThickness, mLength / 2); TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); sensVol->SetLineColor(kYellow); return sensVol; }; -TGeoVolume* TRKLayer::createDeadzone(std::string type) +TGeoVolume* TRKCylindricalLayer::createMetalStack() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string deadName = GeometryTGeo::getTRKDeadzonePattern() + std::to_string(mLayerNumber); + std::string metalName = GeometryTGeo::getTRKMetalStackPattern() + std::to_string(mLayerNumber); + TGeoShape* metalStack metalStack = new TGeoTube(mInnerRadius + sSensorThickness, mInnerRadius + sChipThickness, mLength / 2); + TGeoVolume* metalVol = new TGeoVolume(metalName.c_str(), metalStack, medSi); + metalVol->SetLineColor(kGray); - TGeoShape* deadzone; + return metalVol; +}; - if (type == "cylinder") { - deadzone = new TGeoTube(mInnerRadius, mInnerRadius + mSensorThickness, 0); // TO BE CHECKED !!! - } else if (type == "flat") { - deadzone = new TGeoBBox(mDeadzoneWidth / 2, mSensorThickness / 2, mChipLength / 2); // TO BE CHECKED !!! - } else { - LOGP(fatal, "Deadzone of type '{}' is not implemented", type); - } +void TRKCylindricalLayer::createLayer(TGeoVolume* motherVolume) +{ + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + TGeoTube* layer = new TGeoTube(mInnerRadius, mInnerRadius + sChipThickness, mLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kYellow); + + TGeoVolume* sensVol = createSensor(); + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + layerVol->AddNode(sensVol, 1, nullptr); + + TGeoVolume* metalVol = createMetalStack(); + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); + layerVol->AddNode(metalVol, 1, nullptr); + + LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); + motherVolume->AddNode(layerVol, 1, nullptr); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) + : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, layerX2X0), mNumberOfModules(numberOfModules) +{ + sChipThickness = mX2X0 * Si_X0; + mOuterRadius = rInn + sChipThickness; + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) + : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, thick), mNumberOfModules(numberOfModules) +{ + mOuterRadius = rInn + thick; + mX2X0 = thick / Si_X0; + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} + +TGeoVolume* TRKSegmentedLayer::createSensor() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string sensName = GeometryTGeo::getTRKSensorPattern() + std::to_string(mLayerNumber); + TGeoShape* sensor = new TGeoBBox((sChipWidth - sDeadzoneWidth) / 2, sSensorThickness / 2, sChipLength / 2); + TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); + sensVol->SetLineColor(kYellow); + + return sensVol; +} +TGeoVolume* TRKSegmentedLayer::createDeadzone() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string deadName = GeometryTGeo::getTRKDeadzonePattern() + std::to_string(mLayerNumber); + TGeoShape* deadzone = new TGeoBBox(sDeadzoneWidth / 2, sSensorThickness / 2, sChipLength / 2); TGeoVolume* deadVol = new TGeoVolume(deadName.c_str(), deadzone, medSi); deadVol->SetLineColor(kGray); return deadVol; -}; +} -TGeoVolume* TRKLayer::createMetalStack(std::string type) +TGeoVolume* TRKSegmentedLayer::createMetalStack() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string metalName = GeometryTGeo::getTRKMetalStackPattern() + std::to_string(mLayerNumber); - - TGeoShape* metalStack; - - if (type == "cylinder") { - metalStack = new TGeoTube(mInnerRadius + mSensorThickness, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); // TO BE CHECKED !!! - } else if (type == "flat") { - metalStack = new TGeoBBox(mChipWidth / 2, (mChipThickness - mSensorThickness) / 2, mChipLength / 2); // TO BE CHECKED !!! - } else { - LOGP(fatal, "Metal stack of type '{}' is not implemented", type); - } - + TGeoShape* metalStack = new TGeoBBox(sChipWidth / 2, (sChipThickness - sSensorThickness) / 2, sChipLength / 2); TGeoVolume* metalVol = new TGeoVolume(metalName.c_str(), metalStack, medSi); metalVol->SetLineColor(kGray); return metalVol; -}; +} -TGeoVolume* TRKLayer::createChip(std::string type) +TGeoVolume* TRKSegmentedLayer::createChip() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string chipName = GeometryTGeo::getTRKChipPattern() + std::to_string(mLayerNumber); + TGeoShape* chip = new TGeoBBox(sChipWidth / 2, sChipThickness / 2, sChipLength / 2); + TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); + chipVol->SetLineColor(kYellow); - TGeoShape* chip; - TGeoVolume* chipVol; - - TGeoVolume* sensVol; - TGeoVolume* deadVol; - TGeoVolume* metalVol; - - if (type == "cylinder") { - chip = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); - chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); - - sensVol = createSensor("cylinder"); - LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); - chipVol->AddNode(sensVol, 1, nullptr); - - metalVol = createMetalStack("cylinder"); - LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); - chipVol->AddNode(metalVol, 1, nullptr); - - // deadVol = createDeadzone("cylinder"); - } else if (type == "flat") { - chip = new TGeoBBox(mChipWidth / 2, mChipThickness / 2, mChipLength / 2); // TO BE CHECKED !!! - chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); - - sensVol = createSensor("flat"); - deadVol = createDeadzone("flat"); - metalVol = createMetalStack("flat"); - - TGeoCombiTrans* transSens = new TGeoCombiTrans(); - transSens->SetTranslation(-mDeadzoneWidth / 2, (mChipThickness - mSensorThickness) / 2, 0); // TO BE CHECKED !!! - LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); - chipVol->AddNode(sensVol, 1, transSens); - - TGeoCombiTrans* transDead = new TGeoCombiTrans(); - transDead->SetTranslation((mChipWidth - mDeadzoneWidth) / 2, (mChipThickness - mSensorThickness) / 2, 0); // TO BE CHECKED !!! - LOGP(debug, "Inserting {} in {} ", deadVol->GetName(), chipVol->GetName()); - chipVol->AddNode(deadVol, 1, transDead); - - TGeoCombiTrans* transMetal = new TGeoCombiTrans(); - transMetal->SetTranslation(0, -(mSensorThickness) / 2, 0); // TO BE CHECKED !!! - LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); - chipVol->AddNode(metalVol, 1, transMetal); - } else { - LOGP(fatal, "Sensor of type '{}' is not implemented", type); - } + TGeoVolume* sensVol = createSensor(); + TGeoCombiTrans* transSens = new TGeoCombiTrans(); + transSens->SetTranslation(-sDeadzoneWidth / 2, -(sChipThickness - sSensorThickness) / 2, 0); + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + chipVol->AddNode(sensVol, 1, transSens); - chipVol->SetLineColor(kYellow); + TGeoVolume* deadVol = createDeadzone(); + TGeoCombiTrans* transDead = new TGeoCombiTrans(); + transDead->SetTranslation((sChipWidth - sDeadzoneWidth) / 2, -(sChipThickness - sSensorThickness) / 2, 0); + LOGP(debug, "Inserting {} in {} ", deadVol->GetName(), chipVol->GetName()); + chipVol->AddNode(deadVol, 1, transDead); + + TGeoVolume* metalVol = createMetalStack(); + TGeoCombiTrans* transMetal = new TGeoCombiTrans(); + transMetal->SetTranslation(0, sSensorThickness / 2, 0); + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); + chipVol->AddNode(metalVol, 1, transMetal); return chipVol; } -TGeoVolume* TRKLayer::createModule(std::string type) +TGeoVolume* TRKSegmentedLayer::createModule() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string moduleName = GeometryTGeo::getTRKModulePattern() + std::to_string(mLayerNumber); + TGeoShape* module = new TGeoBBox(sModuleWidth / 2, sChipThickness / 2, sModuleLength / 2); + TGeoVolume* moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); + moduleVol->SetLineColor(kYellow); - TGeoShape* module; - TGeoVolume* moduleVol; - - if (type == "cylinder") { - double moduleLength = constants::moduleMLOT::length * mNumberOfModules; - - module = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, moduleLength / 2); - moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); - - TGeoVolume* chipVol = createChip("cylinder"); - LOGP(debug, "Inserting {} in {} ", chipVol->GetName(), moduleVol->GetName()); - moduleVol->AddNode(chipVol, 1, nullptr); - } else if (type == "flat") { - double moduleWidth = constants::moduleMLOT::width; - double moduleLength = constants::moduleMLOT::length; - - module = new TGeoBBox(moduleWidth / 2, mChipThickness / 2, moduleLength / 2); // TO BE CHECKED !!! - moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); - - for (int iChip = 0; iChip < mHalfNumberOfChips; iChip++) { - TGeoVolume* chipVolLeft = createChip("flat"); - TGeoVolume* chipVolRight = createChip("flat"); - - // Put the chips in the correct position - double xLeft = -moduleWidth / 2 + constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::width / 2; - double zLeft = -moduleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; - - TGeoCombiTrans* transLeft = new TGeoCombiTrans(); - transLeft->SetTranslation(xLeft, 0, zLeft); // TO BE CHECKED !!! - TGeoRotation* rot = new TGeoRotation(); - rot->RotateY(180); - transLeft->SetRotation(rot); - LOGP(debug, "Inserting {} in {} ", chipVolLeft->GetName(), moduleVol->GetName()); - moduleVol->AddNode(chipVolLeft, iChip * 2, transLeft); - - double xRight = +moduleWidth / 2 - constants::moduleMLOT::gaps::outerEdgeLongSide - constants::moduleMLOT::chip::width / 2; - double zRight = -moduleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; - - TGeoCombiTrans* transRight = new TGeoCombiTrans(); - transRight->SetTranslation(xRight, 0, zRight); // TO BE CHECKED !!! - LOGP(debug, "Inserting {} in {} ", chipVolRight->GetName(), moduleVol->GetName()); - moduleVol->AddNode(chipVolRight, iChip * 2 + 1, transRight); - } - } else { - LOGP(fatal, "Chip of type '{}' is not implemented", type); + for (int iChip = 0; iChip < mHalfNumberOfChips; iChip++) { + TGeoVolume* chipVolLeft = createChip(); + double xLeft = -sModuleWidth / 2 + constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::width / 2; + double zLeft = -sModuleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; + TGeoCombiTrans* transLeft = new TGeoCombiTrans(); + transLeft->SetTranslation(xLeft, 0, zLeft); + TGeoRotation* rot = new TGeoRotation(); + rot->RotateY(180); + transLeft->SetRotation(rot); + LOGP(debug, "Inserting {} in {} ", chipVolLeft->GetName(), moduleVol->GetName()); + moduleVol->AddNode(chipVolLeft, iChip * 2, transLeft); + + TGeoVolume* chipVolRight = createChip(); + double xRight = +sModuleWidth / 2 - constants::moduleMLOT::gaps::outerEdgeLongSide - constants::moduleMLOT::chip::width / 2; + double zRight = -sModuleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; + TGeoCombiTrans* transRight = new TGeoCombiTrans(); + transRight->SetTranslation(xRight, 0, zRight); + LOGP(debug, "Inserting {} in {} ", chipVolRight->GetName(), moduleVol->GetName()); + moduleVol->AddNode(chipVolRight, iChip * 2 + 1, transRight); } - moduleVol->SetLineColor(kYellow); - return moduleVol; } -TGeoVolume* TRKLayer::createHalfStave(std::string type) -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string halfStaveName = GeometryTGeo::getTRKHalfStavePattern() + std::to_string(mLayerNumber); - - TGeoShape* halfStave; - TGeoVolume* halfStaveVol; - - double halfStaveLength = constants::moduleMLOT::length * mNumberOfModules; - - if (type == "cylinder") { - halfStave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, halfStaveLength / 2); - halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); - - TGeoVolume* moduleVol = createModule("cylinder"); - LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), halfStaveVol->GetName()); - halfStaveVol->AddNode(moduleVol, 1, nullptr); - } else if (type == "flat") { - double moduleLength = constants::moduleMLOT::length; - double halfStaveWidth = constants::OT::halfstave::width; - - halfStave = new TGeoBBox(halfStaveWidth / 2, mChipThickness / 2, halfStaveLength / 2); - halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - for (int iModule = 0; iModule < mNumberOfModules; iModule++) { - TGeoVolume* moduleVol = createModule("flat"); - - // Put the modules in the correct position - double zPos = -0.5 * mNumberOfModules * moduleLength + (iModule + 0.5) * moduleLength; - - TGeoCombiTrans* trans = new TGeoCombiTrans(); - trans->SetTranslation(0, 0, zPos); // TO BE CHECKED !!! - - LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), halfStaveVol->GetName()); - halfStaveVol->AddNode(moduleVol, iModule, trans); - } - } - - halfStaveVol->SetLineColor(kYellow); +TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, layerX2X0) +{ + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} - return halfStaveVol; +TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thick) +{ + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); } -TGeoVolume* TRKLayer::createStave(std::string type) +TGeoVolume* TRKMLLayer::createStave() { TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); std::string staveName = GeometryTGeo::getTRKStavePattern() + std::to_string(mLayerNumber); + TGeoShape* stave = new TGeoBBox(sStaveWidth / 2, sChipThickness / 2, mLength / 2); + TGeoVolume* staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); + staveVol->SetLineColor(kYellow); - TGeoShape* stave; - TGeoVolume* staveVol; - - double staveLength = constants::moduleMLOT::length * mNumberOfModules; - - if (type == "cylinder") { - stave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, staveLength / 2); - staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); - - TGeoVolume* moduleVol = createModule("cylinder"); + for (int iModule = 0; iModule < mNumberOfModules; iModule++) { + TGeoVolume* moduleVol = createModule(); + double zPos = -0.5 * mNumberOfModules * sModuleLength + (iModule + 0.5) * sModuleLength; + TGeoCombiTrans* trans = new TGeoCombiTrans(); + trans->SetTranslation(0, 0, zPos); LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), staveVol->GetName()); - staveVol->AddNode(moduleVol, 1, nullptr); - } else if (type == "flat") { - double moduleLength = constants::moduleMLOT::length; - double staveWidth = constants::ML::width; + staveVol->AddNode(moduleVol, iModule, trans); + } - stave = new TGeoBBox(staveWidth / 2, mChipThickness / 2, staveLength / 2); - staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); + return staveVol; +} - for (int iModule = 0; iModule < mNumberOfModules; iModule++) { - TGeoVolume* moduleVol = createModule("flat"); +void TRKMLLayer::createLayer(TGeoVolume* motherVolume) +{ + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + TGeoTube* layer = new TGeoTube(mInnerRadius - 0.333 * sLogicalVolumeThickness, mInnerRadius + 0.667 * sLogicalVolumeThickness, mLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kYellow); - // Put the modules in the correct position - double zPos = -0.5 * mNumberOfModules * moduleLength + (iModule + 0.5) * moduleLength; + // Compute the number of staves + int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / sStaveWidth); + nStaves += nStaves % 2; // Require an even number of staves + + // Compute the size of the overlap region + double theta = 2 * TMath::Pi() / nStaves; + double theta1 = std::atan(sStaveWidth / 2 / mInnerRadius); + double st = std::sin(theta); + double ct = std::cos(theta); + double theta2 = std::atan((mInnerRadius * st - sStaveWidth / 2 * ct) / (mInnerRadius * ct + sStaveWidth / 2 * st)); + double overlap = (theta1 - theta2) * mInnerRadius; + LOGP(info, "Creating a layer with {} staves and {} mm overlap", nStaves, overlap * 10); + + for (int iStave = 0; iStave < nStaves; iStave++) { + TGeoVolume* staveVol = createStave(); + TGeoCombiTrans* trans = new TGeoCombiTrans(); + double theta = 360. * iStave / nStaves; + TGeoRotation* rot = new TGeoRotation("rot", theta - 90 + 4, 0, 0); + trans->SetRotation(rot); + trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); + LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); + layerVol->AddNode(staveVol, iStave, trans); + } - TGeoCombiTrans* trans = new TGeoCombiTrans(); - trans->SetTranslation(0, 0, zPos); // TO BE CHECKED !!! + LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); + motherVolume->AddNode(layerVol, 1, nullptr); +} - LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), staveVol->GetName()); - staveVol->AddNode(moduleVol, iModule, trans); - } - } else if (type == "staggered") { - double overlap = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true)overlap - double shift = overlap / 2; - double halfstaveWidth = constants::OT::halfstave::width; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - staveVol = new TGeoVolumeAssembly(staveName.c_str()); +TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, layerX2X0) +{ + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} - // Put the half staves in the correct position - TGeoVolume* halfStaveVolLeft = createHalfStave("flat"); - TGeoVolume* halfStaveVolRight = createHalfStave("flat"); +TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thick) +{ + LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); +} - TGeoCombiTrans* transLeft = new TGeoCombiTrans(); - transLeft->SetTranslation(-halfstaveWidth / 2 + shift, 0, 0); // TO BE CHECKED !!! 1mm overlap between the modules - LOGP(debug, "Inserting {} in {} ", halfStaveVolLeft->GetName(), staveVol->GetName()); - staveVol->AddNode(halfStaveVolLeft, 0, transLeft); +TGeoVolume* TRKOTLayer::createHalfStave() +{ + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + std::string halfStaveName = GeometryTGeo::getTRKHalfStavePattern() + std::to_string(mLayerNumber); + TGeoShape* halfStave = new TGeoBBox(sHalfStaveWidth / 2, sChipThickness / 2, mLength / 2); + TGeoVolume* halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); + halfStaveVol->SetLineColor(kYellow); - TGeoCombiTrans* transRight = new TGeoCombiTrans(); - transRight->SetTranslation(halfstaveWidth / 2 - shift, 0.2, 0); // TO BE CHECKED !!! 1mm overlap between the modules - LOGP(debug, "Inserting {} in {} ", halfStaveVolRight->GetName(), staveVol->GetName()); - staveVol->AddNode(halfStaveVolRight, 1, transRight); - } else { - LOGP(fatal, "Chip of type '{}' is not implemented", type); + for (int iModule = 0; iModule < mNumberOfModules; iModule++) { + TGeoVolume* moduleVol = createModule("flat"); + double zPos = -0.5 * mNumberOfModules * sModuleLength + (iModule + 0.5) * sModuleLength; + TGeoCombiTrans* trans = new TGeoCombiTrans(); + trans->SetTranslation(0, 0, zPos); + LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), halfStaveVol->GetName()); + halfStaveVol->AddNode(moduleVol, iModule, trans); } - staveVol->SetLineColor(kYellow); - - return staveVol; + return halfStaveVol; } -void TRKLayer::createLayer(TGeoVolume* motherVolume) +TGeoVolume* TRKOTLayer::createStave() { - TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + std::string staveName = GeometryTGeo::getTRKStavePattern() + std::to_string(mLayerNumber); + TGeoVolume* staveVol = new TGeoVolumeAssembly(staveName.c_str()); - double layerThickness = mChipThickness; - if (mLayout != eLayout::kCylinder) { - layerThickness = mLogicalVolumeThickness; - } + TGeoVolume* halfStaveVolLeft = createHalfStave(); + TGeoCombiTrans* transLeft = new TGeoCombiTrans(); + transLeft->SetTranslation(-(sHalfStaveWidth - sInStaveOverlap) / 2, 0, 0); + LOGP(debug, "Inserting {} in {} ", halfStaveVolLeft->GetName(), staveVol->GetName()); + staveVol->AddNode(halfStaveVolLeft, 0, transLeft); - TGeoTube* layer; - TGeoVolume* layerVol; + TGeoVolume* halfStaveVolRight = createHalfStave(); + TGeoCombiTrans* transRight = new TGeoCombiTrans(); + transRight->SetTranslation(sHalfStaveWidth / 2 - shift, 0.2, 0); + LOGP(debug, "Inserting {} in {} ", halfStaveVolRight->GetName(), staveVol->GetName()); + staveVol->AddNode(halfStaveVolRight, 1, transRight); - double layerLength = constants::moduleMLOT::length * mNumberOfModules; + return staveVol; +} - if (mLayout == eLayout::kCylinder) { - layer = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, layerLength / 2); - layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); +void TRKOTLayer::createLayer(TGeoVolume* motherVolume) +{ + TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + TGeoTube* layer = new TGeoTube(mInnerRadius - 0.333 * sLogicalVolumeThickness, mInnerRadius + 0.667 * sLogicalVolumeThickness, mLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kYellow); - TGeoVolume* staveVol = createStave("cylinder"); + // Compute the number of staves + int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / sStaveWidth); + nStaves += nStaves % 2; // Require an even number of staves + + // Compute the size of the overlap region + double theta = 2 * TMath::Pi() / nStaves; + double theta1 = std::atan(sStaveWidth / 2 / mInnerRadius); + double st = std::sin(theta); + double ct = std::cos(theta); + double theta2 = std::atan((mInnerRadius * st - sStaveWidth / 2 * ct) / (mInnerRadius * ct + sStaveWidth / 2 * st)); + double overlap = (theta1 - theta2) * mInnerRadius; + LOGP(info, "Creating a layer with {} staves and {} mm overlap", nStaves, overlap * 10); + + for (int iStave = 0; iStave < nStaves; iStave++) { + TGeoVolume* staveVol = createStave(); + TGeoCombiTrans* trans = new TGeoCombiTrans(); + double theta = 360. * iStave / nStaves; + TGeoRotation* rot = new TGeoRotation("rot", theta - 90, 0, 0); + trans->SetRotation(rot); + trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); - layerVol->AddNode(staveVol, 1, nullptr); - } else if (mLayout == eLayout::kTurboStaves) { - double staveWidth = constants::ML::width; // Each stave has two modules (based on the LOI design) - - if (mInnerRadius > 25) { - staveWidth = constants::OT::width; // Outer layers have two modules per stave - } - - layer = new TGeoTube(mInnerRadius - 0.333 * layerThickness, mInnerRadius + 0.667 * layerThickness, layerLength / 2); - layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - - // Compute the number of staves - int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / staveWidth); - nStaves += nStaves % 2; // Require an even number of staves - - // Compute the size of the overlap region - double theta = 2 * TMath::Pi() / nStaves; - double theta1 = std::atan(staveWidth / 2 / mInnerRadius); - double st = std::sin(theta); - double ct = std::cos(theta); - double theta2 = std::atan((mInnerRadius * st - staveWidth / 2 * ct) / (mInnerRadius * ct + staveWidth / 2 * st)); - double overlap = (theta1 - theta2) * mInnerRadius; - LOGP(info, "Creating a layer with {} staves and {} mm overlap", nStaves, overlap * 10); - - for (int iStave = 0; iStave < nStaves; iStave++) { - TGeoVolume* staveVol = createStave("flat"); - - // Put the staves in the correct position and orientation - TGeoCombiTrans* trans = new TGeoCombiTrans(); - double theta = 360. * iStave / nStaves; - TGeoRotation* rot = new TGeoRotation("rot", theta + 90 + 4, 0, 0); - trans->SetRotation(rot); - trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); - - LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); - layerVol->AddNode(staveVol, iStave, trans); - } - } else if (mLayout == kStaggered) { - double overlapInStave = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true)overlap - - double staveWidth = constants::OT::width - overlapInStave; - - layer = new TGeoTube(mInnerRadius - 0.333 * layerThickness, mInnerRadius + 0.667 * layerThickness, layerLength / 2); - layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - - // Compute the number of staves - int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / staveWidth); - nStaves += nStaves % 2; // Require an even number of staves - - // Compute the size of the overlap region - double theta = 2 * TMath::Pi() / nStaves; - double theta1 = std::atan(staveWidth / 2 / mInnerRadius); - double st = std::sin(theta); - double ct = std::cos(theta); - double theta2 = std::atan((mInnerRadius * st - staveWidth / 2 * ct) / (mInnerRadius * ct + staveWidth / 2 * st)); - double overlap = (theta1 - theta2) * mInnerRadius; - LOGP(info, "Creating a layer with {} staves and {} mm overlap", nStaves, overlap * 10); - - for (int iStave = 0; iStave < nStaves; iStave++) { - TGeoVolume* staveVol = createStave("staggered"); - - // Put the staves in the correct position and orientation - TGeoCombiTrans* trans = new TGeoCombiTrans(); - double theta = 360. * iStave / nStaves; - TGeoRotation* rot = new TGeoRotation("rot", theta + 90, 0, 0); - trans->SetRotation(rot); - trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); - - LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); - layerVol->AddNode(staveVol, iStave, trans); - } - } else { - LOGP(fatal, "Layout not implemented"); + layerVol->AddNode(staveVol, iStave, trans); } - layerVol->SetLineColor(kYellow); LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); motherVolume->AddNode(layerVol, 1, nullptr); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer_copy.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer_copy.cxx deleted file mode 100644 index c54cd91f2ba10..0000000000000 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer_copy.cxx +++ /dev/null @@ -1,358 +0,0 @@ -// 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. - -#include "TRKSimulation/TRKLayer.h" -#include "TRKBase/GeometryTGeo.h" -#include "TRKBase/Specs.h" - -#include "Framework/Logger.h" - -#include -#include -#include - -#include -#include "TRKLayer_copy.h" - -namespace o2 -{ -namespace trk -{ -TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float layerX2X0) - : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length), mX2X0(layerX2X0) -{ - sChipThickness = mX2X0 * Si_X0; - mOuterRadius = rInn + sChipThickness; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thick) - : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length), sChipThickness(thick) -{ - mOuterRadius = rInn + thick; - mX2X0 = thick / Si_X0; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TGeoVolume* TRKCylindricalLayer::createSensor() -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string sensName = GeometryTGeo::getTRKSensorPattern() + std::to_string(mLayerNumber); - TGeoShape* sensor = new TGeoTube(mInnerRadius, mInnerRadius + sSensorThickness, mLength / 2); - TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); - sensVol->SetLineColor(kYellow); - - return sensVol; -}; - -TGeoVolume* TRKCylindricalLayer::createMetalStack() -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string metalName = GeometryTGeo::getTRKMetalStackPattern() + std::to_string(mLayerNumber); - TGeoShape* metalStack metalStack = new TGeoTube(mInnerRadius + sSensorThickness, mInnerRadius + sChipThickness, mLength / 2); - TGeoVolume* metalVol = new TGeoVolume(metalName.c_str(), metalStack, medSi); - metalVol->SetLineColor(kGray); - - return metalVol; -}; - -void TRKCylindricalLayer::createLayer(TGeoVolume* motherVolume) -{ - TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); - TGeoTube* layer = new TGeoTube(mInnerRadius, mInnerRadius + sChipThickness, mLength / 2); - TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - layerVol->SetLineColor(kYellow); - - TGeoVolume* sensVol = createSensor(); - LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); - layerVol->AddNode(sensVol, 1, nullptr); - - TGeoVolume* metalVol = createMetalStack(); - LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); - layerVol->AddNode(metalVol, 1, nullptr); - - LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); - motherVolume->AddNode(layerVol, 1, nullptr); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) - : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, layerX2X0), mNumberOfModules(numberOfModules) -{ - sChipThickness = mX2X0 * Si_X0; - mOuterRadius = rInn + sChipThickness; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) - : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, thick), mNumberOfModules(numberOfModules) -{ - mOuterRadius = rInn + thick; - mX2X0 = thick / Si_X0; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TGeoVolume* TRKSegmentedLayer::createSensor() -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string sensName = GeometryTGeo::getTRKSensorPattern() + std::to_string(mLayerNumber); - TGeoShape* sensor = new TGeoBBox((sChipWidth - sDeadzoneWidth) / 2, sSensorThickness / 2, sChipLength / 2); - TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); - sensVol->SetLineColor(kYellow); - - return sensVol; -} - -TGeoVolume* TRKSegmentedLayer::createDeadzone() -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string deadName = GeometryTGeo::getTRKDeadzonePattern() + std::to_string(mLayerNumber); - TGeoShape* deadzone = new TGeoBBox(sDeadzoneWidth / 2, sSensorThickness / 2, sChipLength / 2); - TGeoVolume* deadVol = new TGeoVolume(deadName.c_str(), deadzone, medSi); - deadVol->SetLineColor(kGray); - - return deadVol; -} - -TGeoVolume* TRKSegmentedLayer::createMetalStack() -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string metalName = GeometryTGeo::getTRKMetalStackPattern() + std::to_string(mLayerNumber); - TGeoShape* metalStack = new TGeoBBox(sChipWidth / 2, (sChipThickness - sSensorThickness) / 2, sChipLength / 2); - TGeoVolume* metalVol = new TGeoVolume(metalName.c_str(), metalStack, medSi); - metalVol->SetLineColor(kGray); - - return metalVol; -} - -TGeoVolume* TRKSegmentedLayer::createChip() -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string chipName = GeometryTGeo::getTRKChipPattern() + std::to_string(mLayerNumber); - TGeoShape* chip = new TGeoBBox(sChipWidth / 2, sChipThickness / 2, sChipLength / 2); - TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); - chipVol->SetLineColor(kYellow); - - TGeoVolume* sensVol = createSensor(); - TGeoCombiTrans* transSens = new TGeoCombiTrans(); - transSens->SetTranslation(-sDeadzoneWidth / 2, -(sChipThickness - sSensorThickness) / 2, 0); - LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); - chipVol->AddNode(sensVol, 1, transSens); - - TGeoVolume* deadVol = createDeadzone(); - TGeoCombiTrans* transDead = new TGeoCombiTrans(); - transDead->SetTranslation((sChipWidth - sDeadzoneWidth) / 2, -(sChipThickness - sSensorThickness) / 2, 0); - LOGP(debug, "Inserting {} in {} ", deadVol->GetName(), chipVol->GetName()); - chipVol->AddNode(deadVol, 1, transDead); - - TGeoVolume* metalVol = createMetalStack(); - TGeoCombiTrans* transMetal = new TGeoCombiTrans(); - transMetal->SetTranslation(0, sSensorThickness / 2, 0); - LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); - chipVol->AddNode(metalVol, 1, transMetal); - - return chipVol; -} - -TGeoVolume* TRKSegmentedLayer::createModule() -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string moduleName = GeometryTGeo::getTRKModulePattern() + std::to_string(mLayerNumber); - TGeoShape* module = new TGeoBBox(sModuleWidth / 2, sChipThickness / 2, sModuleLength / 2); - TGeoVolume* moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); - moduleVol->SetLineColor(kYellow); - - for (int iChip = 0; iChip < mHalfNumberOfChips; iChip++) { - TGeoVolume* chipVolLeft = createChip(); - double xLeft = -sModuleWidth / 2 + constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::width / 2; - double zLeft = -sModuleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; - TGeoCombiTrans* transLeft = new TGeoCombiTrans(); - transLeft->SetTranslation(xLeft, 0, zLeft); - TGeoRotation* rot = new TGeoRotation(); - rot->RotateY(180); - transLeft->SetRotation(rot); - LOGP(debug, "Inserting {} in {} ", chipVolLeft->GetName(), moduleVol->GetName()); - moduleVol->AddNode(chipVolLeft, iChip * 2, transLeft); - - TGeoVolume* chipVolRight = createChip(); - double xRight = +sModuleWidth / 2 - constants::moduleMLOT::gaps::outerEdgeLongSide - constants::moduleMLOT::chip::width / 2; - double zRight = -sModuleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; - TGeoCombiTrans* transRight = new TGeoCombiTrans(); - transRight->SetTranslation(xRight, 0, zRight); - LOGP(debug, "Inserting {} in {} ", chipVolRight->GetName(), moduleVol->GetName()); - moduleVol->AddNode(chipVolRight, iChip * 2 + 1, transRight); - } - - return moduleVol; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) - : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, layerX2X0) -{ - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) - : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thick) -{ - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TGeoVolume* TRKMLLayer::createStave() -{ - TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); - std::string staveName = GeometryTGeo::getTRKStavePattern() + std::to_string(mLayerNumber); - TGeoShape* stave = new TGeoBBox(sStaveWidth / 2, sChipThickness / 2, mLength / 2); - TGeoVolume* staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); - staveVol->SetLineColor(kYellow); - - for (int iModule = 0; iModule < mNumberOfModules; iModule++) { - TGeoVolume* moduleVol = createModule(); - double zPos = -0.5 * mNumberOfModules * sModuleLength + (iModule + 0.5) * sModuleLength; - TGeoCombiTrans* trans = new TGeoCombiTrans(); - trans->SetTranslation(0, 0, zPos); - LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), staveVol->GetName()); - staveVol->AddNode(moduleVol, iModule, trans); - } - - return staveVol; -} - -void TRKMLLayer::createLayer(TGeoVolume* motherVolume) -{ - TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); - TGeoTube* layer = new TGeoTube(mInnerRadius - 0.333 * sLogicalVolumeThickness, mInnerRadius + 0.667 * sLogicalVolumeThickness, mLength / 2); - TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - layerVol->SetLineColor(kYellow); - - // Compute the number of staves - int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / sStaveWidth); - nStaves += nStaves % 2; // Require an even number of staves - - // Compute the size of the overlap region - double theta = 2 * TMath::Pi() / nStaves; - double theta1 = std::atan(sStaveWidth / 2 / mInnerRadius); - double st = std::sin(theta); - double ct = std::cos(theta); - double theta2 = std::atan((mInnerRadius * st - sStaveWidth / 2 * ct) / (mInnerRadius * ct + sStaveWidth / 2 * st)); - double overlap = (theta1 - theta2) * mInnerRadius; - LOGP(info, "Creating a layer with {} staves and {} mm overlap", nStaves, overlap * 10); - - for (int iStave = 0; iStave < nStaves; iStave++) { - TGeoVolume* staveVol = createStave(); - TGeoCombiTrans* trans = new TGeoCombiTrans(); - double theta = 360. * iStave / nStaves; - TGeoRotation* rot = new TGeoRotation("rot", theta - 90 + 4, 0, 0); - trans->SetRotation(rot); - trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); - LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); - layerVol->AddNode(staveVol, iStave, trans); - } - - LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); - motherVolume->AddNode(layerVol, 1, nullptr); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) - : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, layerX2X0) -{ - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) - : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thick) -{ - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TGeoVolume* TRKOTLayer::createHalfStave() -{ - TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); - std::string halfStaveName = GeometryTGeo::getTRKHalfStavePattern() + std::to_string(mLayerNumber); - TGeoShape* halfStave = new TGeoBBox(sHalfStaveWidth / 2, sChipThickness / 2, mLength / 2); - TGeoVolume* halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); - halfStaveVol->SetLineColor(kYellow); - - for (int iModule = 0; iModule < mNumberOfModules; iModule++) { - TGeoVolume* moduleVol = createModule("flat"); - double zPos = -0.5 * mNumberOfModules * sModuleLength + (iModule + 0.5) * sModuleLength; - TGeoCombiTrans* trans = new TGeoCombiTrans(); - trans->SetTranslation(0, 0, zPos); - LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), halfStaveVol->GetName()); - halfStaveVol->AddNode(moduleVol, iModule, trans); - } - - return halfStaveVol; -} - -TGeoVolume* TRKOTLayer::createStave() -{ - std::string staveName = GeometryTGeo::getTRKStavePattern() + std::to_string(mLayerNumber); - TGeoVolume* staveVol = new TGeoVolumeAssembly(staveName.c_str()); - - TGeoVolume* halfStaveVolLeft = createHalfStave(); - TGeoCombiTrans* transLeft = new TGeoCombiTrans(); - transLeft->SetTranslation(-(sHalfStaveWidth - sInStaveOverlap) / 2, 0, 0); - LOGP(debug, "Inserting {} in {} ", halfStaveVolLeft->GetName(), staveVol->GetName()); - staveVol->AddNode(halfStaveVolLeft, 0, transLeft); - - TGeoVolume* halfStaveVolRight = createHalfStave(); - TGeoCombiTrans* transRight = new TGeoCombiTrans(); - transRight->SetTranslation(sHalfStaveWidth / 2 - shift, 0.2, 0); - LOGP(debug, "Inserting {} in {} ", halfStaveVolRight->GetName(), staveVol->GetName()); - staveVol->AddNode(halfStaveVolRight, 1, transRight); - - return staveVol; -} - -void TRKOTLayer::createLayer(TGeoVolume* motherVolume) -{ - TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); - TGeoTube* layer = new TGeoTube(mInnerRadius - 0.333 * sLogicalVolumeThickness, mInnerRadius + 0.667 * sLogicalVolumeThickness, mLength / 2); - TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - layerVol->SetLineColor(kYellow); - - // Compute the number of staves - int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / sStaveWidth); - nStaves += nStaves % 2; // Require an even number of staves - - // Compute the size of the overlap region - double theta = 2 * TMath::Pi() / nStaves; - double theta1 = std::atan(sStaveWidth / 2 / mInnerRadius); - double st = std::sin(theta); - double ct = std::cos(theta); - double theta2 = std::atan((mInnerRadius * st - sStaveWidth / 2 * ct) / (mInnerRadius * ct + sStaveWidth / 2 * st)); - double overlap = (theta1 - theta2) * mInnerRadius; - LOGP(info, "Creating a layer with {} staves and {} mm overlap", nStaves, overlap * 10); - - for (int iStave = 0; iStave < nStaves; iStave++) { - TGeoVolume* staveVol = createStave(); - TGeoCombiTrans* trans = new TGeoCombiTrans(); - double theta = 360. * iStave / nStaves; - TGeoRotation* rot = new TGeoRotation("rot", theta - 90, 0, 0); - trans->SetRotation(rot); - trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); - LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); - layerVol->AddNode(staveVol, iStave, trans); - } - - LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); - motherVolume->AddNode(layerVol, 1, nullptr); -} -// ClassImp(TRKLayer); - -} // namespace trk -} // namespace o2 \ No newline at end of file From 4b44f28c14341952704751176a78a47ad86bc83b Mon Sep 17 00:00:00 2001 From: scannito Date: Tue, 10 Mar 2026 11:18:45 +0100 Subject: [PATCH 3/7] Fix --- Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index 93c0171543eca..1a81723a18f63 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -404,7 +404,7 @@ TString GeometryTGeo::getMatrixPath(int index) const // handling cylindrical configuration for ML and/or OT // needed because of the different numbering scheme in the geometry for the cylindrical case wrt the staggered and turbo ones if (subDetID == 1) { - if ((layer < 4 && mLayoutMLOT == eMLOTLayout::kCylindrical) || (layer > 3 && mLayoutMLOT == MLOTLayout::kCylindrical)) { + if ((layer < 4 && mLayoutMLOT == eMLOTLayout::kCylindrical) || (layer > 3 && mLayoutMLOT == eMLOTLayout::kCylindrical)) { stave = 1; mod = 1; chip = 1; From 0f2407c3e68f7bb202d02ec0e6302b215f329607 Mon Sep 17 00:00:00 2001 From: scannito Date: Tue, 10 Mar 2026 14:25:33 +0100 Subject: [PATCH 4/7] Fix constructors --- .../include/TRKSimulation/Detector.h | 3 +- .../include/TRKSimulation/TRKLayer.h | 27 +++--- .../ALICE3/TRK/simulation/src/Detector.cxx | 33 ++++--- .../ALICE3/TRK/simulation/src/TRKLayer.cxx | 88 +++++++------------ .../TRK/simulation/src/TRKSimulationLinkDef.h | 5 +- 5 files changed, 72 insertions(+), 84 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h index ed2c7bfea6218..9666916800185 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h @@ -32,6 +32,7 @@ class Detector : public o2::base::DetImpl public: Detector(bool active); Detector(); + Detector(const Detector& other); ~Detector(); // Factory method @@ -87,7 +88,7 @@ class Detector : public o2::base::DetImpl double mEnergyLoss; // energy loss } mTrackData; //! transient data GeometryTGeo* mGeometryTGeo; //! - std::vector* mHits; // ITSMFT ones for the moment + std::vector* mHits; // Derived from ITSMFT std::vector> mLayers; TRKServices mServices; // Houses the services of the TRK, but not the Iris tracker diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h index c0e15d36929a4..6077d9e5f9839 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h @@ -22,12 +22,16 @@ namespace o2 { namespace trk { +enum class MatBudgetParamMode { + Thickness, + X2X0 +}; + class TRKCylindricalLayer { public: TRKCylindricalLayer() = default; - TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float layerX2X0); - TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thick); + TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thickOrX2X0, MatBudgetParamMode mode); virtual ~TRKCylindricalLayer() = default; auto getInnerRadius() const { return mInnerRadius; } @@ -64,8 +68,7 @@ class TRKSegmentedLayer : public TRKCylindricalLayer { public: TRKSegmentedLayer() = default; - TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); - TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode); ~TRKSegmentedLayer() override = default; TGeoVolume* createSensor() override; @@ -73,10 +76,10 @@ class TRKSegmentedLayer : public TRKCylindricalLayer TGeoVolume* createMetalStack() override; TGeoVolume* createChip(); TGeoVolume* createModule(); - TGeoVolume* createStave() = 0; + virtual TGeoVolume* createStave() = 0; void createLayer(TGeoVolume* motherVolume) override = 0; - private: + protected: int mNumberOfModules; // Fixed parameters for the layer, to be set based on the specifications of the chip and module @@ -90,15 +93,14 @@ class TRKSegmentedLayer : public TRKCylindricalLayer // TGeo objects outside logical volumes can cause errors static constexpr float sLogicalVolumeThickness = 1.3; - ClassDef(TRKSegmentedLayer, 0); + ClassDefOverride(TRKSegmentedLayer, 0); }; class TRKMLLayer : public TRKSegmentedLayer { public: TRKMLLayer() = default; - TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); - TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode); ~TRKMLLayer() override = default; TGeoVolume* createStave() override; @@ -107,15 +109,14 @@ class TRKMLLayer : public TRKSegmentedLayer private: static constexpr double sStaveWidth = constants::ML::width; - ClassDef(TRKMLLayer, 0); + ClassDefOverride(TRKMLLayer, 0); }; class TRKOTLayer : public TRKSegmentedLayer { public: TRKOTLayer() = default; - TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0); - TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick); + TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode); ~TRKOTLayer() override = default; TGeoVolume* createStave() override; @@ -127,7 +128,7 @@ class TRKOTLayer : public TRKSegmentedLayer static constexpr double sInStaveOverlap = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true) overlap static constexpr double sStaveWidth = constants::OT::width - sInStaveOverlap; - ClassDef(TRKOTLayer, 0) + ClassDefOverride(TRKOTLayer, 0) }; } // namespace trk diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx index 95dde592fc043..8e13d31e7915c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -61,10 +61,17 @@ Detector::Detector(bool active) LOGP(info, "Summary of TRK configuration:"); for (auto& layer : mLayers) { - LOGP(info, "Layer: {} name: {} r: {} cm | z: {} cm | thickness: {} cm", layer.getNumber(), layer.getName(), layer.getInnerRadius(), layer.getZ(), layer.getChipThickness()); + LOGP(info, "Layer: {} name: {} r: {} cm | z: {} cm | thickness: {} cm", layer->getNumber(), layer->getName(), layer->getInnerRadius(), layer->getZ(), layer->getChipThickness()); } } +Detector::Detector(const Detector& other) + : o2::base::DetImpl(other), + mTrackData(), + mHits(o2::utils::createSimVector()) +{ +} + Detector::~Detector() { if (mHits) { @@ -88,26 +95,28 @@ void Detector::configMLOT() const float thick = 100.e-3; switch (trkPars.layoutMLOT) { - case kCylindrical: + case kCylindrical: { const std::vector length{128.35f, 128.35f, 128.35f, 128.35f, 128.35f, 256.7f, 256.7f, 256.7f}; LOGP(warning, "Loading cylindrical configuration for ALICE3 TRK"); for (int i{0}; i < 8; ++i) { std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i); - mLayers.push_back(std::make_unique(i, name, rInn[i], length[i], thick)); + mLayers.push_back(std::make_unique(i, name, rInn[i], length[i], thick, MatBudgetParamMode::Thickness)); } break; - case kSegmented: + } + case kSegmented: { const std::vector nMods{10, 10, 10, 10, 10, 20, 20, 20}; LOGP(warning, "Loading segmented configuration for ALICE3 TRK"); for (int i{0}; i < 8; ++i) { std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i); if (i < 4) { - mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick)); + mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick, MatBudgetParamMode::Thickness)); } else { - mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick)); + mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick, MatBudgetParamMode::Thickness)); } } break; + } default: LOGP(fatal, "Unknown option {} for configMLOT", static_cast(trkPars.layoutMLOT)); break; @@ -146,14 +155,14 @@ void Detector::configFromFile(std::string fileName) std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(layerCount); switch (trkPars.layoutMLOT) { case kCylindrical: - mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], tmpBuff[1], tmpBuff[2])); + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], tmpBuff[1], tmpBuff[2], MatBudgetParamMode::Thickness)); break; case kSegmented: { int nMods = static_cast(tmpBuff[1]); if (layerCount < 4) { - mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2])); + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2], MatBudgetParamMode::Thickness)); } else { - mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2])); + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2], MatBudgetParamMode::Thickness)); } break; } @@ -171,8 +180,8 @@ void Detector::configToFile(std::string fileName) LOGP(info, "Exporting TRK Detector layout to {}", fileName); std::ofstream conFile(fileName.c_str(), std::ios::out); conFile << "/// TRK configuration file: inn_radius z_length lay_thickness" << std::endl; - for (auto layer : mLayers) { - conFile << layer.getInnerRadius() << "\t" << layer.getZ() << "\t" << layer.getChipThickness() << std::endl; + for (const auto& layer : mLayers) { + conFile << layer->getInnerRadius() << "\t" << layer->getZ() << "\t" << layer->getChipThickness() << std::endl; } } @@ -237,7 +246,7 @@ void Detector::createGeometry() vTRK->SetTitle(vstrng); for (auto& layer : mLayers) { - layer.createLayer(vTRK); + layer->createLayer(vTRK); } // Add service for inner tracker diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx index c54cd91f2ba10..9fcbb278b774d 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -20,25 +20,24 @@ #include #include -#include "TRKLayer_copy.h" namespace o2 { namespace trk { -TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float layerX2X0) - : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length), mX2X0(layerX2X0) +TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thickOrX2X0, MatBudgetParamMode mode) + : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length) { - sChipThickness = mX2X0 * Si_X0; - mOuterRadius = rInn + sChipThickness; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} + if (mode == MatBudgetParamMode::Thickness) { + mChipThickness = thickOrX2X0; + mX2X0 = thickOrX2X0 / Si_X0; + mOuterRadius = rInn + thickOrX2X0; + } else if (mode == MatBudgetParamMode::X2X0) { + mX2X0 = thickOrX2X0; + mChipThickness = thickOrX2X0 * Si_X0; + mOuterRadius = rInn + thickOrX2X0 * Si_X0; + } -TRKCylindricalLayer::TRKCylindricalLayer(int layerNumber, std::string layerName, float rInn, float length, float thick) - : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length), sChipThickness(thick) -{ - mOuterRadius = rInn + thick; - mX2X0 = thick / Si_X0; LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); } @@ -57,7 +56,7 @@ TGeoVolume* TRKCylindricalLayer::createMetalStack() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string metalName = GeometryTGeo::getTRKMetalStackPattern() + std::to_string(mLayerNumber); - TGeoShape* metalStack metalStack = new TGeoTube(mInnerRadius + sSensorThickness, mInnerRadius + sChipThickness, mLength / 2); + TGeoShape* metalStack = new TGeoTube(mInnerRadius + sSensorThickness, mInnerRadius + mChipThickness, mLength / 2); TGeoVolume* metalVol = new TGeoVolume(metalName.c_str(), metalStack, medSi); metalVol->SetLineColor(kGray); @@ -67,16 +66,16 @@ TGeoVolume* TRKCylindricalLayer::createMetalStack() void TRKCylindricalLayer::createLayer(TGeoVolume* motherVolume) { TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); - TGeoTube* layer = new TGeoTube(mInnerRadius, mInnerRadius + sChipThickness, mLength / 2); + TGeoTube* layer = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, mLength / 2); TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); layerVol->SetLineColor(kYellow); TGeoVolume* sensVol = createSensor(); - LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), layerVol->GetName()); layerVol->AddNode(sensVol, 1, nullptr); TGeoVolume* metalVol = createMetalStack(); - LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), layerVol->GetName()); layerVol->AddNode(metalVol, 1, nullptr); LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); @@ -85,20 +84,9 @@ void TRKCylindricalLayer::createLayer(TGeoVolume* motherVolume) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) - : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, layerX2X0), mNumberOfModules(numberOfModules) +TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode) + : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, thickOrX2X0, mode), mNumberOfModules(numberOfModules) { - sChipThickness = mX2X0 * Si_X0; - mOuterRadius = rInn + sChipThickness; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TRKSegmentedLayer::TRKSegmentedLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) - : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, thick), mNumberOfModules(numberOfModules) -{ - mOuterRadius = rInn + thick; - mX2X0 = thick / Si_X0; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); } TGeoVolume* TRKSegmentedLayer::createSensor() @@ -127,7 +115,7 @@ TGeoVolume* TRKSegmentedLayer::createMetalStack() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string metalName = GeometryTGeo::getTRKMetalStackPattern() + std::to_string(mLayerNumber); - TGeoShape* metalStack = new TGeoBBox(sChipWidth / 2, (sChipThickness - sSensorThickness) / 2, sChipLength / 2); + TGeoShape* metalStack = new TGeoBBox(sChipWidth / 2, (mChipThickness - sSensorThickness) / 2, sChipLength / 2); TGeoVolume* metalVol = new TGeoVolume(metalName.c_str(), metalStack, medSi); metalVol->SetLineColor(kGray); @@ -138,19 +126,19 @@ TGeoVolume* TRKSegmentedLayer::createChip() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string chipName = GeometryTGeo::getTRKChipPattern() + std::to_string(mLayerNumber); - TGeoShape* chip = new TGeoBBox(sChipWidth / 2, sChipThickness / 2, sChipLength / 2); + TGeoShape* chip = new TGeoBBox(sChipWidth / 2, mChipThickness / 2, sChipLength / 2); TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); chipVol->SetLineColor(kYellow); TGeoVolume* sensVol = createSensor(); TGeoCombiTrans* transSens = new TGeoCombiTrans(); - transSens->SetTranslation(-sDeadzoneWidth / 2, -(sChipThickness - sSensorThickness) / 2, 0); + transSens->SetTranslation(-sDeadzoneWidth / 2, -(mChipThickness - sSensorThickness) / 2, 0); LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); chipVol->AddNode(sensVol, 1, transSens); TGeoVolume* deadVol = createDeadzone(); TGeoCombiTrans* transDead = new TGeoCombiTrans(); - transDead->SetTranslation((sChipWidth - sDeadzoneWidth) / 2, -(sChipThickness - sSensorThickness) / 2, 0); + transDead->SetTranslation((sChipWidth - sDeadzoneWidth) / 2, -(mChipThickness - sSensorThickness) / 2, 0); LOGP(debug, "Inserting {} in {} ", deadVol->GetName(), chipVol->GetName()); chipVol->AddNode(deadVol, 1, transDead); @@ -167,11 +155,11 @@ TGeoVolume* TRKSegmentedLayer::createModule() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string moduleName = GeometryTGeo::getTRKModulePattern() + std::to_string(mLayerNumber); - TGeoShape* module = new TGeoBBox(sModuleWidth / 2, sChipThickness / 2, sModuleLength / 2); + TGeoShape* module = new TGeoBBox(sModuleWidth / 2, mChipThickness / 2, sModuleLength / 2); TGeoVolume* moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); moduleVol->SetLineColor(kYellow); - for (int iChip = 0; iChip < mHalfNumberOfChips; iChip++) { + for (int iChip = 0; iChip < sHalfNumberOfChips; iChip++) { TGeoVolume* chipVolLeft = createChip(); double xLeft = -sModuleWidth / 2 + constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::width / 2; double zLeft = -sModuleLength / 2 + constants::moduleMLOT::gaps::outerEdgeShortSide + iChip * (constants::moduleMLOT::chip::length + constants::moduleMLOT::gaps::interChips) + constants::moduleMLOT::chip::length / 2; @@ -197,23 +185,16 @@ TGeoVolume* TRKSegmentedLayer::createModule() ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) - : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, layerX2X0) +TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thickOrX2X0, mode) { - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) - : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thick) -{ - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); } TGeoVolume* TRKMLLayer::createStave() { TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); std::string staveName = GeometryTGeo::getTRKStavePattern() + std::to_string(mLayerNumber); - TGeoShape* stave = new TGeoBBox(sStaveWidth / 2, sChipThickness / 2, mLength / 2); + TGeoShape* stave = new TGeoBBox(sStaveWidth / 2, mChipThickness / 2, mLength / 2); TGeoVolume* staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); staveVol->SetLineColor(kYellow); @@ -266,28 +247,21 @@ void TRKMLLayer::createLayer(TGeoVolume* motherVolume) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float layerX2X0) - : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, layerX2X0) +TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thickOrX2X0, mode) { - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); -} - -TRKOTLayer::TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) - : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thick) -{ - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, mLength, mX2X0); } TGeoVolume* TRKOTLayer::createHalfStave() { TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string halfStaveName = GeometryTGeo::getTRKHalfStavePattern() + std::to_string(mLayerNumber); - TGeoShape* halfStave = new TGeoBBox(sHalfStaveWidth / 2, sChipThickness / 2, mLength / 2); + TGeoShape* halfStave = new TGeoBBox(sHalfStaveWidth / 2, mChipThickness / 2, mLength / 2); TGeoVolume* halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); halfStaveVol->SetLineColor(kYellow); for (int iModule = 0; iModule < mNumberOfModules; iModule++) { - TGeoVolume* moduleVol = createModule("flat"); + TGeoVolume* moduleVol = createModule(); double zPos = -0.5 * mNumberOfModules * sModuleLength + (iModule + 0.5) * sModuleLength; TGeoCombiTrans* trans = new TGeoCombiTrans(); trans->SetTranslation(0, 0, zPos); @@ -311,7 +285,7 @@ TGeoVolume* TRKOTLayer::createStave() TGeoVolume* halfStaveVolRight = createHalfStave(); TGeoCombiTrans* transRight = new TGeoCombiTrans(); - transRight->SetTranslation(sHalfStaveWidth / 2 - shift, 0.2, 0); + transRight->SetTranslation((sHalfStaveWidth - sInStaveOverlap) / 2, 0.2, 0); LOGP(debug, "Inserting {} in {} ", halfStaveVolRight->GetName(), staveVol->GetName()); staveVol->AddNode(halfStaveVolRight, 1, transRight); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h index fec9cb6631a6f..282fc72becc52 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h @@ -18,7 +18,10 @@ #pragma link C++ class o2::trk::Hit + ; #pragma link C++ class std::vector < o2::trk::Hit> + ; -#pragma link C++ class o2::trk::TRKLayer + ; +#pragma link C++ class o2::trk::TRKCylindricalLayer + ; +#pragma link C++ class o2::trk::TRKSegmentedLayer + ; +#pragma link C++ class o2::trk::TRKMLLayer + ; +#pragma link C++ class o2::trk::TRKOTLayer + ; #pragma link C++ class o2::trk::VDLayer + ; #pragma link C++ class o2::trk::TRKServices + ; #pragma link C++ class o2::trk::Detector + ; From 117cad4b158161fefaa15860902f8f46a37698dd Mon Sep 17 00:00:00 2001 From: scannito Date: Tue, 10 Mar 2026 15:27:51 +0100 Subject: [PATCH 5/7] Andrea's modifications --- .../ALICE3/TRK/simulation/src/TRKLayer.cxx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx index 9fcbb278b774d..39c7b3598d19b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -132,19 +132,22 @@ TGeoVolume* TRKSegmentedLayer::createChip() TGeoVolume* sensVol = createSensor(); TGeoCombiTrans* transSens = new TGeoCombiTrans(); - transSens->SetTranslation(-sDeadzoneWidth / 2, -(mChipThickness - sSensorThickness) / 2, 0); + // transSens->SetTranslation(-sDeadzoneWidth / 2, -(mChipThickness - sSensorThickness) / 2, 0); + transSens->SetTranslation(-sDeadzoneWidth / 2, (mChipThickness - sSensorThickness) / 2, 0); LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); chipVol->AddNode(sensVol, 1, transSens); TGeoVolume* deadVol = createDeadzone(); TGeoCombiTrans* transDead = new TGeoCombiTrans(); - transDead->SetTranslation((sChipWidth - sDeadzoneWidth) / 2, -(mChipThickness - sSensorThickness) / 2, 0); + // transDead->SetTranslation((sChipWidth - sDeadzoneWidth) / 2, -(mChipThickness - sSensorThickness) / 2, 0); + transDead->SetTranslation((sChipWidth - sDeadzoneWidth) / 2, (mChipThickness - sSensorThickness) / 2, 0); LOGP(debug, "Inserting {} in {} ", deadVol->GetName(), chipVol->GetName()); chipVol->AddNode(deadVol, 1, transDead); TGeoVolume* metalVol = createMetalStack(); TGeoCombiTrans* transMetal = new TGeoCombiTrans(); - transMetal->SetTranslation(0, sSensorThickness / 2, 0); + // transMetal->SetTranslation(0, sSensorThickness / 2, 0); + transMetal->SetTranslation(0, -sSensorThickness / 2, 0); LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); chipVol->AddNode(metalVol, 1, transMetal); @@ -234,7 +237,8 @@ void TRKMLLayer::createLayer(TGeoVolume* motherVolume) TGeoVolume* staveVol = createStave(); TGeoCombiTrans* trans = new TGeoCombiTrans(); double theta = 360. * iStave / nStaves; - TGeoRotation* rot = new TGeoRotation("rot", theta - 90 + 4, 0, 0); + // TGeoRotation* rot = new TGeoRotation("rot", theta - 90 + 4, 0, 0); + TGeoRotation* rot = new TGeoRotation("rot", theta + 90 + 4, 0, 0); trans->SetRotation(rot); trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); @@ -316,7 +320,8 @@ void TRKOTLayer::createLayer(TGeoVolume* motherVolume) TGeoVolume* staveVol = createStave(); TGeoCombiTrans* trans = new TGeoCombiTrans(); double theta = 360. * iStave / nStaves; - TGeoRotation* rot = new TGeoRotation("rot", theta - 90, 0, 0); + // TGeoRotation* rot = new TGeoRotation("rot", theta - 90, 0, 0); + TGeoRotation* rot = new TGeoRotation("rot", theta + 90, 0, 0); trans->SetRotation(rot); trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); From 44afa5810822c0c7fc8f4e92528a6576f1e424c4 Mon Sep 17 00:00:00 2001 From: scannito Date: Mon, 9 Mar 2026 16:03:14 +0100 Subject: [PATCH 6/7] Naming --- Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx index 39c7b3598d19b..f398b03024b06 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -20,6 +20,7 @@ #include #include +#include "TRKLayer_copy.h" namespace o2 { From 887f8cbb36cc9e4649be1ac3cc10f1789b2b7667 Mon Sep 17 00:00:00 2001 From: scannito Date: Wed, 11 Mar 2026 10:34:25 +0100 Subject: [PATCH 7/7] Removed header --- Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx index f398b03024b06..39c7b3598d19b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -20,7 +20,6 @@ #include #include -#include "TRKLayer_copy.h" namespace o2 {