Rivet analyses

Rapidity structure of p pairs

Experiment: DELPHI (LEP)

Inspire ID: 531568

Status: VALIDATED

Authors: - Peter Richardson

References: - Phys.Lett.B 490 (2000) 61-70

Beams: e+ e-

Beam energies: (45.6, 45.6)GeV

Run details: - e+e- -> hadrons

Rapidity-rank structure of p pairs, the relative occurrence of the rapidity-ordered configuration pM, where M is a meson, and that of adjacent p pairs is compared as a function of the rapidity w.r.t the thrust axis.

Source code:DELPHI_2000_I531568.cc

// -*- C++ -*-
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/ChargedFinalState.hh"
#include "Rivet/Projections/Thrust.hh"

namespace Rivet {


  /// @brief p pbar correlations
  class DELPHI_2000_I531568 : public Analysis {
  public:

    /// Constructor
    RIVET_DEFAULT_ANALYSIS_CTOR(DELPHI_2000_I531568);


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

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

      // Initialise and register projections
      const ChargedFinalState cfs;
      declare(cfs, "CFS");
      declare(Thrust(cfs), "Thrust");

      // book histos
      book(_h_pMp,"_n_pMp",8,0.,1.);
      book(_h_sum,"_n_sum",8,0.,1.);
    }

    double findPP(const size_t mode, const Vector3& axis,
                  const Particles& part, size_t& pp) const {
      pp = 0;
      const size_t n = part.size();
      double dy = numeric_limits<double>::infinity();
      // compute rapidity with respect to axis
      vector<pair<double, size_t>> keys;
      keys.reserve(n);
      for (size_t i=0; i<n; ++i) {
        const double mom = dot(axis, part[i].p3());
        const double energy = part[i].E();
        double rap = 0.5 * std::log((energy + mom) / (energy - mom));
        if (!isfinite(rap))  continue; //< skip nans
        if (mode==0 && rap > 0.)  keys.emplace_back(rap, i);
        else if (mode==1 && fuzzyLessEquals(rap, 0.0))  keys.emplace_back(rap, i);
      }
      // sort by rapidity, break ties by original index for determinism
      std::stable_sort(keys.begin(), keys.end(), [](const auto& a, const auto& b) {
         if (fuzzyLessEquals(a.first, b.first))  return true;
         if (fuzzyLessEquals(b.first, a.first))  return false;
         return a.second < b.second;
      });
      // rebuild particles and rapidities in sorted order
      Particles particles;
      particles.reserve(n);
      vector<double> rapvals;
      rapvals.reserve(n);
      for (const auto& [rap, idx] : keys) {
        particles += part[idx];
        rapvals.push_back(rap);
      }
      // number of particles between the proton and antiproton
      auto itp1 = std::find_if(particles.begin(), particles.end(),
                               [](const Particle& p){ return p.abspid() == PID::PROTON; });
      auto itp2 = std::find_if(itp1+1, particles.end(),
                               [](const Particle& p){ return p.abspid() == PID::PROTON; });
      size_t rank = std::distance(itp1, itp2);
      // number of particles between the proton and antiproton
      if (rank > 4) return dy;
      size_t idx1 = itp1 - particles.begin();
      size_t idx2 = itp2 - particles.begin();
      // proton/antiproton next to each other, distance to nearest meson near them
      if (rank==1) {
        if (idx1 > 0) {
          pp = 1;
          dy = min(2./3.*std::abs(rapvals[idx1] - rapvals[idx1-1]), dy);
        }
        if (idx2+1 < particles.size()) {
          pp = 1;
          dy = min(2./3.*std::abs(rapvals[idx2] - rapvals[idx2+1]), dy);
        }
      }
      else {
        double ycent = 0.5*(rapvals[idx1] + rapvals[idx2]);
        double ymin = numeric_limits<double>::infinity();
        double ymes = numeric_limits<double>::infinity();
        for (size_t im = idx1+1; im != idx2; ++im) {
          double rap = rapvals[im];
          double test = std::abs(ycent - rap);
          if (test < ymin) {
            ymes = rap;
            ymin = test;
          }
        }
        pp = 2;
        dy = std::min(std::abs(rapvals[idx1] - ymes), std::abs(rapvals[idx2] - ymes));
      }
      return dy;
    }

    /// Perform the per-event analysis
    void analyze(const Event& event) {
      const Vector3 axis = apply<Thrust>(event,"Thrust").thrustAxis();
      const Particles chargedParticles = apply<ChargedFinalState>(event, "CFS").particlesByPt();
      unsigned int np[2]={0,0}, npbar[2]={0,0};
      for (const Particle& p : chargedParticles) {
        if (p.abspid() != PID::PROTON)  continue;
        const double mom = dot(axis, p.p3());
        const double energy = p.E();
        const double rap = 0.5 * std::log((energy + mom) / (energy - mom));
        unsigned int irap = rap>0 ? 0 : 1;
        if (p.pid()>0)  ++np[irap];
        else            ++npbar[irap];
      }
      MSG_DEBUG("np[0]=" << np[0] << " np[1]=" << np[1]);
      MSG_DEBUG("npbar[0]=" << npbar[0] << " npbar[1]=" << npbar[1]);
      if (np[0]==1 && npbar[0]==1) {
        size_t pp = 0;
        double dy = findPP(0, axis, chargedParticles, pp);
        if (pp==1)  _h_sum->fill(dy);
        else if (pp==2) {
          _h_sum->fill(dy);
          _h_pMp->fill(dy);
        }
      }
      if (np[1]==1 && npbar[1]==1) {
        size_t pp = 0;
        double dy = findPP(1, axis, chargedParticles, pp);
        if (pp==1)  _h_sum->fill(dy);
        else if (pp==2) {
          _h_sum->fill(dy);
          _h_pMp->fill(dy);
        }
      }
    }


    /// Normalise histograms etc., after the run
    void finalize() {
      Estimate1DPtr h_r;
      book(h_r, 1, 1, 1);
      divide(_h_pMp, _h_sum, h_r);
    }

    /// @}


    /// @name Histograms
    /// @{
    Histo1DPtr _h_sum, _h_pMp;
    /// @}


  };

  RIVET_DECLARE_PLUGIN(DELPHI_2000_I531568);
}