Rivet analyses referenceCMS_2022_I2079374Measurement of the mass dependence of the transverse momentum of lepton pairs in Drell--Yan production in proton-proton collisions at 13 TeVExperiment: CMS (LHC) Inspire ID: 2079374 Status: VALIDATED Authors:
Beam energies: (6500.0, 6500.0) GeV Run details:
The double differential cross sections of the Drell-Yan lepton pair ($\ell^+\ell^-$, dielectron or dimuon) production are measured, as functions of the invariant mass $m_{\ell\ell}$, transverse momentum $p_T^{\ell\ell}$, and $\varphi^*_\eta$. The $\varphi^*_\eta$ observable, derived from angular measurements of the leptons and highly correlated with $p_T^{\ell\ell}$, is used to probe the low-$p_T^{\ell\ell}$ region in a complementary way. Dilepton masses up to 1 TeV are investigated. Additionally, a measurement is performed requiring at least one jet in the final state. To benefit from partial cancellation of the systematic uncertainty, the ratios of the differential cross sections for various $m_{\ell\ell}$ ranges to those in the Z mass peak interval are presented. The collected data correspond to an integrated luminosity of 36.3 fb$^{-1}$ of proton-proton collisions recorded with the CMS detector at the LHC at a centre-of-mass energy of 13 TeV. Measurements are compared with predictions based on perturbative quantum chromodynamics, including soft-gluon resummation. Source code: CMS_2022_I2079374.cc 1// -*- C++ -*-
2#include "Rivet/Analysis.hh"
3#include "Rivet/Projections/FastJets.hh"
4#include "Rivet/Projections/VisibleFinalState.hh"
5#include "Rivet/Projections/FinalState.hh"
6#include "Rivet/Projections/LeptonFinder.hh"
7#include "Rivet/Projections/PromptFinalState.hh"
8
9namespace Rivet {
10
11
12 /// @brief Z pT over a wide mass range
13 class CMS_2022_I2079374 : public Analysis {
14 public:
15
16 /// Constructor
17 RIVET_DEFAULT_ANALYSIS_CTOR(CMS_2022_I2079374);
18
19 /// Book histograms and initialise projections before the run
20 void init() {
21 // Get options from the new option system
22 // default to combined.
23 _mode = 2;
24 if (getOption("LMODE") == "EL") {
25 _mode = 0;
26 } else if (getOption("LMODE") == "MU") {
27 _mode = 1;
28 } else if (getOption("LMODE") == "EMU") {
29 _mode = 2;
30 } else {
31 MSG_INFO("Assuming a mixed electron/muon sample. Set LMODE=EL/MU if your sample contains a single flavor.");
32 }
33
34 FinalState fs;
35 PromptFinalState pfs(fs);
36 PromptFinalState bareMuons(Cuts::abspid == PID::MUON);
37 declare(LeptonFinder(bareMuons, pfs, 0.1, Cuts::abseta < 2.4 && Cuts::pT > 20*GeV), "muons");
38
39 PromptFinalState bareElectrons(Cuts::abspid == PID::ELECTRON);
40 declare(LeptonFinder(bareElectrons, pfs, 0.1, Cuts::abseta < 2.4 && Cuts::pT > 20*GeV), "electrons");
41
42 FastJets jets(fs, JetAlg::ANTIKT, 0.4);
43 declare(jets, "jets");
44
45 // Histograms
46 book(_pt_0jet_mass50_76, 1, 1, 1);
47 book(_pt_0jet_mass76_106, 3, 1, 1);
48 book(_pt_0jet_mass106_170, 5, 1, 1);
49 book(_pt_0jet_mass170_350, 7, 1, 1);
50 book(_pt_0jet_mass350_1000, 9, 1, 1);
51
52 book(_pt_1jet_mass50_76, 11, 1, 1);
53 book(_pt_1jet_mass76_106, 13, 1, 1);
54 book(_pt_1jet_mass106_170, 15, 1, 1);
55 book(_pt_1jet_mass170_350, 17, 1, 1);
56
57 book(_phistar_mass50_76, 19, 1, 1);
58 book(_phistar_mass76_106, 21, 1, 1);
59 book(_phistar_mass106_170, 23, 1, 1);
60 book(_phistar_mass170_350, 25, 1, 1);
61 book(_phistar_mass350_1000, 27, 1, 1);
62
63 }
64
65 /// Z boson finder.
66 /// Note: we don't use the standard DileptonFinder class in order to stick to
67 /// the definition of the publication that is simpler than the DileptonFinder
68 /// algorithm
69 /// @param leptons pt-ordered of electron or muon collection to use to build
70 /// the Z boson
71 std::unique_ptr<Particle> zfinder(const DressedLeptons &leptons)
72 {
73 if (leptons.size() < 2) {
74 return nullptr;
75 }
76 // Leading lepton pT cut
77 if (leptons[0].pT() < 25.*GeV) {
78 return nullptr;
79 }
80 if (leptons[0].charge() * leptons[1].charge() > 0) {
81 return nullptr;
82 }
83
84 std::unique_ptr<Particle> candidate(new Particle(PID::ZBOSON, leptons[0].mom() + leptons[1].mom()));
85 if (candidate->mass() < 50*GeV || candidate->mass() > 1000*GeV) {
86 return nullptr;
87 }
88 return candidate;
89 }
90
91 /// Perform the per-event analysis
92 void analyze(const Event& event)
93 {
94 // Fetch dressed leptons
95 auto muons = apply<LeptonFinder>(event, "muons").dressedLeptons();
96 auto electrons = apply<LeptonFinder>(event, "electrons").dressedLeptons();
97
98 const DressedLeptons* dressedLeptons = nullptr;
99
100 //Look for Z->ee
101 std::unique_ptr<Particle> z = zfinder(electrons);
102 if (z != nullptr) {
103 dressedLeptons = &electrons;
104 if (_mode == 1) {
105 // Z->ee found, but running with LMODE=MU
106 vetoEvent;
107 }
108 } else if (_mode == 0) {
109 // LMODE=EL, but no Z->ee found
110 vetoEvent;
111 } else { //look for Z->mumu
112 z = zfinder(muons);
113 if (z.get() != nullptr) {
114 dressedLeptons = &muons;
115 } else { //no Z boson found
116 vetoEvent;
117 }
118 }
119
120 // Cluster jets
121 Jets jets = apply<FastJets>(event, "jets").jetsByPt(Cuts::absrap < 2.4 && Cuts::pT > 30*GeV);
122 idiscardIfAnyDeltaRLess(jets, *dressedLeptons, 0.4);
123
124 //------------------------------------------------
125
126 // Compute phi*
127 const Particle& lminus = dressedLeptons->at(0).charge() < 0 ? dressedLeptons->at(0) : dressedLeptons->at(1);
128 const Particle& lplus = dressedLeptons->at(0).charge() < 0 ? dressedLeptons->at(1) : dressedLeptons->at(0);
129 double phi_acop = M_PI - deltaPhi(lminus, lplus);
130 double costhetastar = tanh( 0.5 * (lminus.eta() - lplus.eta()) );
131 double sin2thetastar = (costhetastar > 1) ? 0.0 : (1.0 - sqr(costhetastar));
132 double phistar = tan(0.5 * phi_acop) * sqrt(sin2thetastar);
133
134 if (z->mass() > 50. && z->mass() < 76.) {
135 _pt_0jet_mass50_76->fill(z->pT());
136 _phistar_mass50_76->fill(phistar);
137 } else if (z->mass() > 76. && z->mass() < 106.) {
138 _pt_0jet_mass76_106->fill(z->pT());
139 _phistar_mass76_106->fill(phistar);
140 } else if (z->mass() > 106. && z->mass() < 170.) {
141 _pt_0jet_mass106_170->fill(z->pT());
142 _phistar_mass106_170->fill(phistar);
143 } else if (z->mass() > 170. && z->mass() < 350.) {
144 _pt_0jet_mass170_350->fill(z->pT());
145 _phistar_mass170_350->fill(phistar);
146 } else if (z->mass() > 350. && z->mass() < 1000.) {
147 _pt_0jet_mass350_1000->fill(z->pT());
148 _phistar_mass350_1000->fill(phistar);
149 }
150
151 //---------------------- at least one jet --------------------------------
152 if (jets.size() < 1) {
153 return;
154 }
155
156 if (z->mass() > 50. && z->mass() < 76.) {
157 _pt_1jet_mass50_76->fill(z->pT());
158 } else if (z->mass() > 76. && z->mass() < 106.) {
159 _pt_1jet_mass76_106->fill(z->pT());
160 } else if (z->mass() > 106. && z->mass() < 170.) {
161 _pt_1jet_mass106_170->fill(z->pT());
162 } else if (z->mass() > 170. && z->mass() < 350.) {
163 _pt_1jet_mass170_350->fill(z->pT());
164 }
165 }
166
167 /// Calculates the ratio between two histograms
168 void calculateRatio(int d, const Histo1DPtr &numerator, const Histo1DPtr &denominator) {
169 Estimate1DPtr ratio;
170 book(ratio, d, 1, 1);
171
172 // The denominator has a finer binning, so rebin it
173 auto rebinned_den = denominator->clone();
174 rebinned_den.rebinX(numerator->xEdges());
175
176 divide(*numerator, rebinned_den, ratio);
177 }
178
179 /// Normalise histograms etc., after the run
180 void finalize() {
181 double norm = (sumOfWeights() != 0) ? crossSection()/picobarn/sumOfWeights() : 1.0;
182
183 if (_mode == 2) {
184 norm /= 2.;
185 }
186
187 scale(_pt_0jet_mass50_76, norm);
188 scale(_pt_0jet_mass76_106, norm);
189 scale(_pt_0jet_mass106_170, norm);
190 scale(_pt_0jet_mass170_350, norm);
191 scale(_pt_0jet_mass350_1000, norm);
192
193 scale(_pt_1jet_mass50_76, norm);
194 scale(_pt_1jet_mass76_106, norm);
195 scale(_pt_1jet_mass106_170, norm);
196 scale(_pt_1jet_mass170_350, norm);
197
198 scale(_phistar_mass50_76, norm);
199 scale(_phistar_mass76_106, norm);
200 scale(_phistar_mass106_170, norm);
201 scale(_phistar_mass170_350, norm);
202 scale(_phistar_mass350_1000, norm);
203
204 // Calculate the ratios
205 calculateRatio(29, _pt_0jet_mass50_76, _pt_0jet_mass76_106);
206 calculateRatio(31, _pt_0jet_mass106_170, _pt_0jet_mass76_106);
207 calculateRatio(33, _pt_0jet_mass170_350, _pt_0jet_mass76_106);
208 calculateRatio(35, _pt_0jet_mass350_1000, _pt_0jet_mass76_106);
209
210 calculateRatio(37, _pt_1jet_mass50_76, _pt_1jet_mass76_106);
211 calculateRatio(39, _pt_1jet_mass106_170, _pt_1jet_mass76_106);
212 calculateRatio(41, _pt_1jet_mass170_350, _pt_1jet_mass76_106);
213
214 calculateRatio(43, _phistar_mass50_76, _phistar_mass76_106);
215 calculateRatio(45, _phistar_mass106_170, _phistar_mass76_106);
216 calculateRatio(47, _phistar_mass170_350, _phistar_mass76_106);
217 calculateRatio(49, _phistar_mass350_1000, _phistar_mass76_106);
218 }
219
220 protected:
221 size_t _mode;
222
223 private:
224 /// @name Histograms
225 Histo1DPtr _pt_0jet_mass50_76,
226 _pt_0jet_mass76_106,
227 _pt_0jet_mass106_170,
228 _pt_0jet_mass170_350,
229 _pt_0jet_mass350_1000;
230 Histo1DPtr _pt_1jet_mass50_76,
231 _pt_1jet_mass76_106,
232 _pt_1jet_mass106_170,
233 _pt_1jet_mass170_350;
234 Histo1DPtr _phistar_mass50_76,
235 _phistar_mass76_106,
236 _phistar_mass106_170,
237 _phistar_mass170_350,
238 _phistar_mass350_1000;
239 };
240
241 RIVET_DECLARE_PLUGIN(CMS_2022_I2079374);
242}
|