Skip to content

04 Running a simplified trigger

Thiago Tomei edited this page Jul 2, 2020 · 5 revisions

Introduction

In Run 2, one of the trigger paths used for the Disappearing Tracks analysis was HLT_MET105_IsoTrk50. That path was available in many HLT menus used in 2018, including in the /online/collisions/2018/2e34/v3.5/HLT/V10 menu. That path, as it name suggests, selected events with missing Et above 105 GeV and an isolated track with pt above 50 GeV.

The full trigger configuration

By loading the file full_hlt.py, we can look at its paths and sequences in detail.

cmsrel CMSSW_10_1_10 # if needed
cd CMSSW_10_1_10/src
cmsenv
python -i full_hlt.py

Let us start by looking at the path itself

>>> process.HLT_MET105_IsoTrk50_v9
cms.Path(hltTriggerType+hltGtStage2Digis+hltGtStage2ObjectMap+hltScalersRawToDigi+hltOnlineBeamSpot+hltL1sETM80ToETM150+hltPreMET105IsoTrk50+hltEcalDigis+hltEcalUncalibRecHit+hltEcalDetIdToBeRecovered+hltEcalRecHit+hltHcalDigis+hltHbhePhase1Reco+hltHbhereco+hltHfprereco+hltHfreco+hltHoreco+hltTowerMakerForAll+hltMet+hltMET105+hltHcalNoiseInfoProducer+hltHcalTowerNoiseCleanerWithrechit+hltMetClean+hltMETClean65+hltEcalDigis+hltEcalUncalibRecHit+hltEcalDetIdToBeRecovered+hltEcalRecHit+hltHcalDigis+hltHbhePhase1Reco+hltHbhereco+hltHfprereco+hltHfreco+hltHoreco+hltTowerMakerForAll+hltAK4CaloJetsPF+hltAK4CaloJetsPFEt5+hltSiPixelDigis+hltSiPixelClusters+hltSiPixelClustersCache+hltSiPixelRecHits+hltSiStripExcludedFEDListProducer+hltSiStripRawToClustersFacility+hltSiStripClusters+hltPixelTracksFilter+hltPixelTracksFitter+hltPixelTracksTrackingRegions+hltPixelLayerQuadruplets+hltPixelTracksHitDoublets+hltPixelTracksHitQuadruplets+hltPixelTracks+hltPixelVertices+hltTrimmedPixelVertices+hltIter0PFLowPixelSeedsFromPixelTracks+hltIter0PFlowCkfTrackCandidates+hltIter0PFlowCtfWithMaterialTracks+hltIter0PFlowTrackCutClassifier+hltIter0PFlowTrackSelectionHighPurity+hltIter1ClustersRefRemoval+hltIter1MaskedMeasurementTrackerEvent+hltIter1PixelLayerQuadruplets+hltIter1PFlowPixelTrackingRegions+hltIter1PFlowPixelClusterCheck+hltIter1PFlowPixelHitDoublets+hltIter1PFlowPixelHitQuadruplets+hltIter1PixelTracks+hltIter1PFLowPixelSeedsFromPixelTracks+hltIter1PFlowCkfTrackCandidates+hltIter1PFlowCtfWithMaterialTracks+hltIter1PFlowTrackCutClassifierPrompt+hltIter1PFlowTrackCutClassifierDetached+hltIter1PFlowTrackCutClassifierMerged+hltIter1PFlowTrackSelectionHighPurity+hltIter1Merged+hltIter1TrackRefsForJets4Iter2+hltAK4Iter1TrackJets4Iter2+hltIter1TrackAndTauJets4Iter2+hltIter2ClustersRefRemoval+hltIter2MaskedMeasurementTrackerEvent+hltIter2PixelLayerTriplets+hltIter2PFlowPixelTrackingRegions+hltIter2PFlowPixelClusterCheck+hltIter2PFlowPixelHitDoublets+hltIter2PFlowPixelHitTriplets+hltIter2PFlowPixelSeeds+hltIter2PFlowCkfTrackCandidates+hltIter2PFlowCtfWithMaterialTracks+hltIter2PFlowTrackCutClassifier+hltIter2PFlowTrackSelectionHighPurity+hltIter2Merged+hltDoubletRecoveryClustersRefRemoval+hltDoubletRecoveryMaskedMeasurementTrackerEvent+hltDoubletRecoveryPixelLayersAndRegions+hltDoubletRecoveryPFlowPixelClusterCheck+hltDoubletRecoveryPFlowPixelHitDoublets+hltDoubletRecoveryPFlowPixelSeeds+hltDoubletRecoveryPFlowCkfTrackCandidates+hltDoubletRecoveryPFlowCtfWithMaterialTracks+hltDoubletRecoveryPFlowTrackCutClassifier+hltDoubletRecoveryPFlowTrackSelectionHighPurity+hltMergedTracks+hltDeDxEstimatorProducer+hltTrk50Filter+hltBoolEnd)

