Rivet analyses
VBS Zy production at 13 TeV
Experiment: ATLAS (LHC)
Inspire ID: 2663725
Status: VALIDATED
Authors: - Qibin Liu - Gitanjali Poddar - Narei Lorenzo Martinez
References: - arXiv: 2305.19142 - Expt page: ATLAS-STDM-2018-36
Beams: p+ p+
Beam energies: (6500.0, 6500.0)GeV
Run details: - Electroweak Zy + 2jet production
This Letter presents the measurement of the fiducial and differential cross-sections of the electroweak production of a Zγ pair in association with two jets. The analysis uses 140 fb−1 of LHC proton-proton collision data taken at $\sqrt{s}=13$ TeV recorded by the ATLAS detector during the years 2015-2018. Events with a Z boson candidate decaying into either an e+e− or μ+μ− pair, a photon and two jets are selected. The electroweak component is extracted by requiring a large dijet invariant mass and a large rapidity gap between the two jets and is measured with an observed and expected significance well above five standard deviations. The fiducial pp → Zγjj cross-section for the electroweak production is measured to be 3.6 ± 0.5 fb. The total fiducial cross-section that also includes contributions where the jets arise from strong interactions is measured to be 16.8 + 2.0 − 1.8 fb. The results are consistent with the Standard Model predictions. Differential cross-sections are also measured using the same events and are compared with partoni-shower Monte Carlo simulations. Good agreement is observed between data and predictions.
Source
code:ATLAS_2023_I2663725.cc
// -*- C++ -*-
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Projections/FastJets.hh"
#include "Rivet/Projections/LeptonFinder.hh"
#include "Rivet/Projections/PromptFinalState.hh"
#include "Rivet/Projections/InvisibleFinalState.hh"
#include "Rivet/Projections/VetoedFinalState.hh"
namespace Rivet {
/// @brief VBS Zy production at 13 TeV
class ATLAS_2023_I2663725 : public Analysis {
public:
/// Constructor
RIVET_DEFAULT_ANALYSIS_CTOR(ATLAS_2023_I2663725);
/// @name Analysis methods
//@{
/// Book histograms and initialise projections before the run
void init() {
FinalState fs;
// Prompt photons
const PromptFinalState photon_fs(Cuts::abspid == PID::PHOTON && Cuts::pT > 25 * GeV && Cuts::abseta < 2.37);
declare(photon_fs, "Photons");
// Prompt leptons
const PromptFinalState bareelectron_fs = Cuts::abspid == PID::ELECTRON;
const PromptFinalState baremuon_fs = Cuts::abspid == PID::MUON;
// Dressed leptons
const FinalState allphoton_fs(Cuts::abspid == PID::PHOTON);
const Cut leptoncut = Cuts::pT > 20 * GeV && Cuts::abseta < 2.47;
// use *all* photons for dressing
const LeptonFinder dressedelectron_fs(bareelectron_fs, allphoton_fs, 0.1, leptoncut);
const LeptonFinder dressedmuon_fs(baremuon_fs, allphoton_fs, 0.1, leptoncut);
declare(dressedelectron_fs, "Electrons");
declare(dressedmuon_fs, "Muons");
// FS excluding the leading photon
VetoedFinalState vfs;
vfs.addVetoOnThisFinalState(photon_fs);
vfs.addVetoOnThisFinalState(dressedmuon_fs);
vfs.addVetoOnThisFinalState(InvisibleFinalState());
declare(vfs, "isolatedFS");
VetoedFinalState hadrons(FinalState(Cuts::abseta < 4.4));
hadrons.addVetoOnThisFinalState(dressedelectron_fs);
hadrons.addVetoOnThisFinalState(dressedmuon_fs);
// Jets
FastJets jets(hadrons, JetAlg::ANTIKT, 0.4, JetMuons::ALL, JetInvisibles::DECAY);
declare(jets, "jets");
// Histograms
size_t idx = 0;
const vector<string> dists{"pTlep1", "pTy", "pTjet1", "pTll", "pTlly", "mjj", "dRap", "dPhi", "cent"};
for (const string& reg : vector<string>{"", "_ext"}) {
for (const string& obs : dists) {
if (reg == "" && (obs == "pTll" || obs == "cent")) continue;
book(_h[obs+reg], ++idx, 1, 1);
}
}
}
/// Perform the per-event analysis
void analyze(const Event &event) {
// Sort the dressed leptons by pt
Particles electrons = apply<LeptonFinder>(event, "Electrons").particlesByPt();
Particles muons = apply<LeptonFinder>(event, "Muons").particlesByPt();
if (electrons.size() < 2 && muons.size() < 2) vetoEvent;
Particles lep;
if (electrons.size() >= 2) {
lep.push_back(electrons[0]);
lep.push_back(electrons[1]);
}
else if (muons.size() >= 2) {
lep.push_back(muons[0]);
lep.push_back(muons[1]);
}
if (lep.size() != 2) vetoEvent;
if (lep[0].pT() < 30*GeV) vetoEvent;
const double mll = (lep[0].momentum() + lep[1].momentum()).mass();
Particles photons = apply<PromptFinalState>(event, "Photons").particlesByPt();
if (photons.empty()) vetoEvent;
idiscardIfAnyDeltaRLess(photons, electrons, 0.4);
idiscardIfAnyDeltaRLess(photons, muons, 0.4);
Particles selectedPh;
Particles fs = apply<VetoedFinalState>(event, "isolatedFS").particles();
for (const Particle& ph : photons) {
// check photon isolation
double coneEnergy(0.0);
for (const Particle& p : fs) {
if (deltaR(ph, p) < 0.2) coneEnergy += p.Et(); // etcone20
}
if (coneEnergy / ph.pT() > 0.07) continue;
selectedPh += ph;
}
if (selectedPh.size() < 1) vetoEvent;
// Get jets
const Cut jetscut = (Cuts::pT > 25 * GeV && Cuts::absrap < 4.4);
Jets jetsMix = apply<FastJets>(event, "jets").jetsByPt(jetscut);
idiscardIfAnyDeltaRLess(jetsMix, photons, 0.4);
idiscardIfAnyDeltaRLess(jetsMix, electrons, 0.3);
idiscardIfAnyDeltaRLess(jetsMix, muons, 0.3);
// Jet multiplicity
const size_t njets = jetsMix.size();
if (njets < 2) vetoEvent;
if (jetsMix[1].pT() < 50*GeV) vetoEvent; // sorted by pT, must all > 50GeV
if (mll < 40*GeV) vetoEvent;
const FourMomentum lly_system = lep[0].momentum() + lep[1].momentum() + selectedPh[0].momentum();
const double mlly = lly_system.mass();
if (mll + mlly <= 182 * GeV) vetoEvent;
// other complex cuts
const FourMomentum jj_system = jetsMix[0].momentum() + jetsMix[1].momentum();
const double mjj = jj_system.mass();
if (mjj < 150*GeV) vetoEvent;
const double Dyjj = fabs(deltaRap(jetsMix[0].momentum(), jetsMix[1].momentum()));
if (Dyjj < 1) vetoEvent;
const double j1rap = jetsMix[0].rap();
const double j2rap = jetsMix[1].rap();
const double Centrality = fabs((lly_system.rap() - 0.5*(j1rap + j2rap)) / (j1rap - j2rap));
if (Centrality > 5) vetoEvent;
size_t njGap = 0;
for (size_t i=2; i < njets; ++i) {
const double jrap = jetsMix[i].rap();
if ((jrap < j1rap && jrap > j2rap) || (jrap < j2rap && jrap > j1rap)) ++njGap;
}
if (njGap > 0) vetoEvent;
// now start to log hist
// first we select the extended SR
if (Centrality > 0.4) vetoEvent;
_h["pTjet1_ext"]->fill(jetsMix[0].pT() / GeV);
_h["pTy_ext"]->fill(selectedPh[0].pT() / GeV);
_h["pTlep1_ext"]->fill(lep[0].pT() / GeV);
_h["pTll_ext"]->fill((lep[0].momentum() + lep[1].momentum()).pT() / GeV);
_h["pTlly_ext"]->fill(lly_system.pT() / GeV);
_h["cent_ext"]->fill(Centrality);
_h["dRap_ext"]->fill(Dyjj);
_h["mjj_ext"]->fill(mjj);
_h["dPhi_ext"]->fill(fabs(deltaPhi(lly_system, jj_system)));
// deal with EWK SR500
if (mjj < 450 * GeV) vetoEvent; // special since mjj in SR includes the underflow
_h["mjj"]->fill(mjj);
if (mjj < 500*GeV) vetoEvent;
_h["pTjet1"]->fill(jetsMix[0].pT() / GeV);
_h["pTy"]->fill(selectedPh[0].pT() / GeV);
_h["pTlep1"]->fill(lep[0].pT() / GeV);
_h["pTlly"]->fill(lly_system.pT() / GeV);
_h["dRap"]->fill(Dyjj);
_h["dPhi"]->fill(fabs(deltaPhi(lly_system, jj_system)));
}
/// Normalise histograms etc., after the run
void finalize() {
scale(_h, crossSection() / femtobarn / sumOfWeights());
}
private:
/// Histograms
map<string, Histo1DPtr> _h;
};
RIVET_DECLARE_PLUGIN(ATLAS_2023_I2663725);
}