Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ struct FT3BaseParam : public o2::conf::ConfigurableParamHelper<FT3BaseParam> {
Float_t etaOut = 1.5;
Float_t Layerx2X0 = 0.01;

// override values from FT3ModuleConstants, inner and outer
bool cutStavesOnNominalRadius_inner = true;
bool cutStavesOnNominalRadius_outer = true;

// What to place over x=0 line in case of full outer-outer stave: Gap or Sensor
bool placeSensorInMiddleOfStave = false;
// define tolerance allowed for staves to go outside nominal radii
double staveTolMLInner = 0.;
double staveTolMLOuter = 0.;
double staveTolOTInner = 0.;
double staveTolOTOuter = 0.;

// What to place over x=0 line in case of full outer-outer stave: Gap or Module
bool placeSensorStackInMiddleOfStave = false;

// Draw reference circles at inner and outer radius of stave layer, for visualisation
bool drawReferenceCircles = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
namespace o2::ft3::ModuleConstants
{
/* CURRENT STATUS:
* 25x32mm sensors, 2mm inactive on one side
* 25x29mm sensors, 2mm inactive on one side
* Most granular layout is 2x1 sensors, where the one on the right has the inactive region
* on the right, and the one on the left has the inactive region on the left.
* When stacking 2x1 modules, there is a 0.2mm gap between them. By default, we assume this
Expand All @@ -35,7 +35,7 @@ namespace o2::ft3::ModuleConstants
* | | | | |
* | | | | |
* | | | | |
* | | | | | 32mm sensor height
* | | | | | 29mm sensor height
* | | | | |
* | | | | |
* ------------------------
Expand Down Expand Up @@ -105,8 +105,9 @@ const int CuColor = kOrange;
const int kaptonColor = kYellow;
const int carbonFiberColor = kGray + 1;

// Struct for stave position configuration (varies between IT/OT)
// Struct for stave position configuration (varies between ML/OT)
struct StaveConfig {
const unsigned isML; // whether this config is for ML or OT
/*
* Constants for staves are written for both positive
* and negative x even though they are just mirrored now,
Expand All @@ -123,7 +124,10 @@ struct StaveConfig {
// lengths of staves, their midpoint, and their face
const std::vector<double>& y_lengths;
const std::vector<double>& x_midpoints;
double x_midpoint_spacing;
const double x_midpoint_spacing;
// whether staves can be placed outside of nominal radii
const double maxToleranceInner;
const double maxToleranceOuter;
// which side of the disc do we place the stave?
// kSegmentedStave: staggering staves in z (see z_offsetStave)
// accessed via stave index, NOT stave ID
Expand All @@ -149,6 +153,8 @@ const std::vector<double> x_midpoints = {
38.25, 42.75, 47.25, 51.75, 56.25, 60.75, 65.25 // R
};
const double x_midpoint_spacing = 4.5; // assume constant for now
const double maxToleranceInner = 0.; // default not allowed inwards
const double maxToleranceOuter = 3.4; // leave 1mm for layer air encapsulation
const std::vector<bool> staveOnFront =
{
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, // L
Expand All @@ -174,6 +180,8 @@ const std::vector<double> x_midpoints = {
2.25, 6.75, 11.25, 15.75, 20.25, 24.75, 29.25, 33.75 // R
};
const double x_midpoint_spacing = 4.5;
const double maxToleranceInner = 0.; // default not allowed inwards
const double maxToleranceOuter = 3.4; // leave 1mm for layer air encapsulation
const std::vector<bool> staveOnFront =
{
1, 0, 1, 0, 1, 0, 1, 0, // L
Expand All @@ -186,17 +194,23 @@ inline StaveConfig getStaveConfig(bool isInnerDisk)
{
if (isInnerDisk) {
return StaveConfig{
true, // isML
ML_StavePositions::staveID_to_y_midpoint,
ML_StavePositions::y_lengths,
ML_StavePositions::x_midpoints,
ML_StavePositions::x_midpoint_spacing,
ML_StavePositions::maxToleranceInner,
ML_StavePositions::maxToleranceOuter,
ML_StavePositions::staveOnFront};
} else {
return StaveConfig{
false, // isML
OT_StavePositions::staveID_to_y_midpoint,
OT_StavePositions::y_lengths,
OT_StavePositions::x_midpoints,
OT_StavePositions::x_midpoint_spacing,
OT_StavePositions::maxToleranceInner,
OT_StavePositions::maxToleranceOuter,
OT_StavePositions::staveOnFront};
}
}
Expand Down
4 changes: 3 additions & 1 deletion Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Layer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,9 @@ void FT3Layer::createLayer(TGeoVolume* motherVolume)

// shift stave volumes into layer volume, since nominal z_{stave face} = 0
double z_local_offset = z_layer_thickness / 2.0;
TGeoTube* layer = new TGeoTube(mInnerRadius - 0.2, mOuterRadius + 2.5, z_layer_thickness / 2); // margins to ensure staves are fully encapsulated in the layer volume
// ensure staves fully encapsulated in the layer volume,
// but don't cross out of max nominal radii of 38.5cm & 71.5cm respectively (3.5cm tolerance)
TGeoTube* layer = new TGeoTube(mInnerRadius - 0.2, mOuterRadius + 3.49, z_layer_thickness / 2);
layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir);

if (ft3Params.drawReferenceCircles) {
Expand Down
81 changes: 57 additions & 24 deletions Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,10 @@ std::pair<double, double> calculate_y_range(
* Rin: the inner radius of the layer
* x_left: the x position of the left edge of the sensor to be placed
* kSensorStack: the number of sensors to be stacked on top of each other
* tolerance: the tolerance to be subtracted from the maximum y position to avoid
* placing sensors too close to the edge. If this is negative, it effectively
* means that you can place sensors beyond the nominal disc edge
* y_start: the y positions to start placing sensors,
* for positive and negative y respectively
* y_ranges: the y positions to start and end placing sensors,
* for positive and negative y respectively
* absAllowedYRange: the absolute y range allowed for placing sensors,
* used to cut placement if they go past allowed tolerances
*/
void FT3Module::fill_stave(PosNegPositionTypes& y_positions, double Rin, double Rout,
double x_left, unsigned kSensorStack, PositionRangeType y_ranges,
Expand Down Expand Up @@ -550,7 +549,12 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction
unsigned volume_count = 0; // give each subvolume a unique ID
// stave triangle cross sections are the same for every stave (direction based)
std::array<std::array<double, 3>, 4> staveTriangles = buildStaveTriangle(direction);
// Create the stave volumes and fill the y positions where to put sensors on the stave
// declare vector with number of 2xn sensor stacks (modules) -- only used for logging
// each entry is a vector, where each entry is the number of modules of that stack height
std::vector<std::vector<unsigned>> nSensorStackCountPerStave(
staveConfig.x_midpoints.size(),
std::vector<unsigned>(Constants::kSensorsPerStack.size(), 0));
std::vector<unsigned> nSensorStackTotal(Constants::kSensorsPerStack.size(), 0);
for (unsigned i_stave = 0; i_stave < staveConfig.x_midpoints.size(); i_stave++) {
y_positionsPosNeg.emplace_back(PosNegPositionTypes{PositionTypes{}, PositionTypes{}});
const int staveID = Constants::staveIdxToID(i_stave, staveConfig.x_midpoints.size());
Expand All @@ -560,16 +564,21 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction
// default positive and negative starting points has a gap around x-axis for symmetry
double stave_half_length = staveConfig.y_lengths[i_stave] / 2;
PositionRangeType y_ranges;
if (ft3Params.placeSensorInMiddleOfStave) {
if (ft3Params.placeSensorStackInMiddleOfStave) {
/*
* We want a sensor to cross over the x-axis for coverage at y=0
* We want a sensor stack to cross over the x-axis for coverage at y=0
* N.B. not necessarily exactly mirrored, only if stack gap is the same
* as the gap between sensors in a stack.
* as the gap between sensors in a stack. Since we start filling with the
* first value in the kSensorsPerStack vector, we offset the first position
* by half of that.
*
* NOTE: TODO: in case the stave is too short to fit one full stack over the middle,
* then we will not be able to place anything since the bottom right/left point of
* the module will already be outside of acceptable bounds -- killing further placement.
*/
y_ranges = {{-Constants::sensor2x1_height / 2,
stave_half_length},
{-Constants::sensor2x1_height / 2 - Constants::stackGap,
-stave_half_length}};
double stackHeight = Constants::getStackHeight(Constants::kSensorsPerStack[0]);
y_ranges = {{-stackHeight / 2, stave_half_length},
{-stackHeight / 2 - Constants::stackGap, -stave_half_length}};
} else {
/*
* Otherwise have a gap around y=0, so sensors are not placed there.
Expand All @@ -588,23 +597,29 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction
}

// Define tolerances for cutting staves and placing sensors
double tolerance_inner = -1000; // large negative number to allow given numbers
double tolerance_outer = -1000;
double tolerance_inner, tolerance_outer;
if (staveConfig.isML) {
tolerance_inner = ft3Params.staveTolMLInner;
tolerance_outer = ft3Params.staveTolMLOuter;
} else {
tolerance_inner = ft3Params.staveTolOTInner;
tolerance_outer = ft3Params.staveTolOTOuter;
}
// cut staves on nominal inner radius if specified
if (ft3Params.cutStavesOnNominalRadius_inner) {
tolerance_inner = 0.;
if (tolerance_inner > staveConfig.maxToleranceInner) {
tolerance_inner = staveConfig.maxToleranceInner;
}
if (ft3Params.cutStavesOnNominalRadius_outer) {
tolerance_outer = 0.;
if (tolerance_outer > staveConfig.maxToleranceOuter) {
tolerance_outer = staveConfig.maxToleranceOuter;
}

/*
* There are three cases in which we want to mirror the stave around the x-axis,
* There are two cases in which we want to mirror the stave around the x-axis,
* which correspond to the stave not going fully from + to - Rout in y.
*
* (1) The inner tolerance is 0 (or positive)
* (1) The inner tolerance is 0 (or negative)
* a) AND either x_left or x_right lies within the inner radius
* (2) The inner tolerance is large (allow stave placement as wished)
* (2) The inner tolerance is large enough to allow stave placement as wished
* a) AND the given stave midpoint is above the inner radius
*/
double x_left = staveConfig.x_midpoints[i_stave] - Constants::sensor2x1_width / 2;
Expand All @@ -618,8 +633,8 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction
* that there is no lower limit. The upper limit must however be larger than 0,
* if it is not, then skip this stave and give a warning.
*/
absAllowedYRange.first += tolerance_inner;
absAllowedYRange.second -= tolerance_outer;
absAllowedYRange.first -= tolerance_inner;
absAllowedYRange.second += tolerance_outer;

if (absAllowedYRange.first < 0) {
absAllowedYRange.first = 0;
Expand All @@ -637,6 +652,8 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction
std::string stave_volume_name =
"Stave_" + std::to_string(i_stave) + "_" + std::to_string(layerNumber) +
"_" + std::to_string(direction);

// Create the stave volumes and fill the y positions where to put sensors on the stave
addStaveVolume(
motherVolume, stave_volume_name, direction, &volume_count,
staveConfig.y_lengths[i_stave], staveTriangles, absAllowedYRange,
Expand All @@ -651,11 +668,27 @@ void FT3Module::create_layout_staveGeo(double mZ, int layerNumber, int direction

// now add the sensor positions on the stave
for (unsigned i_kSens = 0; i_kSens < Constants::kSensorsPerStack.size(); i_kSens++) {
unsigned nModulesCurr = y_positionsPosNeg.back().first.size() + y_positionsPosNeg.back().second.size();
fill_stave(y_positionsPosNeg.back(), Rin, Rout, x_left,
Constants::kSensorsPerStack[i_kSens], y_ranges,
absAllowedYRange);
unsigned nModulesAdded = y_positionsPosNeg.back().first.size() + y_positionsPosNeg.back().second.size() - nModulesCurr;
nSensorStackCountPerStave[i_stave][i_kSens] = nModulesAdded;
nSensorStackTotal[i_kSens] += nModulesAdded;
}
std::string moduleDebugStr = "Module size counts for layer " + std::to_string(layerNumber) + " in direction " + std::to_string(direction) + ":\n";
for (unsigned i_kSens = 0; i_kSens < Constants::kSensorsPerStack.size(); i_kSens++) {
moduleDebugStr += "\t" + std::to_string(nSensorStackCountPerStave[i_stave][i_kSens]) + " modules with " + std::to_string(Constants::kSensorsPerStack[i_kSens]) + " sensors stacked\n";
}
LOG(debug) << moduleDebugStr;
}
std::string totalModuleInfoStr =
"Total module size counts for layer " + std::to_string(layerNumber) +
" in direction " + std::to_string(direction) + ":\n";
for (unsigned i_kSens = 0; i_kSens < Constants::kSensorsPerStack.size(); i_kSens++) {
totalModuleInfoStr += "\t" + std::to_string(nSensorStackTotal[i_kSens]) + " modules with " + std::to_string(Constants::kSensorsPerStack[i_kSens]) + " sensors stacked\n";
}
LOG(info) << totalModuleInfoStr;

// Create volumes for the sensors and the support materials on top of the stave
for (unsigned i_stave = 0; i_stave < staveConfig.x_midpoints.size(); i_stave++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ void TRKServices::createMLServicesPeacock(TGeoVolume* motherVolume)
motherVolume->AddNode(middleBarrelCarbonSupportVolume, 1, nullptr);

// Get geometry information from TRK which is already present
float rMinMiddleServices = 38.0f; // cm, start radius of the ML services = maximum radius allowed for sensors (35 cm), plus some margin for disk paving with modules
float rMinMiddleServices = 38.5f; // cm, start radius of the ML services = maximum radius allowed for sensors (35 cm), plus some margin for disk paving with modules
const float zMiddleServicesBarrel = 64.5f; // cm, z position of the first barrel ML service disk
const float zMiddleServicesBarrelFwdConnection = 143.f; // cm, z position of barrel to forward connection services
const float zLengthCylinderMiddleServicesBarrel = zMiddleServicesBarrelFwdConnection - zMiddleServicesBarrel;
Expand Down