rivet is hosted by Hepforge, IPPP Durham

Rivet analyses reference

ATLAS_2024_I2762099

WZ polarisation at 13 TeV
Experiment: ATLAS (LHC)
Inspire ID: 149992
Status: UNPHYSICAL
Authors:
  • Prachi Arvind Atmasiddha
  • Junjie Zhu
References: Beams: p+ p+
Beam energies: (6500.0, 6500.0) GeV
Run details:
  • pp -> lllv (+j) in the electron and muon channels

This Letter presents the first study of the energy dependence of diboson polarization fractions in $WZ\to \ell\nu\ell^\prime$ ($\ell,\ell^\prime = e,\mu$) production. The dataset used corresponds to an integrated luminosity of 140 fb$^{-1}$ of proton-proton collisions at a center-of-mass energy of 13 TeV recorded by the ATLAS detector. Two fiducial regions with an enhanced presence of events featuring two longitudinally polarized bosons are defined. A nonzero fraction of events with two longitudinally polarized bosons is measured with an observed significance of 5.3 standard deviations in the region with 100 $< p_\text{T}^Z<$ 200 GeV and 1.6 standard deviations in the region with $p_\text{T}^Z >$ 200 GeV, where $p_\text{T}^Z$ is the transverse momentum of the $Z$ boson. This Letter also reports the first study of the radiation-amplitude-zero effect. Events with two transversely polarized bosons are analyzed for the $\Delta Y(\ell_WZ)$ and $\Delta Y(WZ)$ distributions defined respectively as the rapidity difference between the lepton from the $W$ boson decay and the $Z$ boson and the rapidity difference between the $W$ boson and the $Z$ boson. Significant suppression of events near zero is observed in both distributions. Unfolded $\Delta Y(\ell_WZ)$ and $\Delta Y(WZ)$ distributions are also measured and compared to theoretical predictions. Users should note that explicit matching of lepton flavour between individual SM neutrinos and charged leptons is used in this analysis routine, to match the MC-based correction to the fiducial region applied in the paper. The data are therefore only valid under the assumption of the Standard Model and cannot be used for BSM reinterpretation.

