Example #1
0
def initMET(process, isData):
    """
    Parts of MET re-reconstruction that are independent of PF candidate collection.
    """

    sequence = cms.Sequence()

    addattr = AddAttr(process, sequence)
  
    addattr('caloMet',
        cms.EDProducer("RecoMETExtractor",
            metSource = cms.InputTag("slimmedMETs", processName = cms.InputTag.skipCurrentProcess()),
            correctionLevel = cms.string('rawCalo')
        )
    )

    if not isData:
        addattr('genMetTrue',
            cms.EDProducer("GenMETExtractor",
                metSource= cms.InputTag("slimmedMETs", processName = cms.InputTag.skipCurrentProcess())
            )
        )

    addattr('patCaloMet',
        patMETs.clone(
            metSource = 'caloMet',
            addMuonCorrections = False,
            addGenMET = False
        )
    )

    return sequence
Example #2
0
def initBTag(process,
             vsuffix,
             candidates='particleFlow',
             primaryVertex='offlinePrimaryVertices'):
    if vsuffix in vertexingConfig:
        if (candidates, primaryVertex) != vertexingConfig[vsuffix]:
            raise RuntimeError('Duplicate vertexing configuration name')

        return cms.Sequence()

    if len(vertexingConfig) == 0:
        # ESProducers and vertexing sequences
        process.load('RecoBTag.ImpactParameter.impactParameter_EventSetup_cff')
        process.load('RecoBTag.CTagging.cTagging_EventSetup_cff')
        process.load('RecoBTag.SecondaryVertex.secondaryVertex_EventSetup_cff')
        process.load('RecoBTag.Combined.combinedMVA_EventSetup_cff')
        process.load('RecoBTag.SoftLepton.softLepton_EventSetup_cff')

    vertexingConfig[vsuffix] = (candidates, primaryVertex)

    sequence = cms.Sequence()

    addattr = AddAttr(process, sequence, vsuffix)

    vertexFinder = addattr(
        'inclusiveCandidateVertexFinder',
        vertexing.inclusiveCandidateVertexFinder.clone(
            primaryVertices=primaryVertex, tracks=candidates))

    vertexMerger = addattr(
        'candidateVertexMerger',
        vertexing.candidateVertexMerger.clone(secondaryVertices=vertexFinder))

    vertexArbitrator = addattr(
        'candidateVertexArbitrator',
        vertexing.candidateVertexArbitrator.clone(
            primaryVertices=primaryVertex,
            tracks=candidates,
            secondaryVertices=vertexMerger))

    secondaryVertices = addattr(
        'inclusiveCandidateSecondaryVertices',
        vertexing.inclusiveCandidateSecondaryVertices.clone(
            secondaryVertices=vertexArbitrator))

    vertexFinderCvsL = addattr(
        'inclusiveCandidateVertexFinderCvsL',
        vertexing.inclusiveCandidateVertexFinderCvsL.clone(
            primaryVertices=primaryVertex, tracks=candidates))

    vertexMergerCvsL = addattr(
        'candidateVertexMergerCvsL',
        vertexing.candidateVertexMergerCvsL.clone(
            secondaryVertices=vertexFinderCvsL))

    vertexArbitratorCvsL = addattr(
        'candidateVertexArbitratorCvsL',
        vertexing.candidateVertexArbitratorCvsL.clone(
            primaryVertices=primaryVertex,
            tracks=candidates,
            secondaryVertices=vertexMergerCvsL))

    secondaryVerticesCvsL = addattr(
        'inclusiveCandidateSecondaryVerticesCvsL',
        vertexing.inclusiveCandidateSecondaryVerticesCvsL.clone(
            secondaryVertices='candidateVertexArbitratorCvsL' + vsuffix))

    return sequence
