Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-05-04 22:50:51

0001 import FWCore.ParameterSet.Config as cms
0002 from PhysicsTools.NanoAOD.run3scouting_cff import *
0003 from EventFilter.L1TRawToDigi.gtStage2Digis_cfi import gtStage2Digis
0004 from PhysicsTools.NanoAOD.triggerObjects_cff import l1bits
0005 from PhysicsTools.NanoAOD.globals_cff import puTable
0006 
0007 ############################
0008 ### Sub Task Definitions ###
0009 ############################
0010 
0011 # Task contains all dependent tasks
0012 # ExtensionTask must be run on top of another Task
0013 
0014 #############################
0015 # Scouting Original Objects #
0016 #############################
0017 
0018 # Scouting Muon
0019 scoutingMuonTableTask = cms.Task(scoutingMuonTable)
0020 scoutingMuonDisplacedVertexTableTask = cms.Task(scoutingMuonDisplacedVertexTable)
0021 
0022 # from 2024, there are two muon collections (https://its.cern.ch/jira/browse/CMSHLT-3089)
0023 run3_scouting_nanoAOD_2024.toReplaceWith(scoutingMuonTableTask, cms.Task(scoutingMuonVtxTable, scoutingMuonNoVtxTable))\
0024     .toReplaceWith(scoutingMuonDisplacedVertexTableTask, cms.Task(scoutingMuonVtxDisplacedVertexTable, scoutingMuonNoVtxDisplacedVertexTable))
0025 
0026 # Scouting Electron
0027 scoutingElectronTableTask = cms.Task(scoutingElectronTable)
0028 
0029 # from 2023, scouting electron's tracks are added as std::vector since multiple tracks can be associated to a scouting electron
0030 # plugin to select the best track to reduce to a single track per scouting electron is added
0031 (run3_scouting_nanoAOD_2023 | run3_scouting_nanoAOD_2024).toReplaceWith(
0032      scoutingElectronTableTask, cms.Task(scoutingElectronBestTrack, scoutingElectronTable)
0033 )
0034 
0035 # other collections are directly from original Run3Scouting objects, so unnessary to define tasks
0036 
0037 ############################
0038 # Scouting Derived Objects #
0039 ############################
0040 
0041 scoutingPFCandidateTask = cms.Task(scoutingPFCandidate, scoutingPFCandidateTable)
0042 scoutingPFJetReclusterTask = cms.Task(
0043     scoutingPFCandidate, # translate to reco::PFCandidate, used as input
0044     scoutingPFJetRecluster, # jet clustering
0045     scoutingPFJetReclusterParticleNetJetTagInfos, scoutingPFJetReclusterParticleNetJetTags, # jet tagging
0046     scoutingPFJetReclusterTable
0047 )
0048 scoutingPFJetReclusterMatchGenExtensionTask = cms.Task(
0049     scoutingPFJetReclusterMatchGen, # gen jet matching
0050     scoutingPFJetReclusterMatchGenExtensionTable
0051 )
0052 
0053 scoutingFatPFJetReclusterTask = cms.Task(
0054     scoutingPFCandidate, # translate to reco::PFCandidate, used as input
0055     scoutingFatPFJetRecluster, # jet clustering
0056     scoutingFatPFJetReclusterParticleNetJetTagInfos, scoutingFatPFJetReclusterParticleNetJetTags, # jet tagging
0057     scoutingFatPFJetReclusterGlobalParticleTransformerJetTagInfos, scoutingFatPFJetReclusterGlobalParticleTransformerJetTags, # jet tagging with Global Particle Transformer
0058     scoutingFatPFJetReclusterSoftDrop, scoutingFatPFJetReclusterSoftDropMass, # softdrop mass
0059     scoutingFatPFJetReclusterParticleNetJetTagInfos, scoutingFatPFJetReclusterParticleNetMassRegressionJetTags, # regressed mass
0060     scoutingFatPFJetReclusterEcfNbeta1, scoutingFatPFJetReclusterNjettiness, # substructure variables
0061     scoutingFatPFJetReclusterTable
0062 )
0063 scoutingFatPFJetReclusterMatchGenExtensionTask = cms.Task(
0064     scoutingFatPFJetReclusterMatchGen, # gen jet matching
0065     scoutingFatPFJetReclusterMatchGenExtensionTable
0066 )
0067 
0068 ############################
0069 # Trigger Bits and Objects #
0070 ############################
0071 
0072 ## L1 decisions
0073 gtStage2DigisScouting = gtStage2Digis.clone(InputLabel="hltFEDSelectorL1")
0074 l1bitsScouting = l1bits.clone(src="gtStage2DigisScouting") 
0075 
0076 ## L1 objects
0077 from PhysicsTools.NanoAOD.l1trig_cff import *
0078 l1MuScoutingTable = l1MuTable.clone(src=cms.InputTag("gtStage2DigisScouting", "Muon"))
0079 l1EGScoutingTable = l1EGTable.clone(src=cms.InputTag("gtStage2DigisScouting", "EGamma"))
0080 l1TauScoutingTable = l1TauTable.clone(src=cms.InputTag("gtStage2DigisScouting", "Tau"))
0081 l1JetScoutingTable = l1JetTable.clone(src=cms.InputTag("gtStage2DigisScouting", "Jet"))
0082 l1EtSumScoutingTable = l1EtSumTable.clone(src=cms.InputTag("gtStage2DigisScouting", "EtSum"))
0083 
0084 # reduce the variables to the core variables as only these are available in gtStage2Digis
0085 l1MuScoutingTable.variables = cms.PSet(l1MuonReducedVars)
0086 l1EGScoutingTable.variables = cms.PSet(l1EGReducedVars)
0087 l1TauScoutingTable.variables = cms.PSet(l1TauReducedVars)
0088 l1JetScoutingTable.variables = cms.PSet(l1JetReducedVars)
0089 l1EtSumScoutingTable.variables = cms.PSet(l1EtSumReducedVars)
0090 
0091 ##############################
0092 ### Main Tasks Definitions ###
0093 ##############################
0094 
0095 # default configuration for ScoutingNano common for both data and MC
0096 def prepareScoutingNanoTaskCommon():
0097     # Scouting original objects
0098     # all scouting objects are saved except PF Candidate and Track
0099     scoutingNanoTaskCommon = cms.Task()
0100     scoutingNanoTaskCommon.add(scoutingMuonTableTask, scoutingMuonDisplacedVertexTableTask)
0101     scoutingNanoTaskCommon.add(scoutingElectronTableTask)
0102     scoutingNanoTaskCommon.add(scoutingPhotonTable)
0103     scoutingNanoTaskCommon.add(scoutingPrimaryVertexTable)
0104     scoutingNanoTaskCommon.add(scoutingPFJetTable)
0105     scoutingNanoTaskCommon.add(scoutingMETTable, scoutingRhoTable)
0106     
0107     # Scouting derived objects
0108     scoutingNanoTaskCommon.add(scoutingPFJetReclusterTask)
0109     scoutingNanoTaskCommon.add(scoutingFatPFJetReclusterTask)
0110 
0111     return scoutingNanoTaskCommon
0112 
0113 # tasks related to trigger bits and objects
0114 def prepareScoutingTriggerTask():
0115     scoutingTriggerTask = cms.Task(gtStage2DigisScouting, l1bitsScouting)
0116     scoutingTriggerTask.add(cms.Task(l1MuScoutingTable, l1EGScoutingTable, l1TauScoutingTable, l1JetScoutingTable, l1EtSumScoutingTable))
0117     return scoutingTriggerTask
0118 
0119 # additional tasks for running on MC
0120 def prepareScoutingNanoTaskMC():
0121     scoutingNanoTaskMC = cms.Task()
0122     scoutingNanoTaskMC.add(scoutingPFJetReclusterMatchGenExtensionTask)
0123     scoutingNanoTaskMC.add(scoutingFatPFJetReclusterMatchGenExtensionTask)
0124 
0125     scoutingNanoTaskMC.add(puTable)
0126     return scoutingNanoTaskMC
0127 
0128 # Common tasks added to main scoutingNanoSequence
0129 scoutingNanoTaskCommon = prepareScoutingNanoTaskCommon()
0130 scoutingNanoSequence = cms.Sequence(scoutingNanoTaskCommon)
0131 
0132 # Specific tasks which will be added to sequence during customization
0133 scoutingTriggerTask = prepareScoutingTriggerTask()
0134 scoutingTriggerSequence = cms.Sequence(scoutingTriggerTask)
0135 scoutingNanoTaskMC = prepareScoutingNanoTaskMC()
0136 
0137 def customiseScoutingNano(process):
0138     # if running with standard NanoAOD, triggerSequence is already added
0139     # if running standalone, triggerSequence need to be added
0140     if not ((hasattr(process, "nanoSequence") and process.schedule.contains(process.nanoSequence))
0141             or hasattr(process, "nanoSequenceMC") and process.schedule.contains(process.nanoSequenceMC)):
0142         process.trigger_step = cms.Path(process.scoutingTriggerSequence)
0143         process.schedule.extend([process.trigger_step])
0144 
0145     # specific tasks when running on MC
0146     runOnMC = hasattr(process,"NANOEDMAODSIMoutput") or hasattr(process,"NANOAODSIMoutput")
0147     if runOnMC:
0148         process.scoutingNanoSequence.associate(scoutingNanoTaskMC)
0149     
0150     return process
0151 
0152 #####################
0153 ### Customisation ###
0154 #####################
0155 # these function are designed to be used with --customise flag in cmsDriver.py
0156 # e.g. --customise PhysicsTools/NanoAOD/python/custom_run3scouting_cff.addScoutingPFCandidate
0157 
0158 # additional customisation for running with ScoutingPFMonitor/RAW inputs
0159 # should be used with default customiseScoutingNano
0160 # this is suitable when ScoutingPFMonitor/RAW is involved, e.g. RAW, RAW-MiniAOD two-file solution, full chain RAW-MiniAOD-NanoAOD
0161 # when running full chain RAW-MiniAOD-NanoAOD, this ensures that gtStage2Digis, gmtStage2Digis, and caloStage2Digis are run
0162 def customiseScoutingNanoForScoutingPFMonitor(process):
0163     process = skipEventsWithoutScouting(process)
0164 
0165     # replace gtStage2DigisScouting with standard gtStage2Digis
0166     process.scoutingTriggerTask.remove(process.gtStage2DigisScouting)
0167     process.scoutingTriggerTask.add(process.gtStage2Digis)
0168 
0169     # add gmtStage2Digis
0170     process.load("EventFilter.L1TRawToDigi.gmtStage2Digis_cfi")
0171     process.scoutingTriggerTask.add(process.gmtStage2Digis)
0172 
0173     # add caloStage2Digis
0174     process.load("EventFilter.L1TRawToDigi.caloStage2Digis_cfi")
0175     process.scoutingTriggerTask.add(process.caloStage2Digis)
0176 
0177     # replace l1bitsScouting with standard l1bits
0178     process.scoutingTriggerTask.remove(process.l1bitsScouting)
0179     process.scoutingTriggerTask.add(process.l1bits)
0180 
0181     # change src for l1 objects
0182     process.l1MuScoutingTable.src = cms.InputTag("gmtStage2Digis", "Muon")
0183     process.l1EGScoutingTable.src = cms.InputTag("caloStage2Digis", "EGamma")
0184     process.l1TauScoutingTable.src = cms.InputTag("caloStage2Digis", "Tau")
0185     process.l1JetScoutingTable.src = cms.InputTag("caloStage2Digis", "Jet")
0186     process.l1EtSumScoutingTable.src = cms.InputTag("caloStage2Digis", "EtSum")
0187 
0188     return process
0189 
0190 # additional customisation for running with ScoutingPFMonitor/MiniAOD inputs alone
0191 # can also be used on MC input
0192 # should be used with default customiseScoutingNano and NOT with customiseScoutingNanoForScoutingPFMonitor
0193 def customiseScoutingNanoFromMini(process):
0194     # when running on data, assume ScoutingPFMonitor/MiniAOD dataset as inputs
0195     runOnData = hasattr(process,"NANOAODSIMoutput") or hasattr(process,"NANOAODoutput")
0196     if runOnData:
0197         process = skipEventsWithoutScouting(process)
0198 
0199     # remove gtStage2Digis since they are already run for Mini
0200     process.scoutingTriggerTask.remove(process.gtStage2DigisScouting)
0201 
0202     # replace l1bitsScouting with standard l1bits
0203     process.scoutingTriggerTask.remove(process.l1bitsScouting)
0204     process.scoutingTriggerTask.add(process.l1bits)
0205 
0206     # change src for l1 objects
0207     process.l1MuScoutingTable.src = cms.InputTag("gmtStage2Digis", "Muon")
0208     process.l1EGScoutingTable.src = cms.InputTag("caloStage2Digis", "EGamma")
0209     process.l1TauScoutingTable.src = cms.InputTag("caloStage2Digis", "Tau")
0210     process.l1JetScoutingTable.src = cms.InputTag("caloStage2Digis", "Jet")
0211     process.l1EtSumScoutingTable.src = cms.InputTag("caloStage2Digis", "EtSum")
0212 
0213     return process
0214 
0215 # skip events without scouting object products
0216 # this may be needed since for there are some events which do not contain scouting object products in 2022-24
0217 # this is fixed for 2025: https://its.cern.ch/jira/browse/CMSHLT-3331
0218 def skipEventsWithoutScouting(process):
0219     # if scouting paths are triggered, scouting objects will be reconstructed
0220     # so we select events passing scouting paths
0221     import HLTrigger.HLTfilters.hltHighLevel_cfi
0222 
0223     process.scoutingTriggerPathFilter = HLTrigger.HLTfilters.hltHighLevel_cfi.hltHighLevel.clone(
0224             HLTPaths = cms.vstring("Dataset_ScoutingPFRun3")
0225             )
0226 
0227     process.nanoSkim_step = cms.Path(process.scoutingTriggerPathFilter)
0228     process.schedule.extend([process.nanoSkim_step])
0229 
0230     if hasattr(process, "NANOAODoutput"):
0231         process.NANOAODoutput.SelectEvents = cms.untracked.PSet(SelectEvents = cms.vstring("nanoSkim_step"))
0232 
0233     if hasattr(process, "NANOAODEDMoutput"):
0234         process.NANOEDMAODoutput.SelectEvents = cms.untracked.PSet(SelectEvents = cms.vstring("nanoSkim_step"))
0235 
0236     if hasattr(process, "write_NANOAOD"): # PromptReco
0237         process.write_NANOAOD.SelectEvents = cms.untracked.PSet(SelectEvents = cms.vstring("nanoSkim_step")) 
0238 
0239     return process
0240 
0241 def addScoutingTrack(process):
0242     process.scoutingNanoSequence.associate(cms.Task(scoutingTrackTable))
0243     return process
0244 
0245 def addScoutingParticle(process):
0246     # original PF candidate without post-processing
0247     process.scoutingNanoSequence.associate(cms.Task(scoutingParticleTable))
0248     return process
0249 
0250 def addScoutingPFCandidate(process):
0251     # PF candidate after translation to reco::PFCandidate
0252     process.scoutingNanoSequence.associate(scoutingPFCandidateTask)
0253     return process
0254 
0255 # this adds all electron tracks in addition to best track selected
0256 # this should be only used with ScoutingElectron format from 2023
0257 def addScoutingElectronTrack(process):
0258     process.scoutingElectronTable.externalVariables.bestTrack_index\
0259             = ExtVar(cms.InputTag("scoutingElectronBestTrack", "Run3ScoutingElectronBestTrackIndex"), int, doc="best track index")
0260 
0261     process.scoutingElectronTable.collectionVariables = cms.PSet(
0262         ScoutingElectronTrack = cms.PSet(
0263             name = cms.string("ScoutingElectronTrack"),
0264             doc = cms.string("Scouting Electron Track"),
0265             useCount = cms.bool(True),
0266             useOffset = cms.bool(True),
0267             variables = cms.PSet(
0268                 d0 = Var("trkd0", "float", doc="track d0"),
0269                 dz = Var("trkdz", "float", doc="track dz"),
0270                 pt = Var("trkpt", "float", doc="track pt"),
0271                 eta = Var("trketa", "float", doc="track eta"),
0272                 phi = Var("trkphi", "float", doc="track phi"),
0273                 chi2overndf = Var("trkchi2overndf", "float", doc="track normalized chi squared"),
0274                 charge = Var("trkcharge", "int", doc="track charge"),
0275             ),
0276         ),
0277     )
0278     
0279     # additional electron track variables added in 2024 in https://github.com/cms-sw/cmssw/pull/43744
0280     run3_scouting_nanoAOD_2024.toModify(
0281         process.scoutingElectronTable.collectionVariables.variables,
0282         pMode = Var("trkpMode", "float", doc="track pMode"),
0283         etaMode = Var("trketaMode", "float", doc="track etaMode"),
0284         phiMode = Var("trkphiMode", "float", doc="track phiMode"),
0285         qoverpModeError = Var("trkqoverpModeError", "float", doc="track qoverpModeError"),
0286     )
0287     return process