Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3245748
Add separate file for constants in FT3 module creation
JustusRudolph Mar 26, 2026
59ebef3
Create modular design in similar fashion as before, but with slightly…
JustusRudolph Mar 26, 2026
e0c38f5
Give new geometry creation an FT3Layout enum and change Layer&Module …
JustusRudolph Mar 26, 2026
037580e
Add functionality for the user to enforce a strict cut on module plac…
JustusRudolph Mar 26, 2026
d76f582
Make forward and backward directions mirrored, front and back faces s…
JustusRudolph Mar 27, 2026
2983860
Add loop over all sensors in stack so all sensors are added to volume…
JustusRudolph Mar 27, 2026
e4539fb
Add constants for hollow stave based geometry
JustusRudolph Apr 7, 2026
c0b6b70
Add carbon fiber material, functionality to toggle between stave and …
JustusRudolph Apr 7, 2026
e5fd95e
Add full hollow stave geometry functionality
JustusRudolph Apr 7, 2026
c74d18e
Make Stave layout the standard and remove old kSegmentedMarch26: EDIT…
JustusRudolph Apr 7, 2026
7ea4b89
Remove all instances of old slab geometry and work only with staves.
JustusRudolph Apr 7, 2026
943541d
Remove all log(info) statements, except one which is changed to debug.
JustusRudolph Apr 7, 2026
fba45ba
Don't create the separation layer for stave layout, since we already …
JustusRudolph Apr 7, 2026
48934e7
add bools for cutting staves and sensors on staves on nominal radii
JustusRudolph Apr 9, 2026
88d69a0
merge two if statements with the same if
JustusRudolph Apr 9, 2026
948e308
Add implementations for cutting staves and sensors on nominal radii. …
JustusRudolph Apr 9, 2026
02284a8
Fix bug in default y range for staves & sensor placements
JustusRudolph Apr 9, 2026
99a136e
Bugfix: Stack correctly by using previous stack height in fill_stave,…
JustusRudolph Apr 10, 2026
03bf67c
Remove now stale info statements. TODO: let staves be cut as well on …
JustusRudolph Apr 10, 2026
f74b291
Add splitting of stave in case of strict inner cutoff
JustusRudolph Apr 13, 2026
9a93b25
Add support to place either a stack gap or single sensor around y=0 i…
JustusRudolph Apr 13, 2026
95d7c9b
Bugfix: When starting sensor placement around the x-axis you can have…
JustusRudolph Apr 14, 2026
94251b3
Add option to draw reference circles onto the layer -- strictly for v…
JustusRudolph Apr 14, 2026
6871f81
remove stale info statements
JustusRudolph Apr 14, 2026
6bb8039
Remove stale overlap argument, and add local offset in z. In contrast…
JustusRudolph Apr 15, 2026
dd38ee6
Fix placement issue to get sensor materials inside the volume. This n…
JustusRudolph Apr 15, 2026
5118265
Add OT only segmentation and change defaults
JustusRudolph Apr 28, 2026
8f131f8
Make stave geometry available with middle layer disks as well. Curren…
JustusRudolph Apr 28, 2026
a33fde3
Change default to stave segmentation for outer disks only
JustusRudolph Apr 28, 2026
0764ce0
Please consider the following formatting changes
alibuild Apr 28, 2026
87cb79c
Merge pull request #1 from alibuild/alibot-cleanup-15339
JustusRudolph Apr 29, 2026
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 @@ -24,10 +24,12 @@ enum eFT3Layout {
kCylindrical = 0,
kTrapezoidal,
kSegmented,
kSegmentedStave,
kSegmentedStaveOTOnly
};
struct FT3BaseParam : public o2::conf::ConfigurableParamHelper<FT3BaseParam> {
// Geometry Builder parameters
eFT3Layout layoutFT3 = kSegmented;
eFT3Layout layoutFT3 = kSegmentedStaveOTOnly;
int nTrapezoidalSegments = 32; // for the simple trapezoidal disks

// FT3Geometry::Telescope parameters
Expand All @@ -38,6 +40,16 @@ 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 = false;

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

// Draw reference circles at inner and outer radius of stave layer, for visualisation
bool drawReferenceCircles = false;

O2ParamDef(FT3BaseParam, "FT3Base");
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class FT3Layer : public TObject
// create layer for disk support
void createSeparationLayer(TGeoVolume* motherVolume, const std::string& separationLayerName);
void createSeparationLayer_waterCooling(TGeoVolume* motherVolume, const std::string& separationLayerName);
void createReferenceCircles(TGeoVolume* motherVolume, const std::string& name);

static TGeoMaterial* carbonFiberMat;
static TGeoMedium* medCarbonFiber;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@

#include <TGeoVolume.h>
#include <string>
#include <vector>

#include "FT3Simulation/FT3ModuleConstants.h"

// define types for y positions, second element is the stack height
using PositionType = std::pair<double, unsigned>;
using PositionTypes = std::vector<PositionType>;
using PosNegPositionTypes = std::pair<PositionTypes, PositionTypes>;
// define type of the y position range: First pair is (min, max) for positive y
using PositionRangeType = std::pair<std::pair<double, double>, std::pair<double, double>>;
namespace Constants = o2::ft3::ModuleConstants;

class FT3Module
{
Expand All @@ -33,13 +44,63 @@ class FT3Module
static TGeoMedium* epoxyMed;
static TGeoMaterial* AluminumMat;
static TGeoMedium* AluminumMed;
static TGeoMaterial* carbonFiberMat;
static TGeoMedium* carbonFiberMed;

const char* mDetName;

static void createModule(double mZ, int layerNumber, int direction, double Rin, double Rout, double overlap, const std::string& face, const std::string& layout_type, TGeoVolume* motherVolume);
static void createModule(
double mZ, int layerNumber, int direction, double Rin,
double Rout, double overlap, const std::string& face,
const std::string& layout_type, TGeoVolume* motherVolume);

void createModule_staveGeo(
double mZ, int layerNumber, int direction, double Rin,
double Rout, double z_offset_local, const Constants::StaveConfig& staveConfig,
TGeoVolume* motherVolume);

private:
static void create_layout(double mZ, int layerNumber, int direction, double Rin, double Rout, double overlap, const std::string& face, const std::string& layout_type, TGeoVolume* motherVolume);
static void create_layout(
double mZ, int layerNumber, int direction, double Rin,
double Rout, double overlap, const std::string& face,
const std::string& layout_type, TGeoVolume* motherVolume);

void create_layout_staveGeo(
double mZ, int layerNumber, int direction, double Rin,
double Rout, double z_offset_local, const Constants::StaveConfig& staveConfig,
TGeoVolume* motherVolume);

// Helper functions
void fill_stave(PosNegPositionTypes& y_positions, double Rin, double Rout,
double x_left, unsigned kSensorStack, PositionRangeType y_range,
std::pair<double, double>& absAllowedYRange);
void addStaveVolume(
TGeoVolume* motherVolume, std::string volumeName, int direction,
unsigned* volume_count, double staveLength,
std::array<std::array<double, 3>, 4> staveTriangles,
std::pair<double, double>& absAllowedYRange,
double x_mid, double y_mid, double z_stave_shift_forward);
void addDetectorVolume(
TGeoVolume* motherVolume, std::string volumeName, int color, unsigned* volume_count,
double x_mid, double y_mid, double z_mid,
double x_half_length, double y_half_length, double z_half_length);

void add2x1GlueVolume(
TGeoVolume* motherVolume, int layerNumber, int direction, unsigned stave_idx,
unsigned* volume_count, double x_mid, double y_mid, double z_mid,
std::string element_glued_to);

void add2x1CopperVolume(
TGeoVolume* motherVolume, int layerNumber, int direction, unsigned stave_idx,
unsigned* volume_count, double x_mid, double y_mid, double z_mid);

void add2x1KaptonVolume(
TGeoVolume* motherVolume, int layerNumber, int direction, unsigned stave_idx,
unsigned* volume_count, double x_mid, double y_mid, double z_mid);

void addSingleSensorVolume(
TGeoVolume* motherVolume, int layerNumber, int direction, unsigned stave_idx,
unsigned* volume_count, double active_x_mid, double y_mid, double z_mid, bool isLeft);
};

#endif // FT3MODULE_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// \file FT3ModuleConstants.h
/// \brief Definition of various constants for tiling the modules of sensors

#ifndef FT3MODULECONSTANTS_H
#define FT3MODULECONSTANTS_H

#include <vector>
#include <map>
#include <TColor.h>
#include <TMath.h>

namespace o2::ft3::ModuleConstants
{
/* CURRENT STATUS:
* 25x32mm 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
* gap to be ABOVE the most recently placed module.
*
* |<- 25mm ->|<- 25mm ->|
* _______________________
* ----------------------- 0.2mm gap above
* | | | | |
* | | | | |
* | | | | |
* | | | | | 32mm sensor height
* | | | | |
* | | | | |
* ------------------------
*
*/
// First set all layout constants for the rest of the function
const double single_sensor_width = 2.5;
const double single_sensor_height = 3.2;
const double inactive_width = 0.2;
const double sensor2x1_gap = 0.02;
const double stackGap = sensor2x1_gap; // gap between 2xN module stacks

const double active_width = single_sensor_width - inactive_width;
const double active_height = single_sensor_height;

const double sensor2x1_width = 2 * single_sensor_width;
const double sensor2x1_active_width = 2 * active_width;
const double sensor2x1_height = single_sensor_height;
const std::vector<unsigned> kSensorsPerStack = {4, 2, 1};
inline const double getStackHeight(unsigned nSensorsPerStack)
{
return nSensorsPerStack * sensor2x1_height +
(nSensorsPerStack - 1) * sensor2x1_gap;
}

// small helper function to get 1-indexed stave ID, counting from the middle outwards,
// with negative IDs on the left and positive IDs on the right
inline const int staveIdxToID(int staveIdx, unsigned nStavesPerDisc)
{
unsigned nStavesOneSide = nStavesPerDisc / 2;
bool isRight = staveIdx >= nStavesOneSide;
return staveIdx - nStavesOneSide + isRight;
}

// material properties
const double siliconThickness = 0.01;
const double copperThickness = 0.006;
const double kaptonThickness = 0.03;
const double epoxyThickness = 0.0012;

const double effectiveCarbonThickness_Stave = 0.02; // foam + shell
const double staveOpeningAngle = 60 * TMath::DegToRad();
const double sinTheta = TMath::Sin(staveOpeningAngle / 2);
const double alpha = TMath::Pi() / 2 - staveOpeningAngle / 2; // bottom angles
const double staveSensorGap = 0.1; // 2mm padding on each side when sensor is glued
const double staveTriangleHeight = (sensor2x1_width + 2 * staveSensorGap) / 2.0 / tan(staveOpeningAngle / 2.0);
/*
* Now describe the offset of every other stave in z to avoid overlaps
* ______ ______
* \ /______\ / | <-- z_offsetStave
* \ / \ / \ /
* \/ \ / \/
* \/
*/
// If midpoint spacing becomes non constant, this becomes a function
// TODO: add some tolerance to avoid overlaps?
inline const double z_offsetStave(double x_midpoint_spacing)
{
return staveTriangleHeight *
(2 - x_midpoint_spacing / (sensor2x1_width / 2 + staveSensorGap));
}

const int SiColor = kGreen;
const int SiInactiveColor = kRed;
const int glueColor = kBlue;
const int CuColor = kOrange;
const int kaptonColor = kYellow;
const int carbonColor = kBlack;

// Struct for stave position configuration (varies between IT/OT)
struct StaveConfig {
/*
* Constants for staves are written for both positive
* and negative x even though they are just mirrored now,
* because there might be design changes in the future
* that require a non-mirrored layout, making it easier to
* change here if so required, even though it looks uglier now.
*
* The second element in the mapping pair is whether the stave
* with a certain ID should be mirrored around the x-axis.
*/
// map from Stave ID (1-indexed from other documents) to midpoint
// Do NOT add any zero midpoints, this is taken off separately
const std::map<int, std::pair<double, bool>>& staveID_to_y_midpoint;
// lengths of staves, their midpoint, and their face
const std::vector<double>& y_lengths;
const std::vector<double>& x_midpoints;
double x_midpoint_spacing;
// 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
const std::vector<bool>& staveOnFront;
};

namespace OT_StavePositions
{
const std::map<int, std::pair<double, bool>> staveID_to_y_midpoint = {
{-2, {39.0, true}},
{-1, {41.4, true}},
{1, {41.4, true}},
{2, {39.0, true}}};
const std::vector<double> y_lengths = {
52.8, 66.0, 79.2, 92.4, 99.0, 105.6, 118.8, 118.8,
128.7, 132.0, 132.0, 138.6, 138.6, 56.1, 52.8,
52.8, 56.1, 138.6, 138.6, 132.0, 132.0, 128.7,
118.8, 118.8, 105.6, 99.0, 92.4, 79.2, 66.0, 52.8};
const std::vector<double> x_midpoints = {
-65.25, -60.75, -56.25, -51.75, -47.25, -42.75, -38.25, // L
-33.75, -29.25, -24.75, -20.25, -15.75, -11.25, -6.75, -2.25, // L
2.25, 6.75, 11.25, 15.75, 20.25, 24.75, 29.25, 33.75, // R
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 std::vector<bool> staveOnFront =
{
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, // L
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 // R
};
} // namespace OT_StavePositions

namespace ML_StavePositions
{
// Use prelim numbers for now, these will change! TODO
const std::map<int, std::pair<double, bool>> staveID_to_y_midpoint = {
{-3, {19.1, true}},
{-2, {21.8, true}},
{-1, {22.5, true}},
{1, {22.5, true}},
{2, {21.8, true}},
{3, {19.1, true}}};
const std::vector<double> y_lengths = {
30.5, 44.5, 53.6, 60.0, 64.6, 29.5, 25.8, 25.0,
25.0, 25.8, 29.5, 64.6, 60.0, 53.6, 44.5, 30.5};
const std::vector<double> x_midpoints = {
-33.75, -29.25, -24.75, -20.25, -15.75, -11.25, -6.75, -2.25, // L
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 std::vector<bool> staveOnFront =
{
1, 0, 1, 0, 1, 0, 1, 0, // L
0, 1, 0, 1, 0, 1, 0, 1 // R
};
} // namespace ML_StavePositions

// Get stave configuration based on tracker type
inline StaveConfig getStaveConfig(bool isInnerDisk)
{
if (isInnerDisk) {
return StaveConfig{
ML_StavePositions::staveID_to_y_midpoint,
ML_StavePositions::y_lengths,
ML_StavePositions::x_midpoints,
ML_StavePositions::x_midpoint_spacing,
ML_StavePositions::staveOnFront};
} else {
return StaveConfig{
OT_StavePositions::staveID_to_y_midpoint,
OT_StavePositions::y_lengths,
OT_StavePositions::x_midpoints,
OT_StavePositions::x_midpoint_spacing,
OT_StavePositions::staveOnFront};
}
}

} // namespace o2::ft3::ModuleConstants

#endif // FT3MODULECONSTANTS_H
Loading