Example #3
0
def initFatJets(process, isData, labels):
    """
    @labels: ['AK8', 'CA15', ...]
    """

    ########################################
    ##         INITIAL SETUP              ##
    ########################################

    sequence = cms.Sequence()

    addattr = AddAttr(process, sequence)

    if not isData and not hasattr(process, 'packedGenParticlesForJetsNoNu'):
        genParticlesNoNu = addattr(
            'packedGenParticlesForJetsNoNu',
            cms.EDFilter(
                "CandPtrSelector",
                src=cms.InputTag(finalStateGenParticles),
                cut=cms.string(
                    "abs(pdgId) != 12 && abs(pdgId) != 14 && abs(pdgId) != 16")
            ))

        for label in labels:
            matches = re.match('(AK|CA)([0-9]+)$', label)
            if not matches:
                raise RuntimeError('Unknown algo label ' + label)

            # set up radius and algoName from the input label
            radius = float(matches.group(2)) * 0.1
            if matches.group(1) == 'CA':
                algoName = 'CambridgeAachen'
            elif matches.group(1) == 'AK':
                algoName = 'AntiKt'

            # gen jets
            addattr(
                'genJetsNoNu' + label,
                ak4GenJets.clone(jetAlgorithm=cms.string(algoName),
                                 rParam=cms.double(radius),
                                 src=genParticlesNoNu))
            genJetsMod = addattr.last

            sdZcut, sdBeta = sdParams(radius)

            # gen jets soft drop for subjet gen matching
            addattr(
                'genJetsNoNuSoftDrop' + label,
                genJetsMod.clone(R0=cms.double(radius),
                                 useSoftDrop=cms.bool(True),
                                 zcut=cms.double(sdZcut),
                                 beta=cms.double(sdBeta),
                                 writeCompound=cms.bool(True),
                                 useExplicitGhosts=cms.bool(True),
                                 jetCollInstanceName=cms.string("SubJets")))

    # Charged hadron subtraction
    addattr(
        'pfCHS',
        cms.EDFilter("CandPtrSelector",
                     src=cms.InputTag(pfSource),
                     cut=cms.string("fromPV")))

    # Initialize btag inputs
    sequence += initBTag(process, '', pfSource, pvSource)

    return sequence
