rivet is hosted by Hepforge, IPPP Durham
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 }