Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2b17981
one sensor per chip
maciacco Apr 30, 2026
3b72641
one sensor per chip also in second layer
maciacco Apr 30, 2026
e0f57a7
iotof segmentation and parameters. Segmentation parameters are stolen…
GiorgioAlbertoLucia Apr 30, 2026
c072ae2
compute number of chips in IOTOF
maciacco Apr 30, 2026
876f171
fill L2G transformation matrices
maciacco Apr 30, 2026
6ce0aa3
Merge pull request #4 from GiorgioAlbertoLucia/tf3_digit
maciacco Apr 30, 2026
684490f
fix cmakelist
maciacco Apr 30, 2026
abe83cb
only fill segmentation details if layout is segmented + add function …
maciacco May 1, 2026
ce30af9
use proper chip id for segmented barrel
maciacco May 1, 2026
0038f09
refactoring of segmentation, idependent for inner and outer tof, nons…
GiorgioAlbertoLucia May 4, 2026
728a505
singleton implementation of the segmentation class
GiorgioAlbertoLucia May 6, 2026
5924d18
realistic values fot the chip segmentation
GiorgioAlbertoLucia May 6, 2026
bdbd1b8
hit processing in place, tested on A3Studies/Digitization/testDigitiz…
GiorgioAlbertoLucia May 6, 2026
175f4db
clang format
GiorgioAlbertoLucia May 6, 2026
ea0d674
protect against disks for now
GiorgioAlbertoLucia May 6, 2026
e437ecf
added sanity checks
GiorgioAlbertoLucia May 6, 2026
d4b2789
thickness that matches the values currently in O2
GiorgioAlbertoLucia May 6, 2026
6a4c6c2
default init of chipspecifics to zero
GiorgioAlbertoLucia May 6, 2026
31daa6d
double typo (half the honor)
GiorgioAlbertoLucia May 6, 2026
213c808
Please consider the following formatting changes
alibuild May 6, 2026
f30965d
Merge pull request #1 from alibuild/alibot-cleanup-15372
GiorgioAlbertoLucia May 6, 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 @@ -22,6 +22,9 @@ namespace iotof
class GeometryTGeo : public o2::detectors::DetMatrixCache
{
public:
using Mat3D = o2::math_utils::Transform3D;
using DetMatrixCache::getMatrixL2G;

GeometryTGeo(bool build = false, int loadTrans = 0);
void Build(int loadTrans);
void fillMatrixCache(int mask);
Expand Down Expand Up @@ -79,7 +82,25 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache
static const char* composeBTOFSymNameChip(int d, int lr);
static const char* composeBTOFSymNameSensor(int d, int layer);

int getIOTOFFirstChipIndex(int lay) const;
int getIOTOFLayer(int index) const;
int getIOTOFChipIndex(int lay, int sta, int mod, int chip) const;
bool getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& chip) const;

/// Get the transformation matrix of the SENSOR (not necessary the same as the chip)
/// for a given chip 'index' by querying the TGeoManager
TGeoHMatrix* extractMatrixSensor(int index) const;

TString getMatrixPath(int index) const;

protected:
// Determine the number of active parts in the geometry
int extractNumberOfStavesIOTOF(int lay) const;
int extractNumberOfModulesIOTOF(int lay) const;
int extractNumberOfChipsPerModuleIOTOF(int lay) const;
int extractNumberOfChipsFTOF() const;
int extractNumberOfChipsBTOF() const;

// i/oTOF mother volume
static std::string sIOTOFVolumeName;

Expand Down Expand Up @@ -107,10 +128,24 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache
static std::string sBTOFChipName;
static std::string sBTOFSensorName;

// Inner/outer TOF
int mNumberOfStavesIOTOF[2];
int mNumberOfModulesIOTOF[2];
int mNumberOfChipsPerModuleIOTOF[2];
int mNumberOfChipsPerStaveIOTOF[2];
int mNumberOfChipsIOTOF[2];
int mLastChipIndex[2];

// Forward TOF
int mNumberOfChipsFTOF;

// Backward TOF
int mNumberOfChipsBTOF;

