diff --git a/Detectors/Upgrades/ALICE3/TRKFT3/TRK/README.md b/Detectors/Upgrades/ALICE3/TRKFT3/TRK/README.md index 71bbce74dcbb4..a1d89292be1d5 100644 --- a/Detectors/Upgrades/ALICE3/TRKFT3/TRK/README.md +++ b/Detectors/Upgrades/ALICE3/TRKFT3/TRK/README.md @@ -68,7 +68,9 @@ Both layouts use the same configuration-file syntax (only the OT geometry implem **Middle Layers (ML) - Indices 0 to 4** The first 5 valid lines are parsed as `TRKMLLayer` objects. These layers **require** a 6th parameter for the staggering offset (`stagOffset`). -* **Format:** `rInn` \t `thick` \t `tiltAngle` \t `nStaves` \t `nMods` \t `stagOffset` \t `[optional_mode]` +* **Format:** `rInn` \t `thick` \t `tiltAngle` \t `nStaves` \t `nMods` \t `stagOffset` \t `[optional_mode]` \t `[optional_rInnRow]` \t `[optional_phiOffset]` +* Layers 3 and 4 are staggered: one stave out of two sits at `rInn`, the others are shifted by `stagOffset`. By default the even staves are at `rInn`; `rInnRow` = 1 puts the odd staves there instead, i.e. stave 0 in the shifted row. In the flipped layer 3 the `rInn` row is the outer one and the shift points inwards, so there `rInnRow` = 1 puts stave 0 in the inner row; in layer 4 in the outer row. To give `rInnRow`, the mode column must be written too. +* `phiOffset` (degrees, counterclockwise, default 0) rotates the whole layer about the beam axis; each stave keeps its tilt. It requires the mode and `rInnRow` columns. **Outer Layers (OT) - Indices 5 and above** From the 6th valid line onwards, lines are parsed as OT layer objects (`TRKOTLayer` for `kSegmented`, `TRKOTLayerRealistic` for `kSimplifiedRealistic`). These layers do **not** have a staggering offset. The optional mode parameter shifts to the 6th column. diff --git a/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/include/TRKSimulation/TRKLayer.h b/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/include/TRKSimulation/TRKLayer.h index a533bd1066b41..4875207ea7397 100644 --- a/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/include/TRKSimulation/TRKLayer.h +++ b/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/include/TRKSimulation/TRKLayer.h @@ -111,7 +111,7 @@ class TRKMLLayer : public TRKSegmentedLayer { public: TRKMLLayer() = default; - TRKMLLayer(int layerNumber, std::string layerName, float rInn, float staggerOffset, float tiltAngle, int numberOfStaves, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode); + TRKMLLayer(int layerNumber, std::string layerName, float rInn, float staggerOffset, float tiltAngle, int numberOfStaves, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode, int rInnRow = 0, float phiOffset = 0.f); ~TRKMLLayer() override = default; TGeoVolume* createStave() override; @@ -121,6 +121,8 @@ class TRKMLLayer : public TRKSegmentedLayer TGeoVolume* createEndOfStaveCard(); // A-side (+z) end-of-stave card, in front of the conn disk float mStaggerOffset; + int mRInnRow = 0; // staggered layers: staves with iStave % 2 == mRInnRow sit at rInn, the others are shifted by the stagger offset + float mPhiOffset = 0.f; // deg, rotation of all the staves of the layer about the beam axis (counterclockwise, as phi) static constexpr double sStaveWidth = constants::ML::width; static constexpr int sFlippedLayerNumber = 3; diff --git a/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/Detector.cxx index bd34c9109f72b..f5d7c1c0c5cb9 100644 --- a/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/Detector.cxx @@ -225,6 +225,10 @@ void Detector::configFromFile(std::string fileName) // tmpBuff[4] = nMods // tmpBuff[5] = stagOffset (required ONLY for ML) // tmpBuff[6] = matBudgetMode (optional, default = Thickness) + // tmpBuff[7] = rInnRow (optional, ML only, default = 0): which staves of a staggered layer sit at + // rInn, 0 = even, 1 = odd (needs tmpBuff[6]); in the flipped layer the rInn row is the outer one + // tmpBuff[8] = phiOffset (optional, ML only, default = 0): rotation of all the staves of the layer about + // the beam axis, in degrees, counterclockwise as phi (needs tmpBuff[6] and tmpBuff[7]) // Base parameters for all segmented layers (at least 5 needed) if (tmpBuff.size() < 5) { @@ -250,8 +254,10 @@ void Detector::configFromFile(std::string fileName) if (tmpBuff.size() >= 7) { matBudgetMode = static_cast(static_cast(tmpBuff[6])); } + const int rInnRow = (tmpBuff.size() >= 8) ? static_cast(tmpBuff[7]) : 0; + const float phiOffset = (tmpBuff.size() >= 9) ? tmpBuff[8] : 0.f; - mLayers.push_back(std::make_unique(layerCount, name, rInn, stagOffset, tiltAngle, nStaves, nMods, thick, matBudgetMode)); + mLayers.push_back(std::make_unique(layerCount, name, rInn, stagOffset, tiltAngle, nStaves, nMods, thick, matBudgetMode, rInnRow, phiOffset)); } else { // OT layers do NOT have stagOffset. The optional mode is at index 5. if (tmpBuff.size() >= 6) { diff --git a/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/TRKLayer.cxx index eb33616f8e0db..7f1d06cc052cc 100644 --- a/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/TRKLayer.cxx @@ -233,9 +233,12 @@ std::pair TRKSegmentedLayer::getBoundingRadii(double staveWidth) c ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, float staggerOffset, float tiltAngle, int numberOfStaves, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode) - : TRKSegmentedLayer(layerNumber, layerName, rInn, tiltAngle, numberOfStaves, numberOfModules, thickOrX2X0, mode), mStaggerOffset(staggerOffset) +TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, float staggerOffset, float tiltAngle, int numberOfStaves, int numberOfModules, float thickOrX2X0, MatBudgetParamMode mode, int rInnRow, float phiOffset) + : TRKSegmentedLayer(layerNumber, layerName, rInn, tiltAngle, numberOfStaves, numberOfModules, thickOrX2X0, mode), mStaggerOffset(staggerOffset), mRInnRow(rInnRow), mPhiOffset(phiOffset) { + if (mPhiOffset != 0.f) { + LOGP(info, "Layer {}: staves rotated by {} deg about the beam axis (phiOffset)", mLayerNumber, mPhiOffset); + } if (mLayerNumber == sFlippedLayerNumber) { mOuterRadius = rInn; mInnerRadius = rInn - mChipThickness; @@ -243,6 +246,18 @@ TRKMLLayer::TRKMLLayer(int layerNumber, std::string layerName, float rInn, float mStaggerOffset = -staggerOffset; LOGP(info, "Layer {} is flipped: sensor and metal stack positions are switched", mLayerNumber); } + if (mRInnRow != 0 && mRInnRow != 1) { + LOGP(fatal, "Layer {}: rInnRow = {}, use 0 (even staves at rInn) or 1 (odd staves at rInn)", mLayerNumber, mRInnRow); + } + if (mRInnRow != 0) { + if (mLayerNumber == 3 || mLayerNumber == 4) { + // even staves (stave 0) go to the shifted row: inside the rInn row in the flipped layer, outside + // otherwise (stagOffset >= 0; a negative stagOffset is not handled by getBoundingRadii) + LOGP(info, "Layer {} (staggered): even staves in the {} row (rInnRow = {})", mLayerNumber, mIsFlipped ? "inner" : "outer", mRInnRow); + } else { + LOGP(info, "Layer {} is not staggered: rInnRow = {} has no effect", mLayerNumber, mRInnRow); + } + } } TGeoVolume* TRKMLLayer::createStave() @@ -336,13 +351,14 @@ void TRKMLLayer::createLayer(TGeoVolume* motherVolume) for (int iStave = 0; iStave < mNumberOfStaves; iStave++) { TGeoVolume* staveVol = createStave(); TGeoCombiTrans* trans = new TGeoCombiTrans(); - // If the number of staves is a multiple of 4, rotate by half a stave to avoid having the first one exactly on the x - double phi = (mNumberOfStaves % 4 == 0) ? theta * (iStave + 0.5) : theta * iStave; + // If the number of staves is a multiple of 4, rotate by half a stave to avoid having the first one exactly on the x; + // mPhiOffset rotates the whole layer (position and orientation of every stave) about the beam axis + double phi = ((mNumberOfStaves % 4 == 0) ? theta * (iStave + 0.5) : theta * iStave) + mPhiOffset * TMath::DegToRad(); double phiDeg = phi * TMath::RadToDeg(); TGeoRotation* rot = new TGeoRotation("rot", phiDeg + 90 + mTiltAngle, 0, 0); trans->SetRotation(rot); // float trueRadius = (mLayerNumber == 3 || mLayerNumber == 4) ? (iStave % 2 == 0 ? mInnerRadius : mInnerRadius + mStaggerOffset) : mInnerRadius; - float trueRadius = (mLayerNumber == 3 || mLayerNumber == 4) ? (iStave % 2 == 0 ? avgRadiusInner : avgRadiusOuter) : avgRadiusInner; + float trueRadius = (mLayerNumber == 3 || mLayerNumber == 4) ? (iStave % 2 == mRInnRow ? avgRadiusInner : avgRadiusOuter) : avgRadiusInner; trans->SetTranslation(trueRadius * std::cos(phi), trueRadius * std::sin(phi), 0); LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); layerVol->AddNode(staveVol, iStave, trans);