class JES:

  def __init__(self, filename):
    self.jcp = JetCorrectorParameters(filename, "")
    self.jcu = JetCorrectionUncertainty(self.jcp)

  def uncertainty(self, pt, eta):
    self.jcu.setJetPt(pt)
    self.jcu.setJetEta(eta)
    return self.jcu.getUncertainty(True);
Exemplo n.º 2
0
    def __init__(self, year, **kwargs):

        #--------------------------------------------------------------------------------------------
        # CV: globalTag and jetType not yet used, as there is no consistent set of txt files for
        #     JES uncertainties and JER scale factors and uncertainties yet
        #--------------------------------------------------------------------------------------------

        globalTag = kwargs.get('globalTag', None)
        globalTag_JER = kwargs.get('globalTag_JER', None)
        globalTag_JES = kwargs.get('globalTag_JES', globalTag)
        jetType = kwargs.get('jet', 'AK4PFchs')
        metType = kwargs.get('met', 'MET')
        isData = kwargs.get('data', False)
        era = kwargs.get('era', "")  # for data; A, B, C, D, ...
        redoJEC = kwargs.get('redoJEC', True)
        doJER = kwargs.get('smear', not isData) and not isData
        doSystematics = kwargs.get('systematics', True) and not isData
        noGroom = kwargs.get('noGroom', True)
        jesUncertainties = kwargs.get('uncertainties',
                                      ['Total'] if doSystematics else [])
        updateEvent = kwargs.get('updateEvent', False)  # unreliable...
        correctSeparate = kwargs.get('correctSeparate', False)

        jetTypes = ['AK4PFchs', 'AK4PFPuppi', 'AK8PFchs', 'AK8PFPuppi']
        assert year in [
            2016, 2017, 2018
        ], "JetMETCorrectionTool: You must choose a year from: 2016, 2017, or 2018."
        assert jetType in jetTypes, "JetMETCorrectionTool: You must choose a jet type from: %s" % (
            ', '.join(jetTypes))
        assert all(
            u in ['Total', 'All'] for u in jesUncertainties
        ), "JetMETCorrectionTool: Given uncertainties are %s; must be 'Total' or 'All'!" % (
            jesUncertainties)

        # TARGET VARIABLES
        if "AK4" in jetType:
            self.jetBranchName = 'Jet'
            self.genJetBranchName = 'GenJet'
            self.genSubJetBranchName = None
            self.doGroomed = False
            self.corrMET = True
        elif "AK8" in jetType:
            self.jetBranchName = 'FatJet'
            self.subJetBranchName = 'SubJet'
            self.genJetBranchName = 'GenJetAK8'
            self.genSubJetBranchName = 'SubGenJetAK8'
            self.doGroomed = not noGroom
            self.corrMET = False
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.metBranchName = metType
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        self.jmsVals = [1.00, 0.99, 1.01]  # TODO: change to real values
        self.unclEnThreshold = 15.  # energy threshold below which jets are considered as "unclustered energy"
        # cf. JetMETCorrections/Type1MET/python/correctionTermsPfMetType1Type2_cff.py
        jetSmearer = None
        jmr_vals = []

        if isData:

            # GLOBAL TAG for JES
            if globalTag == None:
                if year == 2016:
                    for eraset in ['BCD', 'EF', 'GH']:
                        if era in eraset: era = eraset
                    globalTag = "Summer16_07Aug2017_V11_DATA"
                    globalTag_JES = "Summer16_07Aug2017%s_V11_DATA" % era
                elif year == 2017:
                    if era in 'DE': era = 'DE'
                    globalTag = "Fall17_17Nov2017_V32_DATA"
                    globalTag_JES = "Fall17_17Nov2017%s_V32_DATA" % era
                else:
                    era = "Run" + era
                    globalTag = "Autumn18_V8_DATA"
                    globalTag_JES = "Autumn18_%s_V8_DATA" % era

        else:

            # GLOBAL TAG for JES
            if globalTag == None:
                if year == 2016:
                    globalTag = "Summer16_07Aug2017_V11_MC"  #"Summer16_23Sep2016V4_MC"
                elif year == 2017:
                    globalTag = "Fall17_17Nov2017_V32_MC"
                else:
                    globalTag = "Autumn18_V8_MC"
                globalTag_JES = globalTag

            # GLOBAL TAG for JER
            if globalTag_JER == None:
                if year == 2016:
                    globalTag_JER = "Summer16_25nsV1_MC"
                elif year == 2017:
                    globalTag_JER = "Fall17_V3_MC"
                elif year == 2018:
                    globalTag_JER = "Autumn18_V1_MC"

            # JERs: https://twiki.cern.ch/twiki/bin/view/CMS/JetWtagging
            if year == 2016 or year == 2018:  #update when 2018 values available
                jmr_vals = [1.00, 1.20, 0.80]  # nominal, up, down
            else:
                jmr_vals = [1.09, 1.14, 1.04]

            # READ JER uncertainties
            ###if doJER:
            jetSmearer = JetSmearer(globalTag_JER,
                                    jetType,
                                    systematics=doSystematics,
                                    jmr_vals=jmr_vals)

        # READ JES
        path_JES = ensureJMEFiles(globalTag)

        # REDO JECs
        if redoJEC:
            jetReCalibrator = JetReCalibrator(globalTag_JES,
                                              jetType,
                                              True,
                                              path=path_JES,
                                              correctSeparate=correctSeparate,
                                              correctType1MET=False)
        else:
            jetReCalibrator = None

        # LOAD LIBRARIES for accessing JES scale factors and uncertainties from txt files
        for library in [
                "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools"
        ]:
            if library not in gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                gSystem.Load(library)

        # READ UNCERTAINTY SOURCE NAMES from the loaded file
        jesUncertainty = {}
        filename_JES = ""
        if doSystematics:
            postfix = '' if jesUncertainties == ['Total'] else "Sources"
            filename_JES = ensureFile(
                path_JES,
                "%s_Uncertainty%s_%s.txt" % (globalTag, postfix, jetType))
            if jesUncertainties == ['All']:
                with open(path_JES + '/' + filename_JES) as file:
                    lines = file.read().split("\n")
                    sources = filter(
                        lambda x: x.startswith("[") and x.endswith("]"), lines)
                    sources = map(lambda x: x[1:-1], sources)
                    jesUncertainties = sources

            # CREATE JES uncertainties
            print("Loading JES uncertainties from file '%s'..." % filename_JES)
            #jesUncertainty = JetCorrectionUncertainty(filename_JES)
            # implementation didn't seem to work for factorized JEC, try again another way
            for uncertainty in jesUncertainties:
                unclabel = '' if uncertainty == 'Total' and len(
                    jesUncertainties) == 1 else uncertainty
                pars = JetCorrectorParameters(filename_JES, unclabel)
                jesUncertainty[uncertainty] = JetCorrectionUncertainty(pars)

        self.year = year
        self.globalTag = globalTag
        self.jetType = jetType
        self.metType = metType
        self.isData = isData
        self.era = era
        self.redoJEC = redoJEC
        ###self.doJER            = doJER
        self.doSystematics = doSystematics
        self.noGroom = noGroom
        self.updateEvent = updateEvent
        self.jesUncertainties = jesUncertainties  # list
        self.jesUncertainty = jesUncertainty  # dictionairy
        self.path_JES = path_JES
        self.filename_JES = filename_JES
        self.jmr_vals = jmr_vals
        self.jetSmearer = jetSmearer
        self.jetReCalibrator = jetReCalibrator
        self.correctJetMET = self.correctJetMET_Data if isData else self.correctJetMET_MC
