Rivet is hosted by Hepforge, IPPP Durham

Rivet analyses reference

CMS_2012_I1298807

Inclusive ZZ production cross section and constraints on anomalous triple gauge couplings at 8 TeV
Experiment: CMS (LHC)
Inspire ID: 1298807
Status: VALIDATED
Authors:
  • Alexander Savin
  • Ian Ross
References: Beams: p+ p+
Beam energies: (4000.0, 4000.0) GeV
Run details:
  • ZZ production, leptonic Z decays

A measurement of the inclusive $ZZ$ production cross section and constraints on anomalous triple gauge couplings in proton-proton collisions at $\sqrt{s} = 8 TeV$ are presented. The analysis is based on a data sample, corresponding to an integrated luminosity of 19.6/fb, collected with the CMS experiment at the LHC. The measurements are performed in the leptonic decay modes $ZZ \to lll^\prime l^\prime$, where $l = e,\mu$ and $l^\prime = e, \mu, \tau$. The measured total cross section $ \sigma (pp \to ZZ) = 7.7 \pm 0.5 (\mathrm{stat}) + 0.5 -0.4 (\mathrm{syst}) \pm 0.4 (\mathrm{theo}) \pm 0.2 (\mathrm{lumi}) pb$, for both $Z$ bosons produced in the mass range $60 < m_Z < 120 \text{GeV}$, is consistent with standard model predictions. Differential cross sections, in phase space $p_T(\mu) > 5 \text{GeV}$, $p_T(e) > 7 \text{GeV}$, $|\eta(\mu)|<2.4$ , $|\eta(e)|<2.5$ and the 60--120 \text{GeV} mass requirement, are measured and well described by the theoretical predictions. The invariant mass distribution of the four-lepton system is used to set limits on anomalous $ZZZ$ and $ZZ\gamma$ couplings at the 95\% confidence level, $-0.004 < f4Z < 0.004$, $-0.004 < f5Z < 0.004$, $-0.005 < f4\gamma < 0.005$, and $-0.005 < f5\gamma < 0.005.$

Source code: CMS_2012_I1298807.cc
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// -*- C++ -*-
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Projections/IdentifiedFinalState.hh"
#include "Rivet/Projections/ZFinder.hh"
#include "Rivet/Projections/VetoedFinalState.hh"
#include "Rivet/Projections/MergedFinalState.hh"

namespace Rivet {


  /// Inclusive ZZ production cross section and constraints on anomalous triple gauge couplings
  class CMS_2012_I1298807 : public Analysis {
  public:

    // Constructor
    DEFAULT_RIVET_ANALYSIS_CTOR(CMS_2012_I1298807);


    /// Initialise projections and histograms
    void init() {

      // FinalState electrons(Cuts::abseta < 2.5 && Cuts::abspid == PID::ELECTRON);
      // FinalState muons(Cuts::abseta < 2.4 && Cuts::abspid == PID::MUON);
      // MergedFinalState leptons(electrons, muons);
      FinalState leptons((Cuts::abspid == PID::ELECTRON && Cuts::abseta < 2.5) ||
                         (Cuts::abspid == PID::MUON && Cuts::abseta < 2.4));
      declare(leptons, "Leptons");

      Cut cut_el = Cuts::abseta < 2.5 && Cuts::pT > 7.0*GeV;
      Cut cut_mu = Cuts::abseta < 2.4 && Cuts::pT > 5.0*GeV;

      ZFinder zeefinder(FinalState(), cut_el, PID::ELECTRON, 60*GeV, 120*GeV, 0.1, ZFinder::CLUSTERNODECAY, ZFinder::TRACK);
      declare(zeefinder, "ZeeFinder");
      ZFinder zmmfinder(FinalState(), cut_mu, PID::MUON, 60*GeV, 120*GeV, 0.1, ZFinder::CLUSTERNODECAY, ZFinder::TRACK);
      declare(zmmfinder, "ZmmFinder");

      VetoedFinalState fs_woZmm;
      fs_woZmm.addVetoOnThisFinalState(zmmfinder);
      VetoedFinalState fs_woZee;
      fs_woZee.addVetoOnThisFinalState(zeefinder);

      ZFinder zeefinder_woZee(fs_woZee, cut_el, PID::ELECTRON, 60*GeV, 120*GeV, 0.1, ZFinder::CLUSTERNODECAY);
      declare(zeefinder_woZee, "Zeefinder_WoZee");
      ZFinder zmmfinder_woZmm(fs_woZmm, cut_mu, PID::MUON, 60*GeV, 120*GeV, 0.1, ZFinder::CLUSTERNODECAY);
      declare(zmmfinder_woZmm, "Zmmfinder_WoZmm");

      // Book histograms
      _hist_pt_l1 = bookHisto1D(1, 1, 1);
      _hist_pt_z1 = bookHisto1D(1, 1, 2);
      _hist_pt_zz = bookHisto1D(1, 1, 3);
      _hist_m_zz = bookHisto1D(1, 1, 4);
      _hist_dphi_zz = bookHisto1D(1, 1, 5);
      _hist_dR_zz = bookHisto1D(1, 1, 6);

    }