... it's a mess. The problem is that loading the file expands all sequences. If we instead we look at the file itself with an editor, we are able to see something that makes a bit more sense:

process.HLT_MET105_IsoTrk50_v9 = cms.Path( process.HLTBeginSequence + process.hltL1sETM80ToETM150 + process.hltPreMET105IsoTrk50 + process.HLTRecoMETSequence + process.hltMET105 + process.HLTHBHENoiseCleanerSequence + process.hltMetClean + process.hltMETClean65 + process.HLTRecoJetSequenceAK4PrePF + process.HLTDoLocalPixelSequence + process.HLTDoLocalStripSequence + process.HLTRecopixelvertexingSequence + process.HLTIterativeTrackingIter02 + process.hltDeDxEstimatorProducer + process.hltTrk50Filter + process.HLTEndSequence )

Let us look at each of those building blocks in isolation.

L1 seed

>>> process.hltL1sETM80ToETM150
cms.EDFilter("HLTL1TSeed",
    L1EGammaInputTag = cms.InputTag("hltGtStage2Digis","EGamma"),
    L1EtSumInputTag = cms.InputTag("hltGtStage2Digis","EtSum"),
    L1GlobalInputTag = cms.InputTag("hltGtStage2Digis"),
    L1JetInputTag = cms.InputTag("hltGtStage2Digis","Jet"),
    L1MuonInputTag = cms.InputTag("hltGtStage2Digis","Muon"),
    L1ObjectMapInputTag = cms.InputTag("hltGtStage2ObjectMap"),
    L1SeedsLogicalExpression = cms.string('L1_ETMHF90_HTT60er OR L1_ETMHF100 OR L1_ETMHF100_HTT60er OR L1_ETMHF110 OR L1_ETM150 OR L1_ETMHF110_HTT60er OR L1_ETMHF120 OR L1_ETMHF120_HTT60er OR L1_ETMHF150'),
    L1TauInputTag = cms.InputTag("hltGtStage2Digis","Tau"),
    saveTags = cms.bool(True)
)

The L1 seed is a big OR of many L1 algorithms. The names of the algorithms described what they do. For instance, L1_ETMHF90_HTT60er stands for missing Et (ETM), calculated including HF, above 90 GeV, AND total Ht, in an eta-restricted region (i.e. no HF), above 60 GeV.

Prescaler

>>> process.hltPreMET105IsoTrk50
cms.EDFilter("HLTPrescaler",
    L1GtReadoutRecordTag = cms.InputTag("hltGtStage2Digis"),
    offset = cms.uint32(0)
)

This is the prescaler that selects 1 out of N events. The offset tells you which is the first event accept, e.g. accepting 1 out of 4 events means you accept events, 0,4,8,... or events 1,5,9,....

Calo MET

>>> process.HLTRecoMETSequence
cms.Sequence(hltEcalDigis+hltEcalUncalibRecHit+hltEcalDetIdToBeRecovered+hltEcalRecHit+hltHcalDigis+hltHbhePhase1Reco+hltHbhereco+hltHfprereco+hltHfreco+hltHoreco+hltTowerMakerForAll+hltMet)

