ATLAS Offline Software
Loading...
Searching...
No Matches
EvtInclusiveDecay.cxx
Go to the documentation of this file.
1//*****************************************************************************
2//
3// Generators/EvtGen_i/EvtInclusiveDecay.h
4//
5// EvtInclusiveDecay is a TopAlg that takes HepMC events from StoreGate and
6// generates particle decays using EvtGen. Depending on job options either all or
7// only a subset of the particles which have decays defined in the EvtGen
8// decay files will be handed to EvtGen. Both undecayed particles and particles
9// with an existing decay tree can be handled (in the latter case,
10// EvtInclusiveDecay will remove the existing decay tree).
11//
12// Written in February 2006 by Juerg Beringer, based in part on the existing
13// EvtDecay module.
14//
15//*****************************************************************************
16
18
19#include "EvtGenBase/EvtAbsRadCorr.hh"
20#include "EvtGenBase/EvtDecayBase.hh"
21#include "EvtGen_i/EvtGenExternal/EvtExternalGenList.hh"
22
23#include "EvtGenBase/EvtVector4R.hh"
24#include "EvtGenBase/EvtParticle.hh"
25#include "EvtGenBase/EvtParticleFactory.hh"
26#include "EvtGen/EvtGen.hh"
27#include "EvtGenBase/EvtRandomEngine.hh"
28#include "EvtGenBase/EvtDecayTable.hh"
29
31
32#include "AtlasHepMC/GenEvent.h"
37
38#include "GaudiKernel/MsgStream.h"
39#include "GaudiKernel/ISvcLocator.h"
40#include "GaudiKernel/DataSvc.h"
41#include "GaudiKernel/IPartPropSvc.h"
45#include "HepPID/ParticleName.hh"
46
48#include "CLHEP/Random/RandFlat.h"
49#include "CLHEP/Vector/LorentzVector.h"
51
52#include <stdlib.h>
53#include <sstream>
54#include <map>
55
56
57EvtInclusiveDecay::EvtInclusiveDecay(const std::string& name, ISvcLocator* pSvcLocator):
58 GenBase( name, pSvcLocator ),
60
61 // Basic EvtGen configuration: decay and particle definition files, random number stream
62 declareProperty("pdtFile", m_pdtFile = "inclusive.pdt");
63 declareProperty("decayFile", m_decayFile = "2014inclusive.dec");
64 declareProperty("userDecayFile", m_userDecayFile = "");
65 declareProperty("randomStreamName", m_randomStreamName = "EVTGEN");
66 declareProperty("inputKeyName", m_inputKeyName = "GEN_EVENT");
67 declareProperty("outputKeyName",m_outputKeyName = "GEN_EVENT_EVTGEN");
68 declareProperty("readExisting",m_readExisting=false);
69
70 // Selection of particles to be decayed
71 declareProperty("prohibitFinalStateDecay", m_prohibitFinalStateDecay=false);
72 declareProperty("prohibitReDecay", m_prohibitReDecay=false);
73 declareProperty("prohibitUnDecay", m_prohibitUnDecay=true);
74 declareProperty("prohibitRemoveSelfDecay", m_prohibitRemoveSelfDecay=false);
75 declareProperty("blackList",m_blackList);
76 declareProperty("allowAllKnownDecays", m_allowAllKnownDecays=true);
77 declareProperty("allowDefaultBDecays", m_allowDefaultBDecays=true);
78 declareProperty("whiteList",m_whiteList);
79
80 // Level of output
81 declareProperty("printHepMCBeforeEvtGen", m_printHepMCBeforeEvtGen=false);
82 declareProperty("printHepMCAfterEvtGen", m_printHepMCAfterEvtGen=false);
83 declareProperty("printHepMCHighlighted", m_printHepMCHighlighted=true);
84 declareProperty("printHepMCHighLightTopLevelDecays", m_printHepMCHighLightTopLevelDecays=true);
85
86 // Optional checks
87 declareProperty("checkDecayTree", m_checkDecayTree=false);
88 declareProperty("checkDecayChannels", m_checkDecayChannels=false);
89
90 // Repeated decays
91 declareProperty("maxNRepeatedDecays", m_maxNRepeatedDecays=1);
92
93 // User selection
94 declareProperty("applyUserSelection", m_applyUserSelection=false);
95 declareProperty("userSelRequireOppositeSignedMu", m_userSelRequireOppositeSignedMu=true);
96 declareProperty("userSelMu1MinPt", m_userSelMu1MinPt=0.);
97 declareProperty("userSelMu2MinPt", m_userSelMu2MinPt=0.);
98 declareProperty("userSelMu1MaxEta", m_userSelMu1MaxEta=102.5);
99 declareProperty("userSelMu2MaxEta", m_userSelMu2MaxEta=102.5);
100 declareProperty("userSelMinDimuMass", m_userSelMinDimuMass=0.);
101 declareProperty("userSelMaxDimuMass", m_userSelMaxDimuMass=-1.); // set to negative to not apply cut
102 declareProperty("isfHerwig", m_isfHerwig=false);
103 declareProperty("setVMtransversePol", m_setVMtransversePol=false);
104
105 // We have decided to blacklist Tau decays because we are not sure whether the polarization
106 // would be properly passed to EvtGen
107 m_blackList.push_back(15);
108}
109
110
111
116
117
118
120
122 // Get the random number service
123 CHECK(m_rndmSvc.retrieve());
124
125 msg(MSG::INFO) << "EvtInclusiveDecay initialize" << endmsg;
126 msg(MSG::INFO) << "Particle properties definition file = " << m_pdtFile << endmsg;
127 msg(MSG::INFO) << "Main decay file = " << m_decayFile << endmsg;
128 msg(MSG::INFO) << "User decay file = " << m_userDecayFile << endmsg;
129 msg(MSG::INFO) << "Max number of repeated decays = " << m_maxNRepeatedDecays << endmsg;
130 msg(MSG::INFO) << "EvtInclusiveDecay selection parameters:" << endmsg;
131 msg(MSG::INFO) << "* prohibitFinalStateDecay = " << m_prohibitFinalStateDecay << endmsg;
132 msg(MSG::INFO) << "* prohibitReDecay = " << m_prohibitReDecay << endmsg;
133 msg(MSG::INFO) << "* prohibitUnDecay = " << m_prohibitUnDecay << endmsg;
134 msg(MSG::INFO) << "* prohibitRemoveSelfDecay = " << m_prohibitRemoveSelfDecay << endmsg;
135 msg(MSG::INFO) << "* allowAllKnownDecays = " << m_allowAllKnownDecays << endmsg;
136 msg(MSG::INFO) << "* allowDefaultBDecays = " << m_allowDefaultBDecays << endmsg;
137 msg(MSG::INFO) << "User selection parameters:" << endmsg;
138 msg(MSG::INFO) << "* applyUserSelection = " << m_applyUserSelection << endmsg;
139 msg(MSG::INFO) << "* userSelRequireOppositeSignedMu = " << m_userSelRequireOppositeSignedMu << endmsg;
140 msg(MSG::INFO) << "* userSelMu1MinPt = " << m_userSelMu1MinPt << endmsg;
141 msg(MSG::INFO) << "* userSelMu2MinPt = " << m_userSelMu2MinPt << endmsg;
142 msg(MSG::INFO) << "* userSelMu1MaxEta = " << m_userSelMu1MaxEta << endmsg;
143 msg(MSG::INFO) << "* userSelMu2MaxEta = " << m_userSelMu2MaxEta << endmsg;
144 msg(MSG::INFO) << "* userSelMinDimuMass = " << m_userSelMinDimuMass << endmsg;
145 msg(MSG::INFO) << "* userSelMaxDimuMass = " << m_userSelMaxDimuMass << endmsg;
146
147 // Initialize and print blackList
148 m_blackListSet.insert(m_blackList.begin(),m_blackList.end());
149 msg(MSG::INFO) << "* blackList; = ";
150 for (std::set<int>::iterator i = m_blackListSet.begin(); i!=m_blackListSet.end(); ++i)
151 msg(MSG::INFO) << (*i) << " ";
152 msg(MSG::INFO)<< endmsg;
153
154 // Initialize and print whiteList
155 m_whiteListSet.insert(m_whiteList.begin(),m_whiteList.end());
156 msg(MSG::INFO) << "* whiteList = ";
157 for (std::set<int>::iterator i = m_whiteListSet.begin(); i!=m_whiteListSet.end(); ++i)
158 msg(MSG::INFO) << (*i) << " ";
159 msg(MSG::INFO) << endmsg;
160
161 CLHEP::HepRandomEngine* rndmEngine = getRandomEngineDuringInitialize(m_randomStreamName, m_randomSeed, m_dsid);
162 // Obtain random number generator for EvtGen
163 m_evtAtRndmGen = new EvtInclusiveAtRndmGen(rndmEngine);
164
165 // Create an instance of EvtGen and read particle properties and decay files
166 EvtExternalGenList genList(true,xmlpath(),"gamma");
167 EvtAbsRadCorr* radCorrEngine = genList.getPhotosModel();
168 std::list<EvtDecayBase*> extraModels = genList.getListOfModels();
169
170 // Create the EvtGen generator object
171 // EvtGen myGenerator("decayFile.dec", "evt.pdl", randomEnginePointer,
172 // radCorrEngine, &extraModels);
173
174
175 m_myEvtGen = new EvtGen( m_decayFile.c_str(), m_pdtFile.c_str(), m_evtAtRndmGen, radCorrEngine, &extraModels);
176 if(!m_userDecayFile.empty())
177 m_myEvtGen->readUDecay(m_userDecayFile.c_str());
178
179 return StatusCode::SUCCESS;
180}
181
182
183void EvtInclusiveDecay::reseedRandomEngine(const std::string& streamName,
184 const EventContext& ctx)
185{
186 long seeds[7];
187 ATHRNG::calculateSeedsMC21(seeds, streamName, ctx.eventID().event_number(), m_dsid, m_randomSeed);
188 m_evtAtRndmGen->getEngine()->setSeeds(seeds, 0); // NOT THREAD-SAFE
189}
190
191
192CLHEP::HepRandomEngine* EvtInclusiveDecay::getRandomEngine(const std::string& streamName, unsigned long int randomSeedOffset,
193 const EventContext& ctx) const
194{
195 ATHRNG::RNGWrapper* rngWrapper = m_rndmSvc->getEngine(this, streamName);
196 rngWrapper->setSeed( streamName, ctx.slot(), randomSeedOffset, ctx.eventID().run_number() );
197 return rngWrapper->getEngine(ctx);
198}
199
200
201CLHEP::HepRandomEngine* EvtInclusiveDecay::getRandomEngineDuringInitialize(const std::string& streamName, unsigned long int randomSeedOffset, unsigned int conditionsRun, unsigned int lbn) const
202{
203 const size_t slot=0;
204 EventContext ctx;
205 ctx.setSlot( slot );
206 ctx.setEventID (EventIDBase (conditionsRun,
207 EventIDBase::UNDEFEVT, // event
208 EventIDBase::UNDEFNUM, // timestamp
209 EventIDBase::UNDEFNUM, // timestamp ns
210 lbn));
212 Atlas::ExtendedEventContext( evtStore()->hiveProxyDict(),
213 conditionsRun) );
214 return getRandomEngine(streamName, randomSeedOffset, ctx);
215}
216
217
219 ATH_MSG_DEBUG("EvtInclusiveDecay executing");
220
221 const EventContext& ctx = Gaudi::Hive::currentContext();
223
224 std::string key = m_inputKeyName;
225 // retrieve event from Transient Store (Storegate)
226
227 // Load HepMC info
228 // FIXME should be using Read/WriteHandles here
229 const McEventCollection* oldmcEvtColl{};
230 if(m_readExisting) {
231 CHECK(evtStore()->retrieve(oldmcEvtColl, key));
232 // Fill the new McEventCollection with a copy of the initial HepMC::GenEvent
233 m_mcEvtColl = new McEventCollection(*oldmcEvtColl);
234 }
235 else {CHECK(evtStore()->retrieve(m_mcEvtColl, key));}
236
237 if(m_readExisting) {
238 if(m_outputKeyName!=key) {
240 }
241 }
242
244 for( mcItr = m_mcEvtColl->begin(); mcItr != m_mcEvtColl->end(); ++mcItr ) {
245 HepMC::GenEvent* hepMC = *mcItr;
246
247 // Search HepMC record for particles to be decayed by EvtGen
248 // NOTE: In order to ensure repeatability, we use customized a std::set to obtain
249 // an ordered list of particles to be decayed by EvtGen.
250 std::set<HepMC::GenVertexPtr> visited;
251 std::set<HepMC::GenParticlePtr,ParticleIdCompare> toBeDecayed;
252 for (auto p: *hepMC) {
253 if ( (!p->production_vertex()) ||
254 (p->production_vertex()->particles_in_size() == 0) ) {
255 StatusCode sc = traverseDecayTree(std::move(p),false,visited,toBeDecayed);
256 if (sc.isFailure())
257 return StatusCode::FAILURE;
258 }
259 }
260 // Print HepMC in tree format if desired (before doing anything)
262 msg(MSG::INFO) << "Printing HepMC record at " << hepMC << " BEFORE running EvtGen:" << endmsg;
264 printHepMC(hepMC,&toBeDecayed);
265 else
266 printHepMC(hepMC);
267 }
268
269
270 // Decay selected particles
271 bool eventPassesCuts(false);
272 int loopCounter(0);
273 while( !eventPassesCuts && loopCounter < m_maxNRepeatedDecays ) {
274
275 for (auto p: toBeDecayed) {
276 if (p == 0) {
277#ifdef HEPMC3
278 msg(MSG::ERROR ) << "Overlapping decay tree for particle" << p <<endmsg;
279#else
280 msg(MSG::ERROR ) << "Overlapping decay tree encountered for barcode " << HepMC::barcode(p) << endmsg;
281#endif
282 return StatusCode::FAILURE;
283 }
284 decayParticle(hepMC,std::move(p));
286 }
287
289 eventPassesCuts = passesUserSelection(hepMC);
290 else
291 eventPassesCuts = true;
292
294 loopCounter++;
295 }
296
297 // Store the number of decay attempts in event weights std::map, only if repeated decays enabled
298
299 if(m_maxNRepeatedDecays > 1) {
300#ifdef HEPMC3
301 hepMC->weight("nEvtGenDecayAttempts") = loopCounter;
302#else
303 hepMC->weights()["nEvtGenDecayAttempts"] = loopCounter;
304#endif
305 }
306 // Print HepMC in tree format if desired (after finishing all EvtGen decays)
308 msg(MSG::INFO) << "Printing HepMC record at " << hepMC << " AFTER running EvtGen:" << endmsg;
310 printHepMC(hepMC,&toBeDecayed);
311 else
312 printHepMC(hepMC);
313 }
314 }
315
316 if(m_readExisting && m_outputKeyName==key) {
318 }
319
320 return StatusCode::SUCCESS;
321}
322
323
325
327 ATH_MSG_INFO("The following particles were checked and didn't have any decay channels:");
328 if (msgLvl(MSG::INFO)) {
329 std::cout << std::endl;
330 std::cout << " Particle code Name from HepPDT # Occurences" << std::endl;
331 std::cout << "------------------------------------------------------" << std::endl;
332 for (std::map<int,long>::iterator p = m_noDecayChannels.begin(); p!=m_noDecayChannels.end(); ++p) {
333 int id = p->first;
334 int count = p->second;
335 std::cout << std::setw(14) << id
336 << std::setw(20) << HepPID::particleName(id)
337 << std::setw(20) << count
338 << std::endl;
339 }
340 std::cout << std::endl;
341 }
342 }
343 ATH_MSG_INFO("Total number of repeated decays: " << m_nRepeatedDecays);
344 ATH_MSG_INFO("EvtInclusiveDecay finalized");
345 return StatusCode::SUCCESS;
346}
347
348
349
350//
351// Recursively traverse the decay tree of a particle p, looking for particles to be
352// decayed by EvtGen. Care is taken to traverse each particle only once.
353// Note that since in each decay tree only the top-most particle will be decayed
354// by EvtGen (with its decay tree being deleted beforehand), we cannot use HepMC's
355// "descendant" iterator.
356//
358 bool isToBeRemoved,
359 std::set<HepMC::GenVertexPtr>& visited,
360 std::set<HepMC::GenParticlePtr,ParticleIdCompare>& toBeDecayed) {
361 ATH_MSG_VERBOSE("Inspecting: " << pdgName(p) << " " << p);
362 if (!isToBeRemoved) {
363 if (isToBeDecayed(p,true)) {
364 toBeDecayed.insert(p);
365 isToBeRemoved = true;
366 ATH_MSG_VERBOSE("Selected particle for decay: " << pdgName(p) << " " << p );
367
368 // In principle we could stop the recursion here. However, to prevent
369 // pathological cases in certain decay trees (in particular from Herwig),
370 // we continue in order to mark all descendants of this particle
371 // as visited. Thus none of these descendants can be flagged for further
372 // decay, even if it has several mothers.
373 }
374 }
375 auto v = p->end_vertex();
376 if (v) {
377 if (visited.insert(v).second) {
378 if ( isToBeRemoved && (v->particles_in_size()>1) && m_checkDecayTree ) {
379 ATH_MSG_WARNING("Found particle to be decayed with vertex with >1 incoming mother particles in decay tree");
380 ATH_MSG_WARNING( ([&p, &v](){ std::stringstream ss; HepMC::Print::line(ss,p); HepMC::Print::line(ss,v); return ss.str();})());
381 }
382 for (auto itp: *v) {
383 ATH_CHECK(traverseDecayTree(std::move(itp),isToBeRemoved,visited,toBeDecayed) );
384 }
385
386 }
387 }
388 return StatusCode::SUCCESS;
389}
390
391
392
393//
394// Remove an existing decay tree
395//
397 auto v = p->end_vertex();
398 if (v) {
399#ifdef HEPMC3
400 //This is recursive in HepMC3. But explicit deletion is allowed as well.
401 hepMC->remove_vertex(std::move(v));
402 p->set_status(1); // For now, flag particle as undecayed (stable)
403 ATH_MSG_DEBUG("Removed existing " << pdgName(p) << " " << p );
404#else
405 std::set<int> vtxBarCodesToDelete;
406 vtxBarCodesToDelete.insert(v->barcode());
407 for (HepMC::GenVertex::vertex_iterator itv = v->vertices_begin(HepMC::descendants);
408 itv != v->vertices_end(HepMC::descendants);
409 ++itv)
410 vtxBarCodesToDelete.insert((*itv)->barcode());
411 for (std::set<int>::iterator itb = vtxBarCodesToDelete.begin(); itb != vtxBarCodesToDelete.end(); ++itb) {
412 auto vdel = hepMC->barcode_to_vertex(*itb);
413 hepMC->remove_vertex(vdel);
414 delete vdel;
415 }
416 p->set_status(1); // For now, flag particle as undecayed (stable)
417 ATH_MSG_DEBUG("Removed existing " << pdgName(p) << " (barcode " << p->barcode() << ")" << " decay tree with " << vtxBarCodesToDelete.size() << " vertices");
418#endif
419 }
420}
421
422
423
424//
425// Decay a particle with EvtGen. Any existing decay tree will be removed.
426//
427// The following status codes are used:
428//
429// status == 1 - undecayed particle (also for particles that are not supposed to decay)
430// status == 2 - particle decayed by EvtGen
431// status == 0 - error, particle was supposed to be decayed by EvtGen, but found no decay channel
432//
433// Note that if a particle with an existing decay tree but no defined decay channels
434// in EvtGen is passed to this routine, the net effect will be to "undecay" this
435// particle. The particle will be flagged by status code 899, but MAY BE LOST further
436// downstream in the simulation chain. The default job parameters are for routine
437// isToBeDecayed() to never enable decays of such particles by EvtGen.
438//
439void EvtInclusiveDecay::decayParticle(HepMC::GenEvent* hepMC, HepMC::GenParticlePtr part) {
440 ATH_MSG_DEBUG("Decaying particle " << pdgName(part) << " " << part);
441 if (msgLvl(MSG::VERBOSE)) HepMC::Print::line(std::cout,part);
442
443 // Remove existing decay tree, if any, and flag particle as being decayed by EvtGen
444 removeDecayTree(hepMC,part);
445 part->set_status(0);
446
447 // Create EvtGen version of part and have EvtGen decay it.
448 // Since EvtGen uses GeV, convert particles momentum from MeV to GeV.
449 int id = part->pdg_id();
450 EvtId evtId=EvtPDL::evtIdFromStdHep(id);
451 double en =(part->momentum()).e()/1000.;
452 double px=(part->momentum()).px()/1000.;
453 double py=(part->momentum()).py()/1000.;
454 double pz=(part->momentum()).pz()/1000.;
455 EvtVector4R evtP(en,px,py,pz);
456 EvtParticle* evtPart = EvtParticleFactory::particleFactory(evtId,evtP);
457
458 // set transverse polarization to vector mesons (relevant for coherent production of J/Psi etc in UPC)
459 if(m_setVMtransversePol && (id==113 || id== 443 || id==100443 || id==553 || id==100553 || id==200553) )evtPart->setVectorSpinDensity();
460
461 m_myEvtGen->generateDecay(evtPart);
462 if (msgLvl(MSG::VERBOSE)) evtPart->printTree();
463 double ct_s = part->production_vertex()->position().t();
464 double x_s = part->production_vertex()->position().x();
465 double y_s = part->production_vertex()->position().y();
466 double z_s = part->production_vertex()->position().z();
467
468 EvtVector4R treeStart(ct_s,x_s,y_s,z_s);
469 // Add new decay tree to hepMC, converting back from GeV to MeV.
470 addEvtGenDecayTree(hepMC, part, evtPart, treeStart, 1000.);
471 if(evtPart->getNDaug() !=0) part->set_status(2);
472 evtPart->deleteTree();
473}
474
475
476
478 EvtParticle* evtPart, EvtVector4R treeStart, double momentumScaleFactor) {
479 if(evtPart->getNDaug()!=0) {
480 // Add decay vertex, starting from production vertex of particle
481 double ct=(evtPart->getDaug(0)->get4Pos()).get(0)+treeStart.get(0);
482 double x=(evtPart->getDaug(0)->get4Pos()).get(1)+treeStart.get(1);
483 double y=(evtPart->getDaug(0)->get4Pos()).get(2)+treeStart.get(2);
484 double z=(evtPart->getDaug(0)->get4Pos()).get(3)+treeStart.get(3);
485
486 HepMC::GenVertexPtr end_vtx = HepMC::newGenVertexPtr(HepMC::FourVector(x,y,z,ct));
487
488 hepMC->add_vertex(end_vtx);
489 end_vtx->add_particle_in(std::move(part));
490
491 // Add decay daughter with their own decay trees
492 for(uint it=0; it<evtPart->getNDaug(); it++) {
493 double e=(evtPart->getDaug(it)->getP4Lab()).get(0) * momentumScaleFactor;
494 double px=(evtPart->getDaug(it)->getP4Lab()).get(1) * momentumScaleFactor;
495 double py=(evtPart->getDaug(it)->getP4Lab()).get(2) * momentumScaleFactor;
496 double pz=(evtPart->getDaug(it)->getP4Lab()).get(3) * momentumScaleFactor;
497 int id=EvtPDL::getStdHep(evtPart->getDaug(it)->getId());
498 int status=1;
499 if(evtPart->getDaug(it)->getNDaug() != 0) status=2;
500 HepMC::GenParticlePtr daughter = HepMC::newGenParticlePtr(HepMC::FourVector(px,py,pz,e),id,status);
501 end_vtx->add_particle_out(daughter);
502 addEvtGenDecayTree(hepMC, std::move(daughter), evtPart->getDaug(it), treeStart, momentumScaleFactor);
503 }
504 }
505}
506
507
508
509//
510// isToBeDecayed returns true if we want the particle p to be decayed by
511// EvtGen based on the job options selected by the user.
512// The parameter doCrossChecks is used to prevent double-counting for cross-checks
513// if isToBeDecayed is called more than once for the same particle.
514//
516 int id = p->pdg_id();
517 int nDaughters = 0;
518 auto v = p->end_vertex();
519 if (v) nDaughters = v->particles_out_size();
520
521 // Ignore documentation lines
522 if (p->status() == 3) return false;
523 // And any particles that aren't stable or decayed
524 if(!m_isfHerwig && !MC::isPhysical(p)) return false;
525
526 // Particularly for Herwig, try to ignore particles that really should
527 // be flagged as documentation lines
528 double m2 = p->momentum().m2();
529 if (m2 < -1.0E-3) {
530 ATH_MSG_DEBUG("Ignoring particle " << pdgName(std::move(p)) << " with m^2 = " << m2);
531 return false;
532 }
533
534 // Check whether EvtGen has any decay channels defined for this particle
535 EvtId evtId = EvtPDL::evtIdFromStdHep(id);
536 // std::cout << "EVTID: " << evtId.getId() << " alias " << evtId.getAlias() << std::endl;
537 int nModes = 0;
538 if (evtId.getId()>=0)
539 // nModes = EvtDecayTable::getNMode(evtId.getAlias());
540 nModes = EvtDecayTable::getInstance()->getNMode(evtId.getAlias());
541 if (doCrossChecks) {
542 ATH_MSG_VERBOSE("Checking particle " << pdgName(p)
543 << " (status = " << p->status()
544 <<") -- " << nModes << " decay modes found");
545 if (m_checkDecayChannels && nModes==0) {
546 std::map<int,long>::iterator pos = m_noDecayChannels.find(id);
547 if (pos != m_noDecayChannels.end())
548 (pos->second)++;
549 else
550 m_noDecayChannels[id] = 1;
551 }
552 }
553
554 // Check prohibit* settings
555 if (m_prohibitFinalStateDecay && MC::isStable(p)) return false;
556 if (m_prohibitReDecay && nDaughters>0) return false;
557 if (m_prohibitUnDecay && nModes==0) return false;
558 if (m_prohibitRemoveSelfDecay && nDaughters>0) {
559 // For now, check only children - this should be sufficient and checking all
560 // descendants would be very expensive.
561 for (auto itd: *v) {
562 if (std::abs(itd->pdg_id()) == std::abs(id)) return false;
563 }
564 }
565
566 // Check blackList
567 if (m_blackListSet.count(std::abs(id))>0) return false;
568
569 // Check allow* settings
570 if (m_allowAllKnownDecays && nModes>0) return true;
571 if (m_allowDefaultBDecays && isDefaultB(id)) return true;
572
573 // Check whiteList
574 if (m_whiteListSet.count(std::abs(id))>0) return true;
575
576 return false; // Default is NOT to decay through EvtGen
577}
578
579
580
581//
582// The following mimicks the particle selection implemented in EvtDecay.
583//
584bool EvtInclusiveDecay::isDefaultB(const int pId) const {
585 int id = std::abs(pId);
586 if ( id == 511 ||
587 id == 521 ||
588 id == 531 ||
589 id == 541 ||
590 id == 5122 ||
591 id == 5132 ||
592 id == 5232 ||
593 id == 5112 ||
594 id == 5212 ||
595 id == 5222 )
596 return true;
597 else
598 return false;
599}
600
601//
602// Function to apply the user selection after repeated decay
603// Now the selection is based on di-muon kinematics only
604// TODO: to be replaced by something more configurable
605//
606bool EvtInclusiveDecay::passesUserSelection(HepMC::GenEvent* hepMC) {
607 bool passed(false);
608 std::vector<HepMC::GenParticlePtr> *muons = new std::vector<HepMC::GenParticlePtr>;
609
610 for ( const auto& p: *hepMC) {
611 if( std::abs(p->pdg_id()) == 13 )
612 muons->push_back(p);
613 }
614
615 for (auto muItr1 = muons->begin(); muItr1 != muons->end(); ++muItr1) {
616 for (auto muItr2 = muItr1+1; muItr2 != muons->end(); ++muItr2) {
617 if( m_userSelRequireOppositeSignedMu && (*muItr1)->pdg_id() * (*muItr2)->pdg_id() > 0)
618 continue;
619 if( !( (*muItr1)->momentum().perp() > m_userSelMu1MinPt && std::abs((*muItr1)->momentum().pseudoRapidity()) < m_userSelMu1MaxEta &&
620 (*muItr2)->momentum().perp() > m_userSelMu2MinPt && std::abs((*muItr2)->momentum().pseudoRapidity()) < m_userSelMu2MaxEta ) &&
621 !( (*muItr2)->momentum().perp() > m_userSelMu1MinPt && std::abs((*muItr2)->momentum().pseudoRapidity()) < m_userSelMu1MaxEta &&
622 (*muItr1)->momentum().perp() > m_userSelMu2MinPt && std::abs((*muItr1)->momentum().pseudoRapidity()) < m_userSelMu2MaxEta ) )
623 continue;
624 double dimuMass = invMass((*muItr1),(*muItr2));
625 if( !( dimuMass > m_userSelMinDimuMass && (dimuMass < m_userSelMaxDimuMass || m_userSelMaxDimuMass < 0.) ) )
626 continue;
627 passed = true;
628 }
629 }
630
631 delete muons;
632
633 return passed;
634}
635
637 double p1Px = p1->momentum().px();
638 double p1Py = p1->momentum().py();
639 double p1Pz = p1->momentum().pz();
640 double p1E = p1->momentum().e();
641 double p2Px = p2->momentum().px();
642 double p2Py = p2->momentum().py();
643 double p2Pz = p2->momentum().pz();
644 double p2E = p2->momentum().e();
645 double dimuE = p2E + p1E;
646 double dimuPx = p2Px + p1Px;
647 double dimuPy = p2Py + p1Py;
648 double dimuPz = p2Pz + p1Pz;
649 double invMass = std::sqrt(dimuE*dimuE - dimuPx*dimuPx - dimuPy*dimuPy - dimuPz*dimuPz);
650
651 return invMass;
652}
653
654//
655// Utility functions to print a HepMC event record in a tree-like format, using
656// colors to denote the status of particles and to indicate which particles
657// are selected by the job options to be decayed by EvtGen.
658//
659
660void EvtInclusiveDecay::printHepMC(HepMC::GenEvent* hepMC, std::set<HepMC::GenParticlePtr,ParticleIdCompare>* particleSet) {
661 std::set<HepMC::GenVertexPtr> visited;
662 unsigned int nParticlesFound = 0;
663 unsigned int nTreesFound = 0;
664 for (auto p: *hepMC) {
665 if ( (!p->production_vertex()) ||
666 (p->production_vertex()->particles_in_size() == 0) ) {
667 nTreesFound++;
668 std::cout << "\n Found new partial decay tree:\n" << std::endl;
669 unsigned int nParticlesVisited = printTree(std::move(p),visited,1,particleSet);
670 std::cout << "\n " << nParticlesVisited << " particles in this subtree" << std::endl;
671 nParticlesFound += nParticlesVisited;
672 }
673 }
674 std::cout << "\n Total of " << nParticlesFound << " particles found in "
675 << nTreesFound << " decay subtrees in HepMC event record\n" << std::endl;
676}
677
678unsigned int EvtInclusiveDecay::printTree(HepMC::GenParticlePtr p, std::set<HepMC::GenVertexPtr>& visited, int level, std::set<HepMC::GenParticlePtr,ParticleIdCompare>* particleSet) {
679
680 unsigned int nParticlesVisited = 1;
681 for (int i=0; i<level; i++) std::cout << " ";
682 std::cout << pdgName(p,m_printHepMCHighlighted,particleSet);
683 auto v = p->end_vertex();
684 if (v) {
685 if (v->particles_in_size() > 1)
686 std::cout << " [interaction: " << v->particles_in_size() << " particles, vertex " << v << "] --> ";
687 else
688 std::cout << " --> ";
689 if (visited.insert(v).second) {
690 for (auto itp: *v) {
691 std::cout << pdgName(itp,m_printHepMCHighlighted,particleSet) << " ";
692 }
693 std::cout << std::endl;
694 for (auto itp: *v) {
695 if (itp->end_vertex())
696 nParticlesVisited += printTree(std::move(itp), visited, level+1, particleSet);
697 else
698 nParticlesVisited++;
699 }
700 } else
701 std::cout << "see above" << std::endl;
702 } else
703 std::cout << " no decay vertex\n" << std::endl;
704 return nParticlesVisited;
705}
706
707std::string EvtInclusiveDecay::pdgName(HepMC::ConstGenParticlePtr p, bool statusHighlighting, std::set<HepMC::GenParticlePtr,ParticleIdCompare>* particleSet) {
708 std::ostringstream buf;
709 bool inlist = false;
710#ifdef HEPMC3
711 if (particleSet) for (const auto& pinl: *particleSet) if (pinl&&p) if (pinl.get() == p.get()) inlist=true;
712#else
713 auto p_nc ATLAS_THREAD_SAFE = const_cast<HepMC::GenParticlePtr> (p);
714 if (particleSet) inlist = (particleSet->find(p_nc) != particleSet->end());
715#endif
716 if (statusHighlighting) {
717 if ( ((particleSet!=0) && (inlist)) ||
718 ((particleSet==0) && isToBeDecayed(p,false)) )
719 buf << "\033[7m"; // reverse
720 if (!MC::isStable(p)) {
721 if (MC::isDecayed(p))
722 buf << "\033[33m"; // yellow
723 else
724 buf << "\033[31m"; // red
725 }
726 }
727 buf << p->pdg_id();
728 buf << "/" << HepPID::particleName(p->pdg_id());
729 if (statusHighlighting) {
730 buf << "\033[0m"; // revert color attributes
731 }
732 return buf.str();
733}
734
735
736//
737// Interface between Athena random number service and EvtGen's EvtRandomEngine class
738//
739EvtInclusiveAtRndmGen::EvtInclusiveAtRndmGen(CLHEP::HepRandomEngine* engine)
740 : m_engine(engine)
741{}
742
744 return CLHEP::RandFlat::shoot(m_engine);
745}
746
748
750 return PathResolverFindCalibDirectory( "Pythia8/xmldoc" );
751}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
defines an "iterator" over instances of a given type in StoreGateSvc
ATLAS-specific HepMC functions.
bool passed(DecisionID id, const DecisionIDContainer &)
checks if required decision ID is in the set of IDs in the container
unsigned int uint
static Double_t ss
static Double_t sc
std::string PathResolverFindCalibDirectory(const std::string &logical_file_name)
#define y
#define x
#define z
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
void setSeed(const std::string &algName, const EventContext &ctx)
Set the random seed using a string (e.g.
Definition RNGWrapper.h:169
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:134
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
bool msgLvl(const MSG::Level lvl) const
DataModel_detail::iterator< DataVector > iterator
Definition DataVector.h:842
EvtInclusiveAtRndmGen(CLHEP::HepRandomEngine *engine)
CLHEP::HepRandomEngine * m_engine
void printHepMC(HepMC::GenEvent *hepMC, std::set< HepMC::GenParticlePtr, ParticleIdCompare > *particleSet=nullptr)
CLHEP::HepRandomEngine * getRandomEngine(const std::string &streamName, unsigned long int randomSeedOffset, const EventContext &ctx) const
ServiceHandle< IAthRNGSvc > m_rndmSvc
void removeDecayTree(HepMC::GenEvent *hepMC, HepMC::GenParticlePtr p)
void reseedRandomEngine(const std::string &streamName, const EventContext &ctx)
bool isDefaultB(const int pId) const
std::set< int > m_blackListSet
CLHEP::HepRandomEngine * getRandomEngineDuringInitialize(const std::string &streamName, unsigned long int randomSeedOffset, unsigned int conditionsRun=1, unsigned int lbn=1) const
void addEvtGenDecayTree(HepMC::GenEvent *hepMC, HepMC::GenParticlePtr part, EvtParticle *evtPart, EvtVector4R treeStart, double momentumScaleFactor=1.0)
std::string m_randomStreamName
IntegerProperty m_dsid
StatusCode traverseDecayTree(HepMC::GenParticlePtr p, bool isToBeRemoved, std::set< HepMC::GenVertexPtr > &visited, std::set< HepMC::GenParticlePtr, ParticleIdCompare > &toBeDecayed)
bool passesUserSelection(HepMC::GenEvent *hepMC)
double invMass(HepMC::ConstGenParticlePtr p1, HepMC::ConstGenParticlePtr p2)
McEventCollection * m_mcEvtColl
std::string m_userDecayFile
std::string xmlpath(void)
std::set< int > m_whiteListSet
IntegerProperty m_randomSeed
Seed for random number engine.
std::vector< int > m_blackList
unsigned int printTree(HepMC::GenParticlePtr p, std::set< HepMC::GenVertexPtr > &visited, int level, std::set< HepMC::GenParticlePtr, ParticleIdCompare > *particleSet=nullptr)
std::string m_outputKeyName
bool isToBeDecayed(HepMC::ConstGenParticlePtr p, bool doCrossChecks)
std::string pdgName(HepMC::ConstGenParticlePtr p, bool statusHighlighting=false, std::set< HepMC::GenParticlePtr, ParticleIdCompare > *particleSet=nullptr)
std::map< int, long > m_noDecayChannels
void decayParticle(HepMC::GenEvent *hepMC, HepMC::GenParticlePtr p)
EvtInclusiveAtRndmGen * m_evtAtRndmGen
EvtInclusiveDecay(const std::string &name, ISvcLocator *pSvcLocator)
std::vector< int > m_whiteList
virtual StatusCode initialize() override
Definition GenBase.cxx:17
GenBase(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition GenBase.cxx:11
This defines the McEventCollection, which is really just an ObjectVector of McEvent objectsFile: Gene...
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
void calculateSeedsMC21(long *seeds, const std::string &algName, uint64_t ev, uint64_t run, uint64_t offset=0)
Set the random seed using a string (e.g.
void setExtendedEventContext(EventContext &ctx, ExtendedEventContext &&ectx)
Move an extended context into a context object.
void line(std::ostream &os, const GenEvent &e)
Definition GenEvent.h:677
int barcode(const T *p)
Definition Barcode.h:16
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
void fillBarcodesAttribute(GenEvent *)
Definition GenEvent.h:627
GenParticle * GenParticlePtr
Definition GenParticle.h:37
const GenParticle * ConstGenParticlePtr
Definition GenParticle.h:38
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
bool isDecayed(const T &p)
Identify if the particle decayed.
bool isPhysical(const T &p)
Identify if the particle is physical, i.e. is stable or decayed.
MsgStream & msg
Definition testRead.cxx:32