file analyses/Analysis_ATLAS_7TeV_1OR2LEPStop_4_7invfb.cpp

[No description available]

Namespaces

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

Classes

Name
classGambit::ColliderBit::Analysis_ATLAS_7TeV_1OR2LEPStop_4_7invfb

Defines

Name
CUTFLOWMAP(X)
f(x)
g(x)
VARMAP(X)
f(x)
g(x)

Macros Documentation

define CUTFLOWMAP

#define CUTFLOWMAP(
    X
)
      X(Total_events)				\
      X(electron_eq_4_jets)			\
      X(electron_met_gt_40)			\
      X(electron_eq_2_bjets)			\
      X(electron_sr)				\
      X(muon_eq_4_jets)				\
      X(muon_met_gt_40)				\
      X(muon_eq_2_bjets)			\
      X(muon_sr)				\
      X(twoLep_met_gt_40)			\
      X(twoLep_gt_1_bjet)			\
      X(mll_lt_81)				\
      X(mll_gt_30_lt_81)			\
      X(num_2lsr1)				\
      X(num_2lsr2)

define f

#define f(
    x
)
x,

define g

#define g(
    x
)
#x,

define VARMAP

#define VARMAP(
    X
)
      X(mTopHad)				\
      X(oneLepSqrtS)				\
      X(mllKey)					\
      X(twoLepSqrtS)

define f

#define f(
    x
)
x,

define g

#define g(
    x
)
#x,

Source code

//
// Created by dsteiner on 31/07/18.
// Amended by Martin White on 08/03/19.
//
// Based on https://atlas.web.cern.ch/Atlas/GROUPS/PHYSICS/PAPERS/SUSY-2012-10/ (arXiv:1209.2102)

//#include <gambit/ColliderBit/colliders/SpecializablePythia.hpp>
#include "gambit/ColliderBit/analyses/Analysis.hpp"
#include "gambit/ColliderBit/analyses/Cutflow.hpp"
#include <gambit/ColliderBit/ATLASEfficiencies.hpp>
#include "gambit/ColliderBit/analyses/AnalysisUtil.hpp"

namespace Gambit {
  namespace ColliderBit {

    using namespace std;
    using namespace HEPUtils;

    class Analysis_ATLAS_7TeV_1OR2LEPStop_4_7invfb : public Analysis {
public:

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


#define CUTFLOWMAP(X)               \
      X(Total_events)               \
      X(electron_eq_4_jets)         \
      X(electron_met_gt_40)         \
      X(electron_eq_2_bjets)            \
      X(electron_sr)                \
      X(muon_eq_4_jets)             \
      X(muon_met_gt_40)             \
      X(muon_eq_2_bjets)            \
      X(muon_sr)                \
      X(twoLep_met_gt_40)           \
      X(twoLep_gt_1_bjet)           \
      X(mll_lt_81)              \
      X(mll_gt_30_lt_81)            \
      X(num_2lsr1)              \
      X(num_2lsr2)
#define f(x) x,
#define g(x) #x,
      const std::vector<std::string> cutflowNames = {CUTFLOWMAP(g)};
      enum cutflowEnum {CUTFLOWMAP(f)};
#undef g
#undef f
#undef CUTFLOWMAP

#define VARMAP(X)               \
      X(mTopHad)                \
      X(oneLepSqrtS)                \
      X(mllKey)                 \
      X(twoLepSqrtS)
#define f(x) x,
#define g(x) #x,
      const std::vector<std::string> varNames = {VARMAP(g)};
      enum varEnum {VARMAP(f)};
#undef g
#undef f
#undef VARMAP

      std::map<std::string, std::vector<double>> varResults;

      std::map<std::string, int> cutflows;

      double num1LSR=0;
      double num2LSR1=0;
      double num2LSR2=0;

      std::vector<double> calcNuPz(double Mw, P4 metMom, P4 lepMom)
      {
    double mu = sqr(Mw) / 2.0 + metMom.px() * lepMom.px() + metMom.py() * lepMom.py();
    double denom = lepMom.E2() - lepMom.pz2();
    double a = mu * lepMom.pz() / denom;
    double a2 = sqr(a);
    double b = (lepMom.E2() * metMom.E2() - sqr(mu)) / denom;
    double delta = a2 - b;
    if (delta < 0)
      {
        return {a};
      }
    else
      {
        return {a + std::sqrt(delta), a - std::sqrt(delta)};
      }
      }

