ATLAS_2012_I1094568.cc
Go to the documentation of this file.
00001 // -*- C++ -*- 00002 #include "Rivet/Analysis.hh" 00003 #include "Rivet/RivetYODA.hh" 00004 #include "Rivet/Tools/Logging.hh" 00005 #include "Rivet/Projections/FinalState.hh" 00006 #include "Rivet/Projections/IdentifiedFinalState.hh" 00007 #include "Rivet/Projections/LeadingParticlesFinalState.hh" 00008 #include "Rivet/Projections/UnstableFinalState.hh" 00009 #include "Rivet/Projections/HadronicFinalState.hh" 00010 #include "Rivet/Projections/VetoedFinalState.hh" 00011 #include "Rivet/Projections/LeptonClusters.hh" 00012 #include "Rivet/Projections/FastJets.hh" 00013 #include "Rivet/Tools/ParticleIdUtils.hh" 00014 #include "Rivet/Particle.hh" 00015 #include "HepMC/GenEvent.h" 00016 00017 namespace Rivet { 00018 00019 struct ATLAS_2012_I1094568_plots { 00020 // Keep track of which veto region this is, to match 00021 // the autobook-ed histograms 00022 int region_index; 00023 00024 // lower rapidity boundary or veto region 00025 double y_low; 00026 // upper rapidity boundary or veto region 00027 double y_high; 00028 00029 double vetoJetPt_Q0; 00030 double vetoJetPt_Qsum; 00031 00032 // Histograms to store the veto jet pT and 00033 // sum(veto jet pT) histograms. 00034 Histo1DPtr _h_vetoJetPt_Q0; 00035 Histo1DPtr _h_vetoJetPt_Qsum; 00036 00037 // DataPointSets for the gap fractions 00038 Scatter2DPtr _d_gapFraction_Q0; 00039 Scatter2DPtr _d_gapFraction_Qsum; 00040 }; 00041 00042 00043 class ATLAS_2012_I1094568 : public Analysis { 00044 public: 00045 00046 /// Constructor 00047 ATLAS_2012_I1094568() : Analysis("ATLAS_2012_I1094568") 00048 {} 00049 00050 00051 public: 00052 00053 /// Book histograms and initialise projections before the run 00054 void init() { 00055 00056 const FinalState fs(-4.5, 4.5); 00057 addProjection(fs, "ALL_FS"); 00058 00059 /// Get electrons from truth record 00060 IdentifiedFinalState elec_fs(-2.47, 2.47, 25.0*GeV); 00061 elec_fs.acceptIdPair(ELECTRON); 00062 addProjection(elec_fs, "ELEC_FS"); 00063 00064 /// Get muons which pass the initial kinematic cuts: 00065 IdentifiedFinalState muon_fs(-2.5, 2.5, 20.0*GeV); 00066 muon_fs.acceptIdPair(MUON); 00067 addProjection(muon_fs, "MUON_FS"); 00068 00069 /// Get all neutrinos. These will not be used to form jets. 00070 /// We'll use the highest 2 pT neutrinos to calculate the MET 00071 IdentifiedFinalState neutrino_fs(-4.5, 4.5, 0.0*GeV); 00072 neutrino_fs.acceptNeutrinos(); 00073 addProjection(neutrino_fs, "NEUTRINO_FS"); 00074 00075 // Final state used as input for jet-finding. 00076 // We include everything except the muons and neutrinos 00077 VetoedFinalState jet_input(fs); 00078 jet_input.vetoNeutrinos(); 00079 jet_input.addVetoPairId(MUON); 00080 addProjection(jet_input, "JET_INPUT"); 00081 00082 // Get the jets 00083 FastJets jets(jet_input, FastJets::ANTIKT, 0.4); 00084 addProjection(jets, "JETS"); 00085 00086 for(int i=0; i<201; ++i) { 00087 double bin_edge = i*5; 00088 m_q0BinEdges += bin_edge; 00089 } 00090 00091 m_total_weight = 0.0; 00092 00093 m_plots[0].region_index = 1; 00094 m_plots[0].y_low = 0.0; 00095 m_plots[0].y_high = 0.8; 00096 InitializePlots(m_plots[0]); 00097 00098 m_plots[1].region_index = 2; 00099 m_plots[1].y_low = 0.8; 00100 m_plots[1].y_high = 1.5; 00101 InitializePlots(m_plots[1]); 00102 00103 m_plots[2].region_index = 3; 00104 m_plots[2].y_low = 1.5; 00105 m_plots[2].y_high = 2.1; 00106 InitializePlots(m_plots[2]); 00107 00108 m_plots[3].region_index = 4; 00109 m_plots[3].y_low = 0.0; 00110 m_plots[3].y_high = 2.1; 00111 InitializePlots(m_plots[3]); 00112 } 00113 00114 void InitializePlots(ATLAS_2012_I1094568_plots& plots) { 00115 int q0_index = 1; 00116 int qsum_index = 2; 00117 00118 std::stringstream vetoPt_Q0_name; 00119 vetoPt_Q0_name << "vetoJetPt_Q0_" << plots.region_index; 00120 00121 std::stringstream vetoPt_Qsum_name; 00122 vetoPt_Qsum_name << "vetoJetPt_Qsum_" << plots.region_index; 00123 00124 plots._h_vetoJetPt_Q0 = bookHisto1D(vetoPt_Q0_name.str(), m_q0BinEdges); 00125 plots._h_vetoJetPt_Qsum = bookHisto1D(vetoPt_Qsum_name.str(), m_q0BinEdges); 00126 00127 plots._d_gapFraction_Q0 = bookScatter2D(plots.region_index, q0_index, 1); 00128 plots._d_gapFraction_Qsum = bookScatter2D(plots.region_index, qsum_index, 1); 00129 00130 plots.vetoJetPt_Q0 = 0.0; 00131 plots.vetoJetPt_Qsum = 0.0; 00132 } 00133 00134 00135 /// Perform the per-event analysis 00136 void analyze(const Event& event) { 00137 00138 const double weight = event.weight(); 00139 00140 /// Get the various sets of final state particles 00141 const ParticleVector& elecFS = applyProjection<IdentifiedFinalState>(event, "ELEC_FS").particlesByPt(); 00142 const ParticleVector& muonFS = applyProjection<IdentifiedFinalState>(event, "MUON_FS").particlesByPt(); 00143 const ParticleVector& neutrinoFS = applyProjection<IdentifiedFinalState>(event, "NEUTRINO_FS").particlesByPt(); 00144 00145 // Get all jets with pT > 25 GeV 00146 const Jets& jets = applyProjection<FastJets>(event, "JETS").jetsByPt(25.0*GeV); 00147 00148 // Keep any jets that pass the initial rapidity cut 00149 vector<const Jet*> central_jets; 00150 double rapMax = 2.4; 00151 foreach(const Jet& j, jets) { 00152 double rapidity = fabs(j.momentum().rapidity()); 00153 if(rapidity < rapMax) central_jets.push_back(&j); 00154 } 00155 00156 // For each of the jets that pass the rapidity cut, only keep those that are not 00157 // too close to any leptons 00158 vector<const Jet*> good_jets; 00159 foreach(const Jet* j, central_jets) { 00160 bool goodJet = true; 00161 foreach(const Particle& e, elecFS) { 00162 double elec_jet_dR = deltaR(e.momentum(), j->momentum()); 00163 if(elec_jet_dR < 0.4) goodJet = false; 00164 } 00165 foreach(const Particle& m, muonFS) { 00166 double muon_jet_dR = deltaR(m.momentum(), j->momentum()); 00167 if(muon_jet_dR < 0.4) goodJet = false; 00168 } 00169 if(goodJet == true) good_jets.push_back(j); 00170 } 00171 00172 // Temporary fix to get B-hadrons in evgen files where they don't show up 00173 // in the UnstableFinalState projection 00174 // (e.g. mc10_7TeV.105200.T1_McAtNlo_Jimmy.evgen.EVNT.e598/) 00175 // This will be updated for MC12 to just use UnstableFinalState 00176 // (Thanks to Steve Bieniek for this!) 00177 std::vector<HepMC::GenParticle*> B_hadrons; 00178 std::vector<HepMC::GenParticle*> allParticles = particles(event.genEvent()); 00179 for(unsigned int i = 0; i < allParticles.size(); i++) { 00180 GenParticle* p = allParticles.at(i); 00181 if ( !(Rivet::PID::isHadron( p->pdg_id() ) && Rivet::PID::hasBottom( p->pdg_id() )) ) continue; 00182 if(p->momentum().perp()*GeV < 5) continue; 00183 B_hadrons.push_back(p); 00184 } 00185 00186 00187 // For each of the good jets, check whether any are b-jets 00188 vector<const Jet*> b_jets; 00189 foreach(const Jet* j, good_jets) { 00190 bool isbJet = false; 00191 foreach(HepMC::GenParticle* b, B_hadrons) { 00192 FourMomentum hadron = b->momentum(); 00193 double hadron_jet_dR = deltaR(j->momentum(), hadron); 00194 if(hadron_jet_dR < 0.3) isbJet = true; 00195 } 00196 if(isbJet) b_jets.push_back(j); 00197 } 00198 00199 00200 // Check the good jets again and keep track of the "additional jets" 00201 // I.e. those which are not either of the 2 highest pT b-jets 00202 vector<const Jet*> veto_jets; 00203 int n_bjets_matched = 0; 00204 foreach(const Jet* j, good_jets) { 00205 bool isBJet = false; 00206 foreach(const Jet* b, b_jets) { 00207 if(n_bjets_matched == 2) break; 00208 if(b == j){isBJet = true; ++ n_bjets_matched;} 00209 } 00210 if(!isBJet) veto_jets.push_back(j); 00211 } 00212 00213 00214 // Get the MET by taking the vector sum of all neutrinos 00215 double MET = 0; 00216 FourMomentum p_MET(0., 0., 0., 0.); 00217 foreach(const Particle& p, neutrinoFS) { 00218 p_MET = p_MET + p.momentum(); 00219 } 00220 MET = p_MET.pT(); 00221 00222 00223 // Now we have everything we need to start doing the event selections 00224 bool passed_ee = false; 00225 vector<const Jet*> vetoJets_ee; 00226 00227 // We want exactly 2 electrons... 00228 if(elecFS.size() == 2) { 00229 // ... with opposite sign charges. 00230 if(PID::charge(elecFS.at(0)) != PID::charge(elecFS.at(1))) { 00231 // Check the MET 00232 if(MET >= 40*GeV) { 00233 // Do some dilepton mass cuts 00234 double dilepton_mass = (elecFS.at(0).momentum() + elecFS.at(1).momentum()).mass(); 00235 if(dilepton_mass >= 15*GeV) { 00236 if(fabs(dilepton_mass - 91.0*GeV) >= 10.0*GeV) { 00237 // we need at least 2 b-jets 00238 if(b_jets.size() > 1) { 00239 // This event has passed all the cuts; 00240 passed_ee = true; 00241 } 00242 } 00243 } 00244 } 00245 } 00246 } 00247 00248 00249 bool passed_mumu = false; 00250 // Now do the same checks for the mumu channel 00251 vector<const Jet*> vetoJets_mumu; 00252 // So we now want 2 good muons... 00253 if(muonFS.size() == 2) { 00254 // ...with opposite sign charges. 00255 if(PID::charge(muonFS.at(0)) != PID::charge(muonFS.at(1))) { 00256 // Check the MET 00257 if(MET >= 40*GeV) { 00258 // and do some di-muon mass cuts 00259 double dilepton_mass = (muonFS.at(0).momentum() + muonFS.at(1).momentum()).mass(); 00260 if(dilepton_mass >= 15*GeV) { 00261 if(fabs(dilepton_mass - 91.0*GeV) >= 10.0*GeV) { 00262 // Need atleast 2 b-jets 00263 if(b_jets.size() > 1) { 00264 // This event has passed all mumu-channel cuts 00265 passed_mumu = true; 00266 } 00267 } 00268 } 00269 } 00270 } 00271 } 00272 00273 00274 bool passed_emu = false; 00275 // Finally, the same again with the emu channel 00276 vector<const Jet*> vetoJets_emu; 00277 // We want exactly 1 electron and 1 muon 00278 if(elecFS.size() == 1 && muonFS.size() == 1) { 00279 // With opposite sign charges 00280 if(PID::charge(elecFS.at(0)) != PID::charge(muonFS.at(0))) { 00281 // Calculate the HT from the scalar sum of the pT of the leptons 00282 // and all good jets 00283 double HT = 0; 00284 HT += fabs(elecFS.at(0).momentum().pT()); 00285 HT += fabs(muonFS.at(0).momentum().pT()); 00286 foreach(const Jet* j, good_jets) { 00287 HT += fabs(j->momentum().pT()); 00288 } 00289 // Keep events with HT > 130 GeV 00290 if(HT > 130.0*GeV) { 00291 // And again we want 2 or more b-jets 00292 if(b_jets.size() > 1) { 00293 passed_emu = true; 00294 } 00295 } 00296 } 00297 } 00298 00299 if(passed_ee == true || passed_mumu == true || passed_emu == true) { 00300 // If the event passes the selection, we use it for all gap fractions 00301 m_total_weight += weight; 00302 00303 // Loop over each veto jet 00304 foreach(const Jet* j, veto_jets) { 00305 double pt = j->momentum().pT(); 00306 double rapidity = fabs(j->momentum().rapidity()); 00307 // Loop over each region 00308 for(int i=0; i<4; ++i) { 00309 // If the jet falls into this region, get its pT and increment sum(pT) 00310 if( (rapidity > m_plots[i].y_low) && (rapidity < m_plots[i].y_high)) { 00311 m_plots[i].vetoJetPt_Qsum += pt; 00312 00313 // If we've already got a veto jet, don't replace it 00314 if(m_plots[i].vetoJetPt_Q0 == 0.0) m_plots[i].vetoJetPt_Q0 = pt; 00315 } 00316 } 00317 } // end loop over veto jets 00318 for(int i=0; i<4; ++i) { 00319 m_plots[i]._h_vetoJetPt_Q0->fill(m_plots[i].vetoJetPt_Q0, weight); 00320 m_plots[i]._h_vetoJetPt_Qsum->fill(m_plots[i].vetoJetPt_Qsum, weight); 00321 ClearVetoJetPts(m_plots[i]); 00322 } 00323 } 00324 } 00325 00326 void ClearVetoJetPts(ATLAS_2012_I1094568_plots& plots) { 00327 plots.vetoJetPt_Q0 = 0.0; 00328 plots.vetoJetPt_Qsum = 0.0; 00329 } 00330 00331 00332 /// Normalise histograms etc., after the run 00333 void finalize() { 00334 for(int i=0; i<4; ++i) { 00335 // @todo YODA 00336 //FinalizeGapFraction(m_total_weight, m_plots[i]._d_gapFraction_Q0, m_plots[i]._h_vetoJetPt_Q0, binEdges(i+1, 1, 1)); 00337 //FinalizeGapFraction(m_total_weight, m_plots[i]._d_gapFraction_Qsum, m_plots[i]._h_vetoJetPt_Qsum, binEdges(i+1, 2, 1)); 00338 } 00339 } 00340 00341 // @todo YODA 00342 ////void FinalizeGapFraction(double total_weight, ATLAS_2011_I1094568_plots& plots, int type) 00343 //void FinalizeGapFraction(double total_weight, Scatter2DPtr gapFraction, Histo1DPtr vetoPt, BinEdges fgap_binEdges) { 00344 00345 // // Stores the cumulative frequency of the veto jet pT histogram 00346 // double vetoPtWeightSum = 0.0; 00347 // 00348 // // Keep track of which gap fraction point we're doing 00349 // unsigned int fgap_point = 0; 00350 // for(unsigned int i=0; i<m_q0BinEdges.size()-2; ++i) { 00351 // vetoPtWeightSum += vetoPt->binHeight(i); 00352 00353 // // If we've done the last point, stop. 00354 // if(fgap_point == fgap_binEdges.size()-1) break; 00355 00356 // // Get the x-value of this gap fraction point, from the mid-point of the bin edges 00357 // double binCentre = ( fgap_binEdges.at(fgap_point) + fgap_binEdges.at(fgap_point+1) ) / 2; 00358 // double errorPlus = fgap_binEdges.at(fgap_point+1) - binCentre; 00359 // double errorMinus = binCentre - fgap_binEdges.at(fgap_point); 00360 00361 // // If this Q0/Qsum point is not the cut value we need for this gap fraction point, continue 00362 // if(m_q0BinEdges.at(i+1) != binCentre) continue; 00363 00364 // // Calculate the gap fraction and its uncertainty 00365 // double fraction = vetoPtWeightSum/total_weight; 00366 // double fraction_error = sqrt(fraction*(1.0-fraction)/total_weight); 00367 // if(total_weight == 0.0) fraction = fraction_error = 0.0; 00368 00369 // // Set the point 00370 // IDataPoint* currentPoint = gapFraction->point(fgap_point); 00371 // IMeasurement* xCoord = currentPoint->coordinate(0); 00372 // IMeasurement* yCoord = currentPoint->coordinate(1); 00373 00374 // xCoord->setValue(binCentre); 00375 // xCoord->setErrorPlus(errorPlus); 00376 // xCoord->setErrorMinus(errorMinus); 00377 // yCoord->setValue(fraction); 00378 // yCoord->setErrorPlus(fraction_error); 00379 // yCoord->setErrorMinus(fraction_error); 00380 00381 // ++fgap_point; 00382 // } 00383 // tree().rm(tree().findPath(dynamic_cast<AIDA::IManagedObject&>(*vetoPt))); 00384 //} 00385 00386 00387 private: 00388 00389 // define the vetoJet pT binning 00390 std::vector<double> m_q0BinEdges; 00391 double m_total_weight; 00392 00393 00394 private: 00395 ATLAS_2012_I1094568_plots m_plots[4]; 00396 00397 }; 00398 00399 00400 // The hook for the plugin system 00401 DECLARE_RIVET_PLUGIN(ATLAS_2012_I1094568); 00402 00403 } Generated on Fri Dec 21 2012 15:03:39 for The Rivet MC analysis system by ![]() |