diff --git a/PhysicsTools/NanoAOD/python/met_cff.py b/PhysicsTools/NanoAOD/python/met_cff.py index f33dda5879cba..9ac9f4f3e8ce3 100644 --- a/PhysicsTools/NanoAOD/python/met_cff.py +++ b/PhysicsTools/NanoAOD/python/met_cff.py @@ -106,6 +106,32 @@ ), ) +deepMetResolutionTuneTable = cms.EDProducer("SimpleCandidateFlatTableProducer", + # current deepMets are saved in slimmedMETs in MiniAOD, + # in the same way as chsMet/TkMET + src = metTable.src, + name = cms.string("DeepMETResolutionTune"), + doc = cms.string("Deep MET trained with resolution tune"), + singleton = cms.bool(True), # there's always exactly one MET per event + extension = cms.bool(False), # this is the main table for the MET + variables = cms.PSet(#NOTA BENE: we don't copy PTVars here! + pt = Var("corPt('RawDeepResolutionTune')", float, doc="DeepMET ResolutionTune pt",precision=-1), + phi = Var("corPhi('RawDeepResolutionTune')", float, doc="DeepmET ResolutionTune phi",precision=12), + ), +) + +deepMetResponseTuneTable = cms.EDProducer("SimpleCandidateFlatTableProducer", + src = metTable.src, + name = cms.string("DeepMETResponseTune"), + doc = cms.string("Deep MET trained with extra response tune"), + singleton = cms.bool(True), # there's always exactly one MET per event + extension = cms.bool(False), # this is the main table for the MET + variables = cms.PSet(#NOTA BENE: we don't copy PTVars here! + pt = Var("corPt('RawDeepResponseTune')", float, doc="DeepMET ResponseTune pt",precision=-1), + phi = Var("corPhi('RawDeepResponseTune')", float, doc="DeepMET ResponseTune phi",precision=12), + ), +) + metFixEE2017Table = metTable.clone() metFixEE2017Table.src = cms.InputTag("slimmedMETsFixEE2017") metFixEE2017Table.name = cms.string("METFixEE2017") @@ -127,6 +153,7 @@ metTables = cms.Sequence( metTable + rawMetTable + caloMetTable + puppiMetTable + rawPuppiMetTable+ tkMetTable + chsMetTable) +deepMetTables = cms.Sequence( deepMetResolutionTuneTable + deepMetResponseTuneTable ) _withFixEE2017_sequence = cms.Sequence(metTables.copy() + metFixEE2017Table) for modifier in run2_nanoAOD_94XMiniAODv1, run2_nanoAOD_94XMiniAODv2: modifier.toReplaceWith(metTables,_withFixEE2017_sequence) # only in old miniAOD, the new ones will come from the UL rereco diff --git a/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py b/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py index 33a6b8ea6633c..16d0aaac43220 100644 --- a/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py +++ b/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py @@ -32,6 +32,20 @@ Plot1D('rawPt', 'rawPt', 20, 5, 25, "pt()*jecFactor('Uncorrected')"), ) ), + DeepMETResolutionTune = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'Deep MET Resolution Tune phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'Deep MET Response Tune pt'), + ) + ), + DeepMETResponseTune = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'Deep MET Response Tune phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'Deep MET Response Tune pt'), + ) + ), Electron = cms.PSet( sels = cms.PSet( Good = cms.string('pt > 15 && abs(dxy) < 0.2 && abs(dz) < 0.5 && cutBased >= 3 && miniPFRelIso_all < 0.4') diff --git a/PhysicsTools/NanoAOD/python/nano_cff.py b/PhysicsTools/NanoAOD/python/nano_cff.py index dcfb273492b98..1df591d5759d6 100644 --- a/PhysicsTools/NanoAOD/python/nano_cff.py +++ b/PhysicsTools/NanoAOD/python/nano_cff.py @@ -176,10 +176,41 @@ def nanoAOD_addDeepInfo(process,addDeepBTag,addDeepFlavour): process.updatedJets.jetSource="selectedUpdatedPatJetsWithDeepInfo" return process +def nanoAOD_addDeepMET(process, addDeepMETProducer, ResponseTune_Graph): + if addDeepMETProducer: + # produce DeepMET on the fly if it is not in MiniAOD + print("add DeepMET Producers") + process.load('RecoMET.METPUSubtraction.deepMETProducer_cfi') + process.deepMETsResolutionTune = process.deepMETProducer.clone() + process.deepMETsResponseTune = process.deepMETProducer.clone() + #process.deepMETsResponseTune.graph_path = 'RecoMET/METPUSubtraction/data/deepmet/deepmet_resp_v1_2018.pb' + process.deepMETsResponseTune.graph_path = ResponseTune_Graph.value() + process.metTables += process.deepMetTables + return process + from PhysicsTools.PatUtils.tools.runMETCorrectionsAndUncertainties import runMetCorAndUncFromMiniAOD #from PhysicsTools.PatAlgos.slimming.puppiForMET_cff import makePuppiesFromMiniAOD def nanoAOD_recalibrateMETs(process,isData): - runMetCorAndUncFromMiniAOD(process,isData=isData) + # add DeepMETs + nanoAOD_DeepMET_switch = cms.PSet( + nanoAOD_addDeepMET_switch = cms.untracked.bool(True), # decide if DeeMET should be included in Nano + nanoAOD_produceDeepMET_switch = cms.untracked.bool(False), # decide if DeepMET should be computed on the fly + ResponseTune_Graph = cms.untracked.string('RecoMET/METPUSubtraction/data/deepmet/deepmet_resp_v1_2018.pb') + ) + for modifier in run2_miniAOD_80XLegacy, run2_nanoAOD_94X2016, run2_nanoAOD_94XMiniAODv1, run2_nanoAOD_94XMiniAODv2, run2_nanoAOD_102Xv1, run2_nanoAOD_106Xv1: + # compute DeepMETs in these eras (before 111X) + modifier.toModify(nanoAOD_DeepMET_switch, nanoAOD_produceDeepMET_switch = cms.untracked.bool(True)) + for modifier in run2_miniAOD_80XLegacy, run2_nanoAOD_94X2016: + modifier.toModify(nanoAOD_DeepMET_switch, ResponseTune_Graph=cms.untracked.string("RecoMET/METPUSubtraction/data/deepmet/deepmet_resp_v1_2016.pb")) + if nanoAOD_DeepMET_switch.nanoAOD_addDeepMET_switch: + process = nanoAOD_addDeepMET(process, + addDeepMETProducer=nanoAOD_DeepMET_switch.nanoAOD_produceDeepMET_switch, + ResponseTune_Graph=nanoAOD_DeepMET_switch.ResponseTune_Graph) + + # if included in Nano, and not computed in the fly, then it should be extracted from minAOD + extractDeepMETs = nanoAOD_DeepMET_switch.nanoAOD_addDeepMET_switch and not nanoAOD_DeepMET_switch.nanoAOD_produceDeepMET_switch + + runMetCorAndUncFromMiniAOD(process,isData=isData, extractDeepMETs=extractDeepMETs) process.nanoSequenceCommon.insert(process.nanoSequenceCommon.index(process.jetSequence),cms.Sequence(process.fullPatMetSequence)) process.basicJetsForMetForT1METNano = process.basicJetsForMet.clone( src = process.updatedJetsWithUserData.src, diff --git a/PhysicsTools/PatAlgos/plugins/RecoMETExtractor.cc b/PhysicsTools/PatAlgos/plugins/RecoMETExtractor.cc index 1ea7504ba7a26..0b91fd3bd1bf4 100644 --- a/PhysicsTools/PatAlgos/plugins/RecoMETExtractor.cc +++ b/PhysicsTools/PatAlgos/plugins/RecoMETExtractor.cc @@ -36,6 +36,10 @@ RecoMETExtractor::RecoMETExtractor(const edm::ParameterSet& iConfig) { corLevel_ = pat::MET::Type01SmearXY; } else if (corLevel == "rawCalo") { corLevel_ = pat::MET::RawCalo; + } else if (corLevel == "rawDeepResponseTune") { + corLevel_ = pat::MET::RawDeepResponseTune; + } else if (corLevel == "rawDeepResolutionTune") { + corLevel_ = pat::MET::RawDeepResolutionTune; } else { //throw exception } diff --git a/PhysicsTools/PatUtils/python/tools/runMETCorrectionsAndUncertainties.py b/PhysicsTools/PatUtils/python/tools/runMETCorrectionsAndUncertainties.py index f5b79eb9374ed..e1775e4910664 100644 --- a/PhysicsTools/PatUtils/python/tools/runMETCorrectionsAndUncertainties.py +++ b/PhysicsTools/PatUtils/python/tools/runMETCorrectionsAndUncertainties.py @@ -91,6 +91,8 @@ def __init__(self): "Exclude jets and PF candidates with EE noise characteristics (fix for 2017 run)", Type=bool) self.addParameter(self._defaultParameters,'fixEE2017Params', {'userawPt': True, 'ptThreshold': 50.0, 'minEtaThreshold': 2.65, 'maxEtaThreshold': 3.139}, "Parameters dict for fixEE2017: userawPt, ptThreshold, minEtaThreshold, maxEtaThreshold", Type=dict) + self.addParameter(self._defaultParameters, 'extractDeepMETs', False, + "Extract DeepMETs from miniAOD, instead of recomputing them.", Type=bool) #private parameters self.addParameter(self._defaultParameters, 'Puppi', False, @@ -136,6 +138,7 @@ def __call__(self, process, onMiniAOD =None, fixEE2017 =None, fixEE2017Params =None, + extractDeepMETs =None, postfix =None): electronCollection = self.initializeInputTag(electronCollection, 'electronCollection') photonCollection = self.initializeInputTag(photonCollection, 'photonCollection') @@ -209,6 +212,8 @@ def __call__(self, process, fixEE2017 = self._defaultParameters['fixEE2017'].value if fixEE2017Params is None : fixEE2017Params = self._defaultParameters['fixEE2017Params'].value + if extractDeepMETs is None : + extractDeepMETs = self._defaultParameters['extractDeepMETs'].value self.setParameter('metType',metType), self.setParameter('correctionLevel',correctionLevel), @@ -242,6 +247,7 @@ def __call__(self, process, self.setParameter('postfix',postfix), self.setParameter('fixEE2017',fixEE2017), self.setParameter('fixEE2017Params',fixEE2017Params), + self.setParameter('extractDeepMETs',extractDeepMETs), #if mva/puppi MET, autoswitch to std jets if metType == "MVA" or metType == "Puppi": @@ -305,6 +311,7 @@ def toolCode(self, process): postfix = self._parameters['postfix'].value fixEE2017 = self._parameters['fixEE2017'].value fixEE2017Params = self._parameters['fixEE2017Params'].value + extractDeepMETs = self._parameters['extractDeepMETs'].value #prepare jet configuration jetUncInfos = { "jCorrPayload":jetFlavor, "jCorLabelUpToL3":jetCorLabelUpToL3, @@ -464,6 +471,11 @@ def toolCode(self, process): #adding the slimmed MET if hasattr(process, "patCaloMet"): fullPatMetSequence +=getattr(process, "patCaloMet") + # include deepMETsResolutionTune and deepMETsResponseTune into fullPatMetSequence + if hasattr(process, "deepMETsResolutionTune"): + fullPatMetSequence +=getattr(process, "deepMETsResolutionTune") + if hasattr(process, "deepMETsResponseTune"): + fullPatMetSequence += getattr(process, "deepMETsResponseTune") if hasattr(process, "slimmedMETs"+postfix): fullPatMetSequence +=getattr(process, "slimmedMETs"+postfix) @@ -1677,6 +1689,26 @@ def miniAODConfigurationPre(self, process, patMetModuleSequence, pfCandCollectio ) getattr(process,"patCaloMet").addGenMET = False + # extract DeepMETs (ResponseTune and ResolutionTune) from miniAOD + if self._parameters["extractDeepMETs"].value: + self.extractMET(process, "rawDeepResponseTune", patMetModuleSequence, postfix) + deepMetResponseTuneName = "metrawDeepResponseTune" if hasattr(process, "metrawDeepResponseTune") else "metrawDeepResponseTune"+postfix + addMETCollection(process, + labelName = "deepMETsResponseTune", + metSource = deepMetResponseTuneName + ) + getattr(process, "deepMETsResponseTune").addGenMET = False + getattr(process, "deepMETsResponseTune").computeMETSignificance = cms.bool(False) + + self.extractMET(process, "rawDeepResolutionTune", patMetModuleSequence, postfix) + deepMetResolutionTuneName = "metrawDeepResolutionTune" if hasattr(process, "metrawDeepResolutionTune") else "metrawDeepResolutionTune"+postfix + addMETCollection(process, + labelName = "deepMETsResolutionTune", + metSource = deepMetResolutionTuneName + ) + getattr(process, "deepMETsResolutionTune").addGenMET = False + getattr(process, "deepMETsResolutionTune").computeMETSignificance = cms.bool(False) + ##adding the necessary chs and track met configuration task = getPatAlgosToolsTask(process) @@ -1762,6 +1794,10 @@ def miniAODConfiguration(self, process, pfCandCollection, jetCollection, getattr(process,"slimmedMETs"+postfix).runningOnMiniAOD = True getattr(process,"slimmedMETs"+postfix).t01Variation = cms.InputTag("slimmedMETs" if not self._parameters["Puppi"].value else "slimmedMETsPuppi",processName=cms.InputTag.skipCurrentProcess()) + if hasattr(process, "deepMETsResolutionTune") and hasattr(process, "deepMETsResponseTune"): + # process includes producing/extracting deepMETsResolutionTune and deepMETsResponseTune + # add them to the slimmedMETs + getattr(process,"slimmedMETs"+postfix).addDeepMETs = True #smearing and type0 variations not yet supported in reprocessing #del getattr(process,"slimmedMETs"+postfix).t1SmearedVarsAndUncs @@ -2033,6 +2069,7 @@ def runMetCorAndUncFromMiniAOD(process, metType="PF", computeMETSignificance=True, fixEE2017=False, fixEE2017Params=None, + extractDeepMETs=False, postfix=""): runMETCorrectionsAndUncertainties = RunMETCorrectionsAndUncertainties() @@ -2066,6 +2103,7 @@ def runMetCorAndUncFromMiniAOD(process, metType="PF", postfix=postfix, fixEE2017=fixEE2017, fixEE2017Params=fixEE2017Params, + extractDeepMETs=extractDeepMETs, ) #MET T1+Txy / Smear @@ -2097,6 +2135,7 @@ def runMetCorAndUncFromMiniAOD(process, metType="PF", postfix=postfix, fixEE2017=fixEE2017, fixEE2017Params=fixEE2017Params, + extractDeepMETs=extractDeepMETs, ) #MET T1+Smear + uncertainties runMETCorrectionsAndUncertainties(process, metType=metType, @@ -2127,4 +2166,5 @@ def runMetCorAndUncFromMiniAOD(process, metType="PF", postfix=postfix, fixEE2017=fixEE2017, fixEE2017Params=fixEE2017Params, + extractDeepMETs=extractDeepMETs, )