Example #4
0
def makeFatJets(process, isData, label, candidates, ptMin=100.):
    """
    @param label: AK8PFchs, CA15PFPuppi, etc.
    """

    matches = re.match('(AK|CA)([0-9]+)PF(.+)', label)
    if not matches:
        raise RuntimeError('Unknown algo label ' + label)

    algo = matches.group(1) + matches.group(2)

    # set up radius and algoName from the input label
    radius = float(matches.group(2)) * 0.1
    if matches.group(1) == 'CA':
        algoName = 'CambridgeAachen'
    elif matches.group(1) == 'AK':
        algoName = 'AntiKt'

    pu = matches.group(3)

    if pu == 'chs':
        jecLabel = 'AK8PFchs'  # regardless of jet algo
    elif pu == 'Puppi':
        jecLabel = 'AK8PFPuppi'  # regardless of jet algo
    else:
        raise RuntimeError('Unknown PU mitigation ' + pu)

    sdZcut, sdBeta = sdParams(radius)

    sequence = cms.Sequence()

    # Callable object that adds the second argument to process and sequence with label attached as suffix
    addattr = AddAttr(process, sequence, label)

    ########################################
    ##           REMAKE JETS              ##
    ########################################

    pfJets = addattr(
        'pfJets',
        ak4PFJets.clone(jetAlgorithm=cms.string(algoName),
                        rParam=cms.double(radius),
                        src=cms.InputTag(candidates),
                        jetPtMin=cms.double(ptMin)))

    pfJetsSoftDrop = addattr(
        'pfJetsSoftDrop',
        ak4PFJets.clone(jetAlgorithm=cms.string(algoName),
                        rParam=cms.double(radius),
                        src=cms.InputTag(candidates),
                        jetPtMin=cms.double(ptMin),
                        useSoftDrop=cms.bool(True),
                        R0=cms.double(radius),
                        zcut=cms.double(sdZcut),
                        beta=cms.double(sdBeta),
                        writeCompound=cms.bool(True),
                        useExplicitGhosts=cms.bool(True),
                        jetCollInstanceName=cms.string("SubJets")))
    subjets = cms.InputTag(pfJetsSoftDrop.getModuleLabel(), 'SubJets')

    pfJetsPruned = addattr(
        'pfJetsPruned',
        ak4PFJets.clone(
            jetAlgorithm=cms.string(algoName),
            rParam=cms.double(radius),
            src=cms.InputTag(candidates),
            jetPtMin=cms.double(ptMin),
            usePruning=cms.bool(True),
            useExplicitGhosts=cms.bool(True),
            writeCompound=cms.bool(True),
            zcut=cms.double(0.1),  # no idea if these parameters are correct
            rcut_factor=cms.double(0.5),
            nFilt=cms.int32(2),
            jetCollInstanceName=cms.string("SubJets")))

    ########################################
    ##           SUBSTRUCTURE             ##
    #######################################

    Njettiness = addattr(
        'Njettiness',
        nJettinessAdder_cfi.Njettiness.clone(src=pfJets,
                                             R0=cms.double(radius),
                                             Njets=cms.vuint32(1, 2, 3, 4)))

    sdKinematics = addattr(
        'sdKinematics',
        cms.EDProducer('RecoJetDeltaRValueMapProducer',
                       src=pfJets,
                       matched=pfJetsSoftDrop,
                       distMax=cms.double(radius),
                       values=cms.vstring('mass'),
                       valueLabels=cms.vstring('Mass')))

    prunedKinematics = addattr(
        'prunedKinematics',
        cms.EDProducer('RecoJetDeltaRValueMapProducer',
                       src=pfJets,
                       matched=pfJetsPruned,
                       distMax=cms.double(radius),
                       values=cms.vstring('mass'),
                       valueLabels=cms.vstring('Mass')))

    ### subjet qg-tagging ###

    subQGTag = addattr(
        'subQGTag',
        QGTagger.clone(srcJets=subjets, jetsLabel=cms.string('QGL_AK4PFchs')))

    ### subjet b-tagging ###

    # sets up process.pfCombinedInclusiveSecondaryVertexV2BJetTags(label)Subjets (and necessary inputs)
    sequence += setupBTag(
        process,
        jetCollection=subjets,
        suffix=label + 'Subjets',
        vsuffix='',
        tags=['pfCombinedInclusiveSecondaryVertexV2BJetTags'])

    ########################################
    ##          MAKE PAT JETS             ##
    ########################################

    ## MAIN JET ##

    jecLevels = ['L1FastJet', 'L2Relative', 'L3Absolute']
    if isData:
        jecLevels.append('L2L3Residual')

    jetCorrFactors = addattr(
        'jetCorrFactors',
        jetUpdater_cff.patJetCorrFactors.clone(src=pfJets,
                                               payload=jecLabel,
                                               levels=jecLevels,
                                               primaryVertices=pvSource))

    if not isData:
        genJetMatch = addattr(
            'genJetMatch',
            patJetGenJetMatch.clone(src=pfJets,
                                    maxDeltaR=radius,
                                    matched='genJetsNoNu' + algo))

    patJets = addattr(
        'patJets',
        jetProducer_cfi.patJets.clone(jetSource=pfJets,
                                      addJetCorrFactors=True,
                                      addBTagInfo=False,
                                      addAssociatedTracks=False,
                                      addJetCharge=False,
                                      addGenPartonMatch=False,
                                      addGenJetMatch=(not isData),
                                      getJetMCFlavour=False,
                                      addJetFlavourInfo=False))
    patJetsMod = addattr.last
    patJetsMod.jetCorrFactorsSource = [jetCorrFactors]
    if not isData:
        patJetsMod.genJetMatch = genJetMatch

    for tau in ['tau1', 'tau2', 'tau3', 'tau4']:
        patJetsMod.userData.userFloats.src.append(Njettiness.getModuleLabel() +
                                                  ':' + tau)

    patJetsMod.userData.userFloats.src.append(sdKinematics.getModuleLabel() +
                                              ':Mass')
    patJetsMod.userData.userFloats.src.append(
        prunedKinematics.getModuleLabel() + ':Mass')

    selectedPatJets = addattr(
        'selectedPatJets',
        jetSelector_cfi.selectedPatJets.clone(src=patJets,
                                              cut='abs(eta) < 2.5'))

    ## SOFT DROP ##

    patJetsSoftDrop = addattr(
        'patJetsSoftDrop',
        jetProducer_cfi._patJets.clone(jetSource=pfJetsSoftDrop,
                                       addJetCorrFactors=False,
                                       addBTagInfo=False,
                                       addAssociatedTracks=False,
                                       addJetCharge=False,
                                       addGenPartonMatch=False,
                                       addGenJetMatch=False,
                                       getJetMCFlavour=False,
                                       addJetFlavourInfo=False))

    selectedPatJetsSoftDrop = addattr(
        'selectedPatJetsSoftDrop',
        jetSelector_cfi.selectedPatJets.clone(src=patJetsSoftDrop,
                                              cut='abs(eta) < 2.5'))

    if not isData:
        genSubjetsMatch = addattr(
            'genSubjetMatch',
            patJetGenJetMatch.clone(src=subjets,
                                    maxDeltaR=0.4,
                                    matched='genJetsNoNuSoftDrop' + algo +
                                    ':SubJets'))

    patSubjets = addattr(
        'patSubjets',
        jetProducer_cfi._patJets.clone(
            jetSource=subjets,
            addJetCorrFactors=False,
            addBTagInfo=True,
            discriminatorSources=[
                'pfCombinedInclusiveSecondaryVertexV2BJetTags' + label +
                'Subjets'
            ],
            addAssociatedTracks=False,
            addJetCharge=False,
            addGenPartonMatch=False,
            addGenJetMatch=(not isData),
            getJetMCFlavour=False,
            addJetFlavourInfo=False))
    patSubjetsMod = addattr.last
    patSubjetsMod.userData.userFloats.src.append(
        cms.InputTag(subQGTag.getModuleLabel(), 'qgLikelihood'))
    if not isData:
        patSubjetsMod.genJetMatch = genSubjetsMatch

    ## MERGE SUBJETS BACK ##
    jetMerger = addattr(
        'jetMerger',
        cms.EDProducer("BoostedJetMerger",
                       jetSrc=selectedPatJetsSoftDrop,
                       subjetSrc=patSubjets))

    ## PACK ##
    addattr(
        'packedPatJets',
        cms.EDProducer("JetSubstructurePacker",
                       jetSrc=selectedPatJets,
                       distMax=cms.double(radius),
                       algoTags=cms.VInputTag(jetMerger),
                       algoLabels=cms.vstring('SoftDrop'),
                       fixDaughters=cms.bool(False)))

    return sequence