>>> process.hltMET105
cms.EDFilter("HLT1CaloMET",
    MaxEta = cms.double(-1.0),
    MaxMass = cms.double(-1.0),
    MinE = cms.double(-1.0),
    MinEta = cms.double(-1.0),
    MinMass = cms.double(-1.0),
    MinN = cms.int32(1),
    MinPt = cms.double(105.0),
    inputTag = cms.InputTag("hltMet"),
    saveTags = cms.bool(True),
    triggerType = cms.int32(87)
)

This sequences reconstructs the MET from calorimeter objects only (CaloMET), and applies a cut of 105 GeV. Notice that this path uses CaloMET only; other paths usually also use MET from ParticleFlow objects (PFMET) and use CaloMET as a preliminary cut only.

Clean MET

process.HLTHBHENoiseCleanerSequence + process.hltMetClean + process.hltMETClean65

This tries to clean the HCAL noise and applies another cut, this time at 65 GeV.

Calo jets

This sequence

>>> process.HLTRecoJetSequenceAK4PrePF
cms.Sequence(hltEcalDigis+hltEcalUncalibRecHit+hltEcalDetIdToBeRecovered+hltEcalRecHit+hltHcalDigis+hltHbhePhase1Reco+hltHbhereco+hltHfprereco+hltHfreco+hltHoreco+hltTowerMakerForAll+hltAK4CaloJetsPF+hltAK4CaloJetsPFEt5)

makes calorimeter towers, calorimeter jets:

>>> process.hltAK4CaloJetsPF
cms.EDProducer("FastjetJetProducer",
    Active_Area_Repeats = cms.int32(5),
    DxyTrVtxMax = cms.double(0.0),
    DzTrVtxMax = cms.double(0.0),
    GhostArea = cms.double(0.01),
    Ghost_EtaMax = cms.double(6.0),
    MaxVtxZ = cms.double(15.0),
    MinVtxNdof = cms.int32(5),
    R0 = cms.double(-1.0),
    Rho_EtaMax = cms.double(4.4),
    UseOnlyOnePV = cms.bool(False),
    UseOnlyVertexTracks = cms.bool(False),
    beta = cms.double(-1.0),
    correctShape = cms.bool(False),
    csRParam = cms.double(-1.0),
    csRho_EtaMax = cms.double(-1.0),
    dRMax = cms.double(-1.0),
    dRMin = cms.double(-1.0),
    doAreaDiskApprox = cms.bool(False),
    doAreaFastjet = cms.bool(False),
    doFastJetNonUniform = cms.bool(False),
    doPUOffsetCorr = cms.bool(False),
    doPVCorrection = cms.bool(False),
    doRhoFastjet = cms.bool(False),
    gridMaxRapidity = cms.double(-1.0),
    gridSpacing = cms.double(-1.0),
    inputEMin = cms.double(0.0),
    inputEtMin = cms.double(0.3),
    jetAlgorithm = cms.string('AntiKt'),
    jetCollInstanceName = cms.string(''),
    jetPtMin = cms.double(1.0),
    jetType = cms.string('CaloJet'),
    maxBadEcalCells = cms.uint32(9999999),
    maxBadHcalCells = cms.uint32(9999999),
    maxDepth = cms.int32(-1),
    maxInputs = cms.uint32(1),
    maxProblematicEcalCells = cms.uint32(9999999),
    maxProblematicHcalCells = cms.uint32(9999999),
    maxRecoveredEcalCells = cms.uint32(9999999),
    maxRecoveredHcalCells = cms.uint32(9999999),
    minSeed = cms.uint32(0),
    muCut = cms.double(-1.0),
    muMax = cms.double(-1.0),
    muMin = cms.double(-1.0),
    nExclude = cms.uint32(0),
    nFilt = cms.int32(-1),
    nSigmaPU = cms.double(1.0),
    puCenters = cms.vdouble(),
    puPtMin = cms.double(10.0),
    puWidth = cms.double(0.0),
    rFilt = cms.double(-1.0),
    rFiltFactor = cms.double(-1.0),
    rParam = cms.double(0.4),
    radiusPU = cms.double(0.4),
    rcut_factor = cms.double(-1.0),
    restrictInputs = cms.bool(False),
    src = cms.InputTag("hltTowerMakerForAll"),
    srcPVs = cms.InputTag("NotUsed"),
    subjetPtMin = cms.double(-1.0),
    subtractorName = cms.string(''),
    sumRecHits = cms.bool(False),
    trimPtFracMin = cms.double(-1.0),
    useCMSBoostedTauSeedingAlgorithm = cms.bool(False),
    useConstituentSubtraction = cms.bool(False),
    useDeterministicSeed = cms.bool(True),
    useDynamicFiltering = cms.bool(False),
    useExplicitGhosts = cms.bool(False),
    useFiltering = cms.bool(False),
    useKtPruning = cms.bool(False),
    useMassDropTagger = cms.bool(False),
    usePruning = cms.bool(False),
    useSoftDrop = cms.bool(False),
    useTrimming = cms.bool(False),
    verbosity = cms.int32(0),
    voronoiRfact = cms.double(-9.0),
    writeCompound = cms.bool(False),
    writeJetsWithConst = cms.bool(False),
    yCut = cms.double(-1.0),
    yMax = cms.double(-1.0),
    yMin = cms.double(-1.0),
    zcut = cms.double(-1.0)
)

