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/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/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index 7b3d33ca1a75c..1a81723a18f63 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 == eMLOTLayout::kCylindrical)) { stave = 1; mod = 1; chip = 1; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h index 32bdc89109269..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 @@ -66,8 +67,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"); @@ -88,8 +88,8 @@ 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 mLayers; + std::vector* mHits; // Derived from ITSMFT + 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/TRKLayer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h index 39dd7752cc010..6077d9e5f9839 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/TRKLayer.h @@ -22,57 +22,113 @@ namespace o2 { namespace trk { -class TRKLayer +enum class MatBudgetParamMode { + Thickness, + X2X0 +}; + +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 thickOrX2X0, MatBudgetParamMode mode); + 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 thickOrX2X0, MatBudgetParamMode mode); + ~TRKSegmentedLayer() override = default; + + TGeoVolume* createSensor() override; + TGeoVolume* createDeadzone(); + TGeoVolume* createMetalStack() override; + TGeoVolume* createChip(); + TGeoVolume* createModule(); + virtual TGeoVolume* createStave() = 0; + void createLayer(TGeoVolume* motherVolume) override = 0; + + protected: + 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; + + ClassDefOverride(TRKSegmentedLayer, 0); +}; + +class TRKMLLayer : public TRKSegmentedLayer +{ + public: + TRKMLLayer() = default; + TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode); + ~TRKMLLayer() override = default; + + TGeoVolume* createStave() override; + void createLayer(TGeoVolume* motherVolume) override; + + private: + static constexpr double sStaveWidth = constants::ML::width; + + ClassDefOverride(TRKMLLayer, 0); +}; + +class TRKOTLayer : public TRKSegmentedLayer +{ + public: + TRKOTLayer() = default; + TRKOTLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode); + ~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; + + 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 2ad1d52ba73c4..8e13d31e7915c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -54,17 +54,24 @@ Detector::Detector(bool active) if (trkPars.configFile != "") { configFromFile(trkPars.configFile); } else { - buildTRKMiddleOuterLayers(); + 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()); + 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) { @@ -78,78 +85,42 @@ 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, MatBudgetParamMode::Thickness)); + } 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, MatBudgetParamMode::Thickness)); + } else { + mLayers.push_back(std::make_unique(i, name, rInn[i], nMods[i], thick, MatBudgetParamMode::Thickness)); + } + } 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 +131,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 +151,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], 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], MatBudgetParamMode::Thickness)); + } else { + mLayers.push_back(std::make_unique(layerCount, name, tmpBuff[0], nMods, tmpBuff[2], MatBudgetParamMode::Thickness)); + } + break; + } + default: + LOGP(fatal, "Unknown option {} for configMLOT", static_cast(trkPars.layoutMLOT)); + break; + } + ++layerCount; } } @@ -188,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; } } @@ -254,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 b5bde06d09484..39c7b3598d19b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -25,400 +25,308 @@ 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 thickOrX2X0, MatBudgetParamMode mode) + : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mLength(length) { - mChipThickness = mX2X0 * Si_X0; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, getZ(), 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; + } -TRKLayer::TRKLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thick) - : mLayerNumber(layerNumber), mLayerName(layerName), mInnerRadius(rInn), mNumberOfModules(numberOfModules), mChipThickness(thick) -{ - mOuterRadius = rInn + thick; - mX2X0 = mChipThickness / Si_X0; - LOGP(info, "Creating layer: id: {} rInner: {} rOuter: {} zLength: {} x2X0: {}", mLayerNumber, mInnerRadius, mOuterRadius, getZ(), mX2X0); + 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 = new TGeoTube(mInnerRadius + sSensorThickness, mInnerRadius + mChipThickness, 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 + mChipThickness, mLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kYellow); + + TGeoVolume* sensVol = createSensor(); + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), layerVol->GetName()); + layerVol->AddNode(sensVol, 1, nullptr); + + TGeoVolume* metalVol = createMetalStack(); + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), layerVol->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 thickOrX2X0, MatBudgetParamMode mode) + : TRKCylindricalLayer(layerNumber, layerName, rInn, numberOfModules * sModuleLength, thickOrX2X0, mode), mNumberOfModules(numberOfModules) +{ +} + +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, (mChipThickness - 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; - 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); - } - + 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, -(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); + 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); + 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, mChipThickness / 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 < 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; + 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); - - return halfStaveVol; +TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thickOrX2X0, mode) +{ } -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, mChipThickness / 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; - - stave = new TGeoBBox(staveWidth / 2, mChipThickness / 2, staveLength / 2); - staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); + staveVol->AddNode(moduleVol, iModule, trans); + } - for (int iModule = 0; iModule < mNumberOfModules; iModule++) { - TGeoVolume* moduleVol = createModule("flat"); + return staveVol; +} - // Put the modules in the correct position - double zPos = -0.5 * mNumberOfModules * moduleLength + (iModule + 0.5) * moduleLength; +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); - TGeoCombiTrans* trans = new TGeoCombiTrans(); - trans->SetTranslation(0, 0, zPos); // TO BE CHECKED !!! + // 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); + 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 {} ", 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; + LOGP(debug, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); + motherVolume->AddNode(layerVol, 1, nullptr); +} - staveVol = new TGeoVolumeAssembly(staveName.c_str()); +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // 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 thickOrX2X0, MatBudgetParamMode mode) + : TRKSegmentedLayer(layerNumber, layerName, rInn, numberOfModules, thickOrX2X0, mode) +{ +} - 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, mChipThickness / 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(); + 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 - sInStaveOverlap) / 2, 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); + 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/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 + ;