rivet is hosted by Hepforge, IPPP Durham

Rivet analyses reference

ATLAS_2015_I1394865

Inclusive 4-lepton lineshape
Experiment: ATLAS (LHC)
Inspire ID: 1394865
Status: TRUE
Authors:
  • Bing Li
References: Beams: p+ p+
Beam energies: (4000.0, 4000.0) GeV
Run details:
  • $p p \to \ell \ell \ell \ell + X$

The four-lepton (4$\ell$, $\ell = e,\mu$) production cross section is measured in the mass range from 80 to 1000 GeV using 20.3 fb$^{-1}$ of data in $pp$ collisions at $\sqrt{s}=8$ TeV collected with the ATLAS detector at the LHC. The $4\ell$ events are produced in the decays of resonant $Z$ and Higgs bosons and the non-resonant $ZZ$ continuum originating from $q\bar{q}$, $gg$, $qg$ initial states. A total of 476 signal candidate events are observed with a background expectation of 26.2$\pm$3.6 events, enabling the measurement of the integrated cross section and the differential cross section as a function of the invariant mass and transverse momentum of the four-lepton system.

Source code: ATLAS_2015_I1394865.cc
  1// -*- C++ -*-
  2#include "Rivet/Analysis.hh"
  3#include "Rivet/Projections/FinalState.hh"
  4#include "Rivet/Projections/IdentifiedFinalState.hh"
  5#include "Rivet/Projections/PromptFinalState.hh"
  6#include "Rivet/Projections/LeptonFinder.hh"
  7
  8namespace Rivet {
  9
 10
 11  /// Inclusive 4-lepton lineshape
 12  class ATLAS_2015_I1394865 : public Analysis {
 13  public:
 14
 15    /// Default constructor
 16    RIVET_DEFAULT_ANALYSIS_CTOR(ATLAS_2015_I1394865);
 17
 18
 19    void init() {
 20      FinalState fs(Cuts::abseta < 5.0);
 21      PromptFinalState pfs(Cuts::abseta < 5.0);
 22
 23      IdentifiedFinalState photon(fs, PID::PHOTON);
 24      IdentifiedFinalState bare_EL(pfs, {PID::ELECTRON, -PID::ELECTRON});
 25      IdentifiedFinalState bare_MU(pfs, {PID::MUON, -PID::MUON});
 26
 27      // Selection 1: ZZ-> llll selection
 28      Cut etaranges_el = Cuts::abseta < 2.5 && Cuts::pT > 7*GeV;
 29      Cut etaranges_mu = Cuts::abseta < 2.7 && Cuts::pT > 6*GeV;
 30
 31      LeptonFinder electron_sel4l(bare_EL, photon, 0.1, etaranges_el);
 32      declare(electron_sel4l, "ELECTRON_sel4l");
 33      LeptonFinder muon_sel4l(bare_MU, photon, 0.1, etaranges_mu);
 34      declare(muon_sel4l, "MUON_sel4l");
 35
 36
 37      // Both ZZ on-shell histos
 38      book(_h_ZZ_mZZ , 1, 1, 1);
 39      book(_h_ZZ_pTZZ, 2, 1, 1);
 40    }
 41
 42
 43    /// Do the analysis
 44    void analyze(const Event& e) {
 45      ////////////////////////////////////////////////////////////////////
 46      // Preselection of leptons for ZZ-> llll final state
 47      ////////////////////////////////////////////////////////////////////
 48
 49      Particles leptons_sel4l;
 50      const DressedLeptons& mu_sel4l = apply<LeptonFinder>(e, "MUON_sel4l").dressedLeptons();
 51      const DressedLeptons& el_sel4l = apply<LeptonFinder>(e, "ELECTRON_sel4l").dressedLeptons();
 52      const DressedLeptons leptonsFS_sel4l = mu_sel4l + el_sel4l;
 53      // leptonsFS_sel4l.insert( leptonsFS_sel4l.end(), mu_sel4l.begin(), mu_sel4l.end() );
 54      // leptonsFS_sel4l.insert( leptonsFS_sel4l.end(), el_sel4l.begin(), el_sel4l.end() );
 55
 56      // mu: pT > 6 GeV, eta < 2.7; ele: pT > 7 GeV, eta < 2.5
 57      for (const DressedLepton& l : leptonsFS_sel4l) {
 58        if (l.abspid() == PID::ELECTRON) leptons_sel4l.push_back(l);  // REDUNDANT: if (l.pT() > 7*GeV && l.abseta() < 2.5)
 59        else if (l.abspid() == PID::MUON) leptons_sel4l.push_back(l); // REDUNDANT: if (l.pT() > 6*GeV && l.abseta() < 2.7)
 60      }
 61
 62      //////////////////////////////////////////////////////////////////
 63      // Exactly two opposite charged leptons
 64      //////////////////////////////////////////////////////////////////
 65
 66      // Calculate total 'flavour' charge
 67      double totalcharge = 0;
 68      for (const Particle& l : leptons_sel4l)  totalcharge += l.pid();
 69
 70      // Analyze 4 lepton events
 71      if (leptons_sel4l.size() != 4 || totalcharge != 0) vetoEvent;
 72
 73      // Identify Z states from 4 lepton pairs
 74      Zstate Z1, Z2, Z1_alt, Z2_alt;
 75      if ( !identifyZstates(Z1, Z2, Z1_alt, Z2_alt, leptons_sel4l) )  vetoEvent;
 76
 77      const double mZ1 = Z1.mom().mass();
 78      const double mZ2 = Z2.mom().mass();
 79      const double mZ1_alt = Z1_alt.mom().mass();
 80      const double mZ2_alt = Z2_alt.mom().mass();
 81      const double pTZ1 = Z1.mom().pT();
 82      const double pTZ2 = Z2.mom().pT();
 83      const double mZZ = (Z1.mom() + Z2.mom()).mass();
 84      const double pTZZ = (Z1.mom() + Z2.mom()).pT();
 85
 86      // Event selections
 87      // pT(Z) > 2 GeV
 88      bool pass = pTZ1 > 2*GeV && pTZ2 > 2*GeV;
 89      if (!pass) vetoEvent;
 90
 91      // Lepton kinematics: pT > 20, 15, 10 (8 if muon) GeV
 92      int n1 = 0, n2 = 0, n3 = 0;
 93      for (Particle& l : leptons_sel4l) {
 94        if (l.pT() > 20*GeV) ++n1;
 95        if (l.pT() > 15*GeV) ++n2;
 96        if (l.pT() > 10*GeV && l.abspid() == PID::ELECTRON) ++n3;
 97        if (l.pT() >  8*GeV && l.abspid() == PID::MUON) ++n3;
 98      }
 99      pass = pass && n1>=1 && n2>=2 && n3>=3;
100      if (!pass) vetoEvent;
101
102      // Dilepton mass: 50 < mZ1 < 120 GeV, 12 < mZ2 < 120 GeV
103      pass = pass && mZ1 > 50*GeV && mZ1 < 120*GeV;
104      pass = pass && mZ2 > 12*GeV && mZ2 < 120*GeV;
105      if (!pass) vetoEvent;
106
107      // Lepton separation: deltaR(l, l') > 0.1 (0.2) for same- (different-) flavor leptons
108      for (size_t i = 0; i < leptons_sel4l.size(); ++i) {
109        for (size_t j = i + 1; j < leptons_sel4l.size(); ++j) {
110          const Particle& l1 = leptons_sel4l[i];
111          const Particle& l2 = leptons_sel4l[j];
112          pass = pass && deltaR(l1, l2) > (l1.abspid() == l2.abspid() ? 0.1 : 0.2);
113          if (!pass) vetoEvent;
114        }
115      }
116
117      // J/Psi veto: m(l+l-) > 5 GeV
118      pass = pass && mZ1 > 5*GeV && mZ2 > 5*GeV && mZ1_alt > 5*GeV && mZ2_alt > 5*GeV;
119      if (!pass) vetoEvent;
120
121      // 80 < m4l < 1000 GeV
122      pass = pass && mZZ > 80*GeV && mZZ < 1000*GeV;
123      if (!pass) vetoEvent;
124
125      // Fill histograms
126      _h_ZZ_mZZ->fill(mZZ);
127      _h_ZZ_pTZZ->fill(pTZZ);
128    }
129
130
131    /// Finalize
132    void finalize() {
133      const double norm = crossSection()/sumOfWeights()/femtobarn*TeV;
134      scale(_h_ZZ_mZZ,  norm);
135      scale(_h_ZZ_pTZZ, norm);
136    }
137
138
139    /// Generic Z candidate
140    struct Zstate : public ParticlePair {
141      Zstate() { }
142      Zstate(ParticlePair _particlepair) : ParticlePair(_particlepair) { }
143      FourMomentum mom() const { return first.momentum() + second.momentum(); }
144      operator FourMomentum() const { return mom(); }
145      static bool cmppT(const Zstate& lx, const Zstate& rx) { return lx.mom().pT() < rx.mom().pT(); }
146    };
147
148
149    /// @brief 4l to ZZ assignment algorithm
150    ///
151    /// ZZ->4l pairing
152    /// - At least two same flavour opposite sign (SFOS) lepton pairs
153    /// - Ambiguities in pairing are resolved following the procedure
154    ///   1. the leading Z (Z1) is choosen as the SFOS with dilepton mass closet to Z mass
155    ///   2. the subleading Z (Z2) is choosen as the remaining SFOS dilepton pair
156    ///
157    /// Z1, Z2: the selected pairing
158    /// Z1_alt, Z2_alt: the alternative pairing (the same as Z1, Z2 in 2e2m case)
159    bool identifyZstates(Zstate& Z1, Zstate& Z2, Zstate& Z1_alt, Zstate& Z2_alt, const Particles& leptons_sel4l) {
160      const double ZMASS = 91.1876*GeV;
161      bool findZZ = false;
162
163      Particles part_pos_el, part_neg_el, part_pos_mu, part_neg_mu;
164      for (const Particle& l : leptons_sel4l) {
165        if (l.abspid() == PID::ELECTRON) {
166          if (l.pid() < 0) part_neg_el.push_back(l);
167          if (l.pid() > 0) part_pos_el.push_back(l);
168        }
169        else if (l.abspid() == PID::MUON) {
170          if (l.pid() < 0) part_neg_mu.push_back(l);
171          if (l.pid() > 0) part_pos_mu.push_back(l);
172        }
173      }
174
175      // eeee/mmmm channel
176      if ((part_neg_el.size() == 2 && part_pos_el.size() == 2) || (part_neg_mu.size() == 2 && part_pos_mu.size() == 2)) {
177        findZZ = true;
178
179        Zstate Zcand_1, Zcand_2, Zcand_3, Zcand_4;
180        Zstate Zcand_1_tmp, Zcand_2_tmp, Zcand_3_tmp, Zcand_4_tmp;
181        if (part_neg_el.size() == 2) { // eeee
182          Zcand_1_tmp = Zstate( ParticlePair( part_neg_el[0],  part_pos_el[0] ) );
183          Zcand_2_tmp = Zstate( ParticlePair( part_neg_el[0],  part_pos_el[1] ) );
184          Zcand_3_tmp = Zstate( ParticlePair( part_neg_el[1],  part_pos_el[0] ) );
185          Zcand_4_tmp = Zstate( ParticlePair( part_neg_el[1],  part_pos_el[1] ) );
186        }
187        else { // mmmm
188          Zcand_1_tmp = Zstate( ParticlePair( part_neg_mu[0],  part_pos_mu[0] ) );
189          Zcand_2_tmp = Zstate( ParticlePair( part_neg_mu[0],  part_pos_mu[1] ) );
190          Zcand_3_tmp = Zstate( ParticlePair( part_neg_mu[1],  part_pos_mu[0] ) );
191          Zcand_4_tmp = Zstate( ParticlePair( part_neg_mu[1],  part_pos_mu[1] ) );
192        }
193
194        // We can have the following pairs: (Z1 + Z4) || (Z2 + Z3)
195        // Firstly, reorder withing each quadruplet to have
196        //  - fabs(mZ1 - ZMASS) < fabs(mZ4 - ZMASS)
197        //  - fabs(mZ2 - ZMASS) < fabs(mZ3 - ZMASS)
198        if (fabs(Zcand_1_tmp.mom().mass() - ZMASS) < fabs(Zcand_4_tmp.mom().mass() - ZMASS)) {
199          Zcand_1 = Zcand_1_tmp;
200          Zcand_4 = Zcand_4_tmp;
201        } else {
202          Zcand_1 = Zcand_4_tmp;
203          Zcand_4 = Zcand_1_tmp;
204        }
205        if (fabs(Zcand_2_tmp.mom().mass() - ZMASS) < fabs(Zcand_3_tmp.mom().mass() - ZMASS)) {
206          Zcand_2 = Zcand_2_tmp;
207          Zcand_3 = Zcand_3_tmp;
208        } else {
209          Zcand_2 = Zcand_3_tmp;
210          Zcand_3 = Zcand_2_tmp;
211        }
212
213        // We can have the following pairs: (Z1 + Z4) || (Z2 + Z3)
214        // Secondly, select the leading and subleading Z following
215        //   1. the leading Z (Z1) is choosen as the SFOS with dilepton mass closet to Z mass
216        //   2. the subleading Z (Z2) is choosen as the remaining SFOS dilepton pair
217        if (fabs(Zcand_1.mom().mass() - ZMASS) < fabs(Zcand_2.mom().mass() - ZMASS)) {
218          Z1 = Zcand_1;
219          Z2 = Zcand_4;
220          Z1_alt = Zcand_2;
221          Z2_alt = Zcand_3;
222        } else {
223          Z1 = Zcand_2;
224          Z2 = Zcand_3;
225          Z1_alt = Zcand_1;
226          Z2_alt = Zcand_4;
227        }
228      } // end of eeee/mmmm channel
229      else if (part_neg_el.size() == 1 && part_pos_el.size() == 1 && part_neg_mu.size() == 1 && part_pos_mu.size() == 1) { // 2e2m channel
230        findZZ = true;
231
232        Zstate Zcand_1, Zcand_2;
233
234        Zcand_1 = Zstate( ParticlePair( part_neg_mu[0],  part_pos_mu[0] ) );
235        Zcand_2 = Zstate( ParticlePair( part_neg_el[0],  part_pos_el[0] ) );
236
237        if (fabs(Zcand_1.mom().mass() - ZMASS) < fabs(Zcand_2.mom().mass() - ZMASS)) {
238          Z1 = Zcand_1;
239          Z2 = Zcand_2;
240        } else {
241          Z1 = Zcand_2;
242          Z2 = Zcand_1;
243        }
244        Z1_alt = Z1;
245        Z2_alt = Z2;
246      }
247
248      return findZZ;
249    }
250
251
252  private:
253
254    Histo1DPtr _h_ZZ_pTZZ, _h_ZZ_mZZ;
255
256  };
257
258
259  RIVET_DECLARE_PLUGIN(ATLAS_2015_I1394865);
260
261}