Rivet analyses
Monte Carlo validation observables for jet photoporudction
Experiment: ()
Status: VALIDATED
Authors: - Peter Meinzinger
References: none listed
Beams: p+ e-, e- p+, p+ e+, e+ p+
Beam energies: ANY
Run details: none listed
Analysing jet photoproduction with ET > 6~GeV.
Source
code:MC_PHOTOPRODUCTION.cc
// -*- C++ -*-
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Projections/FastJets.hh"
#include "Rivet/Projections/DISKinematics.hh"
#include "Rivet/Projections/ChargedFinalState.hh"
#include "Rivet/Projections/Sphericity.hh"
#include "Rivet/Projections/Spherocity.hh"
#include "Rivet/Projections/Thrust.hh"
#include "Rivet/Projections/FastJets.hh"
#include "Rivet/Projections/ParisiTensor.hh"
#include "Rivet/Projections/Hemispheres.hh"
namespace Rivet {
/// @brief Monte Carlo validation observables for jet photoporudction
class MC_PHOTOPRODUCTION : public Analysis {
public:
/// Constructor
RIVET_DEFAULT_ANALYSIS_CTOR(MC_PHOTOPRODUCTION);
/// @name Analysis methods
/// @{
/// Book histograms and initialise projections before the run
void init() {
// set CFS cuts from input options
_fideta = getOption<double>("ABSETAMAX", 4.0);
_fidpt = getOption<double>("PTMIN", 6.);
// set clustering radius from input option
const double R = getOption<double>("R", 1.0);
// set clustering algorithm from input option
JetAlg clusterAlgo;
const string algoopt = getOption("ALGO", "ANTIKT");
if ( algoopt == "KT" ) {
clusterAlgo = JetAlg::KT;
} else if ( algoopt == "CA" ) {
clusterAlgo = JetAlg::CA;
} else if ( algoopt == "ANTIKT" ) {
clusterAlgo = JetAlg::ANTIKT;
} else {
MSG_WARNING("Unknown jet clustering algorithm option " + algoopt + ". Defaulting to anti-kT");
clusterAlgo = JetAlg::ANTIKT;
}
// Initialise and register projections
const FinalState fs;
FastJets jetfs(fs, clusterAlgo, R);
declare(jetfs, "jets");
// For the multiplicity
const ChargedFinalState cfs;
declare(cfs, "CFS");
declare(Sphericity(fs, 1.), "Sphericity");
declare(Spherocity(fs), "Spherocity");
declare(ParisiTensor(fs), "Parisi");
const Thrust thrust(fs);
declare(thrust, "Thrust");
declare(Hemispheres(thrust), "Hemispheres");
declare(DISKinematics(), "Kinematics");
// Book histograms
// First: Standard photoproduction observables
book(_h["et"], "ET", 34, 6., 40.);
book(_h["eta"], "eta", 40, -2., 4.);
book(_h["x"], "x_y", 40, 0., 1.);
book(_h["mjj"], "m_jj", 40, 12., 140.);
book(_h["cosTheta"], "cosThetaStar", 40, 0., 1.);
// Second: jet-shape observables
book(_h["thrust"], "thrust", 35, 0.65, 1.);
book(_h["minor"], "minor", 35, 0., 0.7);
book(_h["C"], "Cparameter", 50, 0., 0.5);
book(_h["D"], "Dparameter", 50, 0., 0.06);
book(_h["rhoH"], "rhoH", 30, 0., 0.5);
book(_h["sphericity"], "sphericity", logspace(50, 3e-4, 0.3));
book(_h["transvSphericity"], "transvSphericity", 50, 0., 0.5);
book(_h["aplanarity"], "aplanarity", logspace(50, 1e-5, 0.01));
//book(_h["spherocity"], "spherocity", 50, 0., 1.);
book(_h["totalB"], "totalB", 30, 0., 0.15);
book(_h["wideB"], "wideB", 30, 0., 0.15);
book(_h["narrowB"], "narrowB", 30, 0., 0.05);
book(_h["y12"], "y12", logspace(50, 1e-6, 1.));
book(_h["y23"], "y23", logspace(50, 1e-6, 1.));
book(_h["y34"], "y34", logspace(50, 1e-6, 1.));
std::vector<double> mult_bins;
for (size_t i = 0; i < 25; ++i) { mult_bins.push_back(2.0*i-0.5); }
book(_h["mult"], "multiplicity", mult_bins);
book(_h["mult_fid"], "multiplicity_fiducial", mult_bins);
// Third: heavy-quark jet observables
double ptmin = 6., ptmax = 40.;
double etamin = -2., etamax = 4.;
double massmin = 12., massmax = 100.;
int nPTbins = 15, nEtaBins = 20, nMassBins = 20;
for (const string& suff : vector<string>{"c", "b", "tot"}) {
book(_h["pt_"+suff], "pt_"+suff, nPTbins, ptmin, ptmax);
book(_h["eta_"+suff], "eta_"+suff, nEtaBins, etamin, etamax);
book(_h["mjj_"+suff], "dijet_mass_"+suff, nMassBins, massmin, massmax);
book(_h["xgamma_"+suff], "xgamma_"+suff, 15, 0., 1.);
book(_e["pt_"+suff], "ratio_pt_"+suff, nPTbins, ptmin, ptmax);
book(_e["eta_"+suff], "ratio_eta_"+suff, nEtaBins, etamin, etamax);
book(_e["mjj_"+suff], "ratio_dijet_mass_"+suff, nMassBins, massmin, massmax);
if (suff == "tot"s) {
book(_h["pt_all"], "_all_pt", nPTbins, ptmin, ptmax);
book(_h["eta_all"], "_all_eta", nEtaBins, etamin, etamax);
book(_h["mjj_all"], "_all_dijet_mass", nMassBins, massmin, massmax);
}
}
}
/// Perform the per-event analysis
void analyze(const Event& event) {
const DISKinematics& kin = apply<DISKinematics>(event, "Kinematics");
const FinalState& cfs = apply<FinalState>(event, "CFS");
if ( kin.failed() ) vetoEvent;
const int orientation = kin.orientation();
// Q2 cut
if (kin.Q2() > 1*GeV2) vetoEvent;
// Jet selection
const Jets jets = apply<FastJets>(event, "jets").jets(Cuts::abseta< _fideta && Cuts::Et > _fidpt*GeV, cmpMomByEt);
if (jets.size() < 2) vetoEvent;
if (jets[0].Et() < 8*GeV) vetoEvent;
// ---------- Inclusive jet observables, eta and E_T ----------
for(const Jet& jet : jets) {
_h["et"]->fill(jet.Et()/GeV);
const double eta = orientation*jet.eta();
_h["eta"]->fill(eta);
}
double xyobs=0;
if (jets.size()>1) {
const Jet& j1 = jets[0];
const Jet& j2 = jets[1];
// Jet eta and cos(theta*) computation
const double eta1 = orientation*j1.eta(), eta2 = orientation*j2.eta();
const double costhetastar = tanh((eta1 - eta2)/2);
// Computation of x_y^obs
xyobs = (j1.Et() * exp(-eta1) + j2.Et() * exp(-eta2)) / (2*kin.y()*kin.beamLepton().E());
// Calculate the invariant mass
const double mjj = (j1.mom()+j2.mom()).mass();
_h["x"]->fill(xyobs);
_h["mjj"]->fill(mjj/GeV);
_h["cosTheta"]->fill(abs(costhetastar));
}
// ---------- Event Shapes ----------
// see arxiv:2301.01086 and arxiv:2007.12600 for definitions
vector<Vector3> momenta;
for (const Jet& jet : jets) {
Vector3 mom = jet.p3();
mom.setZ(0.);
momenta.push_back(mom);
}
// If only 2 particles, we need to use a ghost so that Thrust.calc() doesn't return 1.
if (momenta.size() == 2) {
momenta.push_back(Vector3(1e-10*MeV, 0., 0.));
}
// Transverse Thrust
Thrust thrust = apply<Thrust>(event, "Thrust");
thrust.calc(momenta);
_h["thrust"]->fill(thrust.thrust());
_h["minor"]->fill(thrust.thrustMajor());
// Sphericity
// as defined by ATLAS in arxiv:2007.12600; please note that the transverse sphericity in arxiv:2301.01086
// is defined without the additional factor 2
Sphericity sphericity = apply<Sphericity>(event, "Sphericity");
_h["sphericity"]->fill(sphericity.sphericity());
_h["aplanarity"]->fill(sphericity.aplanarity());
//Linearized sphericity calculation (2D)
momenta.clear();
for (const Jet& jet : jets) {
Vector3 mom = jet.p3();
mom.setZ(0.);
momenta.push_back(mom);
}
double a11 = 0.0; double a22 = 0.0;
double a12 = 0.0; double modSum2 = 0.0;
for (const Vector3& mom : momenta) {
modSum2 += mom.mod();
a11 += mom.x()*mom.x()/mom.mod();
a22 += mom.y()*mom.y()/mom.mod();
a12 += mom.x()*mom.y()/mom.mod();
}
double trc2 = (a11+a22)/modSum2;
double det2 = (a11*a22-a12*a12)/pow(modSum2,2);
double eigen21 = (trc2+sqrt(pow(trc2,2)-4*det2))/2;
double eigen22 = (trc2-sqrt(pow(trc2,2)-4*det2))/2;
double transSphericity = 2*eigen22/(eigen21+eigen22);
_h["transvSphericity"]->fill(transSphericity);
/*// Spherocity
// @todo check whether this is correctly defined for hadron-like collisions
// @todo check the why it always gives 0
const Spherocity& spherocity = apply<Spherocity>(event, "Spherocity");
_h["spherocity"]->fill(spherocity.spherocity());
*/
// C parameter
// as defined by ATLAS in arxiv:2007.12600
const ParisiTensor& parisi = apply<ParisiTensor>(event, "Parisi");
_h["C"]->fill(parisi.C());
_h["D"]->fill(parisi.D());
// Hemispheres
// @todo check whether this is correctly defined for hadron-like collisions
const Hemispheres& hemi = apply<Hemispheres>(event, "Hemispheres");
_h["rhoH"]->fill(hemi.scaledMhigh());
_h["wideB"]->fill(hemi.Bmax());
_h["narrowB"]->fill(hemi.Bmin());
_h["totalB"]->fill(hemi.Bsum());
// Jets
const FastJets& durjet = apply<FastJets>(event, "jets");
const double y12 = durjet.clusterSeq()->exclusive_ymerge_max(1);
_h["y12"]->fill(y12);
const double y23 = durjet.clusterSeq()->exclusive_ymerge_max(2);
_h["y23"]->fill(y23);
const double y34 = durjet.clusterSeq()->exclusive_ymerge_max(3);
_h["y34"]->fill(y34);
// charged particles
_h["mult"]->fill(cfs.particles().size());
_h["mult_fid"]->fill(cfs.particles(Cuts::abseta<4. && Cuts::pT > 230*MeV).size());
// ---------- Heavy Quarks ----------
// @todo check the number of tags, to make sure it's == 1?
if (jets[0].bTagged() || jets[0].cTagged()) {
string tag(jets[0].bTagged()?"b":"c");
_h["pt_tot"]->fill(jets[0].pt()/GeV);
_h["eta_tot"]->fill(orientation*jets[0].eta());
_h["pt_"+tag]->fill(jets[0].pt()/GeV);
_h["eta_"+tag]->fill(orientation*jets[0].eta());
if (jets.size()>1 && (jets[1].bTagged() || jets[1].cTagged())) {
string sub_tag(jets[1].bTagged()?"b":"c");
if (tag == sub_tag) {
const double heavy_mass = (jets[0].mom()+jets[1].mom()).mass();
_h["mjj_tot"]->fill(heavy_mass/GeV);
_h["mjj_"+tag]->fill(heavy_mass/GeV);
_h["xgamma_"+tag]->fill(xyobs);
_h["xgamma_tot"]->fill(xyobs);
}
}
}
_h["pt_all"]->fill(jets[0].pt()/GeV);
_h["eta_all"]->fill(orientation*jets[0].eta());
if (jets.size()>1) _h["mjj_all"]->fill((jets[0].mom()+jets[1].mom()).mass()/GeV);
}
/// Normalise histograms etc., after the run
void finalize() {
scale(_h, crossSection()/picobarn/sumOfWeights());
for (const string& var : vector<string>{"pt", "eta", "mjj"}) {
for (const string& suff : vector<string>{"c", "b", "tot"}) {
divide(_h[var+"_"+suff], _h[var+"_all"], _e[var+"_"+suff]);
}
}
}
/// @}
/// @name Histograms
/// @{
map<string,Histo1DPtr> _h;
map<string,Estimate1DPtr> _e;
/// @}
double _fideta, _fidpt;
};
RIVET_DECLARE_PLUGIN(MC_PHOTOPRODUCTION);
}