Rivet analyses

Higgs diphoton events at 8 TeV in ATLAS

Experiment: ATLAS (LHC)

Inspire ID: 1306615

Status: VALIDATED

Authors: - Michaela Queitsch-Maitland

References: - Expt page: ATLAS-HIGG-2013-10 - arXiv: 1407.4222 - JHEP 09 (2014) 112

Beams: p+ p+

Beam energies: (4000.0, 4000.0)GeV

Run details: - pp Higgs production at 8 TeV, include all processes (ggH, VH, VBF, ttH)

Measurements of fiducial and differential cross sections are presented for Higgs boson production in proton-proton collisions at a centre-of-mass energy of 8TeV. The analysis is performed in the Higgs diphoton decay channel using 20.3/fb of data recorded by the ATLAS experiment at the CERN Large Hadron Collider. The signal yields are corrected for the effects of detector inefficiency and resolution. Differential cross sections are also presented, as a function of variables related to the diphoton kinematics and the jet activity produced in the Higgs boson events. The observed spectra are statistically limited but broadly in line with the theoretical expectations. Note on reinterpretation: Since the background is subtracted from a fit, any BSM signal would presumably also have beed subtracted. Therefore should not be used to constrain BSM signals unless they comes from a genuine excess of SM Higgs->gammagamma.

Source code:ATLAS_2014_I1306615.cc

// -*- C++ -*-
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Projections/PromptFinalState.hh"
#include "Rivet/Projections/LeptonFinder.hh"
#include "Rivet/Projections/VetoedFinalState.hh"
#include "Rivet/Projections/FastJets.hh"

namespace Rivet {


  /// @brief ATLAS H->yy differential cross-sections measurement
  ///
  /// @author Michaela Queitsch-Maitland <michaela.queitsch-maitland@cern.ch>
  //
  // arXiv: http://arxiv.org/abs/ARXIV:1407.4222
  // HepData: http://hepdata.cedar.ac.uk/view/ins1306615
  class ATLAS_2014_I1306615 : public Analysis {
  public:

    // Constructor
    ATLAS_2014_I1306615()
      : Analysis("ATLAS_2014_I1306615")
    {    }


    // Book histograms and initialise projections before the run
    void init() {

      // Final state
      // All particles within |eta| < 5.0
      const FinalState FS(Cuts::abseta<5.0);
      declare(FS,"FS");

      // Project photons with pT > 25 GeV and |eta| < 2.37
      PromptFinalState ph_FS(Cuts::abseta<2.37 && Cuts::pT>25*GeV && Cuts::pid == PID::PHOTON);
      declare(ph_FS, "PH_FS");

      // Project photons for dressing
      FinalState ph_dressing_FS(Cuts::abspid == PID::PHOTON);

      // Project bare electrons
      PromptFinalState el_bare_FS(Cuts::abseta < 5.0 && Cuts::abspid == PID::ELECTRON);

      // Project dressed electrons with pT > 15 GeV and |eta| < 2.47
      LeptonFinder el_dressed_FS(el_bare_FS, ph_dressing_FS, 0.1, Cuts::abseta < 2.47 && Cuts::pT > 15*GeV);
      declare(el_dressed_FS,"EL_DRESSED_FS");

      // Project bare muons
      PromptFinalState mu_bare_FS(Cuts::abseta < 5.0 && Cuts::abspid == PID::MUON);

      // Project dressed muons with pT > 15 GeV and |eta| < 2.47
      LeptonFinder mu_dressed_FS(mu_bare_FS, ph_dressing_FS, 0.1, Cuts::abseta < 2.47 && Cuts::pT > 15*GeV);
      declare(mu_dressed_FS,"MU_DRESSED_FS");

      // Final state excluding muons and neutrinos (for jet building and photon isolation)
      VetoedFinalState veto_mu_nu_FS(FS);
      veto_mu_nu_FS.vetoNeutrinos();
      veto_mu_nu_FS.addVetoPairId(PID::MUON);
      declare(veto_mu_nu_FS, "VETO_MU_NU_FS");

      // Build the anti-kT R=0.4 jets, using FinalState particles (vetoing muons and neutrinos)
      FastJets jets(veto_mu_nu_FS, JetAlg::ANTIKT, 0.4);
      declare(jets, "JETS");

      // Book histograms
      // 1D distributions
      book(_h_pT_yy         ,1,1,1);
      book(_h_y_yy          ,2,1,1);
      book(_h_Njets30       ,3,1,1);
      book(_h_Njets50       ,4,1,1);
      book(_h_pT_j1         ,5,1,1);
      book(_h_y_j1          ,6,1,1);
      book(_h_HT            ,7,1,1);
      book(_h_pT_j2         ,8,1,1);
      book(_h_Dy_jj         ,9,1,1);
      book(_h_Dphi_yy_jj    ,10,1,1);
      book(_h_cosTS_CS      ,11,1,1);
      book(_h_cosTS_CS_5bin ,12,1,1);
      book(_h_Dphi_jj       ,13,1,1);
      book(_h_pTt_yy        ,14,1,1);
      book(_h_Dy_yy         ,15,1,1);
      book(_h_tau_jet       ,16,1,1);
      book(_h_sum_tau_jet   ,17,1,1);
      book(_h_y_j2          ,18,1,1);
      book(_h_pT_j3         ,19,1,1);
      book(_h_m_jj          ,20,1,1);
      book(_h_pT_yy_jj      ,21,1,1);

      // 2D distributions of cosTS_CS x pT_yy
      book(_h_cosTS_pTyy_low,  22,1,1);
      book(_h_cosTS_pTyy_high, 22,1,2);
      book(_h_cosTS_pTyy_rest, 22,1,3);

      // 2D distributions of Njets x pT_yy
      book(_h_pTyy_Njets0, 23,1,1);
      book(_h_pTyy_Njets1, 23,1,2);
      book(_h_pTyy_Njets2, 23,1,3);

      book(_h_pTj1_excl, 24,1,1);

      // Fiducial regions
      book(_h_fidXSecs, 30,1,1);
    }

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

