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