ATLAS Offline Software
Loading...
Searching...
No Matches
ParticleDecayer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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
32double 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)
39double 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
47double 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
94StatusCode ParticleDecayer::changeMass( HepMC::GenParticlePtr genpart, double newMass )
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
118StatusCode 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(std::move(genpart));
130 event->add_vertex(std::move(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);
181 ctau = rnd_ExpLifetime(engine,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(std::move(genpart));
218 event->add_vertex(std::move(end_vtx));
219 return StatusCode::SUCCESS;
220}
221
223ParticleDecayer::ParticleDecayer(const std::string& name, ISvcLocator* pSvcLocator) :
224 GenModule(name, pSvcLocator),
225 m_truthParticleContainerName("GEN_EVENT"),
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
290StatusCode ParticleDecayer::fillEvt(HepMC::GenEvent* event) {
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;
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
330 CHECK( changeMass( genpart, m_particleMass ) );
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
347 CHECK( DFTwoBodyDecay( engine, std::move(genpart), m_particlePolarization ) );
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
363 CHECK( changeMass( genpart, m_scalarMass ) );
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
434
435 return status;
436}
437
438
440void ParticleDecayer::addParticle(HepMC::GenVertexPtr prod_vtx, int pdg, HepMC::FourVector momentum, int statusCode) {
441
442 double mass = 0.;
443 if( pdg == m_particlePDGID)
444 {
445 mass = m_particleMass;
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);
451HepMC::GenParticlePtr aParticle = HepMC::newGenParticlePtr (HepMC::FourVector(momentum.x(), momentum.y(), momentum.z(), energy),
452 pdg, statusCode);
453
454 prod_vtx->add_particle_out(std::move(aParticle));
455}
456
457
460 SmartIF<IPartPropSvc> partPropSvc(Gaudi::svcLocator()->service("PartPropSvc"));
461 if (!partPropSvc) throw GaudiException("PartPropSvc error", "I_ParticleDecayer", StatusCode::FAILURE);
463
464 const HepPDT::ParticleData* particle = m_particleTable->particle(HepPDT::ParticleID(std::abs(pid)));
465 return particle->mass().value();
466}
467
468
470StatusCode ParticleDecayer::DFTwoBodyDecay( CLHEP::HepRandomEngine* engine, HepMC::GenParticlePtr genpart, int Polarization ) {
471
472
473 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- allow the two-body decay of the dark photon...");
474
475 //create heplorentzvector from genpart's fourMomentum, as it is more useful
476 CLHEP::HepLorentzVector boostDF( genpart->momentum().px(), genpart->momentum().py(), genpart->momentum().pz(), genpart->momentum().e() );
477
478 //Given branching fractions, pick decay mode
479 int ModeOfDecay;
480 double unif = rnd_DoubleRange(engine, 0.,1.);
481 if (unif<=m_BRElectron) {
482 ModeOfDecay = 11;
483 } else if (unif<=(m_BRElectron+m_BRMuon) && unif>m_BRElectron) {
484 ModeOfDecay = 13;
485 } else {
486 ModeOfDecay = 211;
487 }
488 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- decayMode = " << ModeOfDecay);
489
490 //Now that we have a decay mode. get the associated particle mass
491 double decayPartMass = getParticleMass(ModeOfDecay);
492
493 //Choose how to decay
494 //angular distribution handling, see pag.6 of http://arxiv.org/pdf/hep-ph/0605296v2.pdf
495 int type = 0; //isotropic by default
496 if(Polarization==0) {
497 type = 0; //isotropic
498 } else if(Polarization==-1 && (ModeOfDecay==11 || ModeOfDecay==13)) {
499 type = 2; //transverse polarization of the dark photon + fermions
500 } else if(Polarization==1 && (ModeOfDecay==11 || ModeOfDecay==13)) {
501 type = 3; //longitudinal polarization of the dark photon + fermions
502 } else if(Polarization==-1 && ModeOfDecay==211) {
503 type = 3; //transverse polarization of the dark photon + scalars
504 } else if(Polarization==1 && ModeOfDecay==211) {
505 type = 1; //longitudinal polarization of the dark photon + scalars
506 } else {
507 ATH_MSG_FATAL("ParticleDecayer::fillEvt: -- wrong polarization value... please check!");
508 return StatusCode::FAILURE;
509 }
510
511 //Now we are ready to decay the dark photon
512 std::vector<CLHEP::HepLorentzVector> daughterLVs;
513 CHECK( getDecayProducts( engine, boostDF, decayPartMass, daughterLVs, type) );
514
515 //Add the daughters to the pool file
516 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- Add the daughters to the pool file");
517 auto end_vtx = genpart->end_vertex();
518 auto v0=daughterLVs.at(0).vect();
519 addParticle(end_vtx, ModeOfDecay, HepMC::FourVector(v0.x(),v0.y(),v0.z(),0.0), 1);
520 auto v1=daughterLVs.at(1).vect();
521 addParticle(std::move(end_vtx), -ModeOfDecay, HepMC::FourVector(v1.x(),v1.y(),v1.z(),0.0), 1);
522
523 return StatusCode::SUCCESS;
524}
525
526
527StatusCode ParticleDecayer::getDecayProducts( CLHEP::HepRandomEngine* engine, CLHEP::HepLorentzVector parentLV,
528 double decayPartMass,
529 std::vector<CLHEP::HepLorentzVector>& daughterLVs,
530 int decayType)
531{
532 double parentMass = parentLV.m();
533 CLHEP::Hep3Vector boostVec = parentLV.boostVector();
534
535 if( decayPartMass > parentMass/2.)
536 {
537 ATH_MSG_FATAL("Decay particle has more than half the mass of parent.");
538 return StatusCode::FAILURE;
539 }
540 //Get the angles in the rest frame
541 double phi_rf = rnd_DoubleRange(engine, -M_PI, M_PI);
542 double ct_rf = cosgen(engine, decayType);
543 double theta_rf = std::acos(ct_rf);
544
545 //construct p1 particle momentum in rest-frame (_rf)
546 double p1_rf = std::sqrt(parentMass*parentMass/4. - decayPartMass*decayPartMass);
547 double px_rf = p1_rf*std::cos(phi_rf)*std::sin(theta_rf);
548 double py_rf = p1_rf*std::sin(phi_rf)*std::sin(theta_rf);
549 double pz_rf = p1_rf*ct_rf;
550 CLHEP::HepLorentzVector hlv1( px_rf, py_rf, pz_rf, parentMass/2.);
551 CLHEP::HepLorentzVector hlv2( -px_rf, -py_rf, -pz_rf, parentMass/2.);
552
553 //Transform from the rotated frame to the (x,y,z) frame.
554 hlv1.rotateUz((parentLV.vect()).unit());
555 hlv2.rotateUz((parentLV.vect()).unit());
556
557 //Now boost back to the lab-frame
558 hlv1.boost(boostVec);
559 hlv2.boost(boostVec);
560
561 daughterLVs.push_back(hlv1);
562 daughterLVs.push_back(hlv2);
563
564 return StatusCode::SUCCESS;
565}
#define M_PI
Scalar phi() const
phi method
Scalar theta() const
theta method
#define ATH_MSG_FATAL(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
static Double_t a
#define x
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
const T * back() const
Access the last element in the collection as an rvalue.
const ServiceHandle< IPartPropSvc > partPropSvc() const
Access the particle property service.
Definition GenBase.h:113
GenModule(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition GenModule.cxx:14
CLHEP::HepRandomEngine * getRandomEngine(const std::string &streamName, const EventContext &ctx) const
Definition GenModule.cxx:34
This defines the McEventCollection, which is really just an ObjectVector of McEvent objectsFile: Gene...
double getParticleMass(int pdgID)
StatusCode changeMass(HepMC::GenParticlePtr, double)
bool m_expDecayDoVariableLifetime
HepPDT::ParticleDataTable * m_particleTable
StatusCode DFTwoBodyDecay(CLHEP::HepRandomEngine *engine, HepMC::GenParticlePtr, int)
StatusCode getDecayProducts(CLHEP::HepRandomEngine *engine, CLHEP::HepLorentzVector, double, std::vector< CLHEP::HepLorentzVector > &, int decayType=0)
StatusCode setDecayPosition(CLHEP::HepRandomEngine *engine, HepMC::GenParticlePtr, HepMC::GenEvent *, bool doScalarDecay=false)
double rnd_DoubleRange(CLHEP::HepRandomEngine *engine, double a, double b)
std::string m_truthParticleContainerName
void addParticle(HepMC::GenVertexPtr, int pdg, HepMC::FourVector, int statusCode)
ParticleDecayer(const std::string &name, ISvcLocator *pSvcLocator)
double cosgen(CLHEP::HepRandomEngine *engine, int itype)
double m_expDecayFractionToKeep
StatusCode fillEvt(HepMC::GenEvent *)
For filling the HepMC event object.
bool m_expDecayDoTruncateLongDecays
StatusCode genInitialize()
For initializing the generator, if required.
double rnd_ExpLifetime(CLHEP::HepRandomEngine *engine, double ct)
int r
Definition globals.cxx:22
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
HepMC::GenVertex * GenVertexPtr
Definition GenVertex.h:59
GenVertexPtr newGenVertexPtr(const HepMC::FourVector &pos=HepMC::FourVector(0.0, 0.0, 0.0, 0.0), const int i=0)
Definition GenVertex.h:64
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
GenParticle * GenParticlePtr
Definition GenParticle.h:37