diff --git a/.gitmodules b/.gitmodules index 9ef7cf8c..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "PileupWeights"] - path = PileupWeights - url = ssh://git@gitlab.cern.ch:7999/ncsmith/PileupWeights.git diff --git a/ConfigureJobs.py b/ConfigureJobs.py new file mode 100644 index 00000000..faf38728 --- /dev/null +++ b/ConfigureJobs.py @@ -0,0 +1,286 @@ +import datetime +import UserInput +import fnmatch +import glob +import os +import json +import array +import string +import configparser + +def get2DBinning(xvar="mjj", yvar="etajj", analysis='WZ'): + #return (array.array('d', [500, 1000,1500, 2000, 2500]), + # [0, 150, 300, 450] # for MT(WZ) +# return (array.array('d', [500, 1000, 1350, 1750, 2000, 2500]), + xbinning = [] + ybinning = [] + if xvar == "mjj": + xbinning = array.array('d', [500, 1000,1500, 2000, 2500]) + #xbinning = array.array('d', [500, 1000, 1350, 1750, 2500]) + + if yvar == 'etajj': + ybinning = [2.5, 4, 5, 20] + #if yvar == 'etajj': + # ybinning = [2.5, 4, 5.5, 20] + elif yvar == 'dRjj': + ybinning = [0, 5, 6, 20] + return (xbinning, ybinning) + +def getChannels(analysis='ZZ'): + if analysis == 'ZZ': + return ["eeee", "eemm", "mmee", "mmmm"] +def getManagerPath(): + config = configparser.ConfigParser() + config.read_file(open("Templates/config.%s" % os.environ["USER"])) + if "dataset_manager_path" not in config['Setup']: + raise ValueError("dataset_manager_path not specified in config file Template/config.%s" + % os.environ["USER"]) + return config['Setup']['dataset_manager_path'] + "/" +def getCombinePath(): + config = configparser.ConfigParser() + config.read_file(open("Templates/config.%s" % os.environ["USER"])) + if "combine_path" not in config['Setup']: + raise ValueError("dataset_manager_path not specified in config file Template/config.%s" + % os.environ["USER"]) + return config['Setup']['combine_path'] + "/" +def getListOfEWKFilenames(): + return [ + #"wz3lnu-amcnlo",#old 2018 ntuples + "wz3lnu-powheg",#New 2018 ntuples + # Use jet binned WZ samples for subtraction by default + #"wz3lnu-mgmlm-0j", + #"wz3lnu-mgmlm-1j", + #"wz3lnu-mgmlm-2j", + #"wz3lnu-mgmlm-3j", + #"wlljj-ewk", + "zz4l-powheg", + #"zz4ljj-ewk", + #"zz2l2vjj-ewk", + #"tzq", + #"ttz", + #"ttw", + #"zzz", + #"wwz", + #"www", + #"ww", + #"zg", + "ggZZ4e", + "ggZZ4m", + "ggZZ4t", + "ggZZ2e2mu", + "ggZZ2e2tau", + "ggZZ2mu2tau", + ] + +def getListOfEWK(): + return [ + "zz4l-powheg", + "ggZZ4e", + "ggZZ4m", + "ggZZ4t", + "ggZZ2e2mu", + "ggZZ2e2tau", + "ggZZ2mu2tau", + ] +def getListOfDYFilenames(): + return[ + "DYJetsToLL_M10to50", + "DYJetsToLLM-50", + ] +def getListOfNonpromptFilenames(): + return ["tt-lep", + "tt-jets", + #"st-schan", + #"st-tchan-t", + #"st-tchan-tbar", + #"st-tw", + #"st-tbarw", + ##"DYm50", + #"DYm50-1j", + #"DYm50-2j", + #"DYm50-3j", + #"DYm50-4j", + ] +def getListOfHZZFilenames(): + return ["ggHZZ", + "vbfHZZ", + "ttH_HToZZ_4L", + "WminusHToZZ", + "WplusHToZZ", + "ZHToZZ_4L" + ] +def getListOfggZZFilenames(): + return ["ggZZ4e", + "ggZZ4m", + "ggZZ4t", + "ggZZ2e2mu", + "ggZZ2e2tau", + "ggZZ2mu2tau" + ] +def getJobName(sample_name, analysis, selection, version): + date = '{:%Y-%m-%d}'.format(datetime.date.today()) + selection = selection.replace(";",",") + selections = selection.split(",") + selection_name = "To".join([selections[0],selections[-1]]) \ + if len(selections) > 1 else selections[0] + return '-'.join([date, sample_name, analysis, selection_name, + ("v%s" % version) if version.isdigit() else version]) +def getNumberAndSizeOfLocalFiles(path_to_files): + file_list = glob.glob(path_to_files) + return (len(file_list), sum([os.path.getsize(f)/1000000 for f in file_list])) +def getNumberAndSizeOfHDFSFiles(file_path): + file_info = [] + for line in out.splitlines(): + split = line.split() + if len(split) != 9: + continue + file_info.append(float(split[4].rstrip("mkg"))) + return (0,0) if len(file_info) == 0 else (len(file_info), sum(file_info)) +def getListOfHDFSFiles(file_path): + try: + out = subprocess.check_output(["hdfs", "dfs", "-ls", file_path.replace("/hdfs", "")]) + except subprocess.CalledProcessError as error: + logging.warning(error) + return [] + files = [] + for line in out.splitlines(): + split = line.split(" ", 1) + if len(split) != 2: + continue + elif "root" in split[1]: + files.append("/"+split[1]) + return files +def getListOfFiles(filelist, selection, manager_path=""): + if manager_path is "": + manager_path = getManagerPath() + data_path = "%s/ZZ4lRun2DatasetManager/FileInfo" % manager_path + data_info = UserInput.readAllJson("/".join([data_path, "%s.json" % "data/*"])) + mc_info = UserInput.readAllJson("/".join([data_path, "%s.json" % "montecarlo/*"])) + valid_names = data_info.keys() + mc_info.keys() + names = [] + for name in filelist: + if "ZZ4l2016" in name: + dataset_file = manager_path + \ + "ZZ4lRun2DatasetManager/FileInfo/ZZ4l2016/%s.json" % selection + allnames = json.load(open(dataset_file)).keys() + print allnames + if "nodata" in name: + nodata = [x for x in allnames if "data" not in x] + names += nodata + elif "data" in name: + names += [x for x in allnames if "data" in x] + else: + names += allnames + elif "ZZ4l2017" in name: + dataset_file = manager_path + \ + "ZZ4lRun2DatasetManager/FileInfo/ZZ4l2017/%s.json" % selection + allnames = json.load(open(dataset_file)).keys() + print allnames + if "nodata" in name: + nodata = [x for x in allnames if "data" not in x] + names += nodata + elif "data" in name: + names += [x for x in allnames if "data" in x] + else: + names += allnames + elif "ZZ4l2018" in name: + dataset_file = manager_path + \ + "ZZ4lRun2DatasetManager/FileInfo/ZZ4l2018/%s.json" % selection + allnames = json.load(open(dataset_file)).keys() + print allnames + if "nodata" in name: + nodata = [x for x in allnames if "data" not in x] + names += nodata + elif "data" in name: + names += [x for x in allnames if "data" in x] + else: + names += allnames + elif "*" in name: + names += fnmatch.filter(valid_names, name) + else: + if name.split("__")[0] not in valid_names: + print "%s is not a valid name" % name + continue + names += [name] + return [str(i) for i in names] +def fillTemplatedFile(template_file_name, out_file_name, template_dict): + with open(template_file_name, "r") as templateFile: + source = string.Template(templateFile.read()) + result = source.substitute(template_dict) + with open(out_file_name, "w") as outFile: + outFile.write(result) +def getListOfFilesWithXSec(filelist, manager_path=""): + if manager_path is "": + manager_path = getManagerPath() + data_path = "%s/ZZ4lRun2DatasetManager/FileInfo" % manager_path + files = getListOfFiles(filelist, "ntuples", manager_path) + #files = getListOfFiles(filelist, "2018Data", manager_path) + mc_info = UserInput.readAllJson("/".join([data_path, "%s.json" % "montecarlo/*"])) + info = {} + for file_name in files: + if "data" in file_name: + info.update({file_name : 1}) + else: + file_info = mc_info[file_name.split("__")[0]] + kfac = file_info["kfactor"] if "kfactor" in file_info.keys() else 1 + info.update({file_name : file_info["cross_section"]*kfac}) + return info +def getPreviousStep(selection, analysis): + selection_map = {} + if analysis == "ZZ4l2016": + selection_map = { "ntuples" : "ntuples", + "preselection" : "ntuples", + "4lCRBase" : "ntuples" + } + elif analysis == "ZplusL2016": + selection_map = { "ntuples": "ntuples", + "ZplusLBase" : "ntuples" + } + elif analysis == "ZZ4l2017": + selection_map = { "ntuples" : "ntuples", + "preselection" : "ntuples", + "4lCRBase" : "ntuples" + } + elif analysis == "ZplusL2017": + selection_map = { "ntuples": "ntuples", + "ZplusLBase" : "ntuples" + } + elif analysis == "ZZ4l2018": + selection_map = { "ntuples" : "ntuples", + "preselection" : "ntuples", + "4lCRBase" : "ntuples" + } + elif analysis == "ZplusL2018": + selection_map = { "ntuples": "ntuples", + "ZplusLBase" : "ntuples" + } + selection = selection.replace(";",",") + first_selection = selection.split(",")[0].strip() + if first_selection not in selection_map.keys(): + if "preselection" in first_selection: + first_selection = "preselection" + else: + raise ValueError("Invalid selection '%s'. Valid selections are:" + "%s" % (first_selection, selection_map.keys())) + return selection_map[first_selection] +def getInputFilesPath(sample_name, selection, analysis, manager_path=""): + if manager_path is "": + manager_path = getManagerPath() + data_path = "%s/ZZ4lRun2DatasetManager/FileInfo" % manager_path + input_file_name = "/".join([data_path, analysis, "%s.json" % + selection]) + input_files = UserInput.readJson(input_file_name) + if sample_name not in input_files.keys(): + raise ValueError("Invalid input file %s. Input file must correspond" + " to a definition in %s" % (sample_name, input_file_name)) + filename = input_files[sample_name]['file_path'] + return filename +def getCutsJsonName(selection, analysis): + return "/".join(["Cuts", analysis, selection + ".json"]) +def getTriggerName(sample_name, analysis, selection): + trigger_names = ["MuonEG", "DoubleMuon", "DoubleEG", "SingleMuon", "SingleElectron"] + if "data" in sample_name and getPreviousStep(selection, analysis) == "ntuples": + for name in trigger_names: + if name in sample_name: + return "-t " + name + return "-t MonteCarlo" diff --git a/PileupWeights b/PileupWeights deleted file mode 160000 index 5edbb498..00000000 --- a/PileupWeights +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5edbb49861ac655e5b9401fa5856b3f751aecb36 diff --git a/PileupWeights16/PU_Central.root b/PileupWeights16/PU_Central.root new file mode 100644 index 00000000..eeaf6bcb Binary files /dev/null and b/PileupWeights16/PU_Central.root differ diff --git a/PileupWeights16/PU_minBiasDOWN.root b/PileupWeights16/PU_minBiasDOWN.root new file mode 100644 index 00000000..423d60b4 Binary files /dev/null and b/PileupWeights16/PU_minBiasDOWN.root differ diff --git a/PileupWeights16/PU_minBiasUP.root b/PileupWeights16/PU_minBiasUP.root new file mode 100644 index 00000000..c52879ca Binary files /dev/null and b/PileupWeights16/PU_minBiasUP.root differ diff --git a/PileupWeights17/PU_Central.root b/PileupWeights17/PU_Central.root new file mode 100644 index 00000000..68676f9b Binary files /dev/null and b/PileupWeights17/PU_Central.root differ diff --git a/PileupWeights17/PU_minBiasDOWN.root b/PileupWeights17/PU_minBiasDOWN.root new file mode 100644 index 00000000..63809570 Binary files /dev/null and b/PileupWeights17/PU_minBiasDOWN.root differ diff --git a/PileupWeights17/PU_minBiasUP.root b/PileupWeights17/PU_minBiasUP.root new file mode 100644 index 00000000..38c83663 Binary files /dev/null and b/PileupWeights17/PU_minBiasUP.root differ diff --git a/PileupWeights18/PU_Central.root b/PileupWeights18/PU_Central.root new file mode 100644 index 00000000..ffa45177 Binary files /dev/null and b/PileupWeights18/PU_Central.root differ diff --git a/PileupWeights18/PU_minBiasDOWN.root b/PileupWeights18/PU_minBiasDOWN.root new file mode 100644 index 00000000..ae55aaa4 Binary files /dev/null and b/PileupWeights18/PU_minBiasDOWN.root differ diff --git a/PileupWeights18/PU_minBiasUP.root b/PileupWeights18/PU_minBiasUP.root new file mode 100644 index 00000000..0cab0cfe Binary files /dev/null and b/PileupWeights18/PU_minBiasUP.root differ diff --git a/ScaleFactors/setupScaleFactors.py b/ScaleFactors/setupScaleFactors.py index 5cb58a5b..752d8518 100755 --- a/ScaleFactors/setupScaleFactors.py +++ b/ScaleFactors/setupScaleFactors.py @@ -9,6 +9,7 @@ import ROOT import argparse import os +import sys ROOT.gROOT.SetBatch(True) ROOT.PyConfig.IgnoreCommandLineOptions = True @@ -37,118 +38,153 @@ def invert2DHist(hist): return new_hist parser = argparse.ArgumentParser() -parser.add_argument("-t", "--tightfr_file", type=str, - default='data/fakeRate18Apr2017-3LooseLeptons-TightMuons.root') -parser.add_argument("-m", "--medfr_file", type=str, - default='data/fakeRate18Apr2017-3LooseLeptons-MediumMuons.root') -args = parser.parse_args() -output_file = 'data/scaleFactors.root' -fScales = ROOT.TFile(output_file, 'recreate') + +def getComLineArgs(): + parser.add_argument("--year", type=str,default="default", help="Year of Analysis") + parser.add_argument("-t", "--tightfr_file", type=str, + default="") + parser.add_argument("--output_file", "-o", type=str, + default="test.root", help="Output file name") + + return vars(parser.parse_args()) + +args = getComLineArgs() + +year = args["year"] +frfile = args["tightfr_file"] +fScales = ROOT.TFile(args['output_file'], 'recreate') + + # For nTruePU reweighting -pileupSF = ROOT.ScaleFactor("pileupSF", "Run2016B-H 36.8/fb Pileup profile over RunIISpring16 MC Scale Factor, x=NTruePU") -pileupFile = ROOT.TFile.Open('PileupWeights/PU_Central.root') -pileupFileUp = ROOT.TFile.Open('PileupWeights/PU_minBiasUP.root') -pileupFileDown = ROOT.TFile.Open('PileupWeights/PU_minBiasDOWN.root') +if year=="2016": + print "2016 PU reweighting" + pileupSF = ROOT.ScaleFactor("pileupSF", "Run2016B-H 35.9/fb Pileup profile over RunIISummer16 MC Scale Factor, x=NTruePU") + pileupFile = ROOT.TFile.Open('PileupWeights16/PU_Central.root') + pileupFileUp = ROOT.TFile.Open('PileupWeights16/PU_minBiasUP.root') + pileupFileDown = ROOT.TFile.Open('PileupWeights16/PU_minBiasDOWN.root') +elif year=="2017": + pileupSF = ROOT.ScaleFactor("pileupSF", "Run2017B-F 41.5/fb Pileup profile over RunIIFall17 MC Scale Factor, x=NTruePU") + pileupFile = ROOT.TFile.Open('PileupWeights17/PU_Central.root') + pileupFileUp = ROOT.TFile.Open('PileupWeights17/PU_minBiasUP.root') + pileupFileDown = ROOT.TFile.Open('PileupWeights17/PU_minBiasDOWN.root') +elif year=="2018": + pileupSF = ROOT.ScaleFactor("pileupSF", "Run2018A-D 59.95/fb Pileup profile over RunIIFall18 MC Scale Factor, x=NTruePU") + pileupFile = ROOT.TFile.Open('PileupWeights18/PU_Central.root') + pileupFileUp = ROOT.TFile.Open('PileupWeights18/PU_minBiasUP.root') + pileupFileDown = ROOT.TFile.Open('PileupWeights18/PU_minBiasDOWN.root') +else: + print "You forgot to specify the year for which you want scale factors" + sys.exit() pileupSF.Set1DHist(pileupFile.Get('pileup'), pileupFileUp.Get('pileup'), pileupFileDown.Get('pileup')) fScales.cd() pileupSF.Write() -electronTightIdSF = ROOT.ScaleFactor("electronTightIdSF", "Moriond '17 Electron Tight WP ID SF, x=Eta, y=Pt") -eidFile = ROOT.TFile.Open('data/moriond17ElectronTightSF.root') -electronTightIdSF.Set2DHist(float2double(eidFile.Get('EGamma_SF2D'))) -fScales.cd() -electronTightIdSF.Write() -electronGsfSF = ROOT.ScaleFactor("electronGsfSF", "Moriond '17 Electron GSF track reco SF, x=Eta, y=Pt") -eleGsfFile = ROOT.TFile.Open('data/moriond17ElectronRecoSF.root') -electronGsfSF.Set2DHist(float2double(eleGsfFile.Get('EGamma_SF2D'))) -fScales.cd() -electronGsfSF.Write() -muonIdSF = ROOT.ScaleFactor("muonTightIdSF", "Moriond '17 Muon Tight WP ID SF, x=abs(Eta), y=Pt, z=run number") -midFile1 = ROOT.TFile.Open('data/moriond17MuonID_BCDEF.root') -midFile2 = ROOT.TFile.Open('data/moriond17MuonID_GH.root') -muon_ptetaratio1 = midFile1.Get('MC_NUM_TightID_DEN_genTracks_PAR_pt_eta/abseta_pt_ratio') -muon_ptetaratio2 = midFile2.Get('MC_NUM_TightID_DEN_genTracks_PAR_pt_eta/abseta_pt_ratio') -muon_allratio = float2double(muon_ptetaratio1.Clone("muon_allratio")) -for xbin in range(muon_ptetaratio1.GetNbinsX()+2): - for ybin in range(muon_ptetaratio1.GetNbinsY()+2): - runBFmean, runBFerr = muon_ptetaratio1.GetBinContent(xbin, ybin), muon_ptetaratio1.GetBinError(xbin, ybin) - runGHmean, runGHerr = muon_ptetaratio2.GetBinContent(xbin, ybin), muon_ptetaratio2.GetBinError(xbin, ybin) - allmean = (20.5*runBFmean + 16.3*runGHmean) / 36.8 - allerr = (20.5*runBFerr + 16.3*runGHerr) / 36.8 - muon_allratio.SetBinContent(xbin, ybin, allmean) - muon_allratio.SetBinError(xbin, ybin, allerr) -muonIdSF.Set2DHist(muon_allratio) -fScales.cd() -muonIdSF.Write() -muonIsoSF = ROOT.ScaleFactor("muonIsoSF", "Moriond '17 Muon Tight Iso (0.15) WP ID SF, x=abs(Eta), y=Pt, z=run number") -misoFile1 = ROOT.TFile.Open('data/moriond17MuonIso_BCDEF.root') -misoFile2 = ROOT.TFile.Open('data/moriond17MuonIso_GH.root') -muIso_ptetaratio1 = misoFile1.Get('TightISO_TightID_pt_eta/abseta_pt_ratio') -muIso_ptetaratio2 = misoFile2.Get('TightISO_TightID_pt_eta/abseta_pt_ratio') -muIso_allratio = float2double(muon_ptetaratio1.Clone("muIso_allratio")) -for xbin in range(muIso_ptetaratio1.GetNbinsX()+2): - for ybin in range(muIso_ptetaratio1.GetNbinsY()+2): - runBFmean, runBFerr = muIso_ptetaratio1.GetBinContent(xbin, ybin), muIso_ptetaratio1.GetBinError(xbin, ybin) - runGHmean, runGHerr = muIso_ptetaratio2.GetBinContent(xbin, ybin), muIso_ptetaratio2.GetBinError(xbin, ybin) - allmean = (20.5*runBFmean + 16.3*runGHmean) / 36.8 - allerr = (20.5*runBFerr + 16.3*runGHerr) / 36.8 - muIso_allratio.SetBinContent(xbin, ybin, allmean) - muIso_allratio.SetBinError(xbin, ybin, allerr) -muonIsoSF.Set2DHist(muIso_allratio) -fScales.cd() -muonIsoSF.Write() - -# Used for tests on fake rate files from Jakob and Svenja -#efakeRateFile = ROOT.TFile.Open('/eos/user/k/kelong/WZAnalysisData/FakeRates/fromJakob/eFakeRates.root') -#jakob_etight = efakeRateFile.Get('eFakeRates') -#jakob_etight = invert2DHist(jakob_etight) -#mfakeRateFile = ROOT.TFile.Open('/eos/user/k/kelong/WZAnalysisData/FakeRates/fromJakob/muFakeRates.root') -#jakob_mtight = mfakeRateFile.Get('muFakeRates') -#jakob_mtight = invert2DHist(jakob_mtight) -# -#eCBTightFakeRate = ROOT.ScaleFactor("eCBTightFakeRate_Jakob", "Fake rate from dijet control, via Jakob") -#eCBTightFakeRate.Set2DHist(jakob_etight, 0, 0, ROOT.ScaleFactor.AsInHist) -#mCBTightFakeRate = ROOT.ScaleFactor("mCBTightFakeRate_Jakob", "Fake rate from dijet control, via Jakob") -#mCBTightFakeRate.Set2DHist(jakob_mtight, 0, 0, ROOT.ScaleFactor.AsInHist) -#fScales.cd() -#mCBTightFakeRate.Write() -#eCBTightFakeRate.Write() - -#fakeRateFile = ROOT.TFile.Open('/eos/user/k/kelong/WZAnalysisData/FakeRates/CutBasedFakeRate_fromSvenja_final.root') -#eCBMedFakeRate = ROOT.ScaleFactor("eCBMedFakeRate_Svenja", "Fake rate from dijet control, by Svenja") -#eCBMedFakeRate.Set2DHist(float2double(fakeRateFile.Get('e/medium/fakeratePtEta')), 0, 0, ROOT.ScaleFactor.AsInHist) -#eCBTightFakeRate = ROOT.ScaleFactor("eCBTightFakeRate_Svenja", "Fake rate from dijet control, by Svenja") -#eCBTightFakeRate.Set2DHist(float2double(fakeRateFile.Get('e/tight/fakeratePtEta')), 0, 0, ROOT.ScaleFactor.AsInHist) -#mCBMedFakeRate = ROOT.ScaleFactor("mCBMedFakeRate_Svenja", "Fake rate from dijet control, by Svenja") -#mCBMedFakeRate.Set2DHist(float2double(fakeRateFile.Get('m/medium/fakeratePtEta')), 0, 0, ROOT.ScaleFactor.AsInHist) -#mCBTightFakeRate = ROOT.ScaleFactor("mCBTightFakeRate_Svenja", "Fake rate from dijet control, by Svenja") -#mCBTightFakeRate.Set2DHist(float2double(fakeRateFile.Get('m/tight/fakeratePtEta')), 0, 0, ROOT.ScaleFactor.AsInHist) -#fScales.cd() -#mCBMedFakeRate.Write() -#mCBTightFakeRate.Write() -#eCBMedFakeRate.Write() -#eCBTightFakeRate.Write() - -if os.path.isfile(args.medfr_file): - print "INFO: Adding medium fake rates to %s" % output_file - fakeRateFile = ROOT.TFile.Open(args.medfr_file) - eCBMedFakeRateZjets = ROOT.ScaleFactor("eCBMedFakeRate", "Fake rate from Z+jet") - eCBMedFakeRateZjets.Set2DHist(fakeRateFile.Get('DataEWKCorrected/ratio2D_allE'), 0, 0, ROOT.ScaleFactor.AsInHist) - mCBMedFakeRateZjets = ROOT.ScaleFactor("mCBMedFakeRate", "Fake rate from Z+jet") - mCBMedFakeRateZjets.Set2DHist(fakeRateFile.Get('DataEWKCorrected/ratio2D_allMu'), 0, 0, ROOT.ScaleFactor.AsInHist) - fScales.cd() - mCBMedFakeRateZjets.Write() - eCBMedFakeRateZjets.Write() +if year=="2016": + print "Doing 2016 Lepton SF" + electronLowReco16SF = ROOT.ScaleFactor("electronLowReco16SF", "Run '16 Electron Low Reco SF, x=Eta, y=Pt") + eLowRecoFile = ROOT.TFile.Open('data/Ele_Reco_LowEt_2016.root') + electronLowReco16SF.Set2DHist(float2double(eLowRecoFile.Get('EGamma_SF2D'))) + fScales.cd() + electronLowReco16SF.Write() + + #Electron (Pt>20 Reco SF from POG https://twiki.cern.ch/twiki/bin/viewauth/CMS/Egamma2016DataRecommendations + electronReco16SF = ROOT.ScaleFactor("electronReco16SF", "Run '16 Electron Reco SF, x=Eta, y=Pt") + eRecoFile = ROOT.TFile.Open('data/Ele_Reco_2016.root') + electronReco16SF.Set2DHist(float2double(eRecoFile.Get('EGamma_SF2D'))) + fScales.cd() + electronReco16SF.Write() + + electronRun16SF = ROOT.ScaleFactor("electronRun16SF", "Run '16 Electron HZZ ID SF, x=Eta, y=Pt") + eidFile = ROOT.TFile.Open('data/ElectronSF_Legacy_2016_NoGap.root') + electronRun16SF.Set2DHist(float2double(eidFile.Get('EGamma_SF2D'))) + fScales.cd() + electronRun16SF.Write() + + electronRun16GapSF = ROOT.ScaleFactor("electronRun16GapSF", "Run '16 GapElectron HZZ ID SF, x=Eta, y=Pt") + eleGsfFile = ROOT.TFile.Open('data/ElectronSF_Legacy_2016_Gap.root') + electronRun16GapSF.Set2DHist(float2double(eleGsfFile.Get('EGamma_SF2D'))) + fScales.cd() + electronRun16GapSF.Write() + + muonRun16SF = ROOT.ScaleFactor("muonRun16SF", "Muon Run '16 Trk+ID+ISO SF, x=abs(Eta), y=Pt") + mid16File = ROOT.TFile.Open('data/MoriondSFs/final_HZZ_SF_2016_legacy_mupogsysts_newLoose_noTracking_1610.root') + muonRun16SF.Set2DHist(float2double(mid16File.Get('FINAL')),float2double(mid16File.Get('ERROR')),float2double(mid16File.Get('ERROR'))) + fScales.cd() + muonRun16SF.Write() +elif year=="2017": + electronLowReco17SF = ROOT.ScaleFactor("electronLowReco17SF", "Run '17 Electron Low Reco SF, x=Eta, y=Pt") + eLowRecoFile = ROOT.TFile.Open('data/Ele_Reco_LowEt_2017.root') + electronLowReco17SF.Set2DHist(float2double(eLowRecoFile.Get('EGamma_SF2D'))) + fScales.cd() + electronLowReco17SF.Write() + + #Electron (Pt>20 Reco SF from POG https://twiki.cern.ch/twiki/bin/viewauth/CMS/Egamma2017DataRecommendations + electronReco17SF = ROOT.ScaleFactor("electronReco17SF", "Run '17 Electron Reco SF, x=Eta, y=Pt") + eRecoFile = ROOT.TFile.Open('data/Ele_Reco_2017.root') + electronReco17SF.Set2DHist(float2double(eRecoFile.Get('EGamma_SF2D'))) + fScales.cd() + electronReco17SF.Write() + + electronRun17SF = ROOT.ScaleFactor("electronRun17SF", "Run '17 Electron HZZ ID SF, x=Eta, y=Pt") + eidFile = ROOT.TFile.Open('data/ElectronSF_Legacy_2017_NoGap.root') + electronRun17SF.Set2DHist(float2double(eidFile.Get('EGamma_SF2D'))) + fScales.cd() + electronRun17SF.Write() + + electronRun17GapSF = ROOT.ScaleFactor("electronRun17GapSF", "Run '17 GapElectron HZZ ID SF, x=Eta, y=Pt") + eleGsfFile = ROOT.TFile.Open('data/ElectronSF_Legacy_2017_Gap.root') + electronRun17GapSF.Set2DHist(float2double(eleGsfFile.Get('EGamma_SF2D'))) + fScales.cd() + electronRun17GapSF.Write() + + muonRun17SF = ROOT.ScaleFactor("muonRun17SF", "Muon Run '17 Trk+ID+ISO SF, x=abs(Eta), y=Pt") + midFile = ROOT.TFile.Open('data/MoriondSFs/ScaleFactors_mu_Moriond2018_final.root') + muonRun17SF.Set2DHist(float2double(midFile.Get('FINAL')),float2double(midFile.Get('ERROR')),float2double(midFile.Get('ERROR'))) + fScales.cd() + muonRun17SF.Write() +elif year=="2018": + #Electron (Pt<20 Reco SF from POG https://twiki.cern.ch/twiki/bin/viewauth/CMS/Egamma2018DataRecommendations + electronLowReco18SF = ROOT.ScaleFactor("electronLowReco18SF", "Run '18 Electron Low Reco SF, x=Eta, y=Pt") + eLowRecoFile = ROOT.TFile.Open('data/Ele_Reco_LowEt_2018.root') + electronLowReco18SF.Set2DHist(float2double(eLowRecoFile.Get('EGamma_SF2D'))) + fScales.cd() + electronLowReco18SF.Write() + + #Electron (Pt>20 Reco SF from POG https://twiki.cern.ch/twiki/bin/viewauth/CMS/Egamma2018DataRecommendations + electronReco18SF = ROOT.ScaleFactor("electronReco18SF", "Run '18 Electron Reco SF, x=Eta, y=Pt") + eRecoFile = ROOT.TFile.Open('data/Ele_Reco_2018.root') + electronReco18SF.Set2DHist(float2double(eRecoFile.Get('EGamma_SF2D'))) + fScales.cd() + electronReco18SF.Write() + + electronRun18SF = ROOT.ScaleFactor("electronRun18SF", "Run '18 Electron HZZ ID SF, x=Eta, y=Pt") + eidFile = ROOT.TFile.Open('data/ElectronSF_Legacy_2018_NoGap.root') + electronRun18SF.Set2DHist(float2double(eidFile.Get('EGamma_SF2D'))) + fScales.cd() + electronRun18SF.Write() + + electronRun18GapSF = ROOT.ScaleFactor("electronRun18GapSF", "Run '18 GapElectron HZZ ID SF, x=Eta, y=Pt") + eleGsfFile = ROOT.TFile.Open('data/ElectronSF_Legacy_2018_Gap.root') + electronRun18GapSF.Set2DHist(float2double(eleGsfFile.Get('EGamma_SF2D'))) + fScales.cd() + electronRun18GapSF.Write() + + muonRun18SF = ROOT.ScaleFactor("muonRun18SF", "Muon Run '18 Trk+ID+ISO SF, x=abs(Eta), y=Pt") + mid18File = ROOT.TFile.Open('data/final_HZZ_muon_SF_2018_IsBDT_0610.root') + muonRun18SF.Set2DHist(float2double(mid18File.Get('FINAL')),float2double(mid18File.Get('ERROR')),float2double(mid18File.Get('ERROR'))) + fScales.cd() + muonRun18SF.Write() -if os.path.isfile(args.tightfr_file): - print "INFO: Adding tight fake rates to %s" % output_file - fakeRateFile = ROOT.TFile.Open(args.tightfr_file) - eCBTightFakeRateZjets = ROOT.ScaleFactor("eCBTightFakeRate", "Fake rate from Z+jet") - eCBTightFakeRateZjets.Set2DHist(fakeRateFile.Get('DataEWKCorrected/ratio2D_allE'), 0, 0, ROOT.ScaleFactor.AsInHist) - mCBTightFakeRateZjets = ROOT.ScaleFactor("mCBTightFakeRate", "Fake rate from Z+jet") - mCBTightFakeRateZjets.Set2DHist(fakeRateFile.Get('DataEWKCorrected/ratio2D_allMu'), 0, 0, ROOT.ScaleFactor.AsInHist) - fScales.cd() - mCBTightFakeRateZjets.Write() - eCBTightFakeRateZjets.Write() +#For every year there is a separate fakeRate file +if os.path.isfile(frfile): + print "INFO: Adding tight fake rates to %s" % args["output_file"] + fakeRateFile = ROOT.TFile.Open(frfile) + eZZTightFakeRate = ROOT.ScaleFactor("eZZTightFakeRate", "Fake rate from Z+jet") + eZZTightFakeRate.Set2DHist(fakeRateFile.Get('DataEWKCorrected/ratioE2D_allE'), 0, 0, ROOT.ScaleFactor.AsInHist) + mZZTightFakeRate = ROOT.ScaleFactor("mZZTightFakeRate", "Fake rate from Z+jet") + mZZTightFakeRate.Set2DHist(fakeRateFile.Get('DataEWKCorrected/ratioMu2D_allMu'), 0, 0, ROOT.ScaleFactor.AsInHist) + fScales.cd() + mZZTightFakeRate.Write() + eZZTightFakeRate.Write() diff --git a/ScaleFactors/testScales.py b/ScaleFactors/testScales.py index 3283b419..d4536106 100755 --- a/ScaleFactors/testScales.py +++ b/ScaleFactors/testScales.py @@ -25,41 +25,47 @@ # Generate with setupScaleFactors.py # Will need appropriate files in ../data/ -fScales = ROOT.TFile('../data/scaleFactors.root') +fScales = ROOT.TFile('../data/scaleFactorsZZ4l2017.root') pu = fScales.Get('pileupSF') -muonIso = fScales.Get('muonIsoSF') -muonId = fScales.Get('muonTightIdSF') -electronTightId = fScales.Get('electronTightIdSF') -electronMediumId = fScales.Get('electronMediumIdSF') +#muonIso = fScales.Get('muonIsoSF') +#muonId = fScales.Get('electronLowRecoSF') +#electronTightId = fScales.Get('electronTightIdSF') +#electronMediumId = fScales.Get('electronMediumIdSF') -#mCBTightFakeRate = fScales.Get("mCBTightFakeRate_Svenja") -#mCBMedFakeRate = fScales.Get("mCBMedFakeRate_Svenja") -#eCBTightFakeRate = fScales.Get("eCBTightFakeRate_Svenja") -#eCBMedFakeRate = fScales.Get("eCBMedFakeRate_Svenja") -mCBTightFakeRate = fScales.Get("mCBTightFakeRate") -eCBTightFakeRate = fScales.Get("eCBTightFakeRate") +mZZTightFakeRate = fScales.Get("mZZTightFakeRate") +eZZTightFakeRate = fScales.Get("eZZTightFakeRate") + +muonMoriondSF= fScales.Get('muonMoriond18SF') +electronLowRecoSF = fScales.Get('electronLowReco18SF') +electronRecoSF = fScales.Get('electronReco18SF') +electronMoriondSF = fScales.Get('electronMoriond18SF') +electronMoriondGapSF = fScales.Get('electronMoriond18GapSF') + + +#mCBTightFakeRate = fScales.Get("mCBTightFakeRate") +#eCBTightFakeRate = fScales.Get("eCBTightFakeRate") del fScales # Make sure we don't rely on file being open pu.RegisterGlobalFunction() print "pileupSF(3) = ", ROOT.pileupSF(3) dummyTree.Scan('10+10*randVal : pileupSF(10+10*randVal)', '', '', 10) -muonIso.RegisterGlobalFunction(2) # 2D function -muonId.RegisterGlobalFunction(2) # 2D function -print "muonIsoSF(1.1, 30) = ", ROOT.muonIsoSF(1.1, 30) -print "muonTightIdSF(1.1, 30) = ", ROOT.muonTightIdSF(1.1, 30) -dummyTree.Scan('abs(randVal*2) : randVal2*5+30 : muonIsoSF(abs(randVal*2), randVal2*5+30)', '', '', 10) -dummyTree.Scan('abs(randVal*2) : randVal2*5+30 : muonTightIdSF(abs(randVal*2), randVal2*5+30)', '', '', 10) - -electronMediumId.RegisterGlobalFunction(2) # 2D function -electronTightId.RegisterGlobalFunction(2) # 2D function -dummyTree.Scan('abs(randVal*2) : randVal2*5+30 : electronMediumIdSF(abs(randVal*2), randVal2*5+30)', '', '', 10) -dummyTree.Scan('abs(randVal*2) : randVal2*5+30 : electronTightIdSF(abs(randVal*2), randVal2*5+30)', '', '', 10) - -mCBTightFakeRate.RegisterGlobalFunction(2) # 2D function -print "mCBTightFakeRate(1.1, 30) = ", ROOT.mCBTightFakeRate(30, 1.1) -dummyTree.Scan('abs(randVal*2) : randVal2*10+30 : mCBTightFakeRate(randVal2*10+30, abs(randVal*2))', '', '', 10) +muonMoriondSF.RegisterGlobalFunction(2) # 2D function +electronLowRecoSF.RegisterGlobalFunction(2) # 2D function +print "muonMoriondSF(1.1, 30) = ", ROOT.muonMoriond18SF(1.1, 30) +print "electronLowRecoSF(1.1, 30) = ", ROOT.electronLowReco18SF(1.1, 30) +dummyTree.Scan('abs(randVal*2) : randVal2*5+30 : muonMoriond18SF(abs(randVal*2), randVal2*5+30)', '', '', 10) +dummyTree.Scan('abs(randVal*2) : randVal2*5+30 : electronLowReco18SF(abs(randVal*2), randVal2*5+30)', '', '', 10) -eCBTightFakeRate.RegisterGlobalFunction(2) # 2D function -print "eCBTightFakeRate(1.1, 30) = ", ROOT.eCBTightFakeRate(30, 1.1) -dummyTree.Scan('abs(randVal*2) : randVal2*10+30 : eCBTightFakeRate(randVal2*10+30, abs(randVal*2))', '', '', 10) +#electronMediumId.RegisterGlobalFunction(2) # 2D function +#electronTightId.RegisterGlobalFunction(2) # 2D function +#dummyTree.Scan('abs(randVal*2) : randVal2*5+30 : electronMediumIdSF(abs(randVal*2), randVal2*5+30)', '', '', 10) +#dummyTree.Scan('abs(randVal*2) : randVal2*5+30 : electronTightIdSF(abs(randVal*2), randVal2*5+30)', '', '', 10) +# +#mCBTightFakeRate.RegisterGlobalFunction(2) # 2D function +#print "mCBTightFakeRate(1.1, 30) = ", ROOT.mCBTightFakeRate(30, 1.1) +#dummyTree.Scan('abs(randVal*2) : randVal2*10+30 : mCBTightFakeRate(randVal2*10+30, abs(randVal*2))', '', '', 10) +# +#eCBTightFakeRate.RegisterGlobalFunction(2) # 2D function +#print "eCBTightFakeRate(1.1, 30) = ", ROOT.eCBTightFakeRate(30, 1.1) +#dummyTree.Scan('abs(randVal*2) : randVal2*10+30 : eCBTightFakeRate(randVal2*10+30, abs(randVal*2))', '', '', 10) diff --git a/Templates/CombineCards/VGen/ZGen_template_ee.txt b/Templates/CombineCards/VGen/ZGen_template_ee.txt new file mode 100644 index 00000000..96e4b4c3 --- /dev/null +++ b/Templates/CombineCards/VGen/ZGen_template_ee.txt @@ -0,0 +1,23 @@ +imax 1 number of channels +jmax 1 number of processes - 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes ${dy_sample} * ${output_file} ${dy_sample}/${fit_variable}_$$CHANNEL ${dy_sample}/${fit_variable}_$$CHANNEL_$$SYSTEMATIC +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_$$CHANNEL nonprompt/${fit_variable}_$$CHANNEL_$$SYSTEMATIC +shapes data_obs * ${output_file} ${data_name}/${fit_variable}_$$CHANNEL + +bin ee +observation -1 + +------------ +bin ee ee +process ${dy_sample} nonprompt +process -1 1 +rate ${dy_lo_2018} ${nonprompt} +------------ +lumi2016_13TeV lnN 1.025 1.025 +dummyErr_ee lnN 1.02 - +QCDscale_${dy_sample} shape 1 - + + diff --git a/Templates/CombineCards/VGen/ZGen_template_mm.txt b/Templates/CombineCards/VGen/ZGen_template_mm.txt new file mode 100644 index 00000000..f4571726 --- /dev/null +++ b/Templates/CombineCards/VGen/ZGen_template_mm.txt @@ -0,0 +1,24 @@ +imax 1 number of channels +jmax 1 number of processes - 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes ${dy_sample} * ${output_file} ${dy_sample}/${fit_variable}_$$CHANNEL ${dy_sample}/${fit_variable}_$$CHANNEL_$$SYSTEMATIC +shapes nonprompt * ${output_file} ${nonprompt}/${fit_variable}_$$CHANNEL ${nonprompt}/${fit_variable}_$$CHANNEL_$$SYSTEMATIC +shapes data_obs * ${output_file} ${data_name}/${fit_variable}_$$CHANNEL + +bin mm +observation -1 + +------------ +bin mm mm +process ${dy_sample} nonprompt +process -1 1 +rate ${dy_lo_2018} ${nonprompt} +------------ +lumi2016_13TeV lnN 1.025 1.025 +dummyErr_mm lnN 1.02 - +QCDscale_${dy_sample} shape 1 - + + + diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2016_all.txt b/Templates/CombineCards/ZZSelection/ZZ_template2016_all.txt new file mode 100644 index 00000000..f1d8d737 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2016_all.txt @@ -0,0 +1,42 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin all +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin all all all all all all +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +--------------------------------------------------------------------------------------------------------------------------- +bkgStat lnN - - - - - 1.4 +trigger lnN 1.020 1.020 1.020 1.020 1.020 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2016_eeee.txt b/Templates/CombineCards/ZZSelection/ZZ_template2016_eeee.txt new file mode 100644 index 00000000..a85bed1c --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2016_eeee.txt @@ -0,0 +1,45 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eeee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eeee eeee eeee eeee eeee eeee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +---------------------------------------------------------------------------------------------------------------------------------- +bkg_eeee_16 lnN - - - - - 1.2 +bkg_ee_16 lnN - - - - - 1.2 +trigger_eeee_16 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2016_eemm.txt b/Templates/CombineCards/ZZSelection/ZZ_template2016_eemm.txt new file mode 100644 index 00000000..c048a41d --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2016_eemm.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eemm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eemm eemm eemm eemm eemm eemm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------ +bkg_mm_16 lnN - - - - - 1.1 +bkg_ee_16 lnN - - - - - 1.1 +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2016_mmee.txt b/Templates/CombineCards/ZZSelection/ZZ_template2016_mmee.txt new file mode 100644 index 00000000..979100b1 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2016_mmee.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmee mmee mmee mmee mmee mmee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +-------------------------------------------------------------------------------------------- ------------------------------- +bkg_mm_16 lnN - - - - - 1.1 +bkg_ee_16 lnN - - - - - 1.1 +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2016_mmmm.txt b/Templates/CombineCards/ZZSelection/ZZ_template2016_mmmm.txt new file mode 100644 index 00000000..8d6b9f08 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2016_mmmm.txt @@ -0,0 +1,44 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmmm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmmm mmmm mmmm mmmm mmmm mmmm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +--------------------------------------------------------------------------------------------------------------------------------- +bkg_mmmm_16 lnN - - - - - 1.2 +bkg_mm_16 lnN - - - - - 1.2 +trigger_mmmm_16 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2017_all.txt b/Templates/CombineCards/ZZSelection/ZZ_template2017_all.txt new file mode 100644 index 00000000..f4affd74 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2017_all.txt @@ -0,0 +1,42 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin all +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin all all all all all all +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +---------------------------------------------------------------------------------------------------------------------- +bkgStat lnN - - - - - 1.4 +trigger lnN 1.020 1.020 1.020 1.020 1.020 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2017_eeee.txt b/Templates/CombineCards/ZZSelection/ZZ_template2017_eeee.txt new file mode 100644 index 00000000..a1be4cf1 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2017_eeee.txt @@ -0,0 +1,45 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eeee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eeee eeee eeee eeee eeee eeee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------ +bkg_eeee_17 lnN - - - - - 1.2 +bkg_ee_17 lnN - - - - - 1.2 +trigger_eeee_17 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_ee_17 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_17 lnN 1.021 1.021 1.021 1.021 1.021 1.021 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2017_eemm.txt b/Templates/CombineCards/ZZSelection/ZZ_template2017_eemm.txt new file mode 100644 index 00000000..14ddbb4e --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2017_eemm.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eemm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eemm eemm eemm eemm eemm eemm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------- +bkg_mm_17 lnN - - - - - 1.1 +bkg_ee_17 lnN - - - - - 1.1 +trigger_ee_17 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_17 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_17 lnN 1.021 1.021 1.021 1.021 1.021 1.021 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2017_mmee.txt b/Templates/CombineCards/ZZSelection/ZZ_template2017_mmee.txt new file mode 100644 index 00000000..6abe06f0 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2017_mmee.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmee mmee mmee mmee mmee mmee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------ +bkg_mm_17 lnN - - - - - 1.1 +bkg_ee_17 lnN - - - - - 1.1 +trigger_ee_17 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_17 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_17 lnN 1.021 1.021 1.021 1.021 1.021 1.021 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2017_mmmm.txt b/Templates/CombineCards/ZZSelection/ZZ_template2017_mmmm.txt new file mode 100644 index 00000000..c318db14 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2017_mmmm.txt @@ -0,0 +1,44 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmmm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmmm mmmm mmmm mmmm mmmm mmmm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------ +bkg_mmmm_17 lnN - - - - - 1.2 +bkg_mm_17 lnN - - - - - 1.2 +trigger_mmmm_17 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_17 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_17 lnN 1.021 1.021 1.021 1.021 1.021 1.021 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2018_all.txt b/Templates/CombineCards/ZZSelection/ZZ_template2018_all.txt new file mode 100644 index 00000000..753e9d54 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2018_all.txt @@ -0,0 +1,42 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable} HZZ_signal/${fit_variable}_$$SYSTEMATIC +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable} qqZZ_powheg/${fit_variable}_$$SYSTEMATIC +shapes ggZZ * ${output_file} ggZZ/${fit_variable} ggZZ/${fit_variable}_$$SYSTEMATIC +shapes VVV * ${output_file} VVV/${fit_variable} VVV/${fit_variable}_$$SYSTEMATIC + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC +shapes data_obs * ${output_file} data/${fit_variable} + +bin all +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin all all all all all all +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +---------------------------------------------------------------------------------------------------------------------- +bkgStat lnN - - - - - 1.4 +trigger lnN 1.020 1.020 1.020 1.020 1.020 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2018_eeee.txt b/Templates/CombineCards/ZZSelection/ZZ_template2018_eeee.txt new file mode 100644 index 00000000..13f96af8 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2018_eeee.txt @@ -0,0 +1,45 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eeee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eeee eeee eeee eeee eeee eeee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +-------------------------------------------------------------------------------------------------------------------------------- +bkg_eeee_18 lnN - - - - - 1.2 +bkg_ee_18 lnN - - - - - 1.2 +trigger_eeee_18 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_ee_18 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_18 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2018_eemm.txt b/Templates/CombineCards/ZZSelection/ZZ_template2018_eemm.txt new file mode 100644 index 00000000..0837d7f8 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2018_eemm.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eemm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eemm eemm eemm eemm eemm eemm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------- +bkg_mm_18 lnN - - - - - 1.1 +bkg_ee_18 lnN - - - - - 1.1 +trigger_ee_18 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_18 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_18 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2018_mmee.txt b/Templates/CombineCards/ZZSelection/ZZ_template2018_mmee.txt new file mode 100644 index 00000000..e8bddb0f --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2018_mmee.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmee mmee mmee mmee mmee mmee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +--------------------------------------------------------------------------------------------- ------------------------------- +bkg_mm_18 lnN - - - - - 1.1 +bkg_ee_18 lnN - - - - - 1.1 +trigger_ee_18 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_18 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_18 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/ZZ_template2018_mmmm.txt b/Templates/CombineCards/ZZSelection/ZZ_template2018_mmmm.txt new file mode 100644 index 00000000..e5aadc57 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/ZZ_template2018_mmmm.txt @@ -0,0 +1,44 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmmm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmmm mmmm mmmm mmmm mmmm mmmm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 4 3 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +-------------------------------------------------------------------------------------------------------------------------------- +bkg_mmmm_18 lnN - - - - - 1.2 +bkg_mm_18 lnN - - - - - 1.2 +trigger_mmmm_18 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_18 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_18 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_VVV shape 0 0 0 0 1 0 +theoAcc lnN - - 1.02 1.02 - - + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/runCombine_Template2017.sh b/Templates/CombineCards/ZZSelection/runCombine_Template2017.sh new file mode 100755 index 00000000..3920b0ce --- /dev/null +++ b/Templates/CombineCards/ZZSelection/runCombine_Template2017.sh @@ -0,0 +1,17 @@ +combineCards.py eeee=ZZ2017_eeee.txt eemm=ZZ2017_eemm.txt mmee=ZZ2017_mmee.txt mmmm=ZZ2017_mmmm.txt > ZZ2017.txt +text2workspace.py ZZ2017.txt -m 999 -o ZZ2017.root + +if [[ $$1 == "impacts" ]]; then + rm -rf impact + mkdir impact + pushd impact + card="../ZZ2017.root" + combineTool.py -M Impacts -m 125 -d $$card --doInitialFit + combineTool.py -M Impacts -m 125 -d $$card --allPars --doFits --parallel 12 + combineTool.py -M Impacts -m 125 -d $$card --allPars -o impacts.json + plotImpacts.py -i impacts.json -o impacts + popd +else + combine -M MaxLikelihoodFit -d ZZ2017.root $$1 +fi + diff --git a/Templates/CombineCards/ZZSelection/runCombine_Template2018.sh b/Templates/CombineCards/ZZSelection/runCombine_Template2018.sh new file mode 100755 index 00000000..a2fde5f7 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/runCombine_Template2018.sh @@ -0,0 +1,17 @@ +combineCards.py eeee=ZZ2018_eeee.txt eemm=ZZ2018_eemm.txt mmee=ZZ2018_mmee.txt mmmm=ZZ2018_mmmm.txt > ZZ2018.txt +text2workspace.py ZZ2018.txt -m 999 -o ZZ2018.root + +if [[ $$1 == "impacts" ]]; then + rm -rf impact + mkdir impact + pushd impact + card="../ZZ2018.root" + combineTool.py -M Impacts -m 125 -d $$card --doInitialFit + combineTool.py -M Impacts -m 125 -d $$card --allPars --doFits --parallel 12 + combineTool.py -M Impacts -m 125 -d $$card --allPars -o impacts.json + plotImpacts.py -i impacts.json -o impacts + popd +else + combine -M MaxLikelihoodFit -d ZZ2018.root $$1 +fi + diff --git a/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_all.txt b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_all.txt new file mode 100644 index 00000000..28067e04 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_all.txt @@ -0,0 +1,47 @@ +imax 1 number of channels +jmax 6 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes qqZZ_sherpa * ${output_file} qqZZ_sherpa/${fit_variable}_$$CHANNEL qqZZ_sherpa/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin all +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin all all all all all all all +process qqZZ_sherpa zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 3 -3 -2 -1 0 1 2 +rate ${qqZZ_sherpa} ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +----------------------------------------------------------------------------------------------------------------------------------------- +bkgStat lnN - - - - - - 1.4 +trigger lnN 1.020 1.020 1.020 1.020 1.020 1.020 - +CMS_eff_e shape 1 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 1 0 +QCDscale_HZZ_signal shape 0 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_eeee.txt b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_eeee.txt new file mode 100644 index 00000000..6c11b75b --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_eeee.txt @@ -0,0 +1,50 @@ +imax 1 number of channels +jmax 6 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes qqZZ_sherpa * ${output_file} qqZZ_sherpa/${fit_variable}_$$CHANNEL qqZZ_sherpa/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eeee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eeee eeee eeee eeee eeee eeee eeee +process qqZZ_sherpa zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 3 -3 -2 -1 0 1 2 +rate ${qqZZ_sherpa} ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------------------------- +bkg_eeee_16 lnN - - - - - - 1.2 +bkg_ee_16 lnN - - - - - - 1.2 +trigger_eeee_16 lnN 1.01 1.01 1.01 1.01 1.01 1.01 - +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_eemm.txt b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_eemm.txt new file mode 100644 index 00000000..632bbbc1 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_eemm.txt @@ -0,0 +1,51 @@ +imax 1 number of channels +jmax 6 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes qqZZ_sherpa * ${output_file} qqZZ_sherpa/${fit_variable}_$$CHANNEL qqZZ_sherpa/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eemm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eemm eemm eemm eemm eemm eemm eemm +process qqZZ_sherpa zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 3 -3 -2 -1 0 1 2 +rate ${qqZZ_sherpa} ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +--------------------------------------------------------------------------------------------------------------------------------------------- +bkg_mm_16 lnN - - - - - - 1.1 +bkg_ee_16 lnN - - - - - - 1.1 +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_mmee.txt b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_mmee.txt new file mode 100644 index 00000000..8e6101e3 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_mmee.txt @@ -0,0 +1,51 @@ +imax 1 number of channels +jmax 6 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes qqZZ_sherpa * ${output_file} qqZZ_sherpa/${fit_variable}_$$CHANNEL qqZZ_sherpa/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmee mmee mmee mmee mmee mmee mmee +process qqZZ_sherpa zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 3 -3 -2 -1 0 1 2 +rate ${qqZZ_sherpa} ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +----------------------------------------------------------------------------------------------------------- ------------------------------- +bkg_mm_16 lnN - - - - - - 1.1 +bkg_ee_16 lnN - - - - - - 1.1 +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_mmmm.txt b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_mmmm.txt new file mode 100644 index 00000000..a5546dc8 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWSherpa/ZZ_template2016_mmmm.txt @@ -0,0 +1,49 @@ +imax 1 number of channels +jmax 6 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes qqZZ_sherpa * ${output_file} qqZZ_sherpa/${fit_variable}_$$CHANNEL qqZZ_sherpa/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmmm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmmm mmmm mmmm mmmm mmmm mmmm mmmm +process qqZZ_sherpa zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process 3 -3 -2 -1 0 1 2 +rate ${qqZZ_sherpa} ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------------------------- +bkg_mmmm_16 lnN - - - - - - 1.2 +bkg_mm_16 lnN - - - - - - 1.2 +trigger_mmmm_16 lnN 1.01 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_m shape 1 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_all.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_all.txt new file mode 100644 index 00000000..3467b98c --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_all.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin all +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin all all all all all all +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +--------------------------------------------------------------------------------------------------------------------------- +bkgStat lnN - - - - - 1.4 +trigger lnN 1.020 1.020 1.020 1.020 1.020 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +CMS_pileup shape 1 1 1 1 1 0 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_eeee.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_eeee.txt new file mode 100644 index 00000000..d9de9a03 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_eeee.txt @@ -0,0 +1,49 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eeee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eeee eeee eeee eeee eeee eeee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +---------------------------------------------------------------------------------------------------------------------------------- +bkg_eeee_16 lnN - - - - - 1.2 +bkg_ee_16 lnN - - - - - 1.2 +trigger_eeee_16 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_eemm.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_eemm.txt new file mode 100644 index 00000000..31dfd8ba --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_eemm.txt @@ -0,0 +1,50 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eemm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eemm eemm eemm eemm eemm eemm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------ +bkg_mm_16 lnN - - - - - 1.1 +bkg_ee_16 lnN - - - - - 1.1 +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_mmee.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_mmee.txt new file mode 100644 index 00000000..50bc537f --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_mmee.txt @@ -0,0 +1,50 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmee mmee mmee mmee mmee mmee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +-------------------------------------------------------------------------------------------- ------------------------------- +bkg_mm_16 lnN - - - - - 1.1 +bkg_ee_16 lnN - - - - - 1.1 +trigger_ee_16 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_mmmm.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_mmmm.txt new file mode 100644 index 00000000..e6bbf877 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2016_mmmm.txt @@ -0,0 +1,48 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmmm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmmm mmmm mmmm mmmm mmmm mmmm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +--------------------------------------------------------------------------------------------------------------------------------- +bkg_mmmm_16 lnN - - - - - 1.2 +bkg_mm_16 lnN - - - - - 1.2 +trigger_mmmm_16 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_16 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_16 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_all.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_all.txt new file mode 100644 index 00000000..b27a5fb6 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_all.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin all +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin all all all all all all +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +---------------------------------------------------------------------------------------------------------------------- +bkgStat lnN - - - - - 1.4 +trigger lnN 1.020 1.020 1.020 1.020 1.020 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_eeee.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_eeee.txt new file mode 100644 index 00000000..41287956 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_eeee.txt @@ -0,0 +1,48 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eeee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eeee eeee eeee eeee eeee eeee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------ +bkg_eeee_17 lnN - - - - - 1.2 +bkg_ee_17 lnN - - - - - 1.2 +trigger_eeee_17 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_ee_17 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_17 lnN 1.021 1.021 1.021 1.021 1.021 1.021 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_eemm.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_eemm.txt new file mode 100644 index 00000000..9019f1db --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_eemm.txt @@ -0,0 +1,50 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eemm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eemm eemm eemm eemm eemm eemm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------- +bkg_mm_17 lnN - - - - - 1.1 +bkg_ee_17 lnN - - - - - 1.1 +trigger_ee_17 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_17 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_17 lnN 1.021 1.021 1.021 1.021 1.021 1.021 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_mmee.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_mmee.txt new file mode 100644 index 00000000..aed705d5 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_mmee.txt @@ -0,0 +1,49 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmee mmee mmee mmee mmee mmee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------ +bkg_mm_17 lnN - - - - - 1.1 +bkg_ee_17 lnN - - - - - 1.1 +trigger_ee_17 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_17 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_17 lnN 1.021 1.021 1.021 1.021 1.021 1.021 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_mmmm.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_mmmm.txt new file mode 100644 index 00000000..e2ae7125 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2017_mmmm.txt @@ -0,0 +1,47 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmmm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmmm mmmm mmmm mmmm mmmm mmmm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------ +bkg_mmmm_17 lnN - - - - - 1.2 +bkg_mm_17 lnN - - - - - 1.2 +trigger_mmmm_17 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_17 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_17 lnN 1.021 1.021 1.021 1.021 1.021 1.021 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_all.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_all.txt new file mode 100644 index 00000000..056b8827 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_all.txt @@ -0,0 +1,46 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable} HZZ_signal/${fit_variable}_$$SYSTEMATIC +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable} qqZZ_powheg/${fit_variable}_$$SYSTEMATIC +shapes ggZZ * ${output_file} ggZZ/${fit_variable} ggZZ/${fit_variable}_$$SYSTEMATIC +shapes VVV * ${output_file} VVV/${fit_variable} VVV/${fit_variable}_$$SYSTEMATIC + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC +shapes data_obs * ${output_file} data/${fit_variable} + +bin all +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin all all all all all all +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +---------------------------------------------------------------------------------------------------------------------- +bkgStat lnN - - - - - 1.4 +trigger lnN 1.020 1.020 1.020 1.020 1.020 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_eeee.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_eeee.txt new file mode 100644 index 00000000..7860cc85 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_eeee.txt @@ -0,0 +1,48 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eeee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eeee eeee eeee eeee eeee eeee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +-------------------------------------------------------------------------------------------------------------------------------- +bkg_eeee_18 lnN - - - - - 1.2 +bkg_ee_18 lnN - - - - - 1.2 +trigger_eeee_18 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_ee_18 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_18 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_eemm.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_eemm.txt new file mode 100644 index 00000000..965fe6a2 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_eemm.txt @@ -0,0 +1,50 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin eemm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin eemm eemm eemm eemm eemm eemm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +------------------------------------------------------------------------------------------------------------------------------- +bkg_mm_18 lnN - - - - - 1.1 +bkg_ee_18 lnN - - - - - 1.1 +trigger_ee_18 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_18 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_18 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_mmee.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_mmee.txt new file mode 100644 index 00000000..6de75044 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_mmee.txt @@ -0,0 +1,49 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmee +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmee mmee mmee mmee mmee mmee +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +--------------------------------------------------------------------------------------------- ------------------------------- +bkg_mm_18 lnN - - - - - 1.1 +bkg_ee_18 lnN - - - - - 1.1 +trigger_ee_18 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_18 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_e shape 1 1 1 1 1 0 +CMS_RecoEff_e shape 1 1 1 1 1 0 +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_18 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + +* autoMCStats 1 diff --git a/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_mmmm.txt b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_mmmm.txt new file mode 100644 index 00000000..70ab5401 --- /dev/null +++ b/Templates/CombineCards/ZZSelection/templateWithTheory/ZZ_template2018_mmmm.txt @@ -0,0 +1,47 @@ +imax 1 number of channels +jmax 5 number of backgrounds plus signals minus 1 +kmax ${nuisances} number of nuisance parameters (sources of systematical uncertainties) +------------ + +shapes zzjj4l_ewk * ${output_file} zzjj4l_ewk/${fit_variable}_$$CHANNEL zzjj4l_ewk/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes HZZ_signal * ${output_file} HZZ_signal/${fit_variable}_$$CHANNEL HZZ_signal/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes qqZZ_powheg * ${output_file} qqZZ_powheg/${fit_variable}_$$CHANNEL qqZZ_powheg/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes ggZZ * ${output_file} ggZZ/${fit_variable}_$$CHANNEL ggZZ/${fit_variable}_$$SYSTEMATIC_$$CHANNEL +shapes VVV * ${output_file} VVV/${fit_variable}_$$CHANNEL VVV/${fit_variable}_$$SYSTEMATIC_$$CHANNEL + +shapes nonprompt * ${output_file} nonprompt/${fit_variable}_Fakes_$$CHANNEL nonprompt/${fit_variable}_Fakes_$$SYSTEMATIC_$$CHANNEL +shapes data_obs * ${output_file} data/${fit_variable}_$$CHANNEL + +bin mmmm +observation ${data} + +------------ +#nonprompt is data-driven Z+X background +# now we list the expected events for signal and all backgrounds in that bin +# the second 'process' line must have a positive number for backgrounds, and 0 for signal +# then we list the independent sources of uncertainties, and give their effect (syst. error) +# on each process and bin + +bin mmmm mmmm mmmm mmmm mmmm mmmm +process zzjj4l_ewk HZZ_signal qqZZ_powheg ggZZ VVV nonprompt +process -3 -2 -1 0 1 2 +rate ${zzjj4l_ewk} ${HZZ_signal} ${qqZZ_powheg} ${ggZZ} ${VVV} ${nonprompt} +-------------------------------------------------------------------------------------------------------------------------------- +bkg_mmmm_18 lnN - - - - - 1.2 +bkg_mm_18 lnN - - - - - 1.2 +trigger_mmmm_18 lnN 1.01 1.01 1.01 1.01 1.01 - +trigger_mm_18 lnN 1.01 1.01 1.01 1.01 1.01 - +CMS_eff_m shape 1 1 1 1 1 0 +#CMS_pileup shape 1 1 1 1 1 0 +CMS_lumi lnN 1.01 1.01 1.01 1.01 1.01 1.01 +lumi_18 lnN 1.023 1.023 1.023 1.023 1.023 1.023 +QCDscale_HZZ_signal shape 0 1 0 0 0 0 +QCDscale_qqZZ_powheg shape 0 0 1 0 0 0 +QCDscale_ggZZ lnN 0 0 0 1.2 0 0 +QCDscale_VVV shape 0 0 0 0 1 0 +pdf_HZZ_signal shape 0 1 0 0 0 0 +pdf_qqZZ_powheg shape 0 0 1 0 0 0 +pdf_ggZZ lnN 0 0 0 1.05 0 0 +pdf_VVV shape 0 0 0 0 1 0 + +* autoMCStats 1 diff --git a/Templates/config.kelong b/Templates/config.kelong index d3790450..afd857d5 100644 --- a/Templates/config.kelong +++ b/Templates/config.kelong @@ -2,6 +2,7 @@ user = kelong analysis = WZ dataset_manager_path = /afs/cern.ch/user/k/%(user)s/work +dataset_manager_name = AnalysisDatasetManager combine_path = %(dataset_manager_path)s/HiggsCombine/CMSSW_8_1_0/src/HiggsAnalysis/CombinedLimit output_path = /eos/user/k/%(user)s/%(analysis)sAnalysisData fakeRate_output = %(output_path)s/FakeRates diff --git a/Templates/config.uhussain b/Templates/config.uhussain new file mode 100644 index 00000000..915b46f1 --- /dev/null +++ b/Templates/config.uhussain @@ -0,0 +1,10 @@ +[Setup] +user = uhussain +analysis = ZZ +dataset_manager_path = /afs/cern.ch/user/u/%(user)s/work +dataset_manager_name = ZZ4lRun2DatasetManager +combine_path = %(dataset_manager_path)s/%(dataset_manager_name)s/HiggsCombine/CMSSW_10_2_3/src/HiggsAnalysis/CombinedLimit +output_path = /eos/user/u/%(user)s/%(analysis)sAnalysisData +fakeRate_output = %(output_path)s/FakesRates +hist_output = %(output_path)s/HistFiles +combine_output = %(output_path)s/CombineData diff --git a/Utilities/python/CombineCardTools.py b/Utilities/python/CombineCardTools.py new file mode 100644 index 00000000..cb98fa5f --- /dev/null +++ b/Utilities/python/CombineCardTools.py @@ -0,0 +1,228 @@ +import logging +import ConfigureJobs +import HistTools +import OutputTools +from prettytable import PrettyTable +import os +import ROOT + +class CombineCardTools(object): + def __init__(self): + self.fitVariable = "" + self.fitVariableAppend = {} + self.processes = [] + self.yields = {} + self.histData = {} + self.crossSectionMap = {} + self.outputFile = "" + self.templateName = "" + self.channels = [] + self.variations = {} + self.rebin = None + self.isMC = True + self.isUnrolledFit = False + self.lumi = 1 + self.outputFolder = "." + self.theoryVariations = {} + + def setPlotGroups(self, xsecMap): + self.crossSectionMap = xsecMap + + def setRebin(self, rebin): + self.rebin = rebin + + def setCrosSectionMap(self, xsecMap): + self.crossSectionMap = xsecMap + + # Map of plot groups and members (individual processes) + def setProcesses(self, processes): + self.processes = processes + + def setFitVariableAppend(self, process, append): + self.fitVariableAppend[process] = append + + def setFitVariable(self, variable): + self.fitVariable = variable + + def setVariations(self, variations, exclude=[]): + if not self.processes: + raise ValueError("No processes defined, can't set variations") + for process in self.processes.keys(): + if process in exclude: + self.setVariationsByProcess(process, []) + continue + self.setVariationsByProcess(process, variations) + + def getVariations(self): + return self.variations + + def getVariationsForProcess(self, process): + if process not in self.variations.keys(): + raise ValueError("Variations not defined for process %s" % process) + return self.variations[process] + + def setVariationsByProcess(self, process, variations): + if "Up" not in variations and "Down" not in variations: + variations = [x+y for x in variations for y in ["Up", "Down"]] + self.variations[process] = variations + + def weightHistName(self, channel, process): + fitVariable = self.getFitVariable(process) + variable = fitVariable.replace("unrolled", "2D") if self.isUnrolledFit else fitVariable + return "_".join([variable, "lheWeights", channel]) + + def setLumi(self, lumi): + self.lumi = lumi + + def setOutputFolder(self, outputFolder): + self.outputFolder = outputFolder + if not os.path.isdir(outputFolder): + os.makedirs(outputFolder) + + def addTheoryVar(self, processName, varName, entries, central=0, exclude=[]): + if "scale" not in varName.lower() and "pdf" not in varName.lower(): + raise ValueError("Invalid theory uncertainty %s. Must be type 'scale' or 'pdf'" % varName) + name = "scale" if "scale" in varName.lower() else "pdf" + + if not processName in self.theoryVariations: + self.theoryVariations[processName] = {} + + self.theoryVariations[processName].update({ name : { + "entries" : entries, + "central" : central, + "exclude" : exclude, + "combine" : "envelope" if name == "scale" else ("hessian" if "hessian" in varName else "mc"), + } + }) + + def getRootFile(self, rtfile, mode=None): + if type(rtfile) == str: + if mode: + return ROOT.TFile.Open(rtfile, mode) + else: + return ROOT.TFile.Open(rtfile) + return rtfile + + def setTemplateFileName(self, templateName): + self.templateName = templateName + + def setOutputFile(self, outputFile): + #self.outputFile = self.getRootFile("/".join([self.outputFolder, outputFile]), "RECREATE") + self.outputFile = self.getRootFile(outputFile, "RECREATE") + + def setInputFile(self, inputFile): + self.inputFile = self.getRootFile(inputFile) + + def setChannels(self, channels): + self.channels = channels + for chan in self.channels + ["all"]: + self.yields[chan] = {} + + def processHists(self, processName): + return self.histData[processName] + + def getFitVariable(self, process): + if process not in self.fitVariableAppend: + return self.fitVariable + return "_".join([self.fitVariable, self.fitVariableAppend[process]]) + + def combineChannels(self, group, central=True): + variations = self.variations[group.GetName()][:] + fitVariable = self.getFitVariable(group.GetName()) + if central: + variations.append("") + for var in variations: + # TODO: Remove these two replace statements, it's WZ/ZZ specific + name = fitVariable if var is "" else "_".join([fitVariable, var]) + hist_name = name + "_" + self.channels[0] + hist = group.FindObject(hist_name) + if not hist: + logging.warning("Failed to find hist %s in group %s. Skipping" % (hist_name, group.GetName())) + continue + hist = hist.Clone(name) + ROOT.SetOwnership(hist, False) + group.Add(hist) + for chan in self.channels[1:]: + chan_hist = group.FindObject(name + "_" + chan) + hist.Add(chan_hist) + + def listOfHistsByProcess(self, processName): + if self.fitVariable == "": + raise ValueError("Must declare fit variable before defining plots") + fitVariable = self.getFitVariable(processName) + plots = ["_".join([fitVariable, chan]) for chan in self.channels] + variations = self.getVariationsForProcess(processName) + plots += ["_".join([fitVariable, var, c]) for var in variations for c in self.channels] + if processName in self.theoryVariations.keys(): + plots += [self.weightHistName(c, processName) for c in self.channels] + return plots + + # processName needs to match a PlotGroup + def loadHistsForProcess(self, processName, scaleNorm=1): + plotsToRead = self.listOfHistsByProcess(processName) + + group = HistTools.makeCompositeHists(self.inputFile, processName, + {proc : self.crossSectionMap[proc] for proc in self.processes[processName]}, + self.lumi, plotsToRead, rebin=self.rebin, overflow=False) + + fitVariable = self.getFitVariable(processName) + #TODO:Make optional + processedHists = [] + for chan in self.channels: + histName = "_".join([fitVariable, chan]) if chan != "all" else fitVariable + hist = group.FindObject(histName) + #TODO: Make optional + if "data" not in processName.lower(): + HistTools.removeZeros(hist) + HistTools.addOverflow(hist) + processedHists.append(histName) + self.yields[chan].update({processName : round(hist.Integral(), 4) if hist.Integral() > 0 else 0.0001}) + + if chan == self.channels[0]: + self.yields["all"][processName] = self.yields[chan][processName] + else: + self.yields["all"][processName] += self.yields[chan][processName] + + if processName in self.theoryVariations: + weightHist = group.FindObject(self.weightHistName(chan, processName)) + if not weightHist: + logging.warning("Failed to find %s. Skipping" % self.weightHistName(chan, processName)) + continue + theoryVars = self.theoryVariations[processName] + scaleHists = HistTools.getScaleHists(weightHist, processName, self.rebin, + entries=theoryVars['scale']['entries'], central=theoryVars['scale']['central']) + pdfFunction = getattr(HistTools, "get%sPDFVariationHists" % ("Hessian" if "hessian" in theoryVars['pdf']['combine'] else "MC")) + pdfHists = pdfFunction(weightHist, theoryVars['pdf']['entries'], processName, + self.rebin, central=theoryVars['pdf']['central']) + group.extend(scaleHists+pdfHists) + #TODO: You may want to combine channels before removing zeros + self.combineChannels(group) + #TODO: Make optional + map(HistTools.addOverflow, filter(lambda x: (x.GetName() not in processedHists), group)) + if "data" not in group.GetName().lower(): + map(HistTools.removeZeros, filter(lambda x: (x.GetName() not in processedHists), group)) + self.histData[processName] = group + + # It's best to call this function for process, otherwise you can end up + # storing many large histograms in memory + def writeProcessHistsToOutput(self, processName): + if processName not in self.histData.keys() or not self.histData[processName]: + raise ValueError("Hists for process %s not found" % processName) + processHists = self.histData[processName] + OutputTools.writeOutputListItem(processHists, self.outputFile) + processHists.Delete() + + def writeCards(self, chan, nuisances, year="", extraArgs={}): + chan_dict = self.yields[chan].copy() + chan_dict.update(extraArgs) + chan_dict["nuisances"] = nuisances + chan_dict["fit_variable"] = self.fitVariable + chan_dict["output_file"] = self.outputFile.GetName() + outputCard = self.templateName.split("/")[-1].format(channel=chan, year=year) + outputCard = outputCard.replace("template", "") + outputCard = outputCard.replace("__", "_") + ConfigureJobs.fillTemplatedFile(self.templateName.format(channel=chan, year=year), + "/".join([self.outputFolder, outputCard]), + chan_dict + ) + diff --git a/Utilities/python/ConfigureJobs.py b/Utilities/python/ConfigureJobs.py index 66a9d627..e89dedf2 100644 --- a/Utilities/python/ConfigureJobs.py +++ b/Utilities/python/ConfigureJobs.py @@ -7,6 +7,8 @@ import json import array import string +import socket +import logging #try: import configparser #except: @@ -43,19 +45,37 @@ def getBinning(variable='MTWZ', isVBS=True, isHiggs=False): def getChannels(analysis='WZ'): if analysis == 'WZ': return ["eee", "eem", "emm", "mmm"] -def getManagerPath(): + +def getManagerName(): + config_name = "Templates/config.%s" % os.getlogin() + default_name = "AnalysisDatasetManager" + if not os.path.isfile(config_name): + logging.warning("dataset_manager_name not specified in config file %s" % config_name) + logging.warning("Using default '%s'" % default_name) + return default_name config = configparser.ConfigParser() - try: - config.read_file(open("Templates/config.%s" % os.environ["USER"])) - if "dataset_manager_path" not in config['Setup']: - raise ValueError("dataset_manager_path not specified in config file Template/config.%s" - % os.environ["USER"]) - except ValueError as e: - if os.path.isdir('AnalysisDatasetManager'): - return '.' - raise e + config.read_file(open(config_name)) + if "dataset_manager_name" not in config['Setup']: + logging.warning("dataset_manager_name not specified in config file %s" % config_name) + logging.warning("Using default '%s'" % default_name) + return default_name + return config['Setup']['dataset_manager_name'] +def getManagerPath(): + config_name = "Templates/config.%s" % os.getlogin() + if not os.path.isfile(config_name): + if os.path.isdir(getManagerName()): + return '.' + else: + raise IOError("Failed to find valid config file. Looking for %s" + % config_name) + config = configparser.ConfigParser() + config.read_file(open(config_name)) + if "dataset_manager_path" not in config['Setup']: + raise ValueError("dataset_manager_path not specified in config file %s" + % config_name) return config['Setup']['dataset_manager_path'] + "/" + def getCombinePath(): config = configparser.ConfigParser() config.read_file(open("Templates/config.%s" % os.environ["USER"])) @@ -63,7 +83,39 @@ def getCombinePath(): raise ValueError("dataset_manager_path not specified in config file Template/config.%s" % os.environ["USER"]) return config['Setup']['combine_path'] + "/" -def getListOfEWKFilenames(): +def getListOfGenFilenames(analysis='ZZ'): + if 'ZZ' in analysis: + return [ + "zz4l-amcatnlo", + "zz4l-powheg", + #"zzjj4l-ewk", + "ggZZ4e", + "ggZZ4m", + "ggZZ4t", + "ggZZ2e2mu", + "ggZZ2e2tau", + "ggZZ2mu2tau", + "ggHZZ", + "ttH_HToZZ_4L", + "WminusHToZZ", + "WplusHToZZ", + "ZHToZZ_4L", + "vbfHZZ", + ] + return [] +def getListOfEWKFilenames(analysis=""): + if "ZZ4l" in analysis: + return [ + "zz4l-powheg", + #"zzjj4l-ewk", + "ggZZ4e", + "ggZZ4m", + "ggZZ4t", + "ggZZ2e2mu", + "ggZZ2e2tau", + "ggZZ2mu2tau", + ] + # TODO: This is obviously WZ specific and should be updated return [ # "wz3lnu-powheg", # Use jet binned WZ samples for subtraction by default @@ -87,6 +139,11 @@ def getListOfEWKFilenames(): "ggZZ4m", "ggZZ2e2mu", ] +def getListOfDYFilenames(): + return[ + "DYJetsToLL_M10to50", + "DYJetsToLLM-50", + ] def getListOfNonpromptFilenames(): return ["tt-lep", "st-schan", @@ -138,20 +195,58 @@ def getListOfHDFSFiles(file_path): elif "root" in split[1]: files.append(split[1]) return files -def getListOfFiles(filelist, selection, manager_path=""): + +# TODO: Would be good to switch the order of the last two arguments +# completely deprecate manager_path without breaking things +def getListOfFiles(filelist, selection, manager_path="", analysis=""): if manager_path is "": manager_path = getManagerPath() - data_path = "%s/AnalysisDatasetManager/FileInfo" % manager_path + data_path = "%s/%s/FileInfo" % (manager_path, getManagerName()) data_info = UserInput.readAllInfo("/".join([data_path, "data/*"])) mc_info = UserInput.readAllInfo("/".join([data_path, "montecarlo/*"])) - valid_names = data_info.keys() + mc_info.keys() + analysis_info = UserInput.readInfo("/".join([data_path, analysis, selection])) \ + if analysis != "" else [] + valid_names = (data_info.keys() + mc_info.keys()) if not analysis_info else analysis_info.keys() names = [] for name in filelist: if ".root" in name: names.append(name) elif "WZxsec2016" in name: dataset_file = manager_path + \ - "AnalysisDatasetManager/FileInfo/WZxsec2016/%s.json" % selection + "%s/FileInfo/WZxsec2016/%s.json" % (getManagerPath(), selection) + allnames = json.load(open(dataset_file)).keys() + if "nodata" in name: + nodata = [x for x in allnames if "data" not in x] + names += nodata + elif "data" in name: + names += [x for x in allnames if "data" in x] + else: + names += allnames + elif "ZZ4l2016" in name: + dataset_file = manager_path + \ + "ZZ4lRun2DatasetManager/FileInfo/ZZ4l2016/%s.json" % selection + allnames = json.load(open(dataset_file)).keys() + if "nodata" in name: + nodata = [x for x in allnames if "data" not in x] + names += nodata + elif "data" in name: + names += [x for x in allnames if "data" in x] + else: + names += allnames + elif "ZZ4l2017" in name: + dataset_file = manager_path + \ + "ZZ4lRun2DatasetManager/FileInfo/ZZ4l2017/%s.json" % selection + allnames = json.load(open(dataset_file)).keys() + if "nodata" in name: + nodata = [x for x in allnames if "data" not in x] + names += nodata + elif "data" in name: + names += [x for x in allnames if "data" in x] + else: + names += allnames + elif "ZZ4l2018" in name: + dataset_file = manager_path + \ + "ZZ4lRun2DatasetManager/FileInfo/ZZ4l2018/%s.json" % selection allnames = json.load(open(dataset_file)).keys() if "nodata" in name: nodata = [x for x in allnames if "data" not in x] @@ -165,16 +260,19 @@ def getListOfFiles(filelist, selection, manager_path=""): else: if name.split("__")[0] not in valid_names: print "%s is not a valid name" % name - print "Valid names are", valid_names + print "Valid names must be defined in AnalysisDatasetManager/FileInfo/(data/montecarlo)*" continue names += [name] return [str(i) for i in names] def getXrdRedirector(): - usbased = ["hep.wisc.edu"] - if any(i in os.environ["HOSTNAME"] for i in usbased): - return 'cmsxrootd.fnal.gov' - return 'cms-xrd-global.cern.ch' + usbased = ["wisc.edu"] + usredir = 'cmsxrootd.fnal.gov' + globalredir = 'cms-xrd-global.cern.ch' + # Cluster machines may not have this env variable + if any(i in socket.gethostname() for i in usbased): + return usredir + return globalredir def fillTemplatedFile(template_file_name, out_file_name, template_dict): with open(template_file_name, "r") as templateFile: @@ -182,21 +280,37 @@ def fillTemplatedFile(template_file_name, out_file_name, template_dict): result = source.substitute(template_dict) with open(out_file_name, "w") as outFile: outFile.write(result) -def getListOfFilesWithXSec(filelist, manager_path=""): + +def getListOfFilesWithXSec(filelist, manager_path="", selection="ntuples"): if manager_path is "": manager_path = getManagerPath() - data_path = "%s/AnalysisDatasetManager/FileInfo" % manager_path - files = getListOfFiles(filelist, "ntuples", manager_path) + data_path = "%s/%s/FileInfo" % (manager_path, getManagerName()) + files = getListOfFiles(filelist, selection, manager_path) mc_info = UserInput.readAllInfo("/".join([data_path, "montecarlo/*"])) info = {} for file_name in files: - if "data" in file_name: + if "data" in file_name.lower() or "nonprompt" in file_name.lower(): info.update({file_name : 1}) else: file_info = mc_info[file_name.split("__")[0]] kfac = file_info["kfactor"] if "kfactor" in file_info.keys() else 1 info.update({file_name : file_info["cross_section"]*kfac}) return info + +def getListOfFilesWithDASPath(filelist, analysis, selection, manager_path=""): + if manager_path is "": + manager_path = getManagerPath() + data_path = "%s/%s/FileInfo" % (manager_path, getManagerName()) + files = getListOfFiles(filelist, selection, manager_path, analysis) + selection_info = UserInput.readInfo("/".join([data_path, analysis, selection])) + info = {} + for file_name in files: + if "DAS" not in selection_info[file_name].keys(): + print "ERROR: DAS path not defined for file %s in analysis %s/%s" % (file_name, analysis, selection) + continue + info.update({file_name : selection_info[file_name]["DAS"]}) + return info + def getPreviousStep(selection, analysis): selection_map = {} if analysis == "WZxsec2016": @@ -239,7 +353,7 @@ def getConfigFileName(config_file_name): for extension in ["json", "py"]: if os.path.isfile(".".join([config_file_name, extension])): return ".".join([config_file_name, extension]) - raise IOError("Invalid configuration file. Tried to read %s which does not exist" % \ + raise ValueError("Invalid configuration file. Tried to read %s which does not exist" % \ config_file_name) def getInputFilesPath(sample_name, selection, analysis, manager_path=""): @@ -248,7 +362,7 @@ def getInputFilesPath(sample_name, selection, analysis, manager_path=""): if ".root" in sample_name: print "INFO: using simple file %s" % sample_name return sample_name - data_path = "%s/AnalysisDatasetManager/FileInfo" % manager_path + data_path = "%s/%s/FileInfo" % (manager_path, getManagerName()) input_file_base_name = "/".join([data_path, analysis, selection]) input_file_name = getConfigFileName(input_file_base_name) input_files = UserInput.readInfo(input_file_name) diff --git a/Utilities/python/HistTools.py b/Utilities/python/HistTools.py index 00c6408e..ddffabdf 100644 --- a/Utilities/python/HistTools.py +++ b/Utilities/python/HistTools.py @@ -1,5 +1,7 @@ import array import ROOT +import logging +import math def getDifference(fOut, name, dir1, dir2, ratioFunc=None): differences = ROOT.TList() @@ -12,11 +14,11 @@ def getDifference(fOut, name, dir1, dir2, ratioFunc=None): diff = hist1.Clone() diff.Add(hist2, -1) elif not hist1: - print "WARNING: Hist %s was not produced for " \ - "dataset(s) %s" % (histname, dir1) + logging.warning("Hist %s was not produced for " \ + "dataset(s) %s" % (histname, dir1)) elif not hist2: - print "WARNING: Hist %s was not produced for " \ - "dataset(s) %s" % (histname, dir2) + logging.warning("Hist %s was not produced for " \ + "dataset(s) %s" % (histname, dir2)) differences.Add(diff) if ratioFunc: ratios = ratioFunc(differences) @@ -126,61 +128,83 @@ def getLHEWeightHists(init2D_hist, entries, name, variation_name, rebin=None): hist_name = init2D_hist.GetName().replace("lheWeights", "%s_%sUp" % (variation_name, name)) return hists, hist_name -def getPDFHists(init2D_hist, entries, name, rebin=None): +def getMCPDFVariationHists(init2D_hist, entries, name, rebin=None, central=0): hists, hist_name = getLHEWeightHists(init2D_hist, entries, name, "pdf", rebin) - #return hists + if central == -1: + upaction = lambda x: x[int(0.84*len(entries))] + downaction = lambda x: x[int(0.16*len(entries))] + else: + upaction = lambda x : x[central]*(1+getPDFPercentVariation(x)) + downaction = lambda x: x[central]*(1-getPDFPercentVariation(x)) + return getVariationHists(hists, name, hist_name, - lambda x: x[0]*(1+getPDFPercentVariation(x)), - lambda x: x[0]*(1-getPDFPercentVariation(x)) + upaction, downaction, central ) +def getHessianPDFVariationHists(init2D_hist, entries, name, rebin=None, central=0): + hists, hist_name = getLHEWeightHists(init2D_hist, entries, name, "pdf", rebin) + #centralIndex = central if central != -1 else int(len(entries)/2) + sumsq = lambda x: math.sqrt(sum([0 if y < 0.01 else ((x[central] - y)**2) for y in x])) + upaction = lambda x: x[central] + sumsq(x) + downaction = lambda x: x[central] - sumsq(x) + return getVariationHists(hists, name, hist_name, + upaction, downaction, central, #downaction, central + ) + +def getAllHessianPDFHists(): + hists, hist_name = getLHEWeightHists(init2D_hist, entries, name, "pdf", rebin) + return hists + def getPDFPercentVariation(values): denom = values[84] + values[16] if denom == 0: return 0 return abs(values[84] - values[16])/denom -def getScaleHists(scale_hist2D, name, rebin=None): - entries = [i for i in range(1,10) if i not in [7, 9]] +def getScaleHists(scale_hist2D, name, rebin=None, entries=[i for i in range(1,10)], central=0, exclude=[7,9]): hists, hist_name = getLHEWeightHists(scale_hist2D, entries, name, "QCDscale", rebin) - return getVariationHists(hists, name, hist_name, lambda x: x[-1], lambda x: x[1]) + return getVariationHists(hists, name, hist_name, lambda x: x[-1], lambda x: x[1], central) -def getVariationHists(hists, process_name, histUp_name, up_action, down_action): - histUp = hists[0].Clone(histUp_name) +def getVariationHists(hists, process_name, histUp_name, up_action, down_action, central=0): + histUp = hists[central].Clone(histUp_name) histDown = histUp.Clone(histUp_name.replace("Up", "Down")) - histCentral = hists[0] + histCentral = hists.pop(central) if central != -1 else None # Include overflow - for i in range(0, hists[0].GetNbinsX()+2): + for i in range(0, histUp.GetNbinsX()+2): vals = [] - for hist in hists[1:]: + for hist in hists: vals.append(hist.GetBinContent(i)) vals.sort() - vals.insert(0, histCentral.GetBinContent(i)) + vals.insert(0, histCentral.GetBinContent(i) if histCentral else 0) histUp.SetBinContent(i, up_action(vals)) histDown.SetBinContent(i, down_action(vals)) # For now, skip this check on aQGC for now, since they're screwed up if "aqgc" in process_name: continue - isValidVariation(process_name, histCentral, histUp, histDown) + logging.debug("For process %s: Central, down, up: %s, %s, %s" % (process_name, histCentral.Integral() if histCentral else 0, histDown.Integral(), histUp.Integral())) + if histCentral and False: # Off for now, it can happen that groups have some hists with no weights which screws this up + isValidVariation(process_name, histCentral, histUp, histDown) return [histUp, histDown] def isValidVariation(process_name, histCentral, histUp, histDown): for i in range(0, histCentral.GetNbinsX()+2): - if histDown.GetBinContent(i) >= histCentral.GetBinContent(i) and histCentral.GetBinContent(i) > 0: + if histDown.GetBinContent(i) > histCentral.GetBinContent(i) and histCentral.GetBinContent(i) > 0.01: raise RuntimeError("Down variation >= central value for %s, hist %s" " This shouldn't be possible.\n" + "up_hist: %0.4f\n" "down_hist: %0.4f\n" "central_hist: %0.4f\n" "bin: %i\n" - % (process_name, histDown.GetName(), histDown.GetBinContent(i), histCentral.GetBinContent(i), i) + % (process_name, histDown.GetName(), histUp.GetBinContent(i), histDown.GetBinContent(i), histCentral.GetBinContent(i), i) ) - if histUp.GetBinContent(i) <= histCentral.GetBinContent(i) and histCentral.GetBinContent(i) > 0: + if histUp.GetBinContent(i) < histCentral.GetBinContent(i) and histCentral.GetBinContent(i) > 0.01: raise RuntimeError("Up variation <= central value for %s, hist %s." " This shouldn't be possible.\n" - "up_hist: %0.2f\n" - "central_hist: %0.2f\n" + "up_hist: %0.4f\n" + "down_hist: %0.4f\n" + "central_hist: %0.4f\n" "bin: %i\n" - % (process_name, histUp.GetName(), histUp.GetBinContent(i), histCentral.GetBinContent(i), i) + % (process_name, histUp.GetName(), histUp.GetBinContent(i), histDown.GetBinContent(i), histCentral.GetBinContent(i), i) ) def getTransformed3DScaleHists(scale_hist3D, transformation, transform_args, name): @@ -229,6 +253,9 @@ def addControlRegionToFitHist(control_hist, input_hist, base_name="unrolled"): ROOT.SetOwnership(hist, False) return hist +def addOverflow(hist): + addOverflowAndUnderflow(hist, underflow=False, overflow=True) + def addOverflowAndUnderflow(hist, underflow=True, overflow=True): if not "TH1" in hist.ClassName(): return @@ -241,7 +268,7 @@ def addOverflowAndUnderflow(hist, underflow=True, overflow=True): add_underflow = hist.GetBinContent(0) + hist.GetBinContent(1) hist.SetBinContent(1, add_underflow) -def makeCompositeHists(hist_file, name, members, lumi, hists=[], underflow=False, overflow=True, rebin=None): +def makeCompositeHists(hist_file, name, members, lumi, hists=[], hist_filter=0, underflow=False, overflow=True, rebin=None): composite = ROOT.TList() composite.SetName(name) for directory in [str(i) for i in members.keys()]: @@ -249,16 +276,18 @@ def makeCompositeHists(hist_file, name, members, lumi, hists=[], underflow=False if "aqgc" in directory: directory = name if not hist_file.Get(directory): - print "Skipping invalid filename %s" % directory + logging.warning("Skipping invalid filename %s" % directory) continue if hists == []: hists = [i.GetName() for i in hist_file.Get(directory).GetListOfKeys()] + if hist_filter: + hists = filter(hist_filter, hists) sumweights = 0 - if "data" not in directory.lower(): - sumweights_hist = hist_file.Get("/".join([directory.split("__")[0], "sumweights"])) + if "data" not in directory.lower() and "nonprompt" not in directory.lower(): + sumweights_hist = hist_file.Get("/".join([directory, "sumweights"])) if not sumweights_hist: raise RuntimeError("Failed to find sumWeights for dataset %s" % directory) - sumweights = sumweights_hist.Integral() + sumweights = sumweights_hist.Integral(1, sumweights_hist.GetNbinsX()+2) sumweights_hist.Delete() for histname in hists: if histname == "sumweights": continue @@ -271,7 +300,8 @@ def makeCompositeHists(hist_file, name, members, lumi, hists=[], underflow=False if hist: sumhist = composite.FindObject(hist.GetName()) if sumweights: - hist.Scale(members[directory.split("__")[0]]*1000*lumi/sumweights) + xsec = members[directory if directory in members.keys() else directory.split("__")[0]] + hist.Scale(xsec*1000*lumi/sumweights) addOverflowAndUnderflow(hist, underflow, overflow) else: raise RuntimeError("hist %s was not produced for " diff --git a/Utilities/python/SelectorTools.py b/Utilities/python/SelectorTools.py index 918bb2dc..a672f1d9 100755 --- a/Utilities/python/SelectorTools.py +++ b/Utilities/python/SelectorTools.py @@ -20,7 +20,9 @@ def __init__(self, analysis, selection, input_tier, year): "Zstudy" : "ZSelector", "Zstudy_2016" : "ZSelector", "Zstudy_2017" : "ZSelector", - "ZZGen" : "ZZGenSelector", + "ZZ4l2016" : "ZZSelector", + "ZZ4l2017" : "ZZSelector", + "ZZ4l2018" : "ZZSelector", "WGen" : "WGenSelector", "ZGen" : "ZGenSelector", "ThreeLep" : "ThreeLepSelector", @@ -40,6 +42,7 @@ def __init__(self, analysis, selection, input_tier, year): self.numCores = 1 self.channels = ["Inclusive"] self.outfile_name = "temp.root" + self.outfile = 0 self.datasets = {} # Needed to parallelize class member function, see @@ -53,11 +56,25 @@ def tempfileName(self, dataset): def setChannels(self, channels): self.channels = channels + def isBackground(self): + self.selector_name = self.selector_name.replace("Selector", "BackgroundSelector") + + def isGen(self): + self.selector_name = self.selector_name.replace("BackgroundSelector", "GenSelector") + + def isFake(self): + self.selector_name = self.selector_name.replace("ZZ", "FakeRate") + + def outputFile(self): + return self.outfile + def setOutputfile(self, outfile_name): + if self.outfile: + self.outfile.Close() self.outfile_name = outfile_name self.outfile = ROOT.gROOT.FindObject(outfile_name) if not self.outfile: - self.outfile = ROOT.TFile.Open(outfile_name) + self.outfile = ROOT.TFile.Open(outfile_name, "recreate") self.current_file = self.outfile def addTNamed(self, name, title): @@ -85,6 +102,9 @@ def setNtupeType(self, ntupleType): def setNumCores(self, numCores): self.numCores = numCores + def setSumWeights(self, addSumweights): + self.addSumweights = addSumweights + def setFileList(self, list_of_files, nPerJob, jobNum): if not os.path.isfile(list_of_files): raise ValueError("%s is not a valid file." % list_of_files) @@ -115,6 +135,7 @@ def setFileList(self, list_of_files, nPerJob, jobNum): self.datasets[dataset].append(file_path) def setDatasets(self, datalist): + self.clearDatasets() datasets = ConfigureJobs.getListOfFiles(datalist, self.input_tier) for dataset in datasets: if "@" in dataset: @@ -128,6 +149,9 @@ def setDatasets(self, datalist): continue self.datasets[dataset] = [file_path] + def clearDatasets(self): + self.datasets.clear() + def applySelector(self): for chan in self.channels: self.addTNamed("channel", chan) @@ -147,8 +171,9 @@ def processDataset(self, dataset, file_path, chan): select.SetInputList(self.inputs) self.addTNamed("name", dataset) # Only add for one channel - addSumweights = self.addSumweights and self.channels.index(chan) == 0 and "data" not in dataset + addSumweights = self.addSumweights and self.channels.index(chan) == 0 and "data" not in dataset and "Background" not in self.selector_name and "Gen" not in self.selector_name if addSumweights: + #print "Should only go here once!" sumweights_hist = ROOT.gROOT.FindObject("sumweights") # Avoid accidentally combining sumweights across datasets if sumweights_hist: @@ -157,7 +182,7 @@ def processDataset(self, dataset, file_path, chan): self.outfile = ROOT.TFile.Open(self.outfile_name) sumweights_hist = self.outfile.Get("%s/sumweights" % dataset) if not sumweights_hist: - sumweights_hist = ROOT.TH1D("sumweights", "sumweights", 100, 0, 100) + sumweights_hist = ROOT.TH1D("sumweights", "sumweights", 1000, 0, 1000) sumweights_hist.SetDirectory(ROOT.gROOT) self.processLocalFiles(select, file_path, addSumweights, chan) output_list = select.GetOutputList() @@ -210,7 +235,7 @@ def getTreeName(self, chan): def combineParallelFiles(self, tempfiles, chan): tempfiles = filter(os.path.isfile, tempfiles) outfile = self.outfile_name - if chan != "Inclusive": + if chan != "Inclusive" and len(self.channels) != 1: outfile = self.outfile_name.replace(".root", "_%s.root" % chan) rval = subprocess.call(["hadd", "-f", outfile] + tempfiles) if rval == 0: diff --git a/Utilities/python/UserInput.py b/Utilities/python/UserInput.py index d7f4b835..edebfe2a 100644 --- a/Utilities/python/UserInput.py +++ b/Utilities/python/UserInput.py @@ -25,7 +25,7 @@ def getDefaultParser(): input_group.add_argument("-f", "--filenames", type=lambda x : [i.strip() for i in x.split(',')], help="List of input file names, " - "as defined in AnalysisDatasetManager, separated " + "as defined in ZZ4lRun2DatasetManager, separated " "by commas") input_group.add_argument("--inputs_from_file", nargs=3, metavar=('filelist', 'nPerJob', 'jobNum'), @@ -82,7 +82,7 @@ def readJson(json_file_name): print(err) return json_info -# Depends on AnalysisDatasetManagerModule +# Depends on ZZ4lRun2DatasetManagerModule def getHistInfo(analysis, input_hists, noConfig=False): if noConfig: print "INFO: assuming histogram information is specified in selector" @@ -90,7 +90,7 @@ def getHistInfo(analysis, input_hists, noConfig=False): manager_path = ConfigureJobs.getManagerPath() ConfigHistTools = imp.load_source("ConfigHistTools", - "/".join([manager_path, "AnalysisDatasetManager/Utilities/python/ConfigHistTools.py"])) + "/".join([manager_path, "ZZ4lRun2DatasetManager/Utilities/python/ConfigHistTools.py"])) # For histograms produced with some postprocessing on the hist file excludedHistPatterns = ["wCR", "unrolled", "YieldByChannel"] config_hists = ConfigHistTools.getAllHistNames(manager_path, analysis) \ @@ -104,7 +104,7 @@ def getHistInfo(analysis, input_hists, noConfig=False): def getHistExpr(hist_names, selection): manager_path = ConfigureJobs.getManagerPath() ConfigHistTools = imp.load_source("ConfigHistTools", - "/".join([manager_path, "AnalysisDatasetManager/Utilities/python/ConfigHistTools.py"])) + "/".join([manager_path, "ZZ4lRun2DatasetManager/Utilities/python/ConfigHistTools.py"])) info = ROOT.TList() info.SetName("histinfo") diff --git a/Utilities/scripts/makeAtgcForSenka.py b/Utilities/scripts/makeAtgcForSenka.py new file mode 100644 index 00000000..226239b7 --- /dev/null +++ b/Utilities/scripts/makeAtgcForSenka.py @@ -0,0 +1,118 @@ +import sys +import ROOT +import os +import logging +import json +import array +from python import ConfigureJobs + +def addOverflow(hist): + addOverflowAndUnderflow(hist, underflow=False, overflow=True) + +def addOverflowAndUnderflow(hist, underflow=True, overflow=True): + if not "TH1" in hist.ClassName(): + return + if overflow: + # Returns num bins + overflow + underflow + num_bins = hist.GetNbinsX() + add_overflow = hist.GetBinContent(num_bins) + hist.GetBinContent(num_bins + 1) + hist.SetBinContent(num_bins, add_overflow) + if underflow: + add_underflow = hist.GetBinContent(0) + hist.GetBinContent(1) + hist.SetBinContent(1, add_underflow) + +manager_path = ConfigureJobs.getManagerPath() +manager_name = ConfigureJobs.getManagerName() +#print "manager_path: ", manager_path +if manager_path not in sys.path: + sys.path.insert(0, "/".join([manager_path,"ZZ4lRun2DatasetManager", "Utilities/python"])) + +fileMap = { "2016" : "/afs/cern.ch/user/u/uhussain/ZZ4lRun2HistFiles/Hists17Oct2019-ZZ4l2016_Moriond.root", + "2017" : "", + "2018" : "/afs/cern.ch/user/u/uhussain/ZZ4lRun2HistFiles/Hists29Oct2019-ZZ4l2018_MVA.root", + } +channels = ["eeee", "eemm", "mmmm"] +#channels = ["eemm"] +eVariations = ["CMS_eff_eUp", "CMS_eff_eDown","CMS_RecoEff_eUp", "CMS_RecoEff_eDown"] +mVariations = ["CMS_eff_mUp","CMS_eff_mDown"] +#systVariations=[] +fitvar = "Mass" +rebin = array.array('d', [100.0,200.0,250.0,300.0,350.0,400.0,500.0,600.0,800.0,1000.0,1200.0]) +outputFolder = "ForSenka/%sFullRunII" % fitvar +if not os.path.isdir(outputFolder): + os.makedirs(outputFolder) + +#for year in fileMap.keys(): +for year in ["2018"]: + dataset_file = "%s/ZZ4lRun2DatasetManager/FileInfo/ZZ4l%s/%s.json" % (manager_path,year, "LooseLeptons") + allnames = json.load(open(dataset_file)) + atgcSamples={} + for name in allnames.keys(): + if "atgc" in name or "sherpa" in name: + atgcSamples[str(name)]= str(allnames[name]['plot_group']) + print atgcSamples + fileName=fileMap[year] + print "fileName: ",fileName + if type(fileName) == str: hist_file = ROOT.TFile.Open(fileName) + for chan in channels: + savehists=[] + outputFile = "ZZatgcInput_%s_%s.root" % (chan,year) + for process in [str(i) for i in atgcSamples.keys()]: + histNames=[] + if process=="nonprompt": + histNames.append("Mass_Fakes_{channel}".format(channel=chan)) + else: + histNames.append("Mass_{channel}".format(channel=chan)) + if not hist_file.Get(process): + logging.warning("Skipping invalid filename %s" % process) + continue + if process not in ["data","nonprompt"]: + if chan=="eeee": + for var in eVariations: + histNames.append("Mass_%s_%s" % (var,chan)) + elif chan=="mmmm": + for var in mVariations: + histNames.append("Mass_%s_%s" % (var,chan)) + elif chan=="eemm": + for var in eVariations+mVariations: + histNames.append("Mass_%s_%s" % (var,chan)) + #print "plot_group: ",process + #print "histNames: ",histNames + for name in histNames: + tmphist = hist_file.Get("/".join([process, name])) + if not tmphist: + raise RuntimeError("Failed to produce histogram %s" % "/".join([process, name])) + if "eemm" in name: + ##combine eemm and mmee channels + secname = name.replace("eemm","mmee") + tmphist2 = hist_file.Get("/".join([process, secname])) + #print tmphist.GetName(),": ",tmphist.Integral() + #print tmphist2.GetName(),": ",tmphist2.Integral() + tmphist.Add(tmphist2) + hist = tmphist.Clone() + #print "total: ",hist.Integral() + histnew = hist.Rebin(len(rebin)-1,"histnew",rebin) + addOverflow(histnew) + tmphist.Delete() + if process=="zz4l-sherpa": + print "this process happens in 2016" + histnew.Scale(0.455985*1000*35.9*1.239/histnew.Integral()) + if process=="zz4l-atgc_1" and year=="2018": + print "this process happens in 2018" + histnew.Scale(0.455985*1000*41.5*1.239/histnew.Integral()) + newName = name.replace("Mass",str(atgcSamples[process])) + newName = newName.replace("_"+chan,"") + hist.Delete() + histnew.SetName(newName) + savehists.append(histnew) + + fOut = ROOT.TFile.Open("/".join([outputFolder, outputFile]), "RECREATE") + fOut.cd() + for newhists in savehists: + newhists.Write() + fOut.Close() + hist_file.Close() + + + + diff --git a/Utilities/scripts/makeFakeRates.py b/Utilities/scripts/makeFakeRates.py index 54d2b6ee..56948204 100755 --- a/Utilities/scripts/makeFakeRates.py +++ b/Utilities/scripts/makeFakeRates.py @@ -5,38 +5,66 @@ from python import UserInput,OutputTools from python import ConfigureJobs from python import SelectorTools,HistTools +import logging +import sys ROOT.gROOT.SetBatch(True) -channels = ["eee", "eem", "emm", "mmm"] def getComLineArgs(): parser = UserInput.getDefaultParser() - parser.add_argument("--proof", "-p", - action='store_true', help="Don't use proof") parser.add_argument("--lumi", "-l", type=float, - default=35.87, help="luminosity value (in fb-1)") + default=41.5, help="luminosity value (in fb-1)") + parser.add_argument("--test", action='store_true', + help="Run test job (no background estimate)") + parser.add_argument("--uwvv", action='store_true', + help="Use UWVV format ntuples in stead of NanoAOD") + parser.add_argument("--noHistConfig", action='store_true', + help="Don't rely on config file to specify hist info") + parser.add_argument("--input_tier", type=str, + default="", help="Selection stage of input files") + parser.add_argument("--year", type=str, + default="default", help="Year of Analysis") + parser.add_argument("-j", "--numCores", type=int, default=1, + help="Number of cores to use (parallelize by dataset)") + parser.add_argument("--scalefactors_file", "-sf", type=str, + default="", help="ScaleFactors file name") parser.add_argument("--output_file", "-o", type=str, default="", help="Output file name") + parser.add_argument("-c", "--channels", + type=lambda x : [i.strip() for i in x.split(',')], + default=["eee","eem","emm","mmm"], help="List of channels" + "separated by commas. NOTE: set to Inclusive for NanoAOD") + parser.add_argument("-b", "--hist_names", + type=lambda x : [i.strip() for i in x.split(',')], + default=["all"], help="List of histograms, " + "as defined in ZZ4lRun2DatasetManager, separated " + "by commas") return vars(parser.parse_args()) def getHistNames(channels): - base_hists = [x+y for x in ["passingLoose", "passingTight"] \ - for y in "1DEta", "1DPt", "2D"] + base_hists = [x+y for x in ["passingLooseE", "passingTightE","passingLooseMu", "passingTightMu"] \ + for y in "1DEta", "1DPt_barrel","1DPt_endcap", "2D"] if len(channels) == 0: return base_hists return [x+"_"+y for x in base_hists for y in channels] # Turn off overflow for FR hists (> 50 is pretty much all EWK anyway) -def makeCompositeHists(name, members, addRatios=True, overflow=False): +def makeCompositeHists(hist_file,name, members, addRatios=True, overflow=False): composite = ROOT.TList() composite.SetName(name) + if name=="AllEWK": + print "EWK members: ",members for directory in [str(i) for i in members.keys()]: for histname in getHistNames(["eee", "eem", "emm", "mmm"]): - hist = fOut.Get("/".join([directory, histname])) + print "histname:", histname + print "hist_file:", hist_file + print "directory:",directory + hist = hist_file.Get("/".join([directory, str(histname)])) + print "hist:", hist if hist: sumhist = composite.FindObject(hist.GetName()) if "data" not in directory and hist.GetEntries() > 0: - sumweights_hist = fOut.Get("/".join([directory, "sumweights"])) + sumweights_hist = hist_file.Get("/".join([directory, "sumweights"])) sumweights = sumweights_hist.Integral() hist.Scale(members[directory]*1000*args['lumi']/sumweights) if overflow and isinstance(hist, ROOT.TH1): @@ -93,35 +121,69 @@ def getRatios(hists): return ratios args = getComLineArgs() -proof = 0 -if args['proof']: - ROOT.TProof.Open("workers=12") - proof = ROOT.gProof -today = datetime.date.today().strftime("%d%b%Y") -fileName = "data/fakeRate%s-%s.root" % (today, args['selection']) if args['output_file'] == "" \ - else args['output_file'] -fOut = ROOT.TFile(fileName, "recreate") - -fScales = ROOT.TFile('data/scaleFactors.root') -muonIsoSF = fScales.Get('muonIsoSF') -muonIdSF = fScales.Get('muonTightIdSF') -electronTightIdSF = fScales.Get('electronTightIdSF') -electronGsfSF = fScales.Get('electronGsfSF') -pileupSF = fScales.Get('pileupSF') -sf_inputs = [electronTightIdSF, electronGsfSF, muonIsoSF, muonIdSF, pileupSF] -SelectorTools.applySelector(args["filenames"], - "FakeRateSelector", args['selection'], fOut, - extra_inputs=sf_inputs, proof=args['proof'], - addSumweights=True) - -alldata = makeCompositeHists("AllData", ConfigureJobs.getListOfFilesWithXSec(["WZxsec2016data"])) -OutputTools.writeOutputListItem(alldata, fOut) -allewk = makeCompositeHists("AllEWK", ConfigureJobs.getListOfFilesWithXSec( - ConfigureJobs.getListOfEWKFilenames()), False) -OutputTools.writeOutputListItem(allewk, fOut) -allnonprompt = makeCompositeHists("NonpromptMC", ConfigureJobs.getListOfFilesWithXSec( - ConfigureJobs.getListOfNonpromptFilenames())) -OutputTools.writeOutputListItem(allnonprompt, fOut) -final = HistTools.getDifference(fOut, "DataEWKCorrected", "AllData", "AllEWK", getRatios) -OutputTools.writeOutputListItem(final, fOut) +today = datetime.date.today().strftime("%d%b%Y") +#fileName = "data/fakeRate%s-%s.root" % (today,args['analysis']) if args['output_file'] == "" \ +# else args['output_file'] +fileName="data/fakeRate15Sep2019-ZZ4l2016.root" +if not args['test']: + fOut = ROOT.TFile(fileName, "recreate") + + + addScaleFacs = False + if args['analysis'] == "WZxsec2016" or args['analysis'] == 'Zstudy_2016' or args['scalefactors_file']: + addScaleFacs = True + sf_inputs = [ROOT.TParameter(bool)("applyScaleFacs", False)] + + if args['input_tier'] == '': + args['input_tier'] = args['selection'] + selection = args['selection'].split("_")[0] + + if selection == "Inclusive2Jet": + selection = "Wselection" + print "Info: Using Wselection for hist defintions" + analysis = "/".join([args['analysis'], selection]) + hists, hist_inputs = UserInput.getHistInfo(analysis, args['hist_names'], args['noHistConfig']) + print "hists: ",hists + print "hist_inputs: ", hist_inputs + selector = SelectorTools.SelectorDriver(args['analysis'], args['selection'], args['input_tier'], args['year']) + selector.setOutputfile(fOut.GetName()) + selector.setInputs(sf_inputs+hist_inputs) + selector.isFake() + + selector.setNtupeType("UWVV" if args['uwvv'] else "NanoAOD") + if args['uwvv']: + logging.debug("Processing channels " % args['channels']) + selector.setChannels(args['channels']) + + selector.setNumCores(args['numCores']) + + if args['filenames']: + selector.setDatasets(args['filenames']) + else: + selector.setFileList(*args['inputs_from_file']) + mc = selector.applySelector() + + #if args['test']: + # sys.exit(0) + + #fOut.Close() +if args['test']: + fOut = ROOT.TFile.Open(fileName, "update") + alldata = makeCompositeHists(fOut,"AllData", ConfigureJobs.getListOfFilesWithXSec([args['analysis']+"data"])) + OutputTools.writeOutputListItem(alldata, fOut) + alldata.Delete() + allewk = makeCompositeHists(fOut,"AllEWK", ConfigureJobs.getListOfFilesWithXSec( + ConfigureJobs.getListOfEWKFilenames()), True) + OutputTools.writeOutputListItem(allewk, fOut) + allewk.Delete() + allDYJets = makeCompositeHists(fOut,"DYMC", ConfigureJobs.getListOfFilesWithXSec( + ConfigureJobs.getListOfDYFilenames()),True) + OutputTools.writeOutputListItem(allDYJets, fOut) + allDYJets.Delete() + #allnonprompt = makeCompositeHists("NonpromptMC", ConfigureJobs.getListOfFilesWithXSec( + # ConfigureJobs.getListOfNonpromptFilenames())) + #OutputTools.writeOutputListItem(allnonprompt, fOut) + final = HistTools.getDifference(fOut, "DataEWKCorrected", "AllData", "AllEWK", getRatios) + OutputTools.writeOutputListItem(final, fOut) + final.Delete() diff --git a/Utilities/scripts/makeFileForSenka.py b/Utilities/scripts/makeFileForSenka.py new file mode 100644 index 00000000..bac2316a --- /dev/null +++ b/Utilities/scripts/makeFileForSenka.py @@ -0,0 +1,93 @@ +import sys +import ROOT +import os +import logging +#Putting qqZZ_sherpa in the atgc files +#plot_groups = ["HZZ_signal","qqZZ_powheg","qqZZ_sherpa","zzjj4l_ewk","ggZZ", "VVV", "data", "nonprompt",] +plot_groups = ["HZZ_signal","qqZZ_powheg","zzjj4l_ewk","ggZZ", "VVV", "data", "nonprompt",] +#plot_groups = ["HZZ_signal"] +fileMap = { "2016" : "/data/uhussain/ZZTo4l/FullRun2/VVAnalyzer/CMSSW_10_3_1/src/Analysis/VVAnalysis/ZZCombineInput_2016.root", + "2017" : "/data/uhussain/ZZTo4l/FullRun2/VVAnalyzer/CMSSW_10_3_1/src/Analysis/VVAnalysis/ZZCombineInput_2017.root", + "2018" : "/data/uhussain/ZZTo4l/FullRun2/VVAnalyzer/CMSSW_10_3_1/src/Analysis/VVAnalysis/ZZCombineInput_2018.root", + } +channels = ["eeee", "eemm", "mmmm"] +#channels = ["eemm"] +eVariations = ["CMS_eff_eUp", "CMS_eff_eDown","CMS_RecoEff_eUp", "CMS_RecoEff_eDown"] +mVariations = ["CMS_eff_mUp","CMS_eff_mDown"] +#systVariations=[] +#"CMS_pileup"], +#theorVariations=[] +theorVariations = ["pdf","QCDscale"] +fitvar = "Mass" + +outputFolder = "ForSenka/%sFullRunII" % fitvar +if not os.path.isdir(outputFolder): + os.makedirs(outputFolder) + +for year in fileMap.keys(): +#for year in ["2016"]: + fileName=fileMap[year] + if type(fileName) == str: hist_file = ROOT.TFile.Open(fileName) + for chan in channels: + savehists=[] + outputFile = "ZZSMInput_%s_%s.root" % (chan,year) + for process in plot_groups: + histNames=[] + if process=="nonprompt": + histNames.append("Mass_Fakes_{channel}".format(channel=chan)) + else: + histNames.append("Mass_{channel}".format(channel=chan)) + if not hist_file.Get(process): + logging.warning("Skipping invalid filename %s" % process) + continue + if process not in ["data","nonprompt"]: + if chan=="eeee": + for var in eVariations: + histNames.append("Mass_%s_%s" % (var,chan)) + elif chan=="mmmm": + for var in mVariations: + histNames.append("Mass_%s_%s" % (var,chan)) + elif chan=="eemm": + for var in eVariations+mVariations: + histNames.append("Mass_%s_%s" % (var,chan)) + if process in ["qqZZ_powheg","HZZ_signal","ggZZ","VVV"]: + for var in theorVariations: + histNames.append("Mass_%s_%sUp_%s" % (var,process,chan)) + histNames.append("Mass_%s_%sDown_%s" % (var,process,chan)) + print "plot_group: ",process + print "histNames: ",histNames + for name in histNames: + tmphist = hist_file.Get("/".join([process, name])) + if not tmphist: + raise RuntimeError("Failed to produce histogram %s" % "/".join([process, name])) + if "eemm" in name: + ##combine eemm and mmee channels + secname = name.replace("eemm","mmee") + tmphist2 = hist_file.Get("/".join([process, secname])) + #print tmphist.GetName(),": ",tmphist.Integral() + #print tmphist2.GetName(),": ",tmphist2.Integral() + tmphist.Add(tmphist2) + hist = tmphist.Clone() + #print "total: ",hist.Integral() + tmphist.Delete() + newName = name.replace("Mass",process) + newName = newName.replace("_"+chan,"") + if "pdf" or "QCD" in newName: + newName = newName.replace("_"+process,"") + if "Fakes" in newName: + newName = newName.replace("_Fakes","") + if "data" in newName: + newName = newName.replace("data","data_obs") + hist.SetName(newName) + savehists.append(hist) + + fOut = ROOT.TFile.Open("/".join([outputFolder, outputFile]), "RECREATE") + fOut.cd() + for newhists in savehists: + newhists.Write() + fOut.Close() + hist_file.Close() + + + + diff --git a/Utilities/scripts/makeHistFile.py b/Utilities/scripts/makeHistFile.py index 034c0622..09d6e008 100755 --- a/Utilities/scripts/makeHistFile.py +++ b/Utilities/scripts/makeHistFile.py @@ -8,6 +8,10 @@ import os import logging import sys +import datetime +import subprocess + +#logging.basicConfig(level=logging.DEBUG) def getComLineArgs(): parser = UserInput.getDefaultParser() @@ -15,10 +19,16 @@ def getComLineArgs(): default=35.87, help="luminosity value (in fb-1)") parser.add_argument("--output_file", "-o", type=str, default="test.root", help="Output file name") + parser.add_argument("--muIDType", type=str, + default="", help="Moriond Muon ID or MVA ID") parser.add_argument("--test", action='store_true', help="Run test job (no background estimate)") parser.add_argument("--uwvv", action='store_true', help="Use UWVV format ntuples in stead of NanoAOD") + parser.add_argument("--with_background", action='store_true', + help="Don't run background selector") + parser.add_argument("--with_Gen", action='store_true', + help="Don't run ZZGen selector") parser.add_argument("--noHistConfig", action='store_true', help="Don't rely on config file to specify hist info") parser.add_argument("-j", "--numCores", type=int, default=1, @@ -27,6 +37,8 @@ def getComLineArgs(): default="", help="Selection stage of input files") parser.add_argument("--year", type=str, default="default", help="Year of Analysis") + parser.add_argument("--scalefactors_file", "-sf", type=str, + default="", help="ScaleFactors file name") parser.add_argument("-c", "--channels", type=lambda x : [i.strip() for i in x.split(',')], default=["eee","eem","emm","mmm"], help="List of channels" @@ -34,7 +46,7 @@ def getComLineArgs(): parser.add_argument("-b", "--hist_names", type=lambda x : [i.strip() for i in x.split(',')], default=["all"], help="List of histograms, " - "as defined in AnalysisDatasetManager, separated " + "as defined in ZZ4lRun2DatasetManager, separated " "by commas") return vars(parser.parse_args()) @@ -44,48 +56,106 @@ def makeHistFile(args): manager_path = ConfigureJobs.getManagerPath() if manager_path not in sys.path: sys.path.insert(0, "/".join([manager_path, - "AnalysisDatasetManager", "Utilities/python"])) + "ZZ4lRun2DatasetManager", "Utilities/python"])) - tmpFileName = args['output_file'] - fOut = ROOT.TFile(tmpFileName, "recreate") + today = datetime.date.today().strftime("%d%b%Y") + + if args['test']: + tmpFileName = "Hists%s-%s.root" % (today, args['output_file']) + else: + tmpFileName = "Hists%s-%s.root" % (today, args['output_file']) if args['selection'] == "SignalSync" \ + else "Hists%s-%s_%s.root" % (today, args['analysis'],args['muIDType']) + toCombine = args['with_background'] or args['with_Gen'] + fOut = ROOT.TFile(tmpFileName if not toCombine else tmpFileName.replace(".root", "sel.root"), "recreate") + combinedNames = [fOut.GetName()] addScaleFacs = False - if args['analysis'] == "WZxsec2016" or args['analysis'] == 'Zstudy_2016': + if args['analysis'] == "WZxsec2016" or args['analysis'] == 'Zstudy_2016' or args['scalefactors_file']: addScaleFacs = True - addScaleFacs=False + sf_inputs = [ROOT.TParameter(bool)("applyScaleFacs", False)] - + fr_inputs = [] if addScaleFacs: - fScales = ROOT.TFile('data/scaleFactors.root') - mCBTightFakeRate = fScales.Get("mCBTightFakeRate") - eCBTightFakeRate = fScales.Get("eCBTightFakeRate") - useSvenjasFRs = False - useJakobsFRs = False - if useSvenjasFRs: - mCBTightFakeRate = fScales.Get("mCBTightFakeRate_Svenja") - eCBTightFakeRate = fScales.Get("eCBTightFakeRate_Svenja") - elif useJakobsFRs: - mCBTightFakeRate = fScales.Get("mCBTightFakeRate_Jakob") - eCBTightFakeRate = fScales.Get("eCBTightFakeRate_Jakob") - # For medium muons - #mCBMedFakeRate.SetName("fakeRate_allMu") - if mCBTightFakeRate: - mCBTightFakeRate.SetName("fakeRate_allMu") - if eCBTightFakeRate: - eCBTightFakeRate.SetName("fakeRate_allE") - - muonIsoSF = fScales.Get('muonIsoSF') - muonIdSF = fScales.Get('muonTightIdSF') - electronTightIdSF = fScales.Get('electronTightIdSF') - electronGsfSF = fScales.Get('electronGsfSF') - pileupSF = fScales.Get('pileupSF') - - #fPrefireEfficiency = ROOT.TFile('data/Map_Jet_L1FinOReff_bxm1_looseJet_JetHT_Run2016B-H.root') - fPrefireEfficiency = ROOT.TFile('data/Map_Jet_L1FinOReff_bxm1_looseJet_SingleMuon_Run2016B-H.root') - prefireEff = fPrefireEfficiency.Get('prefireEfficiencyMap') - - fr_inputs = [eCBTightFakeRate, mCBTightFakeRate,] - sf_inputs = [electronTightIdSF, electronGsfSF, muonIsoSF, muonIdSF, pileupSF, prefireEff] + fScales = ROOT.TFile(args['scalefactors_file']) + if "ZZ4l" in args['analysis']: + mZZTightFakeRate = fScales.Get("mZZTightFakeRate") + eZZTightFakeRate = fScales.Get("eZZTightFakeRate") + if mZZTightFakeRate: + mZZTightFakeRate.SetName("fakeRate_allMu") + if eZZTightFakeRate: + eZZTightFakeRate.SetName("fakeRate_allE") + if "2018" in args['scalefactors_file']: + muonRunSF= fScales.Get('muonRun18SF') + muonRunSF.SetName("muonRunSF") + electronLowRecoSF = fScales.Get('electronLowReco18SF') + electronLowRecoSF.SetName("electronLowRecoSF") + electronRecoSF = fScales.Get('electronReco18SF') + electronRecoSF.SetName("electronRecoSF") + electronRunSF = fScales.Get('electronRun18SF') + electronRunSF.SetName("electronRunSF") + electronRunGapSF = fScales.Get('electronRun18GapSF') + electronRunGapSF.SetName("electronRunGapSF") + elif "2016" in args['scalefactors_file']: + muonRunSF= fScales.Get('muonRun16SF') + muonRunSF.SetName("muonRunSF") + electronLowRecoSF = fScales.Get('electronLowReco16SF') + electronLowRecoSF.SetName("electronLowRecoSF") + electronRecoSF = fScales.Get('electronReco16SF') + electronRecoSF.SetName("electronRecoSF") + electronRunSF = fScales.Get('electronRun16SF') + electronRunSF.SetName("electronRunSF") + electronRunGapSF = fScales.Get('electronRun16GapSF') + electronRunGapSF.SetName("electronRunGapSF") + elif "2017" in args['scalefactors_file']: + muonRunSF= fScales.Get('muonRun17SF') + muonRunSF.SetName("muonRunSF") + electronLowRecoSF = fScales.Get('electronLowReco17SF') + electronLowRecoSF.SetName("electronLowRecoSF") + electronRecoSF = fScales.Get('electronReco17SF') + electronRecoSF.SetName("electronRecoSF") + electronRunSF = fScales.Get('electronRun17SF') + electronRunSF.SetName("electronRunSF") + electronRunGapSF = fScales.Get('electronRun17GapSF') + electronRunGapSF.SetName("electronRunGapSF") + else: + print "what scale factors you want?" + sys.exit() + pileupSF = fScales.Get('pileupSF') + + fr_inputs = [eZZTightFakeRate, mZZTightFakeRate,] + sf_inputs = [electronLowRecoSF,electronRecoSF,electronRunSF, electronRunGapSF,muonRunSF,pileupSF] + else: + fScales = ROOT.TFile('data/scaleFactors.root') + mCBTightFakeRate = fScales.Get("mCBTightFakeRate") + eCBTightFakeRate = fScales.Get("eCBTightFakeRate") + useSvenjasFRs = False + useJakobsFRs = False + if useSvenjasFRs: + mCBTightFakeRate = fScales.Get("mCBTightFakeRate_Svenja") + eCBTightFakeRate = fScales.Get("eCBTightFakeRate_Svenja") + elif useJakobsFRs: + mCBTightFakeRate = fScales.Get("mCBTightFakeRate_Jakob") + eCBTightFakeRate = fScales.Get("eCBTightFakeRate_Jakob") + # For medium muons + #mCBMedFakeRate.SetName("fakeRate_allMu") + if mCBTightFakeRate: + mCBTightFakeRate.SetName("fakeRate_allMu") + if eCBTightFakeRate: + eCBTightFakeRate.SetName("fakeRate_allE") + + muonIsoSF = fScales.Get('muonIsoSF') + muonIdSF = fScales.Get('muonTightIdSF') + electronTightIdSF = fScales.Get('electronTightIdSF') + electronGsfSF = fScales.Get('electronGsfSF') + pileupSF = fScales.Get('pileupSF') + + #fPrefireEfficiency = ROOT.TFile('data/Map_Jet_L1FinOReff_bxm1_looseJet_JetHT_Run2016B-H.root') + fPrefireEfficiency = ROOT.TFile('data/Map_Jet_L1FinOReff_bxm1_looseJet_SingleMuon_Run2016B-H.root') + prefireEff = fPrefireEfficiency.Get('prefireEfficiencyMap') + + fr_inputs = [eCBTightFakeRate, mCBTightFakeRate,] + sf_inputs = [electronTightIdSF, electronGsfSF, muonIsoSF, muonIdSF, pileupSF, prefireEff] + sf_inputs.append(ROOT.TParameter(bool)("applyScaleFacs", True)) if args['input_tier'] == '': @@ -98,18 +168,6 @@ def makeHistFile(args): analysis = "/".join([args['analysis'], selection]) hists, hist_inputs = UserInput.getHistInfo(analysis, args['hist_names'], args['noHistConfig']) - #if "WZxsec2016" in analysis and "FakeRate" not in args['output_selection'] and not args['test']: - # background = SelectorTools.applySelector(["WZxsec2016data"] + - # ConfigureJobs.getListOfEWKFilenames() + ["wz3lnu-powheg"] + - # ConfigureJobs.getListOfNonpromptFilenames(), - # "WZBackgroundSelector", args['selection'], fOut, - # extra_inputs=sf_inputs+fr_inputs+hist_inputs+tselection, - # channels=channels, - # addSumweights=False, - # nanoAOD=nanoAOD, - # parallel=args['parallel'], - # ) - selector = SelectorTools.SelectorDriver(args['analysis'], args['selection'], args['input_tier'], args['year']) selector.setOutputfile(fOut.GetName()) selector.setInputs(sf_inputs+hist_inputs) @@ -126,24 +184,60 @@ def makeHistFile(args): selector.setFileList(*args['inputs_from_file']) mc = selector.applySelector() + + if args['with_background']: + selector.isBackground() + selector.setInputs(sf_inputs+hist_inputs+fr_inputs) + output_name = tmpFileName.replace(".root", "bkgd.root") + selector.setOutputfile(output_name) + bkgd = selector.applySelector() + combinedNames.append(output_name) + + if args['with_Gen']: + selector.isGen() + selector.setChannels([c+"Gen" for c in args['channels']]) + # Make sure to remove data from the dataset lists + selector.setInputs(hist_inputs) + output_name = tmpFileName.replace(".root", "gen.root") + selector.setOutputfile(output_name) + combinedNames.append(output_name) + if args['filenames']: + #selector.setDatasets(args['filenames']) + selector.setDatasets(ConfigureJobs.getListOfGenFilenames(args['analysis'])) + else: + selector.setFileList(*args['inputs_from_file']) + gen = selector.applySelector() + selector.setChannels(args['channels']) + selector.outputFile().Close() + + if len(combinedNames) > 1: + rval = subprocess.call(["hadd", "-f", tmpFileName] + combinedNames) + if rval == 0: + map(os.remove, combinedNames) + if args['test']: fOut.Close() sys.exit(0) + fOut.Close() + fOut = ROOT.TFile.Open(tmpFileName, "update") + alldata = HistTools.makeCompositeHists(fOut,"AllData", - ConfigureJobs.getListOfFilesWithXSec(["WZxsec2016data"], manager_path), args['lumi'], + ConfigureJobs.getListOfFilesWithXSec([args['analysis']+"data"], manager_path), args['lumi'], underflow=False, overflow=False) OutputTools.writeOutputListItem(alldata, fOut) alldata.Delete() - nonpromptmc = HistTools.makeCompositeHists(fOut, "NonpromptMC", ConfigureJobs.getListOfFilesWithXSec( - ConfigureJobs.getListOfNonpromptFilenames(), manager_path), args['lumi'], - underflow=False, overflow=False) - nonpromptmc.Delete() + if "ZZ4l" not in args['analysis']: + nonpromptmc = HistTools.makeCompositeHists(fOut, "NonpromptMC", ConfigureJobs.getListOfFilesWithXSec( + ConfigureJobs.getListOfNonpromptFilenames(), manager_path), args['lumi'], + underflow=False, overflow=False) + nonpromptmc.Delete() + + OutputTools.writeOutputListItem(nonpromptmc, fOut) - OutputTools.writeOutputListItem(nonpromptmc, fOut) ewkmc = HistTools.makeCompositeHists(fOut,"AllEWK", ConfigureJobs.getListOfFilesWithXSec( - ConfigureJobs.getListOfEWKFilenames(), manager_path), args['lumi'], + ConfigureJobs.getListOfEWKFilenames(args['analysis']), manager_path), args['lumi'], underflow=False, overflow=False) OutputTools.writeOutputListItem(ewkmc, fOut) ewkmc.Delete() diff --git a/Utilities/scripts/makeSimpleHtml.py b/Utilities/scripts/makeSimpleHtml.py new file mode 100755 index 00000000..9d9316eb --- /dev/null +++ b/Utilities/scripts/makeSimpleHtml.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +""" + Modified from T. Ruggles and D. Taylor, U. Wisconsin + Changes by K.Long, https://github.com/kdlong/WZConfigPlotting/commit/14d492fe266f87991395aaf188cb25c9116e9cf1 +""" +import glob +import imghdr +import argparse + +def writeHTML(path, name): + image_files = [x for x in glob.glob(path + "/plots/*.*") if imghdr.what(x)] + with open('%s/index.html' % path, 'w') as index: + index = open('%s/index.html' % path, 'w') + index.write('\n' + '
\n' + '|
+ + [log] - + [verbose log] - + [pdf] + | \n'''.format(image=image_file, name=image_file.split(".")[-2])
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-p', '--path_to_files', type=str, required=True)
+ parser.add_argument('-n', '--name', type=str, required=True)
+ args = parser.parse_args()
+
+ writeHTML(args.path_to_files.rstrip("/*"), args.name)
+
+if __name__ == "__main__":
+ main()
diff --git a/Utilities/scripts/plotFakeRates.py b/Utilities/scripts/plotFakeRates.py
index c67119a0..a4b0d5d0 100755
--- a/Utilities/scripts/plotFakeRates.py
+++ b/Utilities/scripts/plotFakeRates.py
@@ -9,16 +9,48 @@
canvas = ROOT.TCanvas("canvas", "canvas")
def getTGraphAsymmErrors(frfile, folder, param, obj):
- tight_hist = frfile.Get("%s/passingTight%s_all%s" % (folder, param, obj))
- loose_hist = frfile.Get("%s/passingLoose%s_all%s" % (folder, param, obj))
+ tight_hist = frfile.Get("%s/passingTight%s%s_all%s" % (folder, obj ,param, obj))
+ loose_hist = frfile.Get("%s/passingLoose%s%s_all%s" % (folder, obj ,param, obj))
+ tight_hist.SetTitle("")
+ loose_hist.SetTitle("")
graph = ROOT.TGraphAsymmErrors(tight_hist, loose_hist)
graph.SetMarkerStyle(6)
- graph.SetMinimum(0)
- graph.SetMaximum(0.8)
+ if obj=="E":
+ graph.SetMinimum(0.01)
+ graph.SetMaximum(0.35) if "Pt" in param else graph.SetMaximum(0.1)
+ else:
+ graph.SetMinimum(0.04)
+ graph.SetMaximum(0.35) if "Pt" in param else graph.SetMaximum(0.3)
return graph
+def getTGraphAsymmErrorsPt(frfile, folder, param, obj):
+ tight_hist_barrel = frfile.Get("%s/passingTight%s%s_barrel_all%s" % (folder, obj, param, obj))
+ loose_hist_barrel = frfile.Get("%s/passingLoose%s%s_barrel_all%s" % (folder, obj, param, obj))
+ tight_hist_barrel.SetTitle("")
+ loose_hist_barrel.SetTitle("")
+ barrel = ROOT.TGraphAsymmErrors(tight_hist_barrel, loose_hist_barrel)
+ barrel.SetMarkerStyle(6)
+ barrel.SetLineColor(ROOT.kBlue)
+ tight_hist_endcap = frfile.Get("%s/passingTight%s%s_endcap_all%s" % (folder, obj, param, obj))
+ loose_hist_endcap = frfile.Get("%s/passingLoose%s%s_endcap_all%s" % (folder,obj, param, obj))
+ tight_hist_endcap.SetTitle("")
+ loose_hist_endcap.SetTitle("")
+ endcap = ROOT.TGraphAsymmErrors(tight_hist_endcap, loose_hist_endcap)
+ endcap.SetMarkerStyle(6)
+ endcap.SetLineColor(ROOT.kRed)
+ if obj=="E":
+ barrel.SetMinimum(0.01)
+ barrel.SetMaximum(0.35) if "Pt" in param else barrel.SetMaximum(0.1)
+ endcap.SetMinimum(0.01)
+ endcap.SetMaximum(0.35) if "Pt" in param else endcap.SetMaximum(0.1)
+ else:
+ barrel.SetMinimum(0.04)
+ barrel.SetMaximum(0.35) if "Pt" in param else barrel.SetMaximum(0.3)
+ endcap.SetMinimum(0.04)
+ endcap.SetMaximum(0.35) if "Pt" in param else endcap.SetMaximum(0.3)
+ return barrel,endcap
def getTextBox(obj, extra_text=""):
- text_box = ROOT.TPaveText(0.2, 0.92, 0.4+0.02*len(extra_text), 0.86, "blNDC")
+ text_box = ROOT.TPaveText(0.2, 0.88, 0.4+0.02*len(extra_text), 0.81, "blNDC")
text_box.SetFillColor(0)
text_box.SetLineColor(ROOT.kBlack)
text_box.SetTextFont(42)
@@ -27,81 +59,178 @@ def getTextBox(obj, extra_text=""):
ROOT.SetOwnership(text_box, False)
return text_box
-def invert2DHist(hist):
- new_hist = ROOT.TH2D(hist.GetName(), hist.GetTitle(),
- 3, 0, 2.5,
- 3, array.array('d', [10,20,30,50]))
- ROOT.SetOwnership(new_hist, False)
- for x in range(hist.GetNbinsX()+1):
- for y in range(hist.GetNbinsY()+1):
- value = hist.GetBinContent(x, y)
- new_hist.SetBinContent(y, x, value)
- new_hist.GetXaxis().SetTitle(hist.GetXaxis().GetTitle())
- new_hist.GetYaxis().SetTitle(hist.GetYaxis().GetTitle())
+def getLumiTextBox():
+ texS = ROOT.TLatex(0.615,0.95,"#sqrt{s} = 13 TeV, 35.9 fb^{-1}")
+ texS.SetNDC()
+ texS.SetTextFont(42)
+ texS.SetTextSize(0.040)
+ texS.Draw()
+ texS1 = ROOT.TLatex(0.15,0.95,"#bf{CMS} #it{Preliminary}")
+ texS1.SetNDC()
+ texS1.SetTextFont(42)
+ texS1.SetTextSize(0.040)
+ texS1.Draw()
+ return texS,texS1
+
+def invert2DHist(hist,obj):
+ if (obj=="E"):
+ new_hist = ROOT.TH2D(hist.GetName(), hist.GetTitle(),
+ 4, array.array('d',[0.,0.7395,1.479,2.0,2.5]),
+ 6, array.array('d', [5,10,20,30,40,50,80]))
+ ROOT.SetOwnership(new_hist, False)
+ for x in range(hist.GetNbinsX()+1):
+ for y in range(hist.GetNbinsY()+1):
+ value = hist.GetBinContent(x, y)
+ new_hist.SetBinContent(y, x, value)
+ new_hist.GetXaxis().SetTitle(hist.GetXaxis().GetTitle())
+ new_hist.GetYaxis().SetTitle(hist.GetYaxis().GetTitle())
+ elif (obj=="Mu"):
+ new_hist = ROOT.TH2D(hist.GetName(), hist.GetTitle(),
+ 2, array.array('d',[0.,1.2,2.4]),
+ 6, array.array('d', [5,10,20,30,40,50,80]))
+ ROOT.SetOwnership(new_hist, False)
+ for x in range(hist.GetNbinsX()+1):
+ for y in range(hist.GetNbinsY()+1):
+ value = hist.GetBinContent(x, y)
+ new_hist.SetBinContent(y, x, value)
+ new_hist.GetXaxis().SetTitle(hist.GetXaxis().GetTitle())
+ new_hist.GetYaxis().SetTitle(hist.GetYaxis().GetTitle())
return new_hist
def makeDataPlots(param, obj, outdir):
- data_ewkcorr_graph = frfile.Get("DataEWKCorrected/ratio%s_all%s" % (param, obj)) \
- if "2D" in param else getTGraphAsymmErrors(frfile, "DataEWKCorrected", param, obj)
- data_ewkcorr_graph.SetLineColor(ROOT.kRed)
+ if "Pt" in param:
+ data_ewkcorr_barrel,data_ewkcorr_endcap = getTGraphAsymmErrorsPt(frfile, "DataEWKCorrected", param, obj)
+ elif "2D" in param:
+ data_ewkcorr_graph = frfile.Get("DataEWKCorrected/ratio%s%s_all%s" % (obj,param, obj))
+ else:
+ data_ewkcorr_graph = getTGraphAsymmErrors(frfile, "DataEWKCorrected", param, obj)
+ data_ewkcorr_graph.SetLineColor(ROOT.kRed)
draw_opt = "PA" if "2D" not in param else "colz text"
if "2D" in param:
- data_ewkcorr_graph = invert2DHist(data_ewkcorr_graph)
+ data_ewkcorr_graph.SetTitle("")
+ ROOT.gStyle.SetOptStat(0)
+ data_ewkcorr_graph = invert2DHist(data_ewkcorr_graph,obj)
#data_ewkcorr_graph.GetYaxis().SetTitle("#eta")
data_ewkcorr_graph.GetYaxis().SetTitle("p_{T} [GeV]")
- data_ewkcorr_graph.GetXaxis().SetTitle("#eta")
- else:
+ data_ewkcorr_graph.GetXaxis().SetTitle("|#eta|")
+ data_ewkcorr_graph.Draw(draw_opt)
+ elif "Eta" in param:
+ data_ewkcorr_graph.SetTitle("")
data_ewkcorr_graph.GetYaxis().SetTitle("Passing Tight / Passing Loose")
- xlabel = "p_{T} [GeV]" if "Pt" in param else "#eta"
+ xlabel = "|#eta|"
data_ewkcorr_graph.GetXaxis().SetTitle(xlabel)
- data_ewkcorr_graph.Draw(draw_opt)
+ data_ewkcorr_graph.Draw(draw_opt)
+ else:
+ data_ewkcorr_barrel.SetTitle("")
+ data_ewkcorr_barrel.SetLineStyle(2)
+ data_ewkcorr_barrel.GetYaxis().SetTitle("Passing Tight / Passing Loose")
+ xlabel = "p_{T} [GeV]"
+ data_ewkcorr_barrel.GetXaxis().SetTitle(xlabel)
+ data_ewkcorr_barrel.Draw("PA")
+ data_ewkcorr_endcap.SetLineStyle(2)
+ data_ewkcorr_endcap.SetTitle("")
+ data_ewkcorr_endcap.Draw("P")
text_box = getTextBox(obj)
text_box.Draw()
-
- if not "2D" in param:
+ texS,texS1=getLumiTextBox()
+
+ if (not "2D" in param) and ("Eta" in param):
data_uncorr_graph = getTGraphAsymmErrors(frfile, "AllData", param, obj)
+ data_uncorr_graph.SetTitle("")
data_uncorr_graph.Draw("P")
- legend = ROOT.TLegend(0.2,.85,.55,.70)
+ legend = ROOT.TLegend(0.2,.80,.40,.70)
legend.AddEntry(data_uncorr_graph, "Data", "l")
legend.AddEntry(data_ewkcorr_graph, "Data - EWK", "l")
legend.Draw()
-
+ elif ("Pt" in param):
+ data_uncorr_barrel,data_uncorr_endcap = getTGraphAsymmErrorsPt(frfile, "AllData", param, obj)
+ data_uncorr_barrel.SetTitle("")
+ data_uncorr_barrel.Draw("P")
+ data_uncorr_endcap.SetTitle("")
+ data_uncorr_endcap.Draw("P")
+
+ legend = ROOT.TLegend(0.2,.80,.40,.70)
+ legend.AddEntry(data_uncorr_barrel, "barrel uncorrected", "l")
+ legend.AddEntry(data_ewkcorr_barrel, "barrel corrected", "l")
+ legend.AddEntry(data_uncorr_endcap, "endcap uncorrected", "l")
+ legend.AddEntry(data_ewkcorr_endcap, "endcap corrected", "l")
+ legend.Draw()
canvas.Print("%s/ratio%s_all%s.png" % (outdir, param, obj))
canvas.Print("%s/ratio%s_all%s.pdf" % (outdir, param, obj))
def makeMCPlots(param, obj, outdir):
- graph = frfile.Get("NonpromptMC/ratio%s_all%s" % (param, obj)) \
- if "2D" in param else getTGraphAsymmErrors(frfile, "NonpromptMC", param, obj)
- graph.SetLineColor(ROOT.kRed)
+ if "Pt" in param:
+ data_ewkcorr_barrel,data_ewkcorr_endcap = getTGraphAsymmErrorsPt(frfile, "DataEWKCorrected", param, obj)
+ elif "2D" in param:
+ data_ewkcorr_graph = frfile.Get("DataEWKCorrected/ratio%s%s_all%s" % (obj,param, obj))
+ else:
+ data_ewkcorr_graph = getTGraphAsymmErrors(frfile, "DataEWKCorrected", param, obj)
+ data_ewkcorr_graph.SetLineColor(ROOT.kRed)
draw_opt = "PA" if "2D" not in param else "colz text"
if "2D" in param:
- graph.GetYaxis().SetTitle("#eta")
+ data_ewkcorr_graph.SetTitle("")
+ ROOT.gStyle.SetOptStat(0)
+ data_ewkcorr_graph = invert2DHist(data_ewkcorr_graph,obj)
+ #data_ewkcorr_graph.GetYaxis().SetTitle("#eta")
+ data_ewkcorr_graph.GetYaxis().SetTitle("p_{T} [GeV]")
+ data_ewkcorr_graph.GetXaxis().SetTitle("|#eta|")
+ data_ewkcorr_graph.Draw(draw_opt)
+ elif "Eta" in param:
+ data_ewkcorr_graph.SetTitle("")
+ data_ewkcorr_graph.GetYaxis().SetTitle("Passing Tight / Passing Loose")
+ xlabel = "|#eta|"
+ data_ewkcorr_graph.GetXaxis().SetTitle(xlabel)
+ data_ewkcorr_graph.Draw(draw_opt)
else:
- graph.GetYaxis().SetTitle("Passing Tight / Passing Loose")
- xlabel = "p_{T} [GeV]" if "Pt" in param else "#eta"
- graph.GetXaxis().SetTitle(xlabel)
- graph.Draw(draw_opt)
+ data_ewkcorr_barrel.SetTitle("")
+ data_ewkcorr_barrel.SetLineStyle(2)
+ data_ewkcorr_barrel.GetYaxis().SetTitle("Passing Tight / Passing Loose")
+ xlabel = "p_{T} [GeV]"
+ data_ewkcorr_barrel.GetXaxis().SetTitle(xlabel)
+ data_ewkcorr_barrel.Draw("PA")
+ data_ewkcorr_endcap.SetLineStyle(2)
+ data_ewkcorr_endcap.SetTitle("")
+ data_ewkcorr_endcap.Draw("P")
- text_box = getTextBox(obj, "(MC)")
+ text_box = getTextBox(obj)
text_box.Draw()
+ texS,texS1=getLumiTextBox()
- if not "2D" in param:
- legend = ROOT.TLegend(0.2,.85,.55,.70)
- legend.AddEntry(graph, "Nonprompt MC", "l")
+ if (not "2D" in param) and ("Eta" in param):
+ data_uncorr_graph = getTGraphAsymmErrors(frfile, "DYMC", param, obj)
+ data_uncorr_graph.SetTitle("")
+ data_uncorr_graph.Draw("P")
+
+ legend = ROOT.TLegend(0.2,.80,.40,.70)
+ legend.AddEntry(data_ewkcorr_graph, "Data - EWK", "l")
+ legend.AddEntry(data_uncorr_graph, "DYJets(MC)", "l")
+ legend.Draw()
+ elif ("Pt" in param):
+ data_uncorr_barrel,data_uncorr_endcap = getTGraphAsymmErrorsPt(frfile, "DYMC", param, obj)
+ data_uncorr_barrel.SetTitle("")
+ data_uncorr_barrel.Draw("P SAME")
+ data_uncorr_endcap.SetTitle("")
+ data_uncorr_endcap.Draw("P SAME")
+
+ legend = ROOT.TLegend(0.2,.80,.40,.70)
+ legend.AddEntry(data_ewkcorr_barrel, "barrel Data-EWK", "l")
+ legend.AddEntry(data_uncorr_barrel, "barrel DYJets MC", "l")
+ legend.AddEntry(data_ewkcorr_endcap, "endcap Data-EWK", "l")
+ legend.AddEntry(data_uncorr_endcap, "endcap DYJets MC", "l")
legend.Draw()
canvas.Print("%s/ratio%s_all%s.png" % (outdir, param, obj))
canvas.Print("%s/ratio%s_all%s.pdf" % (outdir, param, obj))
-frfile = ROOT.TFile("/eos/user/k/kelong/WZAnalysisData/FakeRates/fakeRateMar2018-TightLepsFrom3MediumLeptons.root")
+frfile = ROOT.TFile("/data/uhussain/ZZTo4l/FullRun2/VVAnalyzer/CMSSW_10_3_1/src/Analysis/VVAnalysis/data/fakeRate15Sep2019-ZZ4l2016.root")
-data_folder_name = datetime.date.today().strftime("%Y%b"+"_ScaleFacs")
-data_outdir = "~/www/DibosonAnalysisData/PlottingResults/WZxsec2016/FakeRates/" + data_folder_name + "/plots"
-mc_outdir = "~/www/DibosonAnalysisData/PlottingResults/WZxsec2016/FakeRates/" + data_folder_name + "-MC/plots"
+data_folder_name = datetime.date.today().strftime("%Y%b%d"+"_ZZ4l")
+data_outdir = "~/www/ZZFullRun2/PlottingResults/ZZ4l2016/FakeRatesFromData/" + data_folder_name + "/plots"
+mc_outdir = "~/www/ZZFullRun2/PlottingResults/ZZ4l2016/FakeRates/" + data_folder_name + "-MC/plots"
for outdir in [data_outdir, mc_outdir]:
try:
@@ -111,6 +240,7 @@ def makeMCPlots(param, obj, outdir):
pass
for param in ["1DPt", "1DEta", "2D"]:
+#for param in ["1DPt", "1DEta"]:
for obj in ["Mu", "E"]:
makeDataPlots(param, obj, data_outdir)
makeMCPlots(param, obj, mc_outdir)
diff --git a/Utilities/scripts/setupZGenCombine.py b/Utilities/scripts/setupZGenCombine.py
new file mode 100644
index 00000000..2871c7dc
--- /dev/null
+++ b/Utilities/scripts/setupZGenCombine.py
@@ -0,0 +1,57 @@
+from python import CombineCardTools
+from python import ConfigureJobs
+import sys
+import ROOT
+import logging
+import array
+
+ROOT.gROOT.SetBatch(True)
+logging.basicConfig(level=logging.DEBUG)
+
+cardtool = CombineCardTools.CombineCardTools()
+
+manager_path = ConfigureJobs.getManagerPath()
+sys.path.append("/".join([manager_path, "AnalysisDatasetManager",
+ "Utilities/python"]))
+
+from ConfigHistFactory import ConfigHistFactory
+config_factory = ConfigHistFactory(
+ "%s/AnalysisDatasetManager" % manager_path,
+ "ZGen/NanoAOD",
+)
+
+#plot_groups = ["nonprompt", "dy_lo", "dy_htbinned", "dy_htbinned_cp5", "dy_lo_2018"]
+plot_groups = ["nonprompt", "dy_htbinned_cp5", "dy_lo_2018"]
+plotGroupsMap = {name : config_factory.getPlotGroupMembers(name) for name in plot_groups}
+
+xsecs = ConfigureJobs.getListOfFilesWithXSec([f for files in plotGroupsMap.values() for f in files])
+
+channels = ["ee", "mm"]
+fitvar = "ptZ"
+#rebin = array.array('d', [0.0,50.0,100.0,150.0,200.0,250.0,300.0,350.0,400.0])
+cardtool.setFitVariable(fitvar)
+#cardtool.setRebin(rebin)
+cardtool.setProcesses(plotGroupsMap)
+cardtool.setChannels(channels)
+cardtool.setCrosSectionMap(xsecs)
+cardtool.setVariations([])
+cardtool.setOutputFolder("/eos/user/k/kelong/CombineStudies/ZGen/%s" % fitvar)
+
+cardtool.setLumi(35.9)
+cardtool.setInputFile("/eos/user/k/kelong/HistFiles/ZGen/combined_withNonprompt.root")
+cardtool.setOutputFile("ZGenCombineInput.root")
+for process in plot_groups:
+ #Turn this back on when the theory uncertainties are added
+ if process not in ["nonprompt", "data"]: #and False
+ cardtool.addTheoryVar(process, 'scale', range(0, 8), exclude=[5, 7], central=-1)
+ cardtool.addTheoryVar(process, 'pdf_hessian', range(9, 109), central=-1)
+ cardtool.loadHistsForProcess(process)
+ cardtool.writeProcessHistsToOutput(process)
+
+nuissance_map = {"ee" : 3, "mm" : 3 }
+for chan in channels: #+ ["all"]:
+ cardtool.setTemplateFileName("Templates/CombineCards/VGen/ZGen_template_{channel}.txt")
+ logging.info("Writting cards for channel %s" % chan)
+ cardtool.writeCards(chan, nuissance_map[chan],
+ #extraArgs={"data_name" : "dy_lo", "dy_sample" : "dy_lo"})
+ extraArgs={"data_name" : "dy_lo_2018", "dy_sample" : "dy_lo_2018"})
diff --git a/Utilities/scripts/setupZZCombine.py b/Utilities/scripts/setupZZCombine.py
new file mode 100644
index 00000000..b59d5c98
--- /dev/null
+++ b/Utilities/scripts/setupZZCombine.py
@@ -0,0 +1,107 @@
+from python import CombineCardTools
+from python import ConfigureJobs
+import sys
+import ROOT
+import logging
+import array
+import os
+import shutil
+
+#logging.basicConfig(level=logging.DEBUG)
+
+cardtool = CombineCardTools.CombineCardTools()
+
+
+manager_path = ConfigureJobs.getManagerPath()
+manager_name = ConfigureJobs.getManagerName()
+#print "manager_path: ", manager_path
+#print "manager_name: ", manager_name
+sys.path.append("/".join([manager_path, manager_name,
+ "Utilities/python"]))
+#print sys.path
+from ConfigHistFactory import ConfigHistFactory
+config_factory = ConfigHistFactory(
+ "%s/%s" % (manager_path, manager_name),
+ "ZZ4l2016/LooseLeptons",
+)
+#manager_path = ConfigureJobs.getManagerPath()
+#manager_name = ConfigureJobs.getManagerName()
+##print "manager_path: ", manager_path
+#if manager_path not in sys.path:
+# sys.path.insert(0, "/".join([manager_path,"ZZ4lRun2DatasetManager", "Utilities/python"]))
+#dataset_file = "%s/ZZ4lRun2DatasetManager/FileInfo/ZZ4l2016/%s.json" % (manager_path, "LooseLeptons")
+#allnames = json.load(open(dataset_file))
+#atgcSamples={}
+#for name in allnames.keys():
+# if "atgc" in name or "sherpa" in name:
+# atgcSamples[str(name)]= str(allnames[name]['plot_group'])
+#print atgcSamples
+
+plot_groups = ["HZZ_signal","qqZZ_powheg","zzjj4l_ewk","ggZZ", "VVV", "data", "nonprompt",]
+plotGroupsMap = {name : config_factory.getPlotGroupMembers(name) for name in plot_groups}
+xsecs = ConfigureJobs.getListOfFilesWithXSec([f for files in plotGroupsMap.values() for f in files])
+
+
+lumiMap = {"2016" : 35.9, "2017" : 41.5, "2018" : 59.67,"FullRun2":137.1}
+fileMap = { "2016" : "/afs/cern.ch/user/u/uhussain/ZZ4lRun2HistFiles/Hists17Oct2019-ZZ4l2016_Moriond.root",
+ "2017" : "/afs/cern.ch/user/u/uhussain/ZZ4lRun2HistFiles/Hists14Oct2019-ZZ4l2017_Moriond.root",
+ "2018" : "/afs/cern.ch/user/u/uhussain/ZZ4lRun2HistFiles/Hists15Oct2019-ZZ4l2018_MVA.root",
+ "FullRun2":"/afs/cern.ch/user/u/uhussain/ZZ4lRun2HistFiles/Hists17Oct2019-ZZFullRun2.root",
+ }
+channels = ["eeee", "eemm", "mmee", "mmmm"]
+nuissance_map = {"eeee" : 16, "eemm" : 17, "mmee" : 17, "mmmm" : 15, "all" : 13}
+#fitvar = "ZZPt"
+#rebin = array.array('d', [0.0,50.0,100.0,150.0,200.0,250.0,300.0,350.0,400.0])
+fitvar = "Mass"
+rebin = array.array('d', [100.0,200.0,250.0,300.0,350.0,400.0,500.0,600.0,800.0,1000.0,1200.0])
+#fitvar = "yield"
+#cardtool.setRebin(rebin)
+cardtool.setFitVariable(fitvar)
+cardtool.setFitVariableAppend("nonprompt", "Fakes")
+cardtool.setProcesses(plotGroupsMap)
+cardtool.setChannels(channels)
+cardtool.setCrosSectionMap(xsecs)
+cardtool.setVariations(["CMS_eff_e", "CMS_RecoEff_e", "CMS_eff_m","CMS_pileup"],
+ exclude=["nonprompt", "data"])
+#cardtool.setOutputFolder("/eos/user/k/kelong/CombineStudies/ZZ/%s2016Fit" % fitvar)
+
+combine_dir = ConfigureJobs.getCombinePath()
+folder_name="%sFitFullRunII" % fitvar
+
+output_dir = '/'.join([combine_dir,"ZZ", folder_name])
+
+try:
+ os.makedirs(output_dir)
+except OSError as e:
+ logging.warning(e)
+ pass
+output_folder = "CombineStudies/ZZ/%sFitFullRunII_Oct29" % fitvar
+cardtool.setOutputFolder(output_folder)
+
+for year in ["2016","2017","2018"]:
+#One has to make templates for full Run 2 which i haven't done yet.
+#for year in ["FullRun2"]:
+ cardtool.setLumi(lumiMap[year])
+ cardtool.setInputFile(fileMap[year])
+ print fileMap[year], lumiMap[year]
+ cardtool.setOutputFile("ZZCombineInput_{year}.root".format(year=year))
+ #cardtool.setOutputFolder("/eos/user/k/kelong/CombineStudies/ZZ/%s%sFit" % (fitvar, year))
+ for process in plot_groups:
+ #Turn this back on when the theory uncertainties are added
+ if process not in ["zzjj4l_ewk","qqZZ_sherpa","zzqjj4l_ewk","nonprompt", "data"]: #and False
+ cardtool.addTheoryVar(process, 'scale', range(1, 10), exclude=[7, 9], central=0)
+ cardtool.addTheoryVar(process, 'pdf_hessian' if year != "2016" else 'pdf_mc', [1]+[i for i in range(10, 111)], central=0)
+ cardtool.loadHistsForProcess(process)
+ cardtool.writeProcessHistsToOutput(process)
+
+ for chan in channels + ["all"]:
+ cardtool.setTemplateFileName("Templates/CombineCards/ZZSelection/ZZ_template{year}_{channel}.txt")
+ logging.info("Writting cards for channel %s" % chan)
+ cardtool.writeCards(chan, nuissance_map[chan], year=year)
+
+
+copyFiles=os.listdir(output_folder)
+for f in copyFiles:
+ full_file_name=os.path.join(output_folder,f)
+ if os.path.isfile(full_file_name):
+ shutil.copy(full_file_name,output_dir)
diff --git a/createSignal16.sh b/createSignal16.sh
new file mode 100755
index 00000000..2cd96f81
--- /dev/null
+++ b/createSignal16.sh
@@ -0,0 +1 @@
+./Utilities/scripts/makeHistFile.py -a ZZ4l2016 -s SignalSync -l 35.9 -f 2016SignalSync -sf data/scaleFactorsZZ4l2018.root -ls Signal16 --test > eventlistSignal16_Usama_full.txt
diff --git a/interface/FakeRateSelector.h b/interface/FakeRateSelector.h
index d25cadf9..06ab35a4 100644
--- a/interface/FakeRateSelector.h
+++ b/interface/FakeRateSelector.h
@@ -10,35 +10,59 @@
#include