21#include <TGeoVolume.h>
22#include <TVirtualMC.h>
23#include <TVirtualMCStack.h>
25#include <FairVolume.h>
39 return 2. * (10. + radius * std::cos(2 * std::atan(std::exp(-eta))));
43 :
o2::base::DetImpl<Detector>(
"TRK", true),
54 auto& trkPars = TRKBaseParam::Instance();
56 if (trkPars.configFile !=
"") {
60 if (!trkPars.disableFT3) {
67 LOGP(info,
"Summary of TRK configuration:");
68 for (
auto&
layer : mLayers) {
69 LOGP(info,
"Layer: {} name: {} r: {} cm | z: {} cm | thickness: {} cm",
layer->getNumber(),
layer->getName(),
layer->getInnerRadius(),
layer->getZ(),
layer->getChipThickness());
87void Detector::ConstructGeometry()
93void Detector::configMLOT()
95 auto& trkPars = TRKBaseParam::Instance();
99 const std::vector<float> rInn{7.f, 9.f, 12.f, 20.f, 30.f, 45.f, 60.f, 80.f};
100 const float thick = 100.e-3;
102 switch (trkPars.layoutMLOT) {
104 const std::vector<float>
length{127.985f, 127.985f, 127.985f, 127.985f, 127.985f, 255.9f, 255.9f, 255.9f};
105 LOGP(warning,
"Loading cylindrical configuration for ALICE3 TRK");
106 for (
int i{0};
i < constants::ML::nLayers + constants::OT::nLayers; ++
i) {
108 mLayers.push_back(std::make_unique<TRKCylindricalLayer>(
i,
name, rInn[
i],
length[
i], thick, MatBudgetParamMode::Thickness));
113 const std::vector<float> tiltAngles{11.2f, 11.9f, 11.4f, 0.f, 0.f, 0.f, 0.f, 0.f};
115 const std::vector<int> nStaves{10, 14, 18, 26, 38, 32, 42, 56};
117 const std::vector<int> nMods{11, 11, 11, 11, 11, 22, 22, 22};
119 const std::vector<float> stagOffsets{0.f, 0.f, 0.f, 1.17f, 0.89f};
121 LOGP(warning,
"Loading segmented configuration for ALICE3 TRK");
122 for (
int i{0};
i < constants::ML::nLayers + constants::OT::nLayers; ++
i) {
124 if (
i < constants::ML::nLayers) {
125 mLayers.push_back(std::make_unique<TRKMLLayer>(
i,
name, rInn[
i], stagOffsets[
i], tiltAngles[
i], nStaves[
i], nMods[
i], thick, MatBudgetParamMode::Thickness));
127 mLayers.push_back(std::make_unique<TRKOTLayer>(
i,
name, rInn[
i], tiltAngles[
i], nStaves[
i], nMods[
i], thick, MatBudgetParamMode::Thickness));
133 LOGP(fatal,
"Unknown option {} for configMLOT",
static_cast<int>(trkPars.layoutMLOT));
138void Detector::configFT3ScopingV3()
145 LOG(info) <<
"Building FT3 Detector: v3 scoping version";
147 const int numberOfLayers = 6;
148 const float sensorThickness = 30.e-4;
149 const float layersx2X0 = 1.e-2;
150 using LayerConfig = std::array<float, 4>;
151 const std::array<LayerConfig, numberOfLayers> layersConfigCSide{LayerConfig{77., 10.0, 35., layersx2X0},
152 LayerConfig{100., 10.0, 35., layersx2X0},
153 LayerConfig{122., 10.0, 35., layersx2X0},
154 LayerConfig{150., 20.0, 68.f, layersx2X0},
155 LayerConfig{180., 20.0, 68.f, layersx2X0},
156 LayerConfig{220., 20.0, 68.f, layersx2X0}};
158 const std::array<LayerConfig, numberOfLayers> layersConfigASide{LayerConfig{77., 10.0, 35., layersx2X0},
159 LayerConfig{100., 10.0, 35., layersx2X0},
160 LayerConfig{122., 10.0, 35., layersx2X0},
161 LayerConfig{150., 20.0, 68.f, layersx2X0},
162 LayerConfig{180., 20.0, 68.f, layersx2X0},
163 LayerConfig{220., 20.0, 68.f, layersx2X0}};
164 const std::array<bool, numberOfLayers>
enabled{
true,
true,
true,
true,
true,
true};
166 for (
int direction : {kBackward, kForward}) {
167 mFT3LayerName[direction].clear();
168 const std::array<LayerConfig, numberOfLayers>& layerConfig = (direction == kBackward) ? layersConfigCSide : layersConfigASide;
169 for (
int layerNumber = 0; layerNumber < numberOfLayers; layerNumber++) {
174 const std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string(
"_") +
std::to_string(layerNumber);
175 mFT3LayerName[direction].push_back(layerName.c_str());
176 const float z = layerConfig[layerNumber][0];
177 const float rIn = layerConfig[layerNumber][1];
178 const float rOut = layerConfig[layerNumber][2];
179 const float x0 = layerConfig[layerNumber][3];
180 LOG(info) <<
"buildFT3ScopingV3 -> Adding Layer " << layerNumber <<
"/" << numberOfLayers <<
" " << layerName <<
" at z = " <<
z;
182 const bool isMiddleLayer = layerNumber < 3;
183 auto& thisLayer = mFT3Layers[direction].emplace_back(direction, layerNumber, layerName,
z, rIn, rOut,
x0, isMiddleLayer);
188void Detector::configFromFile(std::string fileName)
191 std::ifstream confFile(fileName);
192 if (!confFile.good()) {
193 LOGP(fatal,
"File {} not found, aborting.", fileName);
196 auto& trkPars = TRKBaseParam::Instance();
200 LOGP(info,
"Overriding geometry of ALICE3 TRK using {} file.", fileName);
203 std::vector<float> tmpBuff;
205 while (std::getline(confFile, line)) {
206 if (line[0] ==
'/') {
210 std::stringstream ss(line);
213 while (getline(ss, substr,
'\t')) {
214 tmpBuff.push_back(std::stof(substr));
219 switch (trkPars.layoutMLOT) {
228 if (tmpBuff.size() < 3) {
229 LOGP(fatal,
"Invalid configuration for cylindrical layer {}: insufficient parameters.", layerCount);
232 float rInn = tmpBuff[0];
233 float length = tmpBuff[1];
234 float thick = tmpBuff[2];
238 if (tmpBuff.size() >= 4) {
242 mLayers.push_back(std::make_unique<TRKCylindricalLayer>(layerCount,
name, rInn,
length, thick, matBudgetMode));
256 if (tmpBuff.size() < 5) {
257 LOGP(fatal,
"Invalid configuration for segmented layer {}: missing base parameters.", layerCount);
260 float rInn = tmpBuff[0];
261 float thick = tmpBuff[1];
262 float tiltAngle = tmpBuff[2];
263 int nStaves =
static_cast<int>(tmpBuff[3]);
264 int nMods =
static_cast<int>(tmpBuff[4]);
269 if (layerCount < constants::ML::nLayers) {
271 if (tmpBuff.size() < 6) {
272 LOGP(fatal,
"Invalid configuration for ML layer {}: stagOffset is missing.", layerCount);
274 float stagOffset = tmpBuff[5];
276 if (tmpBuff.size() >= 7) {
280 mLayers.push_back(std::make_unique<TRKMLLayer>(layerCount,
name, rInn, stagOffset, tiltAngle, nStaves, nMods, thick, matBudgetMode));
283 if (tmpBuff.size() >= 6) {
287 mLayers.push_back(std::make_unique<TRKOTLayer>(layerCount,
name, rInn, tiltAngle, nStaves, nMods, thick, matBudgetMode));
292 LOGP(fatal,
"Unknown option {} for configMLOT",
static_cast<int>(trkPars.layoutMLOT));
300void Detector::configToFile(std::string fileName)
302 LOGP(info,
"Exporting TRK Detector layout to {}", fileName);
303 std::ofstream conFile(fileName.c_str(), std::ios::out);
304 conFile <<
"/// TRK configuration file: inn_radius z_length lay_thickness" << std::endl;
305 for (
const auto&
layer : mLayers) {
306 conFile <<
layer->getInnerRadius() <<
"\t" <<
layer->getZ() <<
"\t" <<
layer->getChipThickness() << std::endl;
310void Detector::configServices()
315void Detector::createMaterials()
321 float tmaxfdSi = 0.1;
322 float stemaxSi = 0.0075;
323 float deemaxSi = 0.1;
324 float epsilSi = 1.0E-4;
327 float tmaxfdAir = 0.1;
328 float stemaxAir = .10000E+01;
329 float deemaxAir = 0.1;
330 float epsilAir = 1.0E-4;
331 float stminAir = 0.0;
333 float tmaxfdCer = 0.1;
334 float stemaxCer = .10000E+01;
335 float deemaxCer = 0.1;
336 float epsilCer = 1.0E-4;
337 float stminCer = 0.0;
340 float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948};
341 float zAir[4] = {6., 7., 8., 18.};
342 float wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827};
343 float dAir = 1.20479E-3;
346 float aCf[2] = {12.0107, 1.00794};
347 float zCf[2] = {6., 1.};
350 o2::base::Detector::Medium(1,
"AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir);
353 o2::base::Detector::Medium(3,
"SILICON$", 3, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
356void Detector::createGeometry()
358 TGeoManager* geoManager = gGeoManager;
359 TGeoVolume* vALIC = geoManager->GetVolume(
"barrel");
361 LOGP(fatal,
"Could not find barrel volume while constructing TRK geometry");
363 new TGeoVolumeAssembly(GeometryTGeo::getTRKVolPattern());
364 TGeoVolume* vTRK = geoManager->GetVolume(GeometryTGeo::getTRKVolPattern());
365 vALIC->AddNode(vTRK, 2,
new TGeoTranslation(0, 30., 0));
367 char vstrng[100] =
"TRKVol";
368 vTRK->SetTitle(vstrng);
370 for (
auto&
layer : mLayers) {
371 layer->createLayer(vTRK);
375 mServices.createServices(vTRK);
379 auto& trkPars = TRKBaseParam::Instance();
383 switch (trkPars.layoutVD) {
385 LOG(info) <<
"Building VD with IRIS4 layout";
389 LOG(info) <<
"Building VD with IRIS fully cylindrical layout";
393 LOG(info) <<
"Building VD with IRIS fully cylindrical layout with 3 inclined walls";
397 LOG(info) <<
"Building VD with IRIS5 layout";
401 LOG(info) <<
"Building VD with IRIS4a layout";
405 LOG(fatal) <<
"Unknown VD layout option: " <<
static_cast<int>(trkPars.layoutVD);
411 mNumberOfVolumesVD =
static_cast<int>(regs.size());
412 mNumberOfVolumes = mNumberOfVolumesVD + mLayers.size();
413 mSensorName.resize(mNumberOfVolumes);
417 for (
const auto& sensor : regs) {
418 mSensorName[VDvolume] = sensor.name;
423 for (
int i = 0;
i < mLayers.size();
i++) {
424 mSensorName[VDvolume++].Form(
"%s%d", GeometryTGeo::getTRKSensorPattern(),
i);
427 for (
auto vd : mSensorName) {
428 std::cout <<
"Volume name: " << vd << std::endl;
431 mServices.excavateFromVacuum(
"IRIS_CUTOUTsh");
432 mServices.registerVacuum(vTRK);
436 TGeoVolume* A3IPvac = gGeoManager->GetVolume(
"OUT_PIPEVACUUM");
438 LOG(info) <<
"Running simulation with no beam pipe.";
444 for (
int direction : {kBackward, kForward}) {
445 const std::string directionString = direction ?
"Forward" :
"Backward";
446 LOG(info) <<
" Creating FT3 without beampipe " << directionString <<
" layers:";
447 for (
int iLayer = 0; iLayer < mFT3Layers[direction].size(); iLayer++) {
448 mFT3Layers[direction][iLayer].createLayer(vTRK);
452 TGeoVolume* volIFT3 =
new TGeoVolumeAssembly(GeometryTGeo::getFT3InnerVolPattern());
453 for (
int direction : {kBackward, kForward}) {
454 const std::string directionString = direction ?
"Forward" :
"Backward";
455 LOG(info) <<
" Creating FT3 " << directionString <<
" layers:";
456 for (
int iLayer = 0; iLayer < mFT3Layers[direction].size(); iLayer++) {
457 LOG(info) <<
" Creating " << directionString <<
" layer " << iLayer;
458 if (mFT3Layers[direction][iLayer].getIsInMiddleLayer()) {
459 mFT3Layers[direction][iLayer].createLayer(volIFT3);
461 mFT3Layers[direction][iLayer].createLayer(vTRK);
465 A3IPvac->AddNode(volIFT3, 2,
new TGeoTranslation(0., 0., 0.));
471 LOG(info) <<
"Initialize TRK O2Detector";
472 mGeometryTGeo = GeometryTGeo::Instance();
473 defineSensitiveVolumes();
475 mSensorID.resize(mNumberOfVolumes);
476 for (
int i = 0;
i < mNumberOfVolumes;
i++) {
477 mSensorID[
i] = gMC ? TVirtualMC::GetMC()->VolId(mSensorName[
i]) : 0;
478 LOGP(info,
"{}: mSensorID={}, mSensorName={}",
i, mSensorID[
i], mSensorName[
i].Data());
482void Detector::defineSensitiveVolumes()
484 TGeoManager* geoManager = gGeoManager;
488 LOGP(info,
"Adding TRK Sensitive Volumes");
491 for (
const auto& s :
o2::trk::vdSensorRegistry()) {
492 TGeoVolume*
v = gGeoManager->GetVolume(s.name.c_str());
494 LOGP(warning,
"VD sensor volume '{}' not found", s.name);
497 LOGP(info,
"Adding VD Sensitive Volume {}",
v->GetName());
498 AddSensitiveVolume(
v);
501 mFirstOrLastLayers.push_back(
s.name);
506 for (
int j{0};
j < mLayers.size();
j++) {
507 volumeName = GeometryTGeo::getTRKSensorPattern() + TString::Itoa(
j, 10);
508 if (
j == mLayers.size() - 1) {
509 mFirstOrLastLayers.push_back(volumeName.Data());
511 LOGP(info,
"Trying {}", volumeName.Data());
512 v = geoManager->GetVolume(volumeName.Data());
513 LOGP(info,
"Adding TRK Sensitive Volume {}",
v->GetName());
514 AddSensitiveVolume(
v);
520 TObjArray* allVolumes = geoManager->GetListOfVolumes();
521 int nVolumes = allVolumes->GetEntriesFast();
523 LOG(info) <<
"Adding FT3 Sensitive Volumes by iterating over all geometry volumes...";
525 for (
int direction : {kBackward, kForward}) {
526 for (
int iLayer = 0; iLayer < getNumberOfFT3Layers(); iLayer++) {
532 std::string sig1 = Form(
"%s_%d_%d", GeometryTGeo::getFT3SensorPattern(), direction, iLayer);
543 for (
int i = 0;
i < nVolumes; ++
i) {
544 TGeoVolume*
v = (TGeoVolume*)allVolumes->At(
i);
545 std::string vName =
v->GetName();
548 if (vName.find(
"Inactive") != std::string::npos || vName.find(
"inactive") != std::string::npos) {
553 bool isMatch =
false;
556 }
else if (vName.find(sig2) == 0 || vName.find(sig3) == 0 || vName.find(sig4) == 0) {
561 AddSensitiveVolume(
v);
573 LOG(error) <<
"NO sensitive volume found for FT3 direction " << direction <<
", layer " << iLayer;
575 LOG(info) << iSens <<
" sensitive volume(s) added for FT3 direction " << direction <<
" layer " << iLayer;
581void Detector::EndOfEvent() { Reset(); }
583void Detector::Register()
589 if (FairRootManager::Instance()) {
590 FairRootManager::Instance()->RegisterAny(
addNameTo(
"Hit").
data(), mHits,
true);
594void Detector::Reset()
601bool Detector::InsideFirstOrLastLayer(std::string layerName)
604 for (
auto& firstOrLastLayer : mFirstOrLastLayers) {
605 if (firstOrLastLayer == layerName) {
613bool Detector::ProcessHits(FairVolume* vol)
616 if (!(fMC->TrackCharge())) {
623 int volID = vol->getMCid();
625 bool notSens =
false;
626 while ((volume < mNumberOfVolumes) && (notSens = (volID != mSensorID[volume]))) {
630 if (volume < mNumberOfVolumesVD) {
634 layer = volume - mNumberOfVolumesVD;
637 if (strstr(vol->GetName(),
"FT3Sensor_Active") || strstr(vol->GetName(),
"FT3Chip")) {
644 LOG(info) <<
"ProcessHit called for insensitive volume " << vol->GetName();
651 if (fMC->IsTrackExiting() && subDetID < 2 && InsideFirstOrLastLayer(vol->GetName())) {
654 tr.setTrackID(
stack->GetCurrentTrackNumber());
655 tr.setUserId(volume);
656 stack->addTrackReference(tr);
658 bool startHit =
false, stopHit =
false;
659 unsigned char status = 0;
660 if (fMC->IsTrackEntering()) {
661 status |= Hit::kTrackEntering;
663 if (fMC->IsTrackInside()) {
664 status |= Hit::kTrackInside;
666 if (fMC->IsTrackExiting()) {
667 status |= Hit::kTrackExiting;
669 if (fMC->IsTrackOut()) {
670 status |= Hit::kTrackOut;
672 if (fMC->IsTrackStop()) {
673 status |= Hit::kTrackStopped;
675 if (fMC->IsTrackAlive()) {
676 status |= Hit::kTrackAlive;
680 if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) {
682 }
else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) {
688 mTrackData.mEnergyLoss += fMC->Edep();
690 if (!(startHit | stopHit)) {
695 mTrackData.mEnergyLoss = 0.;
696 fMC->TrackMomentum(mTrackData.mMomentumStart);
697 fMC->TrackPosition(mTrackData.mPositionStart);
698 mTrackData.mTrkStatusStart = status;
699 mTrackData.mHitStarted =
true;
702 TLorentzVector positionStop;
703 fMC->TrackPosition(positionStop);
706 int stave(0), halfstave(0), mod(0), chip(0);
708 auto& trkPars = TRKBaseParam::Instance();
712 fMC->CurrentVolOffID(1, chip);
713 fMC->CurrentVolOffID(2, mod);
714 if (mGeometryTGeo->getNumberOfHalfStaves(
layer) == 2) {
715 fMC->CurrentVolOffID(3, halfstave);
716 fMC->CurrentVolOffID(4, stave);
717 }
else if (mGeometryTGeo->getNumberOfHalfStaves(
layer) == 1) {
718 fMC->CurrentVolOffID(3, stave);
720 LOGP(fatal,
"Wrong number of halfstaves for layer {}",
layer);
724 else if (subDetID == 2) {
725 mGeometryTGeo->extractChipIdsFT3(vol->GetName(),
layer, stave, chip);
727 unsigned short chipID = mGeometryTGeo->getChipIndex(subDetID, volume,
layer, stave, halfstave, mod, chip);
733 Hit*
p = addHit(
stack->GetCurrentTrackNumber(), chipID, mTrackData.mPositionStart.Vect(), positionStop.Vect(),
734 mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(),
735 mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status);
740 stack->addHit(GetDetId());
746o2::trk::Hit* Detector::addHit(
int trackID,
unsigned short detID,
const TVector3& startPos,
const TVector3& endPos,
747 const TVector3& startMom,
double startE,
double endTime,
double eLoss,
unsigned char startStatus,
748 unsigned char endStatus)
750 mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus);
751 return &(mHits->back());
754void Detector::Print(FairVolume* vol,
int volume,
int subDetID,
int layer,
int stave,
int halfstave,
int mod,
int chip,
int chipID)
const
757 LOG(info) <<
"Current volume name: " << fMC->CurrentVolName() <<
" and ID " << fMC->CurrentVolID(currentVol);
758 LOG(info) <<
"volume: " << volume <<
"/" << mNumberOfVolumes - 1;
760 auto& trkPars = TRKBaseParam::Instance();
764 LOG(info) <<
"off volume name 1 " << fMC->CurrentVolOffName(1) <<
" chip: " << chip;
765 LOG(info) <<
"SubDetector ID: " << subDetID <<
" Layer: " <<
layer <<
" Chip ID: " << chipID;
767 LOG(info) <<
"off volume name 1 " << fMC->CurrentVolOffName(1) <<
" chip: " << chip;
768 LOG(info) <<
"off volume name 2 " << fMC->CurrentVolOffName(2) <<
" module: " << mod;
769 if (mGeometryTGeo->getNumberOfHalfStaves(
layer) == 2) {
770 LOG(info) <<
"off volume name 3 " << fMC->CurrentVolOffName(3) <<
" halfstave: " << halfstave;
771 LOG(info) <<
"off volume name 4 " << fMC->CurrentVolOffName(4) <<
" stave: " << stave;
772 LOG(info) <<
"SubDetector ID: " << subDetID <<
" Layer: " <<
layer <<
" staveinLayer: " << stave <<
" Chip ID: " << chipID;
773 }
else if (mGeometryTGeo->getNumberOfHalfStaves(
layer) == 1) {
774 LOG(info) <<
"off volume name 3 " << fMC->CurrentVolOffName(3) <<
" stave: " << stave;
775 LOG(info) <<
"SubDetector ID: " << subDetID <<
" Layer: " <<
layer <<
" staveinLayer: " << stave <<
" Chip ID: " << chipID;
780 LOG(info) <<
"SubDetector ID: " << subDetID <<
" Chip ID: " << chipID;
Definition of the Stack class.
Definition of the TRK Hit class.
ClassImp(o2::trk::Detector)
o2::base::Detector * create_detector_trk(bool active)
void Mixture(Int_t imat, const char *name, Float_t *a, Float_t *z, Float_t dens, Int_t nlmat, Float_t *wmat)
void Medium(Int_t numed, const char *name, Int_t nmat, Int_t isvol, Int_t ifield, Float_t fieldm, Float_t tmaxfd, Float_t stemax, Float_t deemax, Float_t epsil, Float_t stmin, Float_t *ubuf=nullptr, Int_t nbuf=0)
static void initFieldTrackingParams(int &mode, float &maxfield)
virtual void InitializeO2Detector()=0
void Material(Int_t imat, const char *name, Float_t a, Float_t z, Float_t dens, Float_t radl, Float_t absl, Float_t *buf=nullptr, Int_t nwbuf=0)
std::string addNameTo(const char *ext) const
void configFromFile(std::string fileName="alice3_TRK_layout.txt")
static o2::base::Detector * create(bool active)
void configToFile(std::string fileName="alice3_TRK_layout.txt")
void configFT3ScopingV3()
static ShmManager & Instance()
GLuint const GLchar * name
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLuint GLsizei GLsizei * length
GLenum GLuint GLint GLint layer
GLdouble GLdouble GLdouble z
void createGeometry(TGeoManager &geom, TGeoVolume &topVolume)
std::vector< VDSensorDesc > & vdSensorRegistry()
float getDetLengthFromEta(const float eta, const float radius)
void createIRISGeometry3InclinedWalls(TGeoVolume *motherVolume)
void createIRISGeometryFullCyl(TGeoVolume *motherVolume)
void createIRIS4aGeometry(TGeoVolume *motherVolume)
void createIRIS4Geometry(TGeoVolume *motherVolume)
void createIRIS5Geometry(TGeoVolume *motherVolume)
@ kIRISFullCyl3InclinedWalls
void clearVDSensorRegistry()
void freeSimVector(std::vector< T > *ptr)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Common utility functions.
VectorOfTObjectPtrs other
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"