Example #1
0
def loadDDG4():
    import ROOT
    from ROOT import gSystem

    # Try to load libglapi to avoid issues with TLS Static
    # Turn off all errors from ROOT about the library missing
    if ('libglapi' not in gSystem.GetLibraries()):
        orgLevel = ROOT.gErrorIgnoreLevel
        ROOT.gErrorIgnoreLevel = 6000
        gSystem.Load("libglapi")
        ROOT.gErrorIgnoreLevel = orgLevel

    import platform
    import os
    if platform.system() == "Darwin":
        gSystem.SetDynamicPath(os.environ['DD4HEP_LIBRARY_PATH'])
        os.environ['DYLD_LIBRARY_PATH'] = os.pathsep.join([
            os.environ['DD4HEP_LIBRARY_PATH'],
            os.environ.get('DYLD_LIBRARY_PATH', '')
        ]).strip(os.pathsep)

    result = gSystem.Load("libDDG4Plugins")
    if result < 0:
        raise Exception(
            'DDG4.py: Failed to load the DDG4 library libDDG4Plugins: ' +
            gSystem.GetErrorStr())
    from ROOT import dd4hep as module
    return module
Example #2
0
    def __init__(self,
                 globalTag=None,
                 jetType="AK4PFchs",
                 jmr_vals=[1.09, 1.14, 1.04],
                 year=2017,
                 systematics=True):

        #--------------------------------------------------------------------------------------------
        # 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
        #--------------------------------------------------------------------------------------------

        # GLOBAL TAG
        if globalTag == None:
            if year == 2016:
                globalTag = "Summer16_25nsV1_MC"  #Fall17_25nsV1_MC
            elif year == 2017:
                globalTag = "Fall17_V3_MC"
            elif year == 2018:
                globalTag = "Autumn18_V1_MC"

        # READ JER and JER scale factors and uncertainties
        # from https://github.com/cms-jet/JRDatabase/tree/master/textFiles/ )
        from JetMETCorrectionTool import ensureJMEFiles
        path_JER = ensureJMEFiles(globalTag, JER=True)
        filename = ensureFile(path_JER,
                              "%s_PtResolution_%s.txt" % (globalTag, jetType))
        filenameUnc = ensureFile(path_JER,
                                 "%s_SF_%s.txt" % (globalTag, jetType))

        # LOAD LIBRARIES for accessing JER 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)

        # INITIALIZE JER scale factors and uncertainties (cf. PhysicsTools/PatUtils/interface/SmearedJetProducerT.h )
        print("Loading JER from file '%s'..." % filename)
        jer = PyJetResolutionWrapper(filename)
        print("Loading JER SFs and uncertainties from file '%s'..." %
              filenameUnc)
        jerSF_and_Uncertainty = PyJetResolutionScaleFactorWrapper(filenameUnc)

        self.path_JER = path_JER
        self.filename = filename
        self.filenameUnc = filenameUnc
        self.params_sf_and_uncertainty = PyJetParametersWrapper()
        self.params_resolution = PyJetParametersWrapper()
        self.jer = jer
        self.jerSF_and_Uncertainty = jerSF_and_Uncertainty
        self.jmr_vals = jmr_vals
        self.enums_shift = [0, 2, 1] if systematics else [0]  # nom, up, down
        self.random = TRandom3(12345)  # (needed for jet pT smearing)