      // Get final state particles
      const Particles& FS_ptcls         = apply<FinalState>(event, "FS").particles();
      const Particles& ptcls_veto_mu_nu = apply<VetoedFinalState>(event, "VETO_MU_NU_FS").particles();
      const Particles& photons          = apply<PromptFinalState>(event, "PH_FS").particlesByPt();
      DressedLeptons good_el          = apply<LeptonFinder>(event, "EL_DRESSED_FS").dressedLeptons();
      DressedLeptons good_mu          = apply<LeptonFinder>(event, "MU_DRESSED_FS").dressedLeptons();

      // For isolation calculation
      float dR_iso    = 0.4;
      float ETcut_iso = 14.0;
      FourMomentum ET_iso;

      // Fiducial selection: pT > 25 GeV, |eta| < 2.37 and isolation (in cone deltaR = 0.4) is < 14 GeV
      Particles fid_photons;
      for (const Particle& ph : photons) {

        // Calculate isolation
        ET_iso = - ph.momentum();
        // Loop over fs truth particles (excluding muons and neutrinos)
        for (const Particle& p : ptcls_veto_mu_nu) {
          // Check if the truth particle is in a cone of 0.4
          if ( deltaR(ph, p) < dR_iso ) ET_iso += p.momentum();
        }

        // Check isolation
        if ( ET_iso.Et() > ETcut_iso ) continue;

        // Fill vector of photons passing fiducial selection
        fid_photons.push_back(ph);
      }

      if (fid_photons.size() < 2)  vetoEvent;

      const FourMomentum y1 = fid_photons[0].momentum();
      const FourMomentum y2 = fid_photons[1].momentum();

      double m_yy = (y1 + y2).mass();

      // Relative pT cuts
      if ( y1.pT() < 0.35 * m_yy || y2.pT() < 0.25 * m_yy ) vetoEvent;

      // Mass window cut
      if ( m_yy < 105 || m_yy > 160 ) vetoEvent;

      // -------------------------------------------- //
      // Passed diphoton baseline fiducial selection! //
      // -------------------------------------------- //

      // Muon and Electron selection
      idiscard(good_mu, [&](const DressedLepton& lep) { return deltaR(lep, y1) < 0.4 || deltaR(lep, y2) < 0.4; });
      idiscard(good_el, [&](const DressedLepton& lep) { return deltaR(lep, y1) < 0.4 || deltaR(lep, y2) < 0.4; });

