ATLAS Offline Software
ParticleDecayer.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // SUMMARY: This code implements a "particle decayer" to allow us to augment the standard
6 // "particle gun" with correlated particles, such as those from a decay. We assume that
7 // some previous code has generated a scalar or a boson according to some preferred angular and momentum
8 // distributions using a "geantino" (PDG ID 999). ParticleDecayer will then find this input
9 // geantino assigns a given mass and (using the user defined parameters provided) select a decay vertex location where
10 // the "geantino" is forced to decay into a particle/antiparticle pair.
11 // The processes that the user can generate are
12 //
13 // s -> gd + gd
14 // gd -> l + l
15 //
16 // or
17 //
18 // gd -> l + l
19 //
20 //
21 // See the jobOption in share folder for more information.
22 //
23 
25 #include "HepPDT/ParticleDataTable.hh"
27 #include "CLHEP/Random/RandomEngine.h"
28 #include <cmath> //M_PI
29 
31 //function to generate a lifetime (actually decay-length) according to the proper lifetime of the particle particle
32 double ParticleDecayer::rnd_ExpLifetime(CLHEP::HepRandomEngine* engine, double ct) {
33  double r = engine->flat(); //< Return random num in [0,1]
34  return ((-ct)*std::log(1.-r));
35 }
36 
38 //function to generate a uniform distribution in (a,b)
39 double ParticleDecayer::rnd_DoubleRange(CLHEP::HepRandomEngine* engine, double a, double b) {
40  double r = engine->flat(); //< Return random num in [0,1]
41  return a + r*(b-a);
42 }
43 
44 
46 //function to generate a cos theta valua according to angular distribution
47 double ParticleDecayer::cosgen(CLHEP::HepRandomEngine* engine, int itype){
48  double x,fx,hit;
49  x=0;
50 
51  if(itype==0){ // flat
52  x=rnd_DoubleRange(engine,-1.,1.);
53  return x;
54  }
55 
56  if(itype==1){ // f(cost)=1.5*cost^2
57  hit=1.5;
58  fx=0;
59  while(hit>fx){
60  x=rnd_DoubleRange(engine,-1.,1.);
61  hit=rnd_DoubleRange(engine,0.,1.5);
62  fx=1.5*x*x;
63  }
64  return x;
65  }
66 
67  if(itype==2){ // f(cost)=0.375(1+cost^2)
68  hit=0.75;
69  fx=0;
70  while(hit>fx){
71  x=rnd_DoubleRange(engine,-1.,1.);
72  hit=rnd_DoubleRange(engine,0.,0.75);
73  fx=0.375*(1+x*x);
74  }
75  return x;
76  }
77 
78  if(itype==3){ // f(cost)=0.75(1-cost^2)
79  hit=1.5;
80  fx=0;
81  while(hit>fx){
82  x=rnd_DoubleRange(engine,-1.,1.);
83  hit=rnd_DoubleRange(engine,0.,1.5);
84  fx=0.75*(1-x*x);
85  }
86  return x;
87  }
88 
89  return x;
90 
91 }
92 
95 {
96  double e = genpart->momentum().e();
97  double theta = genpart->momentum().theta();
98  double phi = genpart->momentum().phi();
99  //Sanity check
100  double p2 = e*e - newMass*newMass;
101  if ( p2 < 0 ) {
102  ATH_MSG_FATAL("ParticleDecayer::fillEvt: -- you have generated a tachyon!");
103  return StatusCode::FAILURE;
104  }
105  //At this point, we have e, theta, and phi. Put them together to get the four-momentum.
106  double p = std::sqrt(p2);
107  double px = p*std::sin(theta)*std::cos(phi);
108  double py = p*std::sin(theta)*std::sin(phi);
109  double pz = p*std::cos(theta);
110  //Fill the four-momentum
111  const CLHEP::HepLorentzVector updatedLV(px,py,pz,e);
112  genpart->set_momentum(HepMC::FourVector(updatedLV.x(),updatedLV.y(),updatedLV.z(),updatedLV.e()));
113  genpart->set_generated_mass(newMass);
114  return StatusCode::SUCCESS;
115 }
116 
118 StatusCode ParticleDecayer::setDecayPosition( CLHEP::HepRandomEngine* engine, HepMC::GenParticlePtr genpart, HepMC::GenEvent* event, bool doScalarDecay )
119 {
120  HepMC::GenVertexPtr vtxp = genpart->production_vertex();
121  if(!vtxp) {
122  ATH_MSG_FATAL("ParticleDecayer::fillEvt: -- no production vertex position found!");
123  return StatusCode::FAILURE;
124  }
125  if ( doScalarDecay ) // scalar decay is prompt. decay vtx == scalar production vertex
126  {
128  end_vtx->set_position(vtxp->position());
129  end_vtx->add_particle_in(genpart);
130  event->add_vertex(end_vtx);
131  return StatusCode::SUCCESS;
132  }
133 
134  //lifetime handling
135  double gamma = genpart->momentum().e()/genpart->momentum().m();
136  double ctau = 0.;
137  double theta = genpart->momentum().theta();
138 
139  // Make sure theta is between 0 and pi
140  while( theta > M_PI )
141  {
142  theta -= M_PI;
143  }
144  while( theta < 0 )
145  {
146  theta += M_PI;
147  }
148 
150  {
151  if(m_expDecayDoVariableLifetime) // Variable proper lifetime distribution, such that fixed fraction of events decays within detector, independent of boost
152  {
153  double distanceToEdge = -999.;
154  if ( theta < m_thetaEndCapBarrel || theta > ( M_PI - m_thetaEndCapBarrel) ) // Particle escapes through endcap
155  {
156  distanceToEdge = std::abs(m_endCapDistance/std::cos(theta));
157  }
158  else // Particle escapes through barrel
159  {
160  distanceToEdge = m_barrelRadius/std::sin(theta);
161  }
162  if ( gamma < 1. )
163  {
164  ATH_MSG_FATAL("Gamma factor cannot be smaller than 1" );
165  return StatusCode::FAILURE;
166  }
167  double Limit = distanceToEdge / gamma; // ctau is enhanced by factor gamma in lab frame
168  double lambda = -1.*Limit/std::log(1. - m_expDecayFractionToKeep);
169  ctau = rnd_ExpLifetime(engine,lambda);
171  {
172  while ( ctau > Limit ) // If decay is outside detector, let's sample again (Produces a truncated exponential)
173  {
174  ctau = rnd_ExpLifetime(engine, lambda);
175  }
176  }
177  }
178  else if( m_particleLifeTime > 0 ) // Fixed proper lifetime distribution. Note that if m_particleLifeTime <= 0. ctau remains 0
179  {
180  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set lifetime of the dark photon according to ctau = " << m_particleLifeTime);
182  }
183  }else if (m_doUniformDecay)
184  {
185  double decayRadius = -999.;
186  if ( theta < m_thetaEndCapBarrel || theta > ( M_PI - m_thetaEndCapBarrel) ) // Particle escapes through endcap
187  {
188  double outerLength = std::abs(m_endCapDistance/std::cos(theta));
189  double outerRadius = outerLength*std::sin(theta);
190  decayRadius = rnd_DoubleRange(engine,0., std::min(outerRadius, std::abs(m_barrelRadius)) );
191  }else // Particle escapes through barrel
192  {
193  decayRadius = rnd_DoubleRange(engine,0., std::abs(m_barrelRadius));
194  }
195 
196  double decayLength = decayRadius/std::sin(theta);
197  ctau = decayLength/gamma;
198  }else
199  {
200  ATH_MSG_FATAL("have to pick uniform or exponential decay distance");
201  return StatusCode::FAILURE;
202  }
203 
204  double ctg = gamma * ctau;
205  double px = genpart->momentum().px();
206  double py = genpart->momentum().py();
207  double pz = genpart->momentum().pz();
208  double p = std::sqrt(px*px + py*py + pz*pz);
209 
210  const CLHEP::HepLorentzVector posLV(((ctg*px/p)+(vtxp->position().x())), ((ctg*py/p)+(vtxp->position().y())), ((ctg*pz/p)+(vtxp->position().z())), ((ctg)+(vtxp->position().t())));
211 
212  //set the decay vertex position of the particle
213  //Create a HepMC vertex at the decay position of the particle
214  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the decay vertex");
216  end_vtx->set_position(HepMC::FourVector(posLV.x(),posLV.y(),posLV.z(),posLV.t()));
217  end_vtx->add_particle_in(genpart);
218  event->add_vertex(end_vtx);
219  return StatusCode::SUCCESS;
220 }
221 
223 ParticleDecayer::ParticleDecayer(const std::string& name, ISvcLocator* pSvcLocator) :
224  GenModule(name, pSvcLocator),
225  m_truthParticleContainerName("GEN_EVENT"),
226  m_eventCounter(0)
227 {
228  declareProperty("McEventCollection", m_truthParticleContainerName);
229  declareProperty("LJType", m_LJType = 1); //1 = one dark photon per LeptonJet, 2 = two dark photons per LeptonJet
230  declareProperty("ScalarPDGID", m_scalarPDGID); //new PDG ID of the scalar
231  declareProperty("ScalarMass", m_scalarMass); //new mass of the scalar in MeV
232  declareProperty("ParticleID", m_particleID = 999); //PDG ID of the geantino
233  declareProperty("ParticleMass", m_particleMass = 400); //new mass of the dark photon in MeV (default 400 MeV)
234  declareProperty("ParticleLifeTime", m_particleLifeTime = 0); //ctau of the dark photon in mm (default prompt)
235  declareProperty("ParticlePolarization", m_particlePolarization = 0); //polarization of the dark photon (default 0 : isotropic decay, -1 : transverse, 1 : longitudinal)
236  declareProperty("OppositePolarization", m_oppositePolarization = false);//In case of LJType == 2 and opposite polarization for the two dark photons in the event
237  declareProperty("ParticlePDGID", m_particlePDGID = 700022); //new PDG ID of the dark photon (default 700022)
238  declareProperty("DecayBRElectrons", m_BRElectron = 1.); //BR of dark photon decay to electrons
239  declareProperty("DecayBRMuons", m_BRMuon = 0.); //BR of dark photon decay to muons
240  declareProperty("DecayBRPions", m_BRPion = 0.); //BR of dark photon decay to pions
241 
242  //Choose between the different types of displaced decays
243  declareProperty("DoUniformDecay", m_doUniformDecay = false);
244  declareProperty("DoExponentialDecay", m_doExponentialDecay = true );
245  declareProperty("ExpDecayDoVariableLifetime", m_expDecayDoVariableLifetime = false );
246  declareProperty("ExpDecayPercentageToKeep", m_expDecayFractionToKeep = 0.8 );
247  declareProperty("ExpDecayDoTruncateLongDecays", m_expDecayDoTruncateLongDecays = false );
248 
249  //Dimensions within which to decay in case of non-prompt events
250  declareProperty("BarrelRadius", m_barrelRadius = 10.e3 ); // outer limit for decay radius
251  declareProperty("EndCapDistance", m_endCapDistance = 15.e3 ); // outer limit along z for decays in endcap
252  declareProperty("ThetaEndCapBarrel", m_thetaEndCapBarrel = 0.439067982); // theta if where to switch between barrel and endcap (default: eta = 1.5)
253 }
254 
256 
258 {
259  // Check here if the tool has been configured correctly
261  {
262  ATH_MSG_FATAL("Cannot configure exponential and uniform decay at the same time.");
263  return StatusCode::FAILURE;
264  }
265 
266  double TOTBR = m_BRElectron + m_BRMuon + m_BRPion;
267  if (TOTBR>1.0000001) {
268  ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Branching Ratio sum is larger than 1!! Please check the values in your jobOption.");
269  ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Branching Ratio Electrons " << m_BRElectron);
270  ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Branching Ratio Muons " << m_BRMuon);
271  ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Branching Ratio Pions " << m_BRPion);
272  ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Total Branching Ratio " << TOTBR);
273  return StatusCode::FAILURE;
274  }
275 
276  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- daughters randomly produced: " << m_BRElectron << "% e, " << m_BRMuon << "% mu, " << m_BRPion << "% pi");
277 
278  if( m_LJType != 1 && m_LJType != 2 )
279  {
280  ATH_MSG_FATAL("LJType is set to " << m_LJType);
281  ATH_MSG_FATAL("LJType has to be set to either 1 or 2");
282  return StatusCode::FAILURE;
283  }
284 
285 
286  return StatusCode::SUCCESS;
287 }
288 
291 
292  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- EventCounter: " << m_eventCounter);
293 
294  const EventContext& ctx = Gaudi::Hive::currentContext();
295  CLHEP::HepRandomEngine* engine = this->getRandomEngine("ParticleDecayer", ctx);
296 
297  StatusCode status = StatusCode::SUCCESS;
298 
299  // Extract the event from the TES
300  McEventCollection* mcEvtColl = nullptr;
301  if (evtStore()->contains<McEventCollection>(m_truthParticleContainerName) && evtStore()->retrieve(mcEvtColl, m_truthParticleContainerName).isSuccess() ) {
302  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- Found an McEventCollection for ParticleDecayer");
303  } else {
304  ATH_MSG_FATAL("TES is empty!!!!");
305  status = StatusCode::FAILURE;
306  return status;
307  }
308 
309  event = mcEvtColl->back();
310 
311  if (event == NULL) {
312  ATH_MSG_FATAL("ParticleDecayer::fillEvt: -- McEvent was not successfully created");
313  status = StatusCode::FAILURE;
314  return status;
315  }
316 
317  for ( auto genpart : *event) {
318 
320  // only one dark photon per LeptonJet //
322  if (m_LJType == 1) {
323  if (genpart->pdg_id()==m_particleID) { //if geantino assign the new mass and cross-check
324  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- only one dark photon per LeptonJet");
325  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- found MC particle with PDG ID = " << genpart->pdg_id());
326  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- assign the new mass of the dark photon, m = " << m_particleMass);
327 
328  //Change the mass of the parent particle ( set by user input + command )
329  //Changes the magnitude of the spatial part of the 4-momentum such that the new 4-momentum has the desired inv mass
331 
332  //Add decay position to the event
333  CHECK( setDecayPosition( engine, genpart, event ) );
334 
335  //assign the new PDG_ID of the particle
336  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new PDG ID = " << m_particlePDGID);
337  genpart->set_pdg_id(m_particlePDGID);
338 
339  //set the new status (decayed) of the particle
340  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new status = 2");
341  genpart->set_status(2);
342 
343  //set the new momentum of the particle
344  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new momentum");
345 
348 
349  }
350  }else if (m_LJType == 2) {
352  // two dark photons per LeptonJet //
354  if (genpart->pdg_id()==m_particleID) {
355 
356  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- two dark photons per LeptonJet");
357  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- found MC particle with PDG ID = " << genpart->pdg_id());
358  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- assign the new mass of the dark scalar, m = " << m_scalarMass);
359 
360  //Get the mass of the parent particle ( set by user input + command )
361  //Change the mass of the parent particle ( set by user input + command )
362  //Changes the magnitude of the spatial part of the 4-momentum such that the new 4-momentum has the desired inv mass
364 
365  //set the new PDG_ID of the scalar
366  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new PDG ID = " << m_scalarPDGID);
367  genpart->set_pdg_id(m_scalarPDGID);
368 
369  //set the new status (decayed) of the scalar
370  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new status = 2");
371  genpart->set_status(2);
372 
373  //set the decay vertex position of the scalar
374  //Create a HepMC vertex at the decay position of the scalar
375  CHECK( setDecayPosition( engine, genpart, event, true ) );
376 
378  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- allow the two-body decay of the dark scalar to dark photons...");
379  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- dark photon has PDG ID = " << m_particlePDGID);
380 
381  std::vector<CLHEP::HepLorentzVector> darkPhotonLVs;
382  CHECK( getDecayProducts( engine, CLHEP::HepLorentzVector( genpart->momentum().px(), genpart->momentum().py(), genpart->momentum().pz(), genpart->momentum().e() ),
384  darkPhotonLVs) );
385 
386  //add dark photon 1
387  auto v0=darkPhotonLVs.at(0).vect();
388  addParticle( genpart->end_vertex(), m_particlePDGID, HepMC::FourVector(v0.x(),v0.y(),v0.z(),0.0) , 2);
389  //add dark photon 2
390  auto v1=darkPhotonLVs.at(1).vect();
391  addParticle( genpart->end_vertex(), m_particlePDGID, HepMC::FourVector(v1.x(),v1.y(),v1.z(),0.0), 2);
392 
393  //lifetime handling of the dark photons
394  int polarizationSwitch = 1;
395 #ifdef HEPMC3
396  auto pItBegin = genpart->end_vertex()->particles_out().end();
397  auto pItEnd = genpart->end_vertex()->particles_out().end();
398 #else
399  HepMC::GenVertex::particles_out_const_iterator pItBegin = genpart->end_vertex()->particles_out_const_begin();
400  HepMC::GenVertex::particles_out_const_iterator pItEnd = genpart->end_vertex()->particles_out_const_end();
401 #endif
402  for ( auto pIt=pItBegin ; pIt != pItEnd; ++pIt )
403  {
404  //Add decay position to the event
405  CHECK( setDecayPosition( engine, *pIt, event ) );
406  //And perform two-body decay
407  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- Now allow the two-body decay of the dark photons");
408  CHECK( DFTwoBodyDecay( engine, *pIt, polarizationSwitch*m_particlePolarization ) );
410  {
411  polarizationSwitch = -polarizationSwitch;
412  }
413  }
414 
415  }
416  }else
417  {
418  ATH_MSG_FATAL("LJType set to " << m_LJType );
419  ATH_MSG_FATAL("LJType must be 1 or 2" );
420  return StatusCode::FAILURE;
421  }
422  }
423 
424  //set the event number
425  event->set_event_number(m_eventCounter);
426 
427  //Add a unit entry to the event weight vector if it's currently empty
428  if (event->weights().empty()) {
429  event->weights().push_back(1.);
430  }
431 
432  //increment the event counter
433  m_eventCounter++;
434 
435  return status;
436 }
437 
438 
440 void ParticleDecayer::addParticle(HepMC::GenVertexPtr prod_vtx, int pdg, HepMC::FourVector momentum, int statusCode) {
441 
442  double mass = 0.;
443  if( pdg == m_particlePDGID)
444  {
446  }else
447  {
448  mass = getParticleMass(pdg);
449  }
450  double energy=std::sqrt(std::pow(momentum.x(),2)+std::pow(momentum.y(),2)+std::pow(momentum.z(),2)+mass*mass);
451 HepMC::GenParticlePtr aParticle = HepMC::newGenParticlePtr (HepMC::FourVector(momentum.x(), momentum.y(), momentum.z(), energy),
452  pdg, statusCode);
453 
454  prod_vtx->add_particle_out(aParticle);
455 }
456 
457 
460  IPartPropSvc* partPropSvc = 0;
461  StatusCode PartPropStatus = Gaudi::svcLocator()->service("PartPropSvc", partPropSvc);
462  if (!PartPropStatus.isSuccess() || 0 == partPropSvc) throw GaudiException("PartPropSvc error", "I_ParticleDecayer", StatusCode::FAILURE);
463  m_particleTable = partPropSvc->PDT();
464 
465  const HepPDT::ParticleData* particle = m_particleTable->particle(HepPDT::ParticleID(std::abs(pid)));
466  return particle->mass().value();
467 }
468 
469 
471 StatusCode ParticleDecayer::DFTwoBodyDecay( CLHEP::HepRandomEngine* engine, HepMC::GenParticlePtr genpart, int Polarization ) {
472 
473 
474  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- allow the two-body decay of the dark photon...");
475 
476  //create heplorentzvector from genpart's fourMomentum, as it is more useful
477  CLHEP::HepLorentzVector boostDF( genpart->momentum().px(), genpart->momentum().py(), genpart->momentum().pz(), genpart->momentum().e() );
478 
479  //Given branching fractions, pick decay mode
480  int ModeOfDecay;
481  double unif = rnd_DoubleRange(engine, 0.,1.);
482  if (unif<=m_BRElectron) {
483  ModeOfDecay = 11;
484  } else if (unif<=(m_BRElectron+m_BRMuon) && unif>m_BRElectron) {
485  ModeOfDecay = 13;
486  } else {
487  ModeOfDecay = 211;
488  }
489  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- decayMode = " << ModeOfDecay);
490 
491  //Now that we have a decay mode. get the associated particle mass
492  double decayPartMass = getParticleMass(ModeOfDecay);
493 
494  //Choose how to decay
495  //angular distribution handling, see pag.6 of http://arxiv.org/pdf/hep-ph/0605296v2.pdf
496  int type = 0; //isotropic by default
497  if(Polarization==0) {
498  type = 0; //isotropic
499  } else if(Polarization==-1 && (ModeOfDecay==11 || ModeOfDecay==13)) {
500  type = 2; //transverse polarization of the dark photon + fermions
501  } else if(Polarization==1 && (ModeOfDecay==11 || ModeOfDecay==13)) {
502  type = 3; //longitudinal polarization of the dark photon + fermions
503  } else if(Polarization==-1 && ModeOfDecay==211) {
504  type = 3; //transverse polarization of the dark photon + scalars
505  } else if(Polarization==1 && ModeOfDecay==211) {
506  type = 1; //longitudinal polarization of the dark photon + scalars
507  } else {
508  ATH_MSG_FATAL("ParticleDecayer::fillEvt: -- wrong polarization value... please check!");
509  return StatusCode::FAILURE;
510  }
511 
512  //Now we are ready to decay the dark photon
513  std::vector<CLHEP::HepLorentzVector> daughterLVs;
514  CHECK( getDecayProducts( engine, boostDF, decayPartMass, daughterLVs, type) );
515 
516  //Add the daughters to the pool file
517  ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- Add the daughters to the pool file");
518  auto end_vtx = genpart->end_vertex();
519  auto v0=daughterLVs.at(0).vect();
520  addParticle(end_vtx, ModeOfDecay, HepMC::FourVector(v0.x(),v0.y(),v0.z(),0.0), 1);
521  auto v1=daughterLVs.at(1).vect();
522  addParticle(end_vtx, -ModeOfDecay, HepMC::FourVector(v1.x(),v1.y(),v1.z(),0.0), 1);
523 
524  return StatusCode::SUCCESS;
525 }
526 
527 
528 StatusCode ParticleDecayer::getDecayProducts( CLHEP::HepRandomEngine* engine, CLHEP::HepLorentzVector parentLV,
529  double decayPartMass,
530  std::vector<CLHEP::HepLorentzVector>& daughterLVs,
531  int decayType)
532 {
533  double parentMass = parentLV.m();
534  CLHEP::Hep3Vector boostVec = parentLV.boostVector();
535 
536  if( decayPartMass > parentMass/2.)
537  {
538  ATH_MSG_FATAL("Decay particle has more than half the mass of parent.");
539  return StatusCode::FAILURE;
540  }
541  //Get the angles in the rest frame
542  double phi_rf = rnd_DoubleRange(engine, -M_PI, M_PI);
543  double ct_rf = cosgen(engine, decayType);
544  double theta_rf = std::acos(ct_rf);
545 
546  //construct p1 particle momentum in rest-frame (_rf)
547  double p1_rf = std::sqrt(parentMass*parentMass/4. - decayPartMass*decayPartMass);
548  double px_rf = p1_rf*std::cos(phi_rf)*std::sin(theta_rf);
549  double py_rf = p1_rf*std::sin(phi_rf)*std::sin(theta_rf);
550  double pz_rf = p1_rf*ct_rf;
551  CLHEP::HepLorentzVector hlv1( px_rf, py_rf, pz_rf, parentMass/2.);
552  CLHEP::HepLorentzVector hlv2( -px_rf, -py_rf, -pz_rf, parentMass/2.);
553 
554  //Transform from the rotated frame to the (x,y,z) frame.
555  hlv1.rotateUz((parentLV.vect()).unit());
556  hlv2.rotateUz((parentLV.vect()).unit());
557 
558  //Now boost back to the lab-frame
559  hlv1.boost(boostVec);
560  hlv2.boost(boostVec);
561 
562  daughterLVs.push_back(hlv1);
563  daughterLVs.push_back(hlv2);
564 
565  return StatusCode::SUCCESS;
566 }
HepMC::GenVertexPtr
HepMC::GenVertex * GenVertexPtr
Definition: GenVertex.h:59
ParticleDecayer::m_particlePDGID
int m_particlePDGID
Definition: ParticleDecayer.h:54
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
ParticleDecayer::m_particlePolarization
int m_particlePolarization
Definition: ParticleDecayer.h:56
beamspotman.r
def r
Definition: beamspotman.py:676
ParticleDecayer::DFTwoBodyDecay
StatusCode DFTwoBodyDecay(CLHEP::HepRandomEngine *engine, HepMC::GenParticlePtr, int)
Definition: ParticleDecayer.cxx:471
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
ParticleDecayer::m_particleTable
HepPDT::ParticleDataTable * m_particleTable
Definition: ParticleDecayer.h:77
test_pyathena.px
px
Definition: test_pyathena.py:18
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:64
ParticleDecayer::ParticleDecayer
ParticleDecayer(const std::string &name, ISvcLocator *pSvcLocator)
Definition: ParticleDecayer.cxx:223
ParticleDecayer::m_truthParticleContainerName
std::string m_truthParticleContainerName
Definition: ParticleDecayer.h:40
AthCommonDataStore< AthCommonMsg< Algorithm > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
ParticleDecayer::getDecayProducts
StatusCode getDecayProducts(CLHEP::HepRandomEngine *engine, CLHEP::HepLorentzVector, double, std::vector< CLHEP::HepLorentzVector > &, int decayType=0)
Definition: ParticleDecayer.cxx:528
theta
Scalar theta() const
theta method
Definition: AmgMatrixBasePlugin.h:71
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
ParticleDecayer::m_doUniformDecay
bool m_doUniformDecay
Definition: ParticleDecayer.h:67
HepMC::GenParticlePtr
GenParticle * GenParticlePtr
Definition: GenParticle.h:37
ParticleDecayer::m_LJType
int m_LJType
Definition: ParticleDecayer.h:42
M_PI
#define M_PI
Definition: ActiveFraction.h:11
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
dumpTruth.statusCode
statusCode
Definition: dumpTruth.py:89
ParticleDecayer::addParticle
void addParticle(HepMC::GenVertexPtr, int pdg, HepMC::FourVector, int statusCode)
Definition: ParticleDecayer.cxx:440
x
#define x
ParticleDecayer::m_expDecayDoTruncateLongDecays
bool m_expDecayDoTruncateLongDecays
Definition: ParticleDecayer.h:71
ParticleDecayer::m_oppositePolarization
bool m_oppositePolarization
Definition: ParticleDecayer.h:58
GenModule::getRandomEngine
CLHEP::HepRandomEngine * getRandomEngine(const std::string &streamName, const EventContext &ctx) const
Definition: GenModule.cxx:34
dqt_zlumi_pandas.mass
mass
Definition: dqt_zlumi_pandas.py:170
ParticleDecayer::m_BRElectron
double m_BRElectron
Definition: ParticleDecayer.h:61
ParticleDecayer::m_BRPion
double m_BRPion
Definition: ParticleDecayer.h:65
ParticleDecayer::m_thetaEndCapBarrel
double m_thetaEndCapBarrel
Definition: ParticleDecayer.h:75
GenModule
Base class for common behaviour of generator interfaces.
Definition: GenModule.h:39
ParticleDecayer::setDecayPosition
StatusCode setDecayPosition(CLHEP::HepRandomEngine *engine, HepMC::GenParticlePtr, HepMC::GenEvent *, bool doScalarDecay=false)
Definition: ParticleDecayer.cxx:118
ParticleDecayer::m_expDecayDoVariableLifetime
bool m_expDecayDoVariableLifetime
Definition: ParticleDecayer.h:69
ParticleDecayer::m_particleLifeTime
double m_particleLifeTime
Definition: ParticleDecayer.h:52
AthCommonDataStore< AthCommonMsg< Algorithm > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
CheckAppliedSFs.e3
e3
Definition: CheckAppliedSFs.py:264
ParticleGun_FastCalo_ChargeFlip_Config.energy
energy
Definition: ParticleGun_FastCalo_ChargeFlip_Config.py:78
ParticleGun_EoverP_Config.momentum
momentum
Definition: ParticleGun_EoverP_Config.py:63
event
POOL::TEvent event(POOL::TEvent::kClassAccess)
TrigVtx::gamma
@ gamma
Definition: TrigParticleTable.h:26
McEventCollection.h
HepMC::newGenVertexPtr
GenVertexPtr newGenVertexPtr(const HepMC::FourVector &pos=HepMC::FourVector(0.0, 0.0, 0.0, 0.0), const int i=0)
Definition: GenVertex.h:64
parseMapping.v0
def v0
Definition: parseMapping.py:149
ParticleDecayer::m_scalarMass
double m_scalarMass
Definition: ParticleDecayer.h:46
ParticleDecayer::rnd_ExpLifetime
double rnd_ExpLifetime(CLHEP::HepRandomEngine *engine, double ct)
Definition: ParticleDecayer.cxx:32
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
ParticleDecayer::m_particleMass
double m_particleMass
Definition: ParticleDecayer.h:48
ParticleDecayer::m_BRMuon
double m_BRMuon
Definition: ParticleDecayer.h:63
ParticleGun_EoverP_Config.pid
pid
Definition: ParticleGun_EoverP_Config.py:62
Amg::pz
@ pz
Definition: GeoPrimitives.h:40
ParticleDecayer::m_particleID
int m_particleID
Definition: ParticleDecayer.h:50
jobOptions.ParticleID
ParticleID
Definition: jobOptions.decayer.py:85
ParticleDecayer::m_expDecayFractionToKeep
double m_expDecayFractionToKeep
Definition: ParticleDecayer.h:70
CHECK
#define CHECK(...)
Evaluate an expression and check for errors.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:422
PowhegPythia8EvtGen_H2a4X_ctauY.ctau
int ctau
Definition: PowhegPythia8EvtGen_H2a4X_ctauY.py:28
McEventCollection
This defines the McEventCollection, which is really just an ObjectVector of McEvent objects.
Definition: McEventCollection.h:33
ParticleDecayer::m_endCapDistance
double m_endCapDistance
Definition: ParticleDecayer.h:74
DataVector::back
const T * back() const
Access the last element in the collection as an rvalue.
calibdata.ct
ct
Definition: calibdata.py:418
ParticleDecayer::m_barrelRadius
double m_barrelRadius
Definition: ParticleDecayer.h:73
min
#define min(a, b)
Definition: cfImp.cxx:40
ParticleDecayer::cosgen
double cosgen(CLHEP::HepRandomEngine *engine, int itype)
Definition: ParticleDecayer.cxx:47
Amg::py
@ py
Definition: GeoPrimitives.h:39
ParticleDecayer::m_eventCounter
int m_eventCounter
Definition: ParticleDecayer.h:100
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
GenBase::partPropSvc
const ServiceHandle< IPartPropSvc > partPropSvc() const
Access the particle property service.
Definition: GenBase.h:113
ParticleDecayer::m_doExponentialDecay
bool m_doExponentialDecay
Definition: ParticleDecayer.h:68
ParticleDecayer::m_scalarPDGID
int m_scalarPDGID
Definition: ParticleDecayer.h:44
ParticleDecayer.h
skel.genpart
tuple genpart
Check that the actual generators, tune, and main PDF are consistent with the JO name.
Definition: skel.ABtoEVGEN.py:262
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
a
TList * a
Definition: liststreamerinfos.cxx:10
HepMC::newGenParticlePtr
GenParticlePtr newGenParticlePtr(const HepMC::FourVector &mom=HepMC::FourVector(0.0, 0.0, 0.0, 0.0), int pid=0, int status=0)
Definition: GenParticle.h:39
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
merge.status
status
Definition: merge.py:17
ParticleDecayer::getParticleMass
double getParticleMass(int pdgID)
Definition: ParticleDecayer.cxx:459
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
ParticleDecayer::genInitialize
StatusCode genInitialize()
For initializing the generator, if required.
Definition: ParticleDecayer.cxx:257
ParticleDecayer::changeMass
StatusCode changeMass(HepMC::GenParticlePtr, double)
Definition: ParticleDecayer.cxx:94
PixelByteStreamErrors::Limit
@ Limit
Definition: PixelByteStreamErrors.h:14
ParticleDecayer::rnd_DoubleRange
double rnd_DoubleRange(CLHEP::HepRandomEngine *engine, double a, double b)
Definition: ParticleDecayer.cxx:39
ParticleDecayer::fillEvt
StatusCode fillEvt(HepMC::GenEvent *)
For filling the HepMC event object.
Definition: ParticleDecayer.cxx:290