file analyses/Analysis_ATLAS_13TeV_MONOJET_139infb.cpp

[No description available]

Namespaces

Name
Gambit
TODO: see if we can use this one:
Gambit::ColliderBit

Classes

Name
classGambit::ColliderBit::Analysis_ATLAS_13TeV_MONOJET_139infb
ATLAS Monojet analysis, with 139/fb of data.

Source code

// -*- C++ -*-
#include "gambit/ColliderBit/analyses/Analysis.hpp"
#include "gambit/ColliderBit/analyses/Cutflow.hpp"
#include "gambit/ColliderBit/ATLASEfficiencies.hpp"
#include "Eigen/Eigen"

// This is based on the ATLAS 139 invfb Monojet analysis, found at: https://arxiv.org/pdf/2102.10874.pdf

// #define CHECK_CUTFLOW

namespace Gambit
{
  namespace ColliderBit
  {

    using namespace std;
    using namespace HEPUtils;


    /// @brief ATLAS Monojet analysis, with 139/fb of data
    ///
    class Analysis_ATLAS_13TeV_MONOJET_139infb : public Analysis
    {
      public:

        // Required detector sim
        static constexpr const char* detector = "ATLAS";

        // Numbers passing cuts TODO: Do the inclusive as well
        std::map<string, EventCounter> _counters = {
          {"EM0", EventCounter("EM0")},
          {"EM1", EventCounter("EM1")},
          {"EM2", EventCounter("EM2")},
          {"EM3", EventCounter("EM3")},
          {"EM4", EventCounter("EM4")},
          {"EM5", EventCounter("EM5")},
          {"EM6", EventCounter("EM6")},
          {"EM7", EventCounter("EM7")},
          {"EM8", EventCounter("EM8")},
          {"EM9", EventCounter("EM9")},
          {"EM10", EventCounter("EM10")},
          {"EM11", EventCounter("EM11")},
          {"EM12", EventCounter("EM12")},
        };

        #ifdef CHECK_CUTFLOW
          Cutflows _cutflows;
        #endif

        static const size_t NUMSR = 13;

        Cutflow _cutflow;

        Analysis_ATLAS_13TeV_MONOJET_139infb()
        {

          analysis_specific_reset();
          set_analysis_name("ATLAS_13TeV_MONOJET_139infb");
          set_luminosity(139.0);

          #ifdef CHECK_CUTFLOW
            _cutflows.addCutflow("EM",{"MET>150", //The analysis starts with a trigger of Met > 150GeV
                                       "Lepton",
                                       "Njets<4",
                                       "min DeltaPhi",
                                       "Lead jet pT and eta",
                                       "MET>200"});
          #endif

        }

        // Overlap removal of particle if within delta R range of a jet
        void ejetOverlapRemoval(vector<const HEPUtils::Particle*>& electrons, vector<const HEPUtils::Jet*>& jets, double DeltaRMin, double DeltaRMax)
        {
          vector<const HEPUtils::Particle*> survivors;
          for(const HEPUtils::Particle* e : electrons)
          {
            bool overlap = false;
            for(const HEPUtils::Jet* jet : jets)
            {
              double dR = jet->mom().deltaR_eta(e->mom());
              if(fabs(dR)>=DeltaRMin && fabs(dR)<=DeltaRMax) overlap = true;
            }
            if(!overlap) survivors.push_back(e);
          }
          electrons = survivors;
          return;
        }


