Skip to content

Commit

Permalink
Merge pull request #33992 from bainbrid/LowPtElectrons_nanoAOD_integr…
Browse files Browse the repository at this point in the history
…ation_106X

LowPtElectrons: NanoAOD integration (back port of #33817)
  • Loading branch information
cmsbuild committed Jun 8, 2021
2 parents 7087444 + ce41e4b commit d81c275
Show file tree
Hide file tree
Showing 18 changed files with 747 additions and 81 deletions.
5 changes: 3 additions & 2 deletions DataFormats/EgammaCandidates/interface/GsfElectron.h
Expand Up @@ -836,6 +836,7 @@ class GsfElectron : public RecoCandidate
// setters
void setCorrectedEcalEnergyError( float newEnergyError ) ;
void setCorrectedEcalEnergy( float newEnergy ) ;
void setCorrectedEcalEnergy(float newEnergy, bool rescaleDependentValues);
void setTrackMomentumError( float trackMomentumError ) ;
void setP4( P4Kind kind, const LorentzVector & p4, float p4Error, bool setCandidate ) ;
using RecoCandidate::setP4 ;
Expand All @@ -861,9 +862,9 @@ class GsfElectron : public RecoCandidate
//bool isMomentumCorrected() const { return corrections_.isMomentumCorrected ; }
float caloEnergy() const { return correctedEcalEnergy() ; }
bool isEnergyScaleCorrected() const { return isEcalEnergyCorrected() ; }
void correctEcalEnergy( float newEnergy, float newEnergyError )
void correctEcalEnergy(float newEnergy, float newEnergyError, bool corrEovP = true)
{
setCorrectedEcalEnergy(newEnergy) ;
setCorrectedEcalEnergy(newEnergy, corrEovP) ;
setEcalEnergyError(newEnergyError) ;
}
void correctMomentum( const LorentzVector & p4, float trackMomentumError, float p4Error )
Expand Down
27 changes: 15 additions & 12 deletions DataFormats/EgammaCandidates/src/GsfElectron.cc
Expand Up @@ -179,18 +179,21 @@ bool GsfElectron::ecalDriven() const
void GsfElectron::setCorrectedEcalEnergyError( float energyError )
{ corrections_.correctedEcalEnergyError = energyError ; }

void GsfElectron::setCorrectedEcalEnergy( float newEnergy )
{
math::XYZTLorentzVectorD momentum = p4() ;
momentum *= newEnergy/momentum.e() ;
setP4(momentum) ;
showerShape_.hcalDepth1OverEcal *= corrections_.correctedEcalEnergy/newEnergy ;
showerShape_.hcalDepth2OverEcal *= corrections_.correctedEcalEnergy/newEnergy ;
trackClusterMatching_.eSuperClusterOverP *= newEnergy/corrections_.correctedEcalEnergy ;
corrections_.correctedEcalEnergyError *= newEnergy/corrections_.correctedEcalEnergy ;
corrections_.correctedEcalEnergy = newEnergy ;
corrections_.isEcalEnergyCorrected = true ;
}
void GsfElectron::setCorrectedEcalEnergy(float newEnergy) { setCorrectedEcalEnergy(newEnergy, true); }

void GsfElectron::setCorrectedEcalEnergy(float newEnergy, bool rescaleDependentValues) {
math::XYZTLorentzVectorD momentum = p4();
momentum *= newEnergy / momentum.e();
setP4(momentum);
if (corrections_.correctedEcalEnergy > 0. && rescaleDependentValues) {
showerShape_.hcalDepth1OverEcal *= corrections_.correctedEcalEnergy / newEnergy;
showerShape_.hcalDepth2OverEcal *= corrections_.correctedEcalEnergy / newEnergy;
trackClusterMatching_.eSuperClusterOverP *= newEnergy / corrections_.correctedEcalEnergy;
corrections_.correctedEcalEnergyError *= newEnergy / corrections_.correctedEcalEnergy;
}
corrections_.correctedEcalEnergy = newEnergy;
corrections_.isEcalEnergyCorrected = true;
}

void GsfElectron::setTrackMomentumError( float trackErr )
{ corrections_.trackMomentumError = trackErr ; }
Expand Down
211 changes: 211 additions & 0 deletions PhysicsTools/NanoAOD/python/lowPtElectrons_cff.py
@@ -0,0 +1,211 @@
import FWCore.ParameterSet.Config as cms
from PhysicsTools.NanoAOD.nano_eras_cff import *
from PhysicsTools.NanoAOD.common_cff import *

################################################################################
# Modules
################################################################################

from RecoEgamma.EgammaTools.lowPtElectronModifier_cfi import lowPtElectronModifier
from RecoEgamma.EgammaElectronProducers.lowPtGsfElectrons_cff import lowPtRegressionModifier
modifiedLowPtElectrons = cms.EDProducer(
"ModifiedElectronProducer",
src = cms.InputTag("slimmedLowPtElectrons"),
modifierConfig = cms.PSet(
modifications = cms.VPSet(lowPtElectronModifier,lowPtRegressionModifier)
)
)

import PhysicsTools.PatAlgos.producersLayer1.electronProducer_cfi
updatedLowPtElectrons = cms.EDProducer(
"PATElectronUpdater",
src = cms.InputTag("modifiedLowPtElectrons"),
vertices = cms.InputTag("offlineSlimmedPrimaryVertices"),
computeMiniIso = cms.bool(True),
fixDxySign = cms.bool(False),
pfCandsForMiniIso = cms.InputTag("packedPFCandidates"),
miniIsoParamsB = PhysicsTools.PatAlgos.producersLayer1.electronProducer_cfi.patElectrons.miniIsoParamsB,
miniIsoParamsE = PhysicsTools.PatAlgos.producersLayer1.electronProducer_cfi.patElectrons.miniIsoParamsE,
)

from RecoEgamma.EgammaElectronProducers.lowPtGsfElectronID_cff import lowPtGsfElectronID
lowPtPATElectronID = lowPtGsfElectronID.clone(
usePAT = True,
electrons = "updatedLowPtElectrons",
unbiased = "",
ModelWeights = [
'RecoEgamma/ElectronIdentification/data/LowPtElectrons/LowPtElectrons_ID_2020Nov28.root',
],
Version = cms.string('V1'),
rho = "fixedGridRhoFastjetAll",
)

isoForLowPtEle = cms.EDProducer(
"EleIsoValueMapProducer",
src = cms.InputTag("updatedLowPtElectrons"),
relative = cms.bool(True),
rho_MiniIso = cms.InputTag("fixedGridRhoFastjetAll"),
rho_PFIso = cms.InputTag("fixedGridRhoFastjetAll"),
EAFile_MiniIso = cms.FileInPath("RecoEgamma/ElectronIdentification/data/Fall17/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_94X.txt"),
EAFile_PFIso = cms.FileInPath("RecoEgamma/ElectronIdentification/data/Fall17/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_94X.txt"),
)

updatedLowPtElectronsWithUserData = cms.EDProducer(
"PATElectronUserDataEmbedder",
src = cms.InputTag("updatedLowPtElectrons"),
userFloats = cms.PSet(
ID = cms.InputTag("lowPtPATElectronID"),
miniIsoChg = cms.InputTag("isoForLowPtEle:miniIsoChg"),
miniIsoAll = cms.InputTag("isoForLowPtEle:miniIsoAll"),
),
userIntFromBools = cms.PSet(),
userInts = cms.PSet(),
userCands = cms.PSet(),
)

finalLowPtElectrons = cms.EDFilter(
"PATElectronRefSelector",
src = cms.InputTag("updatedLowPtElectronsWithUserData"),
cut = cms.string("pt > 1. && userFloat('ID') > -0.25"),
)

################################################################################
# electronTable
################################################################################

lowPtElectronTable = cms.EDProducer(
"SimpleCandidateFlatTableProducer",
src = cms.InputTag("finalLowPtElectrons"),
cut = cms.string(""),
name= cms.string("LowPtElectron"),
doc = cms.string("slimmedLowPtElectrons after basic selection (" + finalLowPtElectrons.cut.value()+")"),
singleton = cms.bool(False), # the number of entries is variable
extension = cms.bool(False), # this is the main table for the electrons
variables = cms.PSet(
# Basic variables
CandVars,
# BDT scores and WPs
embeddedID = Var("electronID('ID')",float,doc="ID, BDT (raw) score"),
ID = Var("userFloat('ID')",float,doc="New ID, BDT (raw) score"),
unbiased = Var("electronID('unbiased')",float,doc="ElectronSeed, pT- and dxy- agnostic BDT (raw) score"),
ptbiased = Var("electronID('ptbiased')",float,doc="ElectronSeed, pT- and dxy- dependent BDT (raw) score"),
# Isolation
miniPFRelIso_chg = Var("userFloat('miniIsoChg')",float,
doc="mini PF relative isolation, charged component"),
miniPFRelIso_all = Var("userFloat('miniIsoAll')",float,
doc="mini PF relative isolation, total (with scaled rho*EA PU corrections)"),
# Conversions
convVeto = Var("passConversionVeto()",bool,doc="pass conversion veto"),
convWP = Var("userInt('convOpen')*1 + userInt('convLoose')*2 + userInt('convTight')*4",
int,doc="conversion flag bit map: 1=Veto, 2=Loose, 3=Tight"),
convVtxRadius = Var("userFloat('convVtxRadius')",float,doc="conversion vertex radius (cm)",precision=7),
# Tracking
lostHits = Var("gsfTrack.hitPattern.numberOfLostHits('MISSING_INNER_HITS')","uint8",doc="number of missing inner hits"),
# Cluster-related
energyErr = Var("p4Error('P4_COMBINATION')",float,doc="energy error of the cluster-track combination",precision=6),
deltaEtaSC = Var("superCluster().eta()-eta()",float,doc="delta eta (SC,ele) with sign",precision=10),
r9 = Var("full5x5_r9()",float,doc="R9 of the SC, calculated with full 5x5 region",precision=10),
sieie = Var("full5x5_sigmaIetaIeta()",float,doc="sigma_IetaIeta of the SC, calculated with full 5x5 region",precision=10),
eInvMinusPInv = Var("(1-eSuperClusterOverP())/ecalEnergy()",float,doc="1/E_SC - 1/p_trk",precision=10),
scEtOverPt = Var("(superCluster().energy()/(pt*cosh(superCluster().eta())))-1",float,doc="(SC energy)/pt-1",precision=8),
hoe = Var("hadronicOverEm()",float,doc="H over E",precision=8),
# Displacement
dxy = Var("dB('PV2D')",float,doc="dxy (with sign) wrt first PV, in cm",precision=10),
dxyErr = Var("edB('PV2D')",float,doc="dxy uncertainty, in cm",precision=6),
dz = Var("dB('PVDZ')",float,doc="dz (with sign) wrt first PV, in cm",precision=10),
dzErr = Var("abs(edB('PVDZ'))",float,doc="dz uncertainty, in cm",precision=6),
# Cross-referencing
#jetIdx
#photonIdx
),
)

################################################################################
# electronTable (MC)
################################################################################

from PhysicsTools.NanoAOD.particlelevel_cff import particleLevel
particleLevelForMatchingLowPt = particleLevel.clone(
lepMinPt = cms.double(1.),
phoMinPt = cms.double(1),
)

tautaggerForMatchingLowPt = cms.EDProducer(
"GenJetTauTaggerProducer",
src = cms.InputTag('particleLevelForMatchingLowPt:leptons')
)

matchingLowPtElecPhoton = cms.EDProducer(
"GenJetGenPartMerger",
srcJet =cms.InputTag("particleLevelForMatchingLowPt:leptons"),
srcPart=cms.InputTag("particleLevelForMatchingLowPt:photons"),
hasTauAnc=cms.InputTag("tautaggerForMatchingLowPt"),
)

lowPtElectronsMCMatchForTableAlt = cms.EDProducer(
"GenJetMatcherDRPtByDR", # cut on deltaR, deltaPt/Pt; pick best by deltaR
src = lowPtElectronTable.src, # final reco collection
matched = cms.InputTag("matchingLowPtElecPhoton:merged"), # final mc-truth particle collection
mcPdgId = cms.vint32(11,22), # one or more PDG ID (11 = el, 22 = pho); absolute values (see below)
checkCharge = cms.bool(False), # True = require RECO and MC objects to have the same charge
mcStatus = cms.vint32(),
maxDeltaR = cms.double(0.3), # Minimum deltaR for the match
maxDPtRel = cms.double(0.5), # Minimum deltaPt/Pt for the match
resolveAmbiguities = cms.bool(True), # Forbid two RECO objects to match to the same GEN object
resolveByMatchQuality = cms.bool(True), # False = just match input in order; True = pick lowest deltaR pair first
)

lowPtElectronsMCMatchForTable = cms.EDProducer(
"MCMatcher", # cut on deltaR, deltaPt/Pt; pick best by deltaR
src = lowPtElectronTable.src, # final reco collection
matched = cms.InputTag("finalGenParticles"), # final mc-truth particle collection
mcPdgId = cms.vint32(11), # one or more PDG ID (11 = ele); absolute values (see below)
checkCharge = cms.bool(False), # True = require RECO and MC objects to have the same charge
mcStatus = cms.vint32(1), # PYTHIA status code (1 = stable, 2 = shower, 3 = hard scattering)
maxDeltaR = cms.double(0.3), # Minimum deltaR for the match
maxDPtRel = cms.double(0.5), # Minimum deltaPt/Pt for the match
resolveAmbiguities = cms.bool(True), # Forbid two RECO objects to match to the same GEN object
resolveByMatchQuality = cms.bool(True), # False = just match input in order; True = pick lowest deltaR pair first
)

from PhysicsTools.NanoAOD.electrons_cff import electronMCTable
lowPtElectronMCTable = cms.EDProducer(
"CandMCMatchTableProducer",
src = lowPtElectronTable.src,
mcMapDressedLep = cms.InputTag("lowPtElectronsMCMatchForTableAlt"),
mcMap = cms.InputTag("lowPtElectronsMCMatchForTable"),
mapTauAnc = cms.InputTag("matchingLowPtElecPhoton:hasTauAnc"),
objName = lowPtElectronTable.name,
objType = electronMCTable.objType,
branchName = cms.string("genPart"),
docString = cms.string("MC matching to status==1 electrons or photons"),
genparticles = cms.InputTag("finalGenParticles"),
)

################################################################################
# Sequences
################################################################################

lowPtElectronSequence = cms.Sequence(modifiedLowPtElectrons
+updatedLowPtElectrons
+lowPtPATElectronID
+isoForLowPtEle
+updatedLowPtElectronsWithUserData
+finalLowPtElectrons)
lowPtElectronTables = cms.Sequence(lowPtElectronTable)
lowPtElectronMC = cms.Sequence(
particleLevelForMatchingLowPt
+tautaggerForMatchingLowPt
+matchingLowPtElecPhoton
+lowPtElectronsMCMatchForTable
+lowPtElectronsMCMatchForTableAlt
+lowPtElectronMCTable)

################################################################################
# Modifiers
################################################################################

_modifiers = ~(run2_nanoAOD_106Xv2 | run2_nanoAOD_devel)
_modifiers.toReplaceWith(lowPtElectronSequence,cms.Sequence())
_modifiers.toReplaceWith(lowPtElectronTables,cms.Sequence())
_modifiers.toReplaceWith(lowPtElectronMC,cms.Sequence())
1 change: 1 addition & 0 deletions PhysicsTools/NanoAOD/python/nanoDQM_cff.py
Expand Up @@ -146,6 +146,7 @@
## MC
nanoDQMMC = nanoDQM.clone()
nanoDQMMC.vplots.Electron.sels.Prompt = cms.string("genPartFlav == 1")
nanoDQMMC.vplots.LowPtElectron.sels.Prompt = cms.string("genPartFlav == 1")
nanoDQMMC.vplots.Muon.sels.Prompt = cms.string("genPartFlav == 1")
nanoDQMMC.vplots.Photon.sels.Prompt = cms.string("genPartFlav == 1")
nanoDQMMC.vplots.Tau.sels.Prompt = cms.string("genPartFlav == 5")
Expand Down
45 changes: 45 additions & 0 deletions PhysicsTools/NanoAOD/python/nanoDQM_cfi.py
Expand Up @@ -112,6 +112,51 @@
Plot1D('dEsigmaDown', 'dEsigmaDown', 100, -0.1, 0.1, '#Delta E sigmaDown'),
)
),

