28(
const std::string &name, ISvcLocator *pSvcLocator):
Pythia8_i(name,pSvcLocator) {
69 for (std::vector<int>::iterator iit=
m_bcodes.begin(); iit!=
m_bcodes.end(); ++iit) {
72 m_runinfo = std::make_shared<HepMC3::GenRunInfo>();
73 std::vector<std::string> names = {
"Default"};
87 ATH_MSG_ERROR(
"You are requesting " << trigPtCutsSize <<
" trigger-like pt cuts but are providing required counts for " <<
m_cutCount.size() <<
" cuts. This doesn't make sense.");
88 return StatusCode::FAILURE;
103 return StatusCode::FAILURE;
114 ATH_MSG_FATAL(
"Unable to retrieve HepRandomEngine. Bailing out.");
115 return StatusCode::FAILURE;
118 return StatusCode::SUCCESS;
140 for (std::vector<int>::iterator iit=
m_bcodes.begin(); iit!=
m_bcodes.end(); ++iit) {
144 return StatusCode::SUCCESS;
155 ATH_MSG_DEBUG(
"BEventBuffer not empty; skipping callGenerator");
156 return StatusCode::SUCCESS;
162 const EventContext& ctx = Gaudi::Hive::currentContext();
182 return StatusCode::FAILURE;
188 ATH_MSG_ERROR(
"Exceeded the max number of consecutive event failures.");
189 return StatusCode::FAILURE;
200 int nbBeforeSelection(0);
201 int nbbarBeforeSelection(0);
202 int ncBeforeSelection(0);
203 int ncbarBeforeSelection(0);
209 for (
int i = 0; i <
event.size(); ++i) {
210 stat =
event[i].statusAbs();
211 bool isBQuark(
false);
212 bool isCQuark(
false);
213 bool isAntiBQuark(
false);
214 bool isAntiCQuark(
false);
216 if (event[i].
id() == 5 && (stat == 62 || stat == 63)) {isBQuark=
true; ++nbBeforeSelection;}
217 if (event[i].
id() == 4 && (stat == 62 || stat == 63)) {isCQuark=
true; ++ncBeforeSelection;}
219 bool passesPtCut(
false);
bool passesEtaCut(
false);
220 std::string accString =
" : REJECTED";
221 double qpt =
event[i].pT();
double qeta = std::abs(event[i].
eta());
224 if (passesPtCut && passesEtaCut) {
225 if (isBQuark) ++nbQuark;
226 if (isCQuark) ++ncQuark;
227 accString =
" : ACCEPTED";
229 if (isBQuark)
ATH_MSG_DEBUG(
"bQuark pt/eta = " << qpt <<
"/" << qeta << accString);
230 if (isCQuark)
ATH_MSG_DEBUG(
"cQuark pt/eta = " << qpt <<
"/" << qeta << accString);
233 if (event[i].
id() == -5 && (stat == 62 || stat == 63)) {isAntiBQuark=
true; ++nbbarBeforeSelection;}
234 if (event[i].
id() == -4 && (stat == 62 || stat == 63)) {isAntiCQuark=
true; ++ncbarBeforeSelection;}
236 bool passesPtCut(
false);
bool passesEtaCut(
false);
237 std::string accString =
" : REJECTED";
238 double aqpt =
event[i].pT();
double aqeta = std::abs(event[i].
eta());
241 if (passesPtCut && passesEtaCut) {
242 if (isAntiBQuark) ++nbbarQuark;
243 if (isAntiCQuark) ++ncbarQuark;
244 accString =
" : ACCEPTED";
246 if (isAntiBQuark)
ATH_MSG_DEBUG(
"bbarQuark pt/eta = " << aqpt <<
"/" << aqeta << accString);
247 if (isAntiCQuark)
ATH_MSG_DEBUG(
"ccbarQuark pt/eta = " << aqpt <<
"/" << aqeta << accString);
250 if (nbBeforeSelection+nbbarBeforeSelection>=4 &&
m_vetoDoubleB) {
251 ATH_MSG_DEBUG(
"At user request, rejecting double b-bbar event; throwing dice again");
254 if (ncBeforeSelection+ncbarBeforeSelection>=4 &&
m_vetoDoubleC) {
255 ATH_MSG_DEBUG(
"At user request, rejecting double c-cbar event; throwing dice again");
258 bool rejectBBbar(
false);
259 bool rejectCCbar(
false);
266 ATH_MSG_DEBUG(
"No b- or c- quarks accepted; throwing the dice again");
270 ATH_MSG_DEBUG(
"No b-quarks accepted; throwing the dice again");
274 ATH_MSG_DEBUG(
"No c-quarks accepted; throwing the dice again");
284 bool doRepeatedDecays(
false);
if (
m_dec>1) doRepeatedDecays=
true;
285 if (doRepeatedDecays) {
291 Pythia8::Event eventCopy;
292 std::vector<Pythia8::Event> repeatHadronizedEvents;
293 std::vector<Pythia8::Event>::iterator eventItr;
296 for (
unsigned int iRepeat = 0; iRepeat <
m_had; ++iRepeat) {
299 if (iRepeat > 0)
event = eventCopy;
302 repeatHadronizedEvents.push_back(event);
306 std::vector<Pythia8::Event> savedEvents;
307 if (doRepeatedDecays) {
311 for (eventItr=repeatHadronizedEvents.begin(); eventItr!=repeatHadronizedEvents.end(); ++eventItr) {
312 for (
unsigned int iRepeat = 0; iRepeat <
m_dec; ++iRepeat) {
315 savedEvents.push_back(event);
319 if (!doRepeatedDecays) savedEvents = std::move(repeatHadronizedEvents);
324 std::vector<Pythia8::Event> finalEvents;
325 bool signalSelect(
false);
327 for (eventItr=savedEvents.begin(); eventItr!=savedEvents.end(); ++eventItr) {
340 finalEvents.push_back(*eventItr);
347 for (eventItr=finalEvents.begin(); eventItr!=finalEvents.end(); ++eventItr) {
348 for (
int i = 0; i < (*eventItr).size(); ++i) {
349 int id = (*eventItr)[i].id();
350 std::map<int,int>::iterator it;
365 StatusCode returnCode = StatusCode::SUCCESS;
376 ATH_MSG_DEBUG(
"BEventBuffer now empty - going to next Pythia event");
377 return StatusCode::SUCCESS;
390 if (!evt->run_info()) evt->set_run_info(
m_runinfo);
391 evt->set_units(HepMC3::Units::MEV, HepMC3::Units::MM);
398 return StatusCode::SUCCESS;
410 double xs = info.sigmaGen();
413 std::cout <<
"MetaData: cross-section (nb)= " << xs << std::endl;
415 std::cout <<
"Number of accepted b quarks = " <<
m_totalBQuark<< std::endl;
416 std::cout <<
"Number of accepted bbar quarks = " <<
m_totalBBarQuark<< std::endl;
417 std::cout <<
"Number of accepted c quarks = " <<
m_totalCQuark<< std::endl;
418 std::cout <<
"Number of accepted cbar quarks = " <<
m_totalCBarQuark<< std::endl;
419 std::cout <<
"Number of accepted b/c events before hadronization = " <<
m_totalHard<< std::endl;
420 std::cout <<
"Number of hadronization loops per b/c-event = " <<
m_had<< std::endl;
421 std::cout <<
"Total number of hadronization loops = " <<
m_totalClone<< std::endl;
422 std::cout <<
"Number of accepted b/c events yielding at least one finally accepted event = " <<
m_atLeastOneAcc<< std::endl;
426 std::cout <<
"Summary of cuts: " << std::endl;
428 if (
m_selectBQuarks) std::cout <<
"Quarks cuts apply to b-quarks" << std::endl;
429 if (
m_selectCQuarks) std::cout <<
"Quarks cuts apply to c-quarks" << std::endl;
430 std::cout <<
"Quark pt > " <<
m_qPtCut << std::endl;
431 std::cout <<
"Antiquark pt > " <<
m_aqPtCut << std::endl;
432 std::cout <<
"Quark eta < " <<
m_qEtaCut << std::endl;
433 std::cout <<
"Antiquark eta < " <<
m_aqEtaCut << std::endl;
434 if (
m_and) std::cout <<
"Require quark and anti-quark pass cuts" << std::endl;
436 std::cout <<
"Trigger lepton type = " <<
m_trigCode << std::endl;
437 std::cout <<
"Trigger lepton pt cuts: ";
438 for (
unsigned int prCntr=0; prCntr<
m_trigPtCut.size(); ++prCntr) {std::cout <<
m_trigPtCut[prCntr] <<
" ";}
439 std::cout << std::endl;
440 std::cout <<
"Trigger lepton eta cut: " <<
m_trigEtaCut << std::endl;
441 std::cout <<
"Required number of leptons passing each trigger cut = ";
442 for (
unsigned int prCntr=0; prCntr<
m_cutCount.size(); ++prCntr) {std::cout <<
m_cutCount[prCntr] <<
" ";}
443 std::cout << std::endl;
444 std::cout <<
"Invariant mass of trigger leptons > " <<
m_invMass << std::endl;
445 if (
m_oppCharges) std::cout <<
"Trigger leptons required to have opposite charges" << std::endl;
450 std::cout <<
"\nSpecies\tCount\n"<< std::endl;
453 std::cout << iter->first <<
'\t' << iter->second <<
'\n'<< std::endl;
455 if (
m_dec>1) std::cout <<
"Number of times each of these states were copied and decayed: " <<
m_dec << std::endl;
460 std::cout <<
" I===================================================================================== " << std::endl;
461 std::cout <<
" I CROSSSECTION OF YOUR B-CHANNEL IS I " << std::endl;
462 std::cout <<
" I BX= PX*NB/AC/MHAD= I " << finalXS <<
" nb" << std::endl;
463 std::cout <<
" I I " << std::endl;
464 std::cout <<
" I IN CASE YOU FORCED ANY DECAY YOU SHOULD I " << std::endl;
465 std::cout <<
" I CORRECT CROSS SECTION BX FURTHER, MULTIPLYING I " << std::endl;
466 std::cout <<
" I BX BY BRANCHING RATIO(S) OF YOUR FORCED I " << std::endl;
467 std::cout <<
" I DECAY(S) AND BY A FACTOR OF 2 FOR SYMMETRY I " << std::endl;
468 std::cout <<
" I I " << std::endl;
469 std::cout <<
" I MORE DETAILS ON CROSS SECTION I " << std::endl;
470 std::cout <<
" I PYTHIA CROSS SECTION IS PX= I " << xs <<
" nb" << std::endl;
471 std::cout <<
" I NUMBER OF ACCEPTED HARD EVENTS AC= I " <<
m_totalPythiaCalls << std::endl;
473 std::cout <<
" I REPEATED HADRONIZATIONS IN EACH EVENT MHAD= I " <<
m_had << std::endl;
474 std::cout <<
" I AVERAGE NUM OF ACCEPTED EVTS IN HADRONIZATION LOOP I " << cloningFactor << std::endl;
475 std::cout <<
" I IN CASE YOU FORCED ANY DECAY YOU SHOULD I " << std::endl;
476 std::cout <<
" I CORRECT CROSS SECTION BX FURTHER, MULTIPLYING I " << std::endl;
477 std::cout <<
" I BX BY BRANCHING RATIO(S) OF YOUR FORCED I " << std::endl;
478 std::cout <<
" I DECAY(S) AND BY A FACTOR OF 2 FOR SYMMETRY I " << std::endl;
479 std::cout <<
" I I " << std::endl;
480 std::cout <<
" I===================================================================================== " << std::endl;
481 std::cout <<
"" << std::endl;
482 std::cout <<
"MetaData: cross-section (nb)= " << finalXS << std::endl;
484 return StatusCode::SUCCESS;
493bool Pythia8B_i::leptonSelect(Pythia8::Event &theEvent,
const std::vector<double> &ptCut,
double etaCut,
const std::vector<int> &counts,
int type_id,
double massCut,
bool opposite) {
495 if (type_id==0)
return true;
497 std::string accString(
" : REJECTED");
499 std::vector<int> leptonIDs;
500 int nCuts=ptCut.size();
501 std::vector<int> countGood(nCuts, 0);
503 for (
int i = 0; i<theEvent.size(); ++i) {
504 const Pythia8::Particle &theParticle = theEvent[i];
505 int id = theParticle.idAbs();
506 if (
id == type_id ) {
507 double pt = theParticle.pT();
508 double eta = theParticle.eta();
509 ATH_MSG_DEBUG(
"Lepton of type " <<
id <<
" with pt/eta " << pt <<
"/" <<
eta);
510 for (
int cutCntr=0; cutCntr<nCuts; ++cutCntr) {
511 if ( (pt>ptCut[cutCntr]) && (std::abs(
eta)<etaCut) ) {
512 countGood[cutCntr] += 1;
513 leptonIDs.push_back(i);
519 for (
int cutCntr=0; cutCntr<nCuts; ++cutCntr) {
520 if (countGood[cutCntr] >= counts[cutCntr]) ++nPassed;
522 if (nPassed==nCuts)
break;
527 for (
int cutCntr=0; cutCntr<nCuts; ++cutCntr) {
528 if (countGood[cutCntr] >= counts[cutCntr]) ++nPassed;
530 if (nPassed >= nCuts && nCuts==1) {accString=
" : ACCEPTED";
passed =
true;}
531 if (nPassed >= nCuts && nCuts>1 &&
pairProperties(theEvent,leptonIDs,massCut,opposite)) {accString=
" : ACCEPTED";
passed =
true;}
541 bool cleanEvent(
true);
542 std::string accString(
" : ACCEPTED");
543 for (
int i = 0; i<theEvent.size(); ++i) {
544 const Pythia8::Particle &theParticle = theEvent[i];
545 int id = theParticle.id();
546 int status = theParticle.status();
547 for (
auto iItr = bCodes.begin(); iItr!=bCodes.end(); ++iItr) {
548 if ( (
id == *iItr) && (status>0) ) {accString=
" : REJECTED"; cleanEvent =
false;}
551 ATH_MSG_DEBUG(
"Check event for undecayed signal particles" << accString);
565 bool passesCuts(
false);
566 std::string accString(
" : REJECTED");
567 for (
auto iit = leptonIDs.begin(); iit!=leptonIDs.end(); ++iit) {
568 for (
auto iit2 = iit+1; iit2!=leptonIDs.end(); ++iit2) {
569 int q1=theEvent[*iit].charge();
570 int q2=theEvent[*iit2].charge();
571 if (opposite && (q1*q2>0))
continue;
572 double px1=theEvent[*iit].px();
573 double py1=theEvent[*iit].py();
574 double pz1=theEvent[*iit].pz();
575 double mass1=theEvent[*iit].mSel();
576 double e1=std::sqrt(px1*px1+py1*py1+pz1*pz1+mass1*mass1);
577 double px2=theEvent[*iit2].px();
578 double py2=theEvent[*iit2].py();
579 double pz2=theEvent[*iit2].pz();
580 double mass2=theEvent[*iit2].mSel();
581 double e2=std::sqrt(px2*px2+py2*py2+pz2*pz2+mass2*mass2);
583 double pxSum=px1+px2;
584 double pySum=py1+py2;
585 double pzSum=pz1+pz2;
586 double M=std::sqrt(eSum*eSum-pxSum*pxSum-pySum*pySum-pzSum*pzSum);
589 ATH_MSG_DEBUG(
"Acceptable lepton pair with invariant mass : " << M);
593 if (passesCuts) {accString=
" : ACCEPTED";
break;}
604 list.push_back(theEvent[i]);
605 std::vector<int> childrenIndices = theEvent.daughterList(i);
606 std::vector<int>::iterator iItr;
607 for (iItr = childrenIndices.begin(); iItr != childrenIndices.end(); ++iItr) {
619 std::vector<int> codes;
620 codes.reserve(theParticles.size());
621 for (
auto pItr = theParticles.begin(); pItr!=theParticles.end(); ++pItr ) {
622 codes.push_back( (*pItr).id() );
633 if (vect1.size()!=vect2.size())
return false;
635 bool isTheSame(
true);
636 int size = vect1.size();
639 for (
int i=0; i<
size; ++i) {
640 if (vect1[i] != vect2[i]) {isTheSame =
false;
break;}
654 for (
auto pItr=theParticles.cbegin(); pItr!=theParticles.cend(); ++pItr,++i) {
666 for (
auto pItr=theParticles.cbegin(); pItr!=theParticles.cend(); ++pItr,++i) {
667 if (std::abs((*pItr).eta()) >
m_sigEtaCuts[i]) pass =
false;
679 unsigned int nRequired)
const {
681 bool acceptEvent(
false);
682 std::vector<int> parentsIndices;
683 for (
int i = 0; i<theEvent.size(); ++i) {
684 const Pythia8::Particle &theParticle = theEvent[i];
685 int id = theParticle.id();
686 if (
id==requiredDecay[0]) parentsIndices.push_back(i);
691 if ( (requiredDecay.size()==1) && (parentsIndices.size()>0) ) {
696 unsigned int goodDecayCounter(0);
697 for (std::vector<int>::iterator iItr = parentsIndices.begin(); iItr!=parentsIndices.end(); ++iItr) {
698 std::vector<Pythia8::Particle> decayMembers;
700 std::vector<int> pdgCodes =
getCodes(decayMembers);
701 if (!
compare(requiredDecay,std::move(pdgCodes))) {
702 ATH_MSG_DEBUG(
"Signal event REJECTED as does not contain required decay chain");
709 ATH_MSG_DEBUG(
"Signal event REJECTED as signal chain does not pass pt cuts");
716 ATH_MSG_DEBUG(
"Signal event REJECTED as signal chain does not pass eta cuts");
725 else {++goodDecayCounter;}
728 if (goodDecayCounter>=nRequired) {
729 ATH_MSG_DEBUG(nRequired <<
"signal decays required; " << goodDecayCounter <<
" found; event ACCEPTED");
732 else if (goodDecayCounter<nRequired) {
733 ATH_MSG_DEBUG(nRequired <<
"signal decays required; " << goodDecayCounter <<
" found; event REJECTED");
745void Pythia8B_i::printSignalSelections(
const std::vector<int> &signalProcess,
const std::vector<double> &ptCuts,
const std::vector<double> &etaCuts,
unsigned int nRequired )
const {
746 std::cout <<
"Signal PDG codes required: ";
747 for (
unsigned int k=0; k<
m_sigCodes.size(); ++k) std::cout << signalProcess[k] <<
" ";
748 if (signalProcess.size()==ptCuts.size()) {
749 std::cout <<
"Cuts on the pt of the signal states: " << std::endl;
750 for (
unsigned int l=0; l<ptCuts.size(); ++l) std::cout << ptCuts[l] <<
" ";
752 if (signalProcess.size()==etaCuts.size()) {
753 std::cout <<
"Cuts on the eta of the signal states: " << std::endl;
754 for (
unsigned int l=0; l<etaCuts.size(); ++l) std::cout << etaCuts[l] <<
" ";
756 std::cout <<
"Number of such decays required per event: " << nRequired << std::endl;
757 std::cout << std::endl;
Scalar eta() const
pseudorapidity method
#define CHECK(...)
Evaluate an expression and check for errors.
size_t size() const
Number of registered mappings.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
IntegerProperty m_randomSeed
Seed for random number engine.
std::shared_ptr< HepMC3::GenRunInfo > m_runinfo
The run info for HepMC3.
std::vector< long int > m_seeds
void printSignalSelections(const std::vector< int > &, const std::vector< double > &, const std::vector< double > &, unsigned int) const
std::vector< int > m_sigCodes
bool compare(std::vector< int >, std::vector< int >) const
static CLHEP::HepRandomEngine * p_rndmEngine
std::vector< int > m_internalEventNumbers
std::vector< double > m_sigPtCuts
unsigned int m_nSignalRequired
bool passesPTCuts(const std::vector< Pythia8::Particle > &) const
bool leptonSelect(Pythia8::Event &, const std::vector< double > &, double, const std::vector< int > &, int, double, bool)
Pythia8::SuppressSmallPT * m_SuppressSmallPT
virtual StatusCode callGenerator()
For calling the generator on each iteration of the event loop.
void descendThroughDecay(Pythia8::Event &, std::vector< Pythia8::Particle > &, int) const
bool passesEtaCuts(const std::vector< Pythia8::Particle > &) const
std::vector< Pythia8::Event > m_BEventBuffer
std::vector< int > getCodes(const std::vector< Pythia8::Particle > &) const
std::vector< int > m_bcodes
std::map< int, int > m_speciesCount
virtual StatusCode genFinalize()
For finalising the generator, if required.
std::vector< int > m_cutCount
bool signalAccept(Pythia8::Event &, const std::vector< int > &, unsigned int) const
virtual StatusCode genuserInitialize()
For initialization of user code, if required. Called after genInitialize.
bool cleanUndecayed(Pythia8::Event &, const std::vector< int > &)
unsigned int m_failureCount
std::vector< double > m_trigPtCut
bool userSelection(Pythia8::Event &, const std::string &, const std::vector< double > &)
virtual StatusCode fillEvt(HepMC::GenEvent *)
For filling the HepMC event object.
std::vector< double > m_userVar
bool pairProperties(Pythia8::Event &, const std::vector< int > &, double, bool)
virtual StatusCode genInitialize()
For initializing the generator, if required.
std::vector< double > m_sigEtaCuts
Pythia8B_i(const std::string &name, ISvcLocator *pSvcLocator)
int m_internal_event_number
virtual StatusCode genInitialize()
For initializing the generator, if required.
bool useRndmGenSvc() const
HepMC::Pythia8ToHepMC m_pythiaToHepMC
std::shared_ptr< customRndm > m_atlasRndmEngine
StringArrayProperty m_userHooks
std::unique_ptr< Pythia8::Pythia > m_pythia
UnsignedIntegerProperty m_maxFailures
BooleanProperty m_useRndmGenSvc
Pythia8_i(const std::string &name, ISvcLocator *pSvcLocator)
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 set_random_states(GenEvent *e, std::vector< long int > &a)
HepMC3::GenEvent GenEvent
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.