and applies a minimal Et of 5 GeV only on them:

>>> process.hltAK4CaloJetsPFEt5
cms.EDFilter("EtMinCaloJetSelector",
    etMin = cms.double(5.0),
    filter = cms.bool(False),
    src = cms.InputTag("hltAK4CaloJetsPF")
)

Why do we make these minimal jets? The reason is that they are used in iterative tracking. In iterative tracking:

In the first iteration only the tracks seeded with very tight requirements are reconstructed, and the corresponding hits are locked. In the following iterations, the seeding selection becomes looser and looser, and is applied to the subset of hits not used in the earlier iterations.

Local Tracker reconstruction

process.HLTDoLocalPixelSequence + process.HLTDoLocalStripSequence

No big issues here. Local subdetector reconstruction is fairly stable at this point.

Tracking sequences

These are the big workhorses of the path.

>>> process.HLTRecopixelvertexingSequence
cms.Sequence(hltPixelTracksFilter+hltPixelTracksFitter+hltPixelTracksTrackingRegions+hltPixelLayerQuadruplets+hltPixelTracksHitDoublets+hltPixelTracksHitQuadruplets+hltPixelTracks+hltPixelVertices+hltTrimmedPixelVertices)

and

>>> process.HLTIterativeTrackingIter02
cms.Sequence(hltIter0PFLowPixelSeedsFromPixelTracks+hltIter0PFlowCkfTrackCandidates+hltIter0PFlowCtfWithMaterialTracks+hltIter0PFlowTrackCutClassifier+hltIter0PFlowTrackSelectionHighPurity+hltIter1ClustersRefRemoval+hltIter1MaskedMeasurementTrackerEvent+hltIter1PixelLayerQuadruplets+hltIter1PFlowPixelTrackingRegions+hltIter1PFlowPixelClusterCheck+hltIter1PFlowPixelHitDoublets+hltIter1PFlowPixelHitQuadruplets+hltIter1PixelTracks+hltIter1PFLowPixelSeedsFromPixelTracks+hltIter1PFlowCkfTrackCandidates+hltIter1PFlowCtfWithMaterialTracks+hltIter1PFlowTrackCutClassifierPrompt+hltIter1PFlowTrackCutClassifierDetached+hltIter1PFlowTrackCutClassifierMerged+hltIter1PFlowTrackSelectionHighPurity+hltIter1Merged+hltIter1TrackRefsForJets4Iter2+hltAK4Iter1TrackJets4Iter2+hltIter1TrackAndTauJets4Iter2+hltIter2ClustersRefRemoval+hltIter2MaskedMeasurementTrackerEvent+hltIter2PixelLayerTriplets+hltIter2PFlowPixelTrackingRegions+hltIter2PFlowPixelClusterCheck+hltIter2PFlowPixelHitDoublets+hltIter2PFlowPixelHitTriplets+hltIter2PFlowPixelSeeds+hltIter2PFlowCkfTrackCandidates+hltIter2PFlowCtfWithMaterialTracks+hltIter2PFlowTrackCutClassifier+hltIter2PFlowTrackSelectionHighPurity+hltIter2Merged+hltDoubletRecoveryClustersRefRemoval+hltDoubletRecoveryMaskedMeasurementTrackerEvent+hltDoubletRecoveryPixelLayersAndRegions+hltDoubletRecoveryPFlowPixelClusterCheck+hltDoubletRecoveryPFlowPixelHitDoublets+hltDoubletRecoveryPFlowPixelSeeds+hltDoubletRecoveryPFlowCkfTrackCandidates+hltDoubletRecoveryPFlowCtfWithMaterialTracks+hltDoubletRecoveryPFlowTrackCutClassifier+hltDoubletRecoveryPFlowTrackSelectionHighPurity+hltMergedTracks)