Example #3
0
def createSampleLists(analysis_dir='samples/',
                      channel='VV',
                      weight='',
                      signalSample='',
                      vJetsKFac=1.,
                      reweightVJets=False,
                      reweightTop=False):

    # settings and code to reweight V+jets samples (EW and QCD NLO corrections)
    # the following two k-factors are from samples_13TeV_RunIISpring16MiniAODv2.py
    wJetsKFac = 1.21
    dyJetsKFac = 1.23
    wJetsQCDCorrections = {}
    dyJetsQCDCorrections = {}
    # taken from http://cms.cern.ch/iCMS/jsp/db_notes/noteInfo.jsp?cmsnoteid=CMS%20AN-2015/186 (Table 4)
    wJetsQCDCorrections["WJetsToLNu_HT100to200"] = 1.459 / wJetsKFac
    wJetsQCDCorrections["WJetsToLNu_HT200to400"] = 1.434 / wJetsKFac
    wJetsQCDCorrections["WJetsToLNu_HT400to600"] = 1.532 / wJetsKFac
    wJetsQCDCorrections["WJetsToLNu_HT600to800"] = 1.004 / wJetsKFac
    wJetsQCDCorrections["WJetsToLNu_HT800to1200"] = 1.004 / wJetsKFac
    wJetsQCDCorrections["WJetsToLNu_HT1200to2500"] = 1.004 / wJetsKFac
    wJetsQCDCorrections["WJetsToLNu_HT2500toInf"] = 1.004 / wJetsKFac
    dyJetsQCDCorrections["DYJetsToLL_M50_HT100to200"] = 1.588 / dyJetsKFac
    dyJetsQCDCorrections["DYJetsToLL_M50_HT200to400"] = 1.438 / dyJetsKFac
    dyJetsQCDCorrections["DYJetsToLL_M50_HT400to600"] = 1.494 / dyJetsKFac
    dyJetsQCDCorrections["DYJetsToLL_M50_HT600toInf"] = 1.139 / dyJetsKFac

    # explicit list of samples:
    wjetsSampleNames = [
        "WJetsToLNu_HT1200to2500", "WJetsToLNu_HT2500toInf",
        "WJetsToLNu_HT400to600", "WJetsToLNu_HT600to800",
        "WJetsToLNu_HT800to1200", 'WJetsToLNu_HT100to200',
        'WJetsToLNu_HT200to400'
    ]
    dyjetsSampleNames = [
        'DYJetsToLL_M50_HT100to200', 'DYJetsToLL_M50_HT200to400',
        'DYJetsToLL_M50_HT400to600', 'DYJetsToLL_M50_HT600toInf'
    ]
    ttjetsSampleNames = ["TT_pow_ext3"]
    qcdSampleNames = [
        "QCD_HT1000to1500", "QCD_HT1500to2000", "QCD_HT2000toInf",
        "QCD_HT500to700", "QCD_HT700to1000"
    ]
    vvSampleNames = ['WWTo1L1Nu2Q', 'WZTo1L1Nu2Q']
    singleTopSampleNames = [
        'TToLeptons_tch_powheg', 'TBarToLeptons_tch_powheg', 'TToLeptons_sch',
        'TBar_tWch', 'T_tWch'
    ]
    jj_SampleNames = qcdSampleNames
    lnujj_SampleNames = ttjetsSampleNames + wjetsSampleNames + vvSampleNames + qcdSampleNames + dyjetsSampleNames + singleTopSampleNames
    # cuts to split ttbar sample according to W decay
    ttjetsWCut = '(lnujj_l2_mergedVTruth==1&&lnujj_l2_nearestBDRTruth>0.8)'
    ttjetsNonWCut = '(!(lnujj_l2_mergedVTruth==1&&lnujj_l2_nearestBDRTruth>0.8))'
    # add ttbar pT reweighting
    if reweightTop:
        ttjetsWCut += '*truth_genTop_weight'
        ttjetsNonWCut += '*truth_genTop_weight'

    tree_prod_name = ''

    if (channel == "WV"):
        channelSampleNames = lnujj_SampleNames
    else:
        channelSampleNames = jj_SampleNames
    samples_essential = []

    if "/sVJetsReweighting_cc.so" not in gSystem.GetLibraries():
        ROOT.gROOT.ProcessLine(
            ".L %s/src/CMGTools/VVResonances/python/plotting/VJetsReweighting.cc+"
            % os.environ['CMSSW_BASE'])
    from ROOT import getDYWeight, getWWeight

    # add QCD, DY+jets, W+jets, DiBosons and SingleTop samples, but not those with _ext, since they are merged with the others
    for sample in QCDHT + DYJetsM50HT + WJetsToLNuHT + DiBosons + SingleTop:
        vJetsWeight = str(vJetsKFac)
        if sample.name in channelSampleNames:
            if (sample in DYJetsM50HT) and reweightVJets:
                vJetsWeight = 'getDYWeight(truth_genBoson_pt) * {}'.format(
                    dyJetsQCDCorrections[sample.name])
            elif (sample in WJetsToLNuHT) and reweightVJets:
                vJetsWeight = 'getWWeight(truth_genBoson_pt) * {}'.format(
                    wJetsQCDCorrections[sample.name])
            samples_essential.append(
                SampleCfg(name=sample.name,
                          dir_name=sample.name,
                          ana_dir=analysis_dir,
                          tree_prod_name=tree_prod_name,
                          xsec=sample.xSection,
                          sumweights=sample.nGenEvents,
                          weight_expr=('*'.join([weight, vJetsWeight]))))

    # TTJets sample
    for sample in [TT_pow]:
        if sample.name in channelSampleNames:
            # print "Adding", sample.name, sample.xSection, sample.nGenEvents, weight
            samples_essential.append(
                SampleCfg(name=sample.name + '_W',
                          dir_name=sample.name,
                          ana_dir=analysis_dir,
                          tree_prod_name=tree_prod_name,
                          xsec=sample.xSection,
                          sumweights=sample.nGenEvents,
                          weight_expr=('*'.join([weight, ttjetsWCut]))))
            samples_essential.append(
                SampleCfg(name=sample.name + '_nonW',
                          dir_name=sample.name,
                          ana_dir=analysis_dir,
                          tree_prod_name=tree_prod_name,
                          xsec=sample.xSection,
                          sumweights=sample.nGenEvents,
                          weight_expr=('*'.join([weight, ttjetsNonWCut]))))

    # signal sample (set signal xsec to 5 pb)
    samples_signal = []
    if (signalSample):
        for sample in signalSamples:
            if sample.name == signalSample:
                samples_signal.append(
                    SampleCfg(name=sample.name,
                              dir_name=sample.name,
                              ana_dir=analysis_dir,
                              tree_prod_name=tree_prod_name,
                              xsec=5.,
                              sumweights=sample.nGenEvents,
                              weight_expr=('*'.join([weight])),
                              is_signal=True))

    samples_data = []
    if channel == 'WV':
        samples_data = [
            SampleCfg(name='data_SingleMuon',
                      dir_name='SingleMuon_Run2016B_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_SingleMuon',
                      dir_name='SingleMuon_Run2016C_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_SingleMuon',
                      dir_name='SingleMuon_Run2016D_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_SingleElectron',
                      dir_name='SingleElectron_Run2016B_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_SingleElectron',
                      dir_name='SingleElectron_Run2016C_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_SingleElectron',
                      dir_name='SingleElectron_Run2016D_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_MET',
                      dir_name='MET_Run2016B_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_MET',
                      dir_name='MET_Run2016C_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_MET',
                      dir_name='MET_Run2016D_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
        ]
    else:
        samples_data = [
            SampleCfg(name='data_JetHT',
                      dir_name='JetHT_Run2016B_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_JetHT',
                      dir_name='JetHT_Run2016C_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
            SampleCfg(name='data_JetHT',
                      dir_name='JetHT_Run2016D_PromptReco_v2',
                      ana_dir=analysis_dir,
                      tree_prod_name=tree_prod_name,
                      is_data=True),
        ]

    # samples_WH = []
    # mssm_names = ['HiggsSUSYBB80', 'HiggsSUSYBB90', 'HiggsSUSYBB100', 'HiggsSUSYBB110', 'HiggsSUSYBB120', 'HiggsSUSYBB130', 'HiggsSUSYBB140', 'HiggsSUSYBB160', 'HiggsSUSYBB180', 'HiggsSUSYBB200', 'HiggsSUSYBB250', 'HiggsSUSYBB300', 'HiggsSUSYBB350', 'HiggsSUSYBB400', 'HiggsSUSYBB450', 'HiggsSUSYBB500', 'HiggsSUSYBB600', 'HiggsSUSYBB700', 'HiggsSUSYBB900', 'HiggsSUSYBB1000', 'HiggsSUSYBB1200', 'HiggsSUSYBB1500', 'HiggsSUSYBB1600', 'HiggsSUSYBB1800', 'HiggsSUSYBB2000', 'HiggsSUSYBB2300', 'HiggsSUSYBB2600', 'HiggsSUSYBB2900', 'HiggsSUSYBB3200', 'HiggsSUSYGG80', 'HiggsSUSYGG90',
    #               'HiggsSUSYGG100', 'HiggsSUSYGG110', 'HiggsSUSYGG120', 'HiggsSUSYGG130', 'HiggsSUSYGG140', 'HiggsSUSYGG160', 'HiggsSUSYGG180', 'HiggsSUSYGG200', 'HiggsSUSYGG250', 'HiggsSUSYGG300', 'HiggsSUSYGG400', 'HiggsSUSYGG450', 'HiggsSUSYGG500', 'HiggsSUSYGG600', 'HiggsSUSYGG700', 'HiggsSUSYGG800', 'HiggsSUSYGG900', 'HiggsSUSYGG1000', 'HiggsSUSYGG1200', 'HiggsSUSYGG1400', 'HiggsSUSYGG1500', 'HiggsSUSYGG1600', 'HiggsSUSYGG1800', 'HiggsSUSYGG2000', 'HiggsSUSYGG2300', 'HiggsSUSYGG2600', 'HiggsSUSYGG2900', 'HiggsSUSYGG3200']  # HiggsSUSYBB800, HiggsSUSYBB1400, HiggsSUSYGG350
    # for name in mssm_names:
    #     samples_WH.append(SampleCfg(name=name.replace('HiggsSUSYBB', 'bbH').replace('HiggsSUSYGG', 'ggH'), dir_name=name,
    #                                   ana_dir=analysis_dir, tree_prod_name=tree_prod_name, xsec=1., sumweights=1., is_signal=True),)

    samples_mc = samples_essential + samples_signal
    samples = samples_essential + samples_data + samples_signal
    all_samples = samples_mc + samples_data

    # -> Can add cross sections for samples either explicitly, or from file, or from cfg
    #    (currently taken from htt_common)

    weighted_list = []

    for sample in samples_mc:
        if sample.name not in weighted_list:
            setSumWeights(sample)

    # sampleDict = {s.name: s for s in all_samples}
    sampleDict = {}
    for s in all_samples:
        sampleDict[s.name] = s

    return samples_mc, samples_data, samples, all_samples, sampleDict
Example #4
0
import os
import ROOT
from ROOT import gSystem, gROOT

from CMGTools.H2TauTau.proto.plotter.PlotConfigs import SampleCfg
from CMGTools.H2TauTau.proto.plotter.HistCreator import setSumWeights
from CMGTools.H2TauTau.proto.samples.spring16.sms_xsec import get_xsec

from CMGTools.H2TauTau.proto.samples.spring16.htt_common import TT_pow_ext, DYJetsToLL_M50_LO, DYNJets, WJetsToLNu,  WNJets, WWTo2L2Nu, T_tWch, TBar_tWch, VVTo2L2Nu, ZZTo4L, WZTo1L3Nu, WWTo1L1Nu2Q, ZZTo2L2Q, WZTo2L2Q, WZTo1L1Nu2Q, TBarToLeptons_tch_powheg, TToLeptons_tch_powheg, mssm_signals, dy_weight_dict, w_weight_dict

# WJetsToLNu_LO, TToLeptons_tch_amcatnlo, WZTo3LNu_amcatnlo, , WJetsToLNu_HT100to200, WJetsToLNu_HT200to400, WJetsToLNu_HT400to600, WJetsToLNu_HT600toInf, QCD_Mu15, DYJetsToTauTau_M150_LO, DYJetsToLL_M10to50_ext1

if "/sDYReweighting_cc.so" not in gSystem.GetLibraries(): 
    gROOT.ProcessLine(".L %s/src/CMGTools/H2TauTau/python/proto/plotter/DYReweighting.cc+" % os.environ['CMSSW_BASE']);
    from ROOT import getDYWeight

splitDY = False
useDYWeight = False
# data2016G = True

if useDYWeight:
    dy_exps = []
    for njet in xrange(0, 5):
        weight = dy_weight_dict[(njet, 0)]
        dy_exps.append('(geninfo_nup == {njet})*{weight}'.format(njet=njet, weight=weight))
        # dy_exps.append('(geninfo_nup == {njet} && (geninfo_invmass<150. || !(l2_gen_match==5 || l1_gen_lepfromtau)))*{weight}'.format(njet=njet, weight=weight))
        # weight = dy_weight_dict[(njet, 150)]
        # dy_exps.append('(geninfo_nup == {njet} && (geninfo_invmass>=150. && (l2_gen_match==5 || l1_gen_lepfromtau)))*{weight}'.format(njet=njet, weight=weight))

    dy_exp = '*({})'.format(' + '.join(dy_exps))
                for key, item in vals:
                    if key.startswith(name + '__'):
                        print item, key


if __name__ == '__main__':
    mode = 'susy'  # 'control' 'mssm' 'mva_train' 'susy' 'sm'

    int_lumi = lumi
    analysis_dir = '/data1/steggema/Gael3/MC/'
    verbose = True
    total_weight = 'weight'

    import os
    from ROOT import gSystem, gROOT
    if "/sHTTEfficiencies_cc.so" not in gSystem.GetLibraries():
        gROOT.ProcessLine(
            ".L %s/src/CMGTools/H2TauTau/python/proto/plotter/HTTEfficiencies.cc+"
            % os.environ['CMSSW_BASE'])
        from ROOT import getTauWeight

    total_weight = 'weight*getTauWeight(l1_gen_match, l1_pt, l1_eta, l1_decayMode)*getTauWeight(l2_gen_match, l2_pt, l2_eta, l2_decayMode)'

    optimisation = True
    make_plots = True

    # Check whether friend trees need to be added
    friend_func = None
    if mode == 'mva':
        # friend_func = lambda f: f.replace('MC', 'MCMVAmt200')
        friend_func = lambda f: f.replace('MC', 'MCMVAmt200_7Vars')
Example #6
0
def MultiDraw(self, Formulae, CommonWeight="1"):
    """Draws many histograms in one loop over a tree.

        Instead of:
        MyTree.Draw( "nlcts >> a(100, -1, 1)", "weightA" )
        MyTree.Draw( "nlcts >> b(100, -1, 1)", "weightB" )

        Do:    
        MyTree.MultiDraw( ( "nlcts >> a(100, -1, 1)", "weightA" ),
                          ( "nlcts >> b(100, -1, 1)", "weightB" ) )

        This is significantly faster when there are many histograms to be drawn.
        The first parameter, CommonWeight, decides a weight given to all
        histograms.

        An arbitrary number of additional histograms may be specified. They can 
        either be specified with just a string containing the formula to be 
        drawn, the histogram name and bin configuration. 

        Alternatively it can be a tuple, with  said string, and an additional
        string specifying the weight to be applied to that histogram only.
    """

    if type(CommonWeight) == tuple:
        Formulae = (CommonWeight, ) + Formulae
        CommonWeight = "1"

    results, formulae, weights = [], [], []

    lastFormula, lastWeight = None, None

    # A weight common to everything being drawn
    CommonWeightFormula = TTreeFormula("CommonWeight", CommonWeight, self)
    CommonWeightFormula.SetQuickLoad(True)
    if not CommonWeightFormula.GetTree():
        raise RuntimeError("TTreeFormula didn't compile: " + CommonWeight)

    hists = {}

    for i, origFormula in enumerate(Formulae):
        print "Have an origFormula", origFormula

        # Expand out origFormula and weight, otherwise just use weight of 1.
        if type(origFormula) == tuple:
            origFormula, weight = origFormula
        else:
            origFormula, weight = origFormula, "1"

        # print origFormula, weight

        # Pluck out histogram name and arguments
        match = re.match(r"^(.*?)\s*>>\s*(.*?)\s*\(\s*(.*?)\s*\)$", origFormula)
        if match:

            formula, name, arguments = match.groups()
            arguments = re.split(",\s*", arguments)

            bins, minX, maxX = arguments
            bins, minX, maxX = int(bins), float(minX), float(maxX)

            # Create histogram with name and arguments
            hist = TH1D(name, name, bins, minX, maxX)
            hist.Sumw2()
        else:
            # without arguments
            match = re.match(r"^(.*?)\s*>>\s*(.*?)\s*$", origFormula)
            if not match:
                raise RuntimeError("MultiDraw: Couldn't parse formula: '%s'" % origFormula)

            formula, name = match.groups()
            # print formula, name

            if name.startswith("+") and name[1:] in hists:
                # Drawing additionally into a histogram
                hist = hists[name[1:]]
            else:
                # name = name[1:] # JAN: ???
                hist = gDirectory.Get(name)
                if not hist:
                    raise RuntimeError("MultiDraw: Couldn't find histogram to fill '%s' in current directory." % name)

        if name not in hists:
            hists[name] = hist

        results.append(hist)

        # The following two 'if' clauses check that the next formula is different
        # to the previous one. If it is not, we add an ordinary TObject.
        # Then, the dynamic cast in MultiDraw.cxx fails, giving 'NULL', and
        # The previous value is used. This saves the recomputing of identical values

        if formula != lastFormula:
            f = TTreeFormula("formula%i" % i, formula, self)
            if not f.GetTree():
                raise RuntimeError("TTreeFormula didn't compile: " + formula)
            f.SetQuickLoad(True)
            formulae.append(f)
        else:
            formulae.append(TObject())

        if weight != lastWeight:
            f = TTreeFormula("weight%i" % i, weight, self)
            if not f.GetTree():
                raise RuntimeError("TTreeFormula didn't compile: " + formula)
            f.SetQuickLoad(True)
            weights.append(f)
        else:
            weights.append(TObject())

        lastFormula, lastWeight = formula, weight

    # Only compile MultiDraw once
    try:
        from ROOT import MultiDraw as _MultiDraw
    except ImportError:
        # gROOT.ProcessLine(".L %sMultiDraw.cxx+O" % "./")
        if "/sMultiDraw_cc.so" not in gSystem.GetLibraries(): 
            gROOT.ProcessLine(".L %s/../SFrameAnalysis_emu/datacard/MultiDraw.cc+" % os.environ['CMSSW_BASE']);
        from ROOT import MultiDraw as _MultiDraw

    from time import time
    start = time()

    # Ensure that formulae are told when tree changes
    fManager = TTreeFormulaManager()
    for formula in formulae + weights + [CommonWeightFormula, ]:
        if type(formula) == TTreeFormula:
            fManager.Add(formula)

    fManager.Sync()
    self.SetNotify(fManager)

    # Draw everything!
    _MultiDraw(self, CommonWeightFormula,
               MakeTObjArray(formulae),
               MakeTObjArray(weights),
               MakeTObjArray(results),
               len(Formulae))

    print "Took %.2fs" % (time() - start), " "*20

    return results
Example #7
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