Rivet analyses
Dilepton mass spectrum in 13 TeV pp collisions with 139/fb Run 2 dataset
Experiment: ATLAS (LHC)
Inspire ID: 1725190
Status: VALIDATED SINGLEWEIGHT NOREENTRY
Authors: - Andy Buckley
References: - Expt page: ATLAS-EXOT-2018-08 - Phys.Lett. B796 (2019) 68-87 - DOI:10.1016/j.physletb.2019.07.016 - arXiv: 1903.06248
Beams: p+ p+
Beam energies: (6500.0, 6500.0)GeV
Run details: - Dilepton events, either full process, BSM signal-only, or signal + SM interference.
A search for high-mass dielectron and dimuon resonances in the mass range of 250 GeV to 6 TeV. Functional forms have been fitted to the components of Crystal Ball + Gaussian dilepton invariant-mass distribution smearing functions for electrons and muons separately, which are encoded in this analysis to allow particle-level MC to be compared to the reco-level experimental data.
Source
code:ATLAS_2019_I1725190.cc
// -*- C++ -*-
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Projections/ChargedFinalState.hh"
#include "Rivet/Projections/PromptFinalState.hh"
#include "Rivet/Projections/FastJets.hh"
#include "Rivet/Projections/Smearing.hh"
#include "Rivet/Tools/Random.hh"
namespace Rivet {
/// @brief Dilepton high-mass resonance search
///
/// @todo Use the proper smearing system rather than hand-rolled sampling
class ATLAS_2019_I1725190 : public Analysis {
public:
/// Constructor
RIVET_DEFAULT_ANALYSIS_CTOR(ATLAS_2019_I1725190);
/// @name Analysis methods
/// @{
/// Book histograms and initialise projections before the run
void init() {
PromptFinalState electrons(Cuts::abspid == PID::ELECTRON && Cuts::Et > 30*GeV &&
(Cuts::abseta < 2.47 && !Cuts::absetaIn(1.37, 1.52)));
SmearedParticles recoelectrons(electrons, PARTICLE_EFF_ONE); //ELECTRON_EFF_ATLAS_RUN2_MEDIUM);
declare(recoelectrons, "Elecs");
PromptFinalState muons(Cuts::abspid == PID::MUON && Cuts::pT > 30*GeV && Cuts::abseta < 2.5);
SmearedParticles recomuons(muons, PARTICLE_EFF_ONE);
// [](const Particle& m) -> double {
// if (m.pT() < 1*TeV) return 0.69;
// if (m.pT() > 2.5*TeV) return 0.57;
// return 0.69 - 0.12*(m.pT() - 1*TeV)/(2.5*TeV - 1*TeV);
// });
declare(recomuons, "Muons");
// Book histograms
book(_h_mee, 1, 1, 1);
book(_h_mmm, 2, 1, 1);
}
/// Perform the per-event analysis
void analyze(const Event& event) {
// Get leptons
const Particles elecs = apply<ParticleFinder>(event, "Elecs").particlesByPt();
const Particles muons = apply<ParticleFinder>(event, "Muons").particlesByPt();
// MSG_INFO("Num e, mu = " << elecs.size() << ", " << muons.size());
// for (const Particle& e : elecs) MSG_INFO(e.mom());
// for (const Particle& m : muons) MSG_INFO(m.mom());
// Isolation
/// @todo Can't be done from provided information?
// Particles isoelecs, isomuons;
// for (const Particle& e : elecs) {
// }
// Choose the highest-pT lepton pair, preferring electrons
if (elecs.size() < 2 && muons.size() < 2) vetoEvent;
const Particle l1 = (elecs.size() >= 2) ? elecs[0] : muons[0];
const Particle l2 = (elecs.size() >= 2) ? elecs[1] : muons[1];
// Require opposite sign for muons only
const bool mumu = (l1.abspid() == PID::MUON);
if (mumu && l1.pid()*l2.pid() > 0) vetoEvent;
// Get the true dilepton pair
const FourMomentum pll = l1.mom() + l2.mom();
const double mll = pll.mass();
// Make sure we're in a region where the smearing and efficiencies are well-behaved
if (mll < 200*GeV) vetoEvent;
// Apply dilepton efficiency curves (as function of mX ~ mll)
const double eff = mumu ?
(0.54 - (mll - 200*GeV)/(6000*GeV - 200*GeV) * (0.54 - 0.38)) :
(0.74 - 0.04*exp(-(mll-200*GeV)/100*GeV) - 0.08*exp(-(mll-200*GeV)/1000*GeV));
if (rand01() > eff) vetoEvent;
// Smear the dilepton mass with a CB + Gauss function
double muCB, sigCB, alpCB, nCB, muG, sigG, kappa;
if (!mumu) {
const double lnm = log(mll);
static const vector<double> pmuCB = {0.13287, -0.410663, -0.0126743, 2.9547e-6};
muCB = pmuCB[0] + pmuCB[1]/lnm + pmuCB[2]*lnm + pmuCB[3]*pow(lnm, 4);
static const vector<double> psigCB = {0.0136624, 0.230678, 1.73254};
sigCB = sqrt(pow(psigCB[0],2) + pow(psigCB[1],2)/mll + pow(psigCB[2]/mll, 2));
alpCB = 1.59112;
static const vector<double> pnCB = {1.13055, 0.76705, 0.00298312};
nCB = pnCB[0] + pnCB[1]*exp(-pnCB[2]*mll);
static const vector<double> pmuG = {-0.00402708, 0.814172, -3.94281e-7, 7.97076e-6, -87.6397, -1.64806e-11};
muG = pmuG[0] + pmuG[1]/mll + pmuG[2]*mll + pmuG[3]*pow(lnm,3) + pmuG[4]/sqr(mll) + pmuG[5]*sqr(mll);
static const vector<double> psigG = {0.00553858, 0.140909, 0.644418};
sigG = sqrt(sqr(psigG[0]) + sqr(psigG[1])/mll + sqr(psigG[2]/mll));
static const vector<double> pkappa = {0.347003, 0.135768, 0.00372497, -2.2822e-5, 5.06351e-13};
kappa = pkappa[0] + pkappa[1]*exp(-pkappa[2]*mll) + pkappa[3]*mll + pkappa[4]*pow(mll,3);
} else {
static const vector<double> pmuCB = {-0.0891397, 10.6169, -951.712, 74775.3, 5.60192e-5, -1.58827e-9, -3.81706e-13};
muCB = pmuCB[0] + pmuCB[1]/mll + pmuCB[2]/sqr(mll) + pmuCB[3]/pow(mll,3) + pmuCB[4]*mll + pmuCB[5]*sqr(mll) + pmuCB[6]*pow(mll,3);
static const vector<double> psigCB = {0.0836349, -8.98476, 491.19, 5.18068e-5, -3.45042e-10};
sigCB = psigCB[0] + psigCB[1]/mll + psigCB[2]/sqr(mll) + psigCB[3]*mll + psigCB[4]*sqr(mll);
static const vector<double> palpCB = {0.512577, 252.922, -79337.4, 7.31863e6, 0.000237883};
alpCB = palpCB[0] + palpCB[1]/mll + palpCB[2]/sqr(mll) + palpCB[3]/pow(mll,3) + palpCB[4]*mll;
static const vector<double> pnCB = {1.13055, 0.76705, 0.00298312};
nCB = 6.08818;
static const vector<double> pmuG = {-0.00410659, 2.82352e-6, -6.264e-9, 1.25547e-12, -9.94431e-17};
muG = pmuG[0] + pmuG[1]*mll + pmuG[2]*sqr(mll) + pmuG[3]*pow(mll,3) + pmuG[4]*pow(mll,4);
static const vector<double> psigG = {0.0214264, -0.795058, 15.4726, 3.38205e-5, -1.64984e-9};
sigG = psigG[0] + psigG[1]/mll + psigG[2]/sqr(mll) + psigG[3]*mll + psigG[4]*sqr(mll);
static const vector<double> pkappa = {0.235477, -31.2227, 3447.34, 4.54408e-5, -3.25374e-9};
kappa = pkappa[0] + pkappa[1]/mll + pkappa[2]/sqr(mll) + pkappa[3]*mll + pkappa[4]*sqr(mll);
}
// Do the smearing
double mll_scale = -1;
do {
mll_scale = (rand01() > kappa) ? randnorm(muG, sigG) : randcrystalball(alpCB, nCB, muCB, sigCB);
} while (fabs(mll_scale) > 0.5);
const double mll_reco = (1 + mll_scale) * mll;
// Require high-Mll to avoid the Z peak
if (mll_reco < 225*GeV) vetoEvent;
// Fill Mll histograms
(mumu ? _h_mmm : _h_mee)->fill(mll_reco/GeV);
}
/// Normalise histograms etc., after the run.
// The plot is expressed as number of events in a 10 GeV bin.
// Multiply by luminosity*cross section (in same units!) to get number
// of events a 1 GeV bin, then by 10 to get number of events in a 10 GeV.
void finalize() {
scale(_h_mee, 10.*crossSection()/picobarn*luminosity()/sumOfWeights());
scale(_h_mmm, 10.*crossSection()/picobarn*luminosity()/sumOfWeights());
}
/// @}
/// @name Histograms
/// @{
Histo1DPtr _h_mee, _h_mmm;
/// @}
};
RIVET_DECLARE_PLUGIN(ATLAS_2019_I1725190);
}