Rivet analyses

Measurements of event shapes by DELPHI, above and below $m_Z$

Experiment: DELPHI (LEP)

Inspire ID: 620250

Status: VALIDATED

Authors: - Peter Richardson

References: - Eur.Phys.J. C29 (2003) 285-312

Beams: e+ e-

Beam energies: (22.5, 22.5); (33.0, 33.0); (38.0, 38.0); (91.5, 91.5); (94.5, 94.5); (96.0, 96.0); (98.0, 98.0); (100.0, 100.0); (101.0, 101.0); (102.5, 102.5); (103.5, 103.5)GeV

Run details: - Hadronic Z decay events generated below the Z pole.

Measurement of a wide range of event shapes by DELPHI at energies below the Z pole using radiative events and above $m_Z$ from LEP2. This analyses allows the energy dependence of simulations to be studied. Only the distributions and not the means are implemented.

Source code:DELPHI_2003_I620250.cc

// -*- C++ -*-
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/Beam.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Projections/Hemispheres.hh"
#include "Rivet/Projections/ParisiTensor.hh"
#include "Rivet/Projections/Sphericity.hh"
#include "Rivet/Projections/Thrust.hh"

namespace Rivet {


  /// @brief DELPHI event shapes below the Z pole
  class DELPHI_2003_I620250 : public Analysis {
  public:

    /// Constructor
    RIVET_DEFAULT_ANALYSIS_CTOR(DELPHI_2003_I620250);


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

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

      // Initialise and register projections.
      declare(Beam(), "Beams");
      const FinalState fs;
      declare(fs, "FS");
      const Thrust thrust(fs);
      declare(thrust, "Thrust");
      declare(Sphericity(fs), "Sphericity");
      declare(ParisiTensor(fs), "Parisi");
      declare(Hemispheres(thrust), "Hemispheres");

      // Histogram booking offset numbers.
      size_t ih = 0, iy = 1;
      for (double eVal : allowedEnergies()) {

        const string en = toString(round(eVal));
        if (isCompatibleWithSqrtS(eVal)) {
          _sqs = en;
          skipBin = eVal < 200.;
          isDisc = eVal >= 100.;
        }

        book(_c[en], "_sumW_" + en);
        if (eVal < 100.) {
          book(_h[en + "thrust"], 1, 1, iy);
          book(_h[en + "major"], 2, 1, iy);
          book(_h[en + "minor"], 3, 1, iy);
          book(_h[en + "sphericity"], 4, 1, iy);
          book(_h[en + "planarity"], 5, 1, iy);
          book(_h[en + "oblateness"], 6, 1, iy);
          book(_h[en + "heavy_jet_mass"], 7, 1, iy);
          book(_h[en + "light_jet_mass"], 9, 1, iy);
          book(_h[en + "diff_jet_mass"], 10, 1, iy);
          book(_h[en + "total_jet_mass"], 11, 1, iy);
          book(_h[en + "heavy_jet_mass_E"], 8, 1, iy);
          book(_h[en + "total_jet_mass_E"], 12, 1, iy);
          book(_h[en + "wide_broading"], 13, 1, iy);
          book(_h[en + "narrow_broading"], 14, 1, iy);
          book(_h[en + "total_broading"], 15, 1, iy);
          book(_h[en + "diff_broading"], 16, 1, iy);
          book(_h[en + "CParam"], 17, 1, iy);
          if (iy == 3) iy = 0;
        }
        else {
          book(_d[en]["rap"], 30 + ih, 1, iy);
          book(_d[en]["xi"], 32 + ih, 1, iy);
          book(_d[en]["pTIn"], 34 + ih, 1, iy);
          book(_d[en]["pTOut"], 36 + ih, 1, iy);
          book(_d[en]["thrust"], 38 + ih, 1, iy);
          book(_d[en]["major"], 40 + ih, 1, iy);
          book(_d[en]["minor"], 42 + ih, 1, iy);
          book(_d[en]["oblateness"], 44 + ih, 1, iy);
          book(_d[en]["wide_broading"], 46 + ih, 1, iy);
          book(_d[en]["total_broading"], 48 + ih, 1, iy);
          book(_d[en]["diff_broading"], 50 + ih, 1, iy);
          book(_d[en]["CParam"], 52 + ih, 1, iy);
          book(_d[en]["DParam"], 54 + ih, 1, iy);
          book(_d[en]["heavy_jet_mass"], 56 + ih, 1, iy);
          book(_d[en]["heavy_jet_mass_P"], 58 + ih, 1, iy);
          book(_d[en]["heavy_jet_mass_E"], 60 + ih, 1, iy);
          book(_d[en]["light_jet_mass"], 62 + ih, 1, iy);
          book(_d[en]["diff_jet_mass"], 64 + ih, 1, iy);
          book(_d[en]["sphericity"], 66 + ih, 1, iy);
          book(_d[en]["planarity"], 68 + ih, 1, iy);
          book(_d[en]["aplanarity"], 70 + ih, 1, iy);
        }

        if (iy == 4) {
          ++ih;
          iy = 0;
        }
        ++iy;
      }
      raiseBeamErrorIf(_sqs.empty());