We will write material on them soon.

The simplified trigger configuration

The full_hlt.py contains all the HLT paths used in that menu, plus a lot of other ancillary configurations. We will work, for the time being, with a simplified version that contains only the path we are interested in: simplified.py. Unfortunately, that version doesn't have the sub-sequences defined; it simply lists all the modules one after another. It runs fine, however, and already has some special infrastructure that make it easy to run over a given set of input files:

cmsRun simplified.py inputFiles=file:/home/trtomei/data/skim_HighPU_325308/Run325308_LS97to107_PU121p5.root maxEvents=10

A first homework: rates

Run simplified.py in the high-PU events:

$ ls /home/trtomei/data/skim_HighPU_325308
Run325308_LS108To117_PU121p4.root
Run325308_LS125to135_PU119p6.root
Run325308_LS125to135_PU122p7.root
Run325308_LS125to135_PU128p0.root
Run325308_LS125to135_PU99p8.root
Run325308_LS46to56_PU109p7.root
Run325308_LS46to56_PU112p9.root
Run325308_LS46to56_PU115p7.root
Run325308_LS46to56_PU116p7.root
Run325308_LS46to56_PU96p5.root
Run325308_LS62to72_PU111p3.root
Run325308_LS62to72_PU117p4.root
Run325308_LS62to72_PU125p6.root
Run325308_LS62to72_PU97p2.root
Run325308_LS81to90_PU115p8.root
Run325308_LS97to107_PU101p3.root
Run325308_LS97to107_PU121p5.root
Run325308_LS97to107_PU124p8.root
Run325308_LS97to107_PU130p2.root

and calculate number of events passing vs pileup.

A second homework: timing

Add the following lines to simplified.py

# configure the FastTimerService
process.load( "HLTrigger.Timer.FastTimerService_cfi" )
# print a text summary at the end of the job
process.FastTimerService.printEventSummary         = False
process.FastTimerService.printRunSummary           = False
process.FastTimerService.printJobSummary           = True

# enable DQM plots
process.FastTimerService.enableDQM                 = True

# enable per-path DQM plots (starting with CMSSW 9.2.3-patch2)
process.FastTimerService.enableDQMbyPath           = True

# enable per-module DQM plots
process.FastTimerService.enableDQMbyModule         = True

# enable per-event DQM plots vs lumisection
process.FastTimerService.enableDQMbyLumiSection    = True
process.FastTimerService.dqmLumiSectionsRange      = 200

# set the time resolution of the DQM plots
process.FastTimerService.dqmTimeRange              = 4000.
process.FastTimerService.dqmTimeResolution         =   10.
process.FastTimerService.dqmPathTimeRange          = 1000.
process.FastTimerService.dqmPathTimeResolution     =    5.
process.FastTimerService.dqmModuleTimeRange        =  200.
process.FastTimerService.dqmModuleTimeResolution   =    1.

# set the base DQM folder for the plots
process.FastTimerService.dqmPath                   = 'HLT/TimerService'
process.FastTimerService.enableDQMbyProcesses      = False

to load the FastTimerService. This will produce a series of DQM files, that contain histograms of timing measurements.