      // Find prompt, invisible particles for missing ET calculation
      // Based on VisibleFinalState projection
      FourMomentum invisible(0,0,0,0);
      for (const Particle& p : FS_ptcls) {

        // Veto non-prompt particles (from hadron or tau decay)
        if ( !p.isPrompt() ) continue;
        // Charged particles are visible
        if ( PID::charge3( p.pid() ) != 0 ) continue;
        // Neutral hadrons are visible
        if ( PID::isHadron( p.pid() ) ) continue;
        // Photons are visible
        if ( p.pid() == PID::PHOTON ) continue;
        // Gluons are visible (for parton level analyses)
        if ( p.pid() == PID::GLUON ) continue;
        // Everything else is invisible
        invisible += p.momentum();
      }
      double MET = invisible.Et();

      // Jet selection
      // Get jets with pT > 25 GeV and |rapidity| < 4.4
      const Jets& jets = apply<FastJets>(event, "JETS").jetsByPt(Cuts::pT>25*GeV && Cuts::absrap <4.4);

      Jets jets_25, jets_30, jets_50;

      for (const Jet& jet : jets) {

        bool passOverlap = true;
        // Overlap with leading photons
        if ( deltaR(y1, jet.momentum()) < 0.4 ) passOverlap = false;
        if ( deltaR(y2, jet.momentum()) < 0.4 ) passOverlap = false;

        // Overlap with good electrons
        for (const auto& el : good_el) {
          if ( deltaR(el, jet) < 0.2 ) passOverlap = false;
        }

        if ( ! passOverlap ) continue;

        if ( jet.abseta() < 2.4 || ( jet.abseta() > 2.4 && jet.pT() > 30*GeV) ) jets_25 += jet;
        if ( jet.pT() > 30*GeV ) jets_30 += jet;
        if ( jet.pT() > 50*GeV ) jets_50 += jet;
      }

      // Fiducial regions
      _h_fidXSecs->fill(1);
      if ( jets_30.size() >= 1 ) _h_fidXSecs->fill(2);
      if ( jets_30.size() >= 2 ) _h_fidXSecs->fill(3);
      if ( jets_30.size() >= 3 ) _h_fidXSecs->fill(4);
      if ( jets_30.size() >= 2 && passVBFCuts(y1 + y2, jets_30.at(0).momentum(), jets_30.at(1).momentum()) ) _h_fidXSecs->fill(5);
      if ( (good_el.size() + good_mu.size()) > 0 ) _h_fidXSecs->fill(6);
      if ( MET > 80 ) _h_fidXSecs->fill(7);

      // Fill histograms
      // Inclusive variables
      _pT_yy    = (y1 + y2).pT();
      _y_yy     = (y1 + y2).absrap();
      _cosTS_CS = cosTS_CS(y1, y2);
      _pTt_yy   = pTt(y1, y2);
      _Dy_yy    = fabs( deltaRap(y1, y2) );

      _Njets30 = jets_30.size() > 3 ? 3 : jets_30.size();
      _Njets50 = jets_50.size() > 3 ? 3 : jets_50.size();
      _h_Njets30->fill(_Njets30);
      _h_Njets50->fill(_Njets50);

      _pT_j1 = jets_30.size() > 0 ? jets_30[0].momentum().pT() : 0.;
      _pT_j2 = jets_30.size() > 1 ? jets_30[1].momentum().pT() : 0.;
      _pT_j3 = jets_30.size() > 2 ? jets_30[2].momentum().pT() : 0.;

      _HT = 0.0;
      for (const Jet& jet : jets_30) {  _HT += jet.pT(); }

      _tau_jet     = tau_jet_max(y1 + y2, jets_25);
      _sum_tau_jet = sum_tau_jet(y1 + y2, jets_25);

      _h_pT_yy        ->fill(_pT_yy);
      _h_y_yy         ->fill(_y_yy);
      _h_pT_j1        ->fill(_pT_j1);
      _h_cosTS_CS     ->fill(_cosTS_CS);
      _h_cosTS_CS_5bin->fill(_cosTS_CS);
      _h_HT           ->fill(_HT);
      _h_pTt_yy       ->fill(_pTt_yy);
      _h_Dy_yy        ->fill(_Dy_yy);
      _h_tau_jet      ->fill(_tau_jet);
      _h_sum_tau_jet  ->fill(_sum_tau_jet);

