diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h index 177426e8dba09..577bd1bcabaf1 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/GeometryTGeo.h @@ -32,11 +32,15 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache // Inner TOF static const char* getITOFLayerPattern() { return sITOFLayerName.c_str(); } + static const char* getITOFStavePattern() { return sITOFStaveName.c_str(); } + static const char* getITOFModulePattern() { return sITOFModuleName.c_str(); } static const char* getITOFChipPattern() { return sITOFChipName.c_str(); } static const char* getITOFSensorPattern() { return sITOFSensorName.c_str(); } // Outer TOF static const char* getOTOFLayerPattern() { return sOTOFLayerName.c_str(); } + static const char* getOTOFStavePattern() { return sOTOFStaveName.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(); } @@ -81,11 +85,15 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache // Inner TOF static std::string sITOFLayerName; + static std::string sITOFStaveName; + static std::string sITOFModuleName; static std::string sITOFChipName; static std::string sITOFSensorName; // Outer TOF static std::string sOTOFLayerName; + static std::string sOTOFStaveName; + static std::string sOTOFModuleName; static std::string sOTOFChipName; static std::string sOTOFSensorName; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx index 8c29127a5e7d6..f7d0eb135a27a 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx @@ -23,11 +23,15 @@ std::string GeometryTGeo::sIOTOFVolumeName = "IOTOFV"; // Inner TOF std::string GeometryTGeo::sITOFLayerName = "ITOFLayer"; +std::string GeometryTGeo::sITOFStaveName = "ITOFStave"; +std::string GeometryTGeo::sITOFModuleName = "ITOFModule"; std::string GeometryTGeo::sITOFChipName = "ITOFChip"; std::string GeometryTGeo::sITOFSensorName = "ITOFSensor"; // Outer TOF std::string GeometryTGeo::sOTOFLayerName = "OTOFLayer"; +std::string GeometryTGeo::sOTOFStaveName = "OTOFStave"; +std::string GeometryTGeo::sOTOFModuleName = "OTOFModule"; std::string GeometryTGeo::sOTOFChipName = "OTOFChip"; std::string GeometryTGeo::sOTOFSensorName = "OTOFSensor"; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h index df3687b2b2ea4..29542810b8021 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h @@ -26,7 +26,7 @@ class Layer public: Layer() = default; Layer(std::string layerName, float rInn, float rOut, float zLength, float zOffset, float layerX2X0, - int layout = kBarrel, int nSegments = 0, float segmentSize = 0.0, int nSensorsPerSegment = 0, double tiltAngle = 0.0); + int layout = kBarrel, int nStaves = 0, float staveSize = 0.0, double staveTiltAngle = 0.0, int modulesPerStave = 0); ~Layer() = default; auto getInnerRadius() const { return mInnerRadius; } @@ -37,7 +37,7 @@ class Layer auto getChipThickness() const { return mChipThickness; } auto getName() const { return mLayerName; } auto getLayout() const { return mLayout; } - auto getSegments() const { return mSegments; } + auto getSegments() const { return mStaves; } static constexpr int kBarrel = 0; static constexpr int kDisk = 1; static constexpr int kBarrelSegmented = 2; @@ -54,10 +54,10 @@ class Layer float mX2X0; float mChipThickness; int mLayout{kBarrel}; // Identifier of the type of layer layout (barrel, disk, barrel segmented, disk segmented) - // To be used only in case of the segmented layout, to define the number of segments in phi (for barrel) or in r (for disk) - std::pair mSegments{0, 0.0f}; // Number and size of segments in phi (for barrel) or in r (for disk) in case of segmented layout - int mSensorsPerSegment{0}; // Number of sensors along a segment - double mTiltAngle{0.0}; // Tilt angle in degrees to be applied as a rotation around the local center of the segment + // To be used only in case of the segmented layout, to define the number of staves in phi (for barrel) or in r (for disk) + std::pair mStaves{0, 0.0f}; // Number and size of staves in phi (for barrel) or in r (for disk) in case of segmented layout + int mModulesPerStave{0}; // Number of modules along a stave + double mTiltAngle{0.0}; // Tilt angle in degrees to be applied as a rotation around the local center of the stave }; class ITOFLayer : public Layer diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx index 0742af3a1340a..c056df5fd34ca 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx @@ -98,14 +98,14 @@ void Detector::configLayers(bool itof, bool otof, bool ftof, bool btof, std::str if (itof) { // iTOF mITOFLayer = itofSegmented ? ITOFLayer(std::string{GeometryTGeo::getITOFLayerPattern()}, radiusInnerTof, 0.f, lengthInnerTof, 0.f, 0.02f, ITOFLayer::kBarrelSegmented, - 24, 5.42, 80, 10) + 24, 5.42, 10.0, 10) : ITOFLayer(std::string{GeometryTGeo::getITOFLayerPattern()}, radiusInnerTof, 0.f, lengthInnerTof, 0.f, 0.02f, ITOFLayer::kBarrel); } if (otof) { // oTOF mOTOFLayer = otofSegmented ? OTOFLayer(std::string{GeometryTGeo::getOTOFLayerPattern()}, radiusOuterTof, 0.f, lengthOuterTof, 0.f, 0.02f, OTOFLayer::kBarrelSegmented, - 62, 9.74, 432, 5) + 62, 9.74, 5.0, 54) : OTOFLayer(std::string{GeometryTGeo::getOTOFLayerPattern()}, radiusOuterTof, 0.f, lengthOuterTof, 0.f, 0.02f, OTOFLayer::kBarrel); } diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx index 169a1271da47e..32a24fc46f94c 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx @@ -27,7 +27,8 @@ namespace o2 { namespace iotof { -Layer::Layer(std::string layerName, float rInn, float rOut, float zLength, float zOffset, float layerX2X0, int layout, int nSegments, float segmentSize, int nSensorsPerSegment, double tiltAngle) +Layer::Layer(std::string layerName, float rInn, float rOut, float zLength, float zOffset, float layerX2X0, + int layout, int nStaves, float staveSize, double staveTiltAngle, int modulesPerStave) : mLayerName(layerName), mInnerRadius(rInn), mOuterRadius(rOut), @@ -35,9 +36,9 @@ Layer::Layer(std::string layerName, float rInn, float rOut, float zLength, float mZOffset(zOffset), mX2X0(layerX2X0), mLayout(layout), - mSegments(nSegments, segmentSize), - mSensorsPerSegment(nSensorsPerSegment), - mTiltAngle(tiltAngle) + mStaves(nStaves, staveSize), + mModulesPerStave(modulesPerStave), + mTiltAngle(staveTiltAngle) { float Si_X0 = 9.5f; mChipThickness = mX2X0 * Si_X0; @@ -56,32 +57,72 @@ Layer::Layer(std::string layerName, float rInn, float rOut, float zLength, float default: LOG(fatal) << "Invalid layout " << layout; } - if (1) { // Sanity checks - if (mInnerRadius > mOuterRadius) { - LOG(fatal) << "Invalid layer dimensions: rInner " << mInnerRadius << " cm is larger than rOuter " << mOuterRadius << " cm"; - } - if ((mSegments.first != 0 || mSegments.second != 0.0f) && (layout != kBarrelSegmented && layout != kDiskSegmented)) { - LOG(fatal) << "Invalid configuration: number of segments " << mSegments.first << " is set for non-segmented layout " << layout; - } - if ((mSegments.first <= 1 || mSegments.second <= 0.0f) && (layout == kBarrelSegmented || layout == kDiskSegmented)) { - LOG(fatal) << "Invalid configuration: number of segments " << mSegments.first << " must be positive for segmented layout " << layout; - } - if (mSensorsPerSegment <= 0 && (layout == kBarrelSegmented || layout == kDiskSegmented)) { - LOG(fatal) << "Invalid configuration: number of sensors per segment " << mSensorsPerSegment << " must be positive for segmented layout " << layout; - } - if (std::abs(mTiltAngle) > 0.1 && (layout != kBarrelSegmented && layout != kDiskSegmented)) { - LOG(fatal) << "Invalid configuration: tilt angle " << mTiltAngle << " is set for non-segmented layout " << layout; - } + // Sanity checks + if (mInnerRadius > mOuterRadius) { + LOG(fatal) << "Invalid layer dimensions: rInner " << mInnerRadius << " cm is larger than rOuter " << mOuterRadius << " cm"; + } + if ((mStaves.first != 0 || mStaves.second != 0.0f) && (layout != kBarrelSegmented && layout != kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: number of segments " << mStaves.first << " is set for non-segmented layout " << layout; + } + if ((mStaves.first <= 1 || mStaves.second <= 0.0f) && (layout == kBarrelSegmented || layout == kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: number of segments " << mStaves.first << " must be positive for segmented layout " << layout; + } + if (mModulesPerStave <= 0 && (layout == kBarrelSegmented || layout == kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: number of sensors per segment " << mModulesPerStave << " must be positive for segmented layout " << layout; + } + if (std::abs(mTiltAngle) > 0.1 && (layout != kBarrelSegmented && layout != kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: tilt angle " << mTiltAngle << " is set for non-segmented layout " << layout; + } + if ((mTiltAngle < 0.0 || mTiltAngle > 90.0) && (layout == kBarrelSegmented || layout == kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: tilt angle " << mTiltAngle << " is too large, it must be between 0 and 90 degrees"; } LOGP(info, "TOF: Creating {} layer: rInner: {} (cm) rOuter: {} (cm) zLength: {} (cm) zOffset: {} x2X0: {}", name.c_str(), mInnerRadius, mOuterRadius, mZLength, mZOffset, mX2X0); } +void setLayerStyle(TGeoVolume* obj) +{ + obj->SetLineColor(kRed - 7); + obj->SetFillColor(kRed - 7); + obj->SetLineWidth(1); + obj->SetTransparency(70); +} +void setStaveStyle(TGeoVolume* obj) +{ + obj->SetLineColor(kRed - 5); + obj->SetFillColor(kRed - 9); + obj->SetLineWidth(2); + obj->SetTransparency(45); +} +void setModuleStyle(TGeoVolume* obj) +{ + obj->SetLineColor(kRed - 3); + obj->SetFillColor(kRed - 8); + obj->SetLineWidth(2); + obj->SetTransparency(35); +} +void setChipStyle(TGeoVolume* obj) +{ + obj->SetLineColor(kOrange); + obj->SetFillColor(kOrange - 9); + obj->SetLineWidth(3); + obj->SetTransparency(15); +} +void setSensorStyle(TGeoVolume* obj) +{ + obj->SetLineColor(kRed); + obj->SetFillColor(kRed - 9); + obj->SetLineWidth(3); + obj->SetTransparency(5); +} + std::vector ITOFLayer::mRegister; void ITOFLayer::createLayer(TGeoVolume* motherVolume) { - const std::string chipName = o2::iotof::GeometryTGeo::getITOFChipPattern(); - const std::string sensName = o2::iotof::GeometryTGeo::getITOFSensorPattern(); + const char* chipName = o2::iotof::GeometryTGeo::getITOFChipPattern(); + const char* sensName = o2::iotof::GeometryTGeo::getITOFSensorPattern(); + const char* moduleName = o2::iotof::GeometryTGeo::getITOFModulePattern(); + const char* staveName = o2::iotof::GeometryTGeo::getITOFStavePattern(); TGeoMedium* medSi = gGeoManager->GetMedium("TF3_SILICON$"); TGeoMedium* medAir = gGeoManager->GetMedium("TF3_AIR$"); @@ -93,12 +134,12 @@ void ITOFLayer::createLayer(TGeoVolume* motherVolume) TGeoTube* chip = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); - TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); - TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); + TGeoVolume* sensVol = new TGeoVolume(sensName, sensor, medSi); + TGeoVolume* chipVol = new TGeoVolume(chipName, chip, medSi); TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - sensVol->SetLineColor(kRed + 3); - chipVol->SetLineColor(kRed + 3); - layerVol->SetLineColor(kRed + 3); + setSensorStyle(sensVol); + setChipStyle(chipVol); + setLayerStyle(layerVol); LOGP(info, "Inserting Barrel {} in {} ", sensVol->GetName(), chipVol->GetName()); ITOFLayer::mRegister.push_back(sensVol->GetName()); @@ -112,40 +153,91 @@ void ITOFLayer::createLayer(TGeoVolume* motherVolume) return; } case kBarrelSegmented: { - const double circumference = TMath::TwoPi() * 0.5 * (mInnerRadius + mOuterRadius); - const double segmentSize = mSegments.second; // cm circumference / mSegments; + // 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); - TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + 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 + TGeoTube* layer = new TGeoTube(mInnerRadius - deltaForTilt, mOuterRadius + deltaForTilt, mZLength / 2); TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - layerVol->SetLineColor(kRed + 3); - - for (int i = 0; i < mSegments.first; ++i) { - LOGP(info, "iTOF: Creating segment {}/{} with size {} and thickness {}cm", i + 1, mSegments.first, segmentSize, (mOuterRadius - mInnerRadius)); - const double hx = 0.5 * segmentSize; - const double hy = 0.5 * (mOuterRadius - mInnerRadius); - const double hz = 0.5 * mZLength; - TGeoBBox* sensor = new TGeoBBox(hy, hx, hz); - TGeoBBox* chip = new TGeoBBox(hy, hx, hz); - const std::string segmentTag = Form("segment%d", i + 1); - TGeoVolume* sensVol = new TGeoVolume(Form("%s_%s", sensName.c_str(), segmentTag.c_str()), sensor, medSi); - TGeoVolume* chipVol = new TGeoVolume(Form("%s_%s", chipName.c_str(), segmentTag.c_str()), chip, medSi); - sensVol->SetLineColor(kRed + 3); - chipVol->SetLineColor(kRed + 3); - - LOGP(info, " Inserting Barrel {} in {} ", sensVol->GetName(), chipVol->GetName()); - ITOFLayer::mRegister.push_back(sensVol->GetName()); - chipVol->AddNode(sensVol, 1, nullptr); - - const double phi = TMath::TwoPi() * i / mSegments.first; - - LOG(info) << " Tilting angle for segment " << i + 1 << ": " << phi * TMath::RadToDeg() << " degrees"; + setLayerStyle(layerVol); + + // Now we create the volume for a single stave + TGeoBBox* stave = new TGeoBBox(staveSizeX * 0.5, staveSizeY * 0.5, staveSizeZ * 0.5); + TGeoVolume* staveVol = new TGeoVolume(staveName, stave, medAir); + setStaveStyle(staveVol); + + // Now we create the volume for a single module (sensor + chip) + const int modulesPerStaveX = 1; // we assume that each stave is divided in 2 modules along the x direction + const double moduleSizeX = staveSizeX / modulesPerStaveX; // cm + const double moduleSizeY = staveSizeY; // cm + const double moduleSizeZ = staveSizeZ / mModulesPerStave; // cm + TGeoBBox* module = new TGeoBBox(moduleSizeX * 0.5, moduleSizeY * 0.5, moduleSizeZ * 0.5); + TGeoVolume* moduleVol = new TGeoVolume(moduleName, module, medAir); + setModuleStyle(moduleVol); + + // Now we create the volume of the chip, which is the same for all modules + const int chipsPerModuleX = 2; // we assume that each module is divided in 2 chips along the x direction + const int chipsPerModuleZ = 2; // we assume that each module is divided in 2 chips along the z direction + const double chipSizeX = moduleSizeX / chipsPerModuleX; // cm + const double chipSizeY = moduleSizeY; // cm + const double chipSizeZ = moduleSizeZ / chipsPerModuleZ; // cm + TGeoBBox* chip = new TGeoBBox(chipSizeX * 0.5, chipSizeY * 0.5, chipSizeZ * 0.5); + TGeoVolume* chipVol = new TGeoVolume(chipName, chip, medSi); + setChipStyle(chipVol); + + // Finally we create the volume of the sensor, which is the same for all chips + const int sensorsPerChipX = 2; // we assume that each chip is divided in 2 sensors along the x direction + const int sensorsPerChipZ = 2; // we assume that each chip is divided in 2 sensors along the z direction + const double sensorSizeX = chipSizeX / sensorsPerChipX; // cm + const double sensorSizeY = chipSizeY; // cm + const double sensorSizeZ = chipSizeZ / sensorsPerChipZ; // cm + TGeoBBox* sensor = new TGeoBBox(sensorSizeX * 0.5, sensorSizeY * 0.5, sensorSizeZ * 0.5); + TGeoVolume* sensVol = new TGeoVolume(sensName, sensor, medSi); + setSensorStyle(sensVol); + ITOFLayer::mRegister.push_back(sensVol->GetName()); + + // Now we build a chip from sensors + for (int i = 0; i < sensorsPerChipX; ++i) { + 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, + (j + 0.5) * sensorSizeZ - 0.5 * chipSizeZ); + chipVol->AddNode(sensVol, 1 + i * sensorsPerChipZ + j, translation); + } + } + + // Now we build a module from chips + for (int i = 0; i < chipsPerModuleX; ++i) { + for (int j = 0; j < chipsPerModuleZ; ++j) { + LOGP(info, "iTOF: Creating chip {}/{} for module {}/{}", i + 1, chipsPerModuleX, j + 1, chipsPerModuleZ); + auto* translation = new TGeoTranslation((i + 0.5) * chipSizeX - 0.5 * moduleSizeX, 0, (j + 0.5) * chipSizeZ - 0.5 * moduleSizeZ); + moduleVol->AddNode(chipVol, 1 + i * chipsPerModuleZ + j, translation); + } + } + + // Now we build a stave from modules + for (int i = 0; i < modulesPerStaveX; ++i) { + for (int j = 0; j < mModulesPerStave; ++j) { + LOGP(info, "iTOF: Creating module {}/{} for stave {}/{}", i + 1, modulesPerStaveX, j + 1, mModulesPerStave); + auto* translation = new TGeoTranslation((i + 0.5) * moduleSizeX - 0.5 * staveSizeX, 0, (j + 0.5) * moduleSizeZ - 0.5 * staveSizeZ); + staveVol->AddNode(moduleVol, 1 + i * mModulesPerStave + j, translation); + } + } + + // We finally put all the staves in the layer + for (int i = 0; i < mStaves.first; ++i) { + LOGP(info, "iTOF: Creating stave {}/{} for layer {}", i + 1, mStaves.first, layerVol->GetName()); + const double phi = TMath::TwoPi() * i / mStaves.first; const double x = avgRadius * TMath::Cos(phi); const double y = avgRadius * TMath::Sin(phi); - auto* rotation = new TGeoRotation(Form("segmentRot%d", i + 1), phi * TMath::RadToDeg() + mTiltAngle, 0, 0); + auto* rotation = new TGeoRotation(Form("segmentRot%d", i + 1), phi * TMath::RadToDeg() + 90 + mTiltAngle, 0, 0); auto* transformation = new TGeoCombiTrans(x, y, 0, rotation); LOGP(info, "Inserting Barrel {} in {} ", chipVol->GetName(), layerVol->GetName()); - layerVol->AddNode(chipVol, 1 + i, transformation); + layerVol->AddNode(staveVol, 1 + i, transformation); } LOGP(info, "Inserting Barrel {} in {} at r={} cm", layerVol->GetName(), motherVolume->GetName(), avgRadius); motherVolume->AddNode(layerVol, 1, nullptr); @@ -159,8 +251,10 @@ void ITOFLayer::createLayer(TGeoVolume* motherVolume) std::vector OTOFLayer::mRegister; void OTOFLayer::createLayer(TGeoVolume* motherVolume) { - std::string chipName = o2::iotof::GeometryTGeo::getOTOFChipPattern(), - sensName = o2::iotof::GeometryTGeo::getOTOFSensorPattern(); + const char* chipName = o2::iotof::GeometryTGeo::getOTOFChipPattern(); + const char* sensName = o2::iotof::GeometryTGeo::getOTOFSensorPattern(); + const char* moduleName = o2::iotof::GeometryTGeo::getOTOFModulePattern(); + const char* staveName = o2::iotof::GeometryTGeo::getOTOFStavePattern(); TGeoMedium* medSi = gGeoManager->GetMedium("TF3_SILICON$"); TGeoMedium* medAir = gGeoManager->GetMedium("TF3_AIR$"); @@ -172,12 +266,12 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume) TGeoTube* chip = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); - TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); - TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); + TGeoVolume* sensVol = new TGeoVolume(sensName, sensor, medSi); + TGeoVolume* chipVol = new TGeoVolume(chipName, chip, medSi); TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - sensVol->SetLineColor(kRed + 3); - chipVol->SetLineColor(kRed + 3); - layerVol->SetLineColor(kRed + 3); + setSensorStyle(sensVol); + setChipStyle(chipVol); + setLayerStyle(layerVol); LOGP(info, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); OTOFLayer::mRegister.push_back(sensVol->GetName()); @@ -191,40 +285,90 @@ void OTOFLayer::createLayer(TGeoVolume* motherVolume) return; } case kBarrelSegmented: { - const double circumference = TMath::TwoPi() * 0.5 * (mInnerRadius + mOuterRadius); - const double segmentSize = mSegments.second; // cm circumference / mSegments; + // 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); TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - layerVol->SetLineColor(kRed + 3); - - for (int i = 0; i < mSegments.first; ++i) { - LOGP(info, "oTOF: Creating segment {}/{} with size {} and thickness {}cm", i + 1, mSegments.first, segmentSize, (mOuterRadius - mInnerRadius)); - const double hx = 0.5 * segmentSize; - const double hy = 0.5 * (mOuterRadius - mInnerRadius); - const double hz = 0.5 * mZLength; - TGeoBBox* sensor = new TGeoBBox(hy, hx, hz); - TGeoBBox* chip = new TGeoBBox(hy, hx, hz); - const std::string segmentTag = Form("segment%d", i + 1); - TGeoVolume* sensVol = new TGeoVolume(Form("%s_%s", sensName.c_str(), segmentTag.c_str()), sensor, medSi); - TGeoVolume* chipVol = new TGeoVolume(Form("%s_%s", chipName.c_str(), segmentTag.c_str()), chip, medSi); - sensVol->SetLineColor(kRed + 3); - chipVol->SetLineColor(kRed + 3); - - LOGP(info, " Inserting Barrel {} in {} ", sensVol->GetName(), chipVol->GetName()); - OTOFLayer::mRegister.push_back(sensVol->GetName()); - chipVol->AddNode(sensVol, 1, nullptr); - - const double phi = TMath::TwoPi() * i / mSegments.first; - - LOG(info) << " Tilting angle for segment " << i + 1 << ": " << phi * TMath::RadToDeg() << " degrees"; + setLayerStyle(layerVol); + + // Now we create the volume for a single stave + const double staveSizeX = mStaves.second; // cm + const double staveSizeY = mOuterRadius - mInnerRadius; // cm + const double staveSizeZ = mZLength; // cm + TGeoBBox* stave = new TGeoBBox(staveSizeX * 0.5, staveSizeY * 0.5, staveSizeZ * 0.5); + TGeoVolume* staveVol = new TGeoVolume(staveName, stave, medAir); + setStaveStyle(staveVol); + + // Now we create the volume for a single module (sensor + chip) + const int modulesPerStaveX = 1; // we assume that each stave is divided in 2 modules along the x direction + const double moduleSizeX = staveSizeX / modulesPerStaveX; // cm + const double moduleSizeY = staveSizeY; // cm + const double moduleSizeZ = staveSizeZ / mModulesPerStave; // cm + TGeoBBox* module = new TGeoBBox(moduleSizeX * 0.5, moduleSizeY * 0.5, moduleSizeZ * 0.5); + TGeoVolume* moduleVol = new TGeoVolume(moduleName, module, medAir); + setModuleStyle(moduleVol); + + // Now we create the volume of the chip, which is the same for all modules + const int chipsPerModuleX = 2; // we assume that each module is divided in 2 chips along the x direction + const int chipsPerModuleZ = 2; // we assume that each module is divided in 2 chips along the z direction + const double chipSizeX = moduleSizeX / chipsPerModuleX; // cm + const double chipSizeY = moduleSizeY; // cm + const double chipSizeZ = moduleSizeZ / chipsPerModuleZ; // cm + TGeoBBox* chip = new TGeoBBox(chipSizeX * 0.5, chipSizeY * 0.5, chipSizeZ * 0.5); + TGeoVolume* chipVol = new TGeoVolume(chipName, chip, medSi); + setChipStyle(chipVol); + + // Finally we create the volume of the sensor, which is the same for all chips + const int sensorsPerChipX = 2; // we assume that each chip is divided in 2 sensors along the x direction + const int sensorsPerChipZ = 2; // we assume that each chip is divided in 2 sensors along the z direction + const double sensorSizeX = chipSizeX / sensorsPerChipX; // cm + const double sensorSizeY = chipSizeY; // cm + const double sensorSizeZ = chipSizeZ / sensorsPerChipZ; // cm + TGeoBBox* sensor = new TGeoBBox(sensorSizeX * 0.5, sensorSizeY * 0.5, sensorSizeZ * 0.5); + TGeoVolume* sensVol = new TGeoVolume(sensName, sensor, medSi); + setSensorStyle(sensVol); + OTOFLayer::mRegister.push_back(sensVol->GetName()); + + // Now we build a chip from sensors + for (int i = 0; i < sensorsPerChipX; ++i) { + 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, + (j + 0.5) * sensorSizeZ - 0.5 * chipSizeZ); + chipVol->AddNode(sensVol, 1 + i * sensorsPerChipZ + j, translation); + } + } + + // Now we build a module from chips + for (int i = 0; i < chipsPerModuleX; ++i) { + for (int j = 0; j < chipsPerModuleZ; ++j) { + LOGP(info, "oTOF: Creating chip {}/{} for module {}/{}", i + 1, chipsPerModuleX, j + 1, chipsPerModuleZ); + auto* translation = new TGeoTranslation((i + 0.5) * chipSizeX - 0.5 * moduleSizeX, 0, (j + 0.5) * chipSizeZ - 0.5 * moduleSizeZ); + moduleVol->AddNode(chipVol, 1 + i * chipsPerModuleZ + j, translation); + } + } + + // Now we build a stave from modules + for (int i = 0; i < modulesPerStaveX; ++i) { + for (int j = 0; j < mModulesPerStave; ++j) { + LOGP(info, "oTOF: Creating module {}/{} for stave {}/{}", i + 1, modulesPerStaveX, j + 1, mModulesPerStave); + auto* translation = new TGeoTranslation((i + 0.5) * moduleSizeX - 0.5 * staveSizeX, 0, (j + 0.5) * moduleSizeZ - 0.5 * staveSizeZ); + staveVol->AddNode(moduleVol, 1 + i * mModulesPerStave + j, translation); + } + } + + // 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()); + const double phi = TMath::TwoPi() * i / mStaves.first; const double x = avgRadius * TMath::Cos(phi); const double y = avgRadius * TMath::Sin(phi); - auto* rotation = new TGeoRotation(Form("segmentRot%d", i + 1), phi * TMath::RadToDeg() + mTiltAngle, 0, 0); + auto* rotation = new TGeoRotation(Form("segmentRot%d", i + 1), phi * TMath::RadToDeg() + 90 + mTiltAngle, 0, 0); auto* transformation = new TGeoCombiTrans(x, y, 0, rotation); LOGP(info, "Inserting Barrel {} in {} ", chipVol->GetName(), layerVol->GetName()); - layerVol->AddNode(chipVol, 1 + i, transformation); + layerVol->AddNode(staveVol, 1 + i, transformation); } LOGP(info, "Inserting Barrel {} in {} at r={} cm", layerVol->GetName(), motherVolume->GetName(), avgRadius); motherVolume->AddNode(layerVol, 1, nullptr); @@ -250,9 +394,9 @@ void FTOFLayer::createLayer(TGeoVolume* motherVolume) TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - sensVol->SetLineColor(kRed + 3); - chipVol->SetLineColor(kRed + 3); - layerVol->SetLineColor(kRed + 3); + setSensorStyle(sensVol); + setChipStyle(chipVol); + setLayerStyle(layerVol); LOGP(info, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); chipVol->AddNode(sensVol, 1, nullptr); @@ -282,9 +426,9 @@ void BTOFLayer::createLayer(TGeoVolume* motherVolume) TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - sensVol->SetLineColor(kRed + 3); - chipVol->SetLineColor(kRed + 3); - layerVol->SetLineColor(kRed + 3); + setSensorStyle(sensVol); + setChipStyle(chipVol); + setLayerStyle(layerVol); LOGP(info, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); chipVol->AddNode(sensVol, 1, nullptr);