      _axis["rap"] = YODA::Axis<double>({0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.5});
      _axis["xi"] = YODA::Axis<double>(
          {0.0, 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 2.8, 3.2, 3.6, 4.0, 4.4, 4.8, 5.2, 5.6, 6.0, 6.4});
      _axis["pTIn"] = YODA::Axis<double>({0.0, 0.1, 0.4, 0.65, 0.9, 1.1, 1.4, 2.0, 3.0, 4.0, 6.0, 8.0, 12.0});
      _axis["pTOut"] = YODA::Axis<double>({0.0, 0.2, 0.4, 0.6, 0.85, 1.2, 1.6, 2.0, 3.0});
      _axis["thrust"] = YODA::Axis<double>({0.0,  0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09,
                                            0.10, 0.12, 0.14, 0.16, 0.18, 0.20, 0.24, 0.28, 0.32, 0.36});
      _axis["major"] = YODA::Axis<double>({0.0, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1,  0.12, 0.14, 0.16,
                                           0.2, 0.24, 0.28, 0.32, 0.36, 0.4,  0.44, 0.48, 0.52, 0.56, 0.6});
      _axis["minor"] = YODA::Axis<double>(
          {0.0, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.12, 0.14, 0.16, 0.2, 0.24, 0.28, 0.32});
      _axis["oblateness"] = YODA::Axis<double>({0.0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18,
                                                0.20, 0.24, 0.28, 0.32, 0.36, 0.4, 0.44});
      _axis["wide_broading"] = YODA::Axis<double>(
          {0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.12, 0.14, 0.17, 0.20, 0.24, 0.28});
      _axis["total_broading"] = YODA::Axis<double>({0.0,  0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07,
                                                    0.08, 0.09, 0.1,  0.11, 0.13, 0.15, 0.17, 0.19,
                                                    0.21, 0.24, 0.27, 0.3,  0.33, 0.36});
      _axis["diff_broading"] = YODA::Axis<double>({0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09,
                                                   0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.24, 0.28});
      _axis["CParam"] = YODA::Axis<double>({0.0,  0.04, 0.08, 0.12, 0.16, 0.2,  0.24, 0.28,
                                            0.32, 0.36, 0.4,  0.44, 0.48, 0.52, 0.56, 0.6,
                                            0.64, 0.68, 0.72, 0.76, 0.8,  0.84, 0.88});
      _axis["DParam"] = YODA::Axis<double>({0.00, 0.02, 0.04, 0.06, 0.08, 0.10, 0.12, 0.14, 0.16, 0.20, 0.24,
                                            0.28, 0.32, 0.36, 0.40, 0.44, 0.48, 0.54});
      _axis["heavy_jet_mass"] = YODA::Axis<double>(
          {0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.08, 0.10, 0.12, 0.14, 0.16, 0.20, 0.24, 0.28, 0.32});
      _axis["heavy_jet_mass_P"] = YODA::Axis<double>(
          {0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.2, 0.24, 0.28, 0.32});
      _axis["heavy_jet_mass_E"] = YODA::Axis<double>(
          {0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.08, 0.10, 0.12, 0.14, 0.16, 0.20, 0.24, 0.28, 0.32});
      _axis["light_jet_mass"] = YODA::Axis<double>({0.0, 0.01, 0.02, 0.03, 0.04, 0.05});
      _axis["diff_jet_mass"] = YODA::Axis<double>(
          {0.0, 0.01, 0.02, 0.03, 0.04, 0.06, 0.08, 0.12, 0.16, 0.2, 0.25, 0.3});
      _axis["sphericity"] = YODA::Axis<double>({0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.08, 0.1, 0.12,
                                                0.16, 0.2, 0.25, 0.3, 0.35, 0.4, 0.5, 0.6});
      _axis["planarity"] = YODA::Axis<double>(
          {0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.08, 0.1, 0.12, 0.16, 0.2, 0.25, 0.3, 0.35, 0.4});
      _axis["aplanarity"] = YODA::Axis<double>(
          {0.0, 0.004, 0.01, 0.016, 0.02, 0.03, 0.04, 0.06, 0.08, 0.1, 0.12, 0.16});
    }


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