Exemplo n.º 3
0
    def __init__(self, globalTag, jetFlavour, doResidualJECs=True, **kwargs):
        """Create a corrector object that reads the payloads from the text dumps of a global tag under
        CMGTools/RootTools/data/jec  (see the getJec.py there to make the dumps).
        It will apply the L1,L2,L3 and possibly the residual corrections to the jets.
        If configured to do so, it will also compute the type1 MET corrections."""

        globalTag = globalTag
        jetFlavour = jetFlavour
        doResidualJECs = doResidualJECs
        era = kwargs.get('era', "")
        path = kwargs.get('path', pathJEC)
        upToLevel = kwargs.get('upToLevel', 3)
        correctType1MET = kwargs.get('correctType1MET', False)
        correctSeparate = kwargs.get('correctSeparate', False)
        type1METParams = kwargs.get(
            'type1METParams', {
                'jetPtThreshold': 15.,
                'skipEMfractionThreshold': 0.9,
                'skipMuons': True
            })
        ###if era:
        ###  globalTag = re.sub(r"(201[678])(_V\d+)",r"\1%s\2"%era,globalTag)

        # BASE CORRECTIONS
        path = os.path.expandvars(
            path
        )  #"%s/src/CMGTools/RootTools/data/jec"%os.environ['CMSSW_BASE'];
        print("Loading JES corrections from '%s' with globalTag '%s'..." %
              (path, globalTag))
        filenameL1 = ensureFile("%s/%s_L1FastJet_%s.txt" %
                                (path, globalTag, jetFlavour))
        filenameL2 = ensureFile("%s/%s_L2Relative_%s.txt" %
                                (path, globalTag, jetFlavour))
        filenameL3 = ensureFile("%s/%s_L3Absolute_%s.txt" %
                                (path, globalTag, jetFlavour))
        self.L1JetPar = JetCorrectorParameters(filenameL1, "")
        self.L2JetPar = JetCorrectorParameters(filenameL2, "")
        self.L3JetPar = JetCorrectorParameters(filenameL3, "")
        self.vPar = vector(JetCorrectorParameters)()
        self.vPar.push_back(self.L1JetPar)
        if upToLevel >= 2: self.vPar.push_back(self.L2JetPar)
        if upToLevel >= 3: self.vPar.push_back(self.L3JetPar)

        # ADD RESIDUALS
        if doResidualJECs:
            filenameL2L3 = ensureFile("%s/%s_L2L3Residual_%s.txt" %
                                      (path, globalTag, jetFlavour))
            self.ResJetPar = JetCorrectorParameters(filenameL2L3)
            self.vPar.push_back(self.ResJetPar)

        # STEP 3: Construct a FactorizedJetCorrector object
        self.JetCorrector = FactorizedJetCorrector(self.vPar)
        if os.path.exists("%s/%s_Uncertainty_%s.txt" %
                          (path, globalTag, jetFlavour)):
            self.JetUncertainty = JetCorrectionUncertainty(
                "%s/%s_Uncertainty_%s.txt" % (path, globalTag, jetFlavour))
        elif os.path.exists("%s/Uncertainty_FAKE.txt" % path):
            self.JetUncertainty = JetCorrectionUncertainty(
                "%s/Uncertainty_FAKE.txt" % path)
        else:
            print 'Missing JEC uncertainty file "%s/%s_Uncertainty_%s.txt", so jet energy uncertainties will not be available' % (
                path, globalTag, jetFlavour)
            self.JetUncertainty = None
        self.separateJetCorrectors = {}
        if correctSeparate or correctType1MET:
            self.vParL1 = vector(JetCorrectorParameters)()
            self.vParL1.push_back(self.L1JetPar)
            self.separateJetCorrectors['L1'] = FactorizedJetCorrector(
                self.vParL1)
            if upToLevel >= 2 and correctSeparate:
                self.vParL2 = vector(JetCorrectorParameters)()
                for i in [self.L1JetPar, self.L2JetPar]:
                    self.vParL2.push_back(i)
                self.separateJetCorrectors['L1L2'] = FactorizedJetCorrector(
                    self.vParL2)
            if upToLevel >= 3 and correctSeparate:
                self.vParL3 = vector(JetCorrectorParameters)()
                for i in [self.L1JetPar, self.L2JetPar, self.L3JetPar]:
                    self.vParL3.push_back(i)
                self.separateJetCorrectors['L1L2L3'] = FactorizedJetCorrector(
                    self.vParL3)
            if doResidualJECs and correctSeparate:
                self.vParL3Res = vector(JetCorrectorParameters)()
                for i in [
                        self.L1JetPar, self.L2JetPar, self.L3JetPar,
                        self.ResJetPar
                ]:
                    self.vParL3Res.push_back(i)
                self.separateJetCorrectors[
                    'L1L2L3Res'] = FactorizedJetCorrector(self.vParL3Res)

        self.globalTag = globalTag
        self.jetFlavour = jetFlavour
        self.doResidualJECs = doResidualJECs
        self.path = path
        self.upToLevel = upToLevel
        self.correctType1MET = correctType1MET
        self.correctSeparate = correctSeparate
        self.type1METParams = type1METParams
