Event Selection

Introduction

Overview

Teaching: 10 min
Exercises: 0 min
Questions
  • What did we learn in the physics objects pre-learning module?

  • How should I select events for a physics analysis?

Objectives
  • Summarize information available from POET for various physics objects.

  • Describe the fundamental elements of event selection in CMS.

What we’ve learned so far…

The CMS experment is a giant detector that acts like a camera that “photographs” particle collisions, allowing us to interpret their nature. In the Physics Objects pre-learning exercise, you read about the following physics objects reconstructed by CMS:

The Physics Object Extractor Tool is a collection of EDAnalyzer modules that can be used to process CMS MiniAOD files and extract information about the different physics objects.

Summary of POET contents

POET files are full of information! When you open a POET file you’ll see many “trees” in the myoutput.root that correspond to the results of different EDAnalyzer modules. The trees are “Friends” in the sense that they contain the same collision or simulation events in the same order, but they each contain different sets of information about the event.

Event Selection principles

When beginning a CMS analysis, there are three guiding principles to consider. Let’s assume you have a Feynman diagram in your head representing some physics process that you would like to measure or search for.

Guiding principles

  1. What physics objects should be present to represent the final state particles of my Feynman diagram? Should any of the objects be related to each other in a special way?
  2. What physics objects should NOT be present?
  3. What will cue CMS to store the types of events I want to analyze?

Choosing things to keep

No physics object in CMS is reconstructed with absolute certainty. We always need to consider whether a reconstructed object is “genunine” or “fake”, and the pre-computed identification algorithms are designed to help analysts avoid considering “fake” objects that were caused by spurious information such as detector noise. In fact, for jets, the noise-rejection identification algorithm is applied in POET universally for 2015!

Other considerations are whether objects are “prompt” or “nonprompt” (or “displaced”): muons from a Higgs boson 4-muon decay would be considered “prompt”; muons emerging from b-hadron decays within a jet would be considered “nonprompt”; and muons emerging far from the interaction point from the decay of some long-lived particle would be considered “displaced”. Identification and isolation algorithms can piece these differences apart, but each analysis will apply different choices.

Jets carry information about the quark or boson that produced them, which is described as “tagging” in CMS. Analysts can choose to implement a jet tagging algorithm to select out jets with certain features.

Choosing things to drop

All measurements and searches must consider background processes: reducible backgrounds with different final states that may pass event selection criteria due to some mismeasurement or fluctuation, and irreducible backgrounds with the same final state physics objects. Clever selection choices can often drop the rate of background processes significantly without sacrificing too many signal events. One basic example is the practice of using high momentum thresholds in searches for massive new physics particles, since SM processes with the same final state will preferentially result in low-momentum physics objects. Any physics object that can be selected can also be vetoed, depending on the needs of the analysis. An important part of this process is identifying and studying SM background processes!

Choosing a set of triggers

Triggers determine which collision events are kept or discarded by CMS, so it sounds like this criterion should be chosen first, but in practice it is typically chosen last. Armed with a set of physics object selection criteria, we can search for a “trigger” or set of triggers that should have passed any event that will also pass the analysis criteria. More on this next!

Key Points

  • POET output files contain the important kinematics, identification, isolation, and tagging information typically needed for analysis event selection.

  • Event selection criteria must be a reasoned balance of physics objects to keep, physics objects to reject, and trigger options from CMS.


CMS Trigger System

Overview

Teaching: 10 min
Exercises: 0 min
Questions
  • What is the CMS trigger system and why is it needed?

  • What is a trigger path in CMS?

  • How does the trigger depend on instantaneous luminosity and why are prescales necessary?

  • What do streams and datasets have to do with triggers?

Objectives
  • Learn about what the CMS trigger system is

  • Understand the basic concept of trigger paths

  • Understand the necessity of prescaling

  • Learn how the trigger system allows for the organization of CMSSW data in streams and datasets.

The CMS acquisition and trigger systems

Collisions at the LHC happen at a rate close to 40 million per second (40 MHz). Once each collision is sensed by the different subdetectors, the amount of information they generate corresponds to about what you can fit in a 1 MB file. If we were to record every single collision, it is said (you can do the math) that one can probably fill out all the available disk space in the world in a few days!

Not all collisions that happen at the LHC are interesting. We would like to keep the interesting ones and, most importantly, do not miss the discovery-quality ones. In order to achieve that we need a Trigger.

Before we jump into the details for the trigger system, let’s agree on some terminology:

The trigger system

Deciding on which events to record is the main purpose of the trigger system. It is like determining which events to record by taking a quick picture of it and, even though a bit blurry, decide whether it is interesting to keep or not for a future, more thorough inspection.

CMS does this in two main steps. The first one, the Level 1 trigger (L1), implemented in hardware (fast FPGAs), reduces the input rate of 40 Mhz to around 100 KHz. The other step is the High Level Trigger (HLT), run on commercial machines with good-old C++ and Python, where the input rate is leveled around the maximum available budget of around 2 KHz.

There are hundreds of different triggers in CMS. Each one of them is designed to pick certain types of events, with different intensities and topologies. For instance the HLT_Mu20 trigger, will select events with at least one muon with 20 GeV of transverse momentum.

At the HLT level, which takes L1 as input, triggers are implemented using CMSSW code using pieces of it (modules) that can be arranged to achieve the desired result: selecting specific kinds of events. Computationally, triggers are just Paths in the CMSSW sense, and one could extract a lot of information by exploring the Python configuration of these paths.

At the end of the configuration file, we could have something like

process.mypath = cms.Path (process.m1+process.m2+process.s1+process.m3)

, where m1, m2, m3 could be CMSSW modules (individual EDAnalyzers, EDFilters, EDProducers, etc.) and s1 could be a Sequence of modules.

An example of such an arrangement for an HLT trigger looks like:

process.HLT_Mu20_v2 = cms.Path( process.HLTBeginSequence + process.hltL1sL1SingleMu16 + process.hltPreMu20 + process.hltL1fL1sMu16L1Filtered0 + process.HLTL2muonrecoSequence + process.hltL2fL1sMu16L1f0L2Filtered10Q + process.HLTL3muonrecoSequence + process.hltL3fL1sMu16L1f0L2f10QL3Filtered20Q + process.HLTEndSequence )

Finally, triggers are code, and those pieces of code are constantly changing. Modifications to a trigger could imply a different version identifier. For instance, our HLT_Mu20 could actually be HLT_Mu15_v1 or HLT_Mu15_v2, etc., depending on the version. Therefore, it is completely normal that the trigger names can change from run to run.

Prescales

