Skip to content

Commit d4bd7ef

Browse files
altsybeeIgor Altsybeev
andauthored
simple EoS cards for disks (#15905)
Co-authored-by: Igor Altsybeev <Igor.Altsybeev@cern.ch>
1 parent 9c88580 commit d4bd7ef

6 files changed

Lines changed: 158 additions & 5 deletions

File tree

‎Detectors/Upgrades/ALICE3/TRKFT3/FT3/base/include/FT3Base/FT3BaseParam.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ struct FT3BaseParam : public o2::conf::ConfigurableParamHelper<FT3BaseParam> {
5757
// Draw reference circles at inner and outer radius of stave layer, for visualisation
5858
bool drawReferenceCircles = false;
5959

60+
// Copper per plane [cm] in the disk end-of-stave cards; drives the card x/X0.
61+
// Defaults match o2::ft3::ModuleConstants::eosCard{OT,ML}.copperThickness.
62+
float ft3EosCardCuThicknessOT = 0.0122f; // Large (OT) disks
63+
float ft3EosCardCuThicknessML = 0.0122f; // Small (ML) disks
64+
bool addDiskEosCards = true; // add EoS cards to the stave-geometry disks
65+
6066
O2ParamDef(FT3BaseParam, "FT3Base");
6167
};
6268

‎Detectors/Upgrades/ALICE3/TRKFT3/FT3/simulation/include/FT3Simulation/FT3Materials.h‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ enum class MaterialID : unsigned {
4949
Epoxy,
5050
Aluminum,
5151
Foam,
52-
Water
52+
Water,
53+
FR4
5354
};
5455

5556
// Transport parameters of a medium, in the order expected by Detector::Medium()
@@ -108,7 +109,10 @@ inline const std::unordered_map<MaterialID, MaterialProperties> materials = {
108109
// Carbon foam core of the disk separation layer
109110
{MaterialID::Foam, {"Foam", kBlack, 0.17f, 0.0f, 0.0f, 0, {12.0107f}, {6.0f}, {}, passiveTracking}},
110111
// Coolant inside the kapton pipes
111-
{MaterialID::Water, {"Water", kBlue, 1.064f, 0.0f, 0.0f, 0, {18.01528f}, {8.0f}, {}, passiveTracking}}};
112+
{MaterialID::Water, {"Water", kBlue, 1.064f, 0.0f, 0.0f, 0, {18.01528f}, {8.0f}, {}, passiveTracking}},
113+
// FR4 board of the disk end-of-stave cards: 60% glass (SiO2) + 40% epoxy by
114+
// weight -> Si, O, C, H ; rho = 1.85 g/cm3 (same recipe as the TRK barrel)
115+
{MaterialID::FR4, {"FR4", kGreen + 3, 1.85f, 0.0f, 0.0f, 4, {28.0855f, 15.9994f, 12.0107f, 1.00794f}, {14.0f, 8.0f, 6.0f, 1.0f}, {0.2804f, 0.3836f, 0.3040f, 0.0320f}, passiveTracking}}};
112116
// The inactive rim of a sensor is made of silicon as well, but is drawn
113117
// separately so that it can be told apart from the active area.
114118
const int SiInactiveColor = kRed;

‎Detectors/Upgrades/ALICE3/TRKFT3/FT3/simulation/include/FT3Simulation/FT3Module.h‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ class FT3Module
8484
double z_offset_to_carbon_face, std::pair<double, double>& absAllowedYRange,
8585
double y_midpoint, bool mirrorStaveAroundX, unsigned* staveVolumeCount);
8686