      // >=1 jet variables
      if ( jets_30.size() >= 1 ) {
        FourMomentum j1 = jets_30[0].momentum();
        _y_j1 = j1.absrap();

    _h_pT_j2->fill(_pT_j2);
    _h_y_j1 ->fill(_y_j1);
      }

      // >=2 jet variables
      if ( jets_30.size() >= 2 ) {
        FourMomentum j1 = jets_30[0].momentum();
        FourMomentum j2 = jets_30[1].momentum();

        _Dy_jj      = fabs( deltaRap(j1, j2) );
        _Dphi_jj    = fabs( deltaPhi(j1, j2) );
        _Dphi_yy_jj = fabs( deltaPhi(y1 + y2, j1 + j2) );
        _m_jj       = (j1 + j2).mass();
        _pT_yy_jj   = (y1 + y2 + j1 + j2).pT();
        _y_j2       = j2.absrap();

    _h_Dy_jj      ->fill(_Dy_jj);
    _h_Dphi_jj    ->fill(_Dphi_jj);
    _h_Dphi_yy_jj ->fill(_Dphi_yy_jj);
    _h_m_jj       ->fill(_m_jj);
    _h_pT_yy_jj   ->fill(_pT_yy_jj);
    _h_pT_j3      ->fill(_pT_j3);
    _h_y_j2       ->fill(_y_j2);
      }

      // 2D distributions of cosTS_CS x pT_yy
      if ( _pT_yy < 80 )
    _h_cosTS_pTyy_low->fill(_cosTS_CS);
      else if ( _pT_yy > 80 && _pT_yy < 200 )
    _h_cosTS_pTyy_high->fill(_cosTS_CS);
      else if ( _pT_yy > 200 )
    _h_cosTS_pTyy_rest->fill(_cosTS_CS);

      // 2D distributions of pT_yy x Njets
      if ( _Njets30 == 0 )
    _h_pTyy_Njets0->fill(_pT_yy);
      else if ( _Njets30 == 1 )
    _h_pTyy_Njets1->fill(_pT_yy);
      else if ( _Njets30 >= 2 )
    _h_pTyy_Njets2->fill(_pT_yy);

      if ( _Njets30 == 1 ) _h_pTj1_excl->fill(_pT_j1);

    }

    // Normalise histograms after the run
    void finalize() {

      const double xs = crossSectionPerEvent()/femtobarn;

      scale(_h_pT_yy, xs);
      scale(_h_y_yy, xs);
      scale(_h_pT_j1, xs);
      scale(_h_y_j1, xs);
      scale(_h_HT, xs);
      scale(_h_pT_j2, xs);
      scale(_h_Dy_jj, xs);
      scale(_h_Dphi_yy_jj, xs);
      scale(_h_cosTS_CS, xs);
      scale(_h_cosTS_CS_5bin, xs);
      scale(_h_Dphi_jj, xs);
      scale(_h_pTt_yy, xs);
      scale(_h_Dy_yy, xs);
      scale(_h_tau_jet, xs);
      scale(_h_sum_tau_jet, xs);
      scale(_h_y_j2, xs);
      scale(_h_pT_j3, xs);
      scale(_h_m_jj, xs);
      scale(_h_pT_yy_jj, xs);
      scale(_h_cosTS_pTyy_low, xs);
      scale(_h_cosTS_pTyy_high, xs);
      scale(_h_cosTS_pTyy_rest, xs);
      scale(_h_pTyy_Njets0, xs);
      scale(_h_pTyy_Njets1, xs);
      scale(_h_pTyy_Njets2, xs);
      scale(_h_pTj1_excl, xs);
      scale(_h_Njets30, xs);
      scale(_h_Njets50, xs);
      scale(_h_fidXSecs, xs);
    }

    // VBF-enhanced dijet topology selection cuts
    bool passVBFCuts(const FourMomentum &H, const FourMomentum &j1, const FourMomentum &j2) {
      return ( fabs(deltaRap(j1, j2)) > 2.8 && (j1 + j2).mass() > 400 && fabs(deltaPhi(H, j1 + j2)) > 2.6 );
    }

