Project
Loading...
Searching...
No Matches
Detector.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
15#include "DataFormatsFD3/Hit.h"
19#include "FD3Base/Constants.h"
20
21#include "DetectorsBase/Stack.h"
23#include "Field/MagneticField.h"
24
25// FairRoot includes
26#include "FairDetector.h"
27#include <fairlogger/Logger.h>
28#include "FairRootManager.h"
29#include "FairRun.h"
30#include "FairVolume.h"
31#include "FairRootManager.h"
32
33#include "TVirtualMC.h"
34#include "TLorentzVector.h"
35#include "TVector3.h"
36#include <TGeoTube.h>
37#include <TGeoVolume.h>
38#include <TGeoCompositeShape.h>
39#include <TGeoMedium.h>
40#include <TGeoCone.h>
41#include <TGeoManager.h>
42#include "TRandom.h"
43#include <cmath>
44
45class FairModule;
46
47class TGeoMedium;
48
49using namespace o2::fd3;
50using o2::fd3::Hit;
51
53 : o2::base::DetImpl<Detector>("FD3", true),
54 mHits(o2::utils::createSimVector<o2::fd3::Hit>()),
55 mGeometryTGeo(nullptr),
56 mTrackData()
57{
58 mNumberOfRingsC = Constants::nringsC;
59 mNumberOfSectors = Constants::nsect;
60
61 mEtaMinA = Constants::etaMin;
62 mEtaMaxA = Constants::etaMax;
63 mEtaMinC = -Constants::etaMax;
64 mEtaMaxC = -Constants::etaMin;
65
66 auto& baseParam = FD3BaseParam::Instance();
67
68 if (baseParam.withMG) {
69 mNumberOfRingsA = Constants::nringsA_withMG;
70 mEtaMinA = Constants::etaMinA_withMG;
71 } else {
72 mNumberOfRingsA = Constants::nringsA;
73 mEtaMinA = Constants::etaMin;
74 }
75
76 mDzScint = baseParam.dzscint / 2;
77 mDzPlate = baseParam.dzplate;
78
79 mPlateBehindA = baseParam.plateBehindA;
80 mFullContainer = baseParam.fullContainer;
81
82 mZA = baseParam.zmodA;
83 mZC = baseParam.zmodC;
84
85 for (int i = 0; i <= mNumberOfRingsA + 1; i++) {
86 float eta = mEtaMaxA - i * (mEtaMaxA - mEtaMinA) / mNumberOfRingsA;
87 float r = ringSize(mZA, eta);
88 mRingSizesA.emplace_back(r);
89 }
90
91 for (int i = 0; i <= mNumberOfRingsC + 1; i++) {
92 float eta = mEtaMinC + i * (mEtaMaxC - mEtaMinC) / mNumberOfRingsC;
93 float r = ringSize(mZC, eta);
94 mRingSizesC.emplace_back(r);
95 }
96}
97
99 : o2::base::DetImpl<Detector>(rhs),
100 mTrackData(),
101 mHits(o2::utils::createSimVector<o2::fd3::Hit>())
102{
103}
104
105Detector& Detector::operator=(const Detector& rhs)
106{
107
108 if (this == &rhs) {
109 return *this;
110 }
111 // base class assignment
113 mTrackData = rhs.mTrackData;
114
115 mHits = nullptr;
116 return *this;
117}
118
120{
121
122 if (mHits) {
124 }
125}
126
128{
129 LOG(info) << "Initialize Forward Detector";
130 mGeometryTGeo = GeometryTGeo::Instance();
131 defineSensitiveVolumes();
132}
133
135{
136 // This method is called from the MC stepping
137 if (!(fMC->TrackCharge())) {
138 return kFALSE;
139 }
140
141 int detId;
142 int volID = fMC->CurrentVolID(detId);
143
144 auto stack = (o2::data::Stack*)fMC->GetStack();
145
146 // Check track status to define when hit is started and when it is stopped
147 int particlePdg = fMC->TrackPid();
148 bool startHit = false, stopHit = false;
149 if ((fMC->IsTrackEntering()) || (fMC->IsTrackInside() && !mTrackData.mHitStarted)) {
150 startHit = true;
151 } else if ((fMC->IsTrackExiting() || fMC->IsTrackOut() || fMC->IsTrackStop())) {
152 stopHit = true;
153 }
154
155 // increment energy loss at all steps except entrance
156 if (!startHit) {
157 mTrackData.mEnergyLoss += fMC->Edep();
158 }
159 if (!(startHit | stopHit)) {
160 return kFALSE; // do noting
161 }
162
163 if (startHit) {
164 mTrackData.mHitStarted = true;
165 mTrackData.mEnergyLoss = 0.;
166 fMC->TrackMomentum(mTrackData.mMomentumStart);
167 fMC->TrackPosition(mTrackData.mPositionStart);
168 mTrackData.mTrkStatusStart = true;
169 }
170
171 if (stopHit) {
172 TLorentzVector positionStop;
173 fMC->TrackPosition(positionStop);
174 int trackId = stack->GetCurrentTrackNumber();
175
176 math_utils::Point3D<float> posStart(mTrackData.mPositionStart.X(), mTrackData.mPositionStart.Y(), mTrackData.mPositionStart.Z());
177 math_utils::Point3D<float> posStop(positionStop.X(), positionStop.Y(), positionStop.Z());
178 math_utils::Vector3D<float> momStart(mTrackData.mMomentumStart.Px(), mTrackData.mMomentumStart.Py(), mTrackData.mMomentumStart.Pz());
179
180 Hit* p = addHit(trackId, detId, posStart, posStop,
181 momStart, mTrackData.mMomentumStart.E(),
182 positionStop.T(), mTrackData.mEnergyLoss, particlePdg);
183 stack->addHit(GetDetId());
184 } else {
185 return false; // do nothing more
186 }
187 return true;
188}
189
190o2::fd3::Hit* Detector::addHit(int trackId, unsigned int detId,
191 const math_utils::Point3D<float>& startPos,
192 const math_utils::Point3D<float>& endPos,
193 const math_utils::Vector3D<float>& startMom,
194 double startE,
195 double endTime,
196 double eLoss,
197 int particlePdg)
198{
199 mHits->emplace_back(trackId, detId, startPos,
200 endPos, startMom, startE, endTime, eLoss, particlePdg);
201 return &(mHits->back());
202}
203
209
211{
212 Reset();
213}
214
216{
217 // This will create a branch in the output tree called Hit, setting the last
218 // parameter to kFALSE means that this collection will not be written to the file,
219 // it will exist only during the simulation
220
222 FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE);
223 }
224}
225
227{
228 if (!o2::utils::ShmManager::Instance().isOperational()) {
229 mHits->clear();
230 }
231}
232
234{
235 float density, as[11], zs[11], ws[11];
236 double radLength, absLength, a_ad, z_ad;
237 int id;
238
239 // EJ-204 scintillator, based on polyvinyltoluene
240 const int nScint = 2;
241 float aScint[nScint] = {1.00784, 12.0107};
242 float zScint[nScint] = {1, 6};
243 float wScint[nScint] = {0.07085, 0.92915}; // based on EJ-204 datasheet: n_atoms/cm3
244 const float dScint = 1.023;
245
246 // Aluminium
247 Float_t aAlu = 26.981;
248 Float_t zAlu = 13;
249 Float_t dAlu = 2.7;
250
251 int matId = 0; // tmp material id number
252 const int unsens = 0, sens = 1; // sensitive or unsensitive medium
253 //
254 int fieldType = 3; // Field type
255 float maxField = 5.0; // Field max.
256
257 float tmaxfd3 = -10.0; // max deflection angle due to magnetic field in one step
258 float stemax = 0.1; // max step allowed [cm]
259 float deemax = 1.0; // maximum fractional energy loss in one step 0<deemax<=1
260 float epsil = 0.03; // tracking precision [cm]
261 float stmin = -0.001; // minimum step due to continuous processes [cm] (negative value: choose it automatically)
262
263 LOG(info) << "FD3: CreateMaterials(): fieldType " << fieldType << ", maxField " << maxField;
264
265 o2::base::Detector::Mixture(++matId, "Scintillator", aScint, zScint, dScint, nScint, wScint);
266 o2::base::Detector::Medium(Scintillator, "Scintillator", matId, unsens, fieldType, maxField,
267 tmaxfd3, stemax, deemax, epsil, stmin);
268
269 o2::base::Detector::Material(++matId, "Aluminium", aAlu, zAlu, dAlu, 8.9, 999);
270 o2::base::Detector::Medium(Aluminium, "Aluminium", matId, unsens, fieldType, maxField,
271 tmaxfd3, stemax, deemax, epsil, stmin);
272}
273
275{
276 LOGP(info, "Creating FD3 geometry");
277
278 TGeoVolume* vCave = gGeoManager->GetVolume("cave");
279
280 if (!vCave) {
281 LOG(fatal) << "Could not find the top volume!";
282 }
283
284 TGeoVolumeAssembly* vFD3A = buildModuleA();
285 TGeoVolumeAssembly* vFD3C = buildModuleC();
286
287 vCave->AddNode(vFD3A, 1, new TGeoTranslation(0., 0., mZA));
288 vCave->AddNode(vFD3C, 2, new TGeoTranslation(0., 0., mZC));
289}
290
291TGeoVolumeAssembly* Detector::buildModuleA()
292{
293 TGeoVolumeAssembly* mod = new TGeoVolumeAssembly("FD3A");
294
295 const TGeoMedium* medium = gGeoManager->GetMedium("FD3_Scintillator");
296
297 float dphiDeg = 360. / mNumberOfSectors;
298
299 for (int ir = 0; ir < mNumberOfRingsA; ir++) {
300 std::string rName = "fd3_ring" + std::to_string(ir + 1);
301 TGeoVolumeAssembly* ring = new TGeoVolumeAssembly(rName.c_str());
302 float rmin = mRingSizesA[ir];
303 float rmax = mRingSizesA[ir + 1];
304 LOG(info) << "ring" << ir << ": from " << rmin << " to " << rmax;
305 for (int ic = 0; ic < mNumberOfSectors; ic++) {
306 int cellId = ic + mNumberOfSectors * ir;
307 std::string nodeName = "fd3_node" + std::to_string(cellId);
308 float phimin = dphiDeg * ic;
309 float phimax = dphiDeg * (ic + 1);
310 auto tbs = new TGeoTubeSeg("tbs", rmin, rmax, mDzScint, phimin, phimax);
311 auto nod = new TGeoVolume(nodeName.c_str(), tbs, medium);
312 if ((ir + ic) % 2 == 0) {
313 nod->SetLineColor(kRed);
314 } else {
315 nod->SetLineColor(kRed - 7);
316 }
317 ring->AddNode(nod, cellId);
318 }
319 mod->AddNode(ring, ir + 1);
320 }
321
322 // Aluminium plates on one or both sides of the A side module
323 if (mPlateBehindA || mFullContainer) {
324 LOG(info) << "adding container on A side";
325 auto pmed = (TGeoMedium*)gGeoManager->GetMedium("FD3_Aluminium");
326 auto pvol = new TGeoTube("pvol_fd3a", mRingSizesA[0], mRingSizesA[mNumberOfRingsA], mDzPlate);
327 auto pnod1 = new TGeoVolume("pnod1_FD3A", pvol, pmed);
328 double dpz = 2. + mDzPlate / 2;
329 mod->AddNode(pnod1, 1, new TGeoTranslation(0, 0, dpz));
330
331 if (mFullContainer) {
332 auto pnod2 = new TGeoVolume("pnod2_FD3A", pvol, pmed);
333 mod->AddNode(pnod2, 1, new TGeoTranslation(0, 0, -dpz));
334 }
335 }
336 return mod;
337}
338
339TGeoVolumeAssembly* Detector::buildModuleC()
340{
341 TGeoVolumeAssembly* mod = new TGeoVolumeAssembly("FD3C");
342
343 const TGeoMedium* medium = gGeoManager->GetMedium("FD3_Scintillator");
344
345 float dphiDeg = 360. / mNumberOfSectors;
346
347 for (int ir = 0; ir < mNumberOfRingsC; ir++) {
348 std::string rName = "fd3_ring" + std::to_string(ir + 1 + mNumberOfRingsA);
349 TGeoVolumeAssembly* ring = new TGeoVolumeAssembly(rName.c_str());
350 float rmin = mRingSizesC[ir];
351 float rmax = mRingSizesC[ir + 1];
352 LOG(info) << "ring" << ir + mNumberOfRingsA << ": from " << rmin << " to " << rmax;
353 for (int ic = 0; ic < mNumberOfSectors; ic++) {
354 int cellId = ic + mNumberOfSectors * (ir + mNumberOfRingsA);
355 std::string nodeName = "fd3_node" + std::to_string(cellId);
356 float phimin = dphiDeg * ic;
357 float phimax = dphiDeg * (ic + 1);
358 auto tbs = new TGeoTubeSeg("tbs", rmin, rmax, mDzScint, phimin, phimax);
359 auto nod = new TGeoVolume(nodeName.c_str(), tbs, medium);
360 if ((ir + ic) % 2 == 0) {
361 nod->SetLineColor(kBlue);
362 } else {
363 nod->SetLineColor(kBlue - 7);
364 }
365 ring->AddNode(nod, cellId);
366 }
367 mod->AddNode(ring, ir + 1);
368 }
369
370 // Aluminium plates on both sides of the C side module
371 if (mFullContainer) {
372 LOG(info) << "adding container on C side";
373 auto pmed = (TGeoMedium*)gGeoManager->GetMedium("FD3_Aluminium");
374 auto pvol = new TGeoTube("pvol_fd3c", mRingSizesC[0], mRingSizesC[mNumberOfRingsC], mDzPlate);
375 auto pnod1 = new TGeoVolume("pnod1_FD3C", pvol, pmed);
376 auto pnod2 = new TGeoVolume("pnod2_FD3C", pvol, pmed);
377 double dpz = mDzScint / 2 + mDzPlate / 2;
378
379 mod->AddNode(pnod1, 1, new TGeoTranslation(0, 0, dpz));
380 mod->AddNode(pnod2, 2, new TGeoTranslation(0, 0, -dpz));
381 }
382
383 return mod;
384}
385
386void Detector::defineSensitiveVolumes()
387{
388 LOG(info) << "Adding FD3 Sentitive Volumes";
389
390 TGeoVolume* v;
391 TString volumeName;
392
393 int nCellsA = mNumberOfRingsA * mNumberOfSectors;
394 int nCellsC = mNumberOfRingsC * mNumberOfSectors;
395
396 LOG(info) << "number of A rings = " << mNumberOfRingsA << " number of cells = " << nCellsA;
397 LOG(info) << "number of C rings = " << mNumberOfRingsC << " number of cells = " << nCellsC;
398
399 for (int iv = 0; iv < nCellsA + nCellsC; iv++) {
400 volumeName = "fd3_node" + std::to_string(iv);
401 v = gGeoManager->GetVolume(volumeName);
402 LOG(info) << "Adding sensitive volume => " << v->GetName();
404 }
405}
406
407float Detector::ringSize(float z, float eta)
408{
409 return z * TMath::Tan(2 * TMath::ATan(TMath::Exp(-eta)));
410}
411
Definition of the FD3 Hit class (based on ITSMFT and FV0)
Definition of the Stack class.
General constants in FV0.
int32_t i
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc true
ClassImp(IdPath)
Definition of the MagF class.
uint32_t stack
Definition RawData.h:1
Definition of the Detector class.
Int_t GetDetId()
void AddSensitiveVolume(TGeoVolume *v)
TVirtualMC * fMC
flag for initialisation
Definition FairModule.h:160
void RegisterAny(const char *name, T *&obj, Bool_t toFile)
static FairRootManager * Instance()
Detector & operator=(const Detector &)
Definition Detector.cxx:46
void Mixture(Int_t imat, const char *name, Float_t *a, Float_t *z, Float_t dens, Int_t nlmat, Float_t *wmat)
Definition Detector.cxx:66
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)
Definition Detector.cxx:72
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)
Definition Detector.cxx:59
std::string addNameTo(const char *ext) const
Definition Detector.h:151
o2::fd3::Hit * addHit(int trackId, unsigned int detId, const math_utils::Point3D< float > &startPos, const math_utils::Point3D< float > &endPos, const math_utils::Vector3D< float > &startMom, double startE, double endTime, double eLoss, int particlePdg)
This method is an example of how to add your own point of type Hit to the clones array.
Definition Detector.cxx:190
~Detector() override
Definition Detector.cxx:119
void InitializeO2Detector() override
Definition Detector.cxx:127
void EndOfEvent() override
Definition Detector.cxx:210
void Register() override
Definition Detector.cxx:215
void ConstructGeometry() override
Definition Detector.cxx:204
Detector()=default
bool ProcessHits(FairVolume *v=nullptr) override
Definition Detector.cxx:134
void Reset() override
Definition Detector.cxx:226
static GeometryTGeo * Instance()
static ShmManager & Instance()
Definition ShmManager.h:62
const GLdouble * v
Definition glcorearb.h:832
GLboolean * data
Definition glcorearb.h:298
GLuint id
Definition glcorearb.h:650
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
Definition Hit.h:27
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)
Definition common.h:52
Common utility functions.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)