      if (isDisc && _edges.empty()) {
        for (const auto& item : _axis) {
          _edges[item.first] = _d[_sqs][item.first]->xEdges();
        }
      }

      _c[_sqs]->fill();

      // Get beams and average beam momentum
      const ParticlePair& beams = apply<Beam>(event, "Beams").beams();
      const double meanBeamMom = (beams.first.p3().mod() + beams.second.p3().mod()) / 2.0;
      MSG_DEBUG("Avg beam momentum = " << meanBeamMom);

      const Thrust& thrust = apply<Thrust>(event, "Thrust");
      // sphericity related
      const Sphericity& sphericity = apply<Sphericity>(event, "Sphericity");
      // hemisphere related
      const Hemispheres& hemi = apply<Hemispheres>(event, "Hemispheres");
      smartfill("thrust", 1. - thrust.thrust());
      smartfill("major", thrust.thrustMajor());
      smartfill("minor", thrust.thrustMinor());
      smartfill("oblateness", thrust.oblateness());
      smartfill("sphericity", sphericity.sphericity());
      smartfill("planarity", sphericity.planarity());
      if (isDisc) smartfill("aplanarity", sphericity.aplanarity());
      smartfill("heavy_jet_mass", hemi.scaledM2high());
      smartfill("light_jet_mass", hemi.scaledM2low());
      smartfill("diff_jet_mass", hemi.scaledM2diff());
      smartfill("wide_broading", hemi.Bmax());
      if (!isDisc) smartfill("narrow_broading", hemi.Bmin());
      smartfill("total_broading", hemi.Bsum());
      smartfill("diff_broading", hemi.Bdiff());
      if (!isDisc) smartfill("total_jet_mass", hemi.scaledM2low() + hemi.scaledM2high());
      // E and p scheme jet masses
      Vector3 axis = thrust.thrustAxis();
      FourMomentum p4WithE, p4AgainstE;
      FourMomentum p4WithP, p4AgainstP;
      double Evis(0);
      for (const Particle& p : apply<FinalState>(event, "FS").particles()) {
        Vector3 p3 = p.momentum().vector3().unitVec();
        const double E = p.momentum().E();
        Evis += E;
        p3 = E * p3;
        const double p3Para = dot(p3, axis);
        FourMomentum p4E(E, p3.x(), p3.y(), p3.z());
        FourMomentum p4P(p.p3().mod(), p.p3().x(), p.p3().y(), p.p3().z());
        if (p3Para > 0) {
          p4WithE += p4E;
          p4WithP += p4P;
        }
        else if (p3Para < 0) {
          p4AgainstE += p4E;
          p4AgainstP += p4P;
        }
        else {
          MSG_WARNING("Particle split between hemispheres");
          p4WithE += 0.5 * p4E;
          p4AgainstE += 0.5 * p4E;
          p4WithP += 0.5 * p4P;
          p4AgainstP += 0.5 * p4P;
        }
      }
      // E scheme
      const double mass2With_E = p4WithE.mass2() / sqr(Evis);
      const double mass2Against_E = p4AgainstE.mass2() / sqr(Evis);
      // fill the histograms
      smartfill("heavy_jet_mass_E", max(mass2With_E, mass2Against_E));
      if (!isDisc) smartfill("total_jet_mass_E", mass2With_E + mass2Against_E);
      // pscheme
      const double mass2With_P = p4WithP.mass2() / sqr(Evis);
      const double mass2Against_P = p4AgainstP.mass2() / sqr(Evis);
      // fill the histograms
      if (isDisc) smartfill("heavy_jet_mass_P", max(mass2With_P, mass2Against_P));