        void run(const Event* event)
        {

          #ifdef CHECK_CUTFLOW
            const double w = event->weight();
            _cutflows.fillinit(w);
          #endif

          // Require MET above 200 GeV
          const P4 pmiss = event->missingmom();
          const double met = event->met();

          // Define the cut booleans
          bool EM_ETmiss_gt_150 = false;
          bool EM_lep_lt_1 = false;
          bool EM_Njet_leq_4 = false;
          bool EM_min_deltaphi = false;
          //bool EM_lead_jet_quality = false;
          bool EM_lead_jet_ptandeta = false;
          bool EM_ETmiss_gt_200 = false;

          // lepton and photon objects
          vector<const HEPUtils::Particle*> baselineElectrons;
          vector<const HEPUtils::Particle*> baselineMuons;
          vector<const HEPUtils::Particle*> baselineTaus;
          vector<const HEPUtils::Particle*> baselinePhotons;

          // Fill electron object
          for (const Particle* e : event->electrons())
          {
            if (e->pT() > 7 && e->abseta()<2.47) baselineElectrons.push_back(e);
          }

          // Fill muon object
          for (const Particle* m : event->muons())
          {
            if (m->pT() > 7 && m->abseta()<2.5) baselineMuons.push_back(m);
          }

          // Fill tau object
          for (const Particle* t : event->taus())
          {
            if (t->pT() > 20 && t->abseta()<2.5) baselineTaus.push_back(t);
          }

          // Fill photon object
          for (const Particle* p : event->photons())
          {
            if (p->pT() > 10 && p->abseta()<2.37) baselinePhotons.push_back(p);
          }

          // Get jets (0.9 is to emulate the requirement of coming from a primary vertex)
          vector<const Jet*> baselineJets;
          for (const Jet* jet : event->jets("antikt_R04"))
          {
            if ((jet->pT() > 30) && (jet->abseta() < 2.8))
            {
              if (jet->pT() < 120 && jet->abseta() < 2.5)
              {
                if (random_bool(0.90)) baselineJets.push_back(jet);
              }
              else
              {
                baselineJets.push_back(jet);
              }
            }
          }

          // B-tag efficiencies
          // 60 % b-tag efficiency
          // 1/35 = 2.857% rejection factor for c-jets
          // 1/1500 = 0.066% rejection factor for gluons and light-quarks
          std::map<const Jet*,bool> analysisBtags = generateBTagsMap(baselineJets,0.6,0.02857,0.00066);

          vector<const Jet*> baselineBJets;
          vector<const Jet*> baselineNonBJets;
          for (const HEPUtils::Jet* j : baselineJets)
          {
            if (j->abseta() < 2.5 && analysisBtags.at(j))
            {
              baselineBJets.push_back(j);
            }
            else
            {
              baselineNonBJets.push_back(j);
            }
          }


          // Overlap removal
          // 1) Remove electrons with 0.01 of an muon, mimics shared tracks
          removeOverlap(baselineElectrons, baselineMuons, 0.01);
          // 2) Remove non-b-jets within DeltaR = 0.2 of electron
          removeOverlap(baselineNonBJets, baselineElectrons, 0.2);
          // 3) Remove electrons that are between 0.2 and 0.4 of a jet
          ejetOverlapRemoval(baselineElectrons, baselineNonBJets, 0.2, 0.4);
          ejetOverlapRemoval(baselineElectrons, baselineBJets, 0.2, 0.4);
          // 4) Remove jets within DeltaR = 0.4 of muon. We don't have track information (analysis specifies for 3 tracks)
          removeOverlap(baselineNonBJets, baselineMuons, 0.4);
          removeOverlap(baselineBJets, baselineMuons, 0.4);
          // 5) Any tau within 0.2 of an electron or muon is removed
          removeOverlap(baselineTaus, baselineElectrons, 0.2);
          removeOverlap(baselineTaus, baselineMuons, 0.2);
          // 6) Any jet within 0.2 of a tau is removed
          removeOverlap(baselineNonBJets, baselineTaus, 0.2);
          removeOverlap(baselineBJets, baselineTaus, 0.2);
          // 7) Any photon within 0.4 of a muon or electron is removed
          removeOverlap(baselinePhotons, baselineElectrons, 0.4);
          removeOverlap(baselinePhotons, baselineMuons, 0.4);
          // 8) Any jet within 0.4 of a photon is removed
          removeOverlap(baselineNonBJets, baselinePhotons, 0.4);
          removeOverlap(baselineBJets, baselinePhotons, 0.4);

          ATLAS::applyLooseIDElectronSelectionR2(baselineElectrons);

          // All jets
          vector<const HEPUtils::Jet*> signalJets = baselineNonBJets;
          signalJets.insert(signalJets.end(), baselineBJets.begin(), baselineBJets.end());

          // Sort by Pt
          sortByPt(signalJets);

          // Performing the cuts
          while(true)
          {

            // Require ETmiss > 150 GeV
            if (met > 150) {EM_ETmiss_gt_150 = true;}
            if (!EM_ETmiss_gt_150) break;

            // Veto on any leptons or photons
            if ((baselineElectrons.size() == 0) && (baselineMuons.size() == 0) && (baselineTaus.size() == 0) && (baselinePhotons.size() == 0)) {EM_lep_lt_1 = true;}
            if (!EM_lep_lt_1) break;

            // Require no more than 4 jets
            if (signalJets.size() <= 4) {EM_Njet_leq_4 = true;}
            if (!EM_Njet_leq_4) break;

            // Cut on maximum delta phi
            EM_min_deltaphi = true;
            for (size_t i = 0; i < 4; ++i)
            {
              if (i >= signalJets.size()) break;
              if (met>250)
              {
                if (fabs(deltaPhi(signalJets[i]->mom(), pmiss))<0.4) EM_min_deltaphi = false;
              }
              else
              {
                if (fabs(deltaPhi(signalJets[i]->mom(), pmiss))<0.6) EM_min_deltaphi = false;
              }
            }

            if (!EM_min_deltaphi) break;

            if (signalJets.empty()) break;
            if ((signalJets[0]->pT() > 150) && (signalJets[0]->abseta() < 2.4)) {EM_lead_jet_ptandeta = true;}
            if (!EM_lead_jet_ptandeta) break;

            // Require ETmiss > 200 GeV
            if (met > 200) {EM_ETmiss_gt_200 = true;}
            if (!EM_ETmiss_gt_200) break;

            // Fill signal regions
            // Identify the ptmiss bin and fill the counter
            const static vector<double> metedges = {200, 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200};
            const int i_sr = binIndex(met, metedges, true);

            if (i_sr >= 0)
            {
              std::stringstream sr_key; sr_key << "EM" << i_sr;
              _counters.at(sr_key.str()).add_event(event->weight(), event->weight_err());
            }

            // Applied all cuts
            break;
          }

          // Fill cutflow
          #ifdef CHECK_CUTFLOW
            if (EM_ETmiss_gt_150) _cutflows["EM"].fillnext(w);
            if (EM_lep_lt_1) _cutflows["EM"].fillnext(w);
            if (EM_Njet_leq_4) _cutflows["EM"].fillnext(w);
            if (EM_min_deltaphi) _cutflows["EM"].fillnext(w);
            if (EM_lead_jet_ptandeta) _cutflows["EM"].fillnext(w);
            if (EM_ETmiss_gt_200) _cutflows["EM"].fillnext(w);
          #endif

        }

