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 } Generated on Fri Dec 21 2012 15:03:41 for The Rivet MC analysis system by ![]() |