      MSG_DEBUG("Calculating Parisi params");
      const ParisiTensor& parisi = apply<ParisiTensor>(event, "Parisi");
      smartfill("CParam", parisi.C());
      if (isDisc) smartfill("DParam", parisi.D());

      // single particle distributions
      const FinalState& fs = apply<FinalState>(event, "FS");
      if (isDisc) {
        for (const Particle& p : fs.particles()) {
          if (!PID::isCharged(p.pid())) continue;
          // Get momentum and energy of each particle.
          const Vector3 mom3 = p.p3();
          const double energy = p.E();

          // Scaled momenta.
          const double mom = mom3.mod();
          const double scaledMom = mom / meanBeamMom;
          const double logInvScaledMom = -std::log(scaledMom);
          smartfill("xi", logInvScaledMom);

          // Get momenta components w.r.t. thrust and sphericity.
          const double momT = dot(thrust.thrustAxis(), mom3);
          const double pTinT = dot(mom3, thrust.thrustMajorAxis());
          const double pToutT = dot(mom3, thrust.thrustMinorAxis());
          smartfill("pTIn", fabs(pTinT / GeV));
          smartfill("pTOut", fabs(pToutT / GeV));

          // Calculate rapidities w.r.t. thrust and sphericity.
          const double rapidityT = 0.5 * std::log((energy + momT) / (energy - momT));
          smartfill("rap", fabs(rapidityT));
          MSG_TRACE(fabs(rapidityT) << " " << scaledMom / GeV);
        }
      }
    }

    void smartfill(const string& tag, const double value) {
      if (isDisc) {
        size_t idx = _axis[tag].index(value);
        // skip masked bin in wide broadening
        if (tag == "wide_broading" && skipBin) {
          if (idx == 8)
            idx = 0;
          else if (idx > 8)
            --idx;
        }
        if (idx && idx <= _edges[tag].size()) {
          _d[_sqs][tag]->fill(_edges[tag][idx - 1]);
        }
        else {
          _d[_sqs][tag]->fill(string("OTHER"));
        }
      }
      else {
        _h[_sqs + tag]->fill(value);
      }
    }

    /// Normalise histograms etc., after the run
    void finalize() {
      normalize(_h);
      scale(_c, crossSectionPerEvent());
      scale(_d, crossSectionPerEvent());
      for (double eVal : allowedEnergies()) {
        const string en = toString(round(eVal));
        for (auto& item : _d[en]) {
          if (item.first == "rap" || item.first == "xi" || item.first == "pTIn" || item.first == "pTOut") {
            if (!isZero(_c[en]->sumW())) scale(item.second, 1.0 / _c[en]->sumW());
          }
          else
            normalize(item.second);
          for (auto& b : item.second->bins()) {
            size_t idx = b.index();
            // skip masked bin in wide broadening
            if (skipBin && item.first == "wide_broading") {
              if (idx >= 8) ++idx;
            }
            b.scaleW(1. / _axis[item.first].width(idx));
          }
        }
      }
    }

    /// @}


    /// @name Histograms
    /// @{
    map<string, map<string, BinnedHistoPtr<string>>> _d;
    map<string, YODA::Axis<double>> _axis;
    map<string, vector<string>> _edges;
    map<string, Histo1DPtr> _h;
    map<string, CounterPtr> _c;
    bool isDisc, skipBin;
    string _sqs = "";

    /// @}
  };


  RIVET_DECLARE_PLUGIN(DELPHI_2003_I620250);


}