        /// Combine the variables of another copy of this analysis (typically on another thread) into this one.
        void combine(const Analysis* other)
        {
          const Analysis_ATLAS_13TeV_MONOJET_139infb* specificOther = dynamic_cast<const Analysis_ATLAS_13TeV_MONOJET_139infb*>(other);
          for (auto& pair : _counters) { pair.second += specificOther->_counters.at(pair.first); }
        }


        void collect_results()
        {

          add_result(SignalRegionData(_counters.at("EM0"), 1791624, {1783000., 26000.}));
          add_result(SignalRegionData(_counters.at("EM1"), 752328, {753000., 9000.}));
          add_result(SignalRegionData(_counters.at("EM2"), 313912, {314000., 3500.}));
          add_result(SignalRegionData(_counters.at("EM3"), 141036, {140100., 1600.}));
          add_result(SignalRegionData(_counters.at("EM4"), 102888, {101600., 1200.}));
          add_result(SignalRegionData(_counters.at("EM5"), 29458, {29200., 400.}));
          add_result(SignalRegionData(_counters.at("EM6"), 10203, {10000., 180.}));
          add_result(SignalRegionData(_counters.at("EM7"), 3986, {3870., 80.}));
          add_result(SignalRegionData(_counters.at("EM8"), 1663, {1640., 40.}));
          add_result(SignalRegionData(_counters.at("EM9"), 738, {754., 20.}));
          add_result(SignalRegionData(_counters.at("EM10"), 413, {359., 10.}));
          add_result(SignalRegionData(_counters.at("EM11"), 187, {182., 6.}));
          add_result(SignalRegionData(_counters.at("EM12"), 207, {218., 9.}));

          #ifdef CHECK_CUTFLOW
            // Cutflow printout
            cout << "\nCUTFLOWS:\n" << _cutflows << endl;
            cout << "\nSRCOUNTS:\n";
            for (auto& pair : _counters) cout << pair.first << ": " << pair.second.weight_sum() << "\n";
            cout << "\n" << endl;
          #endif

        }

      protected:

        void analysis_specific_reset()
        {
          for (auto& pair : _counters) { pair.second.reset(); }
        }

    };

    // Factory fn
    DEFINE_ANALYSIS_FACTORY(ATLAS_13TeV_MONOJET_139infb)

  }
}

Updated on 2024-07-18 at 13:53:34 +0000