      P4 getBestHadronicTop(
                std::vector<const Jet *> bJets,
                std::vector<const Jet *> lightJets,
                const P4& leptonMom,
                const P4& metMom,
                double width,
                double mean
                )
      {
    // gaussian probability density function
    auto prob = [&width, &mean](P4 particle) {
      return 1 - std::erf(1.0 * std::abs(particle.m() - mean) / (std::sqrt(2.0) * width));
    };

    double pTotal = 0.0;
    P4 bestHadronicTop;
    std::vector<double> nuPzChoices = calcNuPz(80.0, metMom, leptonMom);
    P4 nu;
    for (double nuPz : nuPzChoices)
      {
        double nuE = std::sqrt(sqr(metMom.px()) + sqr(metMom.py()) + sqr(nuPz));
        nu.setPE(metMom.px(), metMom.py(), nuPz, nuE);
        P4 WLep = leptonMom + nu;
        // go through every bJet
        for (const Jet* firstBJet : bJets)
          {
        for (const Jet* secondBJet : bJets)
          {
            if (firstBJet == secondBJet)
              {
            continue;
              }
            P4 topLep = *firstBJet + WLep;
            // go through every combination of two light jets
            for (const Jet* firstLightJet : lightJets)
              {
            for (const Jet* secondLightJet : lightJets)
              {
                // don't want to use a light jet with itself
                if (firstLightJet == secondLightJet)
                  {
                continue;
                  }
                P4 WHad = *firstLightJet + *secondLightJet;
                P4 topHad = *secondBJet + WHad;
                // calculate a new probability
                double newPTotal = prob(topHad) * prob(WHad) * prob(topLep) * prob(WLep);
                if (newPTotal > pTotal)
                  {
                // update the best values
                pTotal = newPTotal;
                bestHadronicTop = topHad;
                  }
              }
              }
          }
          }
      }
    return bestHadronicTop;
      }

      double calcMt(P4 metVec, P4 lepVec)
      {
    double Met = metVec.pT();
    double pTLep = lepVec.pT();
    return std::sqrt(2 * pTLep * Met - 2 * AnalysisUtil::dot2D(lepVec, metVec));
      }


      double calcSqrtSSubMin(P4 visibleSubsystem, P4 invisbleSubsystem)
      {
    double visiblePart = std::sqrt(sqr(visibleSubsystem.m()) + sqr(visibleSubsystem.pT()));
    double invisiblePart = invisbleSubsystem.pT();
    double twoDimensionalVecSum =
      sqr(visibleSubsystem.px() + invisbleSubsystem.px())
      + sqr(visibleSubsystem.py() + invisbleSubsystem.py());
    return std::sqrt(sqr(visiblePart + invisiblePart) - twoDimensionalVecSum);
      }

      void getBJets(
            std::vector<const Jet*>& jets,
            std::vector<const Jet*>* bJets,
            std::vector<const Jet*>* lightJets)
      {
    /// @note We assume that b jets have previously been 100% tagged
    const std::vector<double> a = {0, 10.};
    const std::vector<double> b = {0, 10000.};
    const std::vector<double> c = {0.60};
    BinnedFn2D<double> _eff2d(a,b,c);
    for (const Jet* jet : jets)
      {
        bool hasTag = has_tag(_eff2d, jet->eta(), jet->pT());
        if(jet->btag() && hasTag && jet->abseta() < 2.5)
          {
        bJets->push_back(jet);
          }
        else
          {
        lightJets->push_back(jet);
          }
      }
      }


      /**
       * The constructor that should initialize some variables
       */
Analysis_ATLAS_7TeV_1OR2LEPStop_4_7invfb()
      {
    set_analysis_name("ATLAS_7TeV_1OR2LEPStop_4_7invfb");
    set_luminosity(4.7);
      }

