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