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
17
18#include <TGeoManager.h>
19#include <TLorentzVector.h>
20#include <TString.h>
21#include <TVirtualMC.h>
22#include <FairRootManager.h>
23#include <FairVolume.h>
25#include "Framework/Logger.h"
26#include "DetectorsBase/Stack.h"
27#include "FV0Base/Geometry.h"
28
29using namespace o2::fv0;
31
33
35 : o2::base::DetImpl<Detector>("FV0", kTRUE),
36 mHits(o2::utils::createSimVector<o2::fv0::Hit>()),
37 mGeometry(nullptr),
38 mTrackData()
39{
40 // Empty
41}
42
44{
45 if (mHits) {
46 o2::utils::freeSimVector(mHits); // delete mHits;
47 }
48 if (mGeometry) {
49 delete mGeometry;
50 }
51}
52
53Detector::Detector(Bool_t isActive)
54 : o2::base::DetImpl<Detector>("FV0", isActive),
55 mHits(o2::utils::createSimVector<o2::fv0::Hit>()),
56 mGeometry(nullptr),
57 mTrackData()
58{
59 // Empty
60}
61
63{
64 LOG(info) << "FV0: Initializing O2 detector. Adding sensitive volumes.";
65
66 std::string volSensitiveName;
67 for (int i = 0; i < mGeometry->getSensitiveVolumeNames().size(); i++) {
68 volSensitiveName = mGeometry->getSensitiveVolumeNames().at(i);
69 TGeoVolume* volSensitive = gGeoManager->GetVolume(volSensitiveName.c_str());
70 if (!volSensitive) {
71 LOG(fatal) << "FV0: Can't find sensitive volume " << volSensitiveName;
72 } else {
73 AddSensitiveVolume(volSensitive);
74 LOG(info) << "FV0: Sensitive volume added: " << volSensitive->GetName();
75 }
76 }
77}
78
79Bool_t Detector::ProcessHits(FairVolume* v)
80{
81 // This method is called from the MC stepping
82
83 // Track only charged particles and photons
84 bool isPhotonTrack = false;
85 Int_t particlePdg = fMC->TrackPid();
86 if (particlePdg == 22) { // If particle is standard PDG photon
87 isPhotonTrack = true;
88 }
89 if (!(isPhotonTrack || fMC->TrackCharge())) {
90 return kFALSE;
91 }
92
93 // Check track status to define when hit is started and when it is stopped
94 bool startHit = false, stopHit = false;
95 if ((fMC->IsTrackEntering()) || (fMC->IsTrackInside() && !mTrackData.mHitStarted)) {
96 startHit = true;
97 } else if ((fMC->IsTrackExiting() || fMC->IsTrackOut() || fMC->IsTrackStop())) {
98 stopHit = true;
99 }
100
101 // Increment energy loss at all steps except entrance
102 if (!startHit) {
103 mTrackData.mEnergyLoss += fMC->Edep();
104 }
105
106 // Track is entering or created in the volume
107 // Start registering new hit, defined as the combination of all the steps from a given particle
108 if (startHit) {
109 mTrackData.mHitStarted = true;
110 mTrackData.mEnergyLoss = 0.;
111 fMC->TrackMomentum(mTrackData.mMomentumStart);
112 fMC->TrackPosition(mTrackData.mPositionStart);
113 }
114
115 // Track is exiting or stopped within the volume, finalize recording of this hit and save it
116 if (stopHit) {
117 TLorentzVector positionStop;
118 fMC->TrackPosition(positionStop);
119 Int_t trackID = fMC->GetStack()->GetCurrentTrackNumber();
120
121 // Get unique ID of the detector cell (sensitive volume)
122 Int_t cellId = mGeometry->getCurrentCellId(fMC);
123
124 math_utils::Point3D<float> posStart(mTrackData.mPositionStart.X(), mTrackData.mPositionStart.Y(), mTrackData.mPositionStart.Z());
125 math_utils::Point3D<float> posStop(positionStop.X(), positionStop.Y(), positionStop.Z());
126 math_utils::Vector3D<float> momStart(mTrackData.mMomentumStart.Px(), mTrackData.mMomentumStart.Py(), mTrackData.mMomentumStart.Pz());
127 addHit(trackID, cellId, posStart, posStop, momStart,
128 mTrackData.mMomentumStart.E(), positionStop.T(),
129 mTrackData.mEnergyLoss, particlePdg);
130 } else {
131 return kFALSE; // do noting more
132 }
133
134 return kTRUE;
135}
136
138{
139 // This will create a branch in the output tree called Hit, setting the last
140 // parameter to kFALSE means that this collection will not be written to the file,
141 // it will exist only during the simulation
142
143 if (FairRootManager::Instance()) {
144 FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE);
145 }
146}
147
149{
150 if (!o2::utils::ShmManager::Instance().isOperational()) {
151 mHits->clear();
152 }
153}
154
156{
157 Reset();
158}
159
161{
162 LOG(info) << "FV0: Creating materials";
163
164 // Air mixture
165 const Int_t nAir = 4;
166 Float_t aAir[nAir] = {12.0107, 14.0067, 15.9994, 39.948};
167 Float_t zAir[nAir] = {6, 7, 8, 18};
168 Float_t wAir[nAir] = {0.000124, 0.755267, 0.231781, 0.012827};
169 const Float_t dAir = 0.00120479;
170
171 // EJ-204 scintillator, based on polyvinyltoluene
172 const Int_t nScint = 2;
173 Float_t aScint[nScint] = {1.00784, 12.0107};
174 Float_t zScint[nScint] = {1, 6};
175 Float_t wScint[nScint] = {0.07085, 0.92915}; // based on EJ-204 datasheet: n_atoms/cm3
176 const Float_t dScint = 1.023;
177
178 // PMMA plastic mixture: (C5O2H8)n, same for plastic fiber support and for the fiber core
179 // Fiber cladding is different, but it comprises only 3% of the fiber volume, so it is not included
180 const Int_t nPlast = 3;
181 Float_t aPlast[nPlast] = {1.00784, 12.0107, 15.999};
182 Float_t zPlast[nPlast] = {1, 6, 8};
183 Float_t wPlast[nPlast] = {0.08054, 0.59985, 0.31961};
184 const Float_t dPlast = 1.18;
185
186 // Densities of fiber-equivalent material, for five radially-distributed density regions
187 const Int_t nFiberRings = 5;
188 Float_t dFiberRings[nFiberRings] = {0.035631, 0.059611, 0.074765, 0.079451, 0.054490};
189
190 // Densities of fiber-equivalent material, for five density regions in front of the PMTs
191 const Int_t nFiberPMTs = 5;
192 Float_t dFiberPMTs[nFiberPMTs] = {0.109313, 0.217216, 0.364493, 1.373307, 1.406480};
193
194 // Aluminum
195 Float_t aAlu = 26.981;
196 Float_t zAlu = 13;
197 Float_t dAlu = 2.7;
198
199 // Titanium grade 5 (https://en.wikipedia.org/wiki/Titanium_alloy) without iron and oxygen
200 const Int_t nTitanium = 3;
201 Float_t aTitanium[nTitanium] = {47.87, 26.98, 50.94};
202 Float_t zTitanium[nTitanium] = {22, 13, 23};
203 Float_t wTitanium[nTitanium] = {0.9, 0.06, 0.04};
204 const Float_t dTitanium = 4.42;
205
206 // Mixture of elements found in the PMTs
207 const Int_t nPMT = 14;
208 Float_t aPMT[nPMT] = {63.546, 65.38, 28.085, 15.999, 12.011, 1.008, 14.007, 55.845, 51.996, 10.81, 121.76, 132.91, 9.0122, 26.982};
209 Float_t zPMT[nPMT] = {29, 30, 14, 8, 6, 1, 7, 26, 24, 5, 51, 55, 4, 13};
210 Float_t wPMT[nPMT] = {0.07, 0.02, 0.14, 0.21, 0.11, 0.02, 0.02, 0.04, 0.01, 0.01, 0.00, 0.00, 0.01, 0.34};
211 const Float_t dPMT = Geometry::getPmtDensity();
212
213 Int_t matId = 0; // tmp material id number
214 const Int_t unsens = 0, sens = 1; // sensitive or unsensitive medium
215
216 Float_t tmaxfd = -10.0; // max deflection angle due to magnetic field in one step
217 Float_t stemax = 0.1; // max step allowed [cm]
218 Float_t deemax = 1.0; // maximum fractional energy loss in one step 0<deemax<=1
219 Float_t epsil = 0.03; // tracking precision [cm]
220 Float_t stmin = -0.001; // minimum step due to continuous processes [cm] (negative value: choose it automatically)
221
222 Int_t fieldType;
223 Float_t maxField;
225 LOG(info) << "FV0: createMaterials(): fieldType " << fieldType << ", maxField " << maxField;
226
227 // TODO: Comment out two lines below once tested that the above function assigns field type and max correctly
228 fieldType = 2;
229 maxField = 10.;
230
231 o2::base::Detector::Mixture(++matId, "Air$", aAir, zAir, dAir, nAir, wAir);
232 o2::base::Detector::Medium(Air, "Air$", matId, unsens, fieldType, maxField,
233 tmaxfd, stemax, deemax, epsil, stmin);
234
235 o2::base::Detector::Mixture(++matId, "Scintillator$", aScint, zScint, dScint, nScint, wScint);
236 o2::base::Detector::Medium(Scintillator, "Scintillator$", matId, unsens, fieldType, maxField,
237 tmaxfd, stemax, deemax, epsil, stmin);
238
239 o2::base::Detector::Mixture(++matId, "Plastic$", aPlast, zPlast, dPlast, nPlast, wPlast);
240 o2::base::Detector::Medium(Plastic, "Plastic$", matId, unsens, fieldType, maxField,
241 tmaxfd, stemax, deemax, epsil, stmin);
242
243 for (int i = 0; i < nFiberRings; i++) {
244 o2::base::Detector::Mixture(++matId, Form("FiberRing%i$", i + 1), aPlast, zPlast, dFiberRings[i], nPlast, wPlast);
245 o2::base::Detector::Medium(FiberRing1 + i, Form("FiberRing%i$", i + 1), matId, unsens, fieldType, maxField,
246 tmaxfd, stemax, deemax, epsil, stmin);
247 }
248
249 for (int i = 0; i < nFiberPMTs; i++) {
250 o2::base::Detector::Mixture(++matId, Form("FiberPMT%i$", i + 1), aPlast, zPlast, dFiberPMTs[i], nPlast, wPlast);
251 o2::base::Detector::Medium(FiberPMT1 + i, Form("FiberPMT%i$", i + 1), matId, unsens, fieldType, maxField,
252 tmaxfd, stemax, deemax, epsil, stmin);
253 }
254
255 o2::base::Detector::Material(++matId, "Aluminium$", aAlu, zAlu, dAlu, 8.9, 999);
256 o2::base::Detector::Medium(Aluminium, "Aluminium$", matId, unsens, fieldType, maxField,
257 tmaxfd, stemax, deemax, epsil, stmin);
258
259 o2::base::Detector::Mixture(++matId, "Titanium$", aTitanium, zTitanium, dTitanium, nTitanium, wTitanium);
260 o2::base::Detector::Medium(Titanium, "Titanium$", matId, unsens, fieldType, maxField,
261 tmaxfd, stemax, deemax, epsil, stmin);
262
263 o2::base::Detector::Mixture(++matId, "PMT$", aPMT, zPMT, dPMT, nPMT, wPMT);
264 o2::base::Detector::Medium(PMT, "PMT$", matId, unsens, fieldType, maxField,
265 tmaxfd, stemax, deemax, epsil, stmin);
266
267 LOG(debug) << "FV0 Detector::createMaterials(): matId = " << matId;
268}
269
271{
272 LOG(info) << "FV0: Constructing geometry";
275 // mGeometry->enableComponent(Geometry::eScintillator, false);
276 // mGeometry->enableComponent(Geometry::ePlastics, false);
277 // mGeometry->enableComponent(Geometry::eFibers, false);
278 // mGeometry->enableComponent(Geometry::eScrews, false);
279 // mGeometry->enableComponent(Geometry::eRods, false);
280 // mGeometry->enableComponent(Geometry::eAluminiumContainer, false);
281 mGeometry->buildGeometry();
282}
284{
285 //
286 // Creates entries for alignable volumes associating the symbolic volume
287 // name with the corresponding volume path.
288 //
289 // First version (mainly ported from AliRoot)
290 //
291
292 LOG(info) << "FV0: Add alignable volumes";
293
294 if (!gGeoManager) {
295 LOG(fatal) << "TGeoManager doesn't exist !";
296 return;
297 }
298
299 TString volPath, symName;
300 for (auto& half : {"RIGHT_0", "LEFT_1"}) {
301 volPath = Form("/cave_1/barrel_1/FV0_1/FV0%s", half);
302 symName = Form("FV0%s", half);
303 LOG(info) << "FV0: Add alignable volume: " << symName << ": " << volPath;
304 if (!gGeoManager->SetAlignableEntry(symName.Data(), volPath.Data())) {
305 LOG(fatal) << "FV0: Unable to set alignable entry! " << symName << ": " << volPath;
306 }
307 }
308}
309
310o2::fv0::Hit* Detector::addHit(Int_t trackId, Int_t cellId,
311 const math_utils::Point3D<float>& startPos, const math_utils::Point3D<float>& endPos,
312 const math_utils::Vector3D<float>& startMom, double startE,
313 double endTime, double eLoss, Int_t particlePdg)
314{
315 mHits->emplace_back(trackId, cellId, startPos, endPos, startMom, startE, endTime, eLoss, particlePdg);
316 auto stack = (o2::data::Stack*)fMC->GetStack();
317 stack->addHit(GetDetId());
318 return &(mHits->back());
319}
Definition of the Stack class.
Base definition of FV0 geometry.
Definition of the FV0 detector class.
ClassImp(Detector)
int32_t i
uint32_t stack
Definition RawData.h:1
std::ostringstream debug
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
static void initFieldTrackingParams(int &mode, float &maxfield)
Definition Detector.cxx:143
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:150
~Detector() override
Default destructor.
Definition Detector.cxx:43
void InitializeO2Detector() override
Initializes the detector (adds sensitive volume)
Definition Detector.cxx:62
void createMaterials()
Registers new materials in o2::base::Detector.
Definition Detector.cxx:160
void EndOfEvent() override
Called at the end of event.
Definition Detector.cxx:155
void Register() override
Registers the produced collections in FAIRRootManager.
Definition Detector.cxx:137
Bool_t ProcessHits(FairVolume *v=nullptr) override
This method is called for each step during simulation (see FairMCApplication::Stepping())
Definition Detector.cxx:79
void ConstructGeometry() override
Creates materials and geometry.
Definition Detector.cxx:270
void addAlignableVolumes() const override
Add alignable volumes.
Definition Detector.cxx:283
Detector()
Default constructor.
Definition Detector.cxx:34
void Reset() override
Has to be called after each event to reset the containers.
Definition Detector.cxx:148
FV0 Geometry.
Definition Geometry.h:51
void buildGeometry() const
Build the geometry.
Definition Geometry.cxx:95
int getCurrentCellId(const TVirtualMC *fMC) const
Definition Geometry.cxx:61
static Geometry * instance(EGeoType initType=eUninitialized)
const std::vector< std::string > & getSensitiveVolumeNames() const
Definition Geometry.h:100
static constexpr float getPmtDensity()
Get the density of the PMTs.
Definition Geometry.h:137
static ShmManager & Instance()
Definition ShmManager.h:61
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLboolean * data
Definition glcorearb.h:298
void freeSimVector(std::vector< T > *ptr)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Common utility functions.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"