The need for prescales (and its meaning) is evident if one thinks of different physics processes having different cross sections. It is a lot more likely to record one minimum bias event, than an event where a Z boson is produced. Even less likely is to record an event with a Higgs boson. We could have triggers named, say, HLT_ZBosonRecorder for the one in charge of filtering Z-carrying events, or HLT_HiggsBosonRecorder for the one accepting Higgses (the actual names are more sophisticated and complex than that, of course.) The prescales are designed to keep these inputs under control by, for instance, recording just 1 out of 100 collisions that produce a likely Z boson, or 1 out of 1 collisions that produce a potential Higgs boson. In the former case, the prescale would be 100, while for the latter it would be 1; if a trigger has a prescale of 1, i.e., records every single event it identifies, we call it unprescaled.

Maybe not so evident is the need for trigger prescale changes for keeping up with luminosity changes. As the luminosity drops, prescales can be relaxed, and therefore could change from to run in the same fill.

A trigger can be prescaled at L1 as well as the HLT levels. L1 triggers have their own nomenclature and can be used as HLT trigger seeds.

Triggers, streams and datasets

After events are accepted by possibly more than one type of trigger, they are streamed in different categories, called streams and then classified and arranged in primary datasets. Most, but not all, of the datasets belonging to the stream A, the physics stream, are or will become available as CMS Open Data.

Finally, it is worth mentioning that:

Key Points

  • The CMS trigger system filters uninteresting events, keeping the budget high for the flow of interesting data.

  • Computationally, a trigger is a CMSSW path, which is composed of several software modules.

  • Trigger prescales allow the data acquisition to adjust to changes in instantaneous luminosity while keeping the rate of incomming data under control

  • The trigger systems allows for the classification and organization of datasets by physics objects of interest


MiniAOD triggering

Overview

Teaching: 10 min
Exercises: 10 min
Questions
  • How can I access trigger information from MiniAOD files?

  • What are trigger objects?

Objectives
  • Learn how one can retrieve trigger information like pass/fail bits or prescales from MiniAOD files

  • Learn what trigger objects are and why they are important

How to access trigger information

We would like to understand the trigger focusing on our final goal, which is to partially reproduce a \(t\bar{t}\) analysis from CMS. There are two primary ways to access trigger information, which both have uses for analysts:

MiniAOD triggering

First make sure to fire up your CMSSW Docker container if you haven’t already:

docker start -i my_od #use the name you gave to yours
cd PhysObjectExtractorTool/PhysObjectExtractor

Investigate the contents of a MiniAOD ROOT file:

edmDumpEventContent root://eospublic.cern.ch//eos/opendata/cms/mc/RunIIFall15MiniAODv2/TT_TuneCUETP8M1_13TeV-powheg-pythia8/MINIAODSIM/PU25nsData2015v1_76X_mcRun2_asymptotic_v12_ext3-v1/00000/02837459-03C2-E511-8EA2-002590A887AC.root
Type                                  Module                      Label             Process   
----------------------------------------------------------------------------------------------
LHEEventProduct                       "externalLHEProducer"       ""                "LHE"     
GenEventInfoProduct                   "generator"                 ""                "SIM"     
edm::TriggerResults                   "TriggerResults"            ""                "SIM"     
edm::TriggerResults                   "TriggerResults"            ""                "HLT"     
HcalNoiseSummary                      "hcalnoise"                 ""                "RECO"    
L1GlobalTriggerReadoutRecord          "gtDigis"                   ""                "RECO"    
double                                "fixedGridRhoAll"           ""                "RECO"    
double                                "fixedGridRhoFastjetAll"    ""                "RECO"    
double                                "fixedGridRhoFastjetAllCalo"   ""                "RECO"    
double                                "fixedGridRhoFastjetCentral"   ""                "RECO"    
double                                "fixedGridRhoFastjetCentralCalo"   ""                "RECO"    
double                                "fixedGridRhoFastjetCentralChargedPileUp"   ""                "RECO"    
double                                "fixedGridRhoFastjetCentralNeutral"   ""                "RECO"    
edm::TriggerResults                   "TriggerResults"            ""                "RECO"    
reco::BeamHaloSummary                 "BeamHaloSummary"           ""                "RECO"    
reco::BeamSpot                        "offlineBeamSpot"           ""                "RECO"    
vector<l1extra::L1EmParticle>         "l1extraParticles"          "Isolated"        "RECO"    
vector<l1extra::L1EmParticle>         "l1extraParticles"          "NonIsolated"     "RECO"    
vector<l1extra::L1EtMissParticle>     "l1extraParticles"          "MET"             "RECO"    
vector<l1extra::L1EtMissParticle>     "l1extraParticles"          "MHT"             "RECO"    
vector<l1extra::L1HFRings>            "l1extraParticles"          ""                "RECO"    
vector<l1extra::L1JetParticle>        "l1extraParticles"          "Central"         "RECO"    
vector<l1extra::L1JetParticle>        "l1extraParticles"          "Forward"         "RECO"    
vector<l1extra::L1JetParticle>        "l1extraParticles"          "IsoTau"          "RECO"    
vector<l1extra::L1JetParticle>        "l1extraParticles"          "Tau"             "RECO"    
vector<l1extra::L1MuonParticle>       "l1extraParticles"          ""                "RECO"    
edm::SortedCollection<EcalRecHit,edm::StrictWeakOrdering<EcalRecHit> >    "reducedEgamma"             "reducedEBRecHits"   "PAT"     
edm::SortedCollection<EcalRecHit,edm::StrictWeakOrdering<EcalRecHit> >    "reducedEgamma"             "reducedEERecHits"   "PAT"     
edm::SortedCollection<EcalRecHit,edm::StrictWeakOrdering<EcalRecHit> >    "reducedEgamma"             "reducedESRecHits"   "PAT"     
edm::TriggerResults                   "TriggerResults"            ""                "PAT"     
edm::ValueMap<float>                  "offlineSlimmedPrimaryVertices"   ""                "PAT"     
pat::PackedTriggerPrescales           "patTrigger"                ""                "PAT"     
pat::PackedTriggerPrescales           "patTrigger"                "l1max"           "PAT"     
pat::PackedTriggerPrescales           "patTrigger"                "l1min"           "PAT"     
vector<PileupSummaryInfo>             "slimmedAddPileupInfo"      ""                "PAT"     
vector<pat::Electron>                 "slimmedElectrons"          ""                "PAT"     
vector<pat::Jet>                      "slimmedJets"               ""                "PAT"     
vector<pat::Jet>                      "slimmedJetsAK8"            ""                "PAT"     
vector<pat::Jet>                      "slimmedJetsPuppi"          ""                "PAT"     
vector<pat::Jet>                      "slimmedJetsAK8PFCHSSoftDropPacked"   "SubJets"         "PAT"     
vector<pat::Jet>                      "slimmedJetsCMSTopTagCHSPacked"   "SubJets"         "PAT"     
vector<pat::MET>                      "slimmedMETs"               ""                "PAT"     
vector<pat::MET>                      "slimmedMETsPuppi"          ""                "PAT"     
vector<pat::Muon>                     "slimmedMuons"              ""                "PAT"     
vector<pat::PackedCandidate>          "lostTracks"                ""                "PAT"     
vector<pat::PackedCandidate>          "packedPFCandidates"        ""                "PAT"     
vector<pat::PackedGenParticle>        "packedGenParticles"        ""                "PAT"     
vector<pat::Photon>                   "slimmedPhotons"            ""                "PAT"     
vector<pat::Tau>                      "slimmedTaus"               ""                "PAT"     
vector<pat::TriggerObjectStandAlone>    "selectedPatTrigger"        ""                "PAT"     
vector<reco::CATopJetTagInfo>         "caTopTagInfosPAT"          ""                "PAT"     
vector<reco::CaloCluster>             "reducedEgamma"             "reducedEBEEClusters"   "PAT"     
vector<reco::CaloCluster>             "reducedEgamma"             "reducedESClusters"   "PAT"     
vector<reco::Conversion>              "reducedEgamma"             "reducedConversions"   "PAT"     
vector<reco::Conversion>              "reducedEgamma"             "reducedSingleLegConversions"   "PAT"     
vector<reco::GenJet>                  "slimmedGenJets"            ""                "PAT"     
vector<reco::GenJet>                  "slimmedGenJetsAK8"         ""                "PAT"     
vector<reco::GenParticle>             "prunedGenParticles"        ""                "PAT"     
vector<reco::GsfElectronCore>         "reducedEgamma"             "reducedGedGsfElectronCores"   "PAT"     
vector<reco::PhotonCore>              "reducedEgamma"             "reducedGedPhotonCores"   "PAT"     
vector<reco::SuperCluster>            "reducedEgamma"             "reducedSuperClusters"   "PAT"     
vector<reco::Vertex>                  "offlineSlimmedPrimaryVertices"   ""                "PAT"     
vector<reco::VertexCompositePtrCandidate>    "slimmedSecondaryVertices"   ""                "PAT"

