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),
49Detector::Detector(
bool active)
50 :
o2::base::DetImpl<Detector>(
"TRK", true),
56 if (trkPars.configFile !=
"") {
57 configFromFile(trkPars.configFile);
64 LOGP(info,
"Summary of TRK configuration:");
65 for (
auto&
layer : mLayers) {
66 LOGP(info,
"Layer: {} name: {} r: {} cm | z: {} cm | thickness: {} cm",
layer->getNumber(),
layer->getName(),
layer->getInnerRadius(),
layer->getZ(),
layer->getChipThickness());
70Detector::Detector(
const Detector&
other)
71 :
o2::base::DetImpl<Detector>(
other),
84void Detector::ConstructGeometry()
90void Detector::configMLOT()
92 auto& trkPars = TRKBaseParam::Instance();
96 const std::vector<float> rInn{7.f, 9.f, 12.f, 20.f, 30.f, 45.f, 60.f, 80.f};
97 const float thick = 100.e-3;
99 switch (trkPars.layoutMLOT) {
101 const std::vector<float>
length{127.985f, 127.985f, 127.985f, 127.985f, 127.985f, 255.9f, 255.9f, 255.9f};
102 LOGP(warning,
"Loading cylindrical configuration for ALICE3 TRK");
103 for (
int i{0};
i < constants::ML::nLayers + constants::OT::nLayers; ++
i) {
105 mLayers.push_back(std::make_unique<TRKCylindricalLayer>(
i,
name, rInn[
i],
length[
i], thick, MatBudgetParamMode::Thickness));
110 const std::vector<float> tiltAngles{11.2f, 11.9f, 11.4f, 0.f, 0.f, 0.f, 0.f, 0.f};
112 const std::vector<int> nStaves{10, 14, 18, 26, 38, 32, 42, 56};
114 const std::vector<int> nMods{11, 11, 11, 11, 11, 22, 22, 22};
116 const std::vector<float> stagOffsets{0.f, 0.f, 0.f, 1.17f, 0.89f};
118 LOGP(warning,
"Loading segmented configuration for ALICE3 TRK");
119 for (
int i{0};
i < constants::ML::nLayers + constants::OT::nLayers; ++
i) {
121 if (
i < constants::ML::nLayers) {
122 mLayers.push_back(std::make_unique<TRKMLLayer>(
i,
name, rInn[
i], stagOffsets[
i], tiltAngles[
i], nStaves[
i], nMods[
i], thick, MatBudgetParamMode::Thickness));
124 mLayers.push_back(std::make_unique<TRKOTLayer>(
i,
name, rInn[
i], tiltAngles[
i], nStaves[
i], nMods[
i], thick, MatBudgetParamMode::Thickness));
130 LOGP(fatal,
"Unknown option {} for configMLOT",
static_cast<int>(trkPars.layoutMLOT));
135void Detector::configFromFile(std::string fileName)
138 std::ifstream confFile(fileName);
139 if (!confFile.good()) {
140 LOGP(fatal,
"File {} not found, aborting.", fileName);
143 auto& trkPars = TRKBaseParam::Instance();
147 LOGP(info,
"Overriding geometry of ALICE3 TRK using {} file.", fileName);
150 std::vector<float> tmpBuff;
152 while (std::getline(confFile, line)) {
153 if (line[0] ==
'/') {
157 std::stringstream ss(line);
160 while (getline(ss, substr,
'\t')) {
161 tmpBuff.push_back(std::stof(substr));
166 switch (trkPars.layoutMLOT) {
175 if (tmpBuff.size() < 3) {
176 LOGP(fatal,
"Invalid configuration for cylindrical layer {}: insufficient parameters.", layerCount);
179 float rInn = tmpBuff[0];
180 float length = tmpBuff[1];
181 float thick = tmpBuff[2];
185 if (tmpBuff.size() >= 4) {
189 mLayers.push_back(std::make_unique<TRKCylindricalLayer>(layerCount,
name, rInn,
length, thick, matBudgetMode));
203 if (tmpBuff.size() < 5) {
204 LOGP(fatal,
"Invalid configuration for segmented layer {}: missing base parameters.", layerCount);
207 float rInn = tmpBuff[0];
208 float thick = tmpBuff[1];
209 float tiltAngle = tmpBuff[2];
210 int nStaves =
static_cast<int>(tmpBuff[3]);
211 int nMods =
static_cast<int>(tmpBuff[4]);
216 if (layerCount < constants::ML::nLayers) {
218 if (tmpBuff.size() < 6) {
219 LOGP(fatal,
"Invalid configuration for ML layer {}: stagOffset is missing.", layerCount);
221 float stagOffset = tmpBuff[5];
223 if (tmpBuff.size() >= 7) {
227 mLayers.push_back(std::make_unique<TRKMLLayer>(layerCount,
name, rInn, stagOffset, tiltAngle, nStaves, nMods, thick, matBudgetMode));
230 if (tmpBuff.size() >= 6) {
234 mLayers.push_back(std::make_unique<TRKOTLayer>(layerCount,
name, rInn, tiltAngle, nStaves, nMods, thick, matBudgetMode));
239 LOGP(fatal,
"Unknown option {} for configMLOT",
static_cast<int>(trkPars.layoutMLOT));
247void Detector::configToFile(std::string fileName)
249 LOGP(info,
"Exporting TRK Detector layout to {}", fileName);
250 std::ofstream conFile(fileName.c_str(), std::ios::out);
251 conFile <<
"/// TRK configuration file: inn_radius z_length lay_thickness" << std::endl;
252 for (
const auto&
layer : mLayers) {
253 conFile <<
layer->getInnerRadius() <<
"\t" <<
layer->getZ() <<
"\t" <<
layer->getChipThickness() << std::endl;
257void Detector::configServices()
262void Detector::createMaterials()
268 float tmaxfdSi = 0.1;
269 float stemaxSi = 0.0075;
270 float deemaxSi = 0.1;
271 float epsilSi = 1.0E-4;
274 float tmaxfdAir = 0.1;
275 float stemaxAir = .10000E+01;
276 float deemaxAir = 0.1;
277 float epsilAir = 1.0E-4;
278 float stminAir = 0.0;
280 float tmaxfdCer = 0.1;
281 float stemaxCer = .10000E+01;
282 float deemaxCer = 0.1;
283 float epsilCer = 1.0E-4;
284 float stminCer = 0.0;
287 float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948};
288 float zAir[4] = {6., 7., 8., 18.};
289 float wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827};
290 float dAir = 1.20479E-3;
293 float aCf[2] = {12.0107, 1.00794};
294 float zCf[2] = {6., 1.};
297 o2::base::Detector::Medium(1,
"AIR$", 1, 0, ifield, fieldm, tmaxfdAir, stemaxAir, deemaxAir, epsilAir, stminAir);
300 o2::base::Detector::Medium(3,
"SILICON$", 3, 0, ifield, fieldm, tmaxfdSi, stemaxSi, deemaxSi, epsilSi, stminSi);
303void Detector::createGeometry()
305 TGeoManager* geoManager = gGeoManager;
306 TGeoVolume* vALIC = geoManager->GetVolume(
"barrel");
308 LOGP(fatal,
"Could not find barrel volume while constructing TRK geometry");
310 new TGeoVolumeAssembly(GeometryTGeo::getTRKVolPattern());
311 TGeoVolume* vTRK = geoManager->GetVolume(GeometryTGeo::getTRKVolPattern());
312 vALIC->AddNode(vTRK, 2,
new TGeoTranslation(0, 30., 0));
314 char vstrng[100] =
"TRKVol";
315 vTRK->SetTitle(vstrng);
317 for (
auto&
layer : mLayers) {
318 layer->createLayer(vTRK);
322 mServices.createServices(vTRK);
326 auto& trkPars = TRKBaseParam::Instance();
330 switch (trkPars.layoutVD) {
332 LOG(info) <<
"Building VD with IRIS4 layout";
336 LOG(info) <<
"Building VD with IRIS fully cylindrical layout";
340 LOG(info) <<
"Building VD with IRIS fully cylindrical layout with 3 inclined walls";
344 LOG(info) <<
"Building VD with IRIS5 layout";
348 LOG(info) <<
"Building VD with IRIS4a layout";
352 LOG(fatal) <<
"Unknown VD layout option: " <<
static_cast<int>(trkPars.layoutVD);
358 mNumberOfVolumesVD =
static_cast<int>(regs.size());
359 mNumberOfVolumes = mNumberOfVolumesVD + mLayers.size();
360 mSensorName.resize(mNumberOfVolumes);
364 for (
const auto& sensor : regs) {
365 mSensorName[VDvolume] = sensor.name;
370 for (
int i = 0;
i < mLayers.size();
i++) {
371 mSensorName[VDvolume++].Form(
"%s%d", GeometryTGeo::getTRKSensorPattern(),
i);
374 for (
auto vd : mSensorName) {
375 std::cout <<
"Volume name: " << vd << std::endl;
378 mServices.excavateFromVacuum(
"IRIS_CUTOUTsh");
379 mServices.registerVacuum(vTRK);
382void Detector::InitializeO2Detector()
384 LOG(info) <<
"Initialize TRK O2Detector";
385 mGeometryTGeo = GeometryTGeo::Instance();
386 defineSensitiveVolumes();
388 mSensorID.resize(mNumberOfVolumes);
389 for (
int i = 0;
i < mNumberOfVolumes;
i++) {
390 mSensorID[
i] = gMC ? TVirtualMC::GetMC()->VolId(mSensorName[
i]) : 0;
391 LOGP(info,
"{}: mSensorID={}, mSensorName={}",
i, mSensorID[
i], mSensorName[
i].Data());
395void Detector::defineSensitiveVolumes()
397 TGeoManager* geoManager = gGeoManager;
401 LOGP(info,
"Adding TRK Sensitive Volumes");
404 for (
const auto& s :
o2::trk::vdSensorRegistry()) {
405 TGeoVolume*
v = gGeoManager->GetVolume(s.name.c_str());
407 LOGP(warning,
"VD sensor volume '{}' not found", s.name);
410 LOGP(info,
"Adding VD Sensitive Volume {}",
v->GetName());
411 AddSensitiveVolume(
v);
414 mFirstOrLastLayers.push_back(
s.name);
419 for (
int j{0};
j < mLayers.size();
j++) {
420 volumeName = GeometryTGeo::getTRKSensorPattern() + TString::Itoa(
j, 10);
421 if (
j == mLayers.size() - 1) {
422 mFirstOrLastLayers.push_back(volumeName.Data());
424 LOGP(info,
"Trying {}", volumeName.Data());
425 v = geoManager->GetVolume(volumeName.Data());
426 LOGP(info,
"Adding TRK Sensitive Volume {}",
v->GetName());
427 AddSensitiveVolume(
v);
431void Detector::EndOfEvent() { Reset(); }
433void Detector::Register()
439 if (FairRootManager::Instance()) {
440 FairRootManager::Instance()->RegisterAny(addNameTo(
"Hit").
data(), mHits,
true);
444void Detector::Reset()
451bool Detector::InsideFirstOrLastLayer(std::string layerName)
454 for (
auto& firstOrLastLayer : mFirstOrLastLayers) {
455 if (firstOrLastLayer == layerName) {
463bool Detector::ProcessHits(FairVolume* vol)
466 if (!(fMC->TrackCharge())) {
473 int volID = vol->getMCid();
475 bool notSens =
false;
476 while ((volume < mNumberOfVolumes) && (notSens = (volID != mSensorID[volume]))) {
484 if (volume < mNumberOfVolumesVD) {
488 layer = volume - mNumberOfVolumesVD;
494 if (fMC->IsTrackExiting() && InsideFirstOrLastLayer(vol->GetName())) {
497 tr.setTrackID(
stack->GetCurrentTrackNumber());
498 tr.setUserId(volume);
499 stack->addTrackReference(tr);
501 bool startHit =
false, stopHit =
false;
502 unsigned char status = 0;
503 if (fMC->IsTrackEntering()) {
504 status |= Hit::kTrackEntering;
506 if (fMC->IsTrackInside()) {
507 status |= Hit::kTrackInside;
509 if (fMC->IsTrackExiting()) {
510 status |= Hit::kTrackExiting;
512 if (fMC->IsTrackOut()) {
513 status |= Hit::kTrackOut;
515 if (fMC->IsTrackStop()) {
516 status |= Hit::kTrackStopped;
518 if (fMC->IsTrackAlive()) {
519 status |= Hit::kTrackAlive;
523 if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) {
525 }
else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) {
531 mTrackData.mEnergyLoss += fMC->Edep();
533 if (!(startHit | stopHit)) {
538 mTrackData.mEnergyLoss = 0.;
539 fMC->TrackMomentum(mTrackData.mMomentumStart);
540 fMC->TrackPosition(mTrackData.mPositionStart);
541 mTrackData.mTrkStatusStart = status;
542 mTrackData.mHitStarted =
true;
545 TLorentzVector positionStop;
546 fMC->TrackPosition(positionStop);
549 int stave(0), halfstave(0), mod(0), chip(0);
551 auto& trkPars = TRKBaseParam::Instance();
555 fMC->CurrentVolOffID(1, chip);
556 fMC->CurrentVolOffID(2, mod);
557 if (mGeometryTGeo->getNumberOfHalfStaves(
layer) == 2) {
558 fMC->CurrentVolOffID(3, halfstave);
559 fMC->CurrentVolOffID(4, stave);
560 }
else if (mGeometryTGeo->getNumberOfHalfStaves(
layer) == 1) {
561 fMC->CurrentVolOffID(3, stave);
563 LOGP(fatal,
"Wrong number of halfstaves for layer {}",
layer);
568 unsigned short chipID = mGeometryTGeo->getChipIndex(subDetID, volume,
layer, stave, halfstave, mod, chip);
574 Hit*
p = addHit(
stack->GetCurrentTrackNumber(), chipID, mTrackData.mPositionStart.Vect(), positionStop.Vect(),
575 mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(),
576 mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status);
581 stack->addHit(GetDetId());
587o2::trk::Hit* Detector::addHit(
int trackID,
unsigned short detID,
const TVector3& startPos,
const TVector3& endPos,
588 const TVector3& startMom,
double startE,
double endTime,
double eLoss,
unsigned char startStatus,
589 unsigned char endStatus)
591 mHits->emplace_back(trackID, detID, startPos, endPos, startMom, startE, endTime, eLoss, startStatus, endStatus);
592 return &(mHits->back());
595void Detector::Print(FairVolume* vol,
int volume,
int subDetID,
int layer,
int stave,
int halfstave,
int mod,
int chip,
int chipID)
const
598 LOG(info) <<
"Current volume name: " << fMC->CurrentVolName() <<
" and ID " << fMC->CurrentVolID(currentVol);
599 LOG(info) <<
"volume: " << volume <<
"/" << mNumberOfVolumes - 1;
601 auto& trkPars = TRKBaseParam::Instance();
605 LOG(info) <<
"off volume name 1 " << fMC->CurrentVolOffName(1) <<
" chip: " << chip;
606 LOG(info) <<
"SubDetector ID: " << subDetID <<
" Layer: " <<
layer <<
" Chip ID: " << chipID;
608 LOG(info) <<
"off volume name 1 " << fMC->CurrentVolOffName(1) <<
" chip: " << chip;
609 LOG(info) <<
"off volume name 2 " << fMC->CurrentVolOffName(2) <<
" module: " << mod;
610 if (mGeometryTGeo->getNumberOfHalfStaves(
layer) == 2) {
611 LOG(info) <<
"off volume name 3 " << fMC->CurrentVolOffName(3) <<
" halfstave: " << halfstave;
612 LOG(info) <<
"off volume name 4 " << fMC->CurrentVolOffName(4) <<
" stave: " << stave;
613 LOG(info) <<
"SubDetector ID: " << subDetID <<
" Layer: " <<
layer <<
" staveinLayer: " << stave <<
" Chip ID: " << chipID;
614 }
else if (mGeometryTGeo->getNumberOfHalfStaves(
layer) == 1) {
615 LOG(info) <<
"off volume name 3 " << fMC->CurrentVolOffName(3) <<
" stave: " << stave;
616 LOG(info) <<
"SubDetector ID: " << subDetID <<
" Layer: " <<
layer <<
" staveinLayer: " << stave <<
" Chip ID: " << chipID;
621 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)
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)
static const TRKBaseParam & Instance()
static o2::base::Detector * create(bool active)
static ShmManager & Instance()
GLuint const GLchar * name
GLuint GLsizei GLsizei * length
GLenum GLuint GLint GLint layer
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)
std::vector< T > * createSimVector()
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"