rivet is hosted by Hepforge, IPPP Durham
ATLAS_2012_I1203852.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Analysis.hh"
00003 #include "Rivet/Projections/FastJets.hh"
00004 #include "Rivet/Projections/FinalState.hh"
00005 #include "Rivet/Projections/IdentifiedFinalState.hh"
00006 #include "Rivet/Projections/WFinder.hh"
00007 #include "Rivet/Projections/LeadingParticlesFinalState.hh"
00008 #include "Rivet/Projections/UnstableFinalState.hh"
00009 #include "Rivet/Projections/VetoedFinalState.hh"
00010 #include "Rivet/Projections/DressedLeptons.hh"
00011 #include "Rivet/Projections/MergedFinalState.hh"
00012 #include "Rivet/Projections/MissingMomentum.hh"
00013 #include "Rivet/Projections/InvMassFinalState.hh"
00014 
00015 #define ZMASS 91.1876 // GeV
00016 
00017 namespace Rivet {
00018 
00019 
00020   /// Generic Z candidate
00021   struct Zstate : public ParticlePair {
00022     Zstate() { }
00023     Zstate(ParticlePair _particlepair) : ParticlePair(_particlepair) { }
00024     FourMomentum mom() const { return first.momentum() + second.momentum(); }
00025     operator FourMomentum() const { return mom(); }
00026     static bool cmppT(const Zstate& lx, const Zstate& rx) { return lx.mom().pT() < rx.mom().pT(); }
00027   };
00028 
00029 
00030   /// 4l to ZZ assignment -- algorithm
00031   void identifyZstates(Zstate& Z1, Zstate& Z2, const Particles& leptons_sel4l) {
00032 
00033     /////////////////////////////////////////////////////////////////////////////
00034     /// ZZ->4l pairing
00035     /// - Exactly two same flavour opposite charged leptons
00036     /// - Ambiguities in pairing are resolved by choosing the combination
00037     ///     that results in the smaller value of the sum |mll - mZ| for the two pairs
00038     /////////////////////////////////////////////////////////////////////////////
00039 
00040     Particles part_pos_el, part_neg_el, part_pos_mu, part_neg_mu;
00041     foreach (const Particle& l , leptons_sel4l) {
00042       if (l.abspid() == PID::ELECTRON) {
00043         if (l.pid() < 0) part_neg_el.push_back(l);
00044         if (l.pid() > 0) part_pos_el.push_back(l);
00045       }
00046       else if (l.abspid() == PID::MUON) {
00047         if (l.pid() < 0) part_neg_mu.push_back(l);
00048         if (l.pid() > 0) part_pos_mu.push_back(l);
00049       }
00050     }
00051 
00052     // ee/mm channel
00053     if ( part_neg_el.size() == 2 || part_neg_mu.size() == 2) {
00054 
00055       Zstate Zcand_1, Zcand_2, Zcand_3, Zcand_4;
00056       if (part_neg_el.size() == 2) { // ee
00057         Zcand_1 = Zstate( ParticlePair( part_neg_el[0],  part_pos_el[0] ) );
00058         Zcand_2 = Zstate( ParticlePair( part_neg_el[0],  part_pos_el[1] ) );
00059         Zcand_3 = Zstate( ParticlePair( part_neg_el[1],  part_pos_el[0] ) );
00060         Zcand_4 = Zstate( ParticlePair( part_neg_el[1],  part_pos_el[1] ) );
00061       } else { // mumu
00062         Zcand_1 = Zstate( ParticlePair( part_neg_mu[0],  part_pos_mu[0] ) );
00063         Zcand_2 = Zstate( ParticlePair( part_neg_mu[0],  part_pos_mu[1] ) );
00064         Zcand_3 = Zstate( ParticlePair( part_neg_mu[1],  part_pos_mu[0] ) );
00065         Zcand_4 = Zstate( ParticlePair( part_neg_mu[1],  part_pos_mu[1] ) );
00066       }
00067 
00068       // We can have the following pairs: (Z1 + Z4) || (Z2 + Z3)
00069       double minValue_1, minValue_2;
00070       minValue_1 = fabs( Zcand_1.mom().mass() - ZMASS ) + fabs( Zcand_4.mom().mass() - ZMASS);
00071       minValue_2 = fabs( Zcand_2.mom().mass() - ZMASS ) + fabs( Zcand_3.mom().mass() - ZMASS);
00072       if (minValue_1 < minValue_2 ) {
00073         Z1 = Zcand_1;
00074         Z2 = Zcand_4;
00075       } else {
00076         Z1 = Zcand_2;
00077         Z2 = Zcand_3;
00078       }
00079 
00080     // emu channel
00081     } else if (part_neg_mu.size() == 1 && part_neg_el.size() == 1) {
00082       Z1 = Zstate ( ParticlePair (part_neg_mu[0],  part_pos_mu[0] ) );
00083       Z2 = Zstate ( ParticlePair (part_neg_el[0],  part_pos_el[0] ) );
00084     }
00085 
00086   }
00087 
00088 
00089   /// @name ZZ analysis
00090   class ATLAS_2012_I1203852 : public Analysis {
00091   public:
00092 
00093     /// Default constructor
00094     ATLAS_2012_I1203852()
00095       : Analysis("ATLAS_2012_I1203852")
00096     {    }
00097 
00098     void init() {
00099       FinalState fs(-5.0, 5.0, 0.0*GeV);
00100 
00101       // Final states to form Z bosons
00102       vids.push_back(make_pair(PID::ELECTRON, PID::POSITRON));
00103       vids.push_back(make_pair(PID::MUON, PID::ANTIMUON));
00104 
00105       vnuids.push_back(make_pair(PID::NU_E, PID::NU_EBAR) );
00106       vnuids.push_back(make_pair(PID::NU_MU, PID::NU_MUBAR) );
00107       vnuids.push_back(make_pair(PID::NU_TAU, PID::NU_TAUBAR) );
00108 
00109       IdentifiedFinalState Photon(fs);
00110       Photon.acceptIdPair(PID::PHOTON);
00111 
00112       IdentifiedFinalState bare_EL(fs);
00113       bare_EL.acceptIdPair(PID::ELECTRON);
00114 
00115       IdentifiedFinalState bare_MU(fs);
00116       bare_MU.acceptIdPair(PID::MUON);
00117 
00118 
00119       // Selection 1: ZZ-> llll selection
00120       Cut etaranges_lep = Cuts::abseta < 3.16 && Cuts::pT > 7*GeV;
00121 
00122       DressedLeptons electron_sel4l(Photon, bare_EL, 0.1, etaranges_lep);
00123       addProjection(electron_sel4l, "ELECTRON_sel4l");
00124       DressedLeptons muon_sel4l(Photon, bare_MU, 0.1, etaranges_lep);
00125       addProjection(muon_sel4l, "MUON_sel4l");
00126 
00127 
00128       // Selection 2: ZZ-> llnunu selection
00129       Cut etaranges_lep2 = Cuts::abseta < 2.5 && Cuts::pT > 10*GeV;
00130 
00131       DressedLeptons electron_sel2l2nu(Photon, bare_EL, 0.1, etaranges_lep2);
00132       addProjection(electron_sel2l2nu, "ELECTRON_sel2l2nu");
00133       DressedLeptons muon_sel2l2nu(Photon, bare_MU, 0.1, etaranges_lep2);
00134       addProjection(muon_sel2l2nu, "MUON_sel2l2nu");
00135 
00136 
00137       /// Get all neutrinos. These will not be used to form jets.
00138       /// We'll use the highest 2 pT neutrinos to calculate the MET
00139       IdentifiedFinalState neutrino_fs(Cuts::abseta < 4.5);
00140       neutrino_fs.acceptNeutrinos();
00141       addProjection(neutrino_fs, "NEUTRINO_FS");
00142 
00143       VetoedFinalState jetinput;
00144       jetinput.addVetoOnThisFinalState(bare_MU);
00145       jetinput.addVetoOnThisFinalState(neutrino_fs);
00146 
00147       FastJets jetpro(fs, FastJets::ANTIKT, 0.4);
00148       addProjection(jetpro, "jet");
00149 
00150       // Both ZZ on-shell histos
00151       _h_ZZ_xsect = bookHisto1D(1, 1, 1);
00152       _h_ZZ_ZpT   = bookHisto1D(3, 1, 1);
00153       _h_ZZ_phill = bookHisto1D(5, 1, 1);
00154       _h_ZZ_mZZ   = bookHisto1D(7, 1, 1);
00155 
00156       // One Z off-shell (ZZstar) histos
00157       _h_ZZs_xsect = bookHisto1D(1, 1, 2);
00158 
00159       // ZZ -> llnunu histos
00160       _h_ZZnunu_xsect = bookHisto1D(1, 1, 3);
00161       _h_ZZnunu_ZpT   = bookHisto1D(4, 1, 1);
00162       _h_ZZnunu_phill = bookHisto1D(6, 1, 1);
00163       _h_ZZnunu_mZZ   = bookHisto1D(8, 1, 1);
00164     }
00165 
00166 
00167     /// Do the analysis
00168     void analyze(const Event& e) {
00169       const double weight = e.weight();
00170 
00171       ////////////////////////////////////////////////////////////////////
00172       // preselection of leptons for ZZ-> llll final state
00173       ////////////////////////////////////////////////////////////////////
00174 
00175       Particles leptons_sel4l;
00176 
00177       const vector<DressedLepton>& mu_sel4l = applyProjection<DressedLeptons>(e, "MUON_sel4l").dressedLeptons();
00178       const vector<DressedLepton>& el_sel4l = applyProjection<DressedLeptons>(e, "ELECTRON_sel4l").dressedLeptons();
00179 
00180       vector<DressedLepton> leptonsFS_sel4l;
00181       leptonsFS_sel4l.insert( leptonsFS_sel4l.end(), mu_sel4l.begin(), mu_sel4l.end() );
00182       leptonsFS_sel4l.insert( leptonsFS_sel4l.end(), el_sel4l.begin(), el_sel4l.end() );
00183 
00184       ////////////////////////////////////////////////////////////////////
00185       // OVERLAP removal dR(l,l)>0.2
00186       ////////////////////////////////////////////////////////////////////
00187       foreach ( const DressedLepton& l1, leptonsFS_sel4l) {
00188         bool isolated = true;
00189         foreach (DressedLepton& l2, leptonsFS_sel4l) {
00190           const double dR = deltaR(l1, l2);
00191           if (dR < 0.2 && l1 != l2) { isolated = false; break; }
00192         }
00193         if (isolated) leptons_sel4l.push_back(l1);
00194       }
00195 
00196       //////////////////////////////////////////////////////////////////
00197       // Exactly two opposite charged leptons
00198       //////////////////////////////////////////////////////////////////
00199 
00200       // calculate total 'flavour' charge
00201       double totalcharge = 0;
00202       foreach (Particle& l, leptons_sel4l) totalcharge += l.pid();
00203 
00204       // Analyze 4 lepton events
00205       if (leptons_sel4l.size() == 4 && totalcharge == 0  ) {
00206         Zstate Z1, Z2;
00207 
00208         // Identifies Z states from 4 lepton pairs
00209         identifyZstates(Z1, Z2,leptons_sel4l);
00210 
00211         ////////////////////////////////////////////////////////////////////////////
00212         // Z MASS WINDOW
00213         //  -ZZ: for both Z: 66<mZ<116 GeV
00214         //  -ZZ*: one Z on-shell: 66<mZ<116 GeV, one Z off-shell: mZ>20 GeV
00215         ///////////////////////////////////////////////////////////////////////////
00216 
00217         Zstate leadPtZ = std::max(Z1, Z2, Zstate::cmppT);
00218 
00219         double mZ1   = Z1.mom().mass();
00220         double mZ2   = Z2.mom().mass();
00221         double ZpT   = leadPtZ.mom().pT();
00222         double phill = fabs(deltaPhi(leadPtZ.first, leadPtZ.second));
00223         if (phill > M_PI) phill = 2*M_PI-phill;
00224         double mZZ   = (Z1.mom() + Z2.mom()).mass();
00225 
00226         if (mZ1 > 20*GeV && mZ2 > 20*GeV) {
00227           // ZZ* selection
00228           if (inRange(mZ1, 66*GeV, 116*GeV) || inRange(mZ2, 66*GeV, 116*GeV)) {
00229             _h_ZZs_xsect  -> fill(sqrtS()*GeV,  weight);
00230           }
00231 
00232           // ZZ selection
00233           if (inRange(mZ1, 66*GeV, 116*GeV) && inRange(mZ2, 66*GeV, 116*GeV)) {
00234             _h_ZZ_xsect  -> fill(sqrtS()*GeV,  weight);
00235             _h_ZZ_ZpT    -> fill(ZpT   , weight);
00236             _h_ZZ_phill  -> fill(phill , weight);
00237             _h_ZZ_mZZ    -> fill(mZZ   , weight);
00238           }
00239         }
00240       }
00241 
00242       ////////////////////////////////////////////////////////////////////
00243       /// preselection of leptons for ZZ-> llnunu final state
00244       ////////////////////////////////////////////////////////////////////
00245 
00246       Particles leptons_sel2l2nu; // output
00247       const vector<DressedLepton>& mu_sel2l2nu = applyProjection<DressedLeptons>(e, "MUON_sel2l2nu").dressedLeptons();
00248       const vector<DressedLepton>& el_sel2l2nu = applyProjection<DressedLeptons>(e, "ELECTRON_sel2l2nu").dressedLeptons();
00249 
00250       vector<DressedLepton> leptonsFS_sel2l2nu;
00251       leptonsFS_sel2l2nu.insert( leptonsFS_sel2l2nu.end(), mu_sel2l2nu.begin(), mu_sel2l2nu.end() );
00252       leptonsFS_sel2l2nu.insert( leptonsFS_sel2l2nu.end(), el_sel2l2nu.begin(), el_sel2l2nu.end() );
00253 
00254       // Lepton preselection for ZZ-> llnunu
00255       if ((mu_sel2l2nu.empty() || el_sel2l2nu.empty()) // cannot have opposite flavour
00256            && (leptonsFS_sel2l2nu.size() == 2) // exactly two leptons
00257            && (leptonsFS_sel2l2nu[0].charge() * leptonsFS_sel2l2nu[1].charge() < 1 ) // opposite charge
00258            && (deltaR(leptonsFS_sel2l2nu[0], leptonsFS_sel2l2nu[1]) > 0.3) // overlap removal
00259            && (leptonsFS_sel2l2nu[0].pT() > 20*GeV && leptonsFS_sel2l2nu[1].pT() > 20*GeV)) { // trigger requirement
00260         leptons_sel2l2nu.insert(leptons_sel2l2nu.end(), leptonsFS_sel2l2nu.begin(), leptonsFS_sel2l2nu.end());
00261       }
00262       if (leptons_sel2l2nu.empty()) vetoEvent; // no further analysis, fine to veto
00263 
00264       Particles leptons_sel2l2nu_jetveto;
00265       foreach (const DressedLepton& l, mu_sel2l2nu) leptons_sel2l2nu_jetveto.push_back(l.constituentLepton());
00266       foreach (const DressedLepton& l, el_sel2l2nu) leptons_sel2l2nu_jetveto.push_back(l.constituentLepton());
00267       double ptll = (leptons_sel2l2nu[0].momentum() + leptons_sel2l2nu[1].momentum()).pT();
00268 
00269       // Find Z1-> ll
00270       FinalState fs2(-3.2, 3.2);
00271       InvMassFinalState imfs(fs2, vids, 20*GeV, sqrtS());
00272       imfs.calc(leptons_sel2l2nu);
00273       if (imfs.particlePairs().size() != 1) vetoEvent;
00274       const ParticlePair& Z1constituents = imfs.particlePairs()[0];
00275       FourMomentum Z1 = Z1constituents.first.momentum() + Z1constituents.second.momentum();
00276 
00277       // Find Z2-> nunu
00278       const Particles& neutrinoFS = applyProjection<IdentifiedFinalState>(e, "NEUTRINO_FS").particlesByPt();
00279       FinalState fs3(-4.5, 4.5);
00280       InvMassFinalState imfs_Znunu(fs3, vnuids, 20*GeV, sqrtS(), ZMASS);
00281       imfs_Znunu.calc(neutrinoFS);
00282       if (imfs_Znunu.particlePairs().size() == 0 ) vetoEvent;
00283 
00284       // Z to neutrinos
00285       FourMomentum Z2 = imfs_Znunu.particlePairs()[0].first.momentum() + imfs_Znunu.particlePairs()[0].second.momentum();
00286       double met_Znunu = Z2.pT();
00287 
00288       // mTZZ
00289       const double mT2_1st_term = add_quad(ZMASS, ptll) + add_quad(ZMASS, met_Znunu);
00290       const double mT2_2nd_term = Z1.px() + Z2.px();
00291       const double mT2_3rd_term = Z1.py() + Z2.py();
00292       const double mTZZ = sqrt(sqr(mT2_1st_term) - sqr(mT2_2nd_term) - sqr(mT2_3rd_term));
00293 
00294       if (!inRange(Z2.mass(), 66*GeV, 116*GeV)) vetoEvent;
00295       if (!inRange(Z1.mass(), 76*GeV, 106*GeV)) vetoEvent;
00296 
00297       /////////////////////////////////////////////////////////////
00298       // AXIAL MET < 75 GeV
00299       ////////////////////////////////////////////////////////////
00300 
00301       double dPhiZ1Z2 = fabs(deltaPhi(Z1, Z2));
00302       if (dPhiZ1Z2 > M_PI) dPhiZ1Z2 = 2*M_PI - dPhiZ1Z2;
00303       const double axialEtmiss = -Z2.pT()*cos(dPhiZ1Z2);
00304       if (axialEtmiss < 75*GeV) vetoEvent;
00305 
00306       const double ZpT   = Z1.pT();
00307       double phill = fabs(deltaPhi(Z1constituents.first, Z1constituents.second));
00308       if (phill > M_PI) phill = 2*M_PI - phill;
00309 
00310 
00311       ////////////////////////////////////////////////////////////////////////////
00312       // JETS
00313       //    -"j": found by "jetpro" projection && pT() > 25 GeV && |eta| < 4.5
00314       //    -"goodjets": "j"  && dR(electron/muon,jet) > 0.3
00315       //
00316       // JETVETO: veto all events with at least one good jet
00317       ///////////////////////////////////////////////////////////////////////////
00318       vector<Jet> good_jets;
00319       foreach (const Jet& j, applyProjection<FastJets>(e, "jet").jetsByPt(25)) {
00320         if (j.abseta() > 4.5) continue;
00321         bool isLepton = 0;
00322         foreach (const Particle& l, leptons_sel2l2nu_jetveto) {
00323           const double dR = deltaR(l.momentum(), j.momentum());
00324           if (dR < 0.3) { isLepton = true; break; }
00325         }
00326         if (!isLepton) good_jets.push_back(j);
00327       }
00328       size_t n_sel_jets = good_jets.size();
00329       if (n_sel_jets != 0) vetoEvent;
00330 
00331 
00332       /////////////////////////////////////////////////////////////
00333       // Fractional MET and lepton pair difference: "RatioMet"< 0.4
00334       ////////////////////////////////////////////////////////////
00335       double ratioMet = fabs(Z2.pT() - Z1.pT()) / Z1.pT();
00336       if (ratioMet  > 0.4 ) vetoEvent;
00337 
00338 
00339       // End of ZZllnunu selection: now fill histograms
00340       _h_ZZnunu_xsect->fill(sqrtS()/GeV, weight);
00341       _h_ZZnunu_ZpT  ->fill(ZpT, weight);
00342       _h_ZZnunu_phill->fill(phill, weight);
00343       _h_ZZnunu_mZZ  ->fill(mTZZ, weight);
00344 
00345     }
00346 
00347 
00348     /// Finalize
00349     void finalize() {
00350       const double norm = crossSection()/sumOfWeights()/femtobarn;
00351 
00352       scale(_h_ZZ_xsect, norm);
00353       normalize(_h_ZZ_ZpT);
00354       normalize(_h_ZZ_phill);
00355       normalize(_h_ZZ_mZZ);
00356 
00357       scale(_h_ZZs_xsect, norm);
00358       scale(_h_ZZnunu_xsect, norm);
00359       normalize(_h_ZZnunu_ZpT);
00360       normalize(_h_ZZnunu_phill);
00361       normalize(_h_ZZnunu_mZZ);
00362     }
00363 
00364 
00365   private:
00366 
00367     Histo1DPtr _h_ZZ_xsect, _h_ZZ_ZpT, _h_ZZ_phill, _h_ZZ_mZZ;
00368     Histo1DPtr _h_ZZs_xsect;
00369     Histo1DPtr _h_ZZnunu_xsect, _h_ZZnunu_ZpT, _h_ZZnunu_phill, _h_ZZnunu_mZZ;
00370     vector< pair<PdgId,PdgId> > vids, vnuids;
00371 
00372   };
00373 
00374 
00375   // The hook for the plugin system
00376   DECLARE_RIVET_PLUGIN(ATLAS_2012_I1203852);
00377 
00378 }