diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h index 616c6409f4577..c62b5b547d99a 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h @@ -50,6 +50,7 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache const int getOTOFNumberOfChips() const { return mNumberOfChipsIOTOF[1]; } static const char* getOTOFLayerPattern() { return sOTOFLayerName.c_str(); } static const char* getOTOFStavePattern() { return sOTOFStaveName.c_str(); } + static const char* getOTOFSubStavePattern() { return sOTOFSubStaveName.c_str(); } static const char* getOTOFModulePattern() { return sOTOFModuleName.c_str(); } static const char* getOTOFChipPattern() { return sOTOFChipName.c_str(); } static const char* getOTOFSensorPattern() { return sOTOFSensorName.c_str(); } @@ -96,8 +97,8 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache int getIOTOFFirstChipIndex(int lay) const; int getIOTOFLayer(int index) const; bool isValidIOTOFChipIndex(int index) const { return index >= 0 && index <= mLastChipIndex[1]; } - int getIOTOFChipIndex(int lay, int sta, int mod, int chip) const; - bool getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& chip) const; + int getIOTOFChipIndex(int lay, int sta, int substa, int mod, int chip) const; + bool getIOTOFChipId(int index, int& lay, int& sta, int& substa, int& mod, int& chip) const; o2::math_utils::Point3D detectorToLocal(int row, int col, int chipId) const; static const ChipSpecifics& getChipSpecifics(int iotofLayer); @@ -133,6 +134,7 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache protected: // Determine the number of active parts in the geometry int extractNumberOfStavesIOTOF(int lay) const; + int extractNumberOfSubStavesIOTOF(int lay) const; int extractNumberOfModulesIOTOF(int lay) const; int extractNumberOfChipsPerModuleIOTOF(int lay) const; int extractNumberOfChipsFTOF() const; @@ -151,6 +153,7 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache // Outer TOF static std::string sOTOFLayerName; static std::string sOTOFStaveName; + static std::string sOTOFSubStaveName; static std::string sOTOFModuleName; static std::string sOTOFChipName; static std::string sOTOFSensorName; @@ -167,9 +170,11 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache // Inner/outer TOF int mNumberOfStavesIOTOF[2]{}; + int mNumberOfSubStavesIOTOF[2]{}; int mNumberOfModulesIOTOF[2]{}; int mNumberOfChipsPerModuleIOTOF[2]{}; int mNumberOfChipsPerStaveIOTOF[2]{}; + int mNumberOfChipsPerSubStaveIOTOF[2]{}; int mNumberOfChipsIOTOF[2]{}; int mLastChipIndex[2]{-1, -1}; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h index f81f3f9484475..3364fd59d2165 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h @@ -21,65 +21,27 @@ namespace iotof { struct ChipSpecifics { - int NCols = 0; - int NRows = 0; - float PitchCol = 0.; - float PitchRow = 0.; + int NCols = 129; + int NRows = 271; + float PitchCol = 250.00e-4; + float PitchRow = 100.00e-4; float PassiveEdgeReadOut = 0.; float PassiveEdgeTop = 0.; float PassiveEdgeSide = 0.; float PixelPassiveEdgeX = 0.; float PixelPassiveEdgeZ = 0.; - float SensorLayerThicknessEff = 0.; - float SensorLayerThickness = 0.; + float SensorLayerThicknessEff = 50.e-4; + float SensorLayerThickness = 50.e-4; int NPixels() const { return NCols * NRows; } float ActiveMatrixSizeCols() const { return PitchCol * NCols; } float ActiveMatrixSizeRows() const { return PitchRow * NRows; } - float SensorSizeCols() const { return ActiveMatrixSizeCols() + 2 * PassiveEdgeSide; } + float SensorSizeCols() const { return ActiveMatrixSizeCols() + PassiveEdgeSide + PassiveEdgeSide; } float SensorSizeRows() const { return ActiveMatrixSizeRows() + PassiveEdgeTop + PassiveEdgeReadOut; } }; -struct ITOFChipSpecifics : ChipSpecifics { - ITOFChipSpecifics() - { - NCols = 129; - NRows = 271; - PitchCol = 250.00e-4; - PitchRow = 100.00e-4; - PassiveEdgeReadOut = 0.; - PassiveEdgeTop = 0.; - PassiveEdgeSide = 0.; - PixelPassiveEdgeX = 0.; - PixelPassiveEdgeZ = 0.; - SensorLayerThicknessEff = 50.e-4; - SensorLayerThickness = 50.e-4; - } -}; - -struct OTOFChipSpecifics : ChipSpecifics { - OTOFChipSpecifics() - { - NCols = 125; - NRows = 243; - PitchCol = 250.00e-4; - PitchRow = 100.00e-4; - PassiveEdgeTop = 50.e-4; - PassiveEdgeSide = 115.8e-4; - PassiveEdgeReadOut = 50.e-4; - PixelPassiveEdgeX = 0.; - PixelPassiveEdgeZ = 0.; - SensorLayerThicknessEff = 50.e-4; - SensorLayerThickness = 50.e-4; - } -}; - -struct ITOFChipSpecificParam : public o2::conf::ConfigurableParamPromoter { - O2ParamDef(ITOFChipSpecificParam, "ITOFChipSpecific"); -}; - -struct OTOFChipSpecificParam : public o2::conf::ConfigurableParamPromoter { - O2ParamDef(OTOFChipSpecificParam, "OTOFChipSpecific"); +struct ChipSpecificsParam : public o2::conf::ConfigurableParamPromoter { + O2ParamDef(ChipSpecificsParam, "ChipSpecificsParam") }; struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper { diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx index 905da9ddce754..8c8a36877eca8 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx @@ -34,6 +34,7 @@ std::string GeometryTGeo::sITOFSensorName = "ITOFSensor"; // Outer TOF std::string GeometryTGeo::sOTOFLayerName = "OTOFLayer"; std::string GeometryTGeo::sOTOFStaveName = "OTOFStave"; +std::string GeometryTGeo::sOTOFSubStaveName = "OTOFSubStave"; std::string GeometryTGeo::sOTOFModuleName = "OTOFModule"; std::string GeometryTGeo::sOTOFChipName = "OTOFChip"; std::string GeometryTGeo::sOTOFSensorName = "OTOFSensor"; @@ -81,11 +82,38 @@ int GeometryTGeo::extractNumberOfStavesIOTOF(int lay) const return numberOfStaves; } +int GeometryTGeo::extractNumberOfSubStavesIOTOF(int lay) const +{ + if (lay == 0) { + return 1; + } + + int numberOfSubStaves{0}; + + std::string staveName = GeometryTGeo::getOTOFStavePattern(); + TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str()); + if (staveV == nullptr) { + LOG(fatal) << "Can't find volume " << staveName; + return -1; + } + + TObjArray* nodes = staveV->GetNodes(); + int nNodes = nodes->GetEntriesFast(); + + for (int j{0}; j < nNodes; ++j) { + if (strstr(nodes->At(j)->GetName(), GeometryTGeo::getOTOFSubStavePattern()) != nullptr) { + numberOfSubStaves++; + } + } + + return numberOfSubStaves; +} + int GeometryTGeo::extractNumberOfModulesIOTOF(int lay) const { int numberOfModules{0}; - std::string staveName = lay == 0 ? GeometryTGeo::getITOFStavePattern() : GeometryTGeo::getOTOFStavePattern(); + std::string staveName = lay == 0 ? GeometryTGeo::getITOFStavePattern() : GeometryTGeo::getOTOFSubStavePattern(); TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str()); if (staveV == nullptr) { LOG(fatal) << "Can't find volume " << staveName; @@ -151,33 +179,27 @@ int GeometryTGeo::getIOTOFLayer(int index) const return index > mLastChipIndex[0] ? 1 : 0; } -int GeometryTGeo::getIOTOFChipIndex(int lay, int sta, int mod, int chip) const +int GeometryTGeo::getIOTOFChipIndex(int lay, int sta, int substa, int mod, int chip) const { - return getIOTOFFirstChipIndex(lay) + (sta - 1) * mNumberOfChipsPerStaveIOTOF[lay] + (mod - 1) * mNumberOfChipsPerModuleIOTOF[lay] + (chip - 1); + return getIOTOFFirstChipIndex(lay) + (sta - 1) * mNumberOfChipsPerStaveIOTOF[lay] + (substa - 1) * mNumberOfChipsPerSubStaveIOTOF[lay] + (mod - 1) * mNumberOfChipsPerModuleIOTOF[lay] + (chip - 1); } -bool GeometryTGeo::getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& chip) const +bool GeometryTGeo::getIOTOFChipId(int index, int& lay, int& sta, int& substa, int& mod, int& chip) const { lay = getIOTOFLayer(index); index -= getIOTOFFirstChipIndex(lay); sta = mNumberOfStavesIOTOF[lay] > 0 ? index / mNumberOfChipsPerStaveIOTOF[lay] : -1; index %= mNumberOfChipsPerStaveIOTOF[lay]; + substa = mNumberOfSubStavesIOTOF[lay] > 0 ? index / mNumberOfChipsPerSubStaveIOTOF[lay] : -1; + index %= mNumberOfChipsPerSubStaveIOTOF[lay]; mod = mNumberOfModulesIOTOF[lay] > 0 ? index / mNumberOfChipsPerModuleIOTOF[lay] : -1; chip = index % mNumberOfChipsPerModuleIOTOF[lay]; return true; } -const ChipSpecifics& GeometryTGeo::getChipSpecifics(int iotofLayer) -{ - if (iotofLayer == 0) { - return ITOFChipSpecificParam::Instance(); - } - return OTOFChipSpecificParam::Instance(); -} - o2::math_utils::Point3D GeometryTGeo::detectorToLocal(int row, int col, int chipId) const { - const auto& specs = getChipSpecifics(getIOTOFLayer(chipId)); + const auto& specs = ChipSpecificsParam::Instance(); o2::math_utils::Point3D loc; loc.SetCoordinates(0.5f * ((specs.ActiveMatrixSizeRows() - specs.PassiveEdgeTop + specs.PassiveEdgeReadOut) - specs.PitchRow) - row * specs.PitchRow, 0.f, @@ -187,11 +209,12 @@ o2::math_utils::Point3D GeometryTGeo::detectorToLocal(int row, int col, i TString GeometryTGeo::getMatrixPath(int index) const { - int lay, sta, mod, chip; - getIOTOFChipId(index, lay, sta, mod, chip); + int lay, sta, substa, mod, chip; + getIOTOFChipId(index, lay, sta, substa, mod, chip); TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getIOTOFVolPattern()); sta += 1; + substa += 1; mod += 1; chip += 1; @@ -211,6 +234,9 @@ TString GeometryTGeo::getMatrixPath(int index) const if (mNumberOfStavesIOTOF[lay] > 0) { path += Form("%s_%d/", GeometryTGeo::getOTOFStavePattern(), sta); } + if (mNumberOfSubStavesIOTOF[lay] > 0) { + path += Form("%s_%d/", GeometryTGeo::getOTOFSubStavePattern(), substa); + } if (mNumberOfModulesIOTOF[lay] > 0) { path += Form("%s_%d/", GeometryTGeo::getOTOFModulePattern(), mod); } @@ -266,6 +292,7 @@ void GeometryTGeo::Build(int loadTrans) // Inner/outer TOF for (int j{0}; j < 2; ++j) { mNumberOfStavesIOTOF[j] = extractNumberOfStavesIOTOF(j); + mNumberOfSubStavesIOTOF[j] = extractNumberOfSubStavesIOTOF(j); mNumberOfModulesIOTOF[j] = extractNumberOfModulesIOTOF(j); mNumberOfChipsPerModuleIOTOF[j] = extractNumberOfChipsPerModuleIOTOF(j); } @@ -278,14 +305,15 @@ void GeometryTGeo::Build(int loadTrans) int numberOfChips{0}; for (int j{0}; j < 2; ++j) { - mNumberOfChipsPerStaveIOTOF[j] = mNumberOfModulesIOTOF[j] * mNumberOfChipsPerModuleIOTOF[j]; + mNumberOfChipsPerStaveIOTOF[j] = mNumberOfSubStavesIOTOF[j] * mNumberOfModulesIOTOF[j] * mNumberOfChipsPerModuleIOTOF[j]; + mNumberOfChipsPerSubStaveIOTOF[j] = mNumberOfModulesIOTOF[j] * mNumberOfChipsPerModuleIOTOF[j]; mNumberOfChipsIOTOF[j] = mNumberOfStavesIOTOF[j] * mNumberOfChipsPerStaveIOTOF[j]; numberOfChips += mNumberOfChipsIOTOF[j]; mLastChipIndex[j] = numberOfChips - 1; } LOG(info) << "TF3 geometry: numberOfChipsITOF = " << mNumberOfChipsIOTOF[0] << ", numberOfChipsOTOF = " - << mNumberOfChipsIOTOF[1] << ", numberOfChips = " << numberOfChips << ", mNumberOfChipesPerStaveITOF" + << mNumberOfChipsIOTOF[1] << ", numberOfChips = " << numberOfChips << ", mNumberOfChipsPerStaveITOF" << mNumberOfChipsPerStaveIOTOF[0]; setSize(numberOfChips); diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/src/IOTOFBaseLinkDef.h b/Detectors/Upgrades/ALICE3/IOTOF/base/src/IOTOFBaseLinkDef.h index e83f4fb51b130..cb5b047e72077 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/src/IOTOFBaseLinkDef.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/src/IOTOFBaseLinkDef.h @@ -19,4 +19,8 @@ #pragma link C++ class o2::iotof::IOTOFBaseParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::iotof::IOTOFBaseParam> + ; +#pragma link C++ class o2::iotof::ChipSpecifics + ; +#pragma link C++ class o2::iotof::ChipSpecificsParam + ; +#pragma link C++ class o2::conf::ConfigurableParamPromoter < o2::iotof::ChipSpecificsParam, o2::iotof::ChipSpecifics> + ; + #endif diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/src/IOTOFBaseParam.cxx b/Detectors/Upgrades/ALICE3/IOTOF/base/src/IOTOFBaseParam.cxx index f6799f41e3786..394bb22749a1d 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/src/IOTOFBaseParam.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/src/IOTOFBaseParam.cxx @@ -12,5 +12,4 @@ #include "IOTOFBase/IOTOFBaseParam.h" O2ParamImpl(o2::iotof::IOTOFBaseParam); -O2ParamImpl(o2::iotof::ITOFChipSpecificParam); -O2ParamImpl(o2::iotof::OTOFChipSpecificParam); +O2ParamImpl(o2::iotof::ChipSpecificsParam); diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h index 4425676b5fdcb..ddde28cf7dd7a 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Segmentation.h @@ -35,16 +35,10 @@ class Segmentation static std::unique_ptr sInstance; public: - ChipSpecifics mITofSpecsConfig; - ChipSpecifics mOTofSpecsConfig; static Segmentation* Instance(); ~Segmentation() = default; - void configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, const float passiveEdgeTop, - const float passiveEdgeSide, const float PixelPassiveEdgeX, const float PixelPassiveEdgeZ, const float sensorLayerThicknessEff, const float sensorLayerThickness, const int subDetectorID); - void configChip(const ChipSpecifics& specsConfig, const int subDetectorID); - /// Transformation from Geant detector centered local coordinates (cm) to /// Pixel cell numbers iRow and iCol. /// Returns kTRUE if point x,z is inside sensitive volume, kFALSE otherwise. @@ -79,7 +73,7 @@ class Segmentation row = col = -1; return; } - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); xRow = getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow; zCol = col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID); } @@ -90,7 +84,7 @@ class Segmentation row = col = -1; return; } - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); loc.SetCoordinates(getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow, T(0.), col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID)); } template @@ -100,7 +94,7 @@ class Segmentation row = col = -1; return; } - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); loc[0] = getFirstRowCoordinate(subDetectorID) - row * specsConfig.PitchRow; loc[1] = T(0); loc[2] = col * specsConfig.PitchCol + getFirstColCoordinate(subDetectorID); @@ -115,7 +109,7 @@ class Segmentation row = col = -1; return false; } - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } @@ -130,7 +124,7 @@ class Segmentation row = col = -1; return false; } - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } @@ -144,7 +138,7 @@ class Segmentation row = col = -1; return false; } - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); if (row < 0 || row >= specsConfig.NRows || col < 0 || col >= specsConfig.NCols) { return false; } @@ -154,17 +148,15 @@ class Segmentation float getFirstRowCoordinate(const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); return 0.5 * ((specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - specsConfig.PitchRow); } float getFirstColCoordinate(const int subDetectorID) { - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); return 0.5 * (specsConfig.PitchCol - specsConfig.ActiveMatrixSizeCols()); } - void print(); - ClassDefNV(Segmentation, 1); // Segmentation class upgrade pixels }; @@ -176,7 +168,7 @@ inline void Segmentation::localToDetectorUnchecked(float xRow, float zCol, int& iRow = iCol = -1; return; } - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix iRow = int(xRow / specsConfig.PitchRow); @@ -202,7 +194,7 @@ inline bool Segmentation::localToDetector(float xRow, float zCol, int& iRow, int iRow = iCol = -1; return false; } - const ChipSpecifics& specsConfig = (subDetectorID == 0) ? mITofSpecsConfig : mOTofSpecsConfig; + const auto& specsConfig = ChipSpecificsParam::Instance(); xRow = 0.5 * (specsConfig.ActiveMatrixSizeRows() - specsConfig.PassiveEdgeTop + specsConfig.PassiveEdgeReadOut) - xRow; // coordinate wrt top edge of Active matrix zCol += 0.5 * specsConfig.ActiveMatrixSizeCols(); // coordinate wrt left edge of Active matrix if (xRow < 0 || xRow >= specsConfig.ActiveMatrixSizeRows() || zCol < 0 || zCol >= specsConfig.ActiveMatrixSizeCols()) { diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx index 26ea7f1ae9812..568d470d13ed5 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx @@ -361,23 +361,28 @@ bool Detector::ProcessHits(FairVolume* vol) TLorentzVector positionStop; fMC->TrackPosition(positionStop); // Retrieve the indices with the volume path - int stave(0), chipinmodule(0), module(0); + int layN = -1; + if (strstr(vol->GetName(), GeometryTGeo::getITOFSensorPattern()) != nullptr) { + layN = 0; + } else if (strstr(vol->GetName(), GeometryTGeo::getOTOFSensorPattern()) != nullptr) { + layN = 1; + } + int stave(0), chipinmodule(0), substave(1), module(0); fMC->CurrentVolOffID(1, chipinmodule); fMC->CurrentVolOffID(2, module); - fMC->CurrentVolOffID(3, stave); + if (layN == 0) { + fMC->CurrentVolOffID(3, stave); + } else if (layN == 1) { + fMC->CurrentVolOffID(3, substave); + fMC->CurrentVolOffID(4, stave); + } int sensorID = lay; auto& iotofPars = IOTOFBaseParam::Instance(); - int layN = -1; - if (strstr(vol->GetName(), GeometryTGeo::getITOFSensorPattern()) != nullptr) { - layN = 0; - } else if (strstr(vol->GetName(), GeometryTGeo::getOTOFSensorPattern())) { - layN = 1; - } if (iotofPars.segmentedInnerTOF && iotofPars.segmentedOuterTOF) { if (layN > -1) { - sensorID = mGeometryTGeo->getIOTOFChipIndex(layN, stave, module, chipinmodule); + sensorID = mGeometryTGeo->getIOTOFChipIndex(layN, stave, substave, module, chipinmodule); } else { sensorID += (mGeometryTGeo->getSize() - 1); // temporary as f/b tof is not yet segmented } diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx index dbcb306911847..5de01639312c4 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Digitizer.cxx @@ -210,8 +210,9 @@ void Digitizer::stepping(const o2::itsmft::Hit& hit, float**& respMatrix, int& r rowStart = std::max(rowStart, 0); colStart = std::max(colStart, 0); - rowEnd = std::min(rowEnd, (subdetectorID == 0 ? sSegmentation->mITofSpecsConfig.NRows : sSegmentation->mOTofSpecsConfig.NRows) - 1); - colEnd = std::min(colEnd, (subdetectorID == 0 ? sSegmentation->mITofSpecsConfig.NCols : sSegmentation->mOTofSpecsConfig.NCols) - 1); + const auto& specsConfig = ChipSpecificsParam::Instance(); + rowEnd = std::min(rowEnd, (specsConfig.NRows) - 1); + colEnd = std::min(colEnd, (specsConfig.NCols) - 1); rowSpan = rowEnd - rowStart + 1; colSpan = colEnd - colStart + 1; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/IOTOFSimulationLinkDef.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/IOTOFSimulationLinkDef.h index 2384d207a03b0..a3cadccfc6d5a 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/IOTOFSimulationLinkDef.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/IOTOFSimulationLinkDef.h @@ -27,12 +27,4 @@ #pragma link C++ class o2::iotof::DPLDigitizerParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::iotof::DPLDigitizerParam> + ; -#pragma link C++ class o2::iotof::ChipSpecifics + ; -#pragma link C++ class o2::iotof::ITOFChipSpecifics + ; -#pragma link C++ class o2::iotof::OTOFChipSpecifics + ; -#pragma link C++ class o2::iotof::ITOFChipSpecificParam + ; -#pragma link C++ class o2::conf::ConfigurableParamPromoter < o2::iotof::ITOFChipSpecificParam, o2::iotof::ITOFChipSpecifics> + ; -#pragma link C++ class o2::iotof::OTOFChipSpecificParam + ; -#pragma link C++ class o2::conf::ConfigurableParamPromoter < o2::iotof::OTOFChipSpecificParam, o2::iotof::OTOFChipSpecifics> + ; - #endif diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx index f63c93d37ce75..6db336aba2533 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx @@ -165,10 +165,22 @@ void ITOFLayer::createLayer(TGeoVolume* motherVolume) const double staveSizeX = mStaves.second; // cm const double staveSizeY = mOuterRadius - mInnerRadius; // cm const double staveSizeZ = mZLength; // cm - const double deltaForTilt = 0.5 * (std::sin(TMath::DegToRad() * mTiltAngle) * staveSizeX + std::cos(TMath::DegToRad() * mTiltAngle) * staveSizeY); // we increase the size of the layer to account for the tilt of the staves - const double radiusMax = std::sqrt(avgRadius * avgRadius + 0.25 * staveSizeX * staveSizeX + 0.25 * staveSizeY * staveSizeY + avgRadius * 2. * deltaForTilt); // we increase the outer radius to account for the tilt of the staves - const double radiusMin = std::sqrt(avgRadius * avgRadius + 0.25 * staveSizeX * staveSizeX + 0.25 * staveSizeY * staveSizeY - avgRadius * 2. * deltaForTilt); // we decrease the inner radius to account for the tilt of the staves - TGeoTube* layer = new TGeoTube(radiusMin - 0.05, radiusMax + 0.05, mZLength / 2); // cm, small margins to ensure staves are fully encapsulated in the layer volume + + // Build the mother layer tube from the exact inscribed/outscribed radii of a tilted stave rectangle. + const double alpha = mTiltAngle * TMath::DegToRad(); + const double u0 = -avgRadius * std::cos(alpha); + const double v0 = avgRadius * std::sin(alpha); + const double uClamped = std::max(-0.5 * staveSizeY, std::min(0.5 * staveSizeY, u0)); + const double vClamped = std::max(-0.5 * staveSizeX, std::min(0.5 * staveSizeX, v0)); + const double radiusMin = std::hypot(uClamped - u0, vClamped - v0); + + const double uCorners[4] = {-0.5 * staveSizeY, 0.5 * staveSizeY, 0.5 * staveSizeY, -0.5 * staveSizeY}; + const double vCorners[4] = {-0.5 * staveSizeX, -0.5 * staveSizeX, 0.5 * staveSizeX, 0.5 * staveSizeX}; + double radiusMax = 0.0; + for (int i = 0; i < 4; ++i) { + radiusMax = std::max(radiusMax, std::hypot(uCorners[i] - u0, vCorners[i] - v0)); + } + TGeoTube* layer = new TGeoTube(radiusMin, radiusMax, mZLength / 2); // cm, small margins to ensure staves are fully encapsulated in the layer volume TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); setLayerStyle(layerVol); @@ -212,7 +224,7 @@ void ITOFLayer::createLayer(TGeoVolume* motherVolume) for (int j = 0; j < sensorsPerChipZ; ++j) { LOGP(info, "iTOF: Creating sensor {}/{} for chip {}/{}", i + 1, sensorsPerChipX, j + 1, sensorsPerChipZ); auto* translation = new TGeoTranslation((i + 0.5) * sensorSizeX - 0.5 * chipSizeX, - 0, + 0.5 * chipSizeY - 0.5 * sensorSizeY, (j + 0.5) * sensorSizeZ - 0.5 * chipSizeZ); chipVol->AddNode(sensVol, 1 + i * sensorsPerChipZ + j, translation); } @@ -263,6 +275,7 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume) const char* chipName = o2::iotof::GeometryTGeo::getOTOFChipPattern(); const char* sensName = o2::iotof::GeometryTGeo::getOTOFSensorPattern(); const char* moduleName = o2::iotof::GeometryTGeo::getOTOFModulePattern(); + const char* subStaveName = o2::iotof::GeometryTGeo::getOTOFSubStavePattern(); const char* staveName = o2::iotof::GeometryTGeo::getOTOFStavePattern(); TGeoMedium* medSi = gGeoManager->GetMedium("TF3_SILICON$"); @@ -294,11 +307,18 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume) return; } case kBarrelSegmented: { + // Additional geometry parameters + const double subStavesDistanceY = 0.3; // cm + const double subStavesOverlapX = 1.1; // cm + // First we create the volume for the whole layer, which will be used as mother volume for the segments const double avgRadius = 0.5 * (mInnerRadius + mOuterRadius); - const double staveSizeX = mStaves.second; // cm, tangential stave size - const double staveSizeY = mOuterRadius - mInnerRadius; // cm, radial stave size - const double staveSizeZ = mZLength; // cm + const double staveSizeX = mStaves.second; // cm, tangential stave size + const double staveSizeY = mOuterRadius - mInnerRadius + subStavesDistanceY; // cm, radial stave size + const double staveSizeZ = mZLength; // cm + const double subStaveSizeX = 0.5 * mStaves.second + 0.5 * subStavesOverlapX; // cm, tangential substave size + const double subStaveSizeY = mOuterRadius - mInnerRadius; // cm, radial substave size + const double subStaveSizeZ = mZLength; // cm // Build the mother layer tube from the exact inscribed/outscribed radii of a tilted stave rectangle. const double alpha = mTiltAngle * TMath::DegToRad(); @@ -323,17 +343,23 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume) TGeoVolume* staveVol = new TGeoVolume(staveName, stave, medAir); setStaveStyle(staveVol); + // Now we create the volume for a single stave + TGeoBBox* subStave = new TGeoBBox(subStaveSizeX * 0.5, subStaveSizeY * 0.5, subStaveSizeZ * 0.5); + TGeoVolume* subStaveVol = new TGeoVolume(subStaveName, subStave, medAir); + setStaveStyle(subStaveVol); + // Now we create the volume for a single module (sensor + chip) // oTOF V2 is a 2xN matrix. - const int modulesPerStaveX = 2; - if (mModulesPerStave % modulesPerStaveX != 0) { - LOG(fatal) << "Invalid oTOF module layout: total modules per stave " << mModulesPerStave - << " is not divisible by modulesPerStaveX=" << modulesPerStaveX; + const int modulesPerSubStave = mModulesPerStave; + const int modulesPerSubStaveX = 1; + if (modulesPerSubStave % modulesPerSubStaveX != 0) { + LOG(fatal) << "Invalid oTOF module layout: total modules per stave " << modulesPerSubStave + << " is not divisible by modulesPerStaveX=" << modulesPerSubStaveX; } - const int modulesPerStaveZ = 2 * mModulesPerStave / modulesPerStaveX; - const double moduleSizeX = staveSizeX / modulesPerStaveX; - const double moduleSizeY = staveSizeY; - const double moduleSizeZ = staveSizeZ / modulesPerStaveZ; + const int modulesPerSubStaveZ = modulesPerSubStave / modulesPerSubStaveX; + const double moduleSizeX = subStaveSizeX / modulesPerSubStaveX; + const double moduleSizeY = subStaveSizeY; + const double moduleSizeZ = subStaveSizeZ / modulesPerSubStaveZ; TGeoBBox* module = new TGeoBBox(moduleSizeX * 0.5, moduleSizeY * 0.5, moduleSizeZ * 0.5); TGeoVolume* moduleVol = new TGeoVolume(moduleName, module, medAir); setModuleStyle(moduleVol); @@ -364,7 +390,7 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume) for (int j = 0; j < sensorsPerChipZ; ++j) { LOGP(info, "oTOF: Creating sensor {}/{} for chip {}/{}", i + 1, sensorsPerChipX, j + 1, sensorsPerChipZ); auto* translation = new TGeoTranslation((i + 0.5) * sensorSizeX - 0.5 * chipSizeX, - 0, + 0.5 * chipSizeY - 0.5 * sensorSizeY, (j + 0.5) * sensorSizeZ - 0.5 * chipSizeZ); chipVol->AddNode(sensVol, 1 + i * sensorsPerChipZ + j, translation); } @@ -379,17 +405,25 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume) } } - // Now we build a stave from modules - for (int i = 0; i < modulesPerStaveX; ++i) { - for (int j = 0; j < modulesPerStaveZ; ++j) { - LOGP(info, "oTOF: Creating module {}/{} for stave {}/{}", i + 1, modulesPerStaveX, j + 1, modulesPerStaveZ); - const double tx = (i + 0.5) * moduleSizeX - 0.5 * staveSizeX; - const double tz = -0.5 * staveSizeZ + (j + 0.5) * moduleSizeZ; + // Now we build a sub-stave from modules + for (int i = 0; i < modulesPerSubStaveX; ++i) { + for (int j = 0; j < modulesPerSubStaveZ; ++j) { + LOGP(info, "oTOF: Creating module {}/{} for substave {}/{}", i + 1, modulesPerSubStaveX, j + 1, modulesPerSubStaveZ); + const double tx = (i + 0.5) * moduleSizeX - 0.5 * subStaveSizeX; + const double tz = -0.5 * subStaveSizeZ + (j + 0.5) * moduleSizeZ; auto* translation = new TGeoTranslation(tx, 0, tz); - staveVol->AddNode(moduleVol, 1 + i * modulesPerStaveZ + j, translation); + subStaveVol->AddNode(moduleVol, 1 + i * modulesPerSubStaveZ + j, translation); } } + // Now we build a stave from two substave + for (int i = 0; i < 2; ++i) { + LOGP(info, "oTOF: Creating substave {}/{} for stave {}/{}", i + 1, 2, 1, 1); + int sign = i > 0 ? 1 : -1; + auto* translation2 = new TGeoTranslation(sign * 0.5 * (subStaveSizeX)-sign * 0.5 * subStavesOverlapX, sign * 0.5 * subStavesDistanceY, 0); + staveVol->AddNode(subStaveVol, i + 1, translation2); + } + // We finally put all the staves in the layer for (int i = 0; i < mStaves.first; ++i) { LOGP(info, "oTOF: Creating stave {}/{} for layer {}", i + 1, mStaves.first, layerVol->GetName()); diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx index 6e4624294a60e..a7ec0d708c3b8 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Segmentation.cxx @@ -36,55 +36,9 @@ Segmentation::Segmentation() { if (sInstance) { printf("Invalid use of public constructor: o2::iotof::Segmentation instance exists\n"); - } else { - auto& itofPars = ITOFChipSpecificParam::Instance(); - auto& otofPars = OTOFChipSpecificParam::Instance(); - const ChipSpecifics mITofChipPars(itofPars.NCols, itofPars.NRows, itofPars.PitchCol, itofPars.PitchRow, itofPars.PassiveEdgeReadOut, itofPars.PassiveEdgeTop, itofPars.PassiveEdgeSide, itofPars.PixelPassiveEdgeX, itofPars.PixelPassiveEdgeZ, itofPars.SensorLayerThicknessEff, itofPars.SensorLayerThickness); - const ChipSpecifics mOTofChipPars(otofPars.NCols, otofPars.NRows, otofPars.PitchCol, otofPars.PitchRow, otofPars.PassiveEdgeReadOut, otofPars.PassiveEdgeTop, otofPars.PassiveEdgeSide, otofPars.PixelPassiveEdgeX, otofPars.PixelPassiveEdgeZ, otofPars.SensorLayerThicknessEff, otofPars.SensorLayerThickness); - - configChip(mITofChipPars, 0 /* subDetectorID for iTOF */); - configChip(mOTofChipPars, 1 /* subDetectorID for oTOF */); } } -void Segmentation::configChip(const int nCols, const int nRows, const float pitchCol, const float pitchRow, const float passiveEdgeReadOut, - const float passiveEdgeTop, const float passiveEdgeSide, const float pixelPassiveEdgeX, const float pixelPassiveEdgeZ, const float sensorLayerThicknessEff, const float sensorLayerThickness, const int subDetectorID) -{ - if (subDetectorID == 0) { - mITofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, pixelPassiveEdgeX, pixelPassiveEdgeZ, sensorLayerThicknessEff, sensorLayerThickness); - } else if (subDetectorID == 1) { - mOTofSpecsConfig = ChipSpecifics(nCols, nRows, pitchCol, pitchRow, passiveEdgeReadOut, passiveEdgeTop, passiveEdgeSide, pixelPassiveEdgeX, pixelPassiveEdgeZ, sensorLayerThicknessEff, sensorLayerThickness); - } else { - printf("Invalid subDetectorID %d. Must be 0 (iTOF) or 1 (oTOF). No configuration applied.\n", subDetectorID); - } -} - -void Segmentation::configChip(const ChipSpecifics& specsConfig, const int subDetectorID) -{ - if (subDetectorID == 0) { - mITofSpecsConfig = specsConfig; - } else if (subDetectorID == 1) { - mOTofSpecsConfig = specsConfig; - } else { - printf("Invalid subDetectorID %d. Must be 0 (iTOF) or 1 (oTOF). No configuration applied.\n", subDetectorID); - } -} - -void Segmentation::print() -{ - // iTOF specs - printf("iTOF specs:\n"); - printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", mITofSpecsConfig.PitchRow * 1e4, mITofSpecsConfig.NRows, mITofSpecsConfig.PitchCol * 1e4, mITofSpecsConfig.NCols); - printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", mITofSpecsConfig.PassiveEdgeReadOut * 1e4, mITofSpecsConfig.PassiveEdgeTop * 1e4, mITofSpecsConfig.PassiveEdgeSide * 1e4); - printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", mITofSpecsConfig.ActiveMatrixSizeRows(), mITofSpecsConfig.SensorSizeRows(), mITofSpecsConfig.ActiveMatrixSizeCols(), mITofSpecsConfig.SensorSizeCols()); - - // oTOF specs - printf("oTOF specs:\n"); - printf("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns\n", mOTofSpecsConfig.PitchRow * 1e4, mOTofSpecsConfig.NRows, mOTofSpecsConfig.PitchCol * 1e4, mOTofSpecsConfig.NCols); - printf("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns\n", mOTofSpecsConfig.PassiveEdgeReadOut * 1e4, mOTofSpecsConfig.PassiveEdgeTop * 1e4, mOTofSpecsConfig.PassiveEdgeSide * 1e4); - printf("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm\n", mOTofSpecsConfig.ActiveMatrixSizeRows(), mOTofSpecsConfig.SensorSizeRows(), mOTofSpecsConfig.ActiveMatrixSizeCols(), mOTofSpecsConfig.SensorSizeCols()); -} - } // namespace iotof } // namespace o2