Exemplo n.º 4
0
class JetReCalibrator:
    def __init__(self, globalTag, jetFlavour, doResidualJECs=True, **kwargs):
        """Create a corrector object that reads the payloads from the text dumps of a global tag under
        CMGTools/RootTools/data/jec  (see the getJec.py there to make the dumps).
        It will apply the L1,L2,L3 and possibly the residual corrections to the jets.
        If configured to do so, it will also compute the type1 MET corrections."""

        globalTag = globalTag
        jetFlavour = jetFlavour
        doResidualJECs = doResidualJECs
        era = kwargs.get('era', "")
        path = kwargs.get('path', pathJEC)
        upToLevel = kwargs.get('upToLevel', 3)
        correctType1MET = kwargs.get('correctType1MET', False)
        correctSeparate = kwargs.get('correctSeparate', False)
        type1METParams = kwargs.get(
            'type1METParams', {
                'jetPtThreshold': 15.,
                'skipEMfractionThreshold': 0.9,
                'skipMuons': True
            })
        ###if era:
        ###  globalTag = re.sub(r"(201[678])(_V\d+)",r"\1%s\2"%era,globalTag)

        # BASE CORRECTIONS
        path = os.path.expandvars(
            path
        )  #"%s/src/CMGTools/RootTools/data/jec"%os.environ['CMSSW_BASE'];
        print("Loading JES corrections from '%s' with globalTag '%s'..." %
              (path, globalTag))
        filenameL1 = ensureFile("%s/%s_L1FastJet_%s.txt" %
                                (path, globalTag, jetFlavour))
        filenameL2 = ensureFile("%s/%s_L2Relative_%s.txt" %
                                (path, globalTag, jetFlavour))
        filenameL3 = ensureFile("%s/%s_L3Absolute_%s.txt" %
                                (path, globalTag, jetFlavour))
        self.L1JetPar = JetCorrectorParameters(filenameL1, "")
        self.L2JetPar = JetCorrectorParameters(filenameL2, "")
        self.L3JetPar = JetCorrectorParameters(filenameL3, "")
        self.vPar = vector(JetCorrectorParameters)()
        self.vPar.push_back(self.L1JetPar)
        if upToLevel >= 2: self.vPar.push_back(self.L2JetPar)
        if upToLevel >= 3: self.vPar.push_back(self.L3JetPar)

        # ADD RESIDUALS
        if doResidualJECs:
            filenameL2L3 = ensureFile("%s/%s_L2L3Residual_%s.txt" %
                                      (path, globalTag, jetFlavour))
            self.ResJetPar = JetCorrectorParameters(filenameL2L3)
            self.vPar.push_back(self.ResJetPar)

        # STEP 3: Construct a FactorizedJetCorrector object
        self.JetCorrector = FactorizedJetCorrector(self.vPar)
        if os.path.exists("%s/%s_Uncertainty_%s.txt" %
                          (path, globalTag, jetFlavour)):
            self.JetUncertainty = JetCorrectionUncertainty(
                "%s/%s_Uncertainty_%s.txt" % (path, globalTag, jetFlavour))
        elif os.path.exists("%s/Uncertainty_FAKE.txt" % path):
            self.JetUncertainty = JetCorrectionUncertainty(
                "%s/Uncertainty_FAKE.txt" % path)
        else:
            print 'Missing JEC uncertainty file "%s/%s_Uncertainty_%s.txt", so jet energy uncertainties will not be available' % (
                path, globalTag, jetFlavour)
            self.JetUncertainty = None
        self.separateJetCorrectors = {}
        if correctSeparate or correctType1MET:
            self.vParL1 = vector(JetCorrectorParameters)()
            self.vParL1.push_back(self.L1JetPar)
            self.separateJetCorrectors['L1'] = FactorizedJetCorrector(
                self.vParL1)
            if upToLevel >= 2 and correctSeparate:
                self.vParL2 = vector(JetCorrectorParameters)()
                for i in [self.L1JetPar, self.L2JetPar]:
                    self.vParL2.push_back(i)
                self.separateJetCorrectors['L1L2'] = FactorizedJetCorrector(
                    self.vParL2)
            if upToLevel >= 3 and correctSeparate:
                self.vParL3 = vector(JetCorrectorParameters)()
                for i in [self.L1JetPar, self.L2JetPar, self.L3JetPar]:
                    self.vParL3.push_back(i)
                self.separateJetCorrectors['L1L2L3'] = FactorizedJetCorrector(
                    self.vParL3)
            if doResidualJECs and correctSeparate:
                self.vParL3Res = vector(JetCorrectorParameters)()
                for i in [
                        self.L1JetPar, self.L2JetPar, self.L3JetPar,
                        self.ResJetPar
                ]:
                    self.vParL3Res.push_back(i)
                self.separateJetCorrectors[
                    'L1L2L3Res'] = FactorizedJetCorrector(self.vParL3Res)

        self.globalTag = globalTag
        self.jetFlavour = jetFlavour
        self.doResidualJECs = doResidualJECs
        self.path = path
        self.upToLevel = upToLevel
        self.correctType1MET = correctType1MET
        self.correctSeparate = correctSeparate
        self.type1METParams = type1METParams

    def getCorrection(self, jet, rho, delta=0, corrector=None):
        """Compute correction for a given jet."""

        if not corrector:
            corrector = self.JetCorrector
        if corrector != self.JetCorrector and delta != 0:
            raise RuntimeError('Configuration not supported')

        corrector.setJetEta(jet.eta)
        corrector.setJetPt(jet.pt * (1. - jet.rawFactor))
        corrector.setJetA(jet.area)
        corrector.setRho(rho)
        corr = corrector.getCorrection()

        if delta != 0:
            if not self.JetUncertainty:
                raise RuntimeError(
                    "Jet energy scale uncertainty shifts requested, but not available"
                )
            self.JetUncertainty.setJetEta(jet.eta)
            self.JetUncertainty.setJetPt(corr * jet.pt * (1. - jet.rawFactor))
            try:
                jet.jetEnergyCorrUncertainty = self.JetUncertainty.getUncertainty(
                    True)
            except RuntimeError as r:
                print "Caught %s when getting uncertainty for jet of pt %.1f, eta %.2f\n" % (
                    r, corr * jet.pt * (1. - jet.rawFactor), jet.eta)
                jet.jetEnergyCorrUncertainty = 0.5
            #print "   jet with corr pt %6.2f has an uncertainty %.2f "%(jet.pt()*jet.rawFactor()*corr, jet.jetEnergyCorrUncertainty)
            corr *= max(0, 1 + delta * jet.jetEnergyCorrUncertainty)

        #print "%10.4f %10.4f %10.5f %10.5f"%(jet.pt,jet.eta,jet.rawFactor,corr)
        return corr

    def correct(self,
                jet,
                rho,
                delta=0,
                addCorr=False,
                addShifts=False,
                metShift=[0, 0]):
        """Corrects a jet energy (optionally shifting it also by delta times the JEC uncertainty)
           If addCorr, set jet.corr to the correction.
           If addShifts, set also the +1 and -1 jet shifts
           The metShift vector will accumulate the x and y changes to the MET from the JEC, i.e. the
           negative difference between the new and old jet momentum, for jets eligible for type1 MET
           corrections, and after subtracting muons. The pt cut is applied to the new corrected pt.
           This shift can be applied on top of the *OLD TYPE1 MET*, but only if there was no change
           in the L1 corrections nor in the definition of the type1 MET (e.g. jet pt cuts).
        """
        raw = 1. - jet.rawFactor
        corr = self.getCorrection(jet, rho, delta)
        ###print "%8.4f %8.4f %8.4f"%(jet.pt,raw,corr)
        if corr <= 0:
            return jet.pt
        newpt = raw * corr * jet.pt
        newmass = raw * corr * jet.mass
        return newpt, newmass
 def __init__(self, filename):
   self.jcp = JetCorrectorParameters(filename, "")
   self.jcu = JetCorrectionUncertainty(self.jcp)
