Skip to content
Draft
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
65 changes: 65 additions & 0 deletions Detectors/Upgrades/ALICE3/TRK/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,70 @@ o2-sim-serial-run5 -n 1 -g pythia8hi -m A3IP TRK FT3 TF3 \
--configKeyValues "TRKBase.layoutVD=kIRISFullCyl;TRKBase.layoutMLOT=kCylindrical"
```

## Custom Geometry Configuration

The geometry of the ML and OT layers can be overridden by providing a custom plain-text configuration file. The parser interprets the file differently depending on the active `TRKBase.layoutMLOT` setting (`kCylindrical` or `kSegmented`).

### General Syntax Rules
* **Separators:** All columns **must** be separated by a single TAB (`\t`). Using spaces will result in a parsing error.
* **Comments:** Any line starting with a forward slash (`/`) is treated as a comment and ignored.
* **Layer Count:** The parser reads valid lines sequentially. The first valid line corresponds to Layer 0, the second to Layer 1, and so on.
* **Material Budget Mode:** All layer definitions accept an optional `matBudgetMode` parameter at the end of the line (e.g., `0` = Thickness, `1` = X2X0). If omitted, it defaults to `Thickness`.

### 1. Cylindrical Layout (`kCylindrical`)

When `TRKBase.layoutMLOT=kCylindrical` is used, each layer requires a minimum of 3 parameters to define the `TRKCylindricalLayer`.

* **Format:** `rInn` \t `length` \t `thick` \t `[optional_mode]`
* *(Note: `rInn`, `length`, and `thick` map directly to the constructor arguments for the cylindrical layer, typically corresponding to Radius, Length, and Thickness).*

**Example for `kCylindrical`:**
```text
/ Configuration for kCylindrical layout - ALICE3 TRK
/ rInn length thick [optional_mode]
7.0 127.985 0.1
9.0 127.985 0.1
12.0 127.985 0.1
20.0 127.985 0.1
30.0 127.985 0.1
45.0 255.9 0.1
60.0 255.9 0.1
80.0 255.9 0.1
```

### 2. Segmented Layout (`kSegmented`)

When `TRKBase.layoutMLOT=kSegmented` is used, each layer requires a minimum of 5 base parameters to define the geometry. The parser distinguishes between Middle Layers (ML) and Outer Layers (OT) based on the sequential layer index.

* *(Note: The 5 base parameters map directly to: Inner Radius (`rInn`), Thickness (`thick`), Tilt Angle (`tiltAngle`), Number of Staves (`nStaves`), and Number of Modules per stave (`nMods`)).*

**Middle Layers (ML) - Indices 0 to 4**
The first 5 valid lines are parsed as `TRKMLLayer` objects. These layers **require** a 6th parameter for the staggering offset (`stagOffset`).
* **Format:** `rInn` \t `thick` \t `tiltAngle` \t `nStaves` \t `nMods` \t `stagOffset` \t `[optional_mode]`

**Outer Layers (OT) - Indices 5 and above**
From the 6th valid line onwards, lines are parsed as `TRKOTLayer` objects. These layers do **not** have a staggering offset. The optional mode parameter shifts to the 6th column.
* **Format:** `rInn` \t `thick` \t `tiltAngle` \t `nStaves` \t `nMods` \t `[optional_mode]`

**Example for `kSegmented`:**

```text
/ Configuration for kSegmented layout - ALICE3 TRK
/ --- ML LAYERS (Indices 0 to 4) ---
/ rInn thick tilt nStaves nMods stagOffset [optional_mode]
7.0 0.01 11.2 10 11 0.0 1
9.0 0.01 11.9 14 11 0.0 1
12.0 0.01 11.4 18 11 0.0 1
20.0 0.01 0.0 26 11 1.17 1
30.0 0.01 0.0 38 11 0.89 1
/
/ --- OT LAYERS (Indices 5 to 7) ---
/ Outer layers do NOT have stagOffset.
/ rInn thick tilt nStaves nMods [optional_mode]
45.0 0.01 0.0 32 22 1
60.0 0.01 0.0 42 22 1
80.0 0.01 0.0 56 22 1
```

<!-- doxy
/doxy -->
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#define O2_ALICE_TRK_SPECS

#include <array>

#include <math.h>

// This is a temporary version with the specs for the ALICE3 TRK
// This files defines the design specifications of the chips for VD, ML, OT.
// Each TGeoShape has the following properties
Expand Down Expand Up @@ -78,7 +80,7 @@ constexpr double thickness{0 * mu}; // thickness of the copper metal stack - for
namespace chip
{
constexpr double width{25 * mm}; // width of the chip
constexpr double length{32 * mm}; // length of the chip
constexpr double length{29 * mm}; // length of the chip
constexpr double pitchX{20 * mu}; // pitch of the row
constexpr double pitchZ{20 * mu}; // pitch of the column
constexpr double totalThickness{silicon::thickness + metalstack::thickness}; // total thickness of the chip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ enum eSrvLayout {
struct TRKBaseParam : public o2::conf::ConfigurableParamHelper<TRKBaseParam> {
std::string configFile = "";
float serviceTubeX0 = 0.02f; // X0 Al2O3
Bool_t irisOpen = false;
bool irisOpen = false;
bool includeLowServices = false;

eVDLayout layoutVD = kIRIS4; // VD detector layout design
eMLOTLayout layoutMLOT = kSegmented; // ML and OT detector layout design
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// Water bundle disk PU 0,44 19 H2O 0,56 36,08

#include <TGeoManager.h>

#include <FairModule.h>

namespace o2
Expand Down Expand Up @@ -51,6 +52,7 @@ class TRKServices : public FairModule
void createMiddleServices(TGeoVolume* motherVolume);
void createOuterDisksServices(TGeoVolume* motherVolume);
void createOuterBarrelServices(TGeoVolume* motherVolume);
void createServicesAroundBeamPipe(TGeoVolume* motherVolume);
void createMLServicesPeacock(TGeoVolume* motherVolume);
void createOTServicesPeacock(TGeoVolume* motherVolume);
void createVacuumCompositeShape();
Expand Down Expand Up @@ -81,4 +83,4 @@ class TRKServices : public FairModule
};
} // namespace trk
} // namespace o2
#endif // O2_TRK_SERVICES_H
#endif // O2_TRK_SERVICES_H
30 changes: 20 additions & 10 deletions Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void Detector::configMLOT()

switch (trkPars.layoutMLOT) {
case kCylindrical: {
const std::vector<float> length{128.35f, 128.35f, 128.35f, 128.35f, 128.35f, 256.7f, 256.7f, 256.7f};
const std::vector<float> length{127.985f, 127.985f, 127.985f, 127.985f, 127.985f, 255.9f, 255.9f, 255.9f};
LOGP(warning, "Loading cylindrical configuration for ALICE3 TRK");
for (int i{0}; i < constants::ML::nLayers + constants::OT::nLayers; ++i) {
std::string name = GeometryTGeo::getTRKLayerPattern() + std::to_string(i);
Expand All @@ -111,7 +111,7 @@ void Detector::configMLOT()
// const std::vector<float> tiltAngles{10.f, 16.1f, 19.2f, 0.f, 0.f, 0.f, 0.f, 0.f};
const std::vector<int> nStaves{10, 14, 18, 26, 38, 32, 42, 56};
// const std::vector<int> nStaves{10, 16, 22, 26, 38, 32, 42, 56};
const std::vector<int> nMods{10, 10, 10, 10, 10, 20, 20, 20};
const std::vector<int> nMods{11, 11, 11, 11, 11, 22, 22, 22};

const std::vector<float> stagOffsets{0.f, 0.f, 0.f, 1.17f, 0.89f};

Expand Down Expand Up @@ -165,18 +165,28 @@ void Detector::configFromFile(std::string fileName)

switch (trkPars.layoutMLOT) {
case kCylindrical: {
// Expected column mapping in the text file (separated by \t):
// tmpBuff[0] = rInn
// tmpBuff[1] = length
// tmpBuff[2] = thick
// tmpBuff[3] = matBudgetMode (optional, default = Thickness)

// Cylindrical requires at least 3 parameters
if (tmpBuff.size() < 3) {
LOGP(fatal, "Invalid configuration for cylindrical layer {}: insufficient parameters.", layerCount);
}

float rInn = tmpBuff[0];
float length = tmpBuff[1];
float thick = tmpBuff[2];

// Default mode is Thickness
MatBudgetParamMode mode = MatBudgetParamMode::Thickness;
MatBudgetParamMode matBudgetMode = MatBudgetParamMode::Thickness;
if (tmpBuff.size() >= 4) {
mode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[3]));
matBudgetMode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[3]));
}

mLayers.push_back(std::make_unique<TRKCylindricalLayer>(layerCount, name, tmpBuff[0], tmpBuff[1], tmpBuff[2], mode));
mLayers.push_back(std::make_unique<TRKCylindricalLayer>(layerCount, name, rInn, length, thick, matBudgetMode));
break;
}
case kSegmented: {
Expand All @@ -201,7 +211,7 @@ void Detector::configFromFile(std::string fileName)
int nMods = static_cast<int>(tmpBuff[4]);

// Default mode is Thickness
MatBudgetParamMode mode = MatBudgetParamMode::Thickness;
MatBudgetParamMode matBudgetMode = MatBudgetParamMode::Thickness;

if (layerCount < constants::ML::nLayers) {
// ML layers require stagOffset (index 5)
Expand All @@ -211,17 +221,17 @@ void Detector::configFromFile(std::string fileName)
float stagOffset = tmpBuff[5];

if (tmpBuff.size() >= 7) {
mode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[6]));
matBudgetMode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[6]));
}

mLayers.push_back(std::make_unique<TRKMLLayer>(layerCount, name, rInn, stagOffset, tiltAngle, nStaves, nMods, thick, mode));
mLayers.push_back(std::make_unique<TRKMLLayer>(layerCount, name, rInn, stagOffset, tiltAngle, nStaves, nMods, thick, matBudgetMode));
} else {
// OT layers do NOT have stagOffset. The optional mode is at index 5.
if (tmpBuff.size() >= 6) {
mode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[5]));
matBudgetMode = static_cast<MatBudgetParamMode>(static_cast<int>(tmpBuff[5]));
}

mLayers.push_back(std::make_unique<TRKOTLayer>(layerCount, name, rInn, tiltAngle, nStaves, nMods, thick, mode));
mLayers.push_back(std::make_unique<TRKOTLayer>(layerCount, name, rInn, tiltAngle, nStaves, nMods, thick, matBudgetMode));
}
break;
}
Expand Down
79 changes: 65 additions & 14 deletions Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,23 @@
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#include <TRKSimulation/TRKServices.h>
#include <DetectorsBase/MaterialManager.h>
#include <Framework/Logger.h>

#include <TColor.h>
#include <TGeoCompositeShape.h>
#include <TGeoNode.h>
#include <TGeoTube.h>
#include <TGeoVolume.h>
#include <TRKBase/GeometryTGeo.h>
#include <TRKBase/TRKBaseParam.h>
#include <TRKSimulation/TRKServices.h>

#include <FT3Base/GeometryTGeo.h>
#include <TGeoVolume.h>
#include <TGeoNode.h>
#include <TGeoTube.h>
#include <TGeoCompositeShape.h>
#include <TColor.h>
#include <Rtypes.h>
#include <numeric>

#include <Framework/Logger.h>
#include <Rtypes.h>

using std::string;
#include <numeric>

namespace o2
{
Expand Down Expand Up @@ -140,6 +141,9 @@ void TRKServices::createServices(TGeoVolume* motherVolume)
createOuterBarrelServices(vol);
} else {
LOGP(info, "TRK services: Peacock layout");
if (trkPars.includeLowServices) {
createServicesAroundBeamPipe(vol);
}
createMLServicesPeacock(vol);
createOTServicesPeacock(vol);
}
Expand Down Expand Up @@ -521,9 +525,56 @@ void TRKServices::createOuterBarrelServices(TGeoVolume* motherVolume)
motherVolume->AddNode(outerBarrelCoolingH2OVolume, 1, nullptr);
}

void TRKServices::createServicesAroundBeamPipe(TGeoVolume* motherVolume)
{
// This method hardcodes the shape for the low services around the beam pipe
auto& matmgr = o2::base::MaterialManager::Instance();

TGeoMedium* medCu = matmgr.getTGeoMedium("ALICE3_TRKSERVICES_COPPER");

const float tolleranceLowServices = 0.3f;

// Low services start longitudinally from middle barrel on the C side, while from the middle barrel connection disks on the A side
const float zStartASideFirstBlock = 65.265f + tolleranceLowServices;
const float zStartCSideFirstBlock = 64.5f + tolleranceLowServices;

const float zStartSecondBlock = 150.f;
const float zEndSecondBlock = 400.f;

// Low services start radially from IRIS out-vacuum services on the A side, while from beam pipe on the C side
const float rInASide = 3.333f + tolleranceLowServices;
const float rInCSide = 5.6f + tolleranceLowServices;

// Low services end radially at the disks inners radius
const float rOutFirstBlock = 10.f - tolleranceLowServices;
const float rOutSecondBlock = 20.f - tolleranceLowServices;

for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) {
std::string orLabel = orientation == Orientation::kASide ? "A" : "C";

float zStartLowServices = orientation == Orientation::kASide ? zStartASideFirstBlock : zStartCSideFirstBlock;
float rInLowServices = orientation == Orientation::kASide ? rInASide : rInCSide;

TGeoTube* lowServicesFirstBlock = new TGeoTube(Form("TRK_LOWSERVICES_FIRSTBLOCKsh_%s", orLabel.c_str()), rInLowServices, rOutFirstBlock, (zStartSecondBlock - zStartLowServices) / 2.);
TGeoVolume* lowServicesFirstBlockVolume = new TGeoVolume(Form("TRK_LOWSERVICES_FIRSTBLOCK_%s", orLabel.c_str()), lowServicesFirstBlock, medCu);
lowServicesFirstBlockVolume->SetLineColor(kGray);

TGeoTube* lowServicesSecondBlock = new TGeoTube(Form("TRK_LOWSERVICES_SECONDBLOCKsh_%s", orLabel.c_str()), rInLowServices, rOutSecondBlock, (zEndSecondBlock - zStartSecondBlock) / 2.);
TGeoVolume* lowServicesSecondBlockVolume = new TGeoVolume(Form("TRK_LOWSERVICES_SECONDBLOCK_%s", orLabel.c_str()), lowServicesSecondBlock, medCu);
lowServicesSecondBlockVolume->SetLineColor(kGray);

auto* rot = new TGeoRotation("", 0, 0, 180);
auto* combiTransFirstBlock = new TGeoCombiTrans(0, 0, (int)orientation * (zStartLowServices + (zStartSecondBlock - zStartLowServices) / 2.), rot);
auto* combiTransSecondBlock = new TGeoCombiTrans(0, 0, (int)orientation * (zStartSecondBlock + (zEndSecondBlock - zStartSecondBlock) / 2.), rot);

motherVolume->AddNode(lowServicesFirstBlockVolume, 1, combiTransFirstBlock);
motherVolume->AddNode(lowServicesSecondBlockVolume, 1, combiTransSecondBlock);
}
}

void TRKServices::createMLServicesPeacock(TGeoVolume* motherVolume)
{
// This method hardcoes the yellow shape for the middle services
// This method hardcodes the yellow shape for the middle services
auto& matmgr = o2::base::MaterialManager::Instance();

TGeoMedium* medSiO2 = matmgr.getTGeoMedium("ALICE3_TRKSERVICES_SILICONDIOXIDE");
Expand Down Expand Up @@ -619,7 +670,7 @@ void TRKServices::createMLServicesPeacock(TGeoVolume* motherVolume)
for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) {
for (int iSide = 0; iSide < 2; iSide++) { // left/right or top/bottom
float refAngle = 0;
string orLabel("A");
std::string orLabel("A");
if (orientation == Orientation::kCSide) {
orLabel = "C";
refAngle = 90;
Expand Down Expand Up @@ -703,7 +754,7 @@ void TRKServices::createMLServicesPeacock(TGeoVolume* motherVolume)
diskCircumference = rMaxMiddleServicesBarFwd * 3.14; // Only half of the area is used
for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) {
float refAngle = 0;
string orLabel("A");
std::string orLabel("A");
if (orientation == Orientation::kCSide) {
refAngle = 90;
orLabel = "C";
Expand Down Expand Up @@ -872,7 +923,7 @@ void TRKServices::createOTServicesPeacock(TGeoVolume* motherVolume)
motherVolume->AddNode(outerBarrelCarbonSupportVolume, 1, nullptr);

for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) {
string orLabel = "A";
std::string orLabel = "A";
float refAngle = 0;
if (orientation == Orientation::kCSide) {
orLabel = "C";
Expand Down