87+
// FR4 + Cu end-of-stave card at the outer-radius tip of a disk stave. One card
88+
// per stave tip, placed downstream of the stave (away from the IP), in front of
89+
// the connection disk. Dimensions from Constants::getEosCardParams(isML).
90+
void addEndOfStaveCard(
91+
TGeoVolume* motherVolume, const std::string& name, int direction,
92+
unsigned volume_count, double x_mid, double y_tip, double z_sensor,
93+
bool isML, double cuThickness);
94+
8795
// Helper functions
8896
void fill_stave_greedy(
8997
PosNegPositionTypes& y_positions, unsigned kSensorStack,

‎Detectors/Upgrades/ALICE3/TRKFT3/FT3/simulation/include/FT3Simulation/FT3ModuleConstants.h‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,39 @@ inline StaveConfig getStaveConfig(bool isInnerDisk)
309309
}
310310
}
311311

312+
// ---------------------------------------------------------------------------
313+
// End-of-stave (EoS) readout cards at the outer-radius tips of the disk staves.
314+
// Same construction as the TRK barrel cards: an FR4 board carrying evenly spaced
315+
// copper planes. Separate parameter sets for the Small (ML/inner) and Large (OT)
316+
// disks. All lengths in cm. Local card axes at the outer stave tip:
317+
// length -> along beam z, width -> along stave width, thickness -> stave axis.
318+
struct EosCardParams {
319+
double length; // along beam z
320+
double width; // along stave width
321+
double thickness; // along stave axis (radial at the tip): FR4 + Cu planes
322+
int nCopperLayers; // copper planes, spread over the thickness
323+
double copperThickness; // per copper plane (default of the FT3Base Cu knob)
324+
double zGap; // clearance from the stave's downstream face
325+
};
326+
// NOTE on width: a card spanning the full z-range must be narrower than the
327+
// clearance to the staggered neighbour stave, whose carbon triangle is
328+
// staveWidth/2 (= 2.61 cm) half-wide: half-width < x_midpoint_spacing - staveWidth/2.
329+
// That is tightest on the ML disks (4.5 - 2.61 = 1.89 cm), so width = 3.4 cm
330+
// (half 1.7 cm) clears both ML and OT (OT spacing 4.92 cm) neighbours.
331+
// Large (OT) disks
332+
constexpr EosCardParams eosCardOT{12.0, 3.4, 0.15, 4, 0.0122, 0.2};
333+
// Small (ML) disks
334+
constexpr EosCardParams eosCardML{8.0, 3.4, 0.15, 4, 0.0122, 0.2};
335+
inline const EosCardParams& getEosCardParams(bool isML) { return isML ? eosCardML : eosCardOT; }
336+
337+
// Downstream half-length (beam z) that the disk layer envelope must gain to
338+
// contain the EoS cards (card body + clearance + a small margin).
339+
inline double eosCardEnvelopeExtension(bool isML)
340+
{
341+
const EosCardParams& c = getEosCardParams(isML);
342+
return c.zGap + c.length + 0.2;
343+
}
344+
312345
} // namespace o2::ft3::ModuleConstants
313346

314347
#endif // FT3MODULECONSTANTS_H

‎Detectors/Upgrades/ALICE3/TRKFT3/FT3/simulation/src/FT3Layer.cxx‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,9 +427,26 @@ void FT3Layer::createLayer(TGeoVolume* motherVolume)
427427
double innerRadiusForAirTube = mIsMiddleLayer ? mInnerRadius : mInnerRadius - 9.0;
428428
double outerRadiusForAirTube = mIsMiddleLayer ? mOuterRadius + 2.5 : mOuterRadius + 3.0;
429429
// MvL: try 70.5 // 2.5 cm tolerance instead
430-
TGeoTube* layer = new TGeoTube(innerRadiusForAirTube - 0.2, outerRadiusForAirTube,
431-
z_layer_thickness / 2);
432-
layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir);
430+
const double rInEnv = innerRadiusForAirTube - 0.2;
431+
const double rOutEnv = outerRadiusForAirTube;
432+
const double H0 = z_layer_thickness / 2;
433+
if (ft3Params.addDiskEosCards) {
434+
// Extend the envelope DOWNSTREAM only (away from the IP) with a union, so the
435+
// end-of-stave cards fit without growing toward the IP / the neighbouring disk.
436+
const double ext = o2::ft3::ModuleConstants::eosCardEnvelopeExtension(mIsMiddleLayer);
437+
const double s = (mDirection == 1) ? 1.0 : -1.0; // downstream sign
438+
TGeoTube* baseTube = new TGeoTube((mLayerName + "_base").c_str(), rInEnv, rOutEnv, H0);
439+
TGeoTube* extTube = new TGeoTube((mLayerName + "_eosext").c_str(), rInEnv, rOutEnv, ext / 2);
440+
TGeoTranslation* extTr = new TGeoTranslation((mLayerName + "_eosext_tr").c_str(), 0, 0, s * (H0 + ext / 2));
441+
extTr->RegisterYourself();
442+
TGeoCompositeShape* layerShape = new TGeoCompositeShape(
443+
(mLayerName + "_env").c_str(),
444+
Form("%s + %s:%s", baseTube->GetName(), extTube->GetName(), extTr->GetName()));
445+
layerVol = new TGeoVolume(mLayerName.c_str(), layerShape, medAir);
446+
} else {
447+
TGeoTube* layer = new TGeoTube(rInEnv, rOutEnv, H0);
448+
layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir);
449+
}
433450