Exemplo n.º 6
0
def selectEvents(fileName,saveProbes=False,saveSummary=False,outputDir='./',xsec=-1,correctionsMap={}):

    gSystem.ExpandPathName(fileName)
    file=TFile.Open(fileName)

    #exclusivity of triggers per PD
    eTriggersOnly  = ('SingleEle' in fileName)
    muTriggersOnly = ('SingleMu'  in fileName)

    #normalizations and corrections
    origEvents=1.0
    puWeightsGr=None
    if xsec>0 :
        origEvents=file.Get('smDataAnalyzer/cutflow').GetBinContent(1)
        if origEvents==0 :
            print '[Warning] 0 initial events ?'

        #derive pileup weights
        origPileup=file.Get('smDataAnalyzer/pileup')
        try:
            dataPileupFile=TFile.Open(correctionsMap['pu'])
            dataPileup=dataPileupFile.Get('pileup')
            normF=origPileup.Integral()/dataPileup.Integral()
            if normF>0 :
                puWeightsGr=TGraph()
                for xbin in xrange(1,origPileup.GetXaxis().GetNbins()+1) :
                    iweight=1.0
                    if origPileup.GetBinContent(xbin)>0 :
                        iweight=normF*dataPileup.GetBinContent(xbin)/origPileup.GetBinContent(xbin)
                        puWeightsGr.SetPoint( puWeightsGr.GetN(), origPileup.GetXaxis().GetBinCenter(xbin), iweight )
            dataPileupFile.Close()
        except :
            print 'No data pileup file provided or other error occurred. If you wish add -w pu,pu_file.root'

    jecCorrector=None
    jecUncertainty=None
    try:
        prefix='Data'
        if xsec>0 : prefix='MC'
        jecDir=correctionsMap['jec']

        gSystem.ExpandPathName(jecDir)
        jetCorLevels='L1FastJet'
        jetCorFiles=jecDir+'/'+prefix+'_L1FastJet_AK5PFchs.txt'
        jetCorLevels=jetCorLevels+':L2Relative'
        jetCorFiles=jetCorFiles+':'+jecDir+'/'+prefix+'_L2Relative_AK5PFchs.txt'
        jetCorLevels=jetCorLevels+':L3Absolute'
        jetCorFiles=jetCorFiles+':'+jecDir+'/'+prefix+'_L3Absolute_AK5PFchs.txt'
        #if prefix=='Data':
        #    jetCorLevels=jetCorLevels+':L2L3Residual'
        #    jetCorFiles=jetCorFiles+':'+jecDir+'/'+prefix+'_L2L3Residual_AK5PFchs.txt'
        jecCorrector=FactorizedJetCorrector(jetCorLevels,jetCorFiles)
        print 'Jet energy corrector initialized with levels ',jetCorLevels,' for ',prefix

        if prefix=='MC':
            jecUncertainty=JetCorrectionUncertainty(jecDir+"/"+prefix+"_Uncertainty_AK5PFchs.txt")
            print 'Jet uncertainty is ',jecUncertainty

    except Exception as e:
        print '[Error]',e



    tree=file.Get("smDataAnalyzer/data")
    nev = tree.GetEntries()

    outUrl=outputDir+'/'+os.path.basename(fileName)
    monitor=Monitor(outUrl)

    #same the initial normalization and cross section
    monitor.addValue(origEvents,'iniEvents')
    monitor.addValue(xsec,'crossSection')

    #some basic histograms
    monitor.addHisto('nvtx',    ';Vertices;Events',                       50,0,50)
    monitor.addHisto('nvtxraw', ';Vertices;Events',                       50,0,50)
    monitor.addHisto('vmass',   ';Mass [GeV];Events',                     50,0,250)
    monitor.addHisto('vmt',     ';Transverse mass [GeV];Events',          50,0,250)
    monitor.addHisto('vpt',     ';Boson transverse momentum [GeV];Events',50,0,250)
    monitor.addHisto('leg1pt',  ';Transverse momentum [GeV];Events',      50,0,250)
    monitor.addHisto('leg2pt',  ';Transverse momentum [GeV];Events',      50,0,250)
    monitor.addHisto('leg1iso', ';Relative isolation;Events',             50,0,0.5)
    monitor.addHisto('leg2iso', ';Relative isolation;Events',             50,0,0.5)

    #save a summary ntuple for analysis
    summaryTuple=None
    if saveSummary :
        varList='cat:weight:nvtx:njets'
        varList=varList+':v_mass:v_mt:v_pt:genv_mass:genv_pt'
        varList=varList+':leg1_pt:leg1_eta:leg1_phi:genleg1_pt:leg1_relIso'
        varList=varList+':leg2_pt:leg2_eta:leg2_phi:genleg2_pt:leg2_relIso'
        varList=varList+':sumEt:ht'
        varList=varList+':met_lesup:met_lesdown:met_jesup:met_jesdown:met_jerup:met_jerdown:met_umetup:met_umetdown'
        summaryTuple=TNtuple('data','summary',varList)
        summaryTuple.SetDirectory(0)
        monitor.addObject(summaryTuple)

    #save a dedicated ntuple for Tag and Probe
    probesTuple=None
    probesId   = array.array( 'f', [ 0 ] )
    probesPt   = array.array( 'f', [ 0 ] )
    probesEta  = array.array( 'f', [ 0 ] )
    probesPhi  = array.array( 'f', [ 0 ] )
    probesNvtx = array.array( 'f', [ 0 ] )
    probesMass = array.array( 'f', [ 0 ] )
    probesIsMatched = array.array( 'i', [0] )
    probesPassLoose = array.array( 'i', [ 0 ] )
    probesPassTight = array.array( 'i', [ 0 ] )
    probesFireTrigger = array.array( 'i', [ 0 ] )
    if saveProbes :
        probesTuple=TTree('tandp','summary for tandp')
        probesTuple.Branch( 'id', probesId, 'id/F' )
        probesTuple.Branch( 'pt', probesPt, 'pt/F' )
        probesTuple.Branch( 'eta', probesEta, 'eta/F' )
        probesTuple.Branch( 'phi', probesPhi, 'phi/F' )
        probesTuple.Branch( 'nvtx', probesNvtx, 'nvtx/F' )
        probesTuple.Branch( 'mass', probesMass, 'mass/F' )
        probesTuple.Branch( 'isMatched', probesIsMatched, 'isMatched/I' )
        probesTuple.Branch( 'passLoose', probesPassLoose, 'passLoose/I' )
        probesTuple.Branch( 'passTight', probesPassTight, 'passTight/I' )
        probesTuple.Branch( 'fireTrigger', probesFireTrigger, 'fireTrigger/I' )
        probesTuple.SetDirectory(0)
        monitor.addObject(probesTuple)

    #
    # LOOP OVER THE EVENTS
    #
    for iev in xrange(0,nev):
        tree.GetEntry(iev)
        if iev%10000 == 0 :
            sys.stdout.write("\r[ %d/100 ] completed" %(100.*iev/nev))
            sys.stdout.flush()

        #check mc truth (select V bosons from the hard process
        genBosonP4=TLorentzVector(0,0,0,0)
        genNeutP4=TLorentzVector(0,0,0,0)
        for g in xrange(0,tree.mcn):
            if tree.mc_status[g]!=3 : continue
            genP4=TLorentzVector(tree.mc_px[g],tree.mc_py[g],tree.mc_pz[g],tree.mc_en[g])
            if abs(tree.mc_id[g])==12 or abs(tree.mc_id[g])==14 or abs(tree.mc_id[g])==14 : genNeutP4=genNeutP4+genP4
            if abs(tree.mc_id[g])!=23 and abs(tree.mc_id[g])!=24 : continue
            genBosonP4=genP4
        
        #get triggers that fired
        eFire,mFire,emFire=decodeTriggerWord(tree.tbits)
        if eTriggersOnly :  mFire=False
        if muTriggersOnly : eFire=False

        #select the leptons
        leptonCands=[]
        validTags=[]
        lepSums=[TLorentzVector(0,0,0,0)]*3
        lepFlux=TLorentzVector(0,0,0,0)
        for l in xrange(0,tree.ln) :
            lep=LeptonCand(tree.ln_id[l],tree.ln_px[l],tree.ln_py[l],tree.ln_pz[l],tree.ln_en[l])
            if lep.p4.Pt()<20 : continue
            if abs(tree.ln_id[l])==11 :
                if math.fabs(lep.p4.Eta())>2.5 : continue
                if math.fabs(lep.p4.Eta())>1.4442 and math.fabs(lep.p4.Eta())<1.566 : continue
            if abs(tree.ln_id[l])==13 :
                if math.fabs(lep.p4.Eta())>2.1 : continue
            relIso, isLoose, isLooseIso, isTight, isTightIso = selectLepton(tree.ln_id[l],tree.ln_idbits[l],tree.ln_gIso[l],tree.ln_chIso[l],tree.ln_nhIso[l],tree.ln_puchIso[l],lep.p4.Pt())
            lep.selectionInfo(relIso,isLoose, isLooseIso, isTight, isTightIso)
            lep.triggerInfo(tree.ln_Tbits[l])

            #check the generator level information
            genMatchIdx=tree.ln_genid[l]
            if genMatchIdx < tree.mcn :
                lep.genMatch(tree.mc_id[genMatchIdx],tree.mc_px[genMatchIdx],tree.mc_py[genMatchIdx],tree.mc_pz[genMatchIdx],tree.mc_en[genMatchIdx])
            else :
                lep.genMatch(0,0,0,0,0)
            leptonCands.append(lep)

            if not saveProbes: continue
            if not isTight or not isTightIso or lep.Tbits==0 : continue
            if abs(lep.id)==11 and not eFire: continue
            if abs(lep.id)==13 and not mFire: continue

            validTags.append( len(leptonCands)-1 )
            lepSums[1]=lepSums[1]+lep.getP4('lesup')-lep.p4
            lepSums[2]=lepSums[2]+lep.getP4('lesdown')-lep.p4
            lepFlux=lepFlux+lep.p4

        #check if probes tree should be saved
        if saveProbes and len(validTags)>0:

            # choose a random tag
            tagIdx=random.choice(validTags)
            tag=leptonCands[tagIdx]

            #find probe
            probe=None
            for l in xrange(0,len(leptonCands)) :
                if l==tagIdx: continue
                if abs(tag.id)!=abs(leptonCands[l].id) : continue
                probe=leptonCands[l]
                break

            #for electrons save superclusters if probe is not found
            matchToEle=1
            #if abs(tag.id)==11 and probe is None :
            #    matchToEle=0
            #    for sc in xrange(0,tree.scn) :
            #        sc_en=tree.scn_e[sc]
            #        sc_eta=tree.scn_eta[sc]
            #        sc_phi=tree.scn_phi[sc]
            #        sc_pt=sc_en/math.cosh(sc_eta)
            #        sc_p4=TLorentzVector(0,0,0,0)
            #        sc_p4.SetPtEtaPhiE(sc_pt,sc_eta,sc_phi,sc_en)
            #        lscp4=tag.p4+sc_p4
            #        if math.fabs(lscp4.M()-91)>30 : continue
            #        scCand=LeptonCand(tag.id,sc_p4.Px(),sc_p4.Py(),sc_p4.Pz(),sc_p4.E())
            #        scCand.selectionInfo(0,0,0,0,0)
            #        scCand.triggerInfo(0)
            #        probe=scCand
            #        break
            if abs(tag.id)==13 : matchToEle=0

            #save info
            if probe is not None:
                tpp4=tag.p4+probe.p4
                if math.fabs(tpp4.M()-91)<30 :
                    probesId[0]=probe.id
                    probesPt[0]=probe.p4.Pt()
                    probesEta[0]=probe.p4.Eta()
                    probesPhi[0]=probe.p4.Phi()
                    probesNvtx[0]=tree.nvtx
                    probesMass[0]=tpp4.M()
                    probesIsMatched[0]=(probe.genId!=0)
                    probesPassLoose[0]=(probe.passLoose and probe.passLooseIso)
                    probesPassTight[0]=(probe.passTight and probe.passTightIso)
                    probesFireTrigger[0]=(probe.Tbits>0)
                    probesTuple.Fill()

        #jets
        selJets=[]
        jetSums=[TLorentzVector(0,0,0,0)]*5
        jetFlux=TLorentzVector(0,0,0,0)
        ht=0
        for j in xrange(0,tree.jn) :
            jet=JetCand(tree.jn_px[j],tree.jn_py[j],tree.jn_pz[j],tree.jn_en[j],tree.jn_area[j],tree.jn_torawsf[j])

            #cross clean with loose isolated leptons
            overlapFound=False
            for l in leptonCands:
                if not l.passLoose or not l.passLooseIso : continue
                dR=jet.p4.DeltaR(l.p4)
                if dR>0.4 : continue
                overlapFound=True
                break
            if overlapFound: continue

            #very loose kinematics cuts
            if math.fabs(jet.p4.Eta())>4.7 or jet.p4.Pt()<10 : continue

            #save it
            jet.genMatch(tree.jn_genpx[j],tree.jn_py[j],tree.jn_pz[j],tree.jn_en[j],tree.jn_genid[j],tree.jn_genflav[j])
            jet.updateJEC(jecCorrector,jecUncertainty,tree.rho,tree.nvtx)
            selJets.append(jet)

            #account for all the corrections you have applied
            jetSums[0]=jetSums[0] + jet.getCorrectedJet()          - jet.getCorrectedJet('raw')
            jetSums[1]=jetSums[1] + jet.getCorrectedJet('jesup')   - jet.getCorrectedJet()
            jetSums[2]=jetSums[2] + jet.getCorrectedJet('jesdown') - jet.getCorrectedJet()
            jetSums[3]=jetSums[3] + jet.getCorrectedJet('jerup')   - jet.getCorrectedJet()
            jetSums[4]=jetSums[4] + jet.getCorrectedJet('jerdown') - jet.getCorrectedJet()
            jetFlux=jetFlux+jet.p4
            ht=ht+jet.p4.Pt()

        # met
        metCand=METCand(tree.met_pt[0]*math.cos(tree.met_phi[0]),tree.met_pt[0]*math.sin(tree.met_phi[0]),0,tree.met_pt[0])
        metCand.genMatch(genNeutP4.Px(),genNeutP4.Py(),genNeutP4.Pz(),genNeutP4.E())
        metCand.addSumEts(tree.met_sumet[0], tree.met_chsumet[0])
        metCand.addJetCorrections(jetSums)
        metCand.addLeptonCorrections(lepSums)
        unclFlux=-(metCand.p4+lepFlux+jetFlux)
        unclSums=[TLorentzVector(0,0,0,0),unclFlux*0.10,unclFlux*(-0.10)]
        metCand.addUnclusteredCorrections(unclSums)

        #build the candidate
        vCand=buildVcand(eFire,mFire,emFire,leptonCands,metCand)
        if vCand is None : continue

        #prepare to save
        weight=1.0
        if puWeightsGr is not None:
            weight=puWeightsGr.Eval(tree.ngenITpu)

        #show isolations
        for ileg in [0,1]:
            hname='leg'+str(ileg+1)+'iso'
            lid=''
            if abs(vCand.m_legs[ileg].id)==11 :   lid='e'
            elif abs(vCand.m_legs[ileg].id)==13 : lid='mu'
            else : continue
            monitor.fill(hname,[lid],vCand.m_legs[ileg].relIso,weight)

        tags=[vCand.tag]
        monitor.fill('nvtxraw',tags, tree.nvtx,               1.0)
        monitor.fill('nvtx',   tags, tree.nvtx,               weight)
        monitor.fill('vmass',  tags, vCand.p4.M(),            weight)
        monitor.fill('vpt',    tags, vCand.p4.Pt(),           weight)
        monitor.fill('leg1pt', tags, vCand.m_legs[0].p4.Pt(), weight)
        monitor.fill('leg2pt', tags, vCand.m_legs[1].p4.Pt(), weight)

        for var in ['','lesup','lesdown','jesup','jesdown','jerup','jerdown','umetup','umetdown']:
            mtVar=vCand.computeMt(var)
            monitor.fill('vmt', [vCand.tag+var], mtVar, weight)


        if saveSummary :
            values=[
                vCand.id, weight, tree.nvtx, len(selJets),
                vCand.p4.M(), vCand.mt, vCand.p4.Pt(), genBosonP4.M(), genBosonP4.Pt(),
                vCand.m_legs[0].p4.Pt(),vCand.m_legs[0].p4.Eta(),vCand.m_legs[0].p4.Phi(), vCand.m_legs[0].genP4.Pt(), vCand.m_legs[0].relIso,
                vCand.m_legs[1].p4.Pt(),vCand.m_legs[1].p4.Eta(),vCand.m_legs[1].p4.Phi(), vCand.m_legs[1].genP4.Pt(), vCand.m_legs[1].relIso,
                metCand.sumet, ht,
                metCand.p4Vars['lesup'].Pt(),metCand.p4Vars['lesdown'].Pt(),metCand.p4Vars['jesup'].Pt(),metCand.p4Vars['jesdown'].Pt(),metCand.p4Vars['jerup'].Pt(),metCand.p4Vars['jerdown'].Pt(),metCand.p4Vars['umetup'].Pt(),metCand.p4Vars['umetdown'].Pt()
                ]
            summaryTuple.Fill(array.array("f",values))

    file.Close()
    monitor.close()