From 745ac732b9538612bebb74601818c42e1232a5db Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 24 Nov 2023 13:45:56 +0100 Subject: [PATCH] Change ITS3 to simulate TDR description --- .../ITS3/base/include/ITS3Base/Specs.h | 101 +++ .../include/ITS3Simulation/ITS3Layer.h | 105 ++- .../ITS3/simulation/src/ITS3Layer.cxx | 619 ++++++++---------- 3 files changed, 421 insertions(+), 404 deletions(-) create mode 100644 Detectors/Upgrades/ITS3/base/include/ITS3Base/Specs.h diff --git a/Detectors/Upgrades/ITS3/base/include/ITS3Base/Specs.h b/Detectors/Upgrades/ITS3/base/include/ITS3Base/Specs.h new file mode 100644 index 0000000000000..4ef824f73b179 --- /dev/null +++ b/Detectors/Upgrades/ITS3/base/include/ITS3Base/Specs.h @@ -0,0 +1,101 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file Specs.h +/// \brief TDR specs of ITS3 +/// \author felix.schlepper@cern.ch + +#include "Rtypes.h" + +namespace o2::its3 +{ +namespace constants +{ +constexpr double cm{1e+2}; // This is the default unit of TGeo so we use this as scale +constexpr double mu{1e-6 * cm}; +constexpr double mm{1e-3 * cm}; +namespace pixelarray +{ +constexpr double length{9.197 * mm}; +constexpr double width{3.571 * mm}; +constexpr EColor color{kGreen}; +constexpr unsigned int nCols{156}; +constexpr unsigned int nRows{440}; +constexpr unsigned int nPixels{nCols * nRows}; +namespace pixel +{ +constexpr double pitchCol{width / static_cast(nCols)}; +constexpr double pitchRow{length / static_cast(nRows)}; +} // namespace pixel +} // namespace pixelarray +namespace tile +{ +namespace biasing +{ +constexpr double length{0.06 * mm}; +constexpr double width{3.571 * mm}; +constexpr EColor color{kYellow}; +static_assert(width == pixelarray::width); +} // namespace biasing +namespace powerswitches +{ +constexpr double length{9.257 * mm}; +constexpr double width{0.02 * mm}; +constexpr double z{pixelarray::width}; +constexpr EColor color{kBlue}; +} // namespace powerswitches +namespace readout +{ +constexpr double length{0.525 * mm}; +constexpr double width{3.591 * mm}; +constexpr EColor color{kMagenta}; +static_assert(width == (biasing::width + powerswitches::width)); +} // namespace readout +constexpr double width{readout::width}; +constexpr double length{powerswitches::length + readout::length}; +} // namespace tile +namespace rsu +{ +namespace databackbone +{ +constexpr double length{9.782 * mm}; +constexpr double width{0.06 * mm}; +constexpr EColor color{kRed}; +} // namespace databackbone +constexpr double length{19.564 * mm}; +constexpr double width{21.666 * mm}; +} // namespace rsu +namespace segment +{ +constexpr double length{rsu::length}; +namespace lec +{ +constexpr double length{segment::length}; +constexpr double width{4.5 * mm}; +constexpr EColor color{kCyan}; +} // namespace lec +namespace rec +{ +constexpr double length{segment::length}; +constexpr double width{1.5 * mm}; +constexpr EColor color{kCyan}; +} // namespace rec +constexpr unsigned int nRSUs{12}; +constexpr double width{nRSUs * rsu::width + lec::width + rec::width}; +} // namespace segment +constexpr unsigned int nLayers{3}; +constexpr std::array radii{19 * mm, 25.2 * mm, 31.5 * mm}; // middle radius e.g. inner radius+thickness/2. +constexpr double equatorialGap{1 * mm}; +constexpr std::array nSegments{3, 4, 5}; +constexpr double thickness{50 * mu}; +constexpr double effThickness{66 * mu}; +} // namespace constants +} // namespace o2::its3 diff --git a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h index c97ff93a01e72..1e0465b599d57 100644 --- a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h +++ b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h @@ -12,81 +12,62 @@ /// \file ITS3Layer.h /// \brief Definition of the ITS3Layer class /// \author Fabrizio Grosa +/// \author felix.schlepper@cern.ch #ifndef ALICEO2_ITS3_ITS3LAYER_H #define ALICEO2_ITS3_ITS3LAYER_H -#include +#include class TGeoVolume; -namespace o2 +namespace o2::its3 { -namespace its3 -{ -/// This class defines the Geometry for the ITS3 using TGeo. This is a work class used -/// to study different configurations during the development of the new ITS structure -class ITS3Layer : public TObject + +/// This class defines the Geometry for the ITS3 using TGeo. +class ITS3Layer { + // The hierarchy will be the following: + // ITS2 -> ITS3 + // --------------------------------- + // Sensor PixelArray + // Chip Tile + // Module RSU + // HalfStave Segment + // Stave Chip + // HalfBarrel CarbonForm + // Layer Layer public: - // Default constructor - ITS3Layer() = default; - - /// Constructor setting layer number - ITS3Layer(int lay); - - /// Copy constructor - ITS3Layer(const ITS3Layer&) = default; - - /// Assignment operator - ITS3Layer& operator=(const ITS3Layer&) = default; + // Create one layer of ITS3 and attach it to the motherVolume. + void createLayer(TGeoVolume* motherVolume, int layer = 0); - /// Default destructor - ~ITS3Layer() override; - - void createLayer(TGeoVolume* motherVolume, double radiusBetweenLayer); - void createLayerWithDeadZones(TGeoVolume* motherVolume, double radiusBetweenLayer); - void create4thLayer(TGeoVolume* motherVolume); - void createCarbonFoamStructure(TGeoVolume* motherVolume, double deltaR, bool fourthLayer = false); - - void setChipThick(double thick) { mChipThickness = thick; } - void setLayerRadius(double radius) { mRadius = radius; } - void setLayerZLen(double zLen) { mZLen = zLen; } - void setGapBetweenEmispheres(double gap) { mGapY = gap; } - void setGapBetweenEmispheresInPhi(double gap) { mGapPhi = gap; } - void setChipID(int chipID) { mChipTypeID = chipID; } - void setFringeChipWidth(double fringeChipWidth) { mFringeChipWidth = fringeChipWidth; } - void setMiddleChipWidth(double middleChipWidth) { mMiddleChipWidth = middleChipWidth; } - void setNumSubSensorsHalfLayer(int numSubSensorsHalfLayer) { mNumSubSensorsHalfLayer = numSubSensorsHalfLayer; } - void setHeightStripFoam(double heightStripFoam) { mHeightStripFoam = heightStripFoam; } - void setLengthSemiCircleFoam(double lengthSemiCircleFoam) { mLengthSemiCircleFoam = lengthSemiCircleFoam; } - void setThickGluedFoam(double thickGluedFoam) { mThickGluedFoam = thickGluedFoam; } - void setGapXDirection(double gapXDirection) { mGapXDirection = gapXDirection; } - void setBuildLevel(int buildLevel) { mBuildLevel = buildLevel; } - void setAdditionalMaterial(double addMat) { mAddMaterial = addMat; } + private: + void init(); + void createPixelArray(); + void createTile(); + void createRSU(); + void createSegment(); + void createChip(); + void createCarbonForm(); + void createLayerImpl(); private: - int mLayerNumber{0}; //! layer number - double mChipThickness{0.}; //! chip thickness - double mSensorThickness{0.}; //! sensor thickness - double mRadius{0.}; //! radius of layer - double mZLen{0.}; //! length of a layer - double mGapY{0.}; //! gap between emispheres in Y direction - double mGapPhi{0.}; //! gap between emispheres in phi (distance in Y direction) - int mChipTypeID{0}; //! chip ID - double mFringeChipWidth{0.}; //! fringe chip width - double mMiddleChipWidth{0.}; //! middle chip width - int mNumSubSensorsHalfLayer{0}; //! num of subsensors in half layer - double mHeightStripFoam{0.}; //! strip foam height - double mLengthSemiCircleFoam{0.}; //! semi-circle foam length - double mThickGluedFoam{0.}; //! glued foam thickness - double mGapXDirection{0.}; //! gap between quarter layer(only for layer 4) - double mAddMaterial{0.}; //! additional material to mimic services - int mBuildLevel{0}; //! build level for material budget studies + uint8_t mNLayer{0}; // Layer number + double mR{0}; // Middle Radius + double mRmin{}; // Minimum Radius + double mRmax{0}; // Maximum Radius + + // Individual Pieces + TGeoVolume* mPixelArray{nullptr}; + TGeoVolumeAssembly* mTile{nullptr}; + TGeoVolumeAssembly* mRSU{nullptr}; + TGeoVolumeAssembly* mSegment{nullptr}; + TGeoVolumeAssembly* mChip{nullptr}; + TGeoVolumeAssembly* mCarbonForm{nullptr}; + TGeoVolumeAssembly* mLayer{nullptr}; - ClassDefOverride(ITS3Layer, 0); // ITS3 geometry -}; // namespace its3 -} // namespace its3 -} // namespace o2 + ClassDefNV(ITS3Layer, 0); +}; +} // namespace o2::its3 #endif diff --git a/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx b/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx index 774b600ac3a09..4b107d9daa7db 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx @@ -12,378 +12,313 @@ /// \file ITS3Layer.h /// \brief Definition of the ITS3Layer class /// \author Fabrizio Grosa +/// \author felix.schlepper@cern.ch +#include "TGeoTube.h" +#include "TGeoVolume.h" + +#include "CommonConstants/MathConstants.h" +#include "ITSBase/Specs.h" #include "ITSBase/GeometryTGeo.h" #include "ITS3Base/SegmentationSuperAlpide.h" #include "ITS3Simulation/ITS3Layer.h" +#include "fairlogger/Logger.h" -#include // for LOG - -#include // for TGeoTube, TGeoTubeSeg -#include -#include // for TGeoVolume, TGeoVolumeAssembly - -using namespace o2::its3; - -/// \cond CLASSIMP -ClassImp(ITS3Layer); -/// \endcond +namespace o2::its3 +{ -ITS3Layer::ITS3Layer(int lay) - : TObject(), - mLayerNumber(lay) +void ITS3Layer::init() { - SegmentationSuperAlpide seg(lay); - mChipThickness = seg.mDetectorLayerThickness; - mSensorThickness = seg.mSensorLayerThickness; + // First we start by creating variables which we are reusing a couple of times. + mR = constants::radii[mNLayer]; + mRmin = mR - constants::thickness / 2.; + mRmax = mR + constants::thickness / 2.; } -ITS3Layer::~ITS3Layer() = default; - -void ITS3Layer::createLayer(TGeoVolume* motherVolume, double radiusBetweenLayer) +void ITS3Layer::createLayer(TGeoVolume* motherVolume, int layer) { - TGeoMedium* medSi = gGeoManager->GetMedium("IT3_SI$"); - TGeoMedium* medAir = gGeoManager->GetMedium("IT3_AIR$"); - - double rmin = mRadius; - double rmax = rmin + mChipThickness; - double rminSensor = rmax - mSensorThickness; - radiusBetweenLayer = radiusBetweenLayer - mChipThickness; - double phiGap = TMath::ASin(mGapPhi / 2.f / mRadius) * TMath::RadToDeg(); // degrees - double piDeg = TMath::Pi() * TMath::RadToDeg(); // degrees - - const int nElements = 7; - std::string names[nElements]; - - // do we need to keep the hierarchy? - names[0] = Form("%s%d", o2::its::GeometryTGeo::getITS3SensorPattern(), mLayerNumber); - names[1] = Form("%s%d", o2::its::GeometryTGeo::getITS3ChipPattern(), mLayerNumber); - names[2] = Form("%s%d", o2::its::GeometryTGeo::getITS3ModulePattern(), mLayerNumber); - names[3] = Form("%s%d", o2::its::GeometryTGeo::getITS3HalfStavePattern(), mLayerNumber); - names[4] = Form("%s%d", o2::its::GeometryTGeo::getITS3StavePattern(), mLayerNumber); - names[5] = Form("%s%d", o2::its::GeometryTGeo::getITS3HalfBarrelPattern(), mLayerNumber); - names[6] = Form("%s%d", o2::its::GeometryTGeo::getITS3LayerPattern(), mLayerNumber); - - TGeoTubeSeg* halfLayer[nElements - 1]; - TGeoVolume* volHalfLayer[nElements - 1]; - for (int iEl{0}; iEl < nElements - 1; ++iEl) { - TGeoMedium* med = (iEl <= 2) ? medSi : medAir; - if (iEl == 3) { - halfLayer[iEl] = new TGeoTubeSeg(rmin, rmax + radiusBetweenLayer, mZLen / 2, phiGap, piDeg - phiGap); - volHalfLayer[iEl] = new TGeoVolume(names[iEl].data(), halfLayer[iEl], med); - createCarbonFoamStructure(volHalfLayer[iEl], radiusBetweenLayer); - volHalfLayer[iEl]->SetVisibility(true); - volHalfLayer[iEl]->SetLineColor(kGray + 2); - } else if (iEl < 2) { - halfLayer[iEl] = new TGeoTubeSeg(rminSensor, rmax, mZLen / 2, phiGap, piDeg - phiGap); - volHalfLayer[iEl] = new TGeoVolume(names[iEl].data(), halfLayer[iEl], med); - volHalfLayer[iEl]->SetVisibility(true); - volHalfLayer[iEl]->SetLineColor(kRed + 1); - } else if (iEl == 2) { - halfLayer[iEl] = new TGeoTubeSeg(rmin, rmax, mZLen / 2, phiGap, piDeg - phiGap); - volHalfLayer[iEl] = new TGeoVolume(names[iEl].data(), halfLayer[iEl], med); - volHalfLayer[iEl]->SetVisibility(true); - volHalfLayer[iEl]->SetLineColor(kRed + 1); - } else { // all the others are simply half cylinders filling all the space - halfLayer[iEl] = new TGeoTubeSeg(rmin, rmax + radiusBetweenLayer, mZLen / 2, phiGap, piDeg - phiGap); - volHalfLayer[iEl] = new TGeoVolume(names[iEl].data(), halfLayer[iEl], med); - } - volHalfLayer[iEl]->SetUniqueID(mChipTypeID); - - if (iEl > 0) { - LOGP(debug, "Inserting {} inside {}", volHalfLayer[iEl - 1]->GetName(), volHalfLayer[iEl]->GetName()); - int id = 0; - if (iEl == 1) { - id = 1; - } - volHalfLayer[iEl]->AddNode(volHalfLayer[iEl - 1], id, nullptr); - } + // Create one layer of ITS3 and attach it to the motherVolume. + if (layer > 2) { + LOGP(fatal, "Cannot create more than 3 layers!"); + return; } + mNLayer = layer; + + init(); + createPixelArray(); + createTile(); + createRSU(); + createSegment(); + createChip(); + createCarbonForm(); + createLayerImpl(); + + // Add it to motherVolume + motherVolume->AddNode(mLayer, 0); +} - TGeoTranslation* translationTop = new TGeoTranslation(0., mGapY / 2, 0.); - TGeoTranslation* translationBottom = new TGeoTranslation(0., -mGapY / 2, 0.); - TGeoRotation* rotationBottom = new TGeoRotation("", piDeg, 0., 0.); - TGeoCombiTrans* rotoTranslationBottom = - new TGeoCombiTrans(*translationBottom, *rotationBottom); - - TGeoVolumeAssembly* volLayer = new TGeoVolumeAssembly(names[nElements - 1].data()); - volLayer->AddNode(volHalfLayer[nElements - 2], 0, translationTop); - volLayer->AddNode(volHalfLayer[nElements - 2], 1, rotoTranslationBottom); - - // Finally put everything in the mother volume - LOGP(debug, "Inserting {} inside {}", volLayer->GetName(), motherVolume->GetName()); - motherVolume->AddNode(volLayer, 1, nullptr); +void ITS3Layer::createPixelArray() +{ + using namespace constants::pixelarray; + // A pixel array is pure silicon and the sensitive part of our detector. + // It will be segmented into a 440x144 matrix by the + // SuperSegmentationAlpide. + // Pixel Array is just a longer version of the biasing but starts in phi at + // biasPhi2. + double pixelArrayPhi1 = + constants::tile::biasing::length / mRmin * constants::math::Rad2Deg; + double pixelArrayPhi2 = + length / mRmin * constants::math::Rad2Deg + pixelArrayPhi1; + auto pixelArray = new TGeoTubeSeg(mRmin, mRmax, width / 2., + pixelArrayPhi1, pixelArrayPhi2); + mPixelArray = new TGeoVolume( + Form("pixelarray_%d", mNLayer) /* TODO change to correct name */, + pixelArray, + gGeoManager->GetMedium(material::MaterialNames[material::Silicon])); + mPixelArray->SetLineColor(color); + mPixelArray->RegisterYourself(); } -void ITS3Layer::createLayerWithDeadZones(TGeoVolume* motherVolume, double radiusBetweenLayer) +void ITS3Layer::createTile() { - TGeoMedium* medSi = gGeoManager->GetMedium("IT3_SI$"); - TGeoMedium* medAir = gGeoManager->GetMedium("IT3_AIR$"); - - double rmin = mRadius; - double rmax = rmin + mChipThickness; - double rminSensor = rmax - mSensorThickness; - double rmed = (rmax + rmin) / 2; - // width of sensors of layers is calculated from r and chips' widths - double widthSensor = (TMath::Pi() * rmed - (mNumSubSensorsHalfLayer - 1) * mMiddleChipWidth - 2 * mFringeChipWidth) / mNumSubSensorsHalfLayer; - radiusBetweenLayer = radiusBetweenLayer - mChipThickness; - double phiGap = TMath::ASin(mGapPhi / 2.f / mRadius) * TMath::RadToDeg(); // degrees - double piDeg = TMath::Pi() * TMath::RadToDeg(); // degrees - - const int nElements = 7; - std::string names[nElements]; - int nObjPerElement[nElements] = {mNumSubSensorsHalfLayer, 1, 1, 1, 1, 1, 1}; // mNumSubSensorsHalfLayer chips and sensors per half layer - - names[0] = Form("%s%d", o2::its::GeometryTGeo::getITS3SensorPattern(), mLayerNumber); - names[1] = Form("%s%d", o2::its::GeometryTGeo::getITS3ChipPattern(), mLayerNumber); - names[2] = Form("%s%d", o2::its::GeometryTGeo::getITS3ModulePattern(), mLayerNumber); - names[3] = Form("%s%d", o2::its::GeometryTGeo::getITS3HalfStavePattern(), mLayerNumber); - names[4] = Form("%s%d", o2::its::GeometryTGeo::getITS3StavePattern(), mLayerNumber); - names[5] = Form("%s%d", o2::its::GeometryTGeo::getITS3HalfBarrelPattern(), mLayerNumber); - names[6] = Form("%s%d", o2::its::GeometryTGeo::getITS3LayerPattern(), mLayerNumber); - - std::array, nElements - 1> halfLayer{}; - TGeoVolume* volHalfLayer[nElements - 1]; - - for (int iEl{0}; iEl < nElements - 1; ++iEl) { - TGeoMedium* med = (iEl <= 2) ? medSi : medAir; - - for (int iObj{0}; iObj < nObjPerElement[iEl]; ++iObj) { - if (iEl == 0) { // subsensors (mNumSubSensorsHalfLayer sectors with dead zones) - if (iObj == 0) { - halfLayer[iEl].push_back(new TGeoTubeSeg(Form("subsens%dlayer%d", iObj, mLayerNumber), rminSensor, rmax, mZLen / 2, TMath::RadToDeg() * mFringeChipWidth / rmed + phiGap, TMath::RadToDeg() * (mFringeChipWidth + widthSensor) / rmed)); - } else if (iObj == mNumSubSensorsHalfLayer - 1) { - halfLayer[iEl].push_back(new TGeoTubeSeg(Form("subsens%dlayer%d", iObj, mLayerNumber), rminSensor, rmax, mZLen / 2, TMath::RadToDeg() * (mFringeChipWidth + iObj * widthSensor + iObj * mMiddleChipWidth) / rmed, piDeg - TMath::RadToDeg() * mFringeChipWidth / rmed - phiGap)); - } else { - halfLayer[iEl].push_back(new TGeoTubeSeg(Form("subsens%dlayer%d", iObj, mLayerNumber), rminSensor, rmax, mZLen / 2, TMath::RadToDeg() * (mFringeChipWidth + iObj * widthSensor + iObj * mMiddleChipWidth) / rmed, TMath::RadToDeg() * (mFringeChipWidth + (iObj + 1) * widthSensor + iObj * mMiddleChipWidth) / rmed)); - } - } else if (iEl == 1) { - halfLayer[iEl].push_back(new TGeoTubeSeg(rminSensor, rmax, mZLen / 2, phiGap, piDeg - phiGap)); - } else if (iEl == 2) { - halfLayer[iEl].push_back(new TGeoTubeSeg(rmin, rmax, mZLen / 2, phiGap, piDeg - phiGap)); - } else { // all the others are simply half cylinders filling all the space - halfLayer[iEl].push_back(new TGeoTubeSeg(rmin, rmax + radiusBetweenLayer, mZLen / 2, phiGap, piDeg - phiGap)); - } - } - - if (iEl == 0) { - std::string subSensNames = ""; - for (int iObj{0}; iObj < nObjPerElement[iEl] - 1; ++iObj) { - subSensNames += Form("subsens%dlayer%d+", iObj, mLayerNumber); - } - subSensNames += Form("subsens%dlayer%d", nObjPerElement[iEl] - 1, mLayerNumber); - TGeoCompositeShape* sensor = new TGeoCompositeShape(subSensNames.data()); - volHalfLayer[iEl] = new TGeoVolume(names[iEl].data(), sensor, med); - volHalfLayer[iEl]->SetUniqueID(mChipTypeID); - volHalfLayer[iEl]->SetVisibility(true); - volHalfLayer[iEl]->SetLineColor(kRed + 1); - } else { - volHalfLayer[iEl] = new TGeoVolume(names[iEl].data(), halfLayer[iEl][0], med); - volHalfLayer[iEl]->SetUniqueID(mChipTypeID); - if (iEl == 3) { - createCarbonFoamStructure(volHalfLayer[iEl], radiusBetweenLayer); - volHalfLayer[iEl]->SetVisibility(true); - volHalfLayer[iEl]->SetLineColor(kGray + 2); - } else if (iEl == 1) { - volHalfLayer[iEl]->SetVisibility(true); - volHalfLayer[iEl]->SetLineColor(kBlue + 2); - } - - int id = (iEl == 1) ? 1 : 0; - LOGP(debug, "Inserting {} id {} inside {}", volHalfLayer[iEl - 1]->GetName(), id, volHalfLayer[iEl]->GetName()); - volHalfLayer[iEl]->AddNode(volHalfLayer[iEl - 1], id, nullptr); - } + using namespace constants::tile; + // This functions creates a single Tile, which is the basic building block + // of the chip. It consists of a pixelArray (sensitive area), biasing, power + // switches and readout periphery (latter three are insensitive). We start + // building the tile with the left upper edge of the biasing as center of + // the tile’s z-coordinate axis. + mTile = new TGeoVolumeAssembly(Form("tile_%d", mNLayer)); + mTile->VisibleDaughters(); + + // Biasing + auto zMoveBiasing = new TGeoTranslation(0, 0, +biasing::width / 2.); + double biasPhi1 = 0; + double biasPhi2 = biasing::length / mRmin * constants::math::Rad2Deg; + auto biasing = + new TGeoTubeSeg(mRmin, mRmax, biasing::width / 2, biasPhi1, + biasPhi2); + auto biasingVol = new TGeoVolume( + Form("biasing_%d", mNLayer), biasing, + gGeoManager->GetMedium(material::MaterialNames[material::DeadZone])); + biasingVol->SetLineColor(biasing::color); + biasingVol->RegisterYourself(); + if (mVerbose) { + std::cout << "Biasing:" << std::endl; + biasingVol->InspectShape(); + biasingVol->InspectMaterial(); } + mTile->AddNode(biasingVol, 0, zMoveBiasing); + + // Pixel Array is just a longer version of the biasing but starts in phi at + // biasPhi2. + mTile->AddNode(mPixelArray, 0, zMoveBiasing); + + // The readout periphery is also on top of the pixel array but extrudes on +z a bit e.g. is wider. + auto zMoveReadout = new TGeoTranslation(0, 0, +readout::width / 2.); + double readoutPhi1 = + constants::pixelarray::length / mRmin * constants::math::Rad2Deg + biasPhi2; + double readoutPhi2 = + readout::length / mRmin * constants::math::Rad2Deg + readoutPhi1; + auto readout = new TGeoTubeSeg(mRmin, mRmax, readout::width / 2, + readoutPhi1, readoutPhi2); + auto readoutVol = new TGeoVolume( + Form("readout_%d", mNLayer), readout, + gGeoManager->GetMedium(material::MaterialNames[material::DeadZone])); + readoutVol->SetLineColor(readout::color); + readoutVol->RegisterYourself(); + if (mVerbose) { + std::cout << "Readout:" << std::endl; + readoutVol->InspectShape(); + readoutVol->InspectMaterial(); + } + mTile->AddNode(readoutVol, 0, zMoveReadout); + + // Power Switches are on the side right side of the pixel array and biasing. + auto zMovePowerSwitches = new TGeoTranslation(0, 0, +powerswitches::width / 2. + biasing::width); + double powerPhi1 = 0; + double powerPhi2 = powerswitches::length / mRmin * constants::math::Rad2Deg; + auto powerSwitches = new TGeoTubeSeg( + mRmin, mRmax, powerswitches::width / 2, powerPhi1, powerPhi2); + auto powerSwitchesVol = new TGeoVolume( + Form("powerswitches_%d", mNLayer), powerSwitches, + gGeoManager->GetMedium(material::MaterialNames[material::DeadZone])); + powerSwitchesVol->SetLineColor(powerswitches::color); + if (mVerbose) { + std::cout << "PowerSwitches:" << std::endl; + powerSwitchesVol->InspectShape(); + powerSwitchesVol->InspectMaterial(); + } + mTile->AddNode(powerSwitchesVol, 0, zMovePowerSwitches); - TGeoTranslation* translationTop = new TGeoTranslation(0., mGapY / 2, 0.); - TGeoTranslation* translationBottom = new TGeoTranslation(0., -mGapY / 2, 0.); - TGeoRotation* rotationBottom = new TGeoRotation("", piDeg, 0., 0.); - TGeoCombiTrans* rotoTranslationBottom = - new TGeoCombiTrans(*translationBottom, *rotationBottom); - - TGeoVolumeAssembly* volLayer = new TGeoVolumeAssembly(names[nElements - 1].data()); - volLayer->AddNode(volHalfLayer[nElements - 2], 0, translationTop); - volLayer->AddNode(volHalfLayer[nElements - 2], 1, rotoTranslationBottom); - - // Finally put everything in the mother volume - LOGP(debug, "Inserting {} inside {}", volLayer->GetName(), motherVolume->GetName()); - motherVolume->AddNode(volLayer, 1, nullptr); + if (mSubstrate) { + // Create the substrate layer at the back of the tile. + // TODO + } } -void ITS3Layer::create4thLayer(TGeoVolume* motherVolume) +void ITS3Layer::createRSU() { - TGeoMedium* medSi = gGeoManager->GetMedium("IT3_SI$"); - TGeoMedium* medAir = gGeoManager->GetMedium("IT3_AIR$"); - - double rmin = mRadius; - double rmax = rmin + mChipThickness; - double rminSensor = rmax - mSensorThickness; - double rmed = (rmax + rmin) / 2; - // width of sensors of layers is calculated from r and chips' widths - double widthSensor = (0.5 * TMath::Pi() * rmed - (mNumSubSensorsHalfLayer - 1) * mMiddleChipWidth - 2 * mFringeChipWidth) / mNumSubSensorsHalfLayer; - double phiGap = TMath::ASin(mGapPhi / 2.f / mRadius) * TMath::RadToDeg(); // degrees - double piDeg = TMath::Pi() * TMath::RadToDeg(); // degrees - - const int nElements = 7; - std::string names[nElements]; - int nObjPerElement[nElements] = {mNumSubSensorsHalfLayer, 1, 1, 1, 1, 1, 1}; // mNumSubSensorsHalfLayer chips and sensors per half layer - - names[0] = Form("%s%d", o2::its::GeometryTGeo::getITS3SensorPattern(), mLayerNumber); - names[1] = Form("%s%d", o2::its::GeometryTGeo::getITS3ChipPattern(), mLayerNumber); - names[2] = Form("%s%d", o2::its::GeometryTGeo::getITS3ModulePattern(), mLayerNumber); - names[3] = Form("%s%d", o2::its::GeometryTGeo::getITS3HalfStavePattern(), mLayerNumber); - names[4] = Form("%s%d", o2::its::GeometryTGeo::getITS3StavePattern(), mLayerNumber); - names[5] = Form("%s%d", o2::its::GeometryTGeo::getITS3HalfBarrelPattern(), mLayerNumber); - names[6] = Form("%s%d", o2::its::GeometryTGeo::getITS3LayerPattern(), mLayerNumber); - - std::array, nElements - 1> quarterLayer{}; - TGeoVolume* volQuarterLayer[nElements - 1]; - - for (int iEl{0}; iEl < nElements - 2; ++iEl) { // we need only 2 half barrels as usual, so we stop at the stave - TGeoMedium* med = (iEl <= 2) ? medSi : medAir; - - for (int iObj{0}; iObj < nObjPerElement[iEl]; ++iObj) { - if (iEl == 0) { // subsensors (mNumSubSensorsHalfLayer sectors with dead zones) - if (iObj == 0) { - quarterLayer[iEl].push_back(new TGeoTubeSeg(Form("subsens%dlayer%d", iObj, mLayerNumber), rminSensor, rmax, mZLen / 2, piDeg / 4. + TMath::RadToDeg() * mFringeChipWidth / rmed + phiGap, piDeg / 4. + TMath::RadToDeg() * (mFringeChipWidth + widthSensor) / rmed)); - } else if (iObj == mNumSubSensorsHalfLayer - 1) { - quarterLayer[iEl].push_back(new TGeoTubeSeg(Form("subsens%dlayer%d", iObj, mLayerNumber), rminSensor, rmax, mZLen / 2, piDeg / 4. + TMath::RadToDeg() * (mFringeChipWidth + iObj * widthSensor + iObj * mMiddleChipWidth) / rmed, 3. / 4. * piDeg - TMath::RadToDeg() * mFringeChipWidth / rmed - phiGap)); - } else { - quarterLayer[iEl].push_back(new TGeoTubeSeg(Form("subsens%dlayer%d", iObj, mLayerNumber), rminSensor, rmax, mZLen / 2, piDeg / 4. + TMath::RadToDeg() * (mFringeChipWidth + iObj * widthSensor + iObj * mMiddleChipWidth) / rmed, piDeg / 4. + TMath::RadToDeg() * (mFringeChipWidth + (iObj + 1) * widthSensor + iObj * mMiddleChipWidth) / rmed)); - } - } else if (iEl == 1) { - quarterLayer[iEl].push_back(new TGeoTubeSeg(rminSensor, rmax, mZLen / 2, phiGap, piDeg / 4. + piDeg * 3 / 4. - phiGap)); - } else if (iEl == 2) { - quarterLayer[iEl].push_back(new TGeoTubeSeg(rmin, rmax, mZLen / 2, piDeg / 4. + phiGap, piDeg * 3 / 4. - phiGap)); - } else { // all the others are simply quarter cylinders filling all the space - quarterLayer[iEl].push_back(new TGeoTubeSeg(rmin, rmax, mZLen / 2, piDeg / 4. + phiGap, piDeg * 3 / 4. - phiGap)); - } - } - - if (iEl == 0) { - std::string subSensNames = ""; - for (int iObj{0}; iObj < nObjPerElement[iEl] - 1; ++iObj) { - subSensNames += Form("subsens%dlayer%d+", iObj, mLayerNumber); - } - subSensNames += Form("subsens%dlayer%d", nObjPerElement[iEl] - 1, mLayerNumber); - TGeoCompositeShape* sensor = new TGeoCompositeShape(subSensNames.data()); - volQuarterLayer[iEl] = new TGeoVolume(names[iEl].data(), sensor, med); - volQuarterLayer[iEl]->SetUniqueID(mChipTypeID); - volQuarterLayer[iEl]->SetVisibility(true); - volQuarterLayer[iEl]->SetLineColor(kRed + 1); - } else { - volQuarterLayer[iEl] = new TGeoVolume(names[iEl].data(), quarterLayer[iEl][0], med); - volQuarterLayer[iEl]->SetUniqueID(mChipTypeID); - if (iEl == 4) { - // createCarbonFoamStructure(volQuarterLayer[iEl], 0., true); - volQuarterLayer[iEl]->SetVisibility(true); - volQuarterLayer[iEl]->SetLineColor(kGray + 2); - } else if (iEl == 1) { - volQuarterLayer[iEl]->SetVisibility(true); - volQuarterLayer[iEl]->SetLineColor(kBlue + 2); - } - - int id = (iEl == 1) ? 1 : 0; - LOGP(debug, "Inserting {} id {} inside {}", volQuarterLayer[iEl - 1]->GetName(), id, volQuarterLayer[iEl]->GetName()); - volQuarterLayer[iEl]->AddNode(volQuarterLayer[iEl - 1], id, nullptr); - } + using namespace constants::rsu; + // A Repeated Sensor Unit (RSU) is 12 Tiles + 4 Databackbones stichted together. + mRSU = new TGeoVolumeAssembly(Form("rsu_%d", mNLayer)); + mRSU->VisibleDaughters(); + int nCopyRSU{0}, nCopyDB{0}; + + // Create the DatabackBone + // The Databackbone spans the whole phi of the tile. + double dataBackbonePhi1 = 0; + double dataBackbonePhi2 = databackbone::length / mRmin * + constants::math::Rad2Deg; + auto dataBackbone = new TGeoTubeSeg(mRmin, mRmax, databackbone::width / 2., + dataBackbonePhi1, + dataBackbonePhi2); + auto dataBackboneVol = new TGeoVolume( + Form("databackbone_%d", mNLayer), dataBackbone, + gGeoManager->GetMedium(material::MaterialNames[material::DeadZone])); + dataBackboneVol->SetLineColor(databackbone::color); + dataBackboneVol->RegisterYourself(); + if (mVerbose) { + std::cout << "DataBackbone:" << std::endl; + dataBackboneVol->InspectShape(); + dataBackboneVol->InspectMaterial(); } - TGeoTranslation* translationTopRight = new TGeoTranslation(mGapXDirection / 2, 0., 0.); - TGeoRotation* rotationTopRight = new TGeoRotation("", -piDeg / 4, 0., 0.); - TGeoCombiTrans* rotoTranslationTopRight = new TGeoCombiTrans(*translationTopRight, *rotationTopRight); - - TGeoTranslation* translationTopLeft = new TGeoTranslation(-mGapXDirection / 2, 0., 0.); - TGeoRotation* rotationTopLeft = new TGeoRotation("", piDeg / 4, 0., 0.); - TGeoCombiTrans* rotoTranslationTopLeft = new TGeoCombiTrans(*translationTopLeft, *rotationTopLeft); - - TGeoVolumeAssembly* halfLayer = new TGeoVolumeAssembly(names[nElements - 2].data()); - halfLayer->AddNode(volQuarterLayer[nElements - 3], 0, rotoTranslationTopRight); - halfLayer->AddNode(volQuarterLayer[nElements - 3], 1, rotoTranslationTopLeft); - - TGeoTranslation* translationTop = new TGeoTranslation(0., mGapY / 2, 0.); - TGeoTranslation* translationBottom = new TGeoTranslation(0., -mGapY / 2, 0.); - TGeoRotation* rotationBottom = new TGeoRotation("", piDeg, 0., 0.); - TGeoCombiTrans* rotoTranslationBottom = new TGeoCombiTrans(*translationBottom, *rotationBottom); - - TGeoVolumeAssembly* volLayer = new TGeoVolumeAssembly(names[nElements - 1].data()); - volLayer->AddNode(halfLayer, 0, translationTop); - volLayer->AddNode(halfLayer, 1, rotoTranslationBottom); - - // Finally put everything in the mother volume - LOGP(debug, "Inserting {} inside {}", volLayer->GetName(), motherVolume->GetName()); - motherVolume->AddNode(volLayer, 1, nullptr); + // Lower Left + auto zMoveLL1 = new TGeoTranslation(0, 0, constants::tile::width); + auto zMoveLL2 = new TGeoTranslation(0, 0, constants::tile::width * 2.); + auto zMoveLLDB = new TGeoTranslation(0, 0, -databackbone::width / 2.); + // Lets attach the tiles to the QS. + mRSU->AddNode(mTile, nCopyRSU++, nullptr); + mRSU->AddNode(mTile, nCopyRSU++, zMoveLL1); + mRSU->AddNode(mTile, nCopyRSU++, zMoveLL2); + mRSU->AddNode(dataBackboneVol, nCopyDB++, zMoveLLDB); + + // Lower Right + auto zMoveLR0 = new TGeoTranslation(0, 0, +width / 2.); + auto zMoveLR1 = new TGeoTranslation(0, 0, constants::tile::width + width / 2.); + auto zMoveLR2 = new TGeoTranslation(0, 0, constants::tile::width * 2. + width / 2.); + auto zMoveLRDB = new TGeoTranslation(0, 0, -databackbone::width / 2. + width / 2.); + // Lets attach the tiles to the QS. + mRSU->AddNode(mTile, nCopyRSU++, zMoveLR0); + mRSU->AddNode(mTile, nCopyRSU++, zMoveLR1); + mRSU->AddNode(mTile, nCopyRSU++, zMoveLR2); + mRSU->AddNode(dataBackboneVol, nCopyDB++, zMoveLRDB); + + // Rotation for top half + double phi = length / mRmin * constants::math::Rad2Deg; + auto rot = new TGeoRotation("", 0, 0, phi / 2.); + + // Upper Left + auto zMoveUL1 = new TGeoCombiTrans(0, 0, constants::tile::width, rot); + auto zMoveUL2 = new TGeoCombiTrans(0, 0, constants::tile::width * 2., rot); + auto zMoveULDB = new TGeoCombiTrans(0, 0, -databackbone::width / 2., rot); + // Lets attach the tiles to the QS. + mRSU->AddNode(mTile, nCopyRSU++, rot); + mRSU->AddNode(mTile, nCopyRSU++, zMoveUL1); + mRSU->AddNode(mTile, nCopyRSU++, zMoveUL2); + mRSU->AddNode(dataBackboneVol, nCopyDB++, zMoveULDB); + + // Upper Right + auto zMoveUR0 = new TGeoCombiTrans(0, 0, +width / 2., rot); + auto zMoveUR1 = new TGeoCombiTrans(0, 0, constants::tile::width + width / 2., rot); + auto zMoveUR2 = new TGeoCombiTrans(0, 0, constants::tile::width * 2. + width / 2., rot); + auto zMoveURDB = new TGeoCombiTrans(0, 0, -databackbone::width / 2. + width / 2., rot); + // Lets attach the tiles to the QS. + mRSU->AddNode(mTile, nCopyRSU++, zMoveUR0); + mRSU->AddNode(mTile, nCopyRSU++, zMoveUR1); + mRSU->AddNode(mTile, nCopyRSU++, zMoveUR2); + mRSU->AddNode(dataBackboneVol, nCopyDB++, zMoveURDB); } -void ITS3Layer::createCarbonFoamStructure(TGeoVolume* motherVolume, double deltaR, bool fourthLayer) +void ITS3Layer::createSegment() { - TGeoMedium* medCarbonFoam = (mBuildLevel < 1) ? gGeoManager->GetMedium("IT3_ERGDUOCEL$") : gGeoManager->GetMedium("IT3_AIR$"); // if build level >= 1 we do not put carbon foam but air - TGeoMedium* medGlue = (mBuildLevel < 2) ? gGeoManager->GetMedium("IT3_IMPREG_FLEECE$") : gGeoManager->GetMedium("IT3_AIR$"); // if build level >= 2 we do not put glue but air - TGeoMedium* medSi = (mBuildLevel <= 2) ? gGeoManager->GetMedium("IT3_SI$") : gGeoManager->GetMedium("IT3_AIR$"); // if build level > 2 we do not put silicon but air - - double rmaxWoAddMat = mRadius + mChipThickness; - double rmax = rmaxWoAddMat + mAddMaterial; - double radiusBetweenLayer = deltaR - mChipThickness; - double rmedFoam = rmax + radiusBetweenLayer / 2; - double phiGap = TMath::ASin(mGapPhi / 2.f / mRadius) * TMath::RadToDeg(); // degrees - double piDeg = TMath::Pi() * TMath::RadToDeg(); // degrees - double phiMin = (fourthLayer) ? piDeg / 4 : 0.; // degrees - double phiMax = (fourthLayer) ? piDeg * 3 / 4 : piDeg; // degrees - - TGeoTranslation* transSemicircle[2]; - transSemicircle[0] = new TGeoTranslation("transSemicircleFoam0", 0, 0, (mZLen - mLengthSemiCircleFoam) / 2); - transSemicircle[0]->RegisterYourself(); - transSemicircle[1] = new TGeoTranslation("transSemicircleFoam1", 0, 0, -(mZLen - mLengthSemiCircleFoam) / 2); - transSemicircle[1]->RegisterYourself(); - - TGeoTubeSeg* subGluedFoamBottom[4]; - subGluedFoamBottom[0] = new TGeoTubeSeg(Form("subgluedfoambottom0layer%d", mLayerNumber), rmax, rmax + mThickGluedFoam, mLengthSemiCircleFoam / 2, phiMin + phiGap, phiMax - phiGap); - subGluedFoamBottom[1] = new TGeoTubeSeg(Form("subgluedfoambottom1layer%d", mLayerNumber), rmax, rmax + mThickGluedFoam, mLengthSemiCircleFoam / 2, phiMin + phiGap, phiMax - phiGap); - subGluedFoamBottom[2] = new TGeoTubeSeg(Form("subgluedfoambottom2layer%d", mLayerNumber), rmax, rmax + mThickGluedFoam, (mZLen - mLengthSemiCircleFoam) / 2, phiMin + phiGap, phiMin + TMath::RadToDeg() * mHeightStripFoam / rmedFoam + phiGap); - subGluedFoamBottom[3] = new TGeoTubeSeg(Form("subgluedfoambottom3layer%d", mLayerNumber), rmax, rmax + mThickGluedFoam, (mZLen - mLengthSemiCircleFoam) / 2, phiMax - TMath::RadToDeg() * (mHeightStripFoam / rmedFoam) - phiGap, phiMax - phiGap); - TGeoTubeSeg* subGluedFoamTop[4]; - subGluedFoamTop[0] = new TGeoTubeSeg(Form("subgluedfoamtop0layer%d", mLayerNumber), rmax + radiusBetweenLayer - mThickGluedFoam, rmax + radiusBetweenLayer, mLengthSemiCircleFoam / 2, phiMin + phiGap, phiMax - phiGap); - subGluedFoamTop[1] = new TGeoTubeSeg(Form("subgluedfoamtop1layer%d", mLayerNumber), rmax + radiusBetweenLayer - mThickGluedFoam, rmax + radiusBetweenLayer, mLengthSemiCircleFoam / 2, phiMin + phiGap, phiMax - phiGap); - subGluedFoamTop[2] = new TGeoTubeSeg(Form("subgluedfoamtop2layer%d", mLayerNumber), rmax + radiusBetweenLayer - mThickGluedFoam, rmax + radiusBetweenLayer, (mZLen - mLengthSemiCircleFoam) / 2, phiMin + phiGap, phiMin + TMath::RadToDeg() * mHeightStripFoam / rmedFoam + phiGap); - subGluedFoamTop[3] = new TGeoTubeSeg(Form("subgluedfoamtop3layer%d", mLayerNumber), rmax + radiusBetweenLayer - mThickGluedFoam, rmax + radiusBetweenLayer, (mZLen - mLengthSemiCircleFoam) / 2, phiMax - TMath::RadToDeg() * (mHeightStripFoam / rmedFoam) - phiGap, phiMax - phiGap); - - std::string subGluedFoamsNames = ""; - for (int iObj{0}; iObj < 2; ++iObj) { - subGluedFoamsNames += Form("(subgluedfoambottom%dlayer%d:transSemicircleFoam%d)+", iObj, mLayerNumber, iObj); + using namespace constants::segment; + // A segment is 12 RSUs + left and right end cap. We place the first rsu + // as z-coordinate center and attach to this. Hence, we will displace the + // left end-cap to the left and the right to right. + mSegment = new TGeoVolumeAssembly(Form("segment_%d", mNLayer)); + mSegment->VisibleDaughters(); + + for (int i{0}; i < nRSUs; ++i) { + auto zMove = new TGeoTranslation(0, 0, +i * constants::rsu::width + constants::rsu::databackbone::width); + mSegment->AddNode(mRSU, i, zMove); } - subGluedFoamsNames += Form("subgluedfoambottom2layer%d+", mLayerNumber); - subGluedFoamsNames += Form("subgluedfoambottom3layer%d+", mLayerNumber); - for (int iObj{0}; iObj < 2; ++iObj) { - subGluedFoamsNames += Form("(subgluedfoamtop%dlayer%d:transSemicircleFoam%d)+", iObj, mLayerNumber, iObj); + // LEC + double lecPhi1 = 0; + double lecPhi2 = lec::length / mRmin * constants::math::Rad2Deg; + auto zMoveLEC = new TGeoTranslation(0, 0, -lec::width / 2.); + auto lec = + new TGeoTubeSeg(mRmin, mRmax, lec::width / 2., lecPhi1, lecPhi2); + auto lecVol = new TGeoVolume( + Form("lec_%d", mNLayer), lec, + gGeoManager->GetMedium(material::MaterialNames[material::DeadZone])); + lecVol->SetLineColor(lec::color); + lecVol->RegisterYourself(); + if (mVerbose) { + std::cout << "LEC:" << std::endl; + lecVol->InspectShape(); + lecVol->InspectMaterial(); } - subGluedFoamsNames += Form("subgluedfoamtop2layer%d+", mLayerNumber); - subGluedFoamsNames += Form("subgluedfoamtop3layer%d", mLayerNumber); - - TGeoCompositeShape* gluedfoam = new TGeoCompositeShape(subGluedFoamsNames.data()); - TGeoVolume* volGlue = new TGeoVolume(Form("Glue%d", mLayerNumber), gluedfoam, medGlue); - motherVolume->AddNode(volGlue, 1, nullptr); - - TGeoTubeSeg* subFoam[4]; - subFoam[0] = new TGeoTubeSeg(Form("subfoam0layer%d", mLayerNumber), rmax + mThickGluedFoam, rmax + radiusBetweenLayer - mThickGluedFoam, mLengthSemiCircleFoam / 2, phiMin + phiGap, phiMax - phiGap); - subFoam[1] = new TGeoTubeSeg(Form("subfoam1layer%d", mLayerNumber), rmax + mThickGluedFoam, rmax + radiusBetweenLayer - mThickGluedFoam, mLengthSemiCircleFoam / 2, phiMin + phiGap, phiMax - phiGap); - subFoam[2] = new TGeoTubeSeg(Form("subfoam2layer%d", mLayerNumber), rmax + mThickGluedFoam, rmax + radiusBetweenLayer - mThickGluedFoam, (mZLen - mLengthSemiCircleFoam) / 2, phiMin + phiGap, phiMin + TMath::RadToDeg() * mHeightStripFoam / rmedFoam + phiGap); - subFoam[3] = new TGeoTubeSeg(Form("subfoam3layer%d", mLayerNumber), rmax + mThickGluedFoam, rmax + radiusBetweenLayer - mThickGluedFoam, (mZLen - mLengthSemiCircleFoam) / 2, phiMax - TMath::RadToDeg() * (mHeightStripFoam / rmedFoam) - phiGap, phiMax - phiGap); - - std::string subFoamNames = ""; - for (int iObj{0}; iObj < 2; ++iObj) { - subFoamNames += Form("(subfoam%dlayer%d:transSemicircleFoam%d)+", iObj, mLayerNumber, iObj); + mSegment->AddNode(lecVol, 0, zMoveLEC); + + // REC; reuses lecPhi1,2 + auto zMoveREC = new TGeoTranslation(0, 0, nRSUs * constants::rsu::width + rec::width / 2.); + auto rec = + new TGeoTubeSeg(mRmin, mRmax, rec::width / 2., lecPhi1, lecPhi2); + auto recVol = new TGeoVolume( + Form("rec_%d", mNLayer), rec, + gGeoManager->GetMedium(material::MaterialNames[material::DeadZone])); + recVol->SetLineColor(rec::color); + recVol->RegisterYourself(); + if (mVerbose) { + std::cout << "REC:" << std::endl; + recVol->InspectShape(); + recVol->InspectMaterial(); } - subFoamNames += Form("subfoam2layer%d+", mLayerNumber); - subFoamNames += Form("subfoam3layer%d", mLayerNumber); + mSegment->AddNode(recVol, 0, zMoveREC); +} + +void ITS3Layer::createChip() +{ - TGeoCompositeShape* foam = new TGeoCompositeShape(subFoamNames.data()); - TGeoVolume* volFoam = new TGeoVolume(Form("CarbonFoam%d", mLayerNumber), foam, medCarbonFoam); - motherVolume->AddNode(volFoam, 1, nullptr); + // A HalfLayer is composed out of multiple segment stitched together along + // rphi. + mChip = new TGeoVolumeAssembly(Form("chip_%d", mNLayer)); + mChip->VisibleDaughters(); - if (mAddMaterial > 0.) { - TGeoTubeSeg* addMat = new TGeoTubeSeg(Form("additionalMaterialLayer%d", mLayerNumber), rmaxWoAddMat, rmax, mLengthSemiCircleFoam / 2, phiMin + phiGap, phiMax - phiGap); - TGeoVolume* volAddMat = new TGeoVolume(Form("AdditionalMaterial%d", mLayerNumber), addMat, medSi); - motherVolume->AddNode(volAddMat, 1, nullptr); + for (int i{0}; i < constants::nSegments[mNLayer]; ++i) { + double phiOffset = constants::segment::length / mRmin * constants::math::Rad2Deg; + auto rot = new TGeoRotation("", 0, 0, phiOffset * i); + mChip->AddNode(mSegment, i, rot); } } + +void ITS3Layer::createCarbonForm() +{ + mCarbonForm = new TGeoVolumeAssembly(Form("carbonform_%d", mNLayer)); + mCarbonForm->VisibleDaughters(); + mCarbonForm->AddNode(mChip, 0); + // TODO +} + +void ITS3Layer::createLayerImpl() +{ + // At long last a single layer... A layer is two HalfLayers (duuhhh) but + // we have to take care of the equatorial gap. So both half layers will be + // offset slightly by rotating in phi the upper HalfLayer and negative phi + // the other one. + mLayer = new TGeoVolumeAssembly(Form("layer_%d", mNLayer)); + mLayer->VisibleDaughters(); + + // The offset is the right angle triangle of the middle radius with the + // transverse axis. + double phiOffset = std::asin(constants::equatorialGap / mR) * constants::math::Rad2Deg; + // double phiOffset = constants::equatorialGap / mRmin / 2.; + auto rotTop = new TGeoRotation("", 0, 0, +phiOffset); + auto rotBot = new TGeoRotation("", 0, 0, phiOffset + 180); + + mLayer->AddNode(mCarbonForm, 0, rotTop); + mLayer->AddNode(mCarbonForm, 1, rotBot); +} +} // namespace o2::its3