rivet is hosted by Hepforge, IPPP Durham
ATLAS_2014_I1304688.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Analysis.hh"
00003 #include "Rivet/Projections/VetoedFinalState.hh"
00004 #include "Rivet/Projections/IdentifiedFinalState.hh"
00005 #include "Rivet/Projections/PromptFinalState.hh"
00006 #include "Rivet/Projections/DressedLeptons.hh"
00007 #include "Rivet/Projections/FastJets.hh"
00008 #include <bitset>
00009 
00010 namespace Rivet {
00011 
00012   
00013 
00014 
00015   /// @brief ATLAS 7 TeV jets in ttbar events analysis
00016   ///
00017   /// @author W. H. Bell <W.Bell@cern.ch>
00018   /// @author A. Grohsjean <alexander.grohsjean@desy.de>
00019   class ATLAS_2014_I1304688 : public Analysis {
00020   public:
00021 
00022     ATLAS_2014_I1304688():
00023       Analysis("ATLAS_2014_I1304688"),
00024       _jet_ntag(0),
00025       _met_et(0.),
00026       _met_phi(0.),
00027       _hMap(),
00028       //_chanLimit(3),
00029       _histLimit(6)
00030     {   }
00031 
00032 
00033     void init() {
00034       // Eta ranges
00035       /// @todo 1 MeV? Really?
00036       Cut eta_full = Cuts::abseta < 5.0 && Cuts::pT > 1.0*MeV;
00037       Cut eta_lep = Cuts::abseta < 2.5;
00038 
00039       // All final state particles
00040       FinalState fs(eta_full);
00041 
00042       // Get photons to dress leptons
00043       IdentifiedFinalState photons(fs);
00044       photons.acceptIdPair(PID::PHOTON);
00045 
00046       // Projection to find the electrons
00047       IdentifiedFinalState el_id(fs);
00048       el_id.acceptIdPair(PID::ELECTRON);
00049       PromptFinalState electrons(el_id);
00050       electrons.acceptTauDecays(true);
00051       addProjection(electrons, "electrons");
00052       DressedLeptons dressedelectrons(photons, electrons, 0.1, eta_lep && Cuts::pT > 25*GeV, true, true);
00053       addProjection(dressedelectrons, "dressedelectrons");
00054       DressedLeptons vetodressedelectrons(photons, electrons, 0.1, eta_lep && Cuts::pT >= 15*GeV, true, true);
00055       addProjection(vetodressedelectrons, "vetodressedelectrons");
00056       DressedLeptons ewdressedelectrons(photons, electrons, 0.1, eta_full, true, true);
00057       addProjection(ewdressedelectrons, "ewdressedelectrons");
00058 
00059       // Projection to find the muons
00060       IdentifiedFinalState mu_id(fs);
00061       mu_id.acceptIdPair(PID::MUON);
00062       PromptFinalState muons(mu_id);
00063       muons.acceptTauDecays(true);
00064       addProjection(muons, "muons");
00065       vector<pair<double, double> > eta_muon;
00066       DressedLeptons dressedmuons(photons, muons, 0.1, eta_lep && Cuts::pT >= 25*GeV, true, true);
00067       addProjection(dressedmuons, "dressedmuons");
00068       DressedLeptons vetodressedmuons(photons, muons, 0.1, eta_lep && Cuts::pT >= 15*GeV, true, true);
00069       addProjection(vetodressedmuons, "vetodressedmuons");
00070       DressedLeptons ewdressedmuons(photons, muons, 0.1, eta_full, true, true);
00071       addProjection(ewdressedmuons, "ewdressedmuons");
00072 
00073       // Projection to find neutrinos and produce MET
00074       IdentifiedFinalState nu_id;
00075       nu_id.acceptNeutrinos();
00076       PromptFinalState neutrinos(nu_id);
00077       neutrinos.acceptTauDecays(true);
00078       addProjection(neutrinos, "neutrinos");
00079 
00080       // Jet clustering.
00081       VetoedFinalState vfs;
00082       vfs.addVetoOnThisFinalState(ewdressedelectrons);
00083       vfs.addVetoOnThisFinalState(ewdressedmuons);
00084       vfs.addVetoOnThisFinalState(neutrinos);
00085       FastJets jets(vfs, FastJets::ANTIKT, 0.4);
00086       jets.useInvisibles();
00087       addProjection(jets, "jets");
00088 
00089       // Book histograms
00090       for (unsigned int ihist = 0; ihist < _histLimit ; ihist++) {
00091         const unsigned int threshLimit = _thresholdLimit(ihist);
00092         for (unsigned int ithres = 0; ithres < threshLimit; ithres++) {
00093           _histogram(ihist, ithres); // Create all histograms
00094         }
00095       }
00096     }
00097 
00098 
00099     void analyze(const Event& event) {
00100 
00101       // Get the selected objects, using the projections.
00102       _dressedelectrons = sortByPt(applyProjection<DressedLeptons>(event, "dressedelectrons").dressedLeptons());
00103       _vetodressedelectrons = applyProjection<DressedLeptons>(event, "vetodressedelectrons").dressedLeptons();
00104 
00105       _dressedmuons = sortByPt(applyProjection<DressedLeptons>(event, "dressedmuons").dressedLeptons());
00106       _vetodressedmuons = applyProjection<DressedLeptons>(event, "vetodressedmuons").dressedLeptons();
00107 
00108       _neutrinos = applyProjection<PromptFinalState>(event, "neutrinos").particlesByPt();
00109 
00110       _jets = applyProjection<FastJets>(event, "jets").jetsByPt(Cuts::pT > 25*GeV && Cuts::abseta < 2.5);
00111 
00112 
00113       // Calculate the missing ET, using the prompt neutrinos only (really?)
00114       /// @todo Why not use MissingMomentum?
00115       FourMomentum pmet;
00116       foreach (const Particle& p, _neutrinos) pmet += p.momentum();
00117       _met_et = pmet.pT();
00118       _met_phi = pmet.phi();
00119 
00120       // Check overlap of jets/leptons.
00121       unsigned int i,j;
00122       _jet_ntag = 0;
00123       _overlap = false;
00124       for (i = 0; i < _jets.size(); i++) {
00125         const Jet& jet = _jets[i];
00126         // If dR(el,jet) < 0.4 skip the event
00127         foreach (const DressedLepton& el, _dressedelectrons) {
00128           if (deltaR(jet, el) < 0.4) _overlap = true;
00129         }
00130         // If dR(mu,jet) < 0.4 skip the event
00131         foreach (const DressedLepton& mu, _dressedmuons) {
00132           if (deltaR(jet, mu) < 0.4) _overlap = true;
00133         }
00134         // If dR(jet,jet) < 0.5 skip the event
00135         for (j = 0; j < _jets.size(); j++) {
00136           const Jet& jet2 = _jets[j];
00137           if (i == j) continue; // skip the diagonal
00138           if (deltaR(jet, jet2) < 0.5) _overlap = true;
00139         }
00140         // Count the number of b-tags
00141         if (!jet.bTags().empty()) _jet_ntag += 1;
00142       }
00143 
00144       // Evaluate basic event selection
00145       unsigned int ejets_bits = 0, mujets_bits = 0;
00146       bool pass_ejets = _ejets(ejets_bits);
00147       bool pass_mujets = _mujets(mujets_bits);
00148 
00149       // Remove events with object overlap
00150       if (_overlap) vetoEvent;
00151       // basic event selection requirements
00152       if (!pass_ejets && !pass_mujets) vetoEvent;
00153 
00154       // Check if the additional pT threshold requirements are passed
00155       bool pass_jetPt = _additionalJetCuts();
00156 
00157       // Count the jet multiplicity for 25, 40, 60 and 80GeV
00158       unsigned int ithres, jet_n[4];
00159       for (ithres = 0; ithres < 4; ithres++) {
00160         jet_n[ithres] = _countJets(ithres);
00161       }
00162 
00163       // Fill histograms
00164       const double weight = event.weight();
00165       for (unsigned int ihist = 0; ihist < 6; ihist++) {
00166         if (ihist > 0 && !pass_jetPt) continue; // additional pT threshold cuts for pT plots
00167         unsigned int threshLimit = _thresholdLimit(ihist);
00168         for (ithres = 0; ithres < threshLimit; ithres++) {
00169           if (jet_n[ithres] < 3) continue; // 3 or more jets for ljets
00170           // Fill
00171           if (ihist == 0) _histogram(ihist, ithres)->fill(jet_n[ithres], weight); // njets
00172           else if (ihist == 1) _histogram(ihist, ithres)->fill(_jets[0].pT(), weight); // leading jet pT
00173           else if (ihist == 2) _histogram(ihist, ithres)->fill(_jets[1].pT(), weight); // 2nd jet pT
00174           else if (ihist == 3 && jet_n[ithres] >= 3) _histogram(ihist, ithres)->fill(_jets[2].pT(), weight); // 3rd jet pT
00175           else if (ihist == 4 && jet_n[ithres] >= 4) _histogram(ihist, ithres)->fill(_jets[3].pT(), weight); // 4th jet pT
00176           else if (ihist == 5 && jet_n[ithres] >= 5) _histogram(ihist, ithres)->fill(_jets[4].pT(), weight); // 5th jet pT
00177         }
00178       }
00179     }
00180 
00181 
00182     void finalize() {
00183       // Normalize to cross-section
00184       const double norm = crossSection()/sumOfWeights();
00185       typedef map<unsigned int, Histo1DPtr>::value_type IDtoHisto1DPtr; ///< @todo Remove when C++11 allowed
00186       foreach (IDtoHisto1DPtr ihpair, _hMap) scale(ihpair.second, norm); ///< @todo Use normalize(ihpair.second, crossSection())
00187       // Calc averages
00188       for (unsigned int ihist = 0; ihist < _histLimit ; ihist++) {
00189         unsigned int threshLimit = _thresholdLimit(ihist);
00190         for (unsigned int ithres = 0; ithres < threshLimit; ithres++) {
00191           scale(_histogram(ihist, ithres), 0.5);
00192         }
00193       }
00194     }
00195 
00196 
00197 
00198   private:
00199 
00200 
00201     /// @name Cut helper functions
00202     //@{
00203 
00204     // Event selection functions
00205     bool _ejets(unsigned int& cutBits) {
00206       // 1. More than zero good electrons
00207       cutBits += 1; if (_dressedelectrons.size() == 0) return false;
00208       // 2. No additional electrons passing the veto selection
00209       cutBits += 1 << 1; if (_vetodressedelectrons.size() > 1) return false;
00210       // 3. No muons passing the veto selection
00211       cutBits += 1 << 2; if (_vetodressedmuons.size() > 0) return false;
00212       // 4. total neutrino pT > 30 GeV
00213       cutBits += 1 << 3; if (_met_et <= 30.0*GeV) return false;
00214       // 5. MTW > 35 GeV
00215       cutBits += 1 << 4;
00216       if (_transMass(_dressedelectrons[0].pT(), _dressedelectrons[0].phi(), _met_et, _met_phi) <= 35*GeV) return false;
00217       // 6. At least one b-tagged jet
00218       cutBits += 1 << 5; if (_jet_ntag < 1) return false;
00219       // 7. At least three good jets
00220       cutBits += 1 << 6; if (_jets.size() < 3) return false;
00221       cutBits += 1 << 7;
00222       return true;
00223     }
00224 
00225     bool _mujets(unsigned int& cutBits) {
00226       // 1. More than zero good muons
00227       cutBits += 1; if (_dressedmuons.size() == 0) return false;
00228       // 2. No additional muons passing the veto selection
00229       cutBits += 1 << 1; if (_vetodressedmuons.size() > 1) return false;
00230       // 3. No electrons passing the veto selection
00231       cutBits += 1 << 2; if (_vetodressedelectrons.size() > 0) return false;
00232       // 4. total neutrino pT > 30 GeV
00233       cutBits += 1 << 3; if (_met_et <= 30*GeV) return false;
00234       // 5. MTW > 35 GeV
00235       cutBits += 1 << 4;
00236       if (_transMass(_dressedmuons[0].pT(), _dressedmuons[0].phi(), _met_et, _met_phi) <= 35*GeV) return false;
00237       // 6. At least one b-tagged jet
00238       cutBits += 1 << 5; if (_jet_ntag < 1) return false;
00239       // 7. At least three good jets
00240       cutBits += 1 << 6; if (_jets.size() < 3) return false;
00241       cutBits += 1 << 7;
00242       return true;
00243     }
00244 
00245     bool _additionalJetCuts() {
00246       if (_jets.size() < 2) return false;
00247       if (_jets[0].pT() <= 50*GeV || _jets[1].pT() <= 35*GeV) return false;
00248       return true;
00249     }
00250 
00251     //@}
00252 
00253 
00254     /// @name Histogram helper functions
00255     //@{
00256 
00257     unsigned int _thresholdLimit(unsigned int histId) {
00258       if (histId == 0) return 4;
00259       return 1;
00260     }
00261 
00262     Histo1DPtr _histogram(unsigned int histId, unsigned int thresholdId) {
00263       assert(histId < _histLimit);
00264       assert(thresholdId < _thresholdLimit(histId));
00265 
00266       const unsigned int hInd = (histId == 0) ? thresholdId : (_thresholdLimit(0) + (histId-1) + thresholdId);
00267       if (_hMap.find(hInd) != _hMap.end()) return _hMap[hInd];
00268 
00269       if (histId == 0) _hMap.insert(make_pair(hInd,bookHisto1D(1,thresholdId+1,1)));
00270       else _hMap.insert(make_pair(hInd,bookHisto1D(2,histId,1)));
00271       return _hMap[hInd];
00272     }
00273 
00274     //@}
00275 
00276 
00277     /// @name Physics object helper functions
00278     //@{
00279 
00280     double _transMass(double ptLep, double phiLep, double met, double phiMet) {
00281       return sqrt(2.0*ptLep*met*(1 - cos(phiLep-phiMet)));
00282     }
00283 
00284     unsigned int _countJets(unsigned int ithres) {
00285       if (ithres > 4) assert(0);
00286       double pTcut[4] = {25.,40.,60.,80.};
00287       unsigned int i, jet_n = 0;
00288       for (i = 0; i < _jets.size(); i++) {
00289         if (_jets[i].pT() > pTcut[ithres]) jet_n++;
00290       }
00291       unsigned int ncutoff[4] = {8,7,6,5};
00292       if (jet_n > ncutoff[ithres]) jet_n = ncutoff[ithres];
00293       return jet_n;
00294     }
00295 
00296     //@}
00297 
00298 
00299   private:
00300 
00301     /// @name Objects that are used by the event selection decisions
00302     //@{
00303     vector<DressedLepton> _dressedelectrons;
00304     vector<DressedLepton> _vetodressedelectrons;
00305     vector<DressedLepton> _dressedmuons;
00306     vector<DressedLepton> _vetodressedmuons;
00307     Particles _neutrinos;
00308     Jets _jets;
00309     unsigned int _jet_ntag;
00310     /// @todo Why not store the whole MET FourMomentum?
00311     double _met_et, _met_phi;
00312     bool _overlap;
00313 
00314     map<unsigned int, Histo1DPtr> _hMap;
00315     //unsigned int _chanLimit;
00316     unsigned int _histLimit;
00317     //@}
00318 
00319   };
00320 
00321 
00322 
00323   // Declare the class as a hook for the plugin system
00324   DECLARE_RIVET_PLUGIN(ATLAS_2014_I1304688);
00325 
00326 }