main84
Back to index.
// main84.cc is a part of the PYTHIA event generator.
// Copyright (C) 2023 Torbjorn Sjostrand.
// PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
// Please respect the MCnet Guidelines, see GUIDELINES for details.
// Authors:
// Stefan Prestel
// Keywords:
// Merging
// Leading order
// CKKW‑L
// Hepmc
// It illustrates how to do CKKW-L merging, see the Matrix Element
// Merging page in the online manual. An example command is
// ./main84 main84.cmnd hepmcout84.dat 2 w+_production_lhc histout84.dat
// where main84.cmnd supplies the commands, hepmcout84.dat is the
// HepMC output, 2 is the maximial number of jets, w+_production_lhc
// provides the input LHE events, and histout84.dat is the output
// histogram file. This example requires FastJet and HepMC.
#include <time.h>
#include "Pythia8/Pythia.h"
#include "Pythia8Plugins/HepMC3.h"
using namespace Pythia8;
// Functions for histogramming
#include "fastjet/PseudoJet.hh"
#include "fastjet/ClusterSequence.hh"
#include "fastjet/CDFMidPointPlugin.hh"
#include "fastjet/CDFJetCluPlugin.hh"
//==========================================================================
// Find the Durham kT separation of the clustering from
// nJetMin --> nJetMin-1 jets in te input event
double pTfirstJet( const Event& event, int nJetMin, double Rparam) {
double yPartonMax = 4.;
// Fastjet analysis - select algorithm and parameters
fastjet::Strategy strategy = fastjet::Best;
fastjet::RecombinationScheme recombScheme = fastjet::E_scheme;
fastjet::JetDefinition *jetDef = NULL;
// For hadronic collision, use hadronic Durham kT measure
if(event[3].colType() != 0 || event[4].colType() != 0)
jetDef = new fastjet::JetDefinition(fastjet::kt_algorithm, Rparam,
recombScheme, strategy);
// For e+e- collision, use e+e- Durham kT measure
else
jetDef = new fastjet::JetDefinition(fastjet::ee_kt_algorithm,
recombScheme, strategy);
// Fastjet input
std::vector <fastjet::PseudoJet> fjInputs;
// Reset Fastjet input
fjInputs.resize(0);
// Loop over event record to decide what to pass to FastJet
for (int i = 0; i < event.size(); ++i) {
// (Final state && coloured+photons) only!
if ( !event[i].isFinal()
|| event[i].isLepton()
|| event[i].id() == 23
|| abs(event[i].id()) == 24
|| abs(event[i].y()) > yPartonMax)
continue;
// Store as input to Fastjet
fjInputs.push_back( fastjet::PseudoJet (event[i].px(),
event[i].py(), event[i].pz(),event[i].e() ) );
}
// Do nothing for empty input
if (int(fjInputs.size()) == 0) {
delete jetDef;
return 0.0;
}
// Run Fastjet algorithm
fastjet::ClusterSequence clustSeq(fjInputs, *jetDef);
// Extract kT of first clustering
double pTFirst = sqrt(clustSeq.exclusive_dmerge_max(nJetMin-1));
delete jetDef;
// Return kT
return pTFirst;
}
//==========================================================================
int main( int argc, char* argv[] ){
// Check that correct number of command-line arguments
if (argc != 6) {
cerr << " Unexpected number of command-line arguments. \n You are"
<< " expected to provide the arguments" << endl
<< " 1. Input file for settings" << endl
<< " 2. Name of output HepMC file" << endl
<< " 3. Maximal number of additional jets"
<< " (not used internally in Pythia, only used to construct the full"
<< " name of lhe files with additional jets, and to label output"
<< " histograms)" << endl
<< " 4. Full name of the input LHE file (with path"
<< " , without any _0.lhe suffix)" << endl
<< " 5. Path for output histogram files" << endl
<< " Program stopped. " << endl;
return 1;
}
Pythia pythia;
// First argument: Get input from an input file
pythia.readFile(argv[1]);
int nEvent = pythia.mode("Main:numberOfEvents");
// Deactivate AUX_ weight output
pythia.readString("Weights:suppressAUX = on");
// Interface for conversion from Pythia8::Event to HepMC event.
// Will fill cross section and event weight directly in this program,
// so switch it off for normal conversion routine.
HepMC3::Pythia8ToHepMC3 toHepMC;
toHepMC.set_store_xsec(false);
toHepMC.set_print_inconsistency(false);
toHepMC.set_free_parton_warnings(false);
// Specify file where HepMC events will be stored.
HepMC3::WriterAscii ascii_io(argv[2]);
// Third argument: Maximal number of additional jets
int njet = atoi(argv[3]);
// Read input and output paths
string iPath = string(argv[4]);
string oPath = string(argv[5]);
// To write correctly normalized events to hepmc file, first get
// a reasonable accurate of the cross section
int njetCounterEstimate = njet;
vector<double> xsecEstimate;
vector<double> nTrialEstimate;
vector<double> nAcceptEstimate;
pythia.readString("Random:setSeed = on");
pythia.readString("Random:seed = 42390964");
while(njetCounterEstimate >= 0) {
// Number of runs
int nRun = 1;
double nTrial = 0.;
double nAccept = 0.;
int countEvents = 0;
// Run pythia nRun times with the same lhe file to get nRun times
// higher statistics in the histograms
for(int n = 1; n <= nRun ; ++n ) {
// Get process and events from LHE file, initialize only the
// first time
if(n > 1) pythia.readString("Main:LHEFskipInit = on");
// From njet, choose LHE file
stringstream in;
in << "_" << njetCounterEstimate << ".lhe";
string LHEfile = iPath + in.str();
pythia.readString("HadronLevel:all = off");
// Read in ME configurations
pythia.readString("Beams:frameType = 4");
pythia.readString("Beams:LHEF = " + LHEfile);
pythia.init();
for( int iEvent=0; iEvent<nEvent; ++iEvent ){
countEvents++;
nTrial += 1.;
if(iEvent == 0) pythia.stat();
// Generate next event
if(pythia.next()) nAccept += 1.;
if(countEvents == nEvent*nRun-1){
xsecEstimate.push_back(pythia.info.sigmaGen());
nTrialEstimate.push_back(nTrial+1.);
nAcceptEstimate.push_back(nAccept+1.);
}
} // end loop over events to generate
} // end outer loop to rerun pythia with the same lhe file
// Restart with ME of a reduced the number of jets
if( njetCounterEstimate > 0 )
njetCounterEstimate--;
else
break;
} // end loop over different jet multiplicities
cout << endl << "Finished estimating cross section"
<< endl;
for(int i=0; i < int(xsecEstimate.size()); ++i)
cout << " Cross section estimate for " << njet-i << " jets :"
<< scientific << setprecision(8) << xsecEstimate[i]
<< endl;
for(int i=0; i < int(nTrialEstimate.size()); ++i)
cout << " Trial events for " << njet-i << " jets :"
<< scientific << setprecision(3) << nTrialEstimate[i]
<< " Accepted events for " << njet-i << " jets :"
<< scientific << setprecision(3) << nAcceptEstimate[i]
<< endl;
cout << endl;
// Now start merging procedure
int njetCounter = njet;
Hist histPTFirstSum("pT of first jet",100,0.,100.);
Hist histPTSecondSum("pT of second jet",100,0.,100.);
pythia.readString("Random:setSeed = on");
pythia.readString("Random:seed = 42390964");
// Sum of event weights
double sigma = 0.0;
double sigma2 = 0.0;
bool wroteRunInfo = false;
while(njetCounter >= 0) {
cout << " Path to lhe files: " << iPath << "_*" << endl;
cout << " Output written to: " << oPath << "'name'.dat" << endl;
// Set up histograms of pT of the first jet
Hist histPTFirst("pT of first jet",100,0.,200.);
Hist histPTSecond("pT of second jet",100,0.,200.);
Hist histPTThird("pT of third jet",100,0.,200.);
Hist histPTFourth("pT of fourth jet",50,0.,100.);
Hist histPTFifth("pT of fifth jet",30,0.,50.);
Hist histPTSixth("pT of sixth jet",30,0.,50.);
// Number of runs
int nRun = 1;
// Number of tried events
int nTriedEvents = 0;
// Number of accepted events
int nAccepEvents = 0;
// Run pythia nRun times with the same lhe file to get nRun times
// higher statistics in the histograms
for(int n = 1; n <= nRun ; ++n ) {
// Get process and events from LHE file, initialize only the
// first time
if(n > 1) pythia.readString("Main:LHEFskipInit = on");
// From njet, choose LHE file
stringstream in;
in << "_" << njetCounter << ".lhe";
string LHEfile = iPath + in.str();
cout << endl << endl
<< "\t LHE FILE FOR + " << njetCounter
<< " JET SAMPLE READ FROM " << LHEfile
<< endl << endl;
cout << "Normalise with xsection " << xsecEstimate[njet-njetCounter]
<< endl << endl;
pythia.readString("HadronLevel:all = on");
// Read in ME configurations
pythia.readString("Beams:frameType = 4");
pythia.readString("Beams:LHEF = " + LHEfile);
pythia.init();
for( int iEvent=0; iEvent<nEvent; ++iEvent ){
nTriedEvents++;
if(iEvent == 0) pythia.stat();
// Generate next event
if( pythia.next()) {
double evtweight = pythia.info.weight();
double weight = pythia.info.mergingWeight();
weight *= evtweight;
nAccepEvents++;
// Jet pT's
double D = 0.4;
double pTfirst = pTfirstJet(pythia.event,1, D);
double pTsecnd = pTfirstJet(pythia.event,2, D);
double pTthird = pTfirstJet(pythia.event,3, D);
double pTfourt = pTfirstJet(pythia.event,4, D);
double pTfifth = pTfirstJet(pythia.event,5, D);
double pTsixth = pTfirstJet(pythia.event,6, D);
histPTFirst.fill( pTfirst, weight);
histPTSecond.fill( pTsecnd, weight);
histPTThird.fill( pTthird, weight);
histPTFourth.fill( pTfourt, weight);
histPTFifth.fill( pTfifth, weight);
histPTSixth.fill( pTsixth, weight);
if(weight > 0.){
// Create a GenRunInfo object with the necessary weight
// names and write them to the HepMC3 file only once.
if (!wroteRunInfo) {
shared_ptr<HepMC3::GenRunInfo> genRunInfo;
genRunInfo = make_shared<HepMC3::GenRunInfo>();
vector<string> weight_names = pythia.info.weightNameVector();
genRunInfo->set_weight_names(weight_names);
ascii_io.set_run_info(genRunInfo);
ascii_io.write_run_info();
wroteRunInfo = true;
}
// Construct new empty HepMC event and fill it.
// Units will be as chosen for HepMC build, but can be changed
// by arguments, e.g. GenEvt( HepMC::Units::GEV, HepMC::Units::MM)
HepMC3::GenEvent hepmcevt;
double normhepmc = 1.* xsecEstimate[njet-njetCounter]
* nTrialEstimate[njet-njetCounter]
/ nAcceptEstimate[njet-njetCounter]
* 1./ (double(nRun)*double(nEvent));
sigma += weight*normhepmc;
sigma2 += pow(weight*normhepmc,2);
// Fill summed histograms
histPTFirstSum.fill( pTfirst, weight*normhepmc);
histPTSecondSum.fill( pTsecnd, weight*normhepmc);
// Fill HepMC event, with PDF info.
toHepMC.fill_next_event( pythia, &hepmcevt );
// Report cross section to hepmc.
shared_ptr<HepMC3::GenCrossSection> xsec;
xsec = make_shared<HepMC3::GenCrossSection>();
// First add object to event, then set cross section. This
// order ensures that the lengths of the cross section and
// the weight vector agree.
hepmcevt.set_cross_section( xsec );
xsec->set_cross_section( sigma*1e9, pythia.info.sigmaErr()*1e9 );
// Write the HepMC event to file.
ascii_io.write_event(hepmcevt);
}
} // if( pythia.next() )
if(nTriedEvents%10000 == 0)
cout << nTriedEvents << endl;
} // end loop over events to generate
// print cross section, errors
pythia.stat();
} // end outer loop to rerun pythia with the same lhe file
// Normalise histograms for this particular multiplicity
double norm = 1.
* pythia.info.sigmaGen()
* double(nTriedEvents)/double(nAccepEvents)
* 1./ (double(nRun)*double(nEvent));
histPTFirst *= norm;
histPTSecond *= norm;
histPTThird *= norm;
histPTFourth *= norm;
histPTFifth *= norm;
histPTSixth *= norm;
// Write histograms for this particular multiplicity to file
ofstream write;
stringstream suffix;
suffix << njet << "_" << njetCounter;
suffix << "_wv.dat";
write.open( (char*)(oPath + "PTjet1_" + suffix.str()).c_str());
histPTFirst.table(write);
write.close();
write.open( (char*)(oPath + "PTjet2_" + suffix.str()).c_str());
histPTSecond.table(write);
write.close();
write.open( (char*)(oPath + "PTjet3_" + suffix.str()).c_str());
histPTThird.table(write);
write.close();
write.open( (char*)(oPath + "PTjet4_" + suffix.str()).c_str());
histPTFourth.table(write);
write.close();
write.open( (char*)(oPath + "PTjet5_" + suffix.str()).c_str());
histPTFifth.table(write);
write.close();
write.open( (char*)(oPath + "PTjet6_" + suffix.str()).c_str());
histPTSixth.table(write);
write.close();
histPTFirst.null();
histPTSecond.null();
histPTThird.null();
histPTFourth.null();
histPTFifth.null();
histPTSixth.null();
// Restart with ME of a reduced the number of jets
if( njetCounter > 0 )
njetCounter--;
else
break;
} // end loop over different jet multiplicities
// Since the histograms have been filled with the correct weight for
// each jet multiplicity, no normalisation is needed.
// Write summed histograms to file.
ofstream writeSum;
stringstream suffixSum;
suffixSum << njet << "_wv.dat";
writeSum.open( (char*)(oPath + "PTjet1Sum_" + suffixSum.str()).c_str());
histPTFirstSum.table(writeSum);
writeSum.close();
writeSum.open( (char*)(oPath + "PTjet2Sum_" + suffixSum.str()).c_str());
histPTSecondSum.table(writeSum);
writeSum.close();
for(int i=0; i < int(xsecEstimate.size()); ++i)
cout << " Cross section estimate for " << njet-i << " jets :"
<< scientific << setprecision(8) << xsecEstimate[i]
<< endl;
for(int i=0; i < int(nTrialEstimate.size()); ++i)
cout << " Trial events for " << njet-i << " jets :"
<< scientific << setprecision(3) << nTrialEstimate[i]
<< " Accepted events for " << njet-i << " jets :"
<< scientific << setprecision(3) << nAcceptEstimate[i]
<< endl;
cout << endl;
cout << "Histogrammed cross section for "
<< iPath << " with " << njet << " additional jets is "
<< scientific << setprecision(8) << sigma
<< " error " << sqrt(sigma2) << endl;
return 0;
}