Example #5
0
def makeJets(process, isData, label, candidates, suffix):
    """
    Light-weight version of pat addJetCollection.
    @labels: e.g. 'AK4PFPuppi'
    """

    sequence = cms.Sequence()

    addattr = AddAttr(process, sequence, suffix)

    ak4PFJets = addattr('ak4PFJets',
        ak4PFJetsPuppi.clone(
            src = candidates,
            doAreaFastjet = True
        )
    )

    jecLevels= ['L1FastJet',  'L2Relative', 'L3Absolute']
    if isData:
        jecLevels.append('L2L3Residual')

    jetCorrFactors = addattr('jetCorrFactors',
        patJetCorrFactors.clone(
            src = ak4PFJets,
            payload = label,
            levels = jecLevels,
            primaryVertices = pvSource
        )
    )

    # btag should always use standard PF collection
    sequence += initBTag(process, '', pfSource, pvSource)

    sequence += setupBTag(
        process,
        jetCollection = ak4PFJets,
        suffix = suffix,
        vsuffix = '',
        muons = muons,
        electrons = electrons,
        tags = ['pfCombinedInclusiveSecondaryVertexV2BJetTags']
    )

    if not isData:
        genJetMatch = addattr('genJetMatch',
            patJetGenJetMatch.clone(
                src = ak4PFJets,
                maxDeltaR = 0.4,
                matched = genJets
            )
        )

    allPatJets = addattr('patJets',
        patJets.clone(
            jetSource = ak4PFJets,
            addJetCorrFactors = True,
            jetCorrFactorsSource = [jetCorrFactors],
            addBTagInfo = True,
            discriminatorSources = [cms.InputTag('pfCombinedInclusiveSecondaryVertexV2BJetTags' + suffix)],
            addAssociatedTracks = False,
            addJetCharge = False,
            addGenPartonMatch = False,
            addGenJetMatch = (not isData),
            getJetMCFlavour = False,
            addJetFlavourInfo = False
        )
    )

    if not isData:
        addattr.last.genJetMatch = genJetMatch

    selectedJets = addattr('selectedJets',
        selectedPatJets.clone(
            src = allPatJets,
            cut = 'pt > 15'
        )
    )

    addattr('slimmedJets',
        slimmedJets.clone(
            src = selectedJets,
            rekeyDaughters = '0'
        )
    )

    return sequence