LowPtElectron = cms.PSet(
sels = cms.PSet(
Good = cms.string('pt > 1. && ID > 5.')
),
plots = cms.VPSet(
#
Count1D('_size', 8, -0.5, 7.5, 'slimmedLowPtElectrons after basic selection'),
# CandVars
Plot1D('charge', 'charge', 3, -1.5, 1.5, 'electric charge'),
Plot1D('eta', 'eta', 20, -3., 3., 'eta'),
NoPlot('mass'),
Plot1D('pdgId', 'pdgId', 101, -50.5, 50.5, 'PDG code assigned by the event reconstruction (not by MC truth)'),
Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'),
Plot1D('pt', 'pt', 40, 0., 20., 'pt (corrected)'),
# BDT scores and WPs
Plot1D('embeddedID', 'embeddedID', 40, -10., 10., 'Embedded ID, BDT (raw) score'),
Plot1D('ID', 'ID', 40, -10., 10., 'ID, BDT (raw) score'),
Plot1D('unbiased', 'unbiased', 40, -10., 10., 'ElectronSeed, pT- and dxy- agnostic BDT (raw) score'),
Plot1D('ptbiased', 'ptbiased', 40, -10., 10., 'ElectronSeed, pT- and dxy- dependent BDT (raw) score'),
# Isolation
Plot1D('miniPFRelIso_chg', 'miniPFRelIso_chg', 20, 0., 1., 'mini PF relative isolation, charged component'),
Plot1D('miniPFRelIso_all', 'miniPFRelIso_all', 20, 0., 1., 'mini PF relative isolation, total (with scaled rho*EA PU corrections)'),
# Conversions
Plot1D('convVeto', 'convVeto', 2, -0.5, 1.5, 'pass conversion veto'),
Plot1D('convWP', 'convWP', 8, -0.5, 7.5, 'conversion flag bit map: 1=Veto, 2=Loose, 3=Tight'),
Plot1D('convVtxRadius', 'convVtxRadius', 40, 0., 20.0, 'conversion vertex radius (cm)'),
# Tracking
Plot1D('lostHits', 'lostHits', 4, -0.5, 3.5, 'number of missing inner hits'),
# Cluster-related
Plot1D('energyErr', 'energyErr', 40, 0., 20., 'energy error of the cluster from regression'),
Plot1D('deltaEtaSC', 'deltaEtaSC', 20, -0.2, 0.2, 'delta eta (SC,ele) with sign'),
Plot1D('r9', 'r9', 20, 0, 1.1, 'R9 of the supercluster, calculated with full 5x5 region'),
Plot1D('sieie', 'sieie', 20, 0, 0.05, 'sigma_IetaIeta of the supercluster, calculated with full 5x5 region'),
Plot1D('eInvMinusPInv', 'eInvMinusPInv', 20, -0.1, 0.1, '1/E_SC - 1/p_trk'),
Plot1D('scEtOverPt', 'scEtOverPt', 20, -0.5, 0.5, '(supercluster transverse energy)/pt - 1'),
Plot1D('hoe', 'hoe', 20, 0, 0.6, 'H over E'),
# Displacement
Plot1D('dxy', 'dxy', 20, -0.1, 0.1, 'dxy (with sign) wrt first PV, in cm'),
Plot1D('dz', 'dz', 20, -0.3, 0.3, 'dz (with sign) wrt first PV, in cm'),
Plot1D('dxyErr', 'dxyErr', 20, 0., 0.2, 'dxy uncertainty, in cm'),
Plot1D('dzErr', 'dzErr', 20, 0., 0.2, 'dz uncertainty, in cm'),
),
),

