CMS 3D CMS Logo

ParticleManager.cc
Go to the documentation of this file.
2 
3 #include "HepMC/GenEvent.h"
4 #include "HepMC/Units.h"
5 #include "HepPDT/ParticleDataTable.hh"
6 
11 
16 
18  const HepMC::GenEvent & genEvent,
19  const HepPDT::ParticleDataTable & particleDataTable,
20  double beamPipeRadius,
21  double deltaRchargedMother,
22  const fastsim::ParticleFilter & particleFilter,
23  std::vector<SimTrack> & simTracks,
24  std::vector<SimVertex> & simVertices,
25  bool fixLongLivedBug)
26  : genEvent_(&genEvent)
27  , genParticleIterator_(genEvent_->particles_begin())
28  , genParticleEnd_(genEvent_->particles_end())
29  , genParticleIndex_(1)
30  , particleDataTable_(&particleDataTable)
31  , beamPipeRadius2_(beamPipeRadius*beamPipeRadius)
32  , deltaRchargedMother_(deltaRchargedMother)
33  , particleFilter_(&particleFilter)
34  , simTracks_(&simTracks)
35  , simVertices_(&simVertices)
36  // prepare unit convsersions
37  // --------------------------------------------
38  // | | hepmc | cms |
39  // --------------------------------------------
40  // | length | genEvent_->length_unit | cm |
41  // | momentum | genEvent_->momentum_unit | GeV |
42  // | time | length unit (t*c) | ns |
43  // --------------------------------------------
44  , momentumUnitConversionFactor_(conversion_factor( genEvent_->momentum_unit(), HepMC::Units::GEV ))
45  , lengthUnitConversionFactor_(conversion_factor(genEvent_->length_unit(),HepMC::Units::LengthUnit::CM))
46  , lengthUnitConversionFactor2_(lengthUnitConversionFactor_*lengthUnitConversionFactor_)
47  , timeUnitConversionFactor_(lengthUnitConversionFactor_/fastsim::Constants::speedOfLight)
48  , fixLongLivedBug_(fixLongLivedBug)
49 {
50 
51  // add the main vertex from the signal event to the simvertex collection
52  if(genEvent.vertices_begin() != genEvent_->vertices_end())
53  {
54  const HepMC::FourVector & position = (*genEvent.vertices_begin())->position();
56  position.y()*lengthUnitConversionFactor_,
57  position.z()*lengthUnitConversionFactor_,
58  position.t()*timeUnitConversionFactor_)
59  ,-1);
60  }
61 }
62 
64 
66 {
67  std::unique_ptr<fastsim::Particle> particle;
68 
69  // retrieve particle from buffer
70  if(!particleBuffer_.empty())
71  {
72  particle = std::move(particleBuffer_.back());
73  particleBuffer_.pop_back();
74  }
75  // or from genParticle list
76  else
77  {
78  particle = nextGenParticle();
79  if(!particle) return nullptr;
80  }
81 
82  // if filter does not accept, skip particle
83  if(!particleFilter_->accepts(*particle))
84  {
85  return nextParticle(random);
86  }
87 
88  // lifetime or charge of particle are not yet set
89  if(!particle->remainingProperLifeTimeIsSet() || !particle->chargeIsSet())
90  {
91  // retrieve the particle data
92  const HepPDT::ParticleData * particleData = particleDataTable_->particle(HepPDT::ParticleID(particle->pdgId()));
93  if(!particleData)
94  {
95  // in very few events the Decayer (pythia) produces high mass resonances that are for some reason not present in the table (even though they should technically be)
96  // they have short lifetimes, so decay them right away (charge and lifetime cannot be taken from table)
97  particle->setRemainingProperLifeTimeC(0.);
98  particle->setCharge(0.);
99  }
100 
101  // set lifetime
102  if(!particle->remainingProperLifeTimeIsSet())
103  {
104  // The lifetime is 0. in the Pythia Particle Data Table! Calculate from width instead (ct=hbar/width).
105  // ct=particleData->lifetime().value();
106  double width = particleData->totalWidth().value();
107  if(width > 1.0e-35)
108  {
109  particle->setRemainingProperLifeTimeC(-log(random.flatShoot())*6.582119e-25/width/10.); // ct in cm
110  }
111  else
112  {
113  particle->setStable();
114  }
115  }
116 
117  // set charge
118  if(!particle->chargeIsSet())
119  {
120  particle->setCharge(particleData->charge());
121  }
122  }
123 
124  // add corresponding simTrack to simTrack collection
125  unsigned simTrackIndex = addSimTrack(particle.get());
126  particle->setSimTrackIndex(simTrackIndex);
127 
128  // and return
129  return particle;
130 }
131 
132 
134  const math::XYZTLorentzVector & vertexPosition,
135  int parentSimTrackIndex,
136  std::vector<std::unique_ptr<Particle> > & secondaries,
137  const SimplifiedGeometry * layer)
138 {
139 
140  // vertex must be within the accepted volume
141  if(!particleFilter_->acceptsVtx(vertexPosition))
142  {
143  return;
144  }
145 
146  // no need to create vertex in case no particles are produced
147  if(secondaries.empty()){
148  return;
149  }
150 
151  // add simVertex
152  unsigned simVertexIndex = addSimVertex(vertexPosition,parentSimTrackIndex);
153 
154  // closest charged daughter continues the track of the mother particle
155  // simplified tracking algorithm for fastSim
156  double distMin = 99999.;
157  int idx = -1;
158  int idxMin = -1;
159  for(auto & secondary : secondaries)
160  {
161  idx++;
162  if(secondary->getMotherDeltaR() != -1){
163  if(secondary->getMotherDeltaR() > deltaRchargedMother_){
164  // larger than max requirement on deltaR
165  secondary->resetMother();
166  }else{
167  if(secondary->getMotherDeltaR() < distMin){
168  distMin = secondary->getMotherDeltaR();
169  idxMin = idx;
170  }
171  }
172  }
173  }
174 
175  // add secondaries to buffer
176  idx = -1;
177  for(auto & secondary : secondaries)
178  {
179  idx++;
180  if(idxMin != -1){
181  // reset all but the particle with the lowest deltaR (which is at idxMin)
182  if(secondary->getMotherDeltaR() != -1 && idx != idxMin){
183  secondary->resetMother();
184  }
185  }
186 
187  // set origin vertex
188  secondary->setSimVertexIndex(simVertexIndex);
189  //
190  if(layer)
191  {
192  secondary->setOnLayer(layer->isForward(), layer->index());
193  }
194  // ...and add particle to buffer
195  particleBuffer_.push_back(std::move(secondary));
196  }
197 
198 }
199 
201 {
202  return this->addSimVertex(particle->position(), particle->simTrackIndex());
203 }
204 
207  int parentSimTrackIndex)
208 {
209  int simVertexIndex = simVertices_->size();
210  simVertices_->emplace_back(position.Vect(),
211  position.T(),
212  parentSimTrackIndex,
213  simVertexIndex);
214  return simVertexIndex;
215 }
216 
217 
219 {
220  int simTrackIndex = simTracks_->size();
221  simTracks_->emplace_back(particle->pdgId(),
222  particle->momentum(),
223  particle->simVertexIndex(),
224  particle->genParticleIndex());
225  simTracks_->back().setTrackId(simTrackIndex);
226  return simTrackIndex;
227 }
228 
229 std::unique_ptr<fastsim::Particle> fastsim::ParticleManager::nextGenParticle()
230 {
231  // only consider particles that start in the beam pipe and end outside the beam pipe
232  // try to get the decay time from pythia
233  // use hepmc units
234  // make the link simtrack to simvertex
235  // try not to change the simvertex structure
236 
237  // loop over gen particles
239  {
240  // some handy pointers and references
241  const HepMC::GenParticle & particle = **genParticleIterator_;
242  const HepMC::GenVertex * productionVertex = particle.production_vertex();
243  const HepMC::GenVertex * endVertex = particle.end_vertex();
244  // skip incoming particles
245  if(!productionVertex){
246  continue;
247  }
248 
249  if (std::abs(particle.pdg_id()) < 10 || std::abs(particle.pdg_id()) == 21) {
250  continue;
251  }
252 
253  // particles which do not descend from exotics must be produced within the beampipe
254  int exoticRelativeId = 0;
255  const bool producedWithinBeamPipe = productionVertex->position().perp2() * lengthUnitConversionFactor2_ < beamPipeRadius2_;
256  if (!producedWithinBeamPipe) //
257  {
258  exoticRelativesChecker(productionVertex, exoticRelativeId, 0);
259  if (!isExotic(fixLongLivedBug_, exoticRelativeId)) {
260  continue;
261  }
262  }
263  const bool decayedWithinBeamPipe = endVertex && endVertex->position().perp2() * lengthUnitConversionFactor2_ < beamPipeRadius2_;
264  // FastSim will not make hits out of particles that decay before reaching the beam pipe
265  if(decayedWithinBeamPipe)
266  {
267  continue;
268  }
269 
270  // SM particles that descend from exotics and cross the beam pipe radius should make hits but not be decayed, by default it will duplicate FastSim hits for long lived particles and so anything produced without activating fixLongLivedBug_ is physically wrong
271  if (fixLongLivedBug_ && producedWithinBeamPipe && !decayedWithinBeamPipe){
272  exoticRelativesChecker(productionVertex, exoticRelativeId, 0);
273  }
274 
275  // make the particle
276  std::unique_ptr<Particle> newParticle(
277  new Particle(particle.pdg_id(),
278  math::XYZTLorentzVector(productionVertex->position().x()*lengthUnitConversionFactor_,
279  productionVertex->position().y()*lengthUnitConversionFactor_,
280  productionVertex->position().z()*lengthUnitConversionFactor_,
281  productionVertex->position().t()*timeUnitConversionFactor_),
283  particle.momentum().y()*momentumUnitConversionFactor_,
284  particle.momentum().z()*momentumUnitConversionFactor_,
285  particle.momentum().e()*momentumUnitConversionFactor_)));
286  newParticle->setGenParticleIndex(genParticleIndex_);
287  if (isExotic(fixLongLivedBug_, exoticRelativeId)) {
288  newParticle->setMotherPdgId(exoticRelativeId);
289  }
290  // try to get the life time of the particle from the genEvent
291  if(endVertex)
292  {
293  double labFrameLifeTime = (endVertex->position().t() - productionVertex->position().t())*timeUnitConversionFactor_;
294  newParticle->setRemainingProperLifeTimeC(labFrameLifeTime / newParticle->gamma() * fastsim::Constants::speedOfLight);
295  }
296 
297  // Find production vertex if it already exists. Otherwise create new vertex
298  // Possible to recreate the whole GenEvent using SimTracks/SimVertices (see FBaseSimEvent::fill(..))
299  bool foundVtx = false;
300  for(const auto& simVtx : *simVertices_){
301  if(std::abs(simVtx.position().x() - newParticle->position().x()) < 1E-3 && std::abs(simVtx.position().y() - newParticle->position().y()) < 1E-3 && std::abs(simVtx.position().z() - newParticle->position().z()) < 1E-3){
302  newParticle->setSimVertexIndex(simVtx.vertexId());
303  foundVtx = true;
304  break;
305  }
306  }
307  if(!foundVtx) newParticle->setSimVertexIndex(addSimVertex(newParticle->position(), -1));
308 
309  // iterator/index has to be increased in case of return (is not done by the loop then)
311  // and return
312  return newParticle;
313  }
314 
315  return std::unique_ptr<Particle>();
316 }
317 
318 void fastsim::ParticleManager::exoticRelativesChecker(const HepMC::GenVertex* originVertex,
319  int& exoticRelativeId_,
320  int ngendepth = 0) {
321  if (ngendepth > 99 || exoticRelativeId_ == -1 || isExotic(fixLongLivedBug_, std::abs(exoticRelativeId_)))
322  return;
323  ngendepth += 1;
324  std::vector<HepMC::GenParticle*>::const_iterator relativesIterator_ = originVertex->particles_in_const_begin();
325  std::vector<HepMC::GenParticle*>::const_iterator relativesIteratorEnd_ = originVertex->particles_in_const_end();
326  for (; relativesIterator_ != relativesIteratorEnd_; ++relativesIterator_) {
327  const HepMC::GenParticle& genRelative = **relativesIterator_;
328  if (isExotic(fixLongLivedBug_, std::abs(genRelative.pdg_id()))) {
329  exoticRelativeId_ = genRelative.pdg_id();
330  if (ngendepth == 100)
331  exoticRelativeId_ = -1;
332  return;
333  }
334  const HepMC::GenVertex* vertex_ = genRelative.production_vertex();
335  if (!vertex_)
336  return;
337  exoticRelativesChecker(vertex_, exoticRelativeId_, ngendepth);
338  }
339  return;
340 }
Implementation of a generic detector layer (base class for forward/barrel layers).
const math::XYZTLorentzVector & position() const
Return position of the particle.
Definition: Particle.h:142
double flatShoot(double xmin=0.0, double xmax=1.0) const
HepPDT::ParticleDataTable ParticleDataTable
const double deltaRchargedMother_
For FastSim (cheat) tracking: cut on the angle between a charged mother and charged daughter...
bool accepts(const Particle &particle) const
Check all if all criteria are fullfilled.
const ParticleFilter *const particleFilter_
(Kinematic) cuts on the particles that have to be propagated.
int genParticleIndex() const
Return index of the particle in the genParticle vector.
Definition: Particle.h:167
double momentumUnitConversionFactor_
Convert pythia units to GeV (FastSim standard)
std::vector< std::unique_ptr< Particle > > particleBuffer_
The vector of all secondaries that are not yet propagated in the event.
static double constexpr speedOfLight
Speed of light [cm / ns].
Definition: Constants.h:16
virtual bool isForward() const =0
Returns false/true depending if the object is a (non-abstract) barrel/forward layer.
HepMC::GenEvent::particle_const_iterator genParticleIterator_
Iterator to keep track on which GenParticles where already considered.
int pdgId() const
Return pdgId of the particle.
Definition: Particle.h:136
TRandom random
Definition: MVATrainer.cc:138
const HepMC::GenEvent *const genEvent_
The GenEvent.
const HepMC::GenEvent::particle_const_iterator genParticleEnd_
The last particle of the GenEvent.
double lengthUnitConversionFactor2_
Convert pythia unis to cm^2 (FastSim standard)
unsigned addSimTrack(const Particle *particle)
Add a simTrack (simTrack contains some basic info about the particle, e.g. pdgId).
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Definition: LorentzVector.h:29
int simVertexIndex() const
Return index of the origin vertex.
Definition: Particle.h:161
const double beamPipeRadius2_
(Radius of the beampipe)^2
~ParticleManager()
Default destructor.
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
void addSecondaries(const math::XYZTLorentzVector &vertexPosition, int motherSimTrackId, std::vector< std::unique_ptr< Particle > > &secondaries, const SimplifiedGeometry *layer=nullptr)
Adds secondaries that are produced by any of the interactions (or particle decay) to the buffer...
bool isExotic(bool fixLongLivedBug, int pdgid_)
ParticleManager(const HepMC::GenEvent &genEvent, const HepPDT::ParticleDataTable &particleDataTable, double beamPipeRadius, double deltaRchargedMother, const ParticleFilter &particleFilter, std::vector< SimTrack > &simTracks, std::vector< SimVertex > &simVertices, bool fixLongLivedBug)
Constructor.
std::unique_ptr< Particle > nextParticle(const RandomEngineAndDistribution &random)
Returns the next particle that has to be propagated (secondary or genParticle).
void exoticRelativesChecker(const HepMC::GenVertex *originVertex, int &hasExoticAssociation, int ngendepth)
HepPDT::ParticleData ParticleData
int simTrackIndex() const
Return index of the SimTrack.
Definition: Particle.h:155
std::vector< SimTrack > * simTracks_
The generated SimTrack of this event.
std::unique_ptr< Particle > nextGenParticle()
Returns next particle from the GenEvent that has to be propagated.
double lengthUnitConversionFactor_
Convert pythia unis to cm (FastSim standard)
const HepPDT::ParticleDataTable *const particleDataTable_
Necessary to get information like lifetime and charge of a particle if unknown.
double timeUnitConversionFactor_
Convert pythia unis to ns (FastSim standard)
int index() const
Return index of this layer (layers are numbered according to their position in the detector)...
static int position[264][3]
Definition: ReadPGInfo.cc:509
std::vector< SimVertex > * simVertices_
The generated SimVertices of this event.
const math::XYZTLorentzVector & momentum() const
Return momentum of the particle.
Definition: Particle.h:145
(Kinematic) cuts on the particles that are propagated.
Definition of a generic FastSim Particle which can be propagated through the detector (formerly Parti...
Definition: Particle.h:19
int genParticleIndex_
Index of particle in the GenEvent (if it is a GenParticle)
unsigned addSimVertex(const math::XYZTLorentzVector &position, int motherIndex)
Add a simVertex (simVertex contains information about the track it was produced). ...
unsigned addEndVertex(const Particle *particle)
Necessary to add an end vertex to a particle.
def move(src, dest)
Definition: eostools.py:511
bool acceptsVtx(const math::XYZTLorentzVector &originVertexPosition) const
Vertex within tracker volume.