Example #6
0
def makeJets(process, isData, label, candidates, suffix):
    """
    Light-weight version of pat addJetCollection.
    @labels: e.g. 'AK4PFPuppi'
    """

    sequence = cms.Sequence()

    addattr = AddAttr(process, sequence, suffix)

    jets = addattr('ak4PFJets',
                   ak4PFJets.clone(src=candidates, doAreaFastjet=True))

    jecLevels = ['L1FastJet', 'L2Relative', 'L3Absolute']
    if isData:
        jecLevels.append('L2L3Residual')

    jetCorrFactors = addattr(
        'jetCorrFactors',
        patJetCorrFactors.clone(src=jets,
                                payload=label,
                                levels=jecLevels,
                                primaryVertices=pvSource))

    # btag should always use standard PF collection
    sequence += initBTag(process, '', pfSource, pvSource)

    sequence += setupBTag(process,
                          jetCollection=jets,
                          suffix=suffix,
                          vsuffix='',
                          muons=muons,
                          electrons=electrons,
                          tags=[
                              'pfCombinedInclusiveSecondaryVertexV2BJetTags',
                              'pfCombinedMVAV2BJetTags', 'pfDeepCSVJetTags',
                              'pfDeepCMVAJetTags'
                          ])

    qgTagger = addattr('QGTagger', QGTagger.clone(srcJets=jets))

    if not isData:
        genJetMatch = addattr(
            'genJetMatch',
            patJetGenJetMatch.clone(src=jets, maxDeltaR=0.4, matched=genJets))


    allPatJets = addattr('patJets',
        patJets.clone(
            jetSource = jets,
            addJetCorrFactors = True,
            jetCorrFactorsSource = [jetCorrFactors],
            addBTagInfo = True,
            discriminatorSources = [
                cms.InputTag('pfCombinedInclusiveSecondaryVertexV2BJetTags' + suffix),
                cms.InputTag('pfCombinedMVAV2BJetTags' + suffix),
                ] + \
                sum([[cms.InputTag('pfDeepCSVJetTags' + suffix, 'prob' + prob),
                      cms.InputTag('pfDeepCMVAJetTags' + suffix, 'prob' + prob)]
                       #                     for prob in ['udsg', 'b', 'c', 'bb', 'cc']],
                     for prob in ['udsg', 'b', 'c', 'bb']],
                    []),
            addAssociatedTracks = False,
            addJetCharge = False,
            addGenPartonMatch = False,
            addGenJetMatch = (not isData),
            getJetMCFlavour = False,
            addJetFlavourInfo = False
        )
    )

    addattr.last.userData.userFloats.src = [
        qgTagger.getModuleLabel() + ':qgLikelihood'
    ]
    addattr.last.userData.userFloats.labelPostfixesToStrip = cms.vstring(
        suffix)

    if not isData:
        addattr.last.genJetMatch = genJetMatch

    selectedJets = addattr(
        'selectedJets', selectedPatJets.clone(src=allPatJets, cut='pt > 15'))

    addattr('slimmedJets',
            slimmedJets.clone(src=selectedJets, rekeyDaughters='0'))

    return sequence