    // Cosine of the decay angle in the Collins-Soper frame
    double cosTS_CS(const FourMomentum &y1, const FourMomentum &y2) {
      return fabs( ( (y1.E() + y1.pz())* (y2.E() - y2.pz()) - (y1.E() - y1.pz()) * (y2.E() + y2.pz()) )
           / ((y1 + y2).mass() * sqrt(pow((y1 + y2).mass(), 2) + pow((y1 + y2).pt(), 2)) ) );
    }

    // Diphoton pT along thrust axis
    double pTt(const FourMomentum &y1, const FourMomentum &y2) {
      return fabs(y1.px() * y2.py() - y2.px() * y1.py()) / (y1 - y2).pT()*2;
    }

    // Tau of jet  (see paper for description)
    // tau_jet = mT/(2*cosh(y*)), where mT = pT (+) m, and y* = rapidty in Higgs rest frame
    double tau_jet( const FourMomentum &H, const FourMomentum &jet ) {
      return sqrt( pow(jet.pT(),2) + pow(jet.mass(),2) ) / (2.0 * cosh( jet.rapidity() - H.rapidity() ) );
    }

    // Maximal (leading) tau_jet (see paper for description)
    double tau_jet_max(const FourMomentum &H, const Jets& jets, double tau_jet_cut = 8.) {
      double max_tj = 0;
      for (const auto& jet : jets) {
        FourMomentum j = jet.momentum();
        if (tau_jet(H, j) > tau_jet_cut)  max_tj = max(tau_jet(H, j), max_tj);
      }
      return max_tj;
    }

    // Scalar sum of tau for all jets (see paper for description)
    double sum_tau_jet(const FourMomentum &H, const Jets& jets, double tau_jet_cut = 8.)  {
      double sum_tj = 0;
      for (const auto& jet : jets) {
        FourMomentum j = jet.momentum();
        if (tau_jet(H, j) > tau_jet_cut)  sum_tj += tau_jet(H, j);
      }
      return sum_tj;
    }

  private:

    Histo1DPtr _h_pT_yy;
    Histo1DPtr _h_y_yy;
    Histo1DPtr _h_Njets30;
    Histo1DPtr _h_Njets50;
    Histo1DPtr _h_pT_j1;
    Histo1DPtr _h_y_j1;
    Histo1DPtr _h_HT;
    Histo1DPtr _h_pT_j2;
    Histo1DPtr _h_Dy_jj;
    Histo1DPtr _h_Dphi_yy_jj;
    Histo1DPtr _h_cosTS_CS;
    Histo1DPtr _h_cosTS_CS_5bin;
    Histo1DPtr _h_Dphi_jj;
    Histo1DPtr _h_pTt_yy;
    Histo1DPtr _h_Dy_yy;
    Histo1DPtr _h_tau_jet;
    Histo1DPtr _h_sum_tau_jet;
    Histo1DPtr _h_y_j2;
    Histo1DPtr _h_pT_j3;
    Histo1DPtr _h_m_jj;
    Histo1DPtr _h_pT_yy_jj;
    Histo1DPtr _h_cosTS_pTyy_low;
    Histo1DPtr _h_cosTS_pTyy_high;
    Histo1DPtr _h_cosTS_pTyy_rest;
    Histo1DPtr _h_pTyy_Njets0;
    Histo1DPtr _h_pTyy_Njets1;
    Histo1DPtr _h_pTyy_Njets2;
    Histo1DPtr _h_pTj1_excl;
    Histo1DPtr _h_fidXSecs;

    int _Njets30;
    int _Njets50;
    double _pT_yy;
    double _y_yy;
    double _cosTS_CS;
    double _pT_j1;
    double _m_jj;
    double _y_j1;
    double _HT;
    double _pT_j2;
    double _y_j2;
    double _Dphi_yy_jj;
    double _pT_yy_jj;
    double _Dphi_jj;
    double _Dy_jj;
    double _pT_j3;
    double _pTt_yy;
    double _Dy_yy;
    double _tau_jet;
    double _sum_tau_jet;
  };


  RIVET_DECLARE_PLUGIN(ATLAS_2014_I1306615);

}