    // Perform the per-event analysis
    void analyze(const Event& evt) {

      // Find leading leptons and apply cuts
      const Particles& leptons = apply<FinalState>(evt, "Leptons").particlesByPt();
      if (leptons.size() < 2) vetoEvent;
      const double leading_l_pt = leptons[0].pT();
      const double second_l_pt = leptons[1].pT();
      if (leading_l_pt < 20*GeV || second_l_pt < 10*GeV) vetoEvent;

      // Find acceptable ZZ combinations and build four-momenta, otherwise veto
      const ZFinder& zeefinder = applyProjection<ZFinder>(evt, "ZeeFinder");
      const ZFinder& zeefinder_woZee = applyProjection<ZFinder>(evt, "Zeefinder_WoZee");
      const ZFinder& zmmfinder = applyProjection<ZFinder>(evt, "ZmmFinder");
      const ZFinder& zmmfinder_woZmm = applyProjection<ZFinder>(evt, "Zmmfinder_WoZmm");

      FourMomentum pZ_a, pZ_b, pZ_1, pZ_2;
      FourMomentum pZZ, Z_a_l1, Z_a_l2, Z_b_l1, Z_b_l2;
      if (zeefinder.bosons().size() > 0 && zmmfinder.bosons().size() > 0) {
        pZ_a = zeefinder.bosons()[0];
        pZ_b = zmmfinder.bosons()[0];
        pZZ = pZ_a + pZ_b;
        pZ_1 = pZ_a;
        pZ_2 = pZ_b;
        Z_a_l1 = zeefinder.constituents()[0];
        Z_a_l2 = zeefinder.constituents()[1];
        Z_b_l1 = zmmfinder.constituents()[0];
        Z_b_l2 = zmmfinder.constituents()[1];
      } else if (zeefinder.bosons().size() > 0 && zeefinder_woZee.bosons().size() > 0) {
        pZ_a = zeefinder.bosons()[0];
        pZ_b = zeefinder_woZee.bosons()[0];
        pZZ = pZ_a + pZ_b;
        pZ_1 = pZ_a;
        pZ_2 = pZ_b;
        Z_a_l1 = zeefinder.constituents()[0];
        Z_a_l2 = zeefinder.constituents()[1];
        Z_b_l1 = zeefinder_woZee.constituents()[0];
        Z_b_l2 = zeefinder_woZee.constituents()[1];
      } else if (zmmfinder.bosons().size() > 0 && zmmfinder_woZmm.bosons().size() > 0) {
        pZ_a = zmmfinder.bosons()[0];
        pZ_b = zmmfinder_woZmm.bosons()[0];
        pZZ = pZ_a + pZ_b;
        pZ_1 = pZ_a;
        pZ_2 = pZ_b;
        Z_a_l1 = zmmfinder.constituents()[0];
        Z_a_l2 = zmmfinder.constituents()[1];
        Z_b_l1 = zmmfinder_woZmm.constituents()[0];
        Z_b_l2 = zmmfinder_woZmm.constituents()[1];
      } else {
        vetoEvent;
      }

      // Set ordered pT variables
      /// @todo Looks like there should be a nicer way than this
      double pt_l1 = Z_a_l1.pT();
      if (Z_a_l2.pT() > pt_l1) pt_l1 = Z_a_l2.pT();
      if (Z_b_l1.pT() > pt_l1) pt_l1 = Z_b_l1.pT();
      if (Z_b_l2.pT() > pt_l1) pt_l1 = Z_b_l2.pT();

      // Leading Z pT
      double pt_z1 = pZ_a.pT();
      if (pZ_b.pT() > pZ_a.pT()) {
        pt_z1 = pZ_b.pT();
        pZ_1 = pZ_b;
        pZ_2 = pZ_a;
      }

      // Fill histograms
      const double weight = evt.weight();
      _hist_pt_zz->fill(pZZ.pT()/GeV, weight);
      _hist_m_zz->fill(pZZ.mass()/GeV, weight);
      _hist_dphi_zz->fill(deltaPhi(pZ_a, pZ_b), weight);
      _hist_dR_zz->fill(deltaR(pZ_a, pZ_b, PSEUDORAPIDITY), weight);
      _hist_pt_z1->fill(pt_z1/GeV, weight);
      _hist_pt_l1->fill(pt_l1/GeV, weight);

    }


