Skip to content

Commit fc55be0

Browse files
committed
add staggered ITOF layout
1 parent 3233a67 commit fc55be0

4 files changed

Lines changed: 48 additions & 21 deletions

File tree

‎Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper<IOTOFBaseParam>
4949
bool enableOuterTOF = true; // Enable Outer TOF layer
5050
bool enableForwardTOF = false; // Enable Forward TOF layer
5151
bool enableBackwardTOF = false; // Enable Backward TOF layer
52+
bool itofTurbo = true; // Segmented ITOF turbo or staggered
5253
std::string detectorPattern = ""; // Layouts of the detector
5354
bool segmentedInnerTOF = true; // If the inner TOF layer is segmented
5455
bool segmentedOuterTOF = true; // If the outer TOF layer is segmented

‎Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class Layer
4242
static constexpr int kDisk = 1;
4343
static constexpr int kBarrelSegmented = 2;
4444
static constexpr int kDiskSegmented = 3;
45+
static constexpr int kBarrelStaggered = 4;
4546

4647
virtual void createLayer(TGeoVolume* motherVolume) {};
4748

@@ -74,6 +75,8 @@ class ITOFLayer : public Layer
7475
virtual void createLayer(TGeoVolume* motherVolume) override;
7576
static std::vector<std::string> mRegister;
7677

78+
static const double sStaggerRadialShift;
79+
7780
private:
7881
};
7982

