28 (
const std::string &
name, ISvcLocator *pSvcLocator):
Pythia8_i(
name,pSvcLocator) {
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;
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) {
294 std::vector<Pythia8::Event> repeatHadronizedEvents;
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();
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);
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;
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) {
520 int id = theParticle.idAbs();
521 if (
id == type_id ) {
522 double pt = theParticle.pT();
523 double eta = theParticle.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) {
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);
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();
652 std::sort(vect1.rbegin(), vect1.rend());
653 std::sort(vect2.rbegin(), vect2.rend());
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) {
694 unsigned int nRequired)
const {
696 bool acceptEvent(
false);
697 std::vector<int> parentsIndices;
698 for (
int i = 0;
i<theEvent.size(); ++
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);
713 std::vector<Pythia8::Particle> decayMembers;
715 std::vector<int> pdgCodes =
getCodes(decayMembers);
716 if (!
compare(requiredDecay,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");
760 void 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;