Rivet analyses


title: LHCB_2019_I1730448

Measurement of charged hadron production in Z-tagged jets at 8 TeV

Experiment: LHCB (LHC)

Inspire ID: 1730448

Status: VALIDATED

Authors: - Alice Xu

References: - Phys. Rev. Lett. 123 (2019) 232001 - DOI:10.1103/PhysRevLett.123.232001 - arXiv: 1904.08878 - Expt page: LHCb-PAPER-2019-012

Beams: p+ p+

Beam energies: (4000.0, 4000.0)GeV

Run details: - Proton-proton interactions at 8 TeV centre-of-mass energy.

The LHCb Collaboration presents measurements of the longitudinal, transverse, and radial distributions of charged hadrons in $Z$-jets using proton-proton data collected at a center-of-mass energy of $\sqrt{s} = 8$TeV. $Z$ bosons are fully reconstructed from the $\mu^- \mu^+$ decay channel. Jets with transverse momentum $p_\mathrm{T,jet} > 20$ GeV are reconstructed within the rapidity range $2.5 < y_\mathrm{jet} < 4.0$ using the anti-$k_\mathrm{T}$ algorithm with resolution paparmeter $R = 0.5$.

Source code:LHCB_2019_I1730448.cc

```c++ // -- C++ --

include "Rivet/Analysis.hh"

include "Rivet/Projections/DileptonFinder.hh"

include "Rivet/Projections/DirectFinalState.hh"

include "Rivet/Projections/FastJets.hh"

include "Rivet/Projections/FinalState.hh"

include "Rivet/Projections/MissingMomentum.hh"

include "fastjet/ClusterSequence.hh"

include "fastjet/JetDefinition.hh"

include "fastjet/Selector.hh" // For creating Filter for jet Projector

namespace Rivet {

/// @brief Measurement of charged hadron production in Z-tagged jets at 8 TeV class LHCB_2019_I1730448 : public Analysis {

/////////////////////////////////////////////////////////////////////////////////////////////////
// Analysis parameters

// Particle reconstruction
const double ETA_MIN_PARTICLES = 2.;  // Min pseudorapidity of final-state particles
const double ETA_MAX_PARTICLES = 4.5; // Max "

// Jet reconstruction
const double JET_R = 0.5;        // Jet resolution parameter for anti-kT
const double ETA_MIN_JETS = 2.5; // Min rapidity of constructed Z-jets
const double ETA_MAX_JETS = 4.;  // Max "
const double PT_MIN_JETS = 20.;  // Min jet transverse momentum
const double PT_MAX_JETS = 100.; // Max "

// Z Boson
const double MASS_MIN_ZBOSONS = 60.;  // Min invariant mass of Z bosons
const double MASS_MAX_ZBOSONS = 120.; // Max "
const double PT_MIN_ZBOSONS = 0.;     // Min Z boson transverse momentum
const double PT_MAX_ZBOSONS = 100.;   // Max "

// Charged Hadron
const double P_MIN_HADRONS = 4.;    // Min momentum of charged hadrons
const double P_MAX_HADRONS = 1000.; // Max "
const double PT_MIN_HADRONS = 0.25; // Min transverse momentum of charged hadrons

public:

// Attaches constituent PID to a PseudoJet
class JetInfo : public fastjet::PseudoJet::UserInfoBase {
public:

  JetInfo(const int& _pid)
      : pid(_pid) { };
  int get_pid() const {
    return this->pid;
  }

private:

  int pid = -999;
};

/// Constructor
RIVET_DEFAULT_ANALYSIS_CTOR(LHCB_2019_I1730448);


/// @name Analysis methods
/// @{

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

  // The basic final-state projection:
  // all final-state particles within the given eta acceptance
  Cut particle_selector = Cuts::etaIn(ETA_MIN_PARTICLES, ETA_MAX_PARTICLES);
  const FinalState fs(particle_selector);
  declare(fs, "fs_particles");

  Cut Z_boson_selector = Cuts::ptIn(PT_MIN_ZBOSONS, PT_MAX_ZBOSONS)
      & Cuts::massIn(MASS_MIN_ZBOSONS, MASS_MAX_ZBOSONS) & particle_selector;

  // Find *decayed* Z bosons from dimuon children
  // pT > 20 GeV according to JHEP 08 (2015) 039;  DOI:10.1007/JHEP08%282015%29039 referenced indirectly in paper
  DileptonFinder zfinder(fs, 91.2 * GeV, -1., (Cuts::abspid == PID::MUON) && Cuts::pT > 20. * GeV,
                         Z_boson_selector);
  declare(zfinder, "ZFinder");

  // Jet pT bin edges
  const vector<double> PT_BIN_EDGES = {20., 30., 50., 100.};

  // Book histograms
  book(_h_ufld_z, PT_BIN_EDGES);
  book(_h_ufld_jt, PT_BIN_EDGES);
  book(_h_ufld_r, PT_BIN_EDGES);
  for (size_t i = 0; i < _h_ufld_z->numBins(); i++) {
    book(_h_ufld_z->bin(i + 1), 1, 1, i + 1);  // HEPData Table 1
    book(_h_ufld_jt->bin(i + 1), 2, 1, i + 1); // HEPData Table 2
    book(_h_ufld_r->bin(i + 1), 3, 1, i + 1);  // HEPData Table 3
  };
}


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

  const FinalState& fs = apply<FinalState>(event, "fs_particles");

  if (getLog().isActive(Rivet::Log::DEBUG)) {
    int nmuons = 0;
    for (const Particle& p : fs.particles()) {
      if (abs(p.pid()) == 13) nmuons++;
    }
    MSG_DEBUG("fs size: " << fs.particles().size() << " | muons: " << nmuons << std::endl);
  }

  // The final-state particles declared above are clustered using FastJet with
  // the anti-kT algorithm and a jet-radius parameter 0.5
  Rivet::PseudoJets trimmed_particles;
  for (const Particle& fs_particle : fs.particles()) {
    fastjet::PseudoJet InfoJet = fs_particle.pseudojet();
    InfoJet.set_user_info_shared_ptr(
        fastjet::SharedPtr<fastjet::PseudoJet::UserInfoBase>(new JetInfo(fs_particle.pid())));
    trimmed_particles.push_back(InfoJet);
  }
  fastjet::JetDefinition jet_def(fastjet::antikt_algorithm, JET_R);
  fastjet::ClusterSequence cs(trimmed_particles, jet_def);
  Rivet::PseudoJets jets = sorted_by_pt(cs.inclusive_jets());

  // Retrieve *decayed* Z bosons and muon children
  const DileptonFinder& zfinder = apply<DileptonFinder>(event, "ZFinder");
  if (zfinder.bosons().empty()) vetoEvent;

  const Particles& Z_bosons = zfinder.bosons();
  const Particles& muons = zfinder.constituents(); // mu+ and mu-

  // Retrieve clustered jets, sorted by pT, with applied rapidity and pT cuts
  fastjet::Selector jet_selector = fastjet::SelectorPtRange(PT_MIN_JETS, PT_MAX_JETS)
      && fastjet::SelectorEtaRange(ETA_MIN_JETS, ETA_MAX_JETS);
  jets = jet_selector(jets);
  if (jets.empty()) {
    vetoEvent;
  }

  // Create a vector of jets that are back to back with a Z boson, with no muons in jet cone
  Jets Z_jets;
  for (const Rivet::Jet jet : jets) {
    for (const Particle& Z_boson : Z_bosons) {
      if ((Z_boson.pT() < PT_MIN_ZBOSONS) || (Z_boson.pT() > PT_MAX_ZBOSONS))
        continue; // Check Z pT - already in cuts!!!
      bool muon_in_jet = false;
      for (const Particle& muon : muons) {
        if (deltaR(muon, jet) < JET_R) {
          muon_in_jet = true;
          break;
        }
      }
      if (muon_in_jet) continue;
      if (deltaPhi(Z_boson, jet) > (7 * M_PI) / 8) { // Azimuthal cut
        Z_jets.push_back(jet);
        // Recording the number of jets in each bin, for scaling purposes
        if ((jet.pT() >= 20.) && (jet.pT() < 30.)) {
          num_jets_20_30 += 1.;
        }
        else if ((jet.pT() >= 30.) && (jet.pT() < 50.)) {
          num_jets_30_50 += 1.;
        }
        else if ((jet.pT() >= 50.) && (jet.pT() < 100.)) {
          num_jets_50_100 += 1.;
        }
        MSG_DEBUG("deltaphi: " << deltaPhi(Z_boson, jet) << std::endl
                               << "jet eta: " << jet.eta() << std::endl
                               << "jet pt: " << jet.pT() << std::endl
                               << "N_jet <20-30>: " << num_jets_20_30 << std::endl
                               << "N_jet <30-50>: " << num_jets_30_50 << std::endl
                               << "N_jet <50-100>: " << num_jets_50_100 << std::endl);
      }
    }
  }
  if (Z_jets.empty()) {
    vetoEvent;
  }

  MSG_DEBUG(Z_jets.size() << " Z jets found." << std::endl);

  ////////////////////////////////////////////////////////////////////////////////////////

  // Loop over jets and apply operations & fill histograms
  for (const Rivet::Jet& Z_jet : Z_jets) {
    for (const fastjet::PseudoJet& constituent : Z_jet.pseudojet().constituents()) {
      const JetInfo& myinfo = constituent.user_info<JetInfo>();
      Rivet::FourMomentum cmom(constituent.E(), constituent.px(), constituent.py(), constituent.pz());
      // Fill histogram
      if (((abs(myinfo.get_pid()) == PID::PIPLUS) || (abs(myinfo.get_pid()) == PID::KPLUS)
           || (abs(myinfo.get_pid()) == PID::PROTON))
          && (constituent.modp() > P_MIN_HADRONS) && (constituent.modp() < P_MAX_HADRONS)
          && (constituent.pt() > PT_MIN_HADRONS)
          && (deltaR(cmom, Z_jet, Rivet::RapScheme::YRAP) < JET_R)) {
        MSG_DEBUG("Filling histograms for " << myinfo.get_pid() << " ..." << std::endl);
        double num_z = Z_jet.p3().dot(cmom.p3());
        double den_z = Z_jet.p2();
        double num_jt = (Z_jet.p3().cross(cmom.p3())).mod();
        double den_jt = Z_jet.p();
        double r = deltaR(cmom, Z_jet, Rivet::RapScheme::YRAP);
        double zj_pt = Z_jet.pT();
        _h_ufld_z->fill(zj_pt, num_z / den_z);    // Fill histogram with longitudinal momentum
        _h_ufld_jt->fill(zj_pt, num_jt / den_jt); // Fill histogram with transverse momentum
        _h_ufld_r->fill(zj_pt, r);                // Fill histogram with radial profile distribution
      };
    }
  }
}


/////////////////////////////////////////////////////////////////////////////////////////////////
/// Scale histograms etc., after the run
void finalize() {
  const vector<double> scaleFactors = {1., (fuzzyEquals(0., num_jets_20_30) ? 1. : 1. / num_jets_20_30),
                                       (fuzzyEquals(0., num_jets_30_50) ? 1. : 1. / num_jets_30_50),
                                       (fuzzyEquals(0., num_jets_50_100) ? 1. : 1. / num_jets_50_100),
                                       1.};
  scale(_h_ufld_z, scaleFactors);
  scale(_h_ufld_jt, scaleFactors);
  scale(_h_ufld_r, scaleFactors);
}

/// @}

private:

/// @name Histograms
/// @{
Histo1DGroupPtr _h_ufld_z;
Histo1DGroupPtr _h_ufld_jt;
Histo1DGroupPtr _h_ufld_r;
/// @}

// Jet reconstruction counters
double num_jets_20_30 = 0.;  // Total number of Z-tagged jets from the 20<pT<30 GeV bin
double num_jets_30_50 = 0.;  // " 30<pT<50 GeV bin
double num_jets_50_100 = 0.; // " 50<pT<100 GeV bin

};

RIVET_DECLARE_PLUGIN(LHCB_2019_I1730448);

} ```