‎Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ void Detector::configLayers(bool itof, bool otof, bool ftof, bool btof, std::str
130130
const double staveTiltAngle = itofSegmented ? iotofPars.itofStaveTilt : 0.0; // degrees
131131
const int modulesPerStave = itofSegmented ? 7 : 0; // number of modules per stave in segmented case
132132
mITOFLayer = ITOFLayer(name,
133-
dInnerTof.first, 0.f, dInnerTof.second, 0.f, x2x0, itofSegmented ? ITOFLayer::kBarrelSegmented : ITOFLayer::kBarrel,
133+
dInnerTof.first, 0.f, dInnerTof.second, 0.f, x2x0, itofSegmented ? (iotofPars.itofTurbo ? ITOFLayer::kBarrelSegmented : ITOFLayer::kBarrelStaggered) : ITOFLayer::kBarrel,
134134
nStaves, staveWidth, staveTiltAngle, modulesPerStave, itofSegmented ? sensorThickness : 0.0f);
135135
}
136136
if (otof) { // oTOF

‎Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx‎

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ const double Layer::sChipGap = 200.e-4; // cm
3535
const double Layer::sModuleGap = 200.e-4; // cm
3636
const double Layer::sChipThickness = 300.e-4; // cm
3737

38+
const double ITOFLayer::sStaggerRadialShift = 0.4; // cm
39+
3840
const double OTOFLayer::sSubStavesDistanceY = 0.3; // cm
3941
const double OTOFLayer::sSubStavesOverlapX = 1.1; // cm
4042

@@ -54,10 +56,12 @@ Layer::Layer(std::string layerName, float rInn, float rOut, float zLength, float
5456
{
5557
const float Si_X0 = 9.5f; // cm, radiation length of silicon
5658
mLayerThickness = mX2X0 * Si_X0;
59+
const bool isSegmented = (layout == kBarrelSegmented || layout == kDiskSegmented || layout == kBarrelStaggered);
5760
std::string name = "";
5861
switch (layout) {
5962
case kBarrel:
6063
case kBarrelSegmented:
64+
case kBarrelStaggered:
6165
name = "barrel";
6266
mOuterRadius = mInnerRadius + mLayerThickness;
6367
break;
@@ -73,21 +77,28 @@ Layer::Layer(std::string layerName, float rInn, float rOut, float zLength, float
7377
if (mInnerRadius > mOuterRadius) {
7478
LOG(fatal) << "Invalid layer dimensions: rInner " << mInnerRadius << " cm is larger than rOuter " << mOuterRadius << " cm";
7579
}
76-
if ((mStaves.first != 0 || mStaves.second != 0.0f) && (layout != kBarrelSegmented && layout != kDiskSegmented)) {
80+
if ((mStaves.first != 0 || mStaves.second != 0.0f) && !isSegmented) {
7781
LOG(fatal) << "Invalid configuration: number of segments " << mStaves.first << " is set for non-segmented layout " << layout;
7882
}
79-
if ((mStaves.first <= 1 || mStaves.second <= 0.0f) && (layout == kBarrelSegmented || layout == kDiskSegmented)) {
83+
if ((mStaves.first <= 1 || mStaves.second <= 0.0f) && isSegmented) {
8084
LOG(fatal) << "Invalid configuration: number of segments " << mStaves.first << " must be positive for segmented layout " << layout;
8185
}
82-
if (mModulesPerStave <= 0 && (layout == kBarrelSegmented || layout == kDiskSegmented)) {
86+
if (mModulesPerStave <= 0 && isSegmented) {
8387
LOG(fatal) << "Invalid configuration: number of sensors per segment " << mModulesPerStave << " must be positive for segmented layout " << layout;
8488
}
85-
if (std::abs(mTiltAngle) > 0.1 && (layout != kBarrelSegmented && layout != kDiskSegmented)) {
89+
if (std::abs(mTiltAngle) > 0.1 && !isSegmented) {
8690
LOG(fatal) << "Invalid configuration: tilt angle " << mTiltAngle << " is set for non-segmented layout " << layout;
8791
}
88-
if ((mTiltAngle < 0.0 || mTiltAngle > 90.0) && (layout == kBarrelSegmented || layout == kDiskSegmented)) {
92+
if ((mTiltAngle < 0.0 || mTiltAngle > 90.0) && isSegmented) {
8993
LOG(fatal) << "Invalid configuration: tilt angle " << mTiltAngle << " is too large, it must be between 0 and 90 degrees";
9094
}
95+
// Staggered and tilted ("turbo") layouts are alternatives
96+
if (layout == kBarrelStaggered && std::abs(mTiltAngle) > 1.e-6) {
97+
LOG(fatal) << "Invalid configuration: staggered layout requires tilt angle = 0, got " << mTiltAngle;
98+
}
99+
if (layout == kBarrelStaggered && (mStaves.first % 2) != 0) {
100+
LOG(fatal) << "Invalid configuration: staggered layout requires an even number of staves, got " << mStaves.first;
101+
}
91102
if (mSensorThickness < 0.0f || mSensorThickness > mLayerThickness) {
92103
LOG(fatal) << "Invalid configuration: sensor thickness " << mSensorThickness << " cm is out of range (0, " << mLayerThickness << ") cm";
93104
}
@@ -177,28 +188,38 @@ void ITOFLayer::createLayer(TGeoVolume* motherVolume)
177188
motherVolume->AddNode(layerVol, 1, nullptr);
178189
return;
179190
}
180-
case kBarrelSegmented: {
191+
case kBarrelSegmented:
192+
case kBarrelStaggered: {
193+
// kBarrelSegmented: staves tilted by mTiltAngle, all at the same radius ("turbo" layout)
194+
// kBarrelStaggered: untilted staves alternating between an inner and an outer radius
195+
const bool staggered = (mLayout == kBarrelStaggered);
196+
const double halfShift = staggered ? 0.5 * sStaggerRadialShift : 0.; // cm
197+
181198
// First we create the volume for the whole layer, which will be used as mother volume for the segments
182199
const double avgRadius = 0.5 * (mInnerRadius + mOuterRadius);
183200
const double staveSizeX = mStaves.second; // cm
184201
const double staveSizeY = mOuterRadius - mInnerRadius; // cm
185202
const double staveSizeZ = mZLength; // cm
186203

187-
// Build the mother layer tube from the exact inscribed/outscribed radii of a tilted stave rectangle.
204+
// Build the mother layer tube from the exact inscribed/circumscribed radii of the tilted stave rectangle.
205+
// For the staggered layout both the inner and the outer stave radii are taken into account.
188206
const double alpha = mTiltAngle * TMath::DegToRad();
189-
const double u0 = -avgRadius * std::cos(alpha);
190-
const double v0 = avgRadius * std::sin(alpha);
191-
const double uClamped = std::max(-0.5 * staveSizeY, std::min(0.5 * staveSizeY, u0));
192-
const double vClamped = std::max(-0.5 * staveSizeX, std::min(0.5 * staveSizeX, v0));
193-
const double radiusMin = std::hypot(uClamped - u0, vClamped - v0);
194-
195207
const double uCorners[4] = {-0.5 * staveSizeY, 0.5 * staveSizeY, 0.5 * staveSizeY, -0.5 * staveSizeY};
196208
const double vCorners[4] = {-0.5 * staveSizeX, -0.5 * staveSizeX, 0.5 * staveSizeX, 0.5 * staveSizeX};
209+
double radiusMin = 1.e10;
197210
double radiusMax = 0.0;
198-
for (int i = 0; i < 4; ++i) {
199-
radiusMax = std::max(radiusMax, std::hypot(uCorners[i] - u0, vCorners[i] - v0));
211+
for (const int s : {-1, 1}) {
212+
const double rStave = avgRadius + s * halfShift;
213+
const double u0 = -rStave * std::cos(alpha);
214+
const double v0 = rStave * std::sin(alpha);
215+
const double uClamped = std::max(-0.5 * staveSizeY, std::min(0.5 * staveSizeY, u0));
216+
const double vClamped = std::max(-0.5 * staveSizeX, std::min(0.5 * staveSizeX, v0));
217+
radiusMin = std::min(radiusMin, std::hypot(uClamped - u0, vClamped - v0));
218+
for (int i = 0; i < 4; ++i) {
219+
radiusMax = std::max(radiusMax, std::hypot(uCorners[i] - u0, vCorners[i] - v0));
220+
}
200221
}
201-
TGeoTube* layer = new TGeoTube(radiusMin, radiusMax, mZLength / 2); // cm, small margins to ensure staves are fully encapsulated in the layer volume
222+
TGeoTube* layer = new TGeoTube(radiusMin, radiusMax, mZLength / 2); // cm, encapsulates all staves
202223
TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir);
203224
setLayerStyle(layerVol);
204225

@@ -246,15 +267,17 @@ void ITOFLayer::createLayer(TGeoVolume* motherVolume)
246267
for (int i = 0; i < mStaves.first; ++i) {
247268
LOGP(info, "iTOF: Creating stave {}/{} for layer {}", i + 1, mStaves.first, layerVol->GetName());
248269
const double phi = TMath::TwoPi() * i / mStaves.first;
249-
const double x = avgRadius * TMath::Cos(phi);
250-
const double y = avgRadius * TMath::Sin(phi);
270+
// staggered: even staves on the inner radius, odd staves on the outer radius
271+
const double rStave = avgRadius + (staggered ? ((i % 2 == 0) ? -halfShift : halfShift) : 0.);
272+
const double x = rStave * TMath::Cos(phi);
273+
const double y = rStave * TMath::Sin(phi);
251274
auto* rotation = new TGeoRotation(Form("segmentRot%d", i + 1), phi * TMath::RadToDeg() + 90 + mTiltAngle, 0, 0);
252275
auto* transformation = new TGeoCombiTrans(x, y, 0, rotation);
253276

254-
LOGP(info, "Inserting Barrel {} in {} ", chipVol->GetName(), layerVol->GetName());
277+
LOGP(info, "Inserting Barrel {} in {} ", staveVol->GetName(), layerVol->GetName());
255278
layerVol->AddNode(staveVol, 1 + i, transformation);
256279
}
257-
LOGP(info, "Inserting Barrel {} in {} at r={} cm", layerVol->GetName(), motherVolume->GetName(), avgRadius);
280+
LOGP(info, "Inserting Barrel {} in {} at r={} cm{}", layerVol->GetName(), motherVolume->GetName(), avgRadius, staggered ? " (staggered)" : "");
258281
motherVolume->AddNode(layerVol, 1, nullptr);
259282
return;
260283
}

0 commit comments

Comments
 (0)