rivet is hosted by Hepforge, IPPP Durham
MC_TTBAR.cc
Go to the documentation of this file.
00001 #include "Rivet/Analysis.hh"
00002 #include "Rivet/Projections/FinalState.hh"
00003 #include "Rivet/Projections/VetoedFinalState.hh"
00004 #include "Rivet/Projections/ChargedLeptons.hh"
00005 #include "Rivet/Projections/MissingMomentum.hh"
00006 #include "Rivet/Projections/FastJets.hh"
00007 #include "Rivet/AnalysisLoader.hh"
00008 #include "Rivet/RivetYODA.hh"
00009 
00010 namespace Rivet {
00011 
00012 
00013   class MC_TTBAR : public Analysis {
00014   public:
00015 
00016     /// Minimal constructor
00017     MC_TTBAR() : Analysis("MC_TTBAR")
00018     {
00019     }
00020 
00021 
00022     /// @name Analysis methods
00023     //@{
00024 
00025     /// Set up projections and book histograms
00026     void init() {
00027 
00028       // A FinalState is used to select particles within |eta| < 4.2 and with pT
00029       // > 30 GeV, out of which the ChargedLeptons projection picks only the
00030       // electrons and muons, to be accessed later as "LFS".
00031       ChargedLeptons lfs(FinalState(-4.2, 4.2, 30*GeV));
00032       addProjection(lfs, "LFS");
00033       // A second FinalState is used to select all particles in |eta| < 4.2,
00034       // with no pT cut. This is used to construct jets and measure missing
00035       // transverse energy.
00036       VetoedFinalState fs(FinalState(-4.2, 4.2, 0*GeV));
00037       fs.addVetoOnThisFinalState(lfs);
00038       addProjection(FastJets(fs, FastJets::ANTIKT, 0.6), "Jets");
00039       addProjection(MissingMomentum(fs), "MissingET");
00040 
00041       // Booking of histograms
00042       _h_njets = bookHisto1D("jet_mult", 11, -0.5, 10.5);
00043       //
00044       _h_jet_1_pT = bookHisto1D("jet_1_pT", logspace(50, 20.0, 500.0));
00045       _h_jet_2_pT = bookHisto1D("jet_2_pT", logspace(50, 20.0, 400.0));
00046       _h_jet_3_pT = bookHisto1D("jet_3_pT", logspace(50, 20.0, 300.0));
00047       _h_jet_4_pT = bookHisto1D("jet_4_pT", logspace(50, 20.0, 200.0));
00048       _h_jet_HT   = bookHisto1D("jet_HT", logspace(50, 100.0, 2000.0));
00049       //
00050       _h_bjet_1_pT = bookHisto1D("jetb_1_pT", logspace(50, 20.0, 400.0));
00051       _h_bjet_2_pT = bookHisto1D("jetb_2_pT", logspace(50, 20.0, 300.0));
00052       //
00053       _h_ljet_1_pT = bookHisto1D("jetl_1_pT", logspace(50, 20.0, 400.0));
00054       _h_ljet_2_pT = bookHisto1D("jetl_2_pT", logspace(50, 20.0, 300.0));
00055       //
00056       _h_W_mass = bookHisto1D("W_mass", 75, 30, 180);
00057       _h_t_mass = bookHisto1D("t_mass", 150, 130, 430);
00058       _h_t_mass_W_cut = bookHisto1D("t_mass_W_cut", 150, 130, 430);
00059       //
00060       _h_jetb_1_jetb_2_dR   = bookHisto1D("jetb_1_jetb_2_dR", 20, 0.0, 7.0);
00061       _h_jetb_1_jetb_2_deta = bookHisto1D("jetb_1_jetb_2_deta", 20, 0.0, 7.0);
00062       _h_jetb_1_jetb_2_dphi = bookHisto1D("jetb_1_jetb_2_dphi", 20, 0.0, M_PI);
00063       _h_jetb_1_jetl_1_dR   = bookHisto1D("jetb_1_jetl_1_dR", 20, 0.0, 7.0);
00064       _h_jetb_1_jetl_1_deta = bookHisto1D("jetb_1_jetl_1_deta", 20, 0.0, 7.0);
00065       _h_jetb_1_jetl_1_dphi = bookHisto1D("jetb_1_jetl_1_dphi", 20, 0.0, M_PI);
00066       _h_jetl_1_jetl_2_dR   = bookHisto1D("jetl_1_jetl_2_dR", 20, 0.0, 7.0);
00067       _h_jetl_1_jetl_2_deta = bookHisto1D("jetl_1_jetl_2_deta", 20, 0.0, 7.0);
00068       _h_jetl_1_jetl_2_dphi = bookHisto1D("jetl_1_jetl_2_dphi", 20, 0.0, M_PI);
00069       _h_jetb_1_W_dR        = bookHisto1D("jetb_1_W_dR", 20, 0.0, 7.0);
00070       _h_jetb_1_W_deta      = bookHisto1D("jetb_1_W_deta", 20, 0.0, 7.0);
00071       _h_jetb_1_W_dphi      = bookHisto1D("jetb_1_W_dphi", 20, 0.0, M_PI);
00072       _h_jetb_1_l_dR        = bookHisto1D("jetb_1_l_dR", 20, 0.0, 7.0);
00073       _h_jetb_1_l_deta      = bookHisto1D("jetb_1_l_deta", 20, 0.0, 7.0);
00074       _h_jetb_1_l_dphi      = bookHisto1D("jetb_1_l_dphi", 20, 0.0, M_PI);
00075       _h_jetb_1_l_mass      = bookHisto1D("jetb_1_l_mass", 40, 0.0, 500.0);
00076     }
00077 
00078 
00079     void analyze(const Event& event) {
00080       const double weight = event.weight();
00081 
00082       // Use the "LFS" projection to require at least one hard charged
00083       // lepton. This is an experimental signature for the leptonically decaying
00084       // W. This helps to reduce pure QCD backgrounds.
00085       const ChargedLeptons& lfs = applyProjection<ChargedLeptons>(event, "LFS");
00086       MSG_DEBUG("Charged lepton multiplicity = " << lfs.chargedLeptons().size());
00087       foreach (const Particle& lepton, lfs.chargedLeptons()) {
00088         MSG_DEBUG("Lepton pT = " << lepton.momentum().pT());
00089       }
00090       if (lfs.chargedLeptons().empty()) {
00091         MSG_DEBUG("Event failed lepton multiplicity cut");
00092         vetoEvent;
00093       }
00094 
00095       // Use a missing ET cut to bias toward events with a hard neutrino from
00096       // the leptonically decaying W. This helps to reduce pure QCD backgrounds.
00097       const MissingMomentum& met = applyProjection<MissingMomentum>(event, "MissingET");
00098       MSG_DEBUG("Vector ET = " << met.vectorEt().mod() << " GeV");
00099       if (met.vectorEt().mod() < 30*GeV) {
00100         MSG_DEBUG("Event failed missing ET cut");
00101         vetoEvent;
00102       }
00103 
00104       // Use the "Jets" projection to check that there are at least 4 jets of
00105       // any pT. Getting the jets sorted by pT ensures that the first jet is the
00106       // hardest, and so on. We apply no pT cut here only because we want to
00107       // plot all jet pTs to help optimise our jet pT cut.
00108       const FastJets& jetpro = applyProjection<FastJets>(event, "Jets");
00109       const Jets alljets = jetpro.jetsByPt();
00110       if (alljets.size() < 4) {
00111         MSG_DEBUG("Event failed jet multiplicity cut");
00112         vetoEvent;
00113       }
00114 
00115       // Update passed-cuts counter and fill all-jets histograms
00116       _h_jet_1_pT->fill(alljets[0].momentum().pT()/GeV, weight);
00117       _h_jet_2_pT->fill(alljets[1].momentum().pT()/GeV, weight);
00118       _h_jet_3_pT->fill(alljets[2].momentum().pT()/GeV, weight);
00119       _h_jet_4_pT->fill(alljets[3].momentum().pT()/GeV, weight);
00120 
00121       // Insist that the hardest 4 jets pass pT hardness cuts. If we don't find
00122       // at least 4 such jets, we abandon this event.
00123       const Jets jets = jetpro.jetsByPt(30*GeV);
00124       _h_njets->fill(jets.size(), weight);
00125       double ht = 0.0;
00126       foreach (const Jet& j, jets) { ht += j.momentum().pT(); }
00127       _h_jet_HT->fill(ht/GeV, weight);
00128       if (jets.size() < 4 ||
00129           jets[0].momentum().pT() < 60*GeV ||
00130           jets[1].momentum().pT() < 50*GeV ||
00131           jets[3].momentum().pT() < 30*GeV) {
00132         MSG_DEBUG("Event failed jet cuts");
00133         vetoEvent;
00134       }
00135 
00136       // Sort the jets into b-jets and light jets. We expect one hard b-jet from
00137       // each top decay, so our 4 hardest jets should include two b-jets. The
00138       // Jet::containsBottom() method is equivalent to perfect experimental
00139       // b-tagging, in a generator-independent way.
00140       Jets bjets, ljets;
00141       foreach (const Jet& jet, jets) {
00142         // // Don't count jets that overlap with the hard leptons
00143         bool isolated = true;
00144         foreach (const Particle& lepton, lfs.chargedLeptons()) {
00145           if (deltaR(jet.momentum(), lepton.momentum()) < 0.3) {
00146             isolated = false;
00147             break;
00148           }
00149         }
00150         if (!isolated) {
00151           MSG_DEBUG("Jet failed lepton isolation cut");
00152           break;
00153         }
00154         if (jet.containsBottom()) {
00155           bjets.push_back(jet);
00156         } else {
00157           ljets.push_back(jet);
00158         }
00159       }
00160       MSG_DEBUG("Number of b-jets = " << bjets.size());
00161       MSG_DEBUG("Number of l-jets = " << ljets.size());
00162       if (bjets.size() != 2) {
00163         MSG_DEBUG("Event failed post-lepton-isolation b-tagging cut");
00164         vetoEvent;
00165       }
00166       if (ljets.size() < 2) {
00167         MSG_DEBUG("Event failed since not enough light jets remaining after lepton-isolation");
00168         vetoEvent;
00169       }
00170 
00171       // Plot the pTs of the identified jets.
00172       _h_bjet_1_pT->fill(bjets[0].momentum().pT(), weight);
00173       _h_bjet_2_pT->fill(bjets[1].momentum().pT(), weight);
00174       _h_ljet_1_pT->fill(ljets[0].momentum().pT(), weight);
00175       _h_ljet_2_pT->fill(ljets[1].momentum().pT(), weight);
00176 
00177       // Construct the hadronically decaying W momentum 4-vector from pairs of
00178       // non-b-tagged jets. The pair which best matches the W mass is used. We start
00179       // with an always terrible 4-vector estimate which should always be "beaten" by
00180       // a real jet pair.
00181       FourMomentum W(10*sqrtS(), 0, 0, 0);
00182       for (size_t i = 0; i < ljets.size()-1; ++i) {
00183         for (size_t j = i + 1; j < ljets.size(); ++j) {
00184           const FourMomentum Wcand = ljets[i].momentum() + ljets[j].momentum();
00185           MSG_TRACE(i << "," << j << ": candidate W mass = " << Wcand.mass()/GeV
00186                     << " GeV, vs. incumbent candidate with " << W.mass()/GeV << " GeV");
00187           if (fabs(Wcand.mass() - 80.4*GeV) < fabs(W.mass() - 80.4*GeV)) {
00188             W = Wcand;
00189           }
00190         }
00191       }
00192       MSG_DEBUG("Candidate W mass = " << W.mass() << " GeV");
00193 
00194       // There are two b-jets with which this can be combined to make the
00195       // hadronically decaying top, one of which is correct and the other is
00196       // not... but we have no way to identify which is which, so we construct
00197       // both possible top momenta and fill the histograms with both.
00198       const FourMomentum t1 = W + bjets[0].momentum();
00199       const FourMomentum t2 = W + bjets[1].momentum();
00200       _h_W_mass->fill(W.mass(), weight);
00201       _h_t_mass->fill(t1.mass(), weight);
00202       _h_t_mass->fill(t2.mass(), weight);
00203 
00204       // Placing a cut on the well-known W mass helps to reduce backgrounds
00205       if (inRange(W.mass()/GeV, 75.0, 85.0)) {
00206         MSG_DEBUG("W found with mass " << W.mass()/GeV << " GeV");
00207         _h_t_mass_W_cut->fill(t1.mass(), weight);
00208         _h_t_mass_W_cut->fill(t2.mass(), weight);
00209 
00210         _h_jetb_1_jetb_2_dR->fill(deltaR(bjets[0].momentum(), bjets[1].momentum()),weight);
00211         _h_jetb_1_jetb_2_deta->fill(fabs(bjets[0].momentum().eta()-bjets[1].momentum().eta()),weight);
00212         _h_jetb_1_jetb_2_dphi->fill(deltaPhi(bjets[0].momentum(),bjets[1].momentum()),weight);
00213 
00214         _h_jetb_1_jetl_1_dR->fill(deltaR(bjets[0].momentum(), ljets[0].momentum()),weight);
00215         _h_jetb_1_jetl_1_deta->fill(fabs(bjets[0].momentum().eta()-ljets[0].momentum().eta()),weight);
00216         _h_jetb_1_jetl_1_dphi->fill(deltaPhi(bjets[0].momentum(),ljets[0].momentum()),weight);
00217 
00218         _h_jetl_1_jetl_2_dR->fill(deltaR(ljets[0].momentum(), ljets[1].momentum()),weight);
00219         _h_jetl_1_jetl_2_deta->fill(fabs(ljets[0].momentum().eta()-ljets[1].momentum().eta()),weight);
00220         _h_jetl_1_jetl_2_dphi->fill(deltaPhi(ljets[0].momentum(),ljets[1].momentum()),weight);
00221 
00222         _h_jetb_1_W_dR->fill(deltaR(bjets[0].momentum(), W),weight);
00223         _h_jetb_1_W_deta->fill(fabs(bjets[0].momentum().eta()-W.eta()),weight);
00224         _h_jetb_1_W_dphi->fill(deltaPhi(bjets[0].momentum(),W),weight);
00225 
00226         FourMomentum l=lfs.chargedLeptons()[0].momentum();
00227         _h_jetb_1_l_dR->fill(deltaR(bjets[0].momentum(), l),weight);
00228         _h_jetb_1_l_deta->fill(fabs(bjets[0].momentum().eta()-l.eta()),weight);
00229         _h_jetb_1_l_dphi->fill(deltaPhi(bjets[0].momentum(),l),weight);
00230         _h_jetb_1_l_mass->fill(FourMomentum(bjets[0].momentum()+l).mass(), weight);
00231       }
00232 
00233     }
00234 
00235 
00236     void finalize() {
00237       normalize(_h_njets);
00238       normalize(_h_jet_1_pT);
00239       normalize(_h_jet_2_pT);
00240       normalize(_h_jet_3_pT);
00241       normalize(_h_jet_4_pT);
00242       normalize(_h_jet_HT);
00243       normalize(_h_bjet_1_pT);
00244       normalize(_h_bjet_2_pT);
00245       normalize(_h_ljet_1_pT);
00246       normalize(_h_ljet_2_pT);
00247       normalize(_h_W_mass);
00248       normalize(_h_t_mass);
00249       normalize(_h_t_mass_W_cut);
00250       normalize(_h_jetb_1_jetb_2_dR);
00251       normalize(_h_jetb_1_jetb_2_deta);
00252       normalize(_h_jetb_1_jetb_2_dphi);
00253       normalize(_h_jetb_1_jetl_1_dR);
00254       normalize(_h_jetb_1_jetl_1_deta);
00255       normalize(_h_jetb_1_jetl_1_dphi);
00256       normalize(_h_jetl_1_jetl_2_dR);
00257       normalize(_h_jetl_1_jetl_2_deta);
00258       normalize(_h_jetl_1_jetl_2_dphi);
00259       normalize(_h_jetb_1_W_dR);
00260       normalize(_h_jetb_1_W_deta);
00261       normalize(_h_jetb_1_W_dphi);
00262       normalize(_h_jetb_1_l_dR);
00263       normalize(_h_jetb_1_l_deta);
00264       normalize(_h_jetb_1_l_dphi);
00265       normalize(_h_jetb_1_l_mass);
00266     }
00267 
00268     //@}
00269 
00270 
00271   private:
00272 
00273     // @name Histogram data members
00274     //@{
00275 
00276     Histo1DPtr _h_njets;
00277     Histo1DPtr _h_jet_1_pT, _h_jet_2_pT, _h_jet_3_pT, _h_jet_4_pT;
00278     Histo1DPtr _h_jet_HT;
00279     Histo1DPtr _h_bjet_1_pT, _h_bjet_2_pT;
00280     Histo1DPtr _h_ljet_1_pT, _h_ljet_2_pT;
00281     Histo1DPtr _h_W_mass;
00282     Histo1DPtr _h_t_mass, _h_t_mass_W_cut;
00283     Histo1DPtr _h_jetb_1_jetb_2_dR, _h_jetb_1_jetb_2_deta, _h_jetb_1_jetb_2_dphi;
00284     Histo1DPtr _h_jetb_1_jetl_1_dR, _h_jetb_1_jetl_1_deta, _h_jetb_1_jetl_1_dphi;
00285     Histo1DPtr _h_jetl_1_jetl_2_dR, _h_jetl_1_jetl_2_deta, _h_jetl_1_jetl_2_dphi;
00286     Histo1DPtr _h_jetb_1_W_dR, _h_jetb_1_W_deta, _h_jetb_1_W_dphi;
00287     Histo1DPtr _h_jetb_1_l_dR, _h_jetb_1_l_deta, _h_jetb_1_l_dphi,_h_jetb_1_l_mass;
00288 
00289 
00290     //@}
00291 
00292   };
00293 
00294 
00295 
00296   // The hook for the plugin system
00297   DECLARE_RIVET_PLUGIN(MC_TTBAR);
00298 
00299 }