      /**
       * Performs the main part of the analysis
       * @param event an event contain particle and jet information
       */
      void run(const HEPUtils::Event* event)
      {
    // TODO: take log of plots and constrain the plot range
    //HEPUtilsAnalysis::analyze(event);
    //cout << "Event number: " << num_events() << endl;
    incrementCut(Total_events);
    std::vector<const Particle*> electrons = event->electrons();
    std::vector<const Particle*> muons = event->muons();
    std::vector<const Jet*> jets = event->jets("antikt_R04");

    electrons = AnalysisUtil::filterPtEta(electrons, 20, 2.47);
    muons = AnalysisUtil::filterPtEta(muons, 10, 2.4);
    jets = AnalysisUtil::filterPtEta(jets, 20, 4.5);

    std::vector<const Jet*> bJets, lightJets;
    getBJets(jets, &bJets, &lightJets);

    jets = AnalysisUtil::jetLeptonOverlapRemoval(jets, electrons, 0.2);
    electrons = AnalysisUtil::leptonJetOverlapRemoval(electrons, jets, 0.4);
    muons = AnalysisUtil::leptonJetOverlapRemoval(muons, jets, 0.4);

    jets = AnalysisUtil::filterMaxEta(jets, 2.5);

    ATLAS::applyTightIDElectronSelection(electrons);

    std::vector<const Particle*> leptons = AnalysisUtil::getSortedLeptons({electrons, muons});
    std::sort(electrons.begin(), electrons.end(), AnalysisUtil::sortParticlesByPt);
    std::sort(muons.begin(), muons.end(), AnalysisUtil::sortParticlesByPt);
    std::sort(jets.begin(), jets.end(), AnalysisUtil::sortJetsByPt);
    std::sort(bJets.begin(), bJets.end(), AnalysisUtil::sortJetsByPt);
    std::sort(lightJets.begin(), lightJets.end(), AnalysisUtil::sortJetsByPt);

    size_t
      nLeptons = leptons.size(),
      nJets = jets.size(),
      nBJets = bJets.size(),
      nLightJets = lightJets.size();

    double Met = event->met();
    const P4& metVec = event->missingmom();

    if (nLeptons == 1)
      {
        if (!AnalysisUtil::muonFilter7TeV(muons) && muons.size() == 1)
          {
        return;
          }
        cutflowEnum a, b, c;
        if (electrons.size() == 1) a = electron_eq_4_jets, b = electron_met_gt_40, c = electron_eq_2_bjets;
        if (muons.size() == 1) a = muon_eq_4_jets, b = muon_met_gt_40, c = muon_eq_2_bjets;
        if (nJets == 4)
          {
        incrementCut(a);
        {
          if (Met > 40)
            {
              incrementCut(b);
              if (nBJets == 2)
            {
              incrementCut(c);
            }
            }
        }
          }
      }




    // minimal selection requirements for single lepton
    if (nLeptons == 1 && nBJets >= 2 && nLightJets >= 2 && Met > 40)
      {
        double mT = calcMt(metVec, leptons[0]->mom());

        auto isValidTop = [](double mean, double width, double mass) {return mass < mean - 0.5 * width;};

        if (mT > 30)
          {
        double mean = 0.0, width = 0.0;
        P4 hadronicTop;

        P4 visibleSubsystem = *leptons[0] + *lightJets[0] + *lightJets[1] + *bJets[0] + *bJets[1];
        double sqrtSsubMin = calcSqrtSSubMin(visibleSubsystem, metVec);
        bool isOneLep = false;
        // e-channel
        if (electrons.size() == 1 && electrons[0]->pT() > 25)
          {
            mean = 168.4, width = 18.0;
            hadronicTop = getBestHadronicTop(bJets, lightJets, *electrons[0], metVec, width, mean);
            isOneLep = true;
          }

        // mu-channel
        if (muons.size() == 1 && muons[0]->pT() > 20)
          {
            mean = 168.2, width = 18.6;
            hadronicTop = getBestHadronicTop(bJets, lightJets, *muons[0], metVec, width, mean);
            isOneLep = true;
          }


        bool validTop = isValidTop(mean, width, hadronicTop.m());

        if (isOneLep)
          {
            varResults[varNames[mTopHad]].push_back(hadronicTop.m());
            varResults[varNames[oneLepSqrtS]].push_back(sqrtSsubMin);
          }

        // check if we are in the 1LSR signal region
        if (isOneLep && validTop && sqrtSsubMin < 250)
          {
            num1LSR += event->weight();
            if (electrons.size() == 1) incrementCut(electron_sr);
            if (muons.size() == 1) incrementCut(muon_sr);
          }
          }
      }

    if (nLeptons == 2 && Met > 40 && AnalysisUtil::oppositeSign(leptons[0], leptons[1]) && nJets >= 2)
      {
        P4 ll = *leptons[0] + *leptons[1];
        double mll = ll.m();
        incrementCut(twoLep_met_gt_40);
        {
          if (nBJets >= 1)
        {
          incrementCut(twoLep_gt_1_bjet);
          if (mll < 81)
            {
              incrementCut(mll_lt_81);
            }
          if (mll < 81 && mll > 30)
            {
              incrementCut(mll_gt_30_lt_81);
            }
        }
        }
      }

    if (nLeptons == 2 && AnalysisUtil::oppositeSign(leptons[0], leptons[1]) && Met > 40 && nJets >= 2 && nBJets >= 1)
      {
        P4 ll = *leptons[0] + *leptons[1];
        double mll = ll.m();

        P4 visibleSubsystem = *leptons[0] + *leptons[1] + *jets[0] + *jets[1];

        double sqrtSsubMin = calcSqrtSSubMin(visibleSubsystem, metVec);

        double mlljj = visibleSubsystem.m();
        varResults[varNames[mllKey]].push_back(mll);
        if (mll > 30 && mll < 81)
          {
        bool isTwoLeptonEvent = false;

        // ee channel
        if (electrons.size() == 2 && electrons[0]->pT() > 25)
          {
            isTwoLeptonEvent = true;
          }

        // mu-mu channel
        if (muons.size() == 2 && muons[0]->pT() > 20)
          {
            isTwoLeptonEvent = true;
          }

        // e-mu channel
        if (electrons.size() == 1 && muons.size() == 1 && (electrons[0]->pT() > 25 || muons[0]->pT() > 20))
          {
            isTwoLeptonEvent = true;
          }

        if (isTwoLeptonEvent)
          {
            varResults[varNames[twoLepSqrtS]].push_back(sqrtSsubMin);

            if (sqrtSsubMin < 225)
              {
            num2LSR1 += event->weight();
            incrementCut(num_2lsr1);
              }
            if (sqrtSsubMin < 235 && mlljj < 140)
              {
            num2LSR2 += event->weight();
            incrementCut(num_2lsr2);
              }
          }
          }
      }
      }

/**
       * Adds results from other threads if OMP_NUM_THREAD != 1
       * @param other results from another thread
       */