private:
static std::unique_ptr<o2::iotof::GeometryTGeo> sInstance;
};

} // namespace iotof
} // namespace o2
#endif
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ namespace o2
namespace iotof
{

struct ChipSpecifics {
int NCols = 0;
int NRows = 0;
float PitchCol = 0.;
float PitchRow = 0.;
float PassiveEdgeReadOut = 0.;
float PassiveEdgeTop = 0.;
float PassiveEdgeSide = 0.;
float SensorLayerThicknessEff = 0.;
float SensorLayerThickness = 0.;

int NPixels() const { return NCols * NRows; }
float ActiveMatrixSizeCols() const { return PitchCol * NCols; }
float ActiveMatrixSizeRows() const { return PitchRow * NRows; }
float SensorSizeCols() const { return ActiveMatrixSizeCols() + 2 * PassiveEdgeSide; }
float SensorSizeRows() const { return ActiveMatrixSizeRows() + PassiveEdgeTop + PassiveEdgeReadOut; }
};

struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper<IOTOFBaseParam> {
bool enableInnerTOF = true; // Enable Inner TOF layer
bool enableOuterTOF = true; // Enable Outer TOF layer
Expand All @@ -31,6 +49,9 @@ struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper<IOTOFBaseParam>
float x2x0 = 0.02f; // thickness expressed in radiation length, for all layers for the moment
float sensorThickness = 0.0050f; // thickness of the sensor in cm, for all layers for the moment, the default is set to 50 microns

ChipSpecifics iTofChipSpecifics{258, 271, 250.00e-4, 100.00e-4, 0.00f, 0.00e-4, 0.00e-4, 50.e-4, 50.e-4};
ChipSpecifics oTofChipSpecifics{251, 487, 250.00e-4, 100.00e-4, 0.00f, 0.00e-4, 106.48e-4, 50.e-4, 50.e-4};

O2ParamDef(IOTOFBaseParam, "IOTOFBase");
};

Expand Down
213 changes: 213 additions & 0 deletions Detectors/Upgrades/ALICE3/IOTOF/base/src/GeometryTGeo.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// or submit itself to any jurisdiction.

#include <IOTOFBase/GeometryTGeo.h>
#include <IOTOFBase/IOTOFBaseParam.h>
#include <TGeoManager.h>

namespace o2
Expand Down Expand Up @@ -55,6 +56,171 @@ GeometryTGeo::GeometryTGeo(bool build, int loadTrans) : DetMatrixCache()
}
}

int GeometryTGeo::extractNumberOfStavesIOTOF(int lay) const
{
int numberOfStaves{0};

std::string layName = lay == 0 ? GeometryTGeo::getITOFLayerPattern() : GeometryTGeo::getOTOFLayerPattern();
TGeoVolume* layV = gGeoManager->GetVolume(layName.c_str());
if (layV == nullptr) {
LOG(fatal) << "Can't find volume " << layName;
return -1;
}

TObjArray* nodes = layV->GetNodes();
int nNodes = nodes->GetEntriesFast();

for (int j{0}; j < nNodes; ++j) {
if (strstr(nodes->At(j)->GetName(), lay == 0 ? GeometryTGeo::getITOFStavePattern() : GeometryTGeo::getOTOFStavePattern()) != nullptr) {
numberOfStaves++;
}
}

return numberOfStaves;
}

int GeometryTGeo::extractNumberOfModulesIOTOF(int lay) const
{
int numberOfModules{0};

std::string staveName = lay == 0 ? GeometryTGeo::getITOFStavePattern() : GeometryTGeo::getOTOFStavePattern();
TGeoVolume* staveV = gGeoManager->GetVolume(staveName.c_str());
if (staveV == nullptr) {
LOG(fatal) << "Can't find volume " << staveName;
return -1;
}

TObjArray* nodes = staveV->GetNodes();
int nNodes = nodes->GetEntriesFast();

for (int j{0}; j < nNodes; ++j) {
if (strstr(nodes->At(j)->GetName(), lay == 0 ? GeometryTGeo::getITOFModulePattern() : GeometryTGeo::getOTOFModulePattern()) != nullptr) {
numberOfModules++;
}
}

return numberOfModules;
}

int GeometryTGeo::extractNumberOfChipsPerModuleIOTOF(int lay) const
{
int numberOfChips{0};

std::string moduleName = lay == 0 ? GeometryTGeo::getITOFModulePattern() : GeometryTGeo::getOTOFModulePattern();
TGeoVolume* moduleV = gGeoManager->GetVolume(moduleName.c_str());
if (moduleV == nullptr) {
LOG(fatal) << "Can't find volume " << moduleName;
return -1;
}

TObjArray* nodes = moduleV->GetNodes();
int nNodes = nodes->GetEntriesFast();

for (int j{0}; j < nNodes; ++j) {
if (strstr(nodes->At(j)->GetName(), lay == 0 ? GeometryTGeo::getITOFChipPattern() : GeometryTGeo::getOTOFChipPattern()) != nullptr) {
numberOfChips++;
}
}

return numberOfChips;
}