Example #7
0
def makeMET(process, isData, pfCandidates, jetSource, jetFlavor, postfix = ''):
    """
    @jetFlavor: e.g. 'ak4PFchs'

    Additional information (such as gen and calo mets) are added only if postfix is empty.
    """

    sequence = cms.Sequence()
    # postfix is automatically added to the module names
    addattr = AddAttr(process, sequence, postfix)

    if postfix == '':
        # default MET - extract from input slimmedMETs
        pfMet = addattr('pfMet',
            cms.EDProducer("RecoMETExtractor",
                metSource = cms.InputTag("slimmedMETs", processName = cms.InputTag.skipCurrentProcess()),
                correctionLevel = cms.string('raw')
            )
        )
    else:
        pfMet = addattr('pfMet',
            PFMET_cfi.pfMet.clone(
                src = pfCandidates,
                calculateSignificance = False # done in PAT
            )
        )

    cleanedJets = addattr('cleanedJetsForMET',
        cms.EDProducer("PATJetCleanerForType1MET",
            src = cms.InputTag(jetSource),
            jetCorrEtaMax = cms.double(9.9),
            jetCorrLabel = cms.InputTag("L3Absolute"),
            jetCorrLabelRes = cms.InputTag("L2L3Residual"),
            offsetCorrLabel = cms.InputTag("L1FastJet"),
            skipEM = cms.bool(True),
            skipEMfractionThreshold = cms.double(0.9),
            skipMuonSelection = cms.string('isGlobalMuon | isStandAloneMuon'),
            skipMuons = cms.bool(True),
            type1JetPtThreshold = cms.double(15.0)
        )
    )
    
    selectedJets = addattr('selectedJetsForMET',
        selectedPatJets.clone(
            src = cleanedJets,
            cut = 'pt > 15 && abs(eta) < 9.9'
        )
    )
    
    crossCleanedJets = addattr('crossCleanedJetsForMET',
        cleanPatJets.clone(
            src = selectedJets
        )
    )
    ccJetsMod = addattr.last
    ccJetsMod.checkOverlaps.muons.src = muons
    ccJetsMod.checkOverlaps.electrons.src = electrons
    del ccJetsMod.checkOverlaps.photons
    del ccJetsMod.checkOverlaps.taus
    # not used at all and electrons are already cleaned
    del ccJetsMod.checkOverlaps.tkIsoElectrons

    patPFMet = addattr('patPFMet',
        patMET_cff.patPFMet.clone(
            metSource = pfMet,
            genMETSource = 'genMetTrue',
            srcPFCands = pfCandidates,
            computeMETSignificance = True,
            parameters = (METSignificanceParams_Data if isData else METSignificanceParams),
            srcJets = crossCleanedJets,
            srcLeptons = [electrons, muons, photons],
            addGenMET = (not isData and postfix == '')
        )
    )

    patPFMetT1Corr = addattr('patPFMetT1Corr',
        patMET_cff.patPFMetT1T2Corr.clone(
            src = crossCleanedJets
        )
    )
    
    patPFMetT1 = addattr('patPFMetT1',
        patMET_cff.patPFMetT1.clone(
            src = patPFMet,
            srcCorrections = [cms.InputTag(patPFMetT1Corr.getModuleLabel(), 'type1')]
        )
    )
    
    pfCandsNoEle = addattr('pfCandsNoEle',
        cms.EDProducer("CandPtrProjector", 
            src = cms.InputTag(pfCandidates),
            veto = electrons
        )
    )

    pfCandsNoEleMu = addattr('pfCandsNoEleMu',
        cms.EDProducer("CandPtrProjector", 
            src = pfCandsNoEle,
            veto = muons
        )
    )
        
    pfCandsNoEleMuTau = addattr('pfCandsNoEleMuTau',
        cms.EDProducer("CandPtrProjector", 
            src = pfCandsNoEleMu,
            veto = taus
        )
    )
        
    pfCandsNoEleMuTauGamma = addattr('pfCandsNoEleMuTauGamma',
        cms.EDProducer("CandPtrProjector", 
            src = pfCandsNoEleMuTau,
            veto = photons
        )
    )
    
    pfCandsForUnclusteredUnc = addattr('pfCandsForUnclusteredUnc',
        cms.EDProducer("CandPtrProjector", 
            src = pfCandsNoEleMuTauGamma,
            veto = crossCleanedJets
        )
    )
    
    for vsign, vname in [(1, 'Up'), (-1, 'Down')]:
        shiftConf = [
            ('MuonEn', muons.value(), '((x<100)?(0.002+0*y):(0.05+0*y))'),
            ('ElectronEn', electrons.value(), '((abs(y)<1.479)?(0.006+0*x):(0.015+0*x))'),
            ('PhotonEn', photons.value(), '((abs(y)<1.479)?(0.01+0*x):(0.025+0*x))'),
            ('TauEn', taus.value(), '0.03+0*x*y'),
            ('UnclusteredEn', pfCandsForUnclusteredUnc.value(), ''),
            ('JetEn', crossCleanedJets.value(), '')
        ]
    
        for part, coll, formula in shiftConf:
            if part == 'UnclusteredEn':
                shifted = addattr('shifted' + part + vname,
                    cms.EDProducer("ShiftedParticleProducer",
                        src = pfCandsForUnclusteredUnc,
                        binning = cms.VPSet(
                            # charged PF hadrons - tracker resolution
                            cms.PSet(
                                binSelection = cms.string('charge!=0'),
                                binUncertainty = cms.string('sqrt(pow(0.00009*x,2)+pow(0.0085/sqrt(sin(2*atan(exp(-y)))),2))')
                            ),
                            # neutral PF hadrons - HCAL resolution
                            cms.PSet(
                                binSelection = cms.string('pdgId==130'),
                                energyDependency = cms.bool(True),
                                binUncertainty = cms.string('((abs(y)<1.3)?(min(0.25,sqrt(0.64/x+0.0025))):(min(0.30,sqrt(1.0/x+0.0016))))')
                            ),
                            # photon - ECAL resolution
                            cms.PSet(
                                binSelection = cms.string('pdgId==22'),
                                energyDependency = cms.bool(True),
                                binUncertainty = cms.string('sqrt(0.0009/x+0.000001)+0*y')
                            ),
                            # HF particules - HF resolution
                            cms.PSet(
                                binSelection = cms.string('pdgId==1 || pdgId==2'),
                                energyDependency = cms.bool(True),
                                binUncertainty = cms.string('sqrt(1./x+0.0025)+0*y')
                            ),
                        ),
                        shiftBy = cms.double(float(vsign))
                    )
                )

            elif part == 'JetEn':
                shifted = addattr('shifted' + part + vname,
                    cms.EDProducer('PandaShiftedPATJetProducer',
                        src = crossCleanedJets,
                        jetCorrPayloadName =  cms.string(jetFlavor),
                        jetCorrUncertaintyTag = cms.string('Uncertainty'),
                        addResidualJES = cms.bool(isData),
                        jetCorrLabelUpToL3 = cms.InputTag('L3Absolute'), # use embedded correction factors
                        jetCorrLabelUpToL3Res = cms.InputTag('L2L3Residual'),
                        shiftBy = cms.double(float(vsign))
                    )
                )

            else:
                shifted = addattr('shifted' + part + vname,
                    cms.EDProducer("ShiftedParticleProducer",
                        src = cms.InputTag(coll),
                        uncertainty = cms.string(formula),
                        shiftBy = cms.double(float(vsign))
                    )
                )

            metCorrShifted = addattr('metCorrShifted' + part + vname,
                cms.EDProducer("ShiftedParticleMETcorrInputProducer",
                    srcOriginal = cms.InputTag(coll),
                    srcShifted = shifted
                )
            )
            addattr('patPFMetT1' + part + vname,
                patMET_cff.patPFMetT1.clone(
                    src = patPFMetT1,
                    srcCorrections = [metCorrShifted]
                )
            )

    # Dummy JetResUp and JetResDown modules because PATJetSlimmer requires them
    # Jet smearing should be propagated to MET simply by using ptSmear(|Up|Down) branches at the ntuples level
    addattr('patPFMetT1JetResUp', getattr(process, 'patPFMetT1JetEnUp' + postfix).clone())
    addattr('patPFMetT1JetResDown', getattr(process, 'patPFMetT1JetEnDown' + postfix).clone())
    
    addattr('slimmedMETs',
        slimmedMETs.clone(
            src = patPFMetT1,
            rawVariation = patPFMet,
            t1Uncertainties = "patPFMetT1%s" + postfix,
            runningOnMiniAOD = True
        )
    )

    slimmed = addattr.last

    if postfix == '': # default MET
        slimmed.caloMET = 'patCaloMet'
    else:
        del slimmed.caloMET
    
    del slimmed.t01Variation
    del slimmed.t1SmearedVarsAndUncs
    del slimmed.tXYUncForT1
    del slimmed.tXYUncForRaw
    del slimmed.tXYUncForT01
    del slimmed.tXYUncForT1Smear
    del slimmed.tXYUncForT01Smear

    return sequence