ATLAS Offline Software
Loading...
Searching...
No Matches
ParticleDecayer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 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
26#include "CLHEP/Random/RandomEngine.h"
27#include <cmath> //M_PI
28
30//function to generate a lifetime (actually decay-length) according to the proper lifetime of the particle particle
31double ParticleDecayer::rnd_ExpLifetime(CLHEP::HepRandomEngine* engine, double ct) {
32 double r = engine->flat(); //< Return random num in [0,1]
33 return ((-ct)*std::log(1.-r));
34}
35
37//function to generate a uniform distribution in (a,b)
38double ParticleDecayer::rnd_DoubleRange(CLHEP::HepRandomEngine* engine, double a, double b) {
39 double r = engine->flat(); //< Return random num in [0,1]
40 return a + r*(b-a);
41}
42
43
45//function to generate a cos theta valua according to angular distribution
46double ParticleDecayer::cosgen(CLHEP::HepRandomEngine* engine, int itype){
47 double x,fx,hit;
48 x=0;
49
50 if(itype==0){ // flat
51 x=rnd_DoubleRange(engine,-1.,1.);
52 return x;
53 }
54
55 if(itype==1){ // f(cost)=1.5*cost^2
56 hit=1.5;
57 fx=0;
58 while(hit>fx){
59 x=rnd_DoubleRange(engine,-1.,1.);
60 hit=rnd_DoubleRange(engine,0.,1.5);
61 fx=1.5*x*x;
62 }
63 return x;
64 }
65
66 if(itype==2){ // f(cost)=0.375(1+cost^2)
67 hit=0.75;
68 fx=0;
69 while(hit>fx){
70 x=rnd_DoubleRange(engine,-1.,1.);
71 hit=rnd_DoubleRange(engine,0.,0.75);
72 fx=0.375*(1+x*x);
73 }
74 return x;
75 }
76
77 if(itype==3){ // f(cost)=0.75(1-cost^2)
78 hit=1.5;
79 fx=0;
80 while(hit>fx){
81 x=rnd_DoubleRange(engine,-1.,1.);
82 hit=rnd_DoubleRange(engine,0.,1.5);
83 fx=0.75*(1-x*x);
84 }
85 return x;
86 }
87
88 return x;
89
90}
91
93StatusCode ParticleDecayer::changeMass( HepMC::GenParticlePtr genpart, double newMass )
94{
95 double e = genpart->momentum().e();
96 double theta = genpart->momentum().theta();
97 double phi = genpart->momentum().phi();
98 //Sanity check
99 double p2 = e*e - newMass*newMass;
100 if ( p2 < 0 ) {
101 ATH_MSG_FATAL("ParticleDecayer::fillEvt: -- you have generated a tachyon!");
102 return StatusCode::FAILURE;
103 }
104 //At this point, we have e, theta, and phi. Put them together to get the four-momentum.
105 double p = std::sqrt(p2);
106 double px = p*std::sin(theta)*std::cos(phi);
107 double py = p*std::sin(theta)*std::sin(phi);
108 double pz = p*std::cos(theta);
109 //Fill the four-momentum
110 const CLHEP::HepLorentzVector updatedLV(px,py,pz,e);
111 genpart->set_momentum(HepMC::FourVector(updatedLV.x(),updatedLV.y(),updatedLV.z(),updatedLV.e()));
112 genpart->set_generated_mass(newMass);
113 return StatusCode::SUCCESS;
114}
115
117StatusCode ParticleDecayer::setDecayPosition( CLHEP::HepRandomEngine* engine, HepMC::GenParticlePtr genpart, HepMC::GenEvent* event, bool doScalarDecay )
118{
119 HepMC::GenVertexPtr vtxp = genpart->production_vertex();
120 if(!vtxp) {
121 ATH_MSG_FATAL("ParticleDecayer::fillEvt: -- no production vertex position found!");
122 return StatusCode::FAILURE;
123 }
124 if ( doScalarDecay ) // scalar decay is prompt. decay vtx == scalar production vertex
125 {
127 end_vtx->set_position(vtxp->position());
128 end_vtx->add_particle_in(std::move(genpart));
129 event->add_vertex(std::move(end_vtx));
130 return StatusCode::SUCCESS;
131 }
132
133 //lifetime handling
134 double gamma = genpart->momentum().e()/genpart->momentum().m();
135 double ctau = 0.;
136 double theta = genpart->momentum().theta();
137
138 // Make sure theta is between 0 and pi
139 while( theta > M_PI )
140 {
141 theta -= M_PI;
142 }
143 while( theta < 0 )
144 {
145 theta += M_PI;
146 }
147
149 {
150 if(m_expDecayDoVariableLifetime) // Variable proper lifetime distribution, such that fixed fraction of events decays within detector, independent of boost
151 {
152 double distanceToEdge = -999.;
153 if ( theta < m_thetaEndCapBarrel || theta > ( M_PI - m_thetaEndCapBarrel) ) // Particle escapes through endcap
154 {
155 distanceToEdge = std::abs(m_endCapDistance/std::cos(theta));
156 }
157 else // Particle escapes through barrel
158 {
159 distanceToEdge = m_barrelRadius/std::sin(theta);
160 }
161 if ( gamma < 1. )
162 {
163 ATH_MSG_FATAL("Gamma factor cannot be smaller than 1" );
164 return StatusCode::FAILURE;
165 }
166 double Limit = distanceToEdge / gamma; // ctau is enhanced by factor gamma in lab frame
167 double lambda = -1.*Limit/std::log(1. - m_expDecayFractionToKeep);
168 ctau = rnd_ExpLifetime(engine,lambda);
170 {
171 while ( ctau > Limit ) // If decay is outside detector, let's sample again (Produces a truncated exponential)
172 {
173 ctau = rnd_ExpLifetime(engine, lambda);
174 }
175 }
176 }
177 else if( m_particleLifeTime > 0 ) // Fixed proper lifetime distribution. Note that if m_particleLifeTime <= 0. ctau remains 0
178 {
179 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set lifetime of the dark photon according to ctau = " << m_particleLifeTime);
180 ctau = rnd_ExpLifetime(engine,m_particleLifeTime);
181 }
182 }else if (m_doUniformDecay)
183 {
184 double decayRadius = -999.;
185 if ( theta < m_thetaEndCapBarrel || theta > ( M_PI - m_thetaEndCapBarrel) ) // Particle escapes through endcap
186 {
187 double outerLength = std::abs(m_endCapDistance/std::cos(theta));
188 double outerRadius = outerLength*std::sin(theta);
189 decayRadius = rnd_DoubleRange(engine,0., std::min(outerRadius, std::abs(m_barrelRadius)) );
190 }else // Particle escapes through barrel
191 {
192 decayRadius = rnd_DoubleRange(engine,0., std::abs(m_barrelRadius));
193 }
194
195 double decayLength = decayRadius/std::sin(theta);
196 ctau = decayLength/gamma;
197 }else
198 {
199 ATH_MSG_FATAL("have to pick uniform or exponential decay distance");
200 return StatusCode::FAILURE;
201 }
202
203 double ctg = gamma * ctau;
204 double px = genpart->momentum().px();
205 double py = genpart->momentum().py();
206 double pz = genpart->momentum().pz();
207 double p = std::sqrt(px*px + py*py + pz*pz);
208
209 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())));
210
211 //set the decay vertex position of the particle
212 //Create a HepMC vertex at the decay position of the particle
213 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the decay vertex");
215 end_vtx->set_position(HepMC::FourVector(posLV.x(),posLV.y(),posLV.z(),posLV.t()));
216 end_vtx->add_particle_in(std::move(genpart));
217 event->add_vertex(std::move(end_vtx));
218 return StatusCode::SUCCESS;
219}
220
222ParticleDecayer::ParticleDecayer(const std::string& name, ISvcLocator* pSvcLocator) :
223 GenModule(name, pSvcLocator),
224 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("DecayOnlyStable", m_decayOnlyStable = false);
239 declareProperty("DecayBRElectrons", m_BRElectron = 1.); //BR of dark photon decay to electrons
240 declareProperty("DecayBRMuons", m_BRMuon = 0.); //BR of dark photon decay to muons
241 declareProperty("DecayBRPions", m_BRPion = 0.); //BR of dark photon decay to pions
242
243 //Choose between the different types of displaced decays
244 declareProperty("DoUniformDecay", m_doUniformDecay = false);
245 declareProperty("DoExponentialDecay", m_doExponentialDecay = true );
246 declareProperty("ExpDecayDoVariableLifetime", m_expDecayDoVariableLifetime = false );
247 declareProperty("ExpDecayPercentageToKeep", m_expDecayFractionToKeep = 0.8 );
248 declareProperty("ExpDecayDoTruncateLongDecays", m_expDecayDoTruncateLongDecays = false );
249
250 //Dimensions within which to decay in case of non-prompt events
251 declareProperty("BarrelRadius", m_barrelRadius = 10.e3 ); // outer limit for decay radius
252 declareProperty("EndCapDistance", m_endCapDistance = 15.e3 ); // outer limit along z for decays in endcap
253 declareProperty("ThetaEndCapBarrel", m_thetaEndCapBarrel = 0.439067982); // theta if where to switch between barrel and endcap (default: eta = 1.5)
254}
255
257
259{
260 // Check here if the tool has been configured correctly
262 {
263 ATH_MSG_FATAL("Cannot configure exponential and uniform decay at the same time.");
264 return StatusCode::FAILURE;
265 }
266
267 double TOTBR = m_BRElectron + m_BRMuon + m_BRPion;
268 if (TOTBR>1.0000001) {
269 ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Branching Ratio sum is larger than 1!! Please check the values in your jobOption.");
270 ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Branching Ratio Electrons " << m_BRElectron);
271 ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Branching Ratio Muons " << m_BRMuon);
272 ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Branching Ratio Pions " << m_BRPion);
273 ATH_MSG_FATAL("ParticleDecayer::genInitialize: -- Total Branching Ratio " << TOTBR);
274 return StatusCode::FAILURE;
275 }
276
277 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- daughters randomly produced: " << m_BRElectron << "% e, " << m_BRMuon << "% mu, " << m_BRPion << "% pi");
278
279 if( m_LJType != 1 && m_LJType != 2 )
280 {
281 ATH_MSG_FATAL("LJType is set to " << m_LJType);
282 ATH_MSG_FATAL("LJType has to be set to either 1 or 2");
283 return StatusCode::FAILURE;
284 }
285
286
287 return StatusCode::SUCCESS;
288}
289
292
293 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- EventCounter: " << m_eventCounter);
294
295 const EventContext& ctx = Gaudi::Hive::currentContext();
296 CLHEP::HepRandomEngine* engine = this->getRandomEngine("ParticleDecayer", ctx);
297
298 StatusCode status = StatusCode::SUCCESS;
299
300 // Extract the event from the TES
301 McEventCollection* mcEvtColl = nullptr;
303 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- Found an McEventCollection for ParticleDecayer");
304 } else {
305 ATH_MSG_FATAL("TES is empty!!!!");
306 status = StatusCode::FAILURE;
307 return status;
308 }
309
310 event = mcEvtColl->back();
311
312 if (event == NULL) {
313 ATH_MSG_FATAL("ParticleDecayer::fillEvt: -- McEvent was not successfully created");
314 status = StatusCode::FAILURE;
315 return status;
316 }
317
318 for ( auto genpart : *event) {
319
320 const bool hasRightPDG = (genpart->pdg_id() == m_particleID);
321 const bool isStable = (genpart->status() == 1);
322 const bool hasEndVtx = (genpart->end_vertex() != nullptr);
323
324 if (!hasRightPDG) {
325 continue;
326 }
327
328 if (m_decayOnlyStable) {
329 if (!isStable || hasEndVtx) {
330 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- skip particle with PDG ID = "
331 << genpart->pdg_id()
332 << " status = " << genpart->status()
333 << " end_vertex = " << (hasEndVtx ? "yes" : "no"));
334 continue;
335 }
336 }
337
339 // only one dark photon per LeptonJet //
341 if (m_LJType == 1) {
342 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- only one dark photon per LeptonJet");
343 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- found MC particle with PDG ID = " << genpart->pdg_id());
344 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- assign the new mass of the dark photon, m = " << m_particleMass);
345
346 //Change the mass of the parent particle ( set by user input + command )
347 //Changes the magnitude of the spatial part of the 4-momentum such that the new 4-momentum has the desired inv mass
348 CHECK( changeMass( genpart, m_particleMass ) );
349
350 //Add decay position to the event
351 CHECK( setDecayPosition( engine, genpart, event ) );
352
353 //assign the new PDG_ID of the particle
354 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new PDG ID = " << m_particlePDGID);
355 genpart->set_pdg_id(m_particlePDGID);
356
357 //set the new status (decayed) of the particle
358 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new status = 2");
359 genpart->set_status(2);
360
361 //set the new momentum of the particle
362 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new momentum");
363
365 CHECK( DFTwoBodyDecay( engine, std::move(genpart), m_particlePolarization ) );
366
367 }else if (m_LJType == 2) {
369 // two dark photons per LeptonJet //
371
372 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- two dark photons per LeptonJet");
373 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- found MC particle with PDG ID = " << genpart->pdg_id());
374 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- assign the new mass of the dark scalar, m = " << m_scalarMass);
375
376 //Get the mass of the parent particle ( set by user input + command )
377 //Change the mass of the parent particle ( set by user input + command )
378 //Changes the magnitude of the spatial part of the 4-momentum such that the new 4-momentum has the desired inv mass
379 CHECK( changeMass( genpart, m_scalarMass ) );
380
381 //set the new PDG_ID of the scalar
382 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new PDG ID = " << m_scalarPDGID);
383 genpart->set_pdg_id(m_scalarPDGID);
384
385 //set the new status (decayed) of the scalar
386 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- set the new status = 2");
387 genpart->set_status(2);
388
389 //set the decay vertex position of the scalar
390 //Create a HepMC vertex at the decay position of the scalar
391 CHECK( setDecayPosition( engine, genpart, event, true ) );
392
394 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- allow the two-body decay of the dark scalar to dark photons...");
395 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- dark photon has PDG ID = " << m_particlePDGID);
396
397 std::vector<CLHEP::HepLorentzVector> darkPhotonLVs;
398 CHECK( getDecayProducts( engine, CLHEP::HepLorentzVector( genpart->momentum().px(), genpart->momentum().py(), genpart->momentum().pz(), genpart->momentum().e() ),
400 darkPhotonLVs) );
401
402 //add dark photon 1
403 auto v0=darkPhotonLVs.at(0).vect();
404 addParticle( genpart->end_vertex(), m_particlePDGID, HepMC::FourVector(v0.x(),v0.y(),v0.z(),0.0) , 2);
405 //add dark photon 2
406 auto v1=darkPhotonLVs.at(1).vect();
407 addParticle( genpart->end_vertex(), m_particlePDGID, HepMC::FourVector(v1.x(),v1.y(),v1.z(),0.0), 2);
408
409 //lifetime handling of the dark photons
410 int polarizationSwitch = 1;
411 const std::vector<HepMC::GenParticlePtr>& particlesOut = genpart->end_vertex()->particles_out();
412 std::vector<HepMC::GenParticlePtr>::const_iterator pItBegin = particlesOut.begin();
413 std::vector<HepMC::GenParticlePtr>::const_iterator pItEnd = particlesOut.end();
414 for ( auto pIt=pItBegin ; pIt != pItEnd; ++pIt )
415 {
416
417 //Add decay position to the event
418 CHECK( setDecayPosition( engine, *pIt, event ) );
419 //And perform two-body decay
420 ATH_MSG_DEBUG("ParticleDecayer::fillEvt: -- Now allow the two-body decay of the dark photons");
421 CHECK( DFTwoBodyDecay( engine, *pIt, polarizationSwitch*m_particlePolarization ) );
423 {
424 polarizationSwitch = -polarizationSwitch;
425 }
426 }
427
428 }else
429 {
430 ATH_MSG_FATAL("LJType set to " << m_LJType );
431 ATH_MSG_FATAL("LJType must be 1 or 2" );
432 return StatusCode::FAILURE;
433 }
434 }
435
436 //set the event number
437 event->set_event_number(m_eventCounter);
438
439 //Add a unit entry to the event weight vector if it's currently empty
440 if (event->weights().empty()) {
441 event->weights().push_back(1.);
442 }
443
444 //increment the event counter
446
447 return status;
448}
449
450
452void ParticleDecayer::addParticle(HepMC::GenVertexPtr prod_vtx, int pdg, HepMC::FourVector momentum, int statusCode) {
453
454 double mass = 0.;
455 if( pdg == m_particlePDGID)
456 {
457 mass = m_particleMass;
458 }else
459 {
460 mass = m_gendata->particleMass(pdg).value();
461 }
462 double energy=std::sqrt(std::pow(momentum.x(),2)+std::pow(momentum.y(),2)+std::pow(momentum.z(),2)+mass*mass);
463HepMC::GenParticlePtr aParticle = HepMC::newGenParticlePtr (HepMC::FourVector(momentum.x(), momentum.y(), momentum.z(), energy),
464 pdg, statusCode);
465
466 prod_vtx->add_particle_out(std::move(aParticle));
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 = m_gendata->particleMass(ModeOfDecay).value();
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)
ServiceHandle< StoreGateSvc > & evtStore()
const T * back() const
Access the last element in the collection as an rvalue.
GenData is a class for particle data access.
Definition GenData.h:18
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...
std::unique_ptr< GenData > m_gendata
StatusCode changeMass(HepMC::GenParticlePtr, double)
bool m_expDecayDoVariableLifetime
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)
STL class.
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:116
HepMC3::FourVector FourVector
GenParticlePtr newGenParticlePtr(const HepMC3::FourVector &mom=HepMC3::FourVector::ZERO_VECTOR(), int pid=0, int status=0)
Definition GenParticle.h:21
HepMC3::GenParticlePtr GenParticlePtr
Definition GenParticle.h:19
GenVertexPtr newGenVertexPtr(const HepMC3::FourVector &pos=HepMC3::FourVector::ZERO_VECTOR(), const int i=0)
Definition GenVertex.h:25
HepMC3::GenVertexPtr GenVertexPtr
Definition GenVertex.h:23
HepMC3::GenEvent GenEvent
Definition GenEvent.h:39
STL namespace.