      /// Combine the variables of another copy of this analysis (typically on another thread) into this one.
void combine(const Analysis* other)
{
  const Analysis_ATLAS_7TeV_1OR2LEPStop_4_7invfb* specificOther = dynamic_cast<const Analysis_ATLAS_7TeV_1OR2LEPStop_4_7invfb*>(other);
  num1LSR += specificOther->num1LSR;
  num2LSR1 += specificOther->num2LSR1;
  num2LSR2 += specificOther->num2LSR2;
}


      void collect_results()
      {
    //saveCutFlow();

    add_result(SignalRegionData("1LSR", 50, {num1LSR, 0.}, {38., 7.}));
    add_result(SignalRegionData("2LSR1", 123, {num2LSR1, 0.}, {115., 15.}));
    add_result(SignalRegionData("2LSR2", 47, {num2LSR2, 0.}, {46., 7.}));

    //cout << "1LSR: " << num1LSR << ", 2LSR1: " << num2LSR1 << ", 2LSR2: " << num2LSR2 << endl;

    /*for (std::pair<std::string, std::vector<double>> entry : varResults)
      {
        cout << "SAVE_START:" << entry.first << endl;
        for (double value : entry.second)
          {
        cout << value << endl;
          }
        cout << "SAVE_END" << endl;
        }*/
      }

protected:

void analysis_specific_reset()
{
  num1LSR = 0;
  num2LSR1 = 0;
  num2LSR2 = 0;
  for (std::string varName : varNames)
    {
      varResults[varName] = {};
    }
}

/*void scale(double factor)
  {
  HEPUtilsAnalysis::scale(factor);
  cout << "SAVE_XSEC:" << xsec() << endl;
  auto save = [](double value, std::string name)
  {
  cout << "SAVE_START:" << name << endl;
  cout << value << endl;
  cout << "SAVE_END" << endl;
  };
  save(num1LSR, "num1LSR");
  save(num2LSR1, "num2LSR1");
  save(num2LSR2, "num2LSR2");
  }*/


void incrementCut(int cutIndex)
{
  cutflows[cutflowNames[cutIndex]]++;
}

void saveCutFlow()
{
  double scale_by = 1.0;
  cout << "SAVE_START:cuts" << endl;
  cout << "CUT;RAW;SCALED;%" << endl;
  double initialCut = cutflows[cutflowNames[Total_events]];
  double thisCut;
  for (std::string name : cutflowNames) {
    thisCut = cutflows[name];
    cout << name.c_str() << ";"
     << thisCut << ";"
     << thisCut * scale_by << ";"
     << 100. * thisCut / initialCut
     << endl;
  }
  cout << "SAVE_END" << endl;
}
};

DEFINE_ANALYSIS_FACTORY(ATLAS_7TeV_1OR2LEPStop_4_7invfb)
}
}

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