    /// Scale histograms
    /// @note This is all needed to undo bin width factor -- WHY DO PEOPLE USE UNPHYSICAL HISTOGRAMS?!?
    /// @todo If we introduce a "bar plot" or similar, it'd work better here
    void finalize() {

      double sum_height_pt_zz = 0;
      for (size_t i = 0; i < _hist_pt_zz->numBins(); i++) {
        _hist_pt_zz->bin(i).scaleW(1. / _hist_pt_zz->bin(i).width());
        sum_height_pt_zz += _hist_pt_zz->bin(i).height();
      }
      scale(_hist_pt_zz, 1. / sum_height_pt_zz);

      double sum_height_m_zz = 0;
      for (size_t i = 0; i < _hist_m_zz->numBins(); i++) {
        _hist_m_zz->bin(i).scaleW(1. / _hist_m_zz->bin(i).width());
        sum_height_m_zz += _hist_m_zz->bin(i).height();
      }
      scale(_hist_m_zz, 1. / sum_height_m_zz);

      double sum_height_dphi_zz = 0;
      for (size_t i = 0; i < _hist_dphi_zz->numBins(); i++) {
        _hist_dphi_zz->bin(i).scaleW(1. / _hist_dphi_zz->bin(i).width());
        sum_height_dphi_zz += _hist_dphi_zz->bin(i).height();
      }
      scale(_hist_dphi_zz, 1. / sum_height_dphi_zz);

      double sum_height_dR_zz = 0;
      for (size_t i = 0; i < _hist_dR_zz->numBins(); i++) {
        _hist_dR_zz->bin(i).scaleW(1. / _hist_dR_zz->bin(i).width());
        sum_height_dR_zz += _hist_dR_zz->bin(i).height();
      }
      scale(_hist_dR_zz, 1. / sum_height_dR_zz);

      double sum_height_pt_z1 = 0;
      for (size_t i = 0; i < _hist_pt_z1->numBins(); i++) {
        _hist_pt_z1->bin(i).scaleW(1. / _hist_pt_z1->bin(i).width());
        sum_height_pt_z1 += _hist_pt_z1->bin(i).height();
      }
      scale(_hist_pt_z1, 1. / sum_height_pt_z1);

      double sum_height_pt_l1 = 0;
      for (size_t i = 0; i < _hist_pt_l1->numBins(); i++) {
        _hist_pt_l1->bin(i).scaleW(1. / _hist_pt_l1->bin(i).width());
        sum_height_pt_l1 += _hist_pt_l1->bin(i).height();
      }
      scale(_hist_pt_l1, 1. / sum_height_pt_l1);
    }


    /// Histograms
    Histo1DPtr _hist_pt_zz, _hist_m_zz, _hist_dphi_zz, _hist_dR_zz, _hist_pt_z1, _hist_pt_l1;

  };


  // The hook for the plugin system
  DECLARE_RIVET_PLUGIN(CMS_2012_I1298807);

}