434451
if (ft3Params.drawReferenceCircles) {
435452
std::string referenceCirclesName = "ReferenceCircles_Dir" + std::to_string(mDirection) + "_Layer" + std::to_string(mLayerNumber);

‎Detectors/Upgrades/ALICE3/TRKFT3/FT3/simulation/src/FT3Module.cxx‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,50 @@ bool staveMidpointAndMirror(const Constants::StaveConfig& staveConfig, int stave
479479
return true;
480480
}
481481

482+
/*
483+
* FR4 + Cu end-of-stave card at the outer-radius tip of a disk stave.
484+
* Mirrors the TRK barrel card: an FR4 board with evenly spaced copper planes.
485+
* Local card axes in the (layer) mother frame: x = stave width, y = stave axis
486+
* (radial at the tip), z = beam. The card sits downstream of the stave (away
487+
* from the IP), just past the disk envelope, in front of the connection disk.
488+
*/
489+
void FT3Module::addEndOfStaveCard(
490+
TGeoVolume* motherVolume, const std::string& name, int direction,
491+
unsigned volume_count, double x_mid, double y_tip, double z_sensor,
492+
bool isML, double cuThickness)
493+
{
494+
const Constants::EosCardParams& c = Constants::getEosCardParams(isML);
495+
if (cuThickness * c.nCopperLayers >= c.thickness) {
496+
LOG(fatal) << "FT3 disk EoS card: Cu " << cuThickness << " cm x " << c.nCopperLayers
497+
<< " planes does not fit in the " << c.thickness << " cm card";
498+
}
499+
500+
// FR4 board (x = width, y = thickness, z = length)
501+
TGeoVolume* cardVol = gGeoManager->MakeBox(name.c_str(), getMedium(Materials::MaterialID::FR4),
502+
c.width / 2, c.thickness / 2, c.length / 2);
503+
cardVol->SetLineColor(kGreen + 3);
504+
505+
// copper planes spread over the thickness (y), outermost two flush with the faces
506+
TGeoVolume* planeVol = gGeoManager->MakeBox((name + "_Cu").c_str(), getMedium(Materials::MaterialID::Copper),
507+
c.width / 2, cuThickness / 2, c.length / 2);
508+
planeVol->SetLineColor(kOrange + 7);
509+
const double span = c.thickness - cuThickness;
510+
for (int i = 0; i < c.nCopperLayers; ++i) {
511+
const double y = (c.nCopperLayers > 1) ? -span / 2 + i * span / (c.nCopperLayers - 1) : 0.;
512+
cardVol->AddNode(planeVol, i, new TGeoTranslation(0, y, 0));
513+
}
514+
515+
// z: IP-facing edge starts just after the sensors (z_sensor), body extends
516+
// downstream (away from the IP), toward the connection disk.
517+
// y: sit just radially OUTSIDE the stave outer tip so the long card runs past
518+
// the carbon stave along z without overlapping it.
519+
const double s = (direction == 1) ? 1.0 : -1.0; // downstream sign
520+
const double zCard = z_sensor + s * (c.zGap + c.length / 2);
521+
const double yClear = 0.05; // radial clearance to the stave tip
522+
const double yCard = y_tip + (y_tip >= 0 ? 1.0 : -1.0) * (c.thickness / 2 + yClear);
523+
motherVolume->AddNode(cardVol, volume_count, new TGeoTranslation(x_mid, yCard, zCard));
524+
}
525+
482526
/*
483527
* Create the carbon shell of one stave, staggered in z, plus the mirrored one
484528
* when the stave is built as two pieces.
@@ -509,6 +553,47 @@ void FT3Module::add_stave_volumes(
509553
staveConfig.y_lengths[i_stave], staveTriangles, absAllowedYRange,
510554
staveConfig.x_midpoints[i_stave], -y_midpoint, z_stave_shift_forward);
511555
}
556+
557+
// End-of-stave card at the outer-radius tip of each stave PIECE, placed
558+
// downstream of the stave in front of the connection disk. A whole stave gets
559+
// one card (the +y "top" tip). A split stave is built as two pieces (main +
560+
// mirror), each reaching the outer radius at opposite ends, so each piece gets
561+
// its own card at its outer tip (+y for the main, -y for the mirror).
562+
// Shared by the exact and greedy paths; the disk layer envelope is extended
563+
// downstream in FT3Layer::createLayer to contain the cards.
564+
auto& ft3Params = o2::ft3::FT3BaseParam::Instance();
565+
if (ft3Params.addDiskEosCards) {
566+
const bool isML = staveConfig.isML;
567+
const double cuT = isML ? ft3Params.ft3EosCardCuThicknessML : ft3Params.ft3EosCardCuThicknessOT;
568+
// Actual outer-radius tip of the stave: greedy clamps the stave to
569+
// absAllowedYRange.second, exact leaves it unbounded (DBL_MAX), so take the
570+
// smaller of the geometric end and the radial clamp.
571+
const double yTip = std::min(y_midpoint + staveConfig.y_lengths[i_stave] / 2,
572+
absAllowedYRange.second);
573+
// Per-stave sensor silicon z in the layer frame, reconstructed from the
574+
// carbon-face offset exactly as the sensor-placement loop does, so the card
575+
// starts right after the sensors.
576+
const double z_offset_to_silicon = z_offset_to_carbon_face +
577+
Constants::epoxyThickness + Constants::kaptonThickness +
578+
Constants::copperThickness + Constants::epoxyThickness +
579+
Constants::siliconThickness / 2;
580+
const double zOffMult = (direction == 1) ? -1.0 : 1.0;
581+
double zStaveShiftSensors = 0.0;
582+
if (!staveConfig.staveOnFront[i_stave]) {
583+
zStaveShiftSensors = (direction == 1) ? Constants::z_offsetStave(staveConfig.x_midpoint_spacing)
584+
: -Constants::z_offsetStave(staveConfig.x_midpoint_spacing);
585+
}
586+
const double zSensor = z_offset_to_silicon * zOffMult + zStaveShiftSensors;
587+
const std::string cardBase = "FT3_EOSdiskCard_" + std::to_string(direction) + "_" +
588+
std::to_string(layerNumber) + "_" + std::to_string(i_stave);
589+
addEndOfStaveCard(motherVolume, cardBase + "_pos", direction, (*staveVolumeCount)++,
590+
staveConfig.x_midpoints[i_stave], +yTip, zSensor, isML, cuT);
591+
// split stave: the mirror piece reaches the outer radius at -y, give it a card too
592+
if (mirrorStaveAroundX) {
593+
addEndOfStaveCard(motherVolume, cardBase + "_neg", direction, (*staveVolumeCount)++,
594+
staveConfig.x_midpoints[i_stave], -yTip, zSensor, isML, cuT);
595+
}
596+
}
512597
}
513598

514599
/*

0 commit comments

Comments
 (0)