There are various entries of type edm::TriggerResults, but we are specifically interested in the one labelled “PAT”. In the “PAT” collection section we also find selectedPatTrigger and patTrigger collections.

Although we do not have such analyzer yet, we know where to find information on how to implement it. If we go to the WorkBookMiniAOD2015 CMS Twiki page, we will find the relevant information necessary to our purposes. Let’s have a look.

As you can see, an example is already provided on how to build such an analyzer with its corresponding configuration.

We have copied the analyzer example here for you:

// system include files
#include <memory>
#include <cmath>

// user include files
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/EDAnalyzer.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"

#include "DataFormats/Math/interface/deltaR.h"
#include "FWCore/Common/interface/TriggerNames.h"
#include "DataFormats/Common/interface/TriggerResults.h"
#include "DataFormats/PatCandidates/interface/TriggerObjectStandAlone.h"
#include "DataFormats/PatCandidates/interface/PackedTriggerPrescales.h"

class MiniAODTriggerAnalyzer : public edm::EDAnalyzer {
   public:
      explicit MiniAODTriggerAnalyzer(const edm::ParameterSet&);
      ~MiniAODTriggerAnalyzer() {}

   private:
      virtual void analyze(const edm::Event&, const edm::EventSetup&) override;

      edm::EDGetTokenT<edm::TriggerResults> triggerBits_;
      edm::EDGetTokenT<pat::TriggerObjectStandAloneCollection> triggerObjects_;
      edm::EDGetTokenT<pat::PackedTriggerPrescales> triggerPrescales_;
};

MiniAODTriggerAnalyzer::MiniAODTriggerAnalyzer(const edm::ParameterSet& iConfig):
    triggerBits_(consumes<edm::TriggerResults>(iConfig.getParameter<edm::InputTag>("bits"))),
    triggerObjects_(consumes<pat::TriggerObjectStandAloneCollection>(iConfig.getParameter<edm::InputTag>("objects"))),
    triggerPrescales_(consumes<pat::PackedTriggerPrescales>(iConfig.getParameter<edm::InputTag>("prescales")))
{
}