int GeometryTGeo::extractNumberOfChipsFTOF() const
{
return 0;
}

int GeometryTGeo::extractNumberOfChipsBTOF() const
{
return 0;
}

int GeometryTGeo::getIOTOFFirstChipIndex(int lay) const
{
return lay == 0 ? 0 : mLastChipIndex[0] + 1;
}

int GeometryTGeo::getIOTOFLayer(int index) const
{
if (index < 0 || index > mLastChipIndex[1]) {
LOG(fatal) << "Invalid chip index " << index;
return -1;
}
return index > mLastChipIndex[0] ? 1 : 0;
}

int GeometryTGeo::getIOTOFChipIndex(int lay, int sta, int mod, int chip) const
{
return getIOTOFFirstChipIndex(lay) + (sta - 1) * mNumberOfChipsPerStaveIOTOF[lay] + (mod - 1) * mNumberOfChipsPerModuleIOTOF[lay] + (chip - 1);
}

bool GeometryTGeo::getIOTOFChipId(int index, int& lay, int& sta, int& mod, int& chip) const
{
lay = getIOTOFLayer(index);
index -= getIOTOFFirstChipIndex(lay);
sta = mNumberOfStavesIOTOF[lay] > 0 ? index / mNumberOfChipsPerStaveIOTOF[lay] : -1;
index %= mNumberOfChipsPerStaveIOTOF[lay];
mod = mNumberOfModulesIOTOF[lay] > 0 ? index / mNumberOfChipsPerModuleIOTOF[lay] : -1;
chip = index % mNumberOfChipsPerModuleIOTOF[lay];
return true;
}

TString GeometryTGeo::getMatrixPath(int index) const
{
int lay, sta, mod, chip;
getIOTOFChipId(index, lay, sta, mod, chip);

TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getIOTOFVolPattern());
sta += 1;
mod += 1;
chip += 1;

if (lay == 0) {
path += Form("%s_1/", GeometryTGeo::getITOFLayerPattern());
if (mNumberOfStavesIOTOF[lay] > 0)
path += Form("%s_%d/", GeometryTGeo::getITOFStavePattern(), sta);
if (mNumberOfModulesIOTOF[lay] > 0)
path += Form("%s_%d/", GeometryTGeo::getITOFModulePattern(), mod);
if (mNumberOfChipsPerModuleIOTOF[lay] > 0)
path += Form("%s_%d/%s_1", GeometryTGeo::getITOFChipPattern(), chip, GeometryTGeo::getITOFSensorPattern());
} else {
path += Form("%s_1/", GeometryTGeo::getOTOFLayerPattern());
if (mNumberOfStavesIOTOF[lay] > 0)
path += Form("%s_%d/", GeometryTGeo::getOTOFStavePattern(), sta);
if (mNumberOfModulesIOTOF[lay] > 0)
path += Form("%s_%d/", GeometryTGeo::getOTOFModulePattern(), mod);
if (mNumberOfChipsPerModuleIOTOF[lay] > 0)
path += Form("%s_%d/%s_1", GeometryTGeo::getOTOFChipPattern(), chip, GeometryTGeo::getOTOFSensorPattern());
}

return path;
}

TGeoHMatrix* GeometryTGeo::extractMatrixSensor(int index) const
{
auto path = getMatrixPath(index);

static TGeoHMatrix matTmp;
gGeoManager->PushPath();

if (!gGeoManager->cd(path.Data())) {
gGeoManager->PopPath();
LOG(error) << "Error in cd-ing to " << path.Data();
return nullptr;
}

matTmp = *gGeoManager->GetCurrentMatrix();
// LOG(info) << "Path = " << path.Data();

// Restore the modeler state
gGeoManager->PopPath();

// account for the difference between physical sensitive layer (where charge collection is simulated) and effective sensor thicknesses
// TODO: apply translation by the effective sensor thickness, not yet done (see ITS)

return &matTmp;
}