Source code: ATLAS_2024_I2762099.cc
  1// -*- C++ -*-
  2
  3#include "Rivet/Analysis.hh"
  4#include "Rivet/Projections/FinalState.hh"
  5#include "Rivet/Projections/FastJets.hh"
  6#include "Rivet/Projections/VetoedFinalState.hh"
  7#include "Rivet/Projections/IdentifiedFinalState.hh"
  8#include "Rivet/Projections/MissingMomentum.hh"
  9#include "Rivet/Projections/LeptonFinder.hh"
 10#include "Rivet/Projections/PromptFinalState.hh"
 11
 12namespace Rivet {
 13
 14
 15  /// @brief WZ polarisation at 13 TeV
 16  class ATLAS_2024_I2762099 : public Analysis {
 17  public:
 18
 19    /// Constructor
 20    RIVET_DEFAULT_ANALYSIS_CTOR(ATLAS_2024_I2762099);
 21
 22    /// @name Analysis methods
 23    //@{
 24
 25    /// Book histograms and initialise projections before the run
 26    void init() {
 27
 28      // Get photons to dress leptons
 29      PromptFinalState photons(Cuts::abspid == PID::PHOTON);
 30
 31      // Electrons and muons in Fiducial PS
 32      PromptFinalState leptons(Cuts::abspid == PID::ELECTRON || Cuts::abspid == PID::MUON);
 33      LeptonFinder dressedleptons(leptons, photons, 0.1, Cuts::open());
 34      declare(dressedleptons, "DressedLeptons");
 35
 36      // Prompt neutrinos (yikes!)
 37      IdentifiedFinalState nu_id;
 38      nu_id.acceptNeutrinos();
 39      PromptFinalState neutrinos(nu_id);
 40      declare(neutrinos, "Neutrinos");
 41      MSG_WARNING("\033[91;1mLIMITED VALIDITY - check info file for details!\033[m");
 42
 43      // Muons
 44      PromptFinalState bare_mu(Cuts::abspid == PID::MUON, TauDecaysAs::PROMPT);
 45      LeptonFinder all_dressed_mu(bare_mu, photons, 0.1, Cuts::abseta < 2.5);
 46
 47      // Electrons
 48      PromptFinalState bare_el(Cuts::abspid == PID::ELECTRON, TauDecaysAs::PROMPT);
 49      LeptonFinder all_dressed_el(bare_el, photons, 0.1, Cuts::abseta < 2.5);
 50
 51      //Jet forming
 52      VetoedFinalState vfs(FinalState(Cuts::abseta < 5.0));
 53      vfs.addVetoOnThisFinalState(all_dressed_el);
 54      vfs.addVetoOnThisFinalState(all_dressed_mu);
 55
 56      FastJets jets(vfs, JetAlg::ANTIKT, 0.4, JetMuons::ALL, JetInvisibles::DECAY);
 57      declare(jets, "Jets");
 58
 59      // CUT 2 PtWZ < 20 GeV
 60      book(_h["PtWZ20CR_DY_WZ"],  25,1,1);
 61      book(_h["PtWZ20CR_DY_lWZ"], 22,1,1);
 62
 63      // CUT 2 PtWZ < 40 GeV
 64      book(_h["PtWZ40CR_DY_WZ"],  26,1,1);
 65      book(_h["PtWZ40CR_DY_lWZ"], 23,1,1);
 66
 67      // CUT 2 PtWZ < 70 GeV
 68      book(_h["PtWZ70CR_DY_WZ"],  27,1,1);
 69      book(_h["PtWZ70CR_DY_lWZ"], 24,1,1);
 70    }
 71
 72    void analyze(const Event& event) {
 73
 74      // Selection cuts
 75      const vector<DressedLepton>& dressedleptons = apply<LeptonFinder>(event, "DressedLeptons").dressedLeptons();
 76      const Particles& neutrinos = apply<PromptFinalState>(event, "Neutrinos").particlesByPt();
 77      Jets jets = apply<FastJets>(event, "Jets").jetsByPt();
 78
 79      int i, j, k;
 80      double MassZ01 = 0., MassZ02 = 0., MassZ12 = 0.;
 81      double MassW0 = 0., MassW1 = 0., MassW2 = 0.;
 82      double WeightZ1, WeightZ2, WeightZ3;
 83      double WeightW1, WeightW2, WeightW3;
 84      double M1, M2, M3;
 85      double WeightTotal1, WeightTotal2, WeightTotal3;
 86
 87      //---Fiducial PS: assign leptons to W and Z bosons using Resonant shape algorithm
 88      if (dressedleptons.size() < 3 || neutrinos.size() < 1)  vetoEvent;
 89
 90      int icomb = 0;
 91      // try Z pair of leptons 01
 92      if ( (dressedleptons[0].pid() == -(dressedleptons[1].pid())) &&
 93           (dressedleptons[2].pid()*neutrinos[0].pid()< 0) &&
 94           (dressedleptons[2].abspid()==neutrinos[0].abspid()-1) ) {
 95        MassZ01 = (dressedleptons[0].mom() + dressedleptons[1].mom()).mass();
 96        MassW2 = (dressedleptons[2].mom() + neutrinos[0].mom()).mass();
 97        icomb = 1;
 98      }
 99      // try Z pair of leptons 02
100      if ( (dressedleptons[0].pid() == -(dressedleptons[2].pid())) &&
101           (dressedleptons[1].pid()*neutrinos[0].pid()< 0) &&
102           (dressedleptons[1].abspid()==neutrinos[0].abspid()-1) ) {
103        MassZ02 = (dressedleptons[0].mom() + dressedleptons[2].mom()).mass();
104        MassW1 = (dressedleptons[1].mom() + neutrinos[0].mom()).mass();
105        icomb = 2;
106      }
107      // try Z pair of leptons 12
108      if ( (dressedleptons[1].pid() == -(dressedleptons[2].pid())) &&
109         (dressedleptons[0].pid()*neutrinos[0].pid()< 0) &&
110         (dressedleptons[0].abspid()==neutrinos[0].abspid()-1) ) {
111        MassZ12 = (dressedleptons[1].mom() + dressedleptons[2].mom()).mass();
112        MassW0 = (dressedleptons[0].mom() + neutrinos[0].mom()).mass();
113        icomb = 3;
114      }
115
116      if (icomb<=0) vetoEvent;
117
118      WeightZ1 = 1/(sqr(MassZ01*MassZ01 - MZ_PDG*MZ_PDG) + sqr(MZ_PDG*GammaZ_PDG));
119      WeightW1 = 1/(sqr(MassW2*MassW2 - MW_PDG*MW_PDG) + sqr(MW_PDG*GammaW_PDG));
120      WeightTotal1 = WeightZ1*WeightW1;
121      M1 = -1*WeightTotal1;
122
123      WeightZ2 = 1/(sqr(MassZ02*MassZ02- MZ_PDG*MZ_PDG) + sqr(MZ_PDG*GammaZ_PDG));
124      WeightW2 = 1/(sqr(MassW1*MassW1- MW_PDG*MW_PDG) + sqr(MW_PDG*GammaW_PDG));
125      WeightTotal2 = WeightZ2*WeightW2;
126      M2 = -1*WeightTotal2;
127
128      WeightZ3 = 1/(sqr(MassZ12*MassZ12 - MZ_PDG*MZ_PDG) + sqr(MZ_PDG*GammaZ_PDG));
129      WeightW3 = 1/(sqr(MassW0*MassW0 - MW_PDG*MW_PDG) + sqr(MW_PDG*GammaW_PDG));
130      WeightTotal3 = WeightZ3*WeightW3;
131      M3 = -1*WeightTotal3;
132
133      if( (M1 < M2 && M1 < M3) || (MassZ01 != 0 && MassW2 != 0 && MassZ02 == 0 && MassZ12 == 0) ) {
134        i = 0; j = 1; k = 2;
135      }
136      if((M2 < M1 && M2 < M3) || (MassZ02 != 0 && MassW1 != 0 && MassZ01 == 0 && MassZ12 == 0) ) {
137        i = 0; j = 2; k = 1;
138      }
139      if((M3 < M1 && M3 < M2) || (MassZ12 != 0 && MassW0 != 0 && MassZ01 == 0 && MassZ02 == 0) ) {
140        i = 1; j = 2; k = 0;
141      }
142
143      DressedLepton Z_Lep_1 = dressedleptons[i];
144      DressedLepton Z_Lep_2 = dressedleptons[j];
145      DressedLepton W_Lep = dressedleptons[k];
146
147      FourMomentum Zlepton1 = dressedleptons[i].mom();
148      FourMomentum Zlepton2 = dressedleptons[j].mom();
149      FourMomentum Wlepton  = dressedleptons[k].mom();
150      FourMomentum Zboson   = dressedleptons[i].mom()+dressedleptons[j].mom();
151      FourMomentum Wboson   = dressedleptons[k].mom()+neutrinos[0].mom();
152
153      const double pT_WZ = (Wboson+Zboson).pT();
154
155      double cosLepNeut;
156      double norm = Wlepton.pT() * neutrinos[0].pt();
157      double mTW = 0;
158      if (norm != 0){
159        cosLepNeut = ( Wlepton.px()*neutrinos[0].px() + Wlepton.py()*neutrinos[0].py() )/norm ;
160        if(1-cosLepNeut >= 0 ) mTW = sqrt( 2 * Wlepton.pT() * neutrinos[0].pt() * (1-cosLepNeut ) );
161      }
162
163      //========================================================================================================//
164      //=========================== Using RIVET to calculate all the kinematic variables =======================//
165      //========================================================================================================//
166
167      // For kinematic variable calculations
168      FourMomentum WZ, W_WZframe, Z_WZframe, Wlep_WZframe, ZlepM_WZframe, ZlepP_WZframe;
169      FourMomentum Wlep_Wframe, Wlep_Wframe_WZ, ZlepM_Zframe, ZlepM_Zframe_WZ, ZlepP_Zframe, ZlepP_Zframe_WZ;
170
171      WZ = Zboson+Wboson;
172
173      W_WZframe = Wboson;
174      Z_WZframe = Zboson;
175      Wlep_WZframe = Wlepton;
176
177      FourMomentum ZleptonM, ZleptonP;
178
179      if (Z_Lep_1.pid()>0) {
180        ZleptonM = Zlepton1;
181        ZleptonP = Zlepton2;
182      }
183      else {
184        ZleptonM = Zlepton2;
185        ZleptonP = Zlepton1;
186      }
187
188      ZlepM_WZframe = ZleptonM;
189      ZlepP_WZframe = ZleptonP;
190
191      LorentzTransform LT_WZ = LorentzTransform();
192      LT_WZ = LT_WZ.mkObjTransformFromBeta(-(WZ.betaVec()));
193
194      W_WZframe = LT_WZ.transform(W_WZframe);
195      Z_WZframe = LT_WZ.transform(Z_WZframe);
196      Wlep_WZframe = LT_WZ.transform(Wlep_WZframe);
197      ZlepM_WZframe = LT_WZ.transform(ZlepM_WZframe);
198      ZlepP_WZframe = LT_WZ.transform(ZlepP_WZframe);
199
200      Wlep_Wframe = Wlepton;
201      Wlep_Wframe_WZ = Wlep_WZframe;
202      ZlepM_Zframe = ZleptonM;
203      ZlepM_Zframe_WZ = ZlepM_WZframe;
204      ZlepP_Zframe = ZleptonP;
205      ZlepP_Zframe_WZ = ZlepP_WZframe;
206
207      LorentzTransform LT_W = LorentzTransform();
208      LT_W = LT_W.mkObjTransformFromBeta(-(Wboson.betaVec()));
209
210      LorentzTransform LT_Z = LorentzTransform();
211      LT_Z = LT_Z.mkObjTransformFromBeta(-(Zboson.betaVec()));
212
213      Wlep_Wframe = LT_W.transform(Wlep_Wframe);
214      ZlepM_Zframe = LT_Z.transform(ZlepM_Zframe);
215      ZlepP_Zframe = LT_Z.transform(ZlepP_Zframe);
216
217      LorentzTransform LT_W_WZ = LorentzTransform();
218      LT_W_WZ = LT_W_WZ.mkObjTransformFromBeta(-(W_WZframe.betaVec()));
219
220      LorentzTransform LT_Z_WZ = LorentzTransform();
221      LT_Z_WZ = LT_Z_WZ.mkObjTransformFromBeta(-(Z_WZframe.betaVec()));
222
223      Wlep_Wframe_WZ = LT_W_WZ.transform(Wlep_Wframe_WZ);
224      ZlepM_Zframe_WZ = LT_Z_WZ.transform(ZlepM_Zframe_WZ);
225      ZlepP_Zframe_WZ = LT_Z_WZ.transform(ZlepP_Zframe_WZ);
226
227      Jets jets30;
228      for (const Jet& jet : jets){
229        if (jet.pt() > 30.*GeV && jet.abseta() < 4.5 &&
230            deltaR(Zlepton1, jet.mom()) > 0.3 &&
231            deltaR(Zlepton2, jet.mom()) > 0.3 &&
232            deltaR(Wlepton, jet.mom())  > 0.3) {
233          jets30 += jet;
234        }
235      }
236
237      const double DY_WZ = Zboson.rap() - Wboson.rap();
238      const double DY_lWZ = Zboson.rap() - Wlepton.rap();
239
240      if (Wlepton.pT() <= 20*GeV || Zlepton1.pT() <= 15*GeV || Zlepton2.pT() <= 15*GeV)     vetoEvent;
241      if (Wlepton.abseta() >= 2.5 || Zlepton1.abseta() >= 2.5 || Zlepton2.abseta() >= 2.5)  vetoEvent;
242      if (fabs(Zboson.mass()/GeV - MZ_PDG) >= 10.)  vetoEvent;
243      if (mTW <= 30*GeV)                            vetoEvent;
244      if (deltaR(Zlepton1, Zlepton2) <= 0.2)        vetoEvent;
245      if (deltaR(Zlepton1, Wlepton)  <= 0.3)        vetoEvent;
246      if (deltaR(Zlepton2, Wlepton)  <= 0.3)        vetoEvent;
247
248      // Selection cuts
249      if (pT_WZ >= 70)  vetoEvent;
250      _h["PtWZ70CR_DY_WZ"]->fill(fabs(DY_WZ));
251      _h["PtWZ70CR_DY_lWZ"]->fill(fabs(DY_lWZ));
252
253      if (pT_WZ >= 40)  vetoEvent;
254      _h["PtWZ40CR_DY_WZ"]->fill(fabs(DY_WZ));
255      _h["PtWZ40CR_DY_lWZ"]->fill(fabs(DY_lWZ));
256
257      if (pT_WZ >= 20)  vetoEvent;
258      _h["PtWZ20CR_DY_WZ"]->fill(fabs(DY_WZ));
259      _h["PtWZ20CR_DY_lWZ"]->fill(fabs(DY_lWZ));
260
261    }
262
263    void finalize() {
264
265      normalize(_h);
266
267    }
268
269    //@}
270
271
272  private:
273
274
275    /// @name Histograms
276    //@{
277
278    map<string,Histo1DPtr> _h;
279
280    //@}
281
282    const double MZ_PDG = 91.1876;
283    const double MW_PDG = 83.385;
284    const double GammaZ_PDG = 2.4952;
285    const double GammaW_PDG = 2.085;
286
287  };
288
289  // The hook for the plugin system
290  RIVET_DECLARE_PLUGIN(ATLAS_2024_I2762099);
291}