FatJet = cms.PSet(
sels = cms.PSet(),
plots = cms.VPSet(
Expand Down
7 changes: 4 additions & 3 deletions PhysicsTools/NanoAOD/python/nano_cff.py
Expand Up @@ -7,6 +7,7 @@
from PhysicsTools.NanoAOD.taus_cff import *
from PhysicsTools.NanoAOD.boostedTaus_cff import *
from PhysicsTools.NanoAOD.electrons_cff import *
from PhysicsTools.NanoAOD.lowPtElectrons_cff import *
from PhysicsTools.NanoAOD.photons_cff import *
from PhysicsTools.NanoAOD.globals_cff import *
from PhysicsTools.NanoAOD.extraflags_cff import *
Expand Down Expand Up @@ -107,10 +108,10 @@
(run2_miniAOD_80XLegacy | run2_nanoAOD_94X2016 | run2_nanoAOD_94XMiniAODv1 | run2_nanoAOD_94XMiniAODv2 | run2_nanoAOD_102Xv1).toModify(l1bits, storeUnprefireableBit=False)

nanoSequenceCommon = cms.Sequence(
nanoMetadata + jetSequence + muonSequence + tauSequence + boostedTauSequence + electronSequence+photonSequence+vertexSequence+
nanoMetadata + jetSequence + muonSequence + tauSequence + boostedTauSequence + electronSequence + lowPtElectronSequence + photonSequence+vertexSequence+
isoTrackSequence + jetLepSequence + # must be after all the leptons
linkedObjects +
jetTables + muonTables + tauTables + boostedTauTables + electronTables + photonTables + globalTables +vertexTables+ metTables+simpleCleanerTable + isoTrackTables
jetTables + muonTables + tauTables + boostedTauTables + electronTables + lowPtElectronTables + photonTables + globalTables +vertexTables+ metTables+simpleCleanerTable + isoTrackTables
)
#remove boosted tau from previous eras
(run2_miniAOD_80XLegacy | run2_nanoAOD_92X | run2_nanoAOD_94XMiniAODv1 | run2_nanoAOD_94X2016 | run2_nanoAOD_94XMiniAODv2 | run2_nanoAOD_102Xv1 | run2_nanoAOD_106Xv1).toReplaceWith(nanoSequenceCommon, nanoSequenceCommon.copyAndExclude([boostedTauSequence, boostedTauTables]))
Expand All @@ -123,7 +124,7 @@

( run2_nanoAOD_106Xv1 & ~run2_nanoAOD_devel).toReplaceWith(nanoSequence, nanoSequence.copyAndExclude([nanoSequenceOnlyData]))

nanoSequenceFS = cms.Sequence(genParticleSequence + genVertexTables + particleLevelSequence + nanoSequenceCommon + jetMC + muonMC + electronMC + photonMC + tauMC + boostedTauMC + metMC + ttbarCatMCProducers + globalTablesMC + btagWeightTable + genWeightsTable + genVertexTable + genParticleTables + particleLevelTables + lheInfoTable + ttbarCategoryTable )
nanoSequenceFS = cms.Sequence(genParticleSequence + genVertexTables + particleLevelSequence + nanoSequenceCommon + jetMC + muonMC + electronMC + lowPtElectronMC + photonMC + tauMC + boostedTauMC + metMC + ttbarCatMCProducers + globalTablesMC + btagWeightTable + genWeightsTable + genVertexTable + genParticleTables + particleLevelTables + lheInfoTable + ttbarCategoryTable )

(run2_nanoAOD_92X | run2_miniAOD_80XLegacy | run2_nanoAOD_94X2016 | run2_nanoAOD_94X2016 | \
run2_nanoAOD_94XMiniAODv1 | run2_nanoAOD_94XMiniAODv2 | \
Expand Down

0 comments on commit d81c275

Please sign in to comment.