void MiniAODTriggerAnalyzer::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup)
{
    edm::Handle<edm::TriggerResults> triggerBits;
    edm::Handle<pat::TriggerObjectStandAloneCollection> triggerObjects;
    edm::Handle<pat::PackedTriggerPrescales> triggerPrescales;

    iEvent.getByToken(triggerBits_, triggerBits);
    iEvent.getByToken(triggerObjects_, triggerObjects);
    iEvent.getByToken(triggerPrescales_, triggerPrescales);

    const edm::TriggerNames &names = iEvent.triggerNames(*triggerBits);
    std::cout << "\n === TRIGGER PATHS === " << std::endl;
    for (unsigned int i = 0, n = triggerBits->size(); i < n; ++i) {
        std::cout << "Trigger " << names.triggerName(i) << 
                ", prescale " << triggerPrescales->getPrescaleForIndex(i) <<
                ": " << (triggerBits->accept(i) ? "PASS" : "fail (or not run)") 
                << std::endl;
    }
    std::cout << "\n === TRIGGER OBJECTS === " << std::endl;
    for (pat::TriggerObjectStandAlone obj : *triggerObjects) { // note: not "const &" since we want to call unpackPathNames
        obj.unpackPathNames(names);
        std::cout << "\tTrigger object:  pt " << obj.pt() << ", eta " << obj.eta() << ", phi " << obj.phi() << std::endl;
        // Print trigger object collection and type
        std::cout << "\t   Collection: " << obj.collection() << std::endl;
        std::cout << "\t   Type IDs:   ";
        for (unsigned h = 0; h < obj.filterIds().size(); ++h) std::cout << " " << obj.filterIds()[h] ;
        std::cout << std::endl;
        // Print associated trigger filters
        std::cout << "\t   Filters:    ";
        for (unsigned h = 0; h < obj.filterLabels().size(); ++h) std::cout << " " << obj.filterLabels()[h];
        std::cout << std::endl;
        std::vector<std::string> pathNamesAll  = obj.pathNames(false);
        std::vector<std::string> pathNamesLast = obj.pathNames(true);
        // Print all trigger paths, for each one record also if the object is associated to a 'l3' filter (always true for the
        // definition used in the PAT trigger producer) and if it's associated to the last filter of a successfull path (which
        // means that this object did cause this trigger to succeed; however, it doesn't work on some multi-object triggers)
        std::cout << "\t   Paths (" << pathNamesAll.size()<<"/"<<pathNamesLast.size()<<"):    ";
        for (unsigned h = 0, n = pathNamesAll.size(); h < n; ++h) {
            bool isBoth = obj.hasPathName( pathNamesAll[h], true, true ); 
            bool isL3   = obj.hasPathName( pathNamesAll[h], false, true ); 
            bool isLF   = obj.hasPathName( pathNamesAll[h], true, false ); 
            bool isNone = obj.hasPathName( pathNamesAll[h], false, false ); 
            std::cout << "   " << pathNamesAll[h];
            if (isBoth) std::cout << "(L,3)";
            if (isL3 && !isBoth) std::cout << "(*,3)";
            if (isLF && !isBoth) std::cout << "(L,*)";
            if (isNone && !isBoth && !isL3 && !isLF) std::cout << "(*,*)";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;

}

//define this as a plug-in
DEFINE_FWK_MODULE(MiniAODTriggerAnalyzer);

And the configuration file from where we can snatch a valid snippet for our stolen analyzer:

import FWCore.ParameterSet.Config as cms

process = cms.Process("Demo")

process.load("FWCore.MessageService.MessageLogger_cfi")
process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(10) )

process.source = cms.Source("PoolSource",
    fileNames = cms.untracked.vstring(
        '/store/cmst3/user/gpetrucc/miniAOD/v1/TT_Tune4C_13TeV-pythia8-tauola_PU_S14_PAT.root'
    )
)

process.demo = cms.EDAnalyzer("MiniAODTriggerAnalyzer",
    bits = cms.InputTag("TriggerResults","","HLT"),
    prescales = cms.InputTag("patTrigger"),
    objects = cms.InputTag("selectedPatTrigger"),
)

process.p = cms.Path(process.demo)

Prep the MiniAODTriggerAnalyzer (Optional / Offline)

Let’s create a src/MiniAODTriggerAnalyzer.cc from scratch! From your local directory just open up your favorite editor and copy paste the code. Save it and compile with scram b, as always.

Now, let’s add the python module that we need to configure it to our python/poet_cfg.py file. We will call it myminiaodtrig instead of demo. From your local directory open the python/poet_cfg.py configuration file and add this module just before the process.simpletrig module (this is just to keep things organized).

Check your editing:

#---- Example on how to add trigger information
#---- To include it, uncomment the lines below and include the
#---- module in the final path
#process.mytriggers = cms.EDAnalyzer('TriggerAnalyzer',
#                              processName = cms.string("HLT"),
#                              #---- These are example of OR of triggers for 2015
#                              #---- Wildcards * and ? are accepted (with usual meanings)
#                              #---- If left empty, all triggers will run              
#                              triggerPatterns = cms.vstring("HLT_IsoMu20_v*","HLT_IsoTkMu20_v*"), 
#                              triggerResults = cms.InputTag("TriggerResults","","HLT")
#                              )

#---- test to see if we get trigger info ----
process.myminiaodtrig = cms.EDAnalyzer("MiniAODTriggerAnalyzer",
    bits = cms.InputTag("TriggerResults","","HLT"),
    prescales = cms.InputTag("patTrigger"),
    objects = cms.InputTag("selectedPatTrigger"),
)

#------------Example of simple trigger module with parameters by hand-------------------#
process.mysimpletrig = cms.EDAnalyzer('SimpleTriggerAnalyzer',
                              processName = cms.string("HLT"),
                              triggerResults = cms.InputTag("TriggerResults","","HLT")
                              )

Now let’s make sure it runs in the CMSSW path at the end of the configuration file. Let’s just add it to both options Data or MC. Make sure you add it to the beginning of the sequence. This is because we need to avoid the intial filters that are already in place (more on this later).

Check your editing:

if isData:
 process.p = cms.Path(process.myminiaodtrig+process.hltHighLevel+process.elemufilter+process.myelectrons+process.mymuons+process.mytaus+process.myphotons+process.mypvertex+process.mysimpletrig+
                             process.looseAK4Jets+process.patJetCorrFactorsReapplyJEC+process.slimmedJetsNewJEC+process.myjets+
                             process.looseAK8Jets+process.patJetCorrFactorsReapplyJECAK8+process.slimmedJetsAK8NewJEC+process.myfatjets+
                             process.uncorrectedMet+process.uncorrectedPatMet+process.Type1CorrForNewJEC+process.slimmedMETsNewJEC+process.mymets
                             )
else:
process.p = cms.Path(process.myninioaodtrig+process.hltHighLevel+process.elemufilter+process.myelectrons+process.mymuons+process.mytaus+process.myphotons+process.mypvertex+process.mysimpletrig+
                             process.mygenparticle+process.looseAK4Jets+process.patJetCorrFactorsReapplyJEC+
                             process.slimmedJetsNewJEC+process.myjets+process.looseAK8Jets+process.patJetCorrFactorsReapplyJECAK8+
                             process.slimmedJetsAK8NewJEC+process.myfatjets+process.uncorrectedMet+process.uncorrectedPatMet+
                             process.Type1CorrForNewJEC+process.slimmedMETsNewJEC+process.mymets
                             )

Lets do just one more change before we get to run POET. Let’s print out for each event, we can achive that by changing the MessageLogger lines to:

#---- Configure the framework messaging system
#---- https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideMessageLogger
process.load("FWCore.MessageService.MessageLogger_cfi")
#process.MessageLogger.cerr.threshold = "WARNING"
#process.MessageLogger.categories.append("POET")
#process.MessageLogger.cerr.INFO = cms.untracked.PSet(
#    limit=cms.untracked.int32(-1))
#process.options = cms.untracked.PSet(wantSummary=cms.untracked.bool(True))
process.MessageLogger.cerr.FwkReport.reportEvery = 1

I.e., comment out most of the lines leaving on only the first one and adding the process.MessageLogger.cerr.FwkReport.reportEvery = 1 line.

Trigger dump from MiniAOD (Optional / Offline)

Now, let’s run with cmsRun python/poet_cfg.py True. We will get a lot of print-outs. Let’s check the printout for the last event:

View dump

Begin processing the 100th record. Run 259809, Event 167531933, LumiSection 132 at 31-Jul-2022 18:03:21.705 CEST

 === TRIGGER PATHS === 
Trigger HLTriggerFirstPath, prescale 1: fail (or not run)
Trigger HLT_AK8PFJet360_TrimMass30_v3, prescale 1: fail (or not run)
Trigger HLT_AK8PFHT700_TrimR0p1PT0p03Mass50_v3, prescale 1: fail (or not run)
Trigger HLT_AK8PFHT650_TrimR0p1PT0p03Mass50_v2, prescale 1: fail (or not run)
Trigger HLT_AK8PFHT600_TrimR0p1PT0p03Mass50_BTagCSV0p45_v2, prescale 1: fail (or not run)
Trigger HLT_CaloJet500_NoJetID_v2, prescale 1: fail (or not run)
Trigger HLT_Dimuon13_PsiPrime_v2, prescale 1: fail (or not run)
Trigger HLT_Dimuon13_Upsilon_v2, prescale 1: fail (or not run)
Trigger HLT_Dimuon20_Jpsi_v2, prescale 1: fail (or not run)
Trigger HLT_DoubleEle24_22_eta2p1_WPLoose_Gsf_v2, prescale 1: fail (or not run)
Trigger HLT_DoubleEle33_CaloIdL_GsfTrkIdVL_MW_v3, prescale 1: fail (or not run)
Trigger HLT_DoubleEle33_CaloIdL_GsfTrkIdVL_v3, prescale 1: fail (or not run)
Trigger HLT_DoubleMediumIsoPFTau35_Trk1_eta2p1_Reg_v2, prescale 1: fail (or not run)
Trigger HLT_DoubleMediumIsoPFTau40_Trk1_eta2p1_Reg_v4, prescale 1: fail (or not run)
Trigger HLT_DoubleMu33NoFiltersNoVtx_v2, prescale 1: fail (or not run)
Trigger HLT_DoubleMu38NoFiltersNoVtx_v2, prescale 1: fail (or not run)
Trigger HLT_DoubleMu23NoFiltersNoVtxDisplaced_v2, prescale 1: fail (or not run)
Trigger HLT_DoubleMu28NoFiltersNoVtxDisplaced_v2, prescale 1: fail (or not run)
Trigger HLT_DoubleMu4_3_Bs_v2, prescale 1: fail (or not run)
Trigger HLT_DoubleMu4_3_Jpsi_Displaced_v2, prescale 1: fail (or not run)
.
.
.
=== TRIGGER OBJECTS === 
 Trigger object:  pt 23.8237, eta -1.59244, phi 0.781614
    Collection: hltHighPtTkMuonCands::HLT
    Type IDs:    83
    Filters:     hltL3fL1sMu16L1f0Tkf18QL3OldCalotrkIsoFiltered0p09 hltL3fL1sMu16L1f0Tkf18QL3trkIsoFiltered0p09 hltL3fL1sMu16L1f0Tkf20QL3trkIsoFiltered0p09 hltL3fL1sMu16f0TkFiltered18Q hltL3fL1sMu16f0TkFiltered18QL3OldpfhcalIsoRhoFilteredHB0p21HE0p22 hltL3fL1sMu16f0TkFiltered18QL3pfOldecalIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu16f0TkFiltered18QL3pfecalIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu16f0TkFiltered18QL3pfhcalIsoRhoFilteredHB0p21HE0p22 hltL3fL1sMu16f0TkFiltered20Q hltL3fL1sMu16f0TkFiltered20QL3pfecalIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu16f0TkFiltered20QL3pfhcalIsoRhoFilteredHB0p21HE0p22 hltL3fL1sMu20L1f0Tkf22QL3trkIsoFiltered0p09 hltL3fL1sMu20f0TkFiltered22Q hltL3fL1sMu20f0TkFiltered22QL3pfecalIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu20f0TkFiltered22QL3pfhcalIsoRhoFilteredHB0p21HE0p22
    Paths (4/4):       HLT_OldIsoTkMu18_v2(L,3)   HLT_IsoTkMu18_v2(L,3)   HLT_IsoTkMu20_v4(L,3)   HLT_IsoTkMu22_v2(L,3)
 Trigger object:  pt 34.9, eta -1.598, phi 0.766604
    Collection: hltL2MuonCandidates::HLT
    Type IDs:    83
    Filters:     hltL2fL1sMu14erorMu16L1f0L2Filtered0 hltL2fL1sMu16Eta2p1L1f0L2Filtered10Q hltL2fL1sMu16L1f0L2Filtered10Q hltL2fL1sMu16erorMu20erL1f0L2Filtered16Q hltL2fL1sMu16orMu20erorMu25L1f0L2Filtered0 hltL2fL1sMu16orMu25L1f0L2Filtered10Q hltL2fL1sMu16orMu25L1f0L2Filtered16Q hltL2fL1sMu16orMu25L1f0L2Filtered25 hltL2fL1sMu20L1f0L2Filtered10Q hltL2fL1sMu25L1f0L2Filtered10Q hltL2fL1sSingleMu16erL1f0L2Filtered10Q
    Paths (4/0):       HLT_IsoMu18_v2(*,3)   HLT_OldIsoMu18_v1(*,3)   HLT_IsoMu20_v3(*,3)   HLT_IsoMu22_v2(*,3)
 Trigger object:  pt 37.6634, eta -1.59606, phi 0.757304
    Collection: hltL2MuonCandidatesNoVtx::HLT
    Type IDs:    83
    Filters:     hltL2fL1sMu16orMu25L1f0L2NoVtxFiltered16
    Paths (0/0):    
 Trigger object:  pt 23.7557, eta -1.59244, phi 0.781631
    Collection: hltL3MuonCandidates::HLT
    Type IDs:    83
    Filters:     hltL3crIsoL1sMu16Eta2p1L1f0L2f10QL3f20QL3trkIsoFiltered0p09 hltL3crIsoL1sMu16L1f0L2f10QL3f18QL3OldCaloIsotrkIsoFiltered0p09 hltL3crIsoL1sMu16L1f0L2f10QL3f18QL3trkIsoFiltered0p09 hltL3crIsoL1sMu16L1f0L2f10QL3f20QL3trkIsoFiltered0p09 hltL3crIsoL1sMu20L1f0L2f10QL3f22QL3trkIsoFiltered0p09 hltL3crIsoL1sSingleMu16erL1f0L2f10QL3f17QL3pfecalIsoRhoFilteredEB0p11EE0p08 hltL3crIsoL1sSingleMu16erL1f0L2f10QL3f17QL3pfhcalIsoRhoFilteredHB0p21HE0p22 hltL3crIsoL1sSingleMu16erL1f0L2f10QL3f17QL3trkIsoFiltered0p09 hltL3fL1sMu14erorMu16L1f0L2f0L3Filtered16 hltL3fL1sMu16Eta2p1L1f0L2f10QL3Filtered20Q hltL3fL1sMu16Eta2p1L1f0L2f10QL3Filtered20QL3pfecalIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu16Eta2p1L1f0L2f10QL3Filtered20QL3pfhcalIsoRhoFilteredHB0p21HE0p22 hltL3fL1sMu16L1f0L2f10QL3Filtered18Q hltL3fL1sMu16L1f0L2f10QL3Filtered18QL3pfecalIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu16L1f0L2f10QL3Filtered18QL3pfecalOldIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu16L1f0L2f10QL3Filtered18QL3pfhcalIsoRhoFilteredHB0p21HE0p22 hltL3fL1sMu16L1f0L2f10QL3Filtered18QL3pfhcalOldIsoRhoFilteredHB0p21HE0p22 hltL3fL1sMu16L1f0L2f10QL3Filtered20Q hltL3fL1sMu16L1f0L2f10QL3Filtered20QL3pfecalIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu16L1f0L2f10QL3Filtered20QL3pfhcalIsoRhoFilteredHB0p21HE0p22 hltL3fL1sMu20L1f0L2f10QL3Filtered22Q hltL3fL1sMu20L1f0L2f10QL3Filtered22QL3pfecalIsoRhoFilteredEB0p11EE0p08 hltL3fL1sMu20L1f0L2f10QL3Filtered22QL3pfhcalIsoRhoFilteredHB0p21HE0p22 hltL3fL1sSingleMu16erL1f0L2f10QL3Filtered17Q
    Paths (4/4):       HLT_OldIsoMu18_v1(L,3)   HLT_IsoMu18_v2(L,3)   HLT_IsoMu20_v3(L,3)   HLT_IsoMu22_v2(L,3)
 Trigger object:  pt 40, eta -1.55, phi 0.698132
    Collection: hltL1extraParticles::HLT
    Type IDs:    -81
    Filters:     hltL1sAlCaRPC hltL1sL1SingleMu14erORSingleMu16 hltL1sL1SingleMu16 hltL1sL1SingleMu16ORSingleMu20erORSingleMu25 hltL1sL1SingleMu16ORSingleMu25 hltL1sL1SingleMu16er hltL1sL1SingleMu16erORSingleMu20er hltL1sL1SingleMu20 hltL1sL1SingleMu20er hltL1sL1SingleMu25
    Paths (8/0):       HLT_IsoMu18_v2(*,3)   HLT_OldIsoMu18_v1(*,3)   HLT_IsoMu20_v3(*,3)   HLT_IsoTkMu18_v2(*,3)   HLT_OldIsoTkMu18_v2(*,3)   HLT_IsoTkMu20_v4(*,3)   HLT_IsoMu22_v2(*,3)   HLT_IsoTkMu22_v2(*,3)

31-Jul-2022 18:03:21 CEST  Closed file root://eospublic.cern.ch//eos/opendata/cms/Run2015D/SingleMuon/MINIAOD/16Dec2015-v1/10000/00006301-CAA8-E511-AD39-549F35AD8BC9.root

Here are the final MiniAODTriggerAnalyzer.cc and poet_cfg.py files.

So, we not only get the triggers and their pass/fail status, but also the prescales and the possible trigger objects associated with them (associated with their trigger filters).

Trigger objects

Let’s explore the code which prints the last part to understand what it means. The HLT is like a reconstruction algorithm capable of identifying particles very very fast. Therefore, an HLT muon, for example, is a trigger object that has a four momentum. These trigger objects are associated to, commonly, the last filter executed by a given path in the HLT. Usually one wants to check whether a given particle that is being used in a given analysis coincides with the trigger object that fired the trigger (this is called trigger matching). We won’t go into more details about that.

std::cout << "\n === TRIGGER OBJECTS === " << std::endl;
    for (pat::TriggerObjectStandAlone obj : *triggerObjects) { // note: not "const &" since we want to call unpackPathNames
        obj.unpackPathNames(names);
        std::cout << "\tTrigger object:  pt " << obj.pt() << ", eta " << obj.eta() << ", phi " << obj.phi() << std::endl;
        // Print trigger object collection and type
        std::cout << "\t   Collection: " << obj.collection() << std::endl;
        std::cout << "\t   Type IDs:   ";
        for (unsigned h = 0; h < obj.filterIds().size(); ++h) std::cout << " " << obj.filterIds()[h] ;
        std::cout << std::endl;
        // Print associated trigger filters
        std::cout << "\t   Filters:    ";
        for (unsigned h = 0; h < obj.filterLabels().size(); ++h) std::cout << " " << obj.filterLabels()[h];
        std::cout << std::endl;
        std::vector<std::string> pathNamesAll  = obj.pathNames(false);
        std::vector<std::string> pathNamesLast = obj.pathNames(true);
        // Print all trigger paths, for each one record also if the object is associated to a 'l3' filter (always true for the
        // definition used in the PAT trigger producer) and if it's associated to the last filter of a successfull path (which
        // means that this object did cause this trigger to succeed; however, it doesn't work on some multi-object triggers)
        std::cout << "\t   Paths (" << pathNamesAll.size()<<"/"<<pathNamesLast.size()<<"):    ";
        for (unsigned h = 0, n = pathNamesAll.size(); h < n; ++h) {
            bool isBoth = obj.hasPathName( pathNamesAll[h], true, true ); 
            bool isL3   = obj.hasPathName( pathNamesAll[h], false, true ); 
            bool isLF   = obj.hasPathName( pathNamesAll[h], true, false ); 
            bool isNone = obj.hasPathName( pathNamesAll[h], false, false ); 
            std::cout << "   " << pathNamesAll[h];
            if (isBoth) std::cout << "(L,3)";
            if (isL3 && !isBoth) std::cout << "(*,3)";
            if (isLF && !isBoth) std::cout << "(L,*)";
            if (isNone && !isBoth && !isL3 && !isLF) std::cout << "(*,*)";
        }
        std::cout << std::endl;
    }

Finally, note that we are not writing any information into our myoutput.root file – but everything is configurable! Any of the printed quantities could have been stored in TTree branches instead.

Key Points

  • It is possible to retrieve trigger information from MiniAOD files directly

  • Trigger objects can be checked against reconstructed objects


Basic objects challenge

Overview

Teaching: 0 min
Exercises: 25 min
Questions
  • How should I construct selection criteria for a physics analysis?

Objectives
  • Combine trigger, identification, and isolation information into a full selection for a specific physics process.

All of the trigger and physics object information from this lesson is combined when designing the event selection procedure for a physics analysis.

Workshop analysis example: \(t\bar{t} \rightarrow (bjj)(b\ell\nu)\)

Later in the workshop we will use a measurement of the top quark pair production cross section as an example analysis. The signal for this measurement is one top quark that decays hadronically, and one top quark that decays leptonically, to either a muon or an electron.

Your analysis example

What is a physics process that you might study? Let’s design a possible CMS event selection. If your process includes a particle with multiple possible decay modes, choose one (or a small group of very similar decay modes) as a test case for this challenge.

For the \(t\bar{t}\) measurement and/or your own process of interest, use the information you have gained about triggers and physics objects to sketch out a possible event selection for your analysis.

Signal

Which final state particles would you expect to observe in the detector from your “signal” process?

Based on these particles, consider:

Background

Which SM backgrounds could easily mimic your signal, given a few extra physics objects, or a few missing physics objects?

Based on these processes, consider:

Key Points

  • Head to the next page for discussion!


Solutions and questions

Overview

Teaching: 15 min
Exercises: min
Questions
  • How should I construct selection criteria for a physics analysis?

Objectives
  • Combine trigger, identification, and isolation information into a full selection for a specific physics process.

All of the trigger and physics object information from this lesson is combined when designing the event selection procedure for a physics analysis.

Workshop analysis example: \(t\bar{t} \rightarrow (bjj)(b\ell\nu)\)

Later in the workshop we will use a measurement of the top quark pair production cross section as an example analysis. The signal for this measurement is one top quark that decays hadronically, and one top quark that decays leptonically, to either a muon or an electron.

Your analysis example

What is a physics process that you might study? Let’s design a possible CMS event selection. If your process includes a particle with multiple possible decay modes, choose one (or a small group of very similar decay modes) as a test case for this challenge.

For the \(t\bar{t}\) measurement and/or your own process of interest, use the information you have gained about triggers and physics objects to sketch out a possible event selection for your analysis.

Signal

Which final state particles would you expect to observe in the detector from your “signal” process?

Solution

For the \(t\bar{t}\) measurement we expect one electron or muon, MET from the accompanying neutrino, and several jets, some of which could be tagged as b quark jets.

Based on these particles, consider:

Solution

This analysis is perfect for the common “single lepton” triggers that require isolated leptons of moderate momentum in the central region of the detector. Central, isolated leptons are produced rarely enough that CMS can typically keep these triggers “unprescaled” for leptons down to about 20-30 GeV (though the threshold has needed to increase over time).

Let’s have a look at the trigger filter you can find in poet_cfg.py:

#----------- Turn on a trigger filter by adding this module to the the final path below -------#
process.hltHighLevel = cms.EDFilter("HLTHighLevel",
    TriggerResultsTag = cms.InputTag("TriggerResults","","HLT"),
    HLTPaths = cms.vstring('HLT_Ele22_eta2p1_WPLoose_Gsf_v*','HLT_IsoMu20_v*','HLT_IsoTkMu20_v*'),           # provide list of HLT paths (or patterns) you want
    eventSetupPathsKey = cms.string(''), # not empty => use read paths from AlCaRecoTriggerBitsRcd via this key
    andOr = cms.bool(True),             # how to deal with multiple triggers: True (OR) accept if ANY is true, False (AND) accept if ALL are true
    throw = cms.bool(True)    # throw exception on unknown path names
)

Solution

Certainly at least 1 muon or electron and 1 jet! Different event categories could be considered, depending on the number of jets or the number of b-tagged jets found in the event – an event with a muon or electron, 2 b-tagged jets, and 2 non-b-tagged jets has a higher probability to arise from top quark pair production than most other SM processes. A MET requirement is more tricky to choose: since the neutrinos involved in this event likely do not carry away very large momenta, imposing a MET threshold may not significantly improve the selection.

Solution

The trigger criterion imposes some constraints: we will lose muons with pT below 20 GeV and electrons with pT below 22 GeV or large pseudorapidity. Since there is typically some “turn-on” in the efficiency of the trigger selection, it would be safer to add a momentum buffer to our selection. This analysis requires:

  • Exactly 1 muon or electron with pT > 30 GeV and absolute \(\eta\) < 2.1
  • At least one jet with pT > 30 GeV and absolute \(\eta\) < 2.4. Avoiding low momentum jets reduces uncertainties due to jet energy corrections, and jets in the central region of the detector can be connected to tracks from the inner tracker for b-tagging algorithms.
  • POET branches: muon_pt, muon_eta, electron_pt, electron_eta, jet_corrpt, jet_eta

Solution

Electron selection:

  • The trigger includes the criterion “WPLoose”, which somewhat (though not always perfectly…) aligns with the “loose” working point of the identification algorithm stored in POET files. For selected electrons this analysis required they pass the “tight” working point.
  • We want to protect against selecting electrons that are “nonprompt”, so the 3D impact parameter of the electron should lie within 4 standard deviations of the primary interaction vertex.
  • POET branches: electron_isTight, electron_sip3d

Muon selection:

  • The ID is not restricted by the trigger, but the “tight” working point is by far the most popular choice for any signal muons.
  • The trigger does require “Iso”, so the analysis selection should also incorporate an isolation criterion. This is sensible since the muon is not expected to be produced very near to a jet. This analysis requires that the pileup-corrected particle-flow relative isolation be < 0.15.
  • We want to protect against selecting muons that are “nonprompt”, so the 3D impact parameter of the electron should lie within 4 standard deviations of the primary interaction vertex.
  • POET branches: muon_isTight, muon_pfreliso04DBCorr, muon_sip3d

Jet selection:

  • It is standard (and applied by default in POET 2015) to apply the noise-rejection jet ID
  • While no b-tagged jets are strictly required, the number of jets passing the “medium” working point of the CSV algorithm are counted.
  • POET branches: jet_btag

Solution

This analysis exploits one noteworthy correlation: one b-tagged jet (if it exists) should emerge from the same top quark as the lepton. The mass of this b-tagged jet and the lepton would show a sharp drop-off below the top quark mass. If more than one b-tagged jet is found in the event, the smallest mass combination of a b-tagged jet and a lepton often yields the correct pair.

Background

Which SM backgrounds could easily mimic your signal, given a few extra physics objects, or a few missing physics objects?

Solution

The dominant backgrounds for this measurement are SM processes that typically produce single-lepton final states: W boson production, and single top quark production. Due to its large cross section, multijet production can also have a large contribution, especially in categories with few b-tagged jets. Similarly, processes like Drell-Yan production that would typically lead to 2-lepton final states must be considered.

Based on these processes, consider:

Solution

The most important sample to include is \(W \rightarrow \ell \nu\) + jets, and single top quark production (the t-channel and tW production modes are most important). Smaller backgrounds from Drell-Yan production, \(t\bar{t} + W/Z\), and diboson production can also be modeled from simulation. Multijet (“QCD”) background simulation is often not used in final results because of the difficulty in modeling pure QCD interactions, so this background is more often estimated using data in alternate selection regions (“control regions”).

Solution

It is often useful to select events with exactly a certain number of objects rather than at least a certain number. Close study of background versus signal processes in simulation can help show which choices are best for a certain signal. In this case, exactly one muon or electron of the qualities described above is allowed in each event.

This analysis also enhances their measurement capabilities by categorizing events based on the number of jets and the number of b-tagged jets. Categories with more jets and more b-tagged jets are more likely to contain top quark pairs. This combination of background-heavy and signal-heavy categories often improves fit results by providing more information that can constain uncertainties in the background distributions.

Solution

Lepton veto: to protect against multi-lepton events, an event is rejected if additional leptons appear. This analysis applies a fairly strict veto, because the additional leptons are not held to the same high momentum and quality thresholds as the signal lepton:

  • Veto-quality muon: pT > 10 GeV, absolute \(\eta\) < 2.5, passing loose ID and isolation working points.
  • Veto-quality electron: pT > 15 GeV, absolute \(\eta\) < 2.5, passing loose ID and isolation working points.

Solution

Not particularly! The dominant W boson background has very similar lepton properties as top quark pairs, so this analysis relies primarily on the event categories to separate out background events.

Applying basic event filters in POET

When running POET on AOD or MiniAOD files, it is extremely useful to apply basic event filters due to the large size of the datasets involved. For the analysis example that we will use in the following lessons we have applied the trigger filter shown above, and a basic preliminary lepton filter, by uncommenting this EDFilter segment in the poet_cfg.py configuration file:

#---- Example of a very basic home-made filter to select only events of interest
#---- The filter can be added to the running path below if needed but is not applied by default
process.elemufilter = cms.EDFilter('SimpleEleMuFilter',
                                   electrons = cms.InputTag("slimmedElectrons"),
                                   muons = cms.InputTag("slimmedMuons"),
                                   vertices=cms.InputTag("offlineSlimmedPrimaryVertices"),
                                   mu_minpt = cms.double(26),
                                   mu_etacut = cms.double(2.1),
                                   ele_minpt = cms.double(26),
                                   ele_etacut = cms.double(2.1)
                                   )

So….how would I do this my own analysis?

The POET modules are set up to be general – for your own analysis you would only need to edit them if you require extra information that is not already stored. In poet_cfg.py you could configure your own filters for triggers or other objects, to reduce the run time and file size for POET jobs.

In the upcoming Analysis Example lesson you’ll learn to process POET files to apply selections and draw histograms. In the upcoming Cloud Computing lesson you’ll learn how to put this all together and scale it up.

Key Points

  • Triggers usually impose various kinematic restrictions on objects of interest.

  • Final state objects produced promptly from the proton collision are typically required to have significant momentum, tight ID quality, and to be isolated (depending on the topology of the physics process).

  • Veto objects are typically selected using looser criteria so that the efficiency of the veto is very high.

  • Correlations between objects can be used either to select specifically for signal events or reject background events.


Bonus Material (Offline): Triggering with HLT Providers

Overview

Teaching: 10 min
Exercises: 10 min
Questions
  • Why might I need to access the DB conditions for trigger studies?

  • What are the HLTConfigProvider and HLTPrescaleProvider classes?

Objectives
  • Learn why one might want to access additional trigger information from the conditions DB

  • Learn how to use the HLTConfigProvider and HLTPrescaleProvider classes

The HLTConfigProvider and HLTPrescaleProvider

While it is true that one can get most of the trigger information needed directly from the miniAOD files, like we found out in the last episode, there are some cases when this information is not enough. An example is the case of multi-object triggers. If one needs to study a trigger in detail it is likely that the HLTConfigProvider and the HLTPrescaleProvider classes are needed. As you can check for yourself these clases have several methods to extract a lot of trigger-related information. Several of those, like the ones related to prescale extraction, need access to the conditions DB. Fortunately, we already included that in the pre-exercises to get the transients tracks built correctly. We will cover a couple of examples.

Accessing trigger prescales and acceptance bits (Optional / Offline)

We already have a POET analyzer that uses the above clases. It has been implemented as src/TriggerAnalyzer.cc. The corresponding module in the python/poet_cfg.py is called mytriggers. It has been commented out so for this exercise will uncomment those lines: After you open the poet_cfg.py file and edit it, the snippet should should look like:

#---- Example on how to add trigger information
#---- To include it, uncomment the lines below and include the
#---- module in the final path
process.mytriggers = cms.EDAnalyzer('TriggerAnalyzer',
                              processName = cms.string("HLT"),
                              #---- These are example of OR of triggers for 2015
                              #---- Wildcards * and ? are accepted (with usual meanings)
                              #---- If left empty, all triggers will run              
                              triggerPatterns = cms.vstring("HLT_IsoMu20_v*","HLT_IsoTkMu20_v*"), 
                              triggerResults = cms.InputTag("TriggerResults","","HLT")
                              )

Note that the configuration file accepts sevaral triggers and wildcards. The combination is an OR of the triggers.

Let’s include this module in the final paths at the end of the poet_cfg.py file. Let’s replace the mysimpletrig module so we don’t pollute the print out.

if isData:
 process.p = cms.Path(process.mytriggers+process.hltHighLevel+process.elemufilter+process.myelectrons+process.mymuons+process.mytaus+process.myphotons+process.mypvertex+process.mysimpletrig+
                             process.looseAK4Jets+process.patJetCorrFactorsReapplyJEC+process.slimmedJetsNewJEC+process.myjets+
                             process.looseAK8Jets+process.patJetCorrFactorsReapplyJECAK8+process.slimmedJetsAK8NewJEC+process.myfatjets+
                             process.uncorrectedMet+process.uncorrectedPatMet+process.Type1CorrForNewJEC+process.slimmedMETsNewJEC+process.mymets
                             )
else:
 process.p = cms.Path(process.mytriggers+process.hltHighLevel+process.elemufilter+process.myelectrons+process.mymuons+process.mytaus+process.myphotons+process.mypvertex+process.mysimpletrig+
                             process.mygenparticle+process.looseAK4Jets+process.patJetCorrFactorsReapplyJEC+
                             process.slimmedJetsNewJEC+process.myjets+process.looseAK8Jets+process.patJetCorrFactorsReapplyJECAK8+
                             process.slimmedJetsAK8NewJEC+process.myfatjets+process.uncorrectedMet+process.uncorrectedPatMet+
                             process.Type1CorrForNewJEC+process.slimmedMETsNewJEC+process.mymets
                             )

Let’s run POET with the usual cmsRun python/poet_cfg.py True.

Let’s explore the output, i.e., let’s open the myoutput.root file.

Special Mac chip users:

You can download this file from the web and investigate it in the ROOT container.

wget https://jmhogan.web.cern.ch/jmhogan/OpenData/myoutput_triggerMuons.root
root -l myoutput.root

This is what you will see for the mytriggers map first and second. The first of this map is the name of the trigger and the second is the product of \(\text{L1 prescale}\times\text{HLT prescale}\times\text{acceptance bit}\).

Explore the code and get ready for the last challenge:

Dump the dataset triggers (Optional / Offline)

As an example of the kind of information you can retrieve using the HLTConfigProvider class, try to dump all the triggers that belong to all the datasets for a specific run.

Some hints:

  • Note that the HLTConfigProvider (or its cousin, the HLTPrescaleProvider) initialize every run. This is because the HLT menu can change from to run to run, as it was mentioned before.
  • There is a method in the HLTPrescaleProvider class to access the HLTConfigProvider (actually it is used in the code)
  • There is already a method in the HLTConfigProvider to dump (print out) the triggers for each dataset. It is called dump and you can pass the string “Datasets” to it.
  • Don’t forget to recompile before running.

Solution

Modify the src/TriggerAnalyzer.cc file to add the one-liner hltPrescaleProvider_.hltConfigProvider().dump("Datasets"); in the beginRun function:

// ------------ method called when starting to processes a run  ------------
void TriggerAnalyzer::beginRun(edm::Run const& iRun, edm::EventSetup const& iSetup)
//--------------------------------------------------------------------------
{
    using namespace std;
    using namespace edm;

    bool changed(true);
    hltPrescaleProvider_.init(iRun,iSetup,processName_,changed);
    if (changed){
      cout<<"HLTConfig has changed for this Run. . . "<<endl;
      hltPrescaleProvider_.hltConfigProvider().dump("Datasets");
   }
} //------------------- beginRun()

This is the final TriggerAnalyzer.cc file and the poet_cfg.py config file.

Key Points

  • A lot more information related to trigger can be obtained from the HLTConfigProvider and HLTPrescaleProvider and the conditions database