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) {
73 m_runinfo = std::make_shared<HepMC3::GenRunInfo>();
74 std::vector<std::string> names = {
"Default"};
75 m_runinfo->set_weight_names(names);
89 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.");
90 return StatusCode::FAILURE;
105 return StatusCode::FAILURE;
116 ATH_MSG_FATAL(
"Unable to retrieve HepRandomEngine. Bailing out.");
117 return StatusCode::FAILURE;
120 return StatusCode::SUCCESS;
142 for (std::vector<int>::iterator iit=
m_bcodes.begin(); iit!=
m_bcodes.end(); ++iit) {
146 return StatusCode::SUCCESS;
157 ATH_MSG_DEBUG(
"BEventBuffer not empty; skipping callGenerator");
158 return StatusCode::SUCCESS;
164 const EventContext& ctx = Gaudi::Hive::currentContext();
184 return StatusCode::FAILURE;
190 ATH_MSG_ERROR(
"Exceeded the max number of consecutive event failures.");
191 return StatusCode::FAILURE;
202 int nbBeforeSelection(0);
203 int nbbarBeforeSelection(0);
204 int ncBeforeSelection(0);
205 int ncbarBeforeSelection(0);
211 for (
int i = 0; i <
event.size(); ++i) {
212 stat =
event[i].statusAbs();
213 bool isBQuark(
false);
214 bool isCQuark(
false);
215 bool isAntiBQuark(
false);
216 bool isAntiCQuark(
false);
218 if (event[i].
id() == 5 && (stat == 62 || stat == 63)) {isBQuark=
true; ++nbBeforeSelection;}
219 if (event[i].
id() == 4 && (stat == 62 || stat == 63)) {isCQuark=
true; ++ncBeforeSelection;}
221 bool passesPtCut(
false);
bool passesEtaCut(
false);
222 std::string accString =
" : REJECTED";
223 double qpt =
event[i].pT();
double qeta = std::abs(event[i].
eta());
226 if (passesPtCut && passesEtaCut) {
227 if (isBQuark) ++nbQuark;
228 if (isCQuark) ++ncQuark;
229 accString =
" : ACCEPTED";
231 if (isBQuark)
ATH_MSG_DEBUG(
"bQuark pt/eta = " << qpt <<
"/" << qeta << accString);
232 if (isCQuark)
ATH_MSG_DEBUG(
"cQuark pt/eta = " << qpt <<
"/" << qeta << accString);
235 if (event[i].
id() == -5 && (stat == 62 || stat == 63)) {isAntiBQuark=
true; ++nbbarBeforeSelection;}
236 if (event[i].
id() == -4 && (stat == 62 || stat == 63)) {isAntiCQuark=
true; ++ncbarBeforeSelection;}
238 bool passesPtCut(
false);
bool passesEtaCut(
false);
239 std::string accString =
" : REJECTED";
240 double aqpt =
event[i].pT();
double aqeta = std::abs(event[i].
eta());
243 if (passesPtCut && passesEtaCut) {
244 if (isAntiBQuark) ++nbbarQuark;
245 if (isAntiCQuark) ++ncbarQuark;
246 accString =
" : ACCEPTED";
248 if (isAntiBQuark)
ATH_MSG_DEBUG(
"bbarQuark pt/eta = " << aqpt <<
"/" << aqeta << accString);
249 if (isAntiCQuark)
ATH_MSG_DEBUG(
"ccbarQuark pt/eta = " << aqpt <<
"/" << aqeta << accString);
252 if (nbBeforeSelection+nbbarBeforeSelection>=4 &&
m_vetoDoubleB) {
253 ATH_MSG_DEBUG(
"At user request, rejecting double b-bbar event; throwing dice again");
256 if (ncBeforeSelection+ncbarBeforeSelection>=4 &&
m_vetoDoubleC) {
257 ATH_MSG_DEBUG(
"At user request, rejecting double c-cbar event; throwing dice again");
260 bool rejectBBbar(
false);
261 bool rejectCCbar(
false);
268 ATH_MSG_DEBUG(
"No b- or c- quarks accepted; throwing the dice again");
272 ATH_MSG_DEBUG(
"No b-quarks accepted; throwing the dice again");
276 ATH_MSG_DEBUG(
"No c-quarks accepted; throwing the dice again");
286 bool doRepeatedDecays(
false);
if (
m_dec>1) doRepeatedDecays=
true;
287 if (doRepeatedDecays) {
293 Pythia8::Event eventCopy;
294 std::vector<Pythia8::Event> repeatHadronizedEvents;
295 std::vector<Pythia8::Event>::iterator eventItr;
298 for (
unsigned int iRepeat = 0; iRepeat <
m_had; ++iRepeat) {
301 if (iRepeat > 0)
event = eventCopy;
304 repeatHadronizedEvents.push_back(event);
308 std::vector<Pythia8::Event> savedEvents;
309 if (doRepeatedDecays) {
313 for (eventItr=repeatHadronizedEvents.begin(); eventItr!=repeatHadronizedEvents.end(); ++eventItr) {
314 for (
unsigned int iRepeat = 0; iRepeat <
m_dec; ++iRepeat) {
317 savedEvents.push_back(event);
321 if (!doRepeatedDecays) savedEvents = std::move(repeatHadronizedEvents);
326 std::vector<Pythia8::Event> finalEvents;
327 bool signalSelect(
false);
329 for (eventItr=savedEvents.begin(); eventItr!=savedEvents.end(); ++eventItr) {
342 finalEvents.push_back(*eventItr);
349 for (eventItr=finalEvents.begin(); eventItr!=finalEvents.end(); ++eventItr) {
350 for (
int i = 0; i < (*eventItr).size(); ++i) {
351 int id = (*eventItr)[i].id();
352 std::map<int,int>::iterator it;
367 StatusCode returnCode = StatusCode::SUCCESS;
378 ATH_MSG_DEBUG(
"BEventBuffer now empty - going to next Pythia event");
379 return StatusCode::SUCCESS;
393 if (!evt->run_info()) evt->set_run_info(m_runinfo);
394 evt->set_units(HepMC3::Units::MEV, HepMC3::Units::MM);
396 evt->weights().push_back(
m_pythia->info.weight());
413 return StatusCode::SUCCESS;
425 double xs = info.sigmaGen();
428 std::cout <<
"MetaData: cross-section (nb)= " << xs << std::endl;
430 std::cout <<
"Number of accepted b quarks = " <<
m_totalBQuark<< std::endl;
431 std::cout <<
"Number of accepted bbar quarks = " <<
m_totalBBarQuark<< std::endl;
432 std::cout <<
"Number of accepted c quarks = " <<
m_totalCQuark<< std::endl;
433 std::cout <<
"Number of accepted cbar quarks = " <<
m_totalCBarQuark<< std::endl;
434 std::cout <<
"Number of accepted b/c events before hadronization = " <<
m_totalHard<< std::endl;
435 std::cout <<
"Number of hadronization loops per b/c-event = " <<
m_had<< std::endl;
436 std::cout <<
"Total number of hadronization loops = " <<
m_totalClone<< std::endl;
437 std::cout <<
"Number of accepted b/c events yielding at least one finally accepted event = " <<
m_atLeastOneAcc<< std::endl;
441 std::cout <<
"Summary of cuts: " << std::endl;
443 if (
m_selectBQuarks) std::cout <<
"Quarks cuts apply to b-quarks" << std::endl;
444 if (
m_selectCQuarks) std::cout <<
"Quarks cuts apply to c-quarks" << std::endl;
445 std::cout <<
"Quark pt > " <<
m_qPtCut << std::endl;
446 std::cout <<
"Antiquark pt > " <<
m_aqPtCut << std::endl;
447 std::cout <<
"Quark eta < " <<
m_qEtaCut << std::endl;
448 std::cout <<
"Antiquark eta < " <<
m_aqEtaCut << std::endl;
449 if (
m_and) std::cout <<
"Require quark and anti-quark pass cuts" << std::endl;
451 std::cout <<
"Trigger lepton type = " <<
m_trigCode << std::endl;
452 std::cout <<
"Trigger lepton pt cuts: ";
453 for (
unsigned int prCntr=0; prCntr<
m_trigPtCut.size(); ++prCntr) {std::cout <<
m_trigPtCut[prCntr] <<
" ";}
454 std::cout << std::endl;
455 std::cout <<
"Trigger lepton eta cut: " <<
m_trigEtaCut << std::endl;
456 std::cout <<
"Required number of leptons passing each trigger cut = ";
457 for (
unsigned int prCntr=0; prCntr<
m_cutCount.size(); ++prCntr) {std::cout <<
m_cutCount[prCntr] <<
" ";}
458 std::cout << std::endl;
459 std::cout <<
"Invariant mass of trigger leptons > " <<
m_invMass << std::endl;
460 if (
m_oppCharges) std::cout <<
"Trigger leptons required to have opposite charges" << std::endl;
465 std::cout <<
"\nSpecies\tCount\n"<< std::endl;
468 std::cout << iter->first <<
'\t' << iter->second <<
'\n'<< std::endl;
470 if (
m_dec>1) std::cout <<
"Number of times each of these states were copied and decayed: " <<
m_dec << std::endl;
475 std::cout <<
" I===================================================================================== " << std::endl;
476 std::cout <<
" I CROSSSECTION OF YOUR B-CHANNEL IS I " << std::endl;
477 std::cout <<
" I BX= PX*NB/AC/MHAD= I " << finalXS <<
" nb" << std::endl;
478 std::cout <<
" I I " << std::endl;
479 std::cout <<
" I IN CASE YOU FORCED ANY DECAY YOU SHOULD I " << std::endl;
480 std::cout <<
" I CORRECT CROSS SECTION BX FURTHER, MULTIPLYING I " << std::endl;
481 std::cout <<
" I BX BY BRANCHING RATIO(S) OF YOUR FORCED I " << std::endl;
482 std::cout <<
" I DECAY(S) AND BY A FACTOR OF 2 FOR SYMMETRY I " << std::endl;
483 std::cout <<
" I I " << std::endl;
484 std::cout <<
" I MORE DETAILS ON CROSS SECTION I " << std::endl;
485 std::cout <<
" I PYTHIA CROSS SECTION IS PX= I " << xs <<
" nb" << std::endl;
486 std::cout <<
" I NUMBER OF ACCEPTED HARD EVENTS AC= I " <<
m_totalPythiaCalls << std::endl;
488 std::cout <<
" I REPEATED HADRONIZATIONS IN EACH EVENT MHAD= I " <<
m_had << std::endl;
489 std::cout <<
" I AVERAGE NUM OF ACCEPTED EVTS IN HADRONIZATION LOOP I " << cloningFactor << std::endl;
490 std::cout <<
" I IN CASE YOU FORCED ANY DECAY YOU SHOULD I " << std::endl;
491 std::cout <<
" I CORRECT CROSS SECTION BX FURTHER, MULTIPLYING I " << std::endl;
492 std::cout <<
" I BX BY BRANCHING RATIO(S) OF YOUR FORCED I " << std::endl;
493 std::cout <<
" I DECAY(S) AND BY A FACTOR OF 2 FOR SYMMETRY I " << std::endl;
494 std::cout <<
" I I " << std::endl;
495 std::cout <<
" I===================================================================================== " << std::endl;
496 std::cout <<
"" << std::endl;
497 std::cout <<
"MetaData: cross-section (nb)= " << finalXS << std::endl;
499 return StatusCode::SUCCESS;
508bool 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) {
510 if (type_id==0)
return true;
512 std::string accString(
" : REJECTED");
514 std::vector<int> leptonIDs;
515 int nCuts=ptCut.size();
516 std::vector<int> countGood(nCuts, 0);
518 for (
int i = 0; i<theEvent.size(); ++i) {
519 const Pythia8::Particle &theParticle = theEvent[i];
520 int id = theParticle.idAbs();
521 if (
id == type_id ) {
522 double pt = theParticle.pT();
523 double eta = theParticle.eta();
524 ATH_MSG_DEBUG(
"Lepton of type " <<
id <<
" with pt/eta " << pt <<
"/" <<
eta);
525 for (
int cutCntr=0; cutCntr<nCuts; ++cutCntr) {
526 if ( (pt>ptCut[cutCntr]) && (std::abs(
eta)<etaCut) ) {
527 countGood[cutCntr] += 1;
528 leptonIDs.push_back(i);
534 for (
int cutCntr=0; cutCntr<nCuts; ++cutCntr) {
535 if (countGood[cutCntr] >= counts[cutCntr]) ++nPassed;
537 if (nPassed==nCuts)
break;
542 for (
int cutCntr=0; cutCntr<nCuts; ++cutCntr) {
543 if (countGood[cutCntr] >= counts[cutCntr]) ++nPassed;
545 if (nPassed >= nCuts && nCuts==1) {accString=
" : ACCEPTED";
passed =
true;}
546 if (nPassed >= nCuts && nCuts>1 &&
pairProperties(theEvent,leptonIDs,massCut,opposite)) {accString=
" : ACCEPTED";
passed =
true;}
556 bool cleanEvent(
true);
557 std::string accString(
" : ACCEPTED");
558 for (
int i = 0; i<theEvent.size(); ++i) {
559 const Pythia8::Particle &theParticle = theEvent[i];
560 int id = theParticle.id();
561 int status = theParticle.status();
562 for (
auto iItr = bCodes.begin(); iItr!=bCodes.end(); ++iItr) {
563 if ( (
id == *iItr) && (status>0) ) {accString=
" : REJECTED"; cleanEvent =
false;}
566 ATH_MSG_DEBUG(
"Check event for undecayed signal particles" << accString);
580 bool passesCuts(
false);
581 std::string accString(
" : REJECTED");
582 for (
auto iit = leptonIDs.begin(); iit!=leptonIDs.end(); ++iit) {
583 for (
auto iit2 = iit+1; iit2!=leptonIDs.end(); ++iit2) {
584 int q1=theEvent[*iit].charge();
585 int q2=theEvent[*iit2].charge();
586 if (opposite && (q1*q2>0))
continue;
587 double px1=theEvent[*iit].px();
588 double py1=theEvent[*iit].py();
589 double pz1=theEvent[*iit].pz();
590 double mass1=theEvent[*iit].mSel();
591 double e1=std::sqrt(px1*px1+py1*py1+pz1*pz1+mass1*mass1);
592 double px2=theEvent[*iit2].px();
593 double py2=theEvent[*iit2].py();
594 double pz2=theEvent[*iit2].pz();
595 double mass2=theEvent[*iit2].mSel();
596 double e2=std::sqrt(px2*px2+py2*py2+pz2*pz2+mass2*mass2);
598 double pxSum=px1+px2;
599 double pySum=py1+py2;
600 double pzSum=pz1+pz2;
601 double M=std::sqrt(eSum*eSum-pxSum*pxSum-pySum*pySum-pzSum*pzSum);
604 ATH_MSG_DEBUG(
"Acceptable lepton pair with invariant mass : " << M);
608 if (passesCuts) {accString=
" : ACCEPTED";
break;}
619 list.push_back(theEvent[i]);
620 std::vector<int> childrenIndices = theEvent.daughterList(i);
621 std::vector<int>::iterator iItr;
622 for (iItr = childrenIndices.begin(); iItr != childrenIndices.end(); ++iItr) {
634 std::vector<int> codes;
635 codes.reserve(theParticles.size());
636 for (
auto pItr = theParticles.begin(); pItr!=theParticles.end(); ++pItr ) {
637 codes.push_back( (*pItr).id() );
648 if (vect1.size()!=vect2.size())
return false;
650 bool isTheSame(
true);
651 int size = vect1.size();
654 for (
int i=0; i<size; ++i) {
655 if (vect1[i] != vect2[i]) {isTheSame =
false;
break;}
669 for (
auto pItr=theParticles.cbegin(); pItr!=theParticles.cend(); ++pItr,++i) {
681 for (
auto pItr=theParticles.cbegin(); pItr!=theParticles.cend(); ++pItr,++i) {
682 if (std::abs((*pItr).eta()) >
m_sigEtaCuts[i]) pass =
false;
694 unsigned int nRequired)
const {
696 bool acceptEvent(
false);
697 std::vector<int> parentsIndices;
698 for (
int i = 0; i<theEvent.size(); ++i) {
699 const Pythia8::Particle &theParticle = theEvent[i];
700 int id = theParticle.id();
701 if (
id==requiredDecay[0]) parentsIndices.push_back(i);
706 if ( (requiredDecay.size()==1) && (parentsIndices.size()>0) ) {
711 unsigned int goodDecayCounter(0);
712 for (std::vector<int>::iterator iItr = parentsIndices.begin(); iItr!=parentsIndices.end(); ++iItr) {
713 std::vector<Pythia8::Particle> decayMembers;
715 std::vector<int> pdgCodes =
getCodes(decayMembers);
716 if (!
compare(requiredDecay,std::move(pdgCodes))) {
717 ATH_MSG_DEBUG(
"Signal event REJECTED as does not contain required decay chain");
724 ATH_MSG_DEBUG(
"Signal event REJECTED as signal chain does not pass pt cuts");
731 ATH_MSG_DEBUG(
"Signal event REJECTED as signal chain does not pass eta cuts");
740 else {++goodDecayCounter;}
743 if (goodDecayCounter>=nRequired) {
744 ATH_MSG_DEBUG(nRequired <<
"signal decays required; " << goodDecayCounter <<
" found; event ACCEPTED");
747 else if (goodDecayCounter<nRequired) {
748 ATH_MSG_DEBUG(nRequired <<
"signal decays required; " << goodDecayCounter <<
" found; event REJECTED");
760void Pythia8B_i::printSignalSelections(
const std::vector<int> &signalProcess,
const std::vector<double> &ptCuts,
const std::vector<double> &etaCuts,
unsigned int nRequired )
const {
761 std::cout <<
"Signal PDG codes required: ";
762 for (
unsigned int k=0; k<
m_sigCodes.size(); ++k) std::cout << signalProcess[k] <<
" ";
763 if (signalProcess.size()==ptCuts.size()) {
764 std::cout <<
"Cuts on the pt of the signal states: " << std::endl;
765 for (
unsigned int l=0; l<ptCuts.size(); ++l) std::cout << ptCuts[l] <<
" ";
767 if (signalProcess.size()==etaCuts.size()) {
768 std::cout <<
"Cuts on the eta of the signal states: " << std::endl;
769 for (
unsigned int l=0; l<etaCuts.size(); ++l) std::cout << etaCuts[l] <<
" ";
771 std::cout <<
"Number of such decays required per event: " << nRequired << std::endl;
772 std::cout << std::endl;
Scalar eta() const
pseudorapidity method
#define CHECK(...)
Evaluate an expression and check for errors.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
const HepPDT::ParticleData * particleData(int pid) const
Access an element in the particle data table.
IntegerProperty m_randomSeed
Seed for random number engine.
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
virtual StatusCode fillEvt(HepMC::GenEvent *)
For filling the HepMC event object.
bool userSelection(Pythia8::Event &, std::string, std::vector< double >)
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< T > a)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.