Skip to content

Commit ab6e1c2

Browse files
bulukutluclaude
andauthored
[ALICE3] TRK update: New radii for the simplified-realistic OT paving (#16009)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent f98960a commit ab6e1c2

5 files changed

Lines changed: 30 additions & 21 deletions

File tree

‎Detectors/Upgrades/ALICE3/TRKFT3/TRK/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ The first 5 valid lines are parsed as `TRKMLLayer` objects. These layers **requi
7575
**Outer Layers (OT) - Indices 5 and above**
7676
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.
7777
* **Format:** `rInn` \t `thick` \t `tiltAngle` \t `nStaves` \t `nMods` \t `[optional_mode]`
78-
* *(Note: for `kSimplifiedRealistic`, `nStaves` is recomputed internally from the average radius and stave width to guarantee the neighbour overlap; the value in the file is ignored for the OT.)*
78+
* *(Note: for `kSimplifiedRealistic`, `nStaves` is the number of staves per ring and must be even; if it is 0 the count is derived from the radius as the smallest one giving the required neighbour overlap.)*
7979

8080
**Example for `kSegmented`:**
8181

@@ -113,7 +113,7 @@ The geometry specification is based on [ALICE3 OT WP1 Material (26.06.2025)](htt
113113

114114
**End-of-stave card** — one readout PCB per stave (`constants::OT::eosCard`), mounted past the last module at the outer z end, coplanar with the two rows: a 120 × 80 mm, 1.5 mm board carrying four copper planes spread symmetrically through the thickness, the remainder FR4. The copper is what sets the card material budget: at the default 122 µm per plane the card is **4.0 % x/X₀** for a track crossing it perpendicularly (copper 3.40 %, FR4 0.60 %). It is tunable through `TRKBase.otEosCardCuThickness`, which changes only the copper/FR4 split inside the fixed 1.5 mm envelope, so the card dimensions and the layer envelopes stay put and only the radiation length moves. The cards reach |z| ≈ 141 cm, just short of the OT barrel service disk, which places them at |η| ≈ 1.84–1.88 on the innermost OT layer and |η| ≈ 1.27–1.32 on the outermost — inside the tracking acceptance, so they matter for forward-disk performance.
115115

116-
**Barrel** — each layer is built in **four parts**: two z-half-barrels (±η), each split azimuthally into two 180° halves. Both η half-barrels are cut on the **same vertical plane** (x = 0), so the region where the vertical beam-pipe supports run is free of staves over the whole barrel (the supports themselves are not in the geometry). Neighbouring staves overlap (≥ 1 mm active double-coverage); at the cut plane the two azimuthal halves instead leave a gap wide enough for the separation wall plus `barrelWallClearance` on each side. The stave count is the smallest even number that still meets the required overlap at the layer radius, so the OT radii (440, 615, 793 mm) are chosen at the top of a stave-count band, giving 30/42/54 staves per ring with 1.5-1.9 mm of overlap. The cooling pipe faces the larger radius on the inner two OT layers and the smaller radius on the flipped outer layer.
116+
**Barrel** — each layer is built in **four parts**: two z-half-barrels (±η), each split azimuthally into two 180° halves. Both η half-barrels are cut on the **same vertical plane** (x = 0), so the region where the vertical beam-pipe supports run is free of staves over the whole barrel (the supports themselves are not in the geometry). Neighbouring staves overlap (≥ 1 mm active double-coverage); at the cut plane the two azimuthal halves instead leave a gap wide enough for the separation wall plus `barrelWallClearance` on each side. The default paving uses OT radii 442, 620 and 820 mm with 30, 42 and 56 staves per ring (15/21/28 per quarter barrel); L9 and L10 follow the mechanical CAD, L8 is placed as close in as the 1 mm active-overlap requirement allows for 30 staves. This gives 8.4-9.0 mm of border-to-border neighbour overlap in the stave plane. Each module's FPC extends 2.1 mm beyond the chips for wire bonding (`constants::OT::fpc::wireBondMargin`). The cooling pipe faces the larger radius on the inner two OT layers and the smaller radius on the flipped outer layer.
117117

118118
**Separation walls** — the quarter barrels are closed on every side but the one carrying the end-of-stave cards (`TRKServices::createOTBarrelWalls`, `kPeacockv1` + `kSimplifiedRealistic`): radially by the ML/OT and outer carbon shells, azimuthally by a rectangular carbon fibre wall in the cut plane, and at mid-rapidity by a half disk at z = 0, one per quarter barrel.
119119

‎Detectors/Upgrades/ALICE3/TRKFT3/TRK/base/include/TRKBase/Specs.h‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,13 @@ constexpr int nModulesPerRow{11}; // mod
139139
constexpr double interModuleGap{0.2 * mm}; // z-gap between module FPCs
140140

141141
// Component dimensions of the simplified-realistic OT stave
142+
constexpr double interChipGap{0.2 * mm}; // gap between chips within a module
142143
namespace fpc
143144
{
144-
constexpr double length{116.8 * mm}; // z-extent
145-
constexpr double width{52.2 * mm}; // phi-extent
146-
constexpr double thickness{0.200 * mm}; // r-extent, Kapton+Cu stack
145+
constexpr double wireBondMargin{2.1 * mm}; // FPC beyond the chips on each long side, for wire bonding
146+
constexpr double length{116.8 * mm}; // z-extent
147+
constexpr double width{2 * moduleMLOT::chip::width + interChipGap + 2 * wireBondMargin}; // phi-extent
148+
constexpr double thickness{0.200 * mm}; // r-extent, Kapton+Cu stack
147149
} // namespace fpc
148150
namespace coldPlate
149151
{
@@ -195,7 +197,6 @@ constexpr double zClearance{1.0 * mm}; // z-clearance to the nearest wall and t
195197
} // namespace supportRing
196198

197199
constexpr double sensorThickness{moduleMLOT::silicon::thickness}; // pure-silicon chip (no metal stack)
198-
constexpr double interChipGap{0.2 * mm}; // gap between chips within a module
199200
constexpr double rowActiveOverlap{1.0 * mm}; // active overlap between the two rows of a stave
200201
constexpr double rowRadialStagger{2.0 * mm}; // radial step between any two overlapping rows
201202
constexpr double halfBarrelChipGap{1.0 * mm}; // gap between the two azimuthal half-barrels

‎Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/include/TRKSimulation/TRKServices.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class TRKServices : public FairModule
6464
// Carbon fibre shells bounding the OT barrel in r; the separation walls span between them.
6565
static constexpr float sMLOTShellRMax = 39.5f; // cm, outer radius of the ML/OT separation shell
6666
static constexpr float sMLOTShellThickness = 0.2f; // cm
67-
static constexpr float sOTShellRMin = 82.0f; // cm, inner radius of the OT outer shell
67+
static constexpr float sOTShellRMin = 83.0f; // cm, inner radius of the OT outer shell
6868
static constexpr float sOTShellThickness = 0.4f; // cm, load bearing, hence thicker
6969

7070
// Vacuum

‎Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/Detector.cxx‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,12 @@ void Detector::configMLOT()
132132
const std::vector<int> nMods{11, 11, 11, 11, 11, 22, 22, 22};
133133
const std::vector<float> stagOffsets{0.f, 0.f, 0.f, 1.17f, 0.89f};
134134

135-
// OT radii chosen at the top of a stave-count band, where the paving closes with
136-
// ~1.5-1.9 mm of neighbour overlap; the outermost also clears TRKServices::sOTShellRMin.
135+
// OT: L9/L10 radii from the mechanical CAD, L8 at 442 mm; staves per ring (15/21/28 per quarter barrel)
137136
std::vector<float> rInnReal = rInn;
138-
rInnReal[constants::ML::nLayers + 0] = 44.0f;
139-
rInnReal[constants::ML::nLayers + 1] = 61.5f;
140-
rInnReal[constants::ML::nLayers + 2] = 79.3f;
141-
// OT counts are informational: TRKOTLayerRealistic derives its own from the radius.
142-
const std::vector<int> nStaves{10, 14, 18, 26, 38, 30, 42, 54};
137+
rInnReal[constants::ML::nLayers + 0] = 44.2f;
138+
rInnReal[constants::ML::nLayers + 1] = 62.0f;
139+
rInnReal[constants::ML::nLayers + 2] = 82.0f;
140+
const std::vector<int> nStaves{10, 14, 18, 26, 38, 30, 42, 56};
143141

144142
LOGP(warning, "Loading simplified-realistic configuration for ALICE3 TRK");
145143
for (int i{0}; i < constants::ML::nLayers + constants::OT::nLayers; ++i) {

‎Detectors/Upgrades/ALICE3/TRKFT3/TRK/simulation/src/TRKLayer.cxx‎

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ TGeoVolume* TRKOTLayerRealistic::createStave()
755755
// Two rows overlapping in phi and staggered in r. They straddle the stave origin, so the
756756
// stave is tangent to the barrel circle at its centre and every row-to-row radial step,
757757
// within a stave and between neighbours, is rowRadialStagger.
758-
const double edgeDead = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut;
758+
const double edgeDead = constants::OT::fpc::wireBondMargin + constants::moduleMLOT::chip::passiveEdgeReadOut;
759759
const double inStaveOverlap = 2 * edgeDead + constants::OT::rowActiveOverlap;
760760
const double rowOffset = constants::OT::fpc::width - inStaveOverlap;
761761

@@ -781,7 +781,7 @@ TGeoVolume* TRKOTLayerRealistic::createStave()
781781

782782
void TRKOTLayerRealistic::createLayer(TGeoVolume* motherVolume)
783783
{
784-
const double edgeDead = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut;
784+
const double edgeDead = constants::OT::fpc::wireBondMargin + constants::moduleMLOT::chip::passiveEdgeReadOut;
785785
const double inStaveOverlap = 2 * edgeDead + constants::OT::rowActiveOverlap;
786786
const double staveWidth = 2 * constants::OT::fpc::width - inStaveOverlap;
787787

@@ -828,19 +828,29 @@ void TRKOTLayerRealistic::createLayer(TGeoVolume* motherVolume)
828828
const double accGap = std::max(constants::OT::halfBarrelChipGap + 2 * constants::moduleMLOT::chip::passiveEdgeReadOut,
829829
2 * (wallThickness / 2 + constants::OT::barrelWallClearance + edgeDead));
830830

831-
// Smallest even count still leaving rowActiveOverlap between neighbours: the two boundary
832-
// staves take activeStaveWidth + accGap each, so only nStaves - 2 junctions share the rest.
831+
// Staves per ring: configured, or else the smallest even count leaving rowActiveOverlap between
832+
// neighbours (the two boundary staves take activeStaveWidth + accGap, nStaves - 2 junctions share the rest).
833833
const double activeStaveWidth = staveWidth - 2 * edgeDead;
834-
int nStavesHalfBarrel = (int)std::ceil(2. + (avgRadius * 2 * TMath::Pi() - 2 * (activeStaveWidth + accGap)) /
835-
(activeStaveWidth - constants::OT::rowActiveOverlap));
836-
nStavesHalfBarrel += nStavesHalfBarrel % 2;
834+
int nStavesHalfBarrel = mNumberOfStaves;
835+
if (nStavesHalfBarrel <= 0) {
836+
nStavesHalfBarrel = (int)std::ceil(2. + (avgRadius * 2 * TMath::Pi() - 2 * (activeStaveWidth + accGap)) /
837+
(activeStaveWidth - constants::OT::rowActiveOverlap));
838+
nStavesHalfBarrel += nStavesHalfBarrel % 2;
839+
}
840+
if (nStavesHalfBarrel % 2) {
841+
LOGP(fatal, "OT layer {}: {} staves per ring, must be even (two azimuthal halves)", mLayerNumber, nStavesHalfBarrel);
842+
}
837843

838844
const int nHalf = nStavesHalfBarrel / 2;
839845
const double thetaGap = (activeStaveWidth + accGap) / avgRadius;
840846
const double thetaInt = (2. * TMath::Pi() - 2. * thetaGap) / (nStavesHalfBarrel - 2);
841847
const double overlap = activeStaveWidth - avgRadius * thetaInt;
842848
LOGP(info, "Creating realistic OT layer {}: {} staves/half-barrel, internal overlap {} mm, boundary gap {} mm, flipped={}",
843849
mLayerNumber, nStavesHalfBarrel, overlap * 10, accGap * 10, mIsFlipped);
850+
if (overlap < constants::OT::rowActiveOverlap) {
851+
LOGP(warning, "OT layer {}: active neighbour overlap {} mm is below the required {} mm",
852+
mLayerNumber, overlap * 10, constants::OT::rowActiveOverlap * 10);
853+
}
844854

845855
const int nStaves = nStavesHalfBarrel * 2;
846856

0 commit comments

Comments
 (0)