void GeometryTGeo::Build(int loadTrans)
{
if (isBuilt()) {
Expand All @@ -66,11 +232,58 @@ void GeometryTGeo::Build(int loadTrans)
LOGP(fatal, "Geometry is not loaded");
}

auto& iotofPars = IOTOFBaseParam::Instance();
if (!iotofPars.segmentedInnerTOF && !iotofPars.segmentedOuterTOF) {
return;
}

// Inner/outer TOF
for (int j{0}; j < 2; ++j) {
mNumberOfStavesIOTOF[j] = extractNumberOfStavesIOTOF(j);
mNumberOfModulesIOTOF[j] = extractNumberOfModulesIOTOF(j);
mNumberOfChipsPerModuleIOTOF[j] = extractNumberOfChipsPerModuleIOTOF(j);
}

// Forward TOF
mNumberOfChipsFTOF = extractNumberOfChipsFTOF();

// Backward TOF
mNumberOfChipsBTOF = extractNumberOfChipsBTOF();

int numberOfChips{0};
for (int j{0}; j < 2; ++j) {
mNumberOfChipsPerStaveIOTOF[j] = mNumberOfModulesIOTOF[j] * mNumberOfChipsPerModuleIOTOF[j];
mNumberOfChipsIOTOF[j] = mNumberOfStavesIOTOF[j] * mNumberOfChipsPerStaveIOTOF[j];
numberOfChips += mNumberOfChipsIOTOF[j];
mLastChipIndex[j] = numberOfChips - 1;
}

LOG(info) << "numberOfChipsITOF = " << mNumberOfChipsIOTOF[0] << ", numberOfChipsOTOF = " << mNumberOfChipsIOTOF[1] << ", numberOfChips = " << numberOfChips << ", mNumberOfChipesPerStaveITOF" << mNumberOfChipsPerStaveIOTOF[0];

setSize(numberOfChips);
fillMatrixCache(loadTrans);
// fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G));
}

void GeometryTGeo::fillMatrixCache(int mask)
{
if (mSize < 1) {
LOG(warning) << "The method Build was not called yet";
Build(mask);
return;
}

if ((mask & o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)) && !getCacheL2G().isFilled()) {
// Matrices for Local (Sensor!!! rather than the full chip) to Global frame transformation
LOG(info) << "Loading " << getName() << " L2G matrices from TGeo; there are " << mSize << " matrices";
auto& cacheL2G = getCacheL2G();
cacheL2G.setSize(mSize);

for (int i = 0; i < mSize; i++) {
TGeoHMatrix* hm = extractMatrixSensor(i);
cacheL2G.setMatrix(Mat3D(*hm), i);
}
}
}

GeometryTGeo* GeometryTGeo::Instance()
Expand Down
7 changes: 5 additions & 2 deletions Detectors/Upgrades/ALICE3/IOTOF/simulation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ o2_add_library(IOTOFSimulation
src/Detector.cxx
src/Digitizer.cxx
# src/IOTOFServices.cxx
src/Segmentation.cxx
PUBLIC_LINK_LIBRARIES O2::IOTOFBase
O2::DataFormatsIOTOF
O2::ITSMFTSimulation)

o2_target_root_dictionary(IOTOFSimulation
HEADERS include/IOTOFSimulation/Detector.h
include/IOTOFSimulation/Layer.h
include/IOTOFSimulation/Digitizer.h)
# include/IOTOFSimulation/IOTOFServices.h)
include/IOTOFSimulation/Digitizer.h
# include/IOTOFSimulation/IOTOFServices.h
include/IOTOFSimulation/Segmentation.h
)
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "SimulationDataFormat/MCCompLabel.h"
#include "SimulationDataFormat/MCTruthContainer.h"
#include "IOTOFBase/GeometryTGeo.h"
#include "IOTOFSimulation/Segmentation.h"

namespace o2::iotof
{
Expand Down Expand Up @@ -105,6 +106,8 @@ class Digitizer
float mTimeResolution = 0.020f; ///< time resolution sigma in ns (20 ps default)
float mEfficiency = 0.98f; ///< detection efficiency
float mEnergyToCharge = 3.6e-9f; ///< energy loss to electrons conversion (3.6 eV per e-h pair in Si)

static o2::iotof::Segmentation* sSegmentation; ///< IOTOF segmentation instance (singleton)
};
} // namespace o2::iotof

Expand Down
Loading