Project
Loading...
Searching...
No Matches
Stack.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
15
16#include "DetectorsBase/Stack.h"
21
22#include "FairDetector.h" // for FairDetector
23#include <fairlogger/Logger.h> // for FairLogger
24#include "FairRootManager.h"
28
29#include "TLorentzVector.h" // for TLorentzVector
30#include "TParticle.h" // for TParticle
31#include "TRefArray.h" // for TRefArray
32#include "TVirtualMC.h" // for VMC
33#include "TMCProcess.h" // for VMC Particle Production Process
34
35#include <algorithm>
36#include <cassert>
37#include <cstddef> // for NULL
38#include <cmath>
39
40using std::cout;
41using std::endl;
42using std::pair;
43using namespace o2::data;
44
45// small helper function to append to vector at arbitrary position
46template <typename T, typename I>
47void insertInVector(std::vector<T>& v, I index, T e)
48{
49 auto currentsize = v.size();
50 if (index >= currentsize) {
51 const auto newsize = std::max(index + 1, (I)(1 + currentsize * 1.2));
52 v.resize(newsize, T(-1));
53 }
54 // new size must at least be as large as index
55 // assert(index < v.size());
56 v[index] = e;
57}
58
61 mStack(),
62 mParticles(),
63 mTracks(new std::vector<o2::MCTrack>),
64 mTrackIDtoParticlesEntry(1000000, -1),
65 mIndexMap(),
66 mIndexOfCurrentTrack(-1),
67 mIndexOfCurrentPrimary(-1),
68 mNumberOfPrimaryParticles(0),
69 mNumberOfEntriesInParticles(0),
70 mNumberOfEntriesInTracks(0),
71 mNumberOfPrimariesforTracking(0),
72 mNumberOfPrimariesPopped(0),
73 mStoreMothers(kTRUE),
74 mStoreSecondaries(kTRUE),
75 mMinHits(1),
76 mEnergyCut(0.),
77 mTrackRefs(new std::vector<o2::TrackReference>),
78 mIsG4Like(false)
79{
80 auto vmc = TVirtualMC::GetMC();
81 if (vmc) {
82 mIsG4Like = !(vmc->SecondariesAreOrdered());
83 }
84
86 TransportFcn transportPrimary;
87 if (param.transportPrimary.compare("none") == 0) {
88 transportPrimary = [](const TParticle& p, const std::vector<TParticle>& particles) {
89 return false;
90 };
91 } else if (param.transportPrimary.compare("all") == 0) {
92 transportPrimary = [](const TParticle& p, const std::vector<TParticle>& particles) {
93 return true;
94 };
95 } else if (param.transportPrimary.compare("barrel") == 0) {
96 transportPrimary = [](const TParticle& p, const std::vector<TParticle>& particles) {
97 return (std::fabs(p.Eta()) < 2.0);
98 };
99 } else if (param.transportPrimary.compare("external") == 0) {
100 transportPrimary = o2::conf::GetFromMacro<o2::data::Stack::TransportFcn>(param.transportPrimaryFileName,
101 param.transportPrimaryFuncName,
102 "o2::data::Stack::TransportFcn", "stack_transport_primary");
103 if (!mTransportPrimary) {
104 LOG(fatal) << "Failed to retrieve external \'transportPrimary\' function: problem with configuration ";
105 }
106 LOG(info) << "Successfully retrieve external \'transportPrimary\' frunction: " << param.transportPrimaryFileName;
107 } else {
108 LOG(fatal) << "unsupported \'trasportPrimary\' mode: " << param.transportPrimary;
109 }
110
111 if (param.transportPrimaryInvert) {
112 mTransportPrimary = [transportPrimary](const TParticle& p, const std::vector<TParticle>& particles) { return !transportPrimary; };
113 } else {
114 mTransportPrimary = transportPrimary;
115 }
116}
117
118Stack::Stack(const Stack& rhs)
119 : FairGenericStack(rhs),
120 mStack(),
121 mParticles(),
122 mTracks(nullptr),
123 mIndexMap(),
124 mIndexOfCurrentTrack(-1),
125 mIndexOfCurrentPrimary(-1),
126 mNumberOfPrimaryParticles(0),
127 mNumberOfEntriesInParticles(0),
128 mNumberOfEntriesInTracks(0),
129 mNumberOfPrimariesforTracking(0),
130 mNumberOfPrimariesPopped(0),
131 mStoreMothers(rhs.mStoreMothers),
132 mStoreSecondaries(rhs.mStoreSecondaries),
133 mMinHits(rhs.mMinHits),
134 mEnergyCut(rhs.mEnergyCut),
135 mTrackRefs(new std::vector<o2::TrackReference>),
136 mIsG4Like(rhs.mIsG4Like)
137{
138 LOG(debug) << "copy constructor called";
139 mTracks = new std::vector<MCTrack>();
140}
141
142Stack::~Stack()
143{
144 if (mTracks) {
145 delete mTracks;
146 }
147}
148
149Stack& Stack::operator=(const Stack& rhs)
150{
151 LOG(fatal) << "operator= called";
152 // check assignment to self
153 if (this == &rhs) {
154 return *this;
155 }
156
157 // base class assignment
158 FairGenericStack::operator=(rhs);
159 mTracks = new std::vector<MCTrack>(rhs.mTracks->size());
160 mIndexOfCurrentTrack = -1;
161 mIndexOfCurrentPrimary = -1;
162 mNumberOfPrimaryParticles = 0;
163 mNumberOfEntriesInParticles = 0;
164 mNumberOfEntriesInTracks = 0;
165 mNumberOfPrimariesforTracking = 0;
166 mNumberOfPrimariesPopped = 0;
167 mStoreMothers = rhs.mStoreMothers;
168 mStoreSecondaries = rhs.mStoreSecondaries;
169 mMinHits = rhs.mMinHits;
170 mEnergyCut = rhs.mEnergyCut;
171 mIsG4Like = rhs.mIsG4Like;
172
173 return *this;
174}
175
176void Stack::PushTrack(Int_t toBeDone, Int_t parentId, Int_t pdgCode, Double_t px, Double_t py, Double_t pz, Double_t e,
177 Double_t vx, Double_t vy, Double_t vz, Double_t time, Double_t polx, Double_t poly, Double_t polz,
178 TMCProcess proc, Int_t& ntr, Double_t weight, Int_t is)
179{
180 PushTrack(toBeDone, parentId, pdgCode, px, py, pz, e, vx, vy, vz, time, polx, poly, polz, proc, ntr, weight, is, -1);
181}
182
183void Stack::PushTrack(Int_t toBeDone, Int_t parentId, Int_t pdgCode, Double_t px, Double_t py, Double_t pz, Double_t e,
184 Double_t vx, Double_t vy, Double_t vz, Double_t time, Double_t polx, Double_t poly, Double_t polz,
185 TMCProcess proc, Int_t& ntr, Double_t weight, Int_t is, Int_t secondparentId)
186{
187 PushTrack(toBeDone, parentId, pdgCode, px, py, pz, e, vx, vy, vz, time, polx, poly, polz, proc, ntr, weight, is, secondparentId, -1, -1, proc);
188}
189
190void Stack::PushTrack(Int_t toBeDone, Int_t parentId, Int_t pdgCode, Double_t px, Double_t py, Double_t pz, Double_t e,
191 Double_t vx, Double_t vy, Double_t vz, Double_t time, Double_t polx, Double_t poly, Double_t polz,
192 TMCProcess proc, Int_t& ntr, Double_t weight, Int_t is, Int_t secondparentId, Int_t daughter1Id, Int_t daughter2Id,
193 TMCProcess proc2)
194{
195 // printf("Pushing %s toBeDone %5d parentId %5d pdgCode %5d is %5d entries %5d \n",
196 // proc == kPPrimary ? "Primary: " : "Secondary: ",
197 // toBeDone, parentId, pdgCode, is, mNumberOfEntriesInParticles);
198
199 //
200 // This method is called
201 //
202 // - during serial simulation directly from the event generator
203 // - during parallel simulation to fill the stack of the primary generator device
204 // - in all cases to push a secondary particle
205 //
206 //
207 // Create new TParticle and add it to the TParticle array
208
209 Int_t trackId = mNumberOfEntriesInParticles;
210 // Set track variable
211 ntr = trackId;
212 // Int_t daughter1Id = -1;
213 // Int_t daughter2Id = -1;
214 Int_t iStatus = (proc == kPPrimary) ? is : trackId;
215 TParticle p(pdgCode, iStatus, parentId, secondparentId, daughter1Id, daughter2Id, px, py, pz, e, vx, vy, vz, time);
216 p.SetPolarisation(polx, poly, polz);
217 p.SetWeight(weight);
218 p.SetUniqueID(proc); // using the unique ID to transfer process ID
219 p.SetBit(ParticleStatus::kPrimary, proc == kPPrimary ? 1 : 0); // set primary bit
220 p.SetBit(ParticleStatus::kToBeDone, toBeDone == 1 ? 1 : 0); // set to be done bit
221 mNumberOfEntriesInParticles++;
222
223 insertInVector(mTrackIDtoParticlesEntry, trackId, (int)(mParticles.size()));
224
225 handleTransportPrimary(p); // handle selective transport of primary particles
226
227 // Push particle on the stack if toBeDone is set
228 if (p.TestBit(ParticleStatus::kPrimary)) {
229 // This is a particle from the primary particle generator
230 //
231 // SetBit is used to pass information about the primary particle to the stack during transport.
232 // Sime particles have already decayed or are partons from a shower. They are needed for the
233 // event history in the stack, but not for transport.
234 //
235
236 // primary particles might have been pushed with a second creation process
237 // in case we pushed a secondary track of a previous simulation to be continued.
238 // We save therefore in the UniqueID the correct process
239 // while the particle will still be treated as a primary given its bit settings
240 p.SetUniqueID(proc2);
241
242 mIndexMap[trackId] = trackId;
243 p.SetBit(ParticleStatus::kKeep, 1);
244 if (p.TestBit(ParticleStatus::kToBeDone)) {
245 mNumberOfPrimariesforTracking++;
246 }
247 mNumberOfPrimaryParticles++;
248 mPrimaryParticles.push_back(p);
249 mTracks->emplace_back(p);
250 } else {
251 mParticles.emplace_back(p);
252 mCurrentParticle0 = p;
253 }
254 mStack.push(p);
255}
256
257void Stack::handleTransportPrimary(TParticle& p)
258{
259 // this function tests whether we really want to transport
260 // this particle and sets the relevant bits accordingly
261
262 if (!p.TestBit(ParticleStatus::kToBeDone) || !p.TestBit(ParticleStatus::kPrimary)) {
263 return;
264 }
265
266 if (!mTransportPrimary(p, mPrimaryParticles)) {
267 p.SetBit(ParticleStatus::kToBeDone, 0);
268 p.SetBit(ParticleStatus::kInhibited, 1);
269 }
270}
271
272void Stack::PushTrack(int toBeDone, TParticle& p)
273{
274 // printf("stack -> Pushing Primary toBeDone %5d %5d parentId %5d pdgCode %5d is %5d entries %5d \n", toBeDone, p.TestBit(ParticleStatus::kToBeDone), p.GetFirstMother(), p.GetPdgCode(), p.GetStatusCode(), mNumberOfEntriesInParticles);
275
276 // This method is called
277 //
278 // - during parallel simulation to push primary particles (called by the stack itself)
279 if (p.TestBit(ParticleStatus::kPrimary)) {
280 // one to one mapping for primaries
281 mIndexMap[mNumberOfPrimaryParticles] = mNumberOfPrimaryParticles;
282 mNumberOfPrimaryParticles++;
283 mPrimaryParticles.push_back(p);
284 // Push particle on the stack
285 if (p.TestBit(ParticleStatus::kToBeDone)) {
286 mNumberOfPrimariesforTracking++;
287 }
288 mStack.push(p);
289 mTracks->emplace_back(p);
290 }
291}
292
296void Stack::SetCurrentTrack(Int_t iTrack)
297{
298 mIndexOfCurrentTrack = iTrack;
299 if (iTrack < mPrimaryParticles.size()) {
300 auto& p = mPrimaryParticles[iTrack];
301 mCurrentParticle = p;
302 mIndexOfCurrentPrimary = iTrack;
303 } else {
304 mCurrentParticle = mCurrentParticle0;
305 }
306}
307
308// calculates a hash based on particle properties
309// hash may serve as seed for this track
310ULong_t getHash(TParticle const& p)
311{
312 auto asLong = [](double x) {
313 return (ULong_t) * (reinterpret_cast<ULong_t*>(&x));
314 };
315
316 ULong_t hash;
317 o2::MCTrackT<double> track(p);
318
319 hash = asLong(track.GetStartVertexCoordinatesX());
320 hash ^= asLong(track.GetStartVertexCoordinatesY());
321 hash ^= asLong(track.GetStartVertexCoordinatesZ());
322 hash ^= asLong(track.GetStartVertexCoordinatesT());
323 hash ^= asLong(track.GetStartVertexMomentumX());
324 hash ^= asLong(track.GetStartVertexMomentumY());
325 hash ^= asLong(track.GetStartVertexMomentumZ());
326 hash += (ULong_t)track.GetPdgCode();
327 return hash;
328}
329
330TParticle* Stack::PopNextTrack(Int_t& iTrack)
331{
332
333 // This functions is mainly used by Geant3?
334 Int_t nprod = (int)(mParticles.size());
335
336 // If end of stack: Return empty pointer
337 if (mStack.empty()) {
338 iTrack = -1;
339 return nullptr;
340 }
341 Bool_t found = kFALSE;
342
343 TParticle* nextParticle = nullptr;
344 while (!found && !mStack.empty()) {
345 // get next particle from stack
346 mCurrentParticle = mStack.top();
347 // remove particle from the top
348 mStack.pop();
349 // test if primary to be transported
350 if (mCurrentParticle.TestBit(ParticleStatus::kToBeDone)) {
351 if (mCurrentParticle.TestBit(ParticleStatus::kPrimary)) {
352 // particle is primary and needs to be tracked -> indicates that previous particle finished
353 mNumberOfPrimariesPopped++;
354 mIndexOfCurrentPrimary = mStack.size();
355 mIndexOfCurrentTrack = mIndexOfCurrentPrimary;
356 } else {
357 mIndexOfCurrentTrack = mCurrentParticle.GetStatusCode();
358 }
359 iTrack = mIndexOfCurrentTrack;
360 if (mDoTrackSeeding) {
361 auto hash = getHash(mCurrentParticle);
362 // LOG(info) << "SEEDING NEW TRACK USING HASH" << hash;
363 // init seed per track
364 gRandom->SetSeed(hash);
366 // NOTE: THE BETTER PLACE WOULD BE IN PRETRACK HOOK BUT THIS DOES NOT SEEM TO WORK
367 // WORKS ONLY WITH G3 SINCE G4 DOES NOT CALL THIS FUNCTION
368 } // .trackSeed ?
369 nextParticle = &mCurrentParticle;
370 found = kTRUE;
371 } else {
372 iTrack = -1;
373 nextParticle = nullptr;
374 }
375 } // while
376 return nextParticle;
377}
378
379TParticle* Stack::PopPrimaryForTracking(Int_t iPrim)
380{
381 // This function is used by Geant4 to setup their own internal stack
382 // printf("PopPrimary for tracking %5d %5d \n", iPrim, mNumberOfPrimaryParticles);
383 // Remark: Contrary to what the interface name is suggesting
384 // this is not a pop operation (but rather a get)
385
386 // Test for index
387 if (iPrim < 0 || iPrim >= mNumberOfPrimaryParticles) {
388 LOG(fatal) << "Stack::PopPrimaryForTracking: Stack: Primary index out of range! " << iPrim << " ";
389 return nullptr;
390 }
391 // Return the iPrim-th TParticle from the fParticle array. This should be
392 // a primary.
393 auto particle = &mPrimaryParticles[iPrim];
394 if (particle->TestBit(ParticleStatus::kToBeDone)) {
395 return particle;
396 } else {
397 return nullptr;
398 }
399}
400
401void Stack::updateEventStats()
402{
403 if (mMCEventStats) {
404 mMCEventStats->setNHits(mHitCounter);
405 mMCEventStats->setNTransportedTracks(mNumberOfEntriesInParticles);
406 mMCEventStats->setNKeptTracks(mTracks->size());
407 }
408}
409
410void Stack::FillTrackArray()
411{
414 LOG(info) << "Stack: " << mTracks->size() << " out of " << mNumberOfEntriesInParticles << " stored \n";
415}
416
417void Stack::FinishPrimary()
418{
419 // Here transport of a primary and all its secondaries is finished
420 // we can do some cleanup of the memory structures
421 mPrimariesDone++;
422 LOG(debug) << "Finish primary hook " << mPrimariesDone;
423 // preserve particles and theire ancestors that produced hits
424
425 auto selected = selectTracks();
426
427 // loop over current particle buffer
428 // - build index map indicesKept
429 // - update mother index information
430 int indexOld = 0;
431 int indexNew = 0;
432 int indexoffset = mTracks->size();
433 int neglected = 0;
434 std::vector<int> indicesKept((int)(mParticles.size()));
435 std::vector<MCTrack> tmpTracks;
436 Int_t ic = 0;
437
438 // mTrackIDtoParticlesEntry
439 // trackID to mTrack -> index in mParticles
440 //
441 // indicesKept
442 // index in mParticles -> index in mTrack - highWaterMark
443 //
444 // mReorderIndices
445 // old (mTrack-highWaterMark) -> new (mTrack-highWaterMark)
446 //
447
448 for (auto& particle : mParticles) {
449 if (particle.getStore() || !mPruneKinematics) {
450 // map the global track index to the new persistent index
451 auto imother = particle.getMotherTrackId();
452 // here mother is relative to the mParticles array
453 if (imother >= 0) {
454 // daughter of a secondary: obtain index from lookup table
455 imother = indicesKept[imother];
456 particle.SetMotherTrackId(imother);
457 }
458 // at this point we have the correct mother index in mParticles or
459 // a negative one which is a pointer to a primary
460 tmpTracks.emplace_back(particle);
461 indicesKept[indexOld] = indexNew;
462 indexNew++;
463 } else {
464 indicesKept[indexOld] = -1;
465 neglected++;
466 }
467 indexOld++;
468 mTracksDone++;
469 }
470 Int_t ntr = (int)(tmpTracks.size());
471 std::vector<int> reOrderedIndices(ntr);
472 std::vector<int> invreOrderedIndices(ntr);
473 for (Int_t i = 0; i < ntr; i++) {
474 invreOrderedIndices[i] = i;
475 reOrderedIndices[i] = i;
476 }
477
478 if (mIsG4Like) {
479 ReorderKine(tmpTracks, reOrderedIndices);
480 for (Int_t i = 0; i < ntr; i++) {
481 Int_t index = reOrderedIndices[i];
482 invreOrderedIndices[index] = i;
483 }
484 }
485 for (Int_t i = 0; i < ntr; i++) {
486 Int_t index = reOrderedIndices[i];
487 auto& particle = tmpTracks[index];
488 Int_t imo = particle.getMotherTrackId();
489 Int_t imo0 = imo;
490 if (imo >= 0) {
491 imo = invreOrderedIndices[imo];
492 }
493 imo += indexoffset;
494 particle.SetMotherTrackId(imo);
495 mTracks->emplace_back(particle);
496 auto& mother = mTracks->at(imo);
497 if (mother.getFirstDaughterTrackId() == -1) {
498 mother.SetFirstDaughterTrackId((int)(mTracks->size()) - 1);
499 }
500 mother.SetLastDaughterTrackId((int)(mTracks->size()) - 1);
501 }
502
503 //
504 // Update index map
505 //
506 Int_t imax = mNumberOfEntriesInParticles;
507 Int_t imin = imax - mParticles.size();
508 for (Int_t idTrack = imin; idTrack < imax; idTrack++) {
509 Int_t index1 = mTrackIDtoParticlesEntry[idTrack];
510 Int_t index2 = indicesKept[index1];
511 if (index2 == -1) {
512 continue;
513 }
514 Int_t index3 = (mIsG4Like) ? invreOrderedIndices[index2] : index2;
515 mIndexMap[idTrack] = index3 + indexoffset;
516 }
517
518 // we can now clear the particles buffer!
519 reOrderedIndices.clear();
520 invreOrderedIndices.clear();
521 mParticles.clear();
522 tmpTracks.clear();
523 mTransportedIDs.clear();
524 mTrackIDtoParticlesEntry.clear();
525 mIndexOfPrimaries.clear();
526}
527
528void Stack::UpdateTrackIndex(TRefArray* detList)
529{
530 // we can avoid any updating in case no tracks have been filtered out
531 // check this like this
532 if (mIndexMap.size() == 0) {
533 LOG(info) << "No TrackIndex update necessary\n";
534 return;
535 }
536
537 // we are getting the detectorlist from FairRoot as TRefArray
538 // at each call, but this list never changes so we cache it here
539 // as the right type to avoid repeated dynamic casts
540 if (mActiveDetectors.size() == 0) {
541 if (detList == nullptr) {
542 LOG(fatal) << "No detList passed to Stack";
543 }
544 auto iter = detList->MakeIterator();
545 while (auto det = iter->Next()) {
546 auto o2det = dynamic_cast<o2::base::Detector*>(det);
547 if (o2det) {
548 mActiveDetectors.emplace_back(o2det);
549 } else {
550 LOG(info) << "Found nonconforming detector " << det->GetName();
551 }
552 }
553 }
554
555 LOG(debug) << "Stack::UpdateTrackIndex: Stack: Updating track indices...";
556 Int_t nColl = 0;
557
558 // update track references
559 // use some caching since repeated trackIDs
560 for (auto& ref : *mTrackRefs) {
561 const auto id = ref.getTrackID();
562 auto iter = mIndexMap.find(id);
563 if (iter == mIndexMap.end()) {
564 LOG(info) << "Invalid trackref ... needs to be rmoved \n";
565 ref.setTrackID(-1);
566 } else {
567 ref.setTrackID(iter->second);
568 }
569 }
570
571 // sort trackrefs according to new track index
572 // then according to track length
573 std::sort(mTrackRefs->begin(), mTrackRefs->end(), [](const o2::TrackReference& a, const o2::TrackReference& b) {
574 if (a.getTrackID() == b.getTrackID()) {
575 return a.getLength() < b.getLength();
576 }
577 return a.getTrackID() < b.getTrackID();
578 });
579
580 for (auto det : mActiveDetectors) {
581 // update the track indices by delegating to specialized detector functions
582 det->updateHitTrackIndices(mIndexMap);
583 } // List of active detectors
584
585 LOG(debug) << "Stack::UpdateTrackIndex: ...stack and " << nColl << " collections updated.";
586}
587
588void Stack::Reset()
589{
590
591 mIndexOfCurrentTrack = -1;
592 mNumberOfPrimaryParticles = mNumberOfEntriesInParticles = mNumberOfEntriesInTracks = 0;
593 while (!mStack.empty()) {
594 mStack.pop();
595 }
596 mParticles.clear();
597 mTracks->clear();
598 if (!mIsExternalMode && (mPrimariesDone != mNumberOfPrimariesforTracking)) {
599 LOG(fatal) << "Inconsistency in primary particles treated " << mPrimariesDone << " vs expected "
600 << mNumberOfPrimariesforTracking << "\n(This points to a flaw in the stack logic)";
601 }
602 mPrimariesDone = 0;
603 mNumberOfPrimariesforTracking = 0;
604 mNumberOfPrimariesPopped = 0;
605 mPrimaryParticles.clear();
606 mTrackRefs->clear();
607 mTrackIDtoParticlesEntry.clear();
608 mHitCounter = 0;
609}
610
611void Stack::Register()
612{
613 FairRootManager::Instance()->RegisterAny("MCTrack", mTracks, kTRUE);
614 FairRootManager::Instance()->RegisterAny("TrackRefs", mTrackRefs, kTRUE);
615}
616
617void Stack::Print(Int_t iVerbose) const
618{
619 cout << "-I- Stack: Number of primaries = " << mNumberOfPrimaryParticles << endl;
620 cout << " Total number of particles = " << mNumberOfEntriesInParticles << endl;
621 cout << " Number of tracks in output = " << mNumberOfEntriesInTracks << endl;
622 if (iVerbose) {
623 for (auto& track : *mTracks) {
624 track.Print();
625 }
626 }
627}
628
629void Stack::Print(Option_t* option) const
630{
631 Int_t verbose = 0;
632 if (option) {
633 verbose = 1;
634 }
635 Print(verbose);
636}
637
638void Stack::addHit(int iDet)
639{
640 // translate detector ID to bit id
641 const auto bitID = o2::base::Detector::getDetId2HitBitIndex()[iDet];
642
643 if (mIndexOfCurrentTrack < mNumberOfPrimaryParticles) {
644 auto& part = mTracks->at(mIndexOfCurrentTrack);
645 part.setHit(bitID);
646
647 } else {
648 Int_t iTrack = mTrackIDtoParticlesEntry[mIndexOfCurrentTrack];
649 auto& part = mParticles[iTrack];
650 part.setHit(bitID);
651 }
652 mCurrentParticle.SetBit(ParticleStatus::kHasHits, 1);
653 mHitCounter++;
654}
655void Stack::addHit(int iDet, Int_t iTrack)
656{
657 mHitCounter++;
658 auto& part = mParticles[iTrack];
659 // fetch the bit encoding for hits
660 const auto bitID = o2::base::Detector::getDetId2HitBitIndex()[iDet];
661 part.setHit(bitID);
662 mCurrentParticle.SetBit(ParticleStatus::kHasHits, 1);
663}
664
665Int_t Stack::GetCurrentParentTrackNumber() const
666{
667 TParticle* currentPart = GetCurrentTrack();
668 if (currentPart) {
669 return currentPart->GetFirstMother();
670 } else {
671 return -1;
672 }
673}
674
675bool Stack::selectTracks()
676{
677 bool tracksdiscarded = false;
678 // Check particles in the fParticle array
679 int prim = -1; // counter how many primaries seen (mainly to constrain search in motherindex remapping)
680 LOG(debug) << "Stack: Entering track selection on " << mParticles.size() << " tracks";
681 for (auto& thisPart : mParticles) {
682 Bool_t store = kTRUE;
683 // Get track parameters
684 Bool_t isPrimary = (thisPart.getProcess() == 0);
685 Int_t iMother = thisPart.getMotherTrackId();
686 auto& mother = mParticles[iMother];
687 Bool_t motherIsPrimary = (iMother < mNumberOfPrimaryParticles);
688
689 if (isPrimary) {
690 prim++;
691 // for primaries we are done quickly
692 // in fact the primary has already been stored
693 // so this should not happen
694 store = kTRUE;
695 } else {
696 // for other particles we potentially need to correct the mother indices
697 if (!motherIsPrimary) {
698 // the mapping is from the index in the stack to the index in mParticles
699 thisPart.SetMotherTrackId(mTrackIDtoParticlesEntry[iMother]);
700 } else {
701 // for a secondary which is a direct decendant of a primary use a negative index which will be restored later
702 thisPart.SetMotherTrackId(iMother - (int)(mTracks->size()));
703 }
704 // no secondaries; also done
705 if (!mStoreSecondaries) {
706 store = kFALSE;
707 tracksdiscarded = true;
708 } else {
709 // Calculate number of hits created by this track
710 // Note: we only distinguish between no hit and more than 0 hits
711 int nHits = thisPart.hasHits();
712 // Check for cuts (store primaries in any case)
713 if (nHits < mMinHits) {
714 store = kFALSE;
715 tracksdiscarded = true;
716 }
717 // only if we have non-trival energy cut
718 if (mEnergyCut > 0.) {
719 Double_t energy = thisPart.GetEnergy();
720 Double_t mass = thisPart.GetMass();
721 Double_t eKin = energy - mass;
722 if (eKin < mEnergyCut) {
723 store = kFALSE;
724 tracksdiscarded = true;
725 }
726 }
727 if (keepPhysics(thisPart)) {
728 store = kTRUE;
729 tracksdiscarded = false;
730 }
731 }
732 }
733
734 store = store || thisPart.getStore();
735 thisPart.setStore(store);
736 }
737
738 // If flag is set, flag recursively mothers of selected tracks
739 //
740 if (mStoreMothers) {
741 for (auto& particle : mParticles) {
742 if (particle.getStore()) {
743 Int_t iMother = particle.getMotherTrackId();
744 while (iMother >= 0) {
745 auto& mother = mParticles[iMother];
746 mother.setStore(true);
747 iMother = mother.getMotherTrackId();
748 } // while mother
749 } // store ?
750 } // particle loop
751 }
752
753 return !tracksdiscarded;
754}
755
756bool Stack::isPrimary(const MCTrack& part)
757{
759 if (part.getProcess() == kPPrimary || part.getMotherTrackId() < 0) {
760 return true;
761 }
763 return false;
764}
765
766bool Stack::isFromPrimaryDecayChain(const MCTrack& part)
767{
772 if (part.getProcess() != kPDecay) {
773 return false;
774 }
776 auto imother = part.getMotherTrackId();
777 auto mother = mParticles[imother];
778 if (isPrimary(mother)) {
779 return true;
780 }
782 return isFromPrimaryDecayChain(mother);
783}
784
785bool Stack::isFromPrimaryPairProduction(const MCTrack& part)
786{
792 if (part.getProcess() != kPPair) {
793 return false;
794 }
796 auto imother = part.getMotherTrackId();
797 auto mother = mParticles[imother];
798 if (isPrimary(mother)) {
799 return true;
800 }
802 return isFromPrimaryDecayChain(mother);
803}
804
805bool Stack::keepPhysics(const MCTrack& part)
806{
807 //
808 // Some particles have to kept on the stack for reasons motivated
809 // by physics analysis. Decision is put here.
810 //
811
812 if (isPrimary(part)) {
813 return true;
814 }
815 if (isFromPrimaryDecayChain(part)) {
816 return true;
817 }
818 if (isFromPrimaryPairProduction(part)) {
819 return true;
820 }
821
822 return false;
823}
824
825TClonesArray* Stack::GetListOfParticles()
826{
827 LOG(fatal) << "Stack::GetListOfParticles interface not implemented\n";
828 return nullptr;
829}
830
831bool Stack::isTrackDaughterOf(int trackid, int parentid) const
832{
833 // a daughter trackid should be larger than parentid
834 if (trackid < parentid) {
835 return false;
836 }
837
838 if (trackid == parentid) {
839 return true;
840 }
841
842 auto mother = getMotherTrackId(trackid);
843 while (mother != -1) {
844 if (mother == parentid) {
845 return true;
846 }
847 mother = getMotherTrackId(mother);
848 }
849 return false;
850}
851
852void Stack::fillParentIDs(std::vector<int>& parentids) const
853{
854 parentids.clear();
855 int mother = mIndexOfCurrentTrack;
856 do {
857 if (mother != -1) {
858 parentids.push_back(mother);
859 }
860 mother = getMotherTrackId(mother);
861 } while (mother != -1);
862}
863
864void Stack::ReorderKine(std::vector<MCTrack>& particles, std::vector<int>& reOrderedIndices)
865{
866 //
867 // Particles are ordered in a way that descendants of a particle appear next to each other.
868 // This has the advantage that their position in the stack can be identified by two number,
869 // for example the index of the first and last descentant.
870 // The result of the ordering is returned via the look-up table reOrderedIndices
871 //
872
873 Int_t ntr = (int)(particles.size());
874 std::vector<bool> done(ntr, false);
875
876 int indexoffset = mTracks->size();
877 Int_t index = 0;
878 Int_t imoOld = 0;
879 for (Int_t i = 0; i < ntr; i++) {
880 reOrderedIndices[i] = i;
881 }
882
883 for (Int_t i = -1; i < ntr; i++) {
884 if (i != -1) {
885 // secondaries
886 if (!done[i]) {
887 reOrderedIndices[index] = i;
888 index++;
889 done[i] = true;
890 }
891 imoOld = i;
892 } else {
893 // current primary
894 imoOld = mIndexOfCurrentPrimary - indexoffset;
895 }
896 for (Int_t j = i + 1; j < ntr; j++) {
897 if (!done[j]) {
898 if ((particles[j]).getMotherTrackId() == imoOld) {
899 reOrderedIndices[index] = j;
900 index++;
901 done[j] = true;
902 } // child found
903 } // done
904 } // j
905 } // i
906}
907
908FairGenericStack* Stack::CloneStack() const { return new o2::data::Stack(*this); }
909
Definition of the Detector class.
Definition of the Stack class.
int16_t time
Definition RawEventData.h:4
int32_t i
bool done
ClassImp(IdPath)
Definition of the MCTrack class.
@ kKeep
@ kHasHits
@ kInhibited
@ kPrimary
@ kToBeDone
uint32_t j
Definition RawData.h:0
void insertInVector(std::vector< T > &v, I index, T e)
Definition Stack.cxx:47
ULong_t getHash(TParticle const &p)
Definition Stack.cxx:310
std::ostringstream debug
int getProcess() const
get the production process (id) of this track
Definition MCTrack.h:230
Double_t GetStartVertexMomentumZ() const
Definition MCTrack.h:81
Double_t GetStartVertexMomentumX() const
Definition MCTrack.h:79
Double_t GetStartVertexCoordinatesY() const
Definition MCTrack.h:83
Double_t GetStartVertexCoordinatesZ() const
Definition MCTrack.h:84
Double_t GetStartVertexMomentumY() const
Definition MCTrack.h:80
Double_t GetStartVertexCoordinatesT() const
Definition MCTrack.h:85
Double_t GetStartVertexCoordinatesX() const
Definition MCTrack.h:82
Int_t GetPdgCode() const
Accessors.
Definition MCTrack.h:72
Int_t getMotherTrackId() const
Definition MCTrack.h:73
static std::vector< int > const & getDetId2HitBitIndex()
Definition Detector.h:221
static VMCSeederService const & instance()
void ReorderKine(std::vector< MCTrack > &particles, std::vector< int > &reOrderedIndices)
Definition Stack.cxx:864
int getMotherTrackId(int) const
Allow to query the direct mother track ID of an arbitrary trackID managed by stack.
Definition Stack.h:345
virtual void Print(Int_t iVerbose=0) const
Definition Stack.cxx:617
TParticle * GetCurrentTrack() const override
Definition Stack.h:125
void PushTrack(Int_t toBeDone, Int_t parentID, Int_t pdgCode, Double_t px, Double_t py, Double_t pz, Double_t e, Double_t vx, Double_t vy, Double_t vz, Double_t time, Double_t polx, Double_t poly, Double_t polz, TMCProcess proc, Int_t &ntr, Double_t weight, Int_t is) override
Definition Stack.cxx:176
std::function< bool(const TParticle &p, const std::vector< TParticle > &particles)> TransportFcn
Definition Stack.h:240
GLint GLenum GLint x
Definition glcorearb.h:403
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLuint index
Definition glcorearb.h:781
GLuint GLuint GLfloat weight
Definition glcorearb.h:5477
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLenum GLfloat param
Definition glcorearb.h